Skip to content

Commit 32bde8d

Browse files
authored
Merge pull request #121 from Opencode-DCP/on-idle-strategy
On idle strategy
2 parents 9f043dc + 9d64c42 commit 32bde8d

File tree

9 files changed

+375
-8
lines changed

9 files changed

+375
-8
lines changed

index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import type { Plugin } from "@opencode-ai/plugin"
22
import { getConfig } from "./lib/config"
33
import { Logger } from "./lib/logger"
44
import { createSessionState } from "./lib/state"
5-
import { createPruneTool } from "./lib/strategies/prune-tool"
6-
import { createChatMessageTransformHandler } from "./lib/hooks"
5+
import { createPruneTool } from "./lib/strategies"
6+
import { createChatMessageTransformHandler, createEventHandler } from "./lib/hooks"
77

88
const plugin: Plugin = (async (ctx) => {
99
const config = getConfig(ctx)
@@ -54,6 +54,7 @@ const plugin: Plugin = (async (ctx) => {
5454
logger.info("Added 'prune' to experimental.primary_tools via config mutation")
5555
}
5656
},
57+
event: createEventHandler(ctx.client, config, state, logger, ctx.directory),
5758
}
5859
}) satisfies Plugin
5960

lib/hooks.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { syncToolCache } from "./state/tool-cache"
55
import { deduplicate } from "./strategies"
66
import { prune, insertPruneToolContext } from "./messages"
77
import { checkSession } from "./state"
8+
import { runOnIdle } from "./strategies/on-idle"
89

910

1011
export function createChatMessageTransformHandler(
@@ -24,11 +25,48 @@ export function createChatMessageTransformHandler(
2425

2526
syncToolCache(state, config, logger, output.messages);
2627

27-
28-
deduplicate(client, state, logger, config, output.messages)
28+
deduplicate(state, logger, config, output.messages)
2929

3030
prune(state, logger, config, output.messages)
3131

3232
insertPruneToolContext(state, config, logger, output.messages)
3333
}
3434
}
35+
36+
export function createEventHandler(
37+
client: any,
38+
config: PluginConfig,
39+
state: SessionState,
40+
logger: Logger,
41+
workingDirectory?: string
42+
) {
43+
return async (
44+
{ event }: { event: any }
45+
) => {
46+
if (state.sessionId === null || state.isSubAgent) {
47+
return
48+
}
49+
50+
if (event.type === "session.status" && event.properties.status.type === "idle") {
51+
if (!config.strategies.onIdle.enabled) {
52+
return
53+
}
54+
if (state.lastToolPrune) {
55+
logger.info("Skipping OnIdle pruning - last tool was prune")
56+
return
57+
}
58+
59+
try {
60+
await runOnIdle(
61+
client,
62+
state,
63+
logger,
64+
config,
65+
workingDirectory
66+
)
67+
} catch (err: any) {
68+
logger.error("OnIdle pruning failed", { error: err.message })
69+
}
70+
}
71+
}
72+
}

lib/messages/prune.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ export const insertPruneToolContext = (
4040
logger: Logger,
4141
messages: WithParts[]
4242
): void => {
43+
if (!config.strategies.pruneTool.enabled) {
44+
return
45+
}
46+
4347
const lastUserMessage = getLastUserMessage(messages)
4448
if (!lastUserMessage || lastUserMessage.info.role !== 'user') {
4549
return
@@ -48,7 +52,7 @@ export const insertPruneToolContext = (
4852
const prunableToolsList = buildPrunableToolsList(state, config, logger, messages)
4953

5054
let nudgeString = ""
51-
if (config.strategies.pruneTool.nudge.enabled && state.nudgeCounter >= config.strategies.pruneTool.nudge.frequency) {
55+
if (state.nudgeCounter >= config.strategies.pruneTool.nudge.frequency) {
5256
logger.info("Inserting prune nudge message")
5357
nudgeString = "\n" + NUDGE_STRING
5458
}

lib/state/state.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ export function createSessionState(): SessionState {
4343
totalPruneTokens: 0,
4444
},
4545
toolParameters: new Map<string, ToolParameterEntry>(),
46-
nudgeCounter: 0
46+
nudgeCounter: 0,
47+
lastToolPrune: false
4748
}
4849
}
4950

@@ -59,6 +60,7 @@ export function resetSessionState(state: SessionState): void {
5960
}
6061
state.toolParameters.clear()
6162
state.nudgeCounter = 0
63+
state.lastToolPrune = false
6264
}
6365

6466
export async function ensureSessionInitialized(

lib/state/tool-cache.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export async function syncToolCache(
1717
): Promise<void> {
1818
try {
1919
logger.info("Syncing tool parameters from OpenCode messages")
20+
2021
for (const msg of messages) {
2122
for (const part of msg.parts) {
2223
if (part.type !== "tool" || !part.callID || state.toolParameters.has(part.callID)) {
@@ -36,6 +37,9 @@ export async function syncToolCache(
3637
if (!config.strategies.pruneTool.protectedTools.includes(part.tool)) {
3738
state.nudgeCounter++
3839
}
40+
41+
state.lastToolPrune = part.tool === "prune"
42+
logger.info("lastToolPrune=" + String(state.lastToolPrune))
3943
}
4044
}
4145

lib/state/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ export interface SessionState {
3030
stats: SessionStats
3131
toolParameters: Map<string, ToolParameterEntry>
3232
nudgeCounter: number
33+
lastToolPrune: boolean
3334
}

lib/strategies/deduplication.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { calculateTokensSaved } from "../utils"
99
* Modifies the session state in place to add pruned tool call IDs.
1010
*/
1111
export const deduplicate = (
12-
client: any,
1312
state: SessionState,
1413
logger: Logger,
1514
config: PluginConfig,

lib/strategies/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { deduplicate } from "./deduplication"
2-
2+
export { runOnIdle } from "./on-idle"
3+
export { createPruneTool } from "./prune-tool"

0 commit comments

Comments
 (0)