@tarquinen/opencode-dcp 0.4.17 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -59
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +30 -13
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +339 -121
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/hooks.d.ts +5 -13
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/hooks.js +26 -125
- package/dist/lib/hooks.js.map +1 -1
- package/dist/lib/logger.d.ts +5 -9
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +30 -160
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/messages/index.d.ts +2 -0
- package/dist/lib/messages/index.d.ts.map +1 -0
- package/dist/lib/messages/index.js +2 -0
- package/dist/lib/messages/index.js.map +1 -0
- package/dist/lib/messages/prune.d.ts +6 -0
- package/dist/lib/messages/prune.d.ts.map +1 -0
- package/dist/lib/messages/prune.js +85 -0
- package/dist/lib/messages/prune.js.map +1 -0
- package/dist/lib/messages/utils.d.ts +10 -0
- package/dist/lib/messages/utils.d.ts.map +1 -0
- package/dist/lib/messages/utils.js +103 -0
- package/dist/lib/messages/utils.js.map +1 -0
- package/dist/lib/model-selector.js +3 -3
- package/dist/lib/model-selector.js.map +1 -1
- package/dist/lib/{core/prompt.d.ts → prompt.d.ts} +1 -1
- package/dist/lib/prompt.d.ts.map +1 -0
- package/dist/lib/{core/prompt.js → prompt.js} +2 -6
- package/dist/lib/prompt.js.map +1 -0
- package/dist/lib/prompts/pruning.txt +1 -1
- package/dist/lib/prompts/tool.txt +3 -3
- package/dist/lib/state/index.d.ts +3 -27
- package/dist/lib/state/index.d.ts.map +1 -1
- package/dist/lib/state/index.js +3 -40
- package/dist/lib/state/index.js.map +1 -1
- package/dist/lib/state/persistence.d.ts +4 -4
- package/dist/lib/state/persistence.d.ts.map +1 -1
- package/dist/lib/state/persistence.js +24 -20
- package/dist/lib/state/persistence.js.map +1 -1
- package/dist/lib/state/state.d.ts +7 -0
- package/dist/lib/state/state.d.ts.map +1 -0
- package/dist/lib/state/state.js +76 -0
- package/dist/lib/state/state.js.map +1 -0
- package/dist/lib/state/tool-cache.d.ts +4 -6
- package/dist/lib/state/tool-cache.d.ts.map +1 -1
- package/dist/lib/state/tool-cache.js +20 -46
- package/dist/lib/state/tool-cache.js.map +1 -1
- package/dist/lib/state/types.d.ts +30 -0
- package/dist/lib/state/types.d.ts.map +1 -0
- package/dist/lib/state/types.js +2 -0
- package/dist/lib/state/types.js.map +1 -0
- package/dist/lib/strategies/deduplication.d.ts +10 -0
- package/dist/lib/strategies/deduplication.d.ts.map +1 -0
- package/dist/lib/strategies/deduplication.js +89 -0
- package/dist/lib/strategies/deduplication.js.map +1 -0
- package/dist/lib/strategies/index.d.ts +4 -0
- package/dist/lib/strategies/index.d.ts.map +1 -0
- package/dist/lib/strategies/index.js +4 -0
- package/dist/lib/strategies/index.js.map +1 -0
- package/dist/lib/strategies/on-idle.d.ts +14 -0
- package/dist/lib/strategies/on-idle.d.ts.map +1 -0
- package/dist/lib/strategies/on-idle.js +216 -0
- package/dist/lib/strategies/on-idle.js.map +1 -0
- package/dist/lib/strategies/prune-tool.d.ts +17 -0
- package/dist/lib/strategies/prune-tool.d.ts.map +1 -0
- package/dist/lib/strategies/prune-tool.js +70 -0
- package/dist/lib/strategies/prune-tool.js.map +1 -0
- package/dist/lib/ui/display-utils.d.ts +3 -12
- package/dist/lib/ui/display-utils.d.ts.map +1 -1
- package/dist/lib/ui/display-utils.js +12 -79
- package/dist/lib/ui/display-utils.js.map +1 -1
- package/dist/lib/ui/notification.d.ts +7 -23
- package/dist/lib/ui/notification.d.ts.map +1 -1
- package/dist/lib/ui/notification.js +38 -47
- package/dist/lib/ui/notification.js.map +1 -1
- package/dist/lib/utils.d.ts +9 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +61 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +1 -1
- package/dist/lib/core/janitor.d.ts +0 -38
- package/dist/lib/core/janitor.d.ts.map +0 -1
- package/dist/lib/core/janitor.js +0 -294
- package/dist/lib/core/janitor.js.map +0 -1
- package/dist/lib/core/prompt.d.ts.map +0 -1
- package/dist/lib/core/prompt.js.map +0 -1
- package/dist/lib/core/strategies/deduplication.d.ts +0 -7
- package/dist/lib/core/strategies/deduplication.d.ts.map +0 -1
- package/dist/lib/core/strategies/deduplication.js +0 -76
- package/dist/lib/core/strategies/deduplication.js.map +0 -1
- package/dist/lib/core/strategies/index.d.ts +0 -51
- package/dist/lib/core/strategies/index.d.ts.map +0 -1
- package/dist/lib/core/strategies/index.js +0 -48
- package/dist/lib/core/strategies/index.js.map +0 -1
- package/dist/lib/fetch-wrapper/formats/anthropic.d.ts +0 -8
- package/dist/lib/fetch-wrapper/formats/anthropic.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/formats/anthropic.js +0 -96
- package/dist/lib/fetch-wrapper/formats/anthropic.js.map +0 -1
- package/dist/lib/fetch-wrapper/formats/bedrock.d.ts +0 -8
- package/dist/lib/fetch-wrapper/formats/bedrock.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/formats/bedrock.js +0 -97
- package/dist/lib/fetch-wrapper/formats/bedrock.js.map +0 -1
- package/dist/lib/fetch-wrapper/formats/gemini.d.ts +0 -8
- package/dist/lib/fetch-wrapper/formats/gemini.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/formats/gemini.js +0 -134
- package/dist/lib/fetch-wrapper/formats/gemini.js.map +0 -1
- package/dist/lib/fetch-wrapper/formats/index.d.ts +0 -6
- package/dist/lib/fetch-wrapper/formats/index.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/formats/index.js +0 -6
- package/dist/lib/fetch-wrapper/formats/index.js.map +0 -1
- package/dist/lib/fetch-wrapper/formats/openai-chat.d.ts +0 -3
- package/dist/lib/fetch-wrapper/formats/openai-chat.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/formats/openai-chat.js +0 -100
- package/dist/lib/fetch-wrapper/formats/openai-chat.js.map +0 -1
- package/dist/lib/fetch-wrapper/formats/openai-responses.d.ts +0 -3
- package/dist/lib/fetch-wrapper/formats/openai-responses.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/formats/openai-responses.js +0 -63
- package/dist/lib/fetch-wrapper/formats/openai-responses.js.map +0 -1
- package/dist/lib/fetch-wrapper/gc-tracker.d.ts +0 -4
- package/dist/lib/fetch-wrapper/gc-tracker.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/gc-tracker.js +0 -61
- package/dist/lib/fetch-wrapper/gc-tracker.js.map +0 -1
- package/dist/lib/fetch-wrapper/handler.d.ts +0 -3
- package/dist/lib/fetch-wrapper/handler.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/handler.js +0 -118
- package/dist/lib/fetch-wrapper/handler.js.map +0 -1
- package/dist/lib/fetch-wrapper/index.d.ts +0 -18
- package/dist/lib/fetch-wrapper/index.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/index.js +0 -107
- package/dist/lib/fetch-wrapper/index.js.map +0 -1
- package/dist/lib/fetch-wrapper/prunable-list.d.ts +0 -8
- package/dist/lib/fetch-wrapper/prunable-list.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/prunable-list.js +0 -38
- package/dist/lib/fetch-wrapper/prunable-list.js.map +0 -1
- package/dist/lib/fetch-wrapper/tool-tracker.d.ts +0 -9
- package/dist/lib/fetch-wrapper/tool-tracker.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/tool-tracker.js +0 -12
- package/dist/lib/fetch-wrapper/tool-tracker.js.map +0 -1
- package/dist/lib/fetch-wrapper/types.d.ts +0 -62
- package/dist/lib/fetch-wrapper/types.d.ts.map +0 -1
- package/dist/lib/fetch-wrapper/types.js +0 -7
- package/dist/lib/fetch-wrapper/types.js.map +0 -1
- package/dist/lib/pruning-tool.d.ts +0 -20
- package/dist/lib/pruning-tool.d.ts.map +0 -1
- package/dist/lib/pruning-tool.js +0 -160
- package/dist/lib/pruning-tool.js.map +0 -1
- package/dist/lib/state/id-mapping.d.ts +0 -25
- package/dist/lib/state/id-mapping.d.ts.map +0 -1
- package/dist/lib/state/id-mapping.js +0 -51
- package/dist/lib/state/id-mapping.js.map +0 -1
- package/dist/lib/tokenizer.d.ts +0 -3
- package/dist/lib/tokenizer.d.ts.map +0 -1
- package/dist/lib/tokenizer.js +0 -16
- package/dist/lib/tokenizer.js.map +0 -1
- package/dist/lib/version-checker.d.ts +0 -9
- package/dist/lib/version-checker.d.ts.map +0 -1
- package/dist/lib/version-checker.js +0 -77
- package/dist/lib/version-checker.js.map +0 -1
|
@@ -1,66 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
const MAX_TOOL_CACHE_SIZE = 500;
|
|
1
|
+
const MAX_TOOL_CACHE_SIZE = 1000;
|
|
3
2
|
/**
|
|
4
3
|
* Sync tool parameters from OpenCode's session.messages() API.
|
|
5
|
-
* This is the single source of truth for tool parameters, replacing
|
|
6
|
-
* format-specific parsing from LLM API requests.
|
|
7
4
|
*/
|
|
8
|
-
export async function syncToolCache(
|
|
5
|
+
export async function syncToolCache(state, config, logger, messages) {
|
|
9
6
|
try {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
query: { limit: 500 }
|
|
13
|
-
});
|
|
14
|
-
const messages = messagesResponse.data || messagesResponse;
|
|
15
|
-
if (!Array.isArray(messages)) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
let synced = 0;
|
|
19
|
-
// Build lowercase set of pruned IDs for comparison (IDs in state may be mixed case)
|
|
20
|
-
const prunedIdsLower = tracker
|
|
21
|
-
? new Set((state.prunedIds.get(sessionId) ?? []).map(id => id.toLowerCase()))
|
|
22
|
-
: null;
|
|
7
|
+
logger.info("Syncing tool parameters from OpenCode messages");
|
|
8
|
+
state.nudgeCounter = 0;
|
|
23
9
|
for (const msg of messages) {
|
|
24
|
-
if (!msg.parts)
|
|
25
|
-
continue;
|
|
26
10
|
for (const part of msg.parts) {
|
|
27
|
-
if (part.type !== "tool" || !part.callID)
|
|
11
|
+
if (part.type !== "tool" || !part.callID) {
|
|
28
12
|
continue;
|
|
29
|
-
const id = part.callID.toLowerCase();
|
|
30
|
-
// Track tool results for nudge injection
|
|
31
|
-
if (tracker && !tracker.seenToolResultIds.has(id)) {
|
|
32
|
-
tracker.seenToolResultIds.add(id);
|
|
33
|
-
// Only count non-protected tools toward nudge threshold
|
|
34
|
-
// Also skip already-pruned tools to avoid re-counting on restart
|
|
35
|
-
if ((!part.tool || !protectedTools?.has(part.tool)) && !prunedIdsLower?.has(id)) {
|
|
36
|
-
tracker.toolResultCount++;
|
|
37
|
-
}
|
|
38
13
|
}
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
14
|
+
if (part.tool === "prune") {
|
|
15
|
+
state.nudgeCounter = 0;
|
|
16
|
+
}
|
|
17
|
+
else if (!config.strategies.pruneTool.protectedTools.includes(part.tool)) {
|
|
18
|
+
state.nudgeCounter++;
|
|
19
|
+
}
|
|
20
|
+
state.lastToolPrune = part.tool === "prune";
|
|
21
|
+
if (state.toolParameters.has(part.callID)) {
|
|
42
22
|
continue;
|
|
43
|
-
|
|
44
|
-
state.toolParameters.set(
|
|
23
|
+
}
|
|
24
|
+
state.toolParameters.set(part.callID, {
|
|
45
25
|
tool: part.tool,
|
|
46
26
|
parameters: part.state?.input ?? {},
|
|
47
|
-
status,
|
|
48
|
-
error: status === "error" ? part.state
|
|
27
|
+
status: part.state.status,
|
|
28
|
+
error: part.state.status === "error" ? part.state.error : undefined,
|
|
29
|
+
compacted: part.state.status === "completed" && !!part.state.time.compacted,
|
|
49
30
|
});
|
|
50
|
-
synced++;
|
|
51
31
|
}
|
|
52
32
|
}
|
|
33
|
+
// logger.info(`nudgeCounter=${state.nudgeCounter}, lastToolPrune=${state.lastToolPrune}`)
|
|
53
34
|
trimToolParametersCache(state);
|
|
54
|
-
if (logger && synced > 0) {
|
|
55
|
-
logger.debug("tool-cache", "Synced tool parameters from OpenCode", {
|
|
56
|
-
sessionId: sessionId.slice(0, 8),
|
|
57
|
-
synced
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
35
|
}
|
|
61
36
|
catch (error) {
|
|
62
|
-
logger
|
|
63
|
-
sessionId: sessionId.slice(0, 8),
|
|
37
|
+
logger.warn("Failed to sync tool parameters from OpenCode", {
|
|
64
38
|
error: error instanceof Error ? error.message : String(error)
|
|
65
39
|
});
|
|
66
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-cache.js","sourceRoot":"","sources":["../../../lib/state/tool-cache.ts"],"names":[],"mappings":"AAIA,
|
|
1
|
+
{"version":3,"file":"tool-cache.js","sourceRoot":"","sources":["../../../lib/state/tool-cache.ts"],"names":[],"mappings":"AAIA,MAAM,mBAAmB,GAAG,IAAI,CAAA;AAEhC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,KAAmB,EACnB,MAAoB,EACpB,MAAc,EACd,QAAqB;IAErB,IAAI,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAA;QAE7D,KAAK,CAAC,YAAY,GAAG,CAAC,CAAA;QAEtB,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YACzB,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;gBAC3B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACvC,SAAQ;gBACZ,CAAC;gBAED,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBACxB,KAAK,CAAC,YAAY,GAAG,CAAC,CAAA;gBAC1B,CAAC;qBAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzE,KAAK,CAAC,YAAY,EAAE,CAAA;gBACxB,CAAC;gBACD,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,IAAI,KAAK,OAAO,CAAA;gBAE3C,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;oBACxC,SAAQ;gBACZ,CAAC;gBAED,KAAK,CAAC,cAAc,CAAC,GAAG,CACpB,IAAI,CAAC,MAAM,EACX;oBACI,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,UAAU,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;oBACnC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAgC;oBACnD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;oBACnE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS;iBAC9E,CACJ,CAAA;YACL,CAAC;QACL,CAAC;QAED,0FAA0F;QAE1F,uBAAuB,CAAC,KAAK,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,8CAA8C,EAAE;YACxD,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAChE,CAAC,CAAA;IACN,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAmB;IACvD,IAAI,KAAK,CAAC,cAAc,CAAC,IAAI,IAAI,mBAAmB,EAAE,CAAC;QACnD,OAAM;IACV,CAAC;IAED,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;SACvD,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,GAAG,mBAAmB,CAAC,CAAA;IAE9D,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC7B,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACpC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Message, Part } from "@opencode-ai/sdk";
|
|
2
|
+
export interface WithParts {
|
|
3
|
+
info: Message;
|
|
4
|
+
parts: Part[];
|
|
5
|
+
}
|
|
6
|
+
export type ToolStatus = "pending" | "running" | "completed" | "error";
|
|
7
|
+
export interface ToolParameterEntry {
|
|
8
|
+
tool: string;
|
|
9
|
+
parameters: any;
|
|
10
|
+
status?: ToolStatus;
|
|
11
|
+
error?: string;
|
|
12
|
+
compacted?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface SessionStats {
|
|
15
|
+
pruneTokenCounter: number;
|
|
16
|
+
totalPruneTokens: number;
|
|
17
|
+
}
|
|
18
|
+
export interface Prune {
|
|
19
|
+
toolIds: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface SessionState {
|
|
22
|
+
sessionId: string | null;
|
|
23
|
+
isSubAgent: boolean;
|
|
24
|
+
prune: Prune;
|
|
25
|
+
stats: SessionStats;
|
|
26
|
+
toolParameters: Map<string, ToolParameterEntry>;
|
|
27
|
+
nudgeCounter: number;
|
|
28
|
+
lastToolPrune: boolean;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../lib/state/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAEhD,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,IAAI,EAAE,CAAA;CAChB;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAA;AAEtE,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,GAAG,CAAA;IACf,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IACzB,iBAAiB,EAAE,MAAM,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,KAAK;IAClB,OAAO,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,YAAY,CAAA;IACnB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;IAC/C,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,OAAO,CAAA;CACzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../lib/state/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PluginConfig } from "../config";
|
|
2
|
+
import { Logger } from "../logger";
|
|
3
|
+
import type { SessionState, WithParts } from "../state";
|
|
4
|
+
/**
|
|
5
|
+
* Deduplication strategy - prunes older tool calls that have identical
|
|
6
|
+
* tool name and parameters, keeping only the most recent occurrence.
|
|
7
|
+
* Modifies the session state in place to add pruned tool call IDs.
|
|
8
|
+
*/
|
|
9
|
+
export declare const deduplicate: (state: SessionState, logger: Logger, config: PluginConfig, messages: WithParts[]) => void;
|
|
10
|
+
//# sourceMappingURL=deduplication.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deduplication.d.ts","sourceRoot":"","sources":["../../../lib/strategies/deduplication.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAIvD;;;;GAIG;AACH,eAAO,MAAM,WAAW,GACpB,OAAO,YAAY,EACnB,QAAQ,MAAM,EACd,QAAQ,YAAY,EACpB,UAAU,SAAS,EAAE,KACtB,IA4DF,CAAA"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { calculateTokensSaved } from "../utils";
|
|
2
|
+
import { buildToolIdList } from "../messages/utils";
|
|
3
|
+
/**
|
|
4
|
+
* Deduplication strategy - prunes older tool calls that have identical
|
|
5
|
+
* tool name and parameters, keeping only the most recent occurrence.
|
|
6
|
+
* Modifies the session state in place to add pruned tool call IDs.
|
|
7
|
+
*/
|
|
8
|
+
export const deduplicate = (state, logger, config, messages) => {
|
|
9
|
+
if (!config.strategies.deduplication.enabled) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
// Build list of all tool call IDs from messages (chronological order)
|
|
13
|
+
const allToolIds = buildToolIdList(messages);
|
|
14
|
+
if (allToolIds.length === 0) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Filter out IDs already pruned
|
|
18
|
+
const alreadyPruned = new Set(state.prune.toolIds);
|
|
19
|
+
const unprunedIds = allToolIds.filter(id => !alreadyPruned.has(id));
|
|
20
|
+
if (unprunedIds.length === 0) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const protectedTools = config.strategies.deduplication.protectedTools;
|
|
24
|
+
// Group by signature (tool name + normalized parameters)
|
|
25
|
+
const signatureMap = new Map();
|
|
26
|
+
for (const id of unprunedIds) {
|
|
27
|
+
const metadata = state.toolParameters.get(id);
|
|
28
|
+
if (!metadata) {
|
|
29
|
+
logger.warn(`Missing metadata for tool call ID: ${id}`);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
// Skip protected tools
|
|
33
|
+
if (protectedTools.includes(metadata.tool)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const signature = createToolSignature(metadata.tool, metadata.parameters);
|
|
37
|
+
if (!signatureMap.has(signature)) {
|
|
38
|
+
signatureMap.set(signature, []);
|
|
39
|
+
}
|
|
40
|
+
signatureMap.get(signature).push(id);
|
|
41
|
+
}
|
|
42
|
+
// Find duplicates - keep only the most recent (last) in each group
|
|
43
|
+
const newPruneIds = [];
|
|
44
|
+
for (const [, ids] of signatureMap.entries()) {
|
|
45
|
+
if (ids.length > 1) {
|
|
46
|
+
// All except last (most recent) should be pruned
|
|
47
|
+
const idsToRemove = ids.slice(0, -1);
|
|
48
|
+
newPruneIds.push(...idsToRemove);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
state.stats.totalPruneTokens += calculateTokensSaved(messages, newPruneIds);
|
|
52
|
+
if (newPruneIds.length > 0) {
|
|
53
|
+
state.prune.toolIds.push(...newPruneIds);
|
|
54
|
+
logger.debug(`Marked ${newPruneIds.length} duplicate tool calls for pruning`);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function createToolSignature(tool, parameters) {
|
|
58
|
+
if (!parameters) {
|
|
59
|
+
return tool;
|
|
60
|
+
}
|
|
61
|
+
const normalized = normalizeParameters(parameters);
|
|
62
|
+
const sorted = sortObjectKeys(normalized);
|
|
63
|
+
return `${tool}::${JSON.stringify(sorted)}`;
|
|
64
|
+
}
|
|
65
|
+
function normalizeParameters(params) {
|
|
66
|
+
if (typeof params !== 'object' || params === null)
|
|
67
|
+
return params;
|
|
68
|
+
if (Array.isArray(params))
|
|
69
|
+
return params;
|
|
70
|
+
const normalized = {};
|
|
71
|
+
for (const [key, value] of Object.entries(params)) {
|
|
72
|
+
if (value !== undefined && value !== null) {
|
|
73
|
+
normalized[key] = value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return normalized;
|
|
77
|
+
}
|
|
78
|
+
function sortObjectKeys(obj) {
|
|
79
|
+
if (typeof obj !== 'object' || obj === null)
|
|
80
|
+
return obj;
|
|
81
|
+
if (Array.isArray(obj))
|
|
82
|
+
return obj.map(sortObjectKeys);
|
|
83
|
+
const sorted = {};
|
|
84
|
+
for (const key of Object.keys(obj).sort()) {
|
|
85
|
+
sorted[key] = sortObjectKeys(obj[key]);
|
|
86
|
+
}
|
|
87
|
+
return sorted;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=deduplication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deduplication.js","sourceRoot":"","sources":["../../../lib/strategies/deduplication.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/strategies/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/strategies/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SessionState } from "../state";
|
|
2
|
+
import type { Logger } from "../logger";
|
|
3
|
+
import type { PluginConfig } from "../config";
|
|
4
|
+
export interface OnIdleResult {
|
|
5
|
+
prunedCount: number;
|
|
6
|
+
tokensSaved: number;
|
|
7
|
+
prunedIds: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Run the onIdle pruning strategy.
|
|
11
|
+
* This is called when the session transitions to idle state.
|
|
12
|
+
*/
|
|
13
|
+
export declare function runOnIdle(client: any, state: SessionState, logger: Logger, config: PluginConfig, workingDirectory?: string): Promise<void | null>;
|
|
14
|
+
//# sourceMappingURL=on-idle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"on-idle.d.ts","sourceRoot":"","sources":["../../../lib/strategies/on-idle.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAiC,MAAM,UAAU,CAAA;AAC3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAQ7C,MAAM,WAAW,YAAY;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,EAAE,CAAA;CACtB;AAoLD;;;GAGG;AACH,wBAAsB,SAAS,CAC3B,MAAM,EAAE,GAAG,EACX,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,EACpB,gBAAgB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAgHtB"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { buildAnalysisPrompt } from "../prompt";
|
|
3
|
+
import { selectModel } from "../model-selector";
|
|
4
|
+
import { calculateTokensSaved } from "../utils";
|
|
5
|
+
import { findCurrentAgent } from "../messages/utils";
|
|
6
|
+
import { saveSessionState } from "../state/persistence";
|
|
7
|
+
import { sendUnifiedNotification } from "../ui/notification";
|
|
8
|
+
/**
|
|
9
|
+
* Parse messages to extract tool information.
|
|
10
|
+
*/
|
|
11
|
+
function parseMessages(messages, toolParametersCache) {
|
|
12
|
+
const toolCallIds = [];
|
|
13
|
+
const toolMetadata = new Map();
|
|
14
|
+
for (const msg of messages) {
|
|
15
|
+
if (msg.parts) {
|
|
16
|
+
for (const part of msg.parts) {
|
|
17
|
+
if (part.type === "tool" && part.callID) {
|
|
18
|
+
toolCallIds.push(part.callID);
|
|
19
|
+
const cachedData = toolParametersCache.get(part.callID);
|
|
20
|
+
const parameters = cachedData?.parameters ?? part.state?.input ?? {};
|
|
21
|
+
toolMetadata.set(part.callID, {
|
|
22
|
+
tool: part.tool,
|
|
23
|
+
parameters: parameters,
|
|
24
|
+
status: part.state?.status,
|
|
25
|
+
error: part.state?.status === "error" ? part.state.error : undefined
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { toolCallIds, toolMetadata };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Replace pruned tool outputs in messages for LLM analysis.
|
|
35
|
+
*/
|
|
36
|
+
function replacePrunedToolOutputs(messages, prunedIds) {
|
|
37
|
+
if (prunedIds.length === 0)
|
|
38
|
+
return messages;
|
|
39
|
+
const prunedIdsSet = new Set(prunedIds);
|
|
40
|
+
return messages.map(msg => {
|
|
41
|
+
if (!msg.parts)
|
|
42
|
+
return msg;
|
|
43
|
+
return {
|
|
44
|
+
...msg,
|
|
45
|
+
parts: msg.parts.map((part) => {
|
|
46
|
+
if (part.type === 'tool' &&
|
|
47
|
+
part.callID &&
|
|
48
|
+
prunedIdsSet.has(part.callID) &&
|
|
49
|
+
part.state?.output) {
|
|
50
|
+
return {
|
|
51
|
+
...part,
|
|
52
|
+
state: {
|
|
53
|
+
...part.state,
|
|
54
|
+
output: '[Output removed to save context - information superseded or no longer needed]'
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return part;
|
|
59
|
+
})
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Run LLM analysis to determine which tool calls can be pruned.
|
|
65
|
+
*/
|
|
66
|
+
async function runLlmAnalysis(client, state, logger, config, messages, unprunedToolCallIds, alreadyPrunedIds, toolMetadata, workingDirectory) {
|
|
67
|
+
const protectedToolCallIds = [];
|
|
68
|
+
const prunableToolCallIds = unprunedToolCallIds.filter(id => {
|
|
69
|
+
const metadata = toolMetadata.get(id);
|
|
70
|
+
if (metadata && config.strategies.onIdle.protectedTools.includes(metadata.tool)) {
|
|
71
|
+
protectedToolCallIds.push(id);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
});
|
|
76
|
+
if (prunableToolCallIds.length === 0) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
// Get model info from messages
|
|
80
|
+
let validModelInfo = undefined;
|
|
81
|
+
if (messages.length > 0) {
|
|
82
|
+
const lastMessage = messages[messages.length - 1];
|
|
83
|
+
const model = lastMessage.info?.model;
|
|
84
|
+
if (model?.providerID && model?.modelID) {
|
|
85
|
+
validModelInfo = {
|
|
86
|
+
providerID: model.providerID,
|
|
87
|
+
modelID: model.modelID
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const modelSelection = await selectModel(validModelInfo, logger, config.strategies.onIdle.model, workingDirectory);
|
|
92
|
+
logger.info(`OnIdle Model: ${modelSelection.modelInfo.providerID}/${modelSelection.modelInfo.modelID}`, {
|
|
93
|
+
source: modelSelection.source
|
|
94
|
+
});
|
|
95
|
+
if (modelSelection.failedModel && config.strategies.onIdle.showModelErrorToasts) {
|
|
96
|
+
const skipAi = modelSelection.source === 'fallback' && config.strategies.onIdle.strictModelSelection;
|
|
97
|
+
try {
|
|
98
|
+
await client.tui.showToast({
|
|
99
|
+
body: {
|
|
100
|
+
title: skipAi ? "DCP: AI analysis skipped" : "DCP: Model fallback",
|
|
101
|
+
message: skipAi
|
|
102
|
+
? `${modelSelection.failedModel.providerID}/${modelSelection.failedModel.modelID} failed\nAI analysis skipped (strictModelSelection enabled)`
|
|
103
|
+
: `${modelSelection.failedModel.providerID}/${modelSelection.failedModel.modelID} failed\nUsing ${modelSelection.modelInfo.providerID}/${modelSelection.modelInfo.modelID}`,
|
|
104
|
+
variant: "info",
|
|
105
|
+
duration: 5000
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Ignore toast errors
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (modelSelection.source === 'fallback' && config.strategies.onIdle.strictModelSelection) {
|
|
114
|
+
logger.info("Skipping AI analysis (fallback model, strictModelSelection enabled)");
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
const { generateObject } = await import('ai');
|
|
118
|
+
const sanitizedMessages = replacePrunedToolOutputs(messages, alreadyPrunedIds);
|
|
119
|
+
const analysisPrompt = buildAnalysisPrompt(prunableToolCallIds, sanitizedMessages, alreadyPrunedIds, protectedToolCallIds);
|
|
120
|
+
const result = await generateObject({
|
|
121
|
+
model: modelSelection.model,
|
|
122
|
+
schema: z.object({
|
|
123
|
+
pruned_tool_call_ids: z.array(z.string()),
|
|
124
|
+
reasoning: z.string(),
|
|
125
|
+
}),
|
|
126
|
+
prompt: analysisPrompt
|
|
127
|
+
});
|
|
128
|
+
const rawLlmPrunedIds = result.object.pruned_tool_call_ids;
|
|
129
|
+
const llmPrunedIds = rawLlmPrunedIds.filter(id => prunableToolCallIds.includes(id));
|
|
130
|
+
// Always log LLM output as debug
|
|
131
|
+
const reasoning = result.object.reasoning.replace(/\n+/g, ' ').replace(/\s+/g, ' ').trim();
|
|
132
|
+
logger.debug(`OnIdle LLM output`, {
|
|
133
|
+
pruned_tool_call_ids: rawLlmPrunedIds,
|
|
134
|
+
reasoning: reasoning
|
|
135
|
+
});
|
|
136
|
+
return llmPrunedIds;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Run the onIdle pruning strategy.
|
|
140
|
+
* This is called when the session transitions to idle state.
|
|
141
|
+
*/
|
|
142
|
+
export async function runOnIdle(client, state, logger, config, workingDirectory) {
|
|
143
|
+
try {
|
|
144
|
+
if (!state.sessionId) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
const sessionId = state.sessionId;
|
|
148
|
+
// Fetch session info and messages
|
|
149
|
+
const [sessionInfoResponse, messagesResponse] = await Promise.all([
|
|
150
|
+
client.session.get({ path: { id: sessionId } }),
|
|
151
|
+
client.session.messages({ path: { id: sessionId } })
|
|
152
|
+
]);
|
|
153
|
+
const sessionInfo = sessionInfoResponse.data;
|
|
154
|
+
const messages = messagesResponse.data || messagesResponse;
|
|
155
|
+
if (!messages || messages.length < 3) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
const currentAgent = findCurrentAgent(messages);
|
|
159
|
+
const { toolCallIds, toolMetadata } = parseMessages(messages, state.toolParameters);
|
|
160
|
+
const alreadyPrunedIds = state.prune.toolIds;
|
|
161
|
+
const unprunedToolCallIds = toolCallIds.filter(id => !alreadyPrunedIds.includes(id));
|
|
162
|
+
if (unprunedToolCallIds.length === 0) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
// Count prunable tools (excluding protected)
|
|
166
|
+
const candidateCount = unprunedToolCallIds.filter(id => {
|
|
167
|
+
const metadata = toolMetadata.get(id);
|
|
168
|
+
return !metadata || !config.strategies.onIdle.protectedTools.includes(metadata.tool);
|
|
169
|
+
}).length;
|
|
170
|
+
if (candidateCount === 0) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
// Run LLM analysis
|
|
174
|
+
const llmPrunedIds = await runLlmAnalysis(client, state, logger, config, messages, unprunedToolCallIds, alreadyPrunedIds, toolMetadata, workingDirectory);
|
|
175
|
+
const newlyPrunedIds = llmPrunedIds.filter(id => !alreadyPrunedIds.includes(id));
|
|
176
|
+
if (newlyPrunedIds.length === 0) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
// Log the tool IDs being pruned with their tool names
|
|
180
|
+
for (const id of newlyPrunedIds) {
|
|
181
|
+
const metadata = toolMetadata.get(id);
|
|
182
|
+
const toolName = metadata?.tool || 'unknown';
|
|
183
|
+
logger.info(`OnIdle pruning tool: ${toolName}`, { callID: id });
|
|
184
|
+
}
|
|
185
|
+
// Update state
|
|
186
|
+
const allPrunedIds = [...new Set([...alreadyPrunedIds, ...newlyPrunedIds])];
|
|
187
|
+
state.prune.toolIds = allPrunedIds;
|
|
188
|
+
state.stats.pruneTokenCounter += calculateTokensSaved(messages, newlyPrunedIds);
|
|
189
|
+
// Build tool metadata map for notification
|
|
190
|
+
const prunedToolMetadata = new Map();
|
|
191
|
+
for (const id of newlyPrunedIds) {
|
|
192
|
+
const metadata = toolMetadata.get(id);
|
|
193
|
+
if (metadata) {
|
|
194
|
+
prunedToolMetadata.set(id, metadata);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Send notification
|
|
198
|
+
await sendUnifiedNotification(client, logger, config, state, sessionId, newlyPrunedIds, prunedToolMetadata, undefined, // reason
|
|
199
|
+
currentAgent, workingDirectory || "");
|
|
200
|
+
state.stats.totalPruneTokens += state.stats.pruneTokenCounter;
|
|
201
|
+
state.stats.pruneTokenCounter = 0;
|
|
202
|
+
state.nudgeCounter = 0;
|
|
203
|
+
state.lastToolPrune = true;
|
|
204
|
+
// Persist state
|
|
205
|
+
const sessionName = sessionInfo?.title;
|
|
206
|
+
saveSessionState(state, logger, sessionName).catch(err => {
|
|
207
|
+
logger.error("Failed to persist state", { error: err.message });
|
|
208
|
+
});
|
|
209
|
+
logger.info(`OnIdle: Pruned ${newlyPrunedIds.length}/${candidateCount} tools`);
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
logger.error("OnIdle analysis failed", { error: error.message });
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=on-idle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"on-idle.js","sourceRoot":"","sources":["../../../lib/strategies/on-idle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import type { SessionState } from "../state";
|
|
3
|
+
import type { PluginConfig } from "../config";
|
|
4
|
+
import type { Logger } from "../logger";
|
|
5
|
+
export interface PruneToolContext {
|
|
6
|
+
client: any;
|
|
7
|
+
state: SessionState;
|
|
8
|
+
logger: Logger;
|
|
9
|
+
config: PluginConfig;
|
|
10
|
+
workingDirectory: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates the prune tool definition.
|
|
14
|
+
* Accepts numeric IDs from the <prunable-tools> list and prunes those tool outputs.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createPruneTool(ctx: PruneToolContext): ReturnType<typeof tool>;
|
|
17
|
+
//# sourceMappingURL=prune-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune-tool.d.ts","sourceRoot":"","sources":["../../../lib/strategies/prune-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAiC,MAAM,UAAU,CAAA;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAO7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAMvC,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,GAAG,CAAA;IACX,KAAK,EAAE,YAAY,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,YAAY,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;CAC3B;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,GAAG,EAAE,gBAAgB,GACtB,UAAU,CAAC,OAAO,IAAI,CAAC,CAoFzB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import { findCurrentAgent, buildToolIdList, getPruneToolIds } from "../messages/utils";
|
|
3
|
+
import { calculateTokensSaved } from "../utils";
|
|
4
|
+
import { sendUnifiedNotification } from "../ui/notification";
|
|
5
|
+
import { formatPruningResultForTool } from "../ui/display-utils";
|
|
6
|
+
import { ensureSessionInitialized } from "../state";
|
|
7
|
+
import { saveSessionState } from "../state/persistence";
|
|
8
|
+
import { loadPrompt } from "../prompt";
|
|
9
|
+
/** Tool description loaded from prompts/tool.txt */
|
|
10
|
+
const TOOL_DESCRIPTION = loadPrompt("tool");
|
|
11
|
+
/**
|
|
12
|
+
* Creates the prune tool definition.
|
|
13
|
+
* Accepts numeric IDs from the <prunable-tools> list and prunes those tool outputs.
|
|
14
|
+
*/
|
|
15
|
+
export function createPruneTool(ctx) {
|
|
16
|
+
return tool({
|
|
17
|
+
description: TOOL_DESCRIPTION,
|
|
18
|
+
args: {
|
|
19
|
+
ids: tool.schema.array(tool.schema.string()).describe("First element is the reason ('completion', 'noise', 'consolidation'), followed by numeric IDs as strings to prune"),
|
|
20
|
+
},
|
|
21
|
+
async execute(args, toolCtx) {
|
|
22
|
+
const { client, state, logger, config, workingDirectory } = ctx;
|
|
23
|
+
const sessionId = toolCtx.sessionID;
|
|
24
|
+
if (!args.ids || args.ids.length === 0) {
|
|
25
|
+
return "No IDs provided. Check the <prunable-tools> list for available IDs to prune.";
|
|
26
|
+
}
|
|
27
|
+
// Parse reason from first element, numeric IDs from the rest
|
|
28
|
+
const reason = args.ids[0];
|
|
29
|
+
const validReasons = ["completion", "noise", "consolidation"];
|
|
30
|
+
if (typeof reason !== "string" || !validReasons.includes(reason)) {
|
|
31
|
+
return "No valid pruning reason found. Use 'completion', 'noise', or 'consolidation' as the first element.";
|
|
32
|
+
}
|
|
33
|
+
const numericToolIds = args.ids.slice(1)
|
|
34
|
+
.map(id => parseInt(id, 10))
|
|
35
|
+
.filter((n) => !isNaN(n));
|
|
36
|
+
if (numericToolIds.length === 0) {
|
|
37
|
+
return "No numeric IDs provided. Format: [reason, id1, id2, ...] where reason is 'completion', 'noise', or 'consolidation'.";
|
|
38
|
+
}
|
|
39
|
+
await ensureSessionInitialized(ctx.client, state, sessionId, logger);
|
|
40
|
+
// Fetch messages to calculate tokens and find current agent
|
|
41
|
+
const messagesResponse = await client.session.messages({
|
|
42
|
+
path: { id: sessionId }
|
|
43
|
+
});
|
|
44
|
+
const messages = messagesResponse.data || messagesResponse;
|
|
45
|
+
const currentAgent = findCurrentAgent(messages);
|
|
46
|
+
const toolIdList = buildToolIdList(messages);
|
|
47
|
+
const pruneToolIds = getPruneToolIds(numericToolIds, toolIdList);
|
|
48
|
+
state.prune.toolIds.push(...pruneToolIds);
|
|
49
|
+
const toolMetadata = new Map();
|
|
50
|
+
for (const id of pruneToolIds) {
|
|
51
|
+
const toolParameters = state.toolParameters.get(id);
|
|
52
|
+
if (toolParameters) {
|
|
53
|
+
toolMetadata.set(id, toolParameters);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
logger.debug("No metadata found for ID", { id });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
state.stats.pruneTokenCounter += calculateTokensSaved(messages, pruneToolIds);
|
|
60
|
+
await sendUnifiedNotification(client, logger, config, state, sessionId, pruneToolIds, toolMetadata, reason, currentAgent, workingDirectory);
|
|
61
|
+
state.stats.totalPruneTokens += state.stats.pruneTokenCounter;
|
|
62
|
+
state.stats.pruneTokenCounter = 0;
|
|
63
|
+
state.nudgeCounter = 0;
|
|
64
|
+
saveSessionState(state, logger)
|
|
65
|
+
.catch(err => logger.error("Failed to persist state", { error: err.message }));
|
|
66
|
+
return formatPruningResultForTool(pruneToolIds, toolMetadata, workingDirectory);
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=prune-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune-tool.js","sourceRoot":"","sources":["../../../lib/strategies/prune-tool.ts"],"names":[],"mappings":"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"}
|