@tuanhung303/opencode-acp 2.2.0 → 2.2.1

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.
Files changed (160) hide show
  1. package/README.md +131 -71
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +10 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/commands/budget.d.ts +15 -0
  6. package/dist/lib/commands/budget.d.ts.map +1 -0
  7. package/dist/lib/commands/budget.js +120 -0
  8. package/dist/lib/commands/budget.js.map +1 -0
  9. package/dist/lib/commands/context.d.ts +1 -1
  10. package/dist/lib/commands/context.js +4 -4
  11. package/dist/lib/commands/context.js.map +1 -1
  12. package/dist/lib/commands/help.d.ts.map +1 -1
  13. package/dist/lib/commands/help.js +2 -0
  14. package/dist/lib/commands/help.js.map +1 -1
  15. package/dist/lib/commands/protected.d.ts +17 -0
  16. package/dist/lib/commands/protected.d.ts.map +1 -0
  17. package/dist/lib/commands/protected.js +50 -0
  18. package/dist/lib/commands/protected.js.map +1 -0
  19. package/dist/lib/commands/stats.d.ts +1 -1
  20. package/dist/lib/commands/stats.d.ts.map +1 -1
  21. package/dist/lib/commands/stats.js +24 -4
  22. package/dist/lib/commands/stats.js.map +1 -1
  23. package/dist/lib/commands/sweep.d.ts.map +1 -1
  24. package/dist/lib/commands/sweep.js +5 -2
  25. package/dist/lib/commands/sweep.js.map +1 -1
  26. package/dist/lib/config-schema.d.ts +119 -0
  27. package/dist/lib/config-schema.d.ts.map +1 -0
  28. package/dist/lib/config-schema.js +97 -0
  29. package/dist/lib/config-schema.js.map +1 -0
  30. package/dist/lib/config.d.ts +7 -30
  31. package/dist/lib/config.d.ts.map +1 -1
  32. package/dist/lib/config.js +45 -483
  33. package/dist/lib/config.js.map +1 -1
  34. package/dist/lib/hooks.d.ts +14 -0
  35. package/dist/lib/hooks.d.ts.map +1 -1
  36. package/dist/lib/hooks.js +120 -13
  37. package/dist/lib/hooks.js.map +1 -1
  38. package/dist/lib/logger.d.ts +25 -1
  39. package/dist/lib/logger.d.ts.map +1 -1
  40. package/dist/lib/logger.js +45 -4
  41. package/dist/lib/logger.js.map +1 -1
  42. package/dist/lib/messages/index.d.ts +1 -1
  43. package/dist/lib/messages/index.d.ts.map +1 -1
  44. package/dist/lib/messages/index.js +1 -1
  45. package/dist/lib/messages/index.js.map +1 -1
  46. package/dist/lib/messages/inject.d.ts +6 -1
  47. package/dist/lib/messages/inject.d.ts.map +1 -1
  48. package/dist/lib/messages/inject.js +8 -125
  49. package/dist/lib/messages/inject.js.map +1 -1
  50. package/dist/lib/messages/prune.d.ts +8 -0
  51. package/dist/lib/messages/prune.d.ts.map +1 -1
  52. package/dist/lib/messages/prune.js +89 -2
  53. package/dist/lib/messages/prune.js.map +1 -1
  54. package/dist/lib/messages/utils.d.ts +12 -0
  55. package/dist/lib/messages/utils.d.ts.map +1 -1
  56. package/dist/lib/messages/utils.js +34 -0
  57. package/dist/lib/messages/utils.js.map +1 -1
  58. package/dist/lib/prompts/discard-tool-spec.d.ts +1 -1
  59. package/dist/lib/prompts/discard-tool-spec.d.ts.map +1 -1
  60. package/dist/lib/prompts/discard-tool-spec.js +30 -17
  61. package/dist/lib/prompts/discard-tool-spec.js.map +1 -1
  62. package/dist/lib/prompts/extract-tool-spec.d.ts +1 -1
  63. package/dist/lib/prompts/extract-tool-spec.d.ts.map +1 -1
  64. package/dist/lib/prompts/extract-tool-spec.js +19 -11
  65. package/dist/lib/prompts/extract-tool-spec.js.map +1 -1
  66. package/dist/lib/prompts/index.d.ts.map +1 -1
  67. package/dist/lib/prompts/index.js +2 -7
  68. package/dist/lib/prompts/index.js.map +1 -1
  69. package/dist/lib/prompts/restore-tool-spec.d.ts +2 -0
  70. package/dist/lib/prompts/restore-tool-spec.d.ts.map +1 -0
  71. package/dist/lib/prompts/restore-tool-spec.js +37 -0
  72. package/dist/lib/prompts/restore-tool-spec.js.map +1 -0
  73. package/dist/lib/prompts/system/both.d.ts +1 -1
  74. package/dist/lib/prompts/system/both.d.ts.map +1 -1
  75. package/dist/lib/prompts/system/both.js +20 -16
  76. package/dist/lib/prompts/system/both.js.map +1 -1
  77. package/dist/lib/prompts/system/discard.d.ts +1 -1
  78. package/dist/lib/prompts/system/discard.d.ts.map +1 -1
  79. package/dist/lib/prompts/system/discard.js +19 -16
  80. package/dist/lib/prompts/system/discard.js.map +1 -1
  81. package/dist/lib/prompts/system/extract.d.ts +1 -1
  82. package/dist/lib/prompts/system/extract.d.ts.map +1 -1
  83. package/dist/lib/prompts/system/extract.js +19 -16
  84. package/dist/lib/prompts/system/extract.js.map +1 -1
  85. package/dist/lib/protected-file-patterns.js +1 -1
  86. package/dist/lib/protected-file-patterns.js.map +1 -1
  87. package/dist/lib/safe-execute.d.ts +20 -0
  88. package/dist/lib/safe-execute.d.ts.map +1 -0
  89. package/dist/lib/safe-execute.js +38 -0
  90. package/dist/lib/safe-execute.js.map +1 -0
  91. package/dist/lib/shared-utils.js +1 -1
  92. package/dist/lib/shared-utils.js.map +1 -1
  93. package/dist/lib/state/persistence.d.ts +6 -1
  94. package/dist/lib/state/persistence.d.ts.map +1 -1
  95. package/dist/lib/state/persistence.js +59 -1
  96. package/dist/lib/state/persistence.js.map +1 -1
  97. package/dist/lib/state/state.d.ts.map +1 -1
  98. package/dist/lib/state/state.js +54 -3
  99. package/dist/lib/state/state.js.map +1 -1
  100. package/dist/lib/state/tool-cache.d.ts +2 -0
  101. package/dist/lib/state/tool-cache.d.ts.map +1 -1
  102. package/dist/lib/state/tool-cache.js +34 -12
  103. package/dist/lib/state/tool-cache.js.map +1 -1
  104. package/dist/lib/state/types.d.ts +50 -5
  105. package/dist/lib/state/types.d.ts.map +1 -1
  106. package/dist/lib/strategies/deduplication.d.ts +1 -0
  107. package/dist/lib/strategies/deduplication.d.ts.map +1 -1
  108. package/dist/lib/strategies/deduplication.js +87 -3
  109. package/dist/lib/strategies/deduplication.js.map +1 -1
  110. package/dist/lib/strategies/index.d.ts +1 -5
  111. package/dist/lib/strategies/index.d.ts.map +1 -1
  112. package/dist/lib/strategies/index.js +1 -5
  113. package/dist/lib/strategies/index.js.map +1 -1
  114. package/dist/lib/strategies/purge-errors.d.ts.map +1 -1
  115. package/dist/lib/strategies/purge-errors.js +4 -1
  116. package/dist/lib/strategies/purge-errors.js.map +1 -1
  117. package/dist/lib/strategies/supersede-writes.d.ts.map +1 -1
  118. package/dist/lib/strategies/supersede-writes.js +7 -1
  119. package/dist/lib/strategies/supersede-writes.js.map +1 -1
  120. package/dist/lib/strategies/tools.d.ts +1 -0
  121. package/dist/lib/strategies/tools.d.ts.map +1 -1
  122. package/dist/lib/strategies/tools.js +215 -62
  123. package/dist/lib/strategies/tools.js.map +1 -1
  124. package/dist/lib/ui/notification.d.ts +5 -2
  125. package/dist/lib/ui/notification.d.ts.map +1 -1
  126. package/dist/lib/ui/notification.js +10 -6
  127. package/dist/lib/ui/notification.js.map +1 -1
  128. package/dist/lib/ui/utils.d.ts +3 -3
  129. package/dist/lib/ui/utils.d.ts.map +1 -1
  130. package/dist/lib/ui/utils.js +38 -12
  131. package/dist/lib/ui/utils.js.map +1 -1
  132. package/package.json +7 -12
  133. package/dist/lib/prompts/nudge/both.d.ts +0 -2
  134. package/dist/lib/prompts/nudge/both.d.ts.map +0 -1
  135. package/dist/lib/prompts/nudge/both.js +0 -11
  136. package/dist/lib/prompts/nudge/both.js.map +0 -1
  137. package/dist/lib/prompts/nudge/discard.d.ts +0 -2
  138. package/dist/lib/prompts/nudge/discard.d.ts.map +0 -1
  139. package/dist/lib/prompts/nudge/discard.js +0 -10
  140. package/dist/lib/prompts/nudge/discard.js.map +0 -1
  141. package/dist/lib/prompts/nudge/extract.d.ts +0 -2
  142. package/dist/lib/prompts/nudge/extract.d.ts.map +0 -1
  143. package/dist/lib/prompts/nudge/extract.js +0 -10
  144. package/dist/lib/prompts/nudge/extract.js.map +0 -1
  145. package/dist/lib/strategies/head-tail-truncation.d.ts +0 -15
  146. package/dist/lib/strategies/head-tail-truncation.d.ts.map +0 -1
  147. package/dist/lib/strategies/head-tail-truncation.js +0 -144
  148. package/dist/lib/strategies/head-tail-truncation.js.map +0 -1
  149. package/dist/lib/strategies/placeholder-compression.d.ts +0 -5
  150. package/dist/lib/strategies/placeholder-compression.d.ts.map +0 -1
  151. package/dist/lib/strategies/placeholder-compression.js +0 -148
  152. package/dist/lib/strategies/placeholder-compression.js.map +0 -1
  153. package/dist/lib/strategies/prune-thinking.d.ts +0 -15
  154. package/dist/lib/strategies/prune-thinking.d.ts.map +0 -1
  155. package/dist/lib/strategies/prune-thinking.js +0 -79
  156. package/dist/lib/strategies/prune-thinking.js.map +0 -1
  157. package/dist/lib/strategies/read-consolidation.d.ts +0 -21
  158. package/dist/lib/strategies/read-consolidation.d.ts.map +0 -1
  159. package/dist/lib/strategies/read-consolidation.js +0 -155
  160. package/dist/lib/strategies/read-consolidation.js.map +0 -1
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@tuanhung303/opencode-acp",
4
- "version": "2.2.0",
4
+ "version": "2.2.1",
5
5
  "type": "module",
6
- "description": "OpenCode plugin that optimizes token usage by pruning obsolete tool outputs - Aggressive fork with Head-Tail Truncation, Read Consolidation, Prune Thinking, and Placeholder Compression strategies",
6
+ "description": "OpenCode plugin that optimizes token usage by pruning obsolete tool outputs from conversation context",
7
7
  "main": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "scripts": {
@@ -15,7 +15,6 @@
15
15
  "typecheck": "tsc --noEmit",
16
16
  "test": "vitest run",
17
17
  "test:watch": "vitest",
18
- "test:coverage": "vitest run --coverage",
19
18
  "format": "prettier --write .",
20
19
  "format:check": "prettier --check ."
21
20
  },
@@ -26,20 +25,17 @@
26
25
  "context",
27
26
  "pruning",
28
27
  "optimization",
29
- "tokens",
30
- "aggressive",
31
- "thinking",
32
- "compression"
28
+ "tokens"
33
29
  ],
34
30
  "repository": {
35
31
  "type": "git",
36
- "url": "git+https://github.com/tuanhung303/opencode-agent-context-pruning.git"
32
+ "url": "git+https://github.com/opencode-acp/opencode-acp.git"
37
33
  },
38
34
  "bugs": {
39
- "url": "https://github.com/tuanhung303/opencode-agent-context-pruning/issues"
35
+ "url": "https://github.com/opencode-acp/opencode-acp/issues"
40
36
  },
41
- "homepage": "https://github.com/tuanhung303/opencode-agent-context-pruning#readme",
42
- "author": "tuanhung303",
37
+ "homepage": "https://github.com/opencode-acp/opencode-acp#readme",
38
+ "author": "tarquinen",
43
39
  "license": "MIT",
44
40
  "peerDependencies": {
45
41
  "@opencode-ai/plugin": ">=0.13.7"
@@ -53,7 +49,6 @@
53
49
  "devDependencies": {
54
50
  "@opencode-ai/plugin": "^1.0.143",
55
51
  "@types/node": "^24.10.1",
56
- "@vitest/coverage-v8": "^4.0.18",
57
52
  "prettier": "^3.4.2",
58
53
  "tsx": "^4.21.0",
59
54
  "typescript": "^5.9.3",
@@ -1,2 +0,0 @@
1
- export declare const NUDGE_BOTH = "<instruction name=context_management_required>\n**CRITICAL CONTEXT WARNING:** Your context window is filling with tool outputs. Strict adherence to context hygiene is required.\n\n**Immediate Actions Required:**\n1. **Task Completion:** If a sub-task is complete, decide: use `discard` if no valuable context to preserve (default), or use `extract` if insights are worth keeping.\n2. **Noise Removal:** If you read files or ran commands that yielded no value, use `discard` to remove them.\n3. **Knowledge Preservation:** If you are holding valuable raw data you'll need to reference later, use `extract` to distill the insights and remove the raw entry.\n\n**Protocol:** You should prioritize this cleanup, but do not interrupt a critical atomic operation if one is in progress. Once the immediate step is done, you must perform context management.\n</instruction>";
2
- //# sourceMappingURL=both.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"both.d.ts","sourceRoot":"","sources":["../../../../lib/prompts/nudge/both.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,s2BASR,CAAA"}
@@ -1,11 +0,0 @@
1
- export const NUDGE_BOTH = `<instruction name=context_management_required>
2
- **CRITICAL CONTEXT WARNING:** Your context window is filling with tool outputs. Strict adherence to context hygiene is required.
3
-
4
- **Immediate Actions Required:**
5
- 1. **Task Completion:** If a sub-task is complete, decide: use \`discard\` if no valuable context to preserve (default), or use \`extract\` if insights are worth keeping.
6
- 2. **Noise Removal:** If you read files or ran commands that yielded no value, use \`discard\` to remove them.
7
- 3. **Knowledge Preservation:** If you are holding valuable raw data you'll need to reference later, use \`extract\` to distill the insights and remove the raw entry.
8
-
9
- **Protocol:** You should prioritize this cleanup, but do not interrupt a critical atomic operation if one is in progress. Once the immediate step is done, you must perform context management.
10
- </instruction>`;
11
- //# sourceMappingURL=both.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"both.js","sourceRoot":"","sources":["../../../../lib/prompts/nudge/both.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;eASX,CAAA"}
@@ -1,2 +0,0 @@
1
- export declare const NUDGE_DISCARD = "<instruction name=context_management_required>\n**CRITICAL CONTEXT WARNING:** Your context window is filling with tool outputs. Strict adherence to context hygiene is required.\n\n**Immediate Actions Required:**\n1. **Task Completion:** If a sub-task is complete, use the `discard` tool to remove the tools used.\n2. **Noise Removal:** If you read files or ran commands that yielded no value, use the `discard` tool to remove them.\n\n**Protocol:** You should prioritize this cleanup, but do not interrupt a critical atomic operation if one is in progress. Once the immediate step is done, you must discard unneeded tool outputs.\n</instruction>";
2
- //# sourceMappingURL=discard.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"discard.d.ts","sourceRoot":"","sources":["../../../../lib/prompts/nudge/discard.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,0oBAQX,CAAA"}
@@ -1,10 +0,0 @@
1
- export const NUDGE_DISCARD = `<instruction name=context_management_required>
2
- **CRITICAL CONTEXT WARNING:** Your context window is filling with tool outputs. Strict adherence to context hygiene is required.
3
-
4
- **Immediate Actions Required:**
5
- 1. **Task Completion:** If a sub-task is complete, use the \`discard\` tool to remove the tools used.
6
- 2. **Noise Removal:** If you read files or ran commands that yielded no value, use the \`discard\` tool to remove them.
7
-
8
- **Protocol:** You should prioritize this cleanup, but do not interrupt a critical atomic operation if one is in progress. Once the immediate step is done, you must discard unneeded tool outputs.
9
- </instruction>`;
10
- //# sourceMappingURL=discard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"discard.js","sourceRoot":"","sources":["../../../../lib/prompts/nudge/discard.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;eAQd,CAAA"}
@@ -1,2 +0,0 @@
1
- export declare const NUDGE_EXTRACT = "<instruction name=context_management_required>\n**CRITICAL CONTEXT WARNING:** Your context window is filling with tool outputs. Strict adherence to context hygiene is required.\n\n**Immediate Actions Required:**\n1. **Task Completion:** If you have completed work, extract key findings from the tools used. Scale distillation depth to the value of the content.\n2. **Knowledge Preservation:** If you are holding valuable raw data you'll need to reference later, use the `extract` tool with high-fidelity distillation to preserve the insights and remove the raw entry.\n\n**Protocol:** You should prioritize this cleanup, but do not interrupt a critical atomic operation if one is in progress. Once the immediate step is done, you must extract valuable findings from tool outputs.\n</instruction>";
2
- //# sourceMappingURL=extract.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../../../lib/prompts/nudge/extract.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,gyBAQX,CAAA"}
@@ -1,10 +0,0 @@
1
- export const NUDGE_EXTRACT = `<instruction name=context_management_required>
2
- **CRITICAL CONTEXT WARNING:** Your context window is filling with tool outputs. Strict adherence to context hygiene is required.
3
-
4
- **Immediate Actions Required:**
5
- 1. **Task Completion:** If you have completed work, extract key findings from the tools used. Scale distillation depth to the value of the content.
6
- 2. **Knowledge Preservation:** If you are holding valuable raw data you'll need to reference later, use the \`extract\` tool with high-fidelity distillation to preserve the insights and remove the raw entry.
7
-
8
- **Protocol:** You should prioritize this cleanup, but do not interrupt a critical atomic operation if one is in progress. Once the immediate step is done, you must extract valuable findings from tool outputs.
9
- </instruction>`;
10
- //# sourceMappingURL=extract.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../../../lib/prompts/nudge/extract.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;eAQd,CAAA"}
@@ -1,15 +0,0 @@
1
- import { PluginConfig } from "../config";
2
- import { Logger } from "../logger";
3
- import type { SessionState, WithParts } from "../state";
4
- /**
5
- * Head-Tail Truncation Strategy
6
- *
7
- * Preserves the first 20% (head) and last 30% (tail) of tool outputs,
8
- * removing the middle section which is often less important due to
9
- * the "Lost in the Middle" phenomenon in LLMs.
10
- *
11
- * This preserves real content unlike placeholder compression which
12
- * replaces everything with a generic hint.
13
- */
14
- export declare function headTailTruncation(state: SessionState, logger: Logger, config: PluginConfig, messages: WithParts[]): void;
15
- //# sourceMappingURL=head-tail-truncation.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"head-tail-truncation.d.ts","sourceRoot":"","sources":["../../../lib/strategies/head-tail-truncation.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;AAmDvD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,SAAS,EAAE,GACtB,IAAI,CAiHN"}
@@ -1,144 +0,0 @@
1
- import { isMessageCompacted } from "../shared-utils";
2
- import { countTokens } from "./utils";
3
- /**
4
- * Icon mapping by tool type for truncation markers
5
- */
6
- const TOOL_ICONS = {
7
- // File content
8
- read: "📄",
9
- "pdf-reader_read_pdf": "📄",
10
- // Search results
11
- glob: "🔍",
12
- grep: "🔍",
13
- "ddg-search_search": "🔍",
14
- google_search: "🔍",
15
- // Command output
16
- bash: "💻",
17
- // Web content
18
- webfetch: "🌐",
19
- "url-context-mcp_analyze_urls": "🌐",
20
- "url-context-mcp_google_search": "🌐",
21
- // Data/Excel
22
- excel_read_data_from_excel: "📊",
23
- // Default
24
- default: "📋",
25
- };
26
- /**
27
- * Get the appropriate icon for a tool
28
- */
29
- function getToolIcon(toolName) {
30
- return TOOL_ICONS[toolName] || TOOL_ICONS.default;
31
- }
32
- // Tools that should NEVER be truncated (their output is critical)
33
- const PROTECTED_TOOLS = new Set([
34
- "write",
35
- "edit",
36
- "todowrite",
37
- "todoread",
38
- "discard",
39
- "extract",
40
- "task",
41
- "question",
42
- "batch",
43
- "plan_enter",
44
- "plan_exit",
45
- "skill",
46
- ]);
47
- /**
48
- * Head-Tail Truncation Strategy
49
- *
50
- * Preserves the first 20% (head) and last 30% (tail) of tool outputs,
51
- * removing the middle section which is often less important due to
52
- * the "Lost in the Middle" phenomenon in LLMs.
53
- *
54
- * This preserves real content unlike placeholder compression which
55
- * replaces everything with a generic hint.
56
- */
57
- export function headTailTruncation(state, logger, config, messages) {
58
- const strategyConfig = config.strategies.headTailTruncation;
59
- if (!strategyConfig?.enabled) {
60
- return;
61
- }
62
- const delayTurns = strategyConfig.delayTurns ?? 2;
63
- const headRatio = strategyConfig.headRatio ?? 0.2;
64
- const tailRatio = strategyConfig.tailRatio ?? 0.3;
65
- const minOutputTokens = 200; // Don't truncate small outputs
66
- const additionalProtected = new Set(strategyConfig.protectedTools ?? []);
67
- let totalTokensSaved = 0;
68
- let truncatedCount = 0;
69
- const totalMessages = messages.length;
70
- for (let i = 0; i < messages.length; i++) {
71
- const msg = messages[i];
72
- // Skip compacted messages
73
- if (isMessageCompacted(state, msg)) {
74
- continue;
75
- }
76
- // Calculate turn age (0 = most recent)
77
- const turnAge = totalMessages - 1 - i;
78
- // Skip recent turns
79
- if (turnAge < delayTurns) {
80
- continue;
81
- }
82
- // Process tool parts
83
- const parts = Array.isArray(msg.parts) ? msg.parts : [];
84
- for (const part of parts) {
85
- // Only process tool parts with completed status
86
- if (part.type !== "tool") {
87
- continue;
88
- }
89
- const toolName = part.tool;
90
- const toolState = part.state;
91
- if (!toolName || !toolState)
92
- continue;
93
- // Skip if not completed
94
- if (toolState.status !== "completed") {
95
- continue;
96
- }
97
- // Skip protected tools
98
- if (PROTECTED_TOOLS.has(toolName) || additionalProtected.has(toolName)) {
99
- continue;
100
- }
101
- // Get the output
102
- const output = toolState.output;
103
- if (output === undefined || output === null) {
104
- continue;
105
- }
106
- const outputStr = typeof output === "string" ? output : JSON.stringify(output);
107
- // Skip already truncated outputs
108
- if (outputStr.includes("[...") && outputStr.includes("tokens truncated...]")) {
109
- continue;
110
- }
111
- const outputTokens = countTokens(outputStr);
112
- // Skip small outputs
113
- if (outputTokens < minOutputTokens) {
114
- continue;
115
- }
116
- const icon = getToolIcon(toolName);
117
- // Calculate head and tail sizes in characters
118
- const headSize = Math.floor(outputStr.length * headRatio);
119
- const tailSize = Math.floor(outputStr.length * tailRatio);
120
- // Ensure we're actually truncating something meaningful
121
- if (headSize + tailSize >= outputStr.length) {
122
- continue;
123
- }
124
- const head = outputStr.slice(0, headSize);
125
- const tail = outputStr.slice(-tailSize);
126
- const middleTokens = countTokens(outputStr.slice(headSize, -tailSize));
127
- // Create truncation marker
128
- const marker = `\n\n[...${icon} ${middleTokens} tokens truncated...]\n\n`;
129
- // Replace output with truncated version
130
- toolState.output = head + marker + tail;
131
- const newTokens = countTokens(toolState.output);
132
- const saved = outputTokens - newTokens;
133
- if (saved > 0) {
134
- totalTokensSaved += saved;
135
- truncatedCount++;
136
- }
137
- }
138
- }
139
- if (truncatedCount > 0) {
140
- state.stats.totalPruneTokens += totalTokensSaved;
141
- logger.debug(`Head-tail truncation: truncated ${truncatedCount} tool outputs (estimated ${totalTokensSaved} tokens saved)`);
142
- }
143
- }
144
- //# sourceMappingURL=head-tail-truncation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"head-tail-truncation.js","sourceRoot":"","sources":["../../../lib/strategies/head-tail-truncation.ts"],"names":[],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import { PluginConfig } from "../config";
2
- import { Logger } from "../logger";
3
- import type { SessionState, WithParts } from "../state";
4
- export declare const placeholderCompression: (state: SessionState, logger: Logger, config: PluginConfig, messages: WithParts[]) => void;
5
- //# sourceMappingURL=placeholder-compression.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"placeholder-compression.d.ts","sourceRoot":"","sources":["../../../lib/strategies/placeholder-compression.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;AAyEvD,eAAO,MAAM,sBAAsB,GAC/B,OAAO,YAAY,EACnB,QAAQ,MAAM,EACd,QAAQ,YAAY,EACpB,UAAU,SAAS,EAAE,KACtB,IAuGF,CAAA"}
@@ -1,148 +0,0 @@
1
- import { isMessageCompacted } from "../shared-utils";
2
- import { countTokens } from "./utils";
3
- /**
4
- * Placeholder Compression Strategy
5
- *
6
- * Replaces verbose tool outputs with actionable placeholder hints while preserving
7
- * the tool call structure (name + input) as breadcrumbs for the agent.
8
- *
9
- * This allows the agent to see what actions were taken and re-execute if needed,
10
- * while dramatically reducing context size.
11
- *
12
- * Based on: https://www.hadijaveed.me/2025/11/26/escaping-context-amnesia-ai-agents/
13
- */
14
- // Tool-specific placeholder templates
15
- const PLACEHOLDER_TEMPLATES = {
16
- read: (input) => `[File read previously. Read again if needed: ${input?.filePath || input?.path || 'unknown'}]`,
17
- glob: (input) => `[Glob search completed for pattern: ${input?.pattern || 'unknown'}. Search again if needed]`,
18
- grep: (input) => `[Content search completed for: ${input?.pattern || 'unknown'}. Search again if needed]`,
19
- bash: (input) => `[Command executed: ${truncate(input?.command || input?.description || 'unknown', 80)}. Re-run if needed]`,
20
- webfetch: (input) => `[URL fetched: ${truncate(input?.url || 'unknown', 60)}. Fetch again if needed]`,
21
- "ddg-search_search": (input) => `[Search completed for: ${input?.query || 'unknown'}. Search again for current results]`,
22
- "ddg-search_fetch_content": (input) => `[Content fetched from: ${truncate(input?.url || 'unknown', 60)}]`,
23
- "google_search": (input) => `[Google search completed for: ${input?.query || 'unknown'}. Search again if needed]`,
24
- "context7_query-docs": (input) => `[Docs queried for: ${input?.query || 'unknown'}. Query again if needed]`,
25
- "context7_resolve-library-id": (input) => `[Library resolved: ${input?.libraryName || 'unknown'}. Resolve again if needed]`,
26
- "excel_read_data_from_excel": (input) => `[Excel data read from: ${input?.filepath || 'unknown'}. Read again if needed]`,
27
- "pdf-reader_read_pdf": () => `[PDF content read. Read again if needed]`,
28
- "url-context-mcp_analyze_urls": (input) => `[URLs analyzed. Analyze again if needed: ${truncate(JSON.stringify(input?.urls || []), 60)}]`,
29
- "url-context-mcp_google_search": (input) => `[Search completed for: ${input?.query || 'unknown'}. Search again if needed]`,
30
- list: (input) => `[Directory listed: ${input?.path || 'current'}. List again if needed]`,
31
- codesearch: (input) => `[Code search completed for: ${input?.query || 'unknown'}. Search again if needed]`,
32
- websearch: (input) => `[Web search completed for: ${input?.query || 'unknown'}. Search again if needed]`,
33
- };
34
- // Default placeholder for tools not in the template list
35
- const DEFAULT_PLACEHOLDER = (toolName, input) => {
36
- const inputHint = input ? ` with: ${truncate(JSON.stringify(input), 80)}` : '';
37
- return `[${toolName} executed${inputHint}. Re-run if needed]`;
38
- };
39
- // Tools that should NEVER be compressed (their output is critical)
40
- const PROTECTED_TOOLS = new Set([
41
- 'write',
42
- 'edit',
43
- 'todowrite',
44
- 'todoread',
45
- 'discard',
46
- 'extract',
47
- 'task',
48
- 'question',
49
- 'batch',
50
- 'plan_enter',
51
- 'plan_exit',
52
- 'skill',
53
- ]);
54
- // Tools whose output should be preserved for schema/structure understanding
55
- const SCHEMA_TOOLS = new Set([
56
- 'excel_get_workbook_metadata',
57
- 'excel_get_data_validation_info',
58
- 'word-document-server_get_document_outline',
59
- 'word-document-server_get_document_info',
60
- ]);
61
- function truncate(str, maxLen) {
62
- if (!str)
63
- return 'unknown';
64
- if (str.length <= maxLen)
65
- return str;
66
- return str.slice(0, maxLen - 3) + '...';
67
- }
68
- export const placeholderCompression = (state, logger, config, messages) => {
69
- const compressionConfig = config.strategies.placeholderCompression;
70
- if (!compressionConfig?.enabled) {
71
- return;
72
- }
73
- const delayTurns = compressionConfig.delayTurns ?? 2;
74
- const minOutputTokens = compressionConfig.minOutputTokens ?? 100;
75
- const additionalProtected = new Set(compressionConfig.protectedTools ?? []);
76
- let compressedCount = 0;
77
- let tokensSaved = 0;
78
- // Calculate current turn from messages
79
- const totalMessages = messages.length;
80
- for (let i = 0; i < messages.length; i++) {
81
- const msg = messages[i];
82
- // Skip compacted messages
83
- if (isMessageCompacted(state, msg)) {
84
- continue;
85
- }
86
- // Calculate turn age (0 = most recent)
87
- const turnAge = totalMessages - 1 - i;
88
- // Skip recent turns to preserve cache and allow agent to reference
89
- if (turnAge < delayTurns) {
90
- continue;
91
- }
92
- // Process tool parts
93
- const parts = Array.isArray(msg.parts) ? msg.parts : [];
94
- for (const part of parts) {
95
- // Only process tool parts with completed status
96
- if (part.type !== "tool") {
97
- continue;
98
- }
99
- const toolName = part.tool;
100
- const toolState = part.state;
101
- if (!toolName || !toolState)
102
- continue;
103
- // Skip if not completed (errors handled by purgeErrors)
104
- if (toolState.status !== "completed") {
105
- continue;
106
- }
107
- // Skip protected tools
108
- if (PROTECTED_TOOLS.has(toolName) || additionalProtected.has(toolName)) {
109
- continue;
110
- }
111
- // Skip schema tools
112
- if (SCHEMA_TOOLS.has(toolName)) {
113
- continue;
114
- }
115
- // Get the output
116
- const output = toolState.output;
117
- if (output === undefined || output === null) {
118
- continue;
119
- }
120
- // Calculate output size
121
- const outputStr = typeof output === 'string' ? output : JSON.stringify(output);
122
- const outputTokens = countTokens(outputStr);
123
- // Only compress if output is large enough
124
- if (outputTokens < minOutputTokens) {
125
- continue;
126
- }
127
- // Generate placeholder
128
- const template = PLACEHOLDER_TEMPLATES[toolName];
129
- const placeholder = template
130
- ? template(toolState.input)
131
- : DEFAULT_PLACEHOLDER(toolName, toolState.input);
132
- // Calculate savings
133
- const placeholderTokens = countTokens(placeholder);
134
- const saved = outputTokens - placeholderTokens;
135
- if (saved > 0) {
136
- // Replace output with placeholder
137
- toolState.output = placeholder;
138
- tokensSaved += saved;
139
- compressedCount++;
140
- }
141
- }
142
- }
143
- if (compressedCount > 0) {
144
- state.stats.totalPruneTokens += tokensSaved;
145
- logger.debug(`Placeholder compression: compressed ${compressedCount} tool outputs (estimated ${tokensSaved} tokens saved)`);
146
- }
147
- };
148
- //# sourceMappingURL=placeholder-compression.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"placeholder-compression.js","sourceRoot":"","sources":["../../../lib/strategies/placeholder-compression.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAErC;;;;;;;;;;GAUG;AAEH,sCAAsC;AACtC,MAAM,qBAAqB,GAA2C;IAClE,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,gDAAgD,KAAK,EAAE,QAAQ,IAAI,KAAK,EAAE,IAAI,IAAI,SAAS,GAAG;IAC/G,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,uCAAuC,KAAK,EAAE,OAAO,IAAI,SAAS,2BAA2B;IAC9G,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,kCAAkC,KAAK,EAAE,OAAO,IAAI,SAAS,2BAA2B;IACzG,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,QAAQ,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,EAAE,WAAW,IAAI,SAAS,EAAE,EAAE,CAAC,qBAAqB;IAC3H,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,QAAQ,CAAC,KAAK,EAAE,GAAG,IAAI,SAAS,EAAE,EAAE,CAAC,0BAA0B;IACrG,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,0BAA0B,KAAK,EAAE,KAAK,IAAI,SAAS,qCAAqC;IACxH,0BAA0B,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,0BAA0B,QAAQ,CAAC,KAAK,EAAE,GAAG,IAAI,SAAS,EAAE,EAAE,CAAC,GAAG;IACzG,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,iCAAiC,KAAK,EAAE,KAAK,IAAI,SAAS,2BAA2B;IACjH,qBAAqB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,KAAK,EAAE,KAAK,IAAI,SAAS,0BAA0B;IAC3G,6BAA6B,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,KAAK,EAAE,WAAW,IAAI,SAAS,4BAA4B;IAC3H,4BAA4B,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,0BAA0B,KAAK,EAAE,QAAQ,IAAI,SAAS,yBAAyB;IACxH,qBAAqB,EAAE,GAAG,EAAE,CAAC,0CAA0C;IACvE,8BAA8B,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,4CAA4C,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG;IACzI,+BAA+B,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,0BAA0B,KAAK,EAAE,KAAK,IAAI,SAAS,2BAA2B;IAC1H,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,KAAK,EAAE,IAAI,IAAI,SAAS,yBAAyB;IACxF,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,+BAA+B,KAAK,EAAE,KAAK,IAAI,SAAS,2BAA2B;IAC1G,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,8BAA8B,KAAK,EAAE,KAAK,IAAI,SAAS,2BAA2B;CAC3G,CAAA;AAED,yDAAyD;AACzD,MAAM,mBAAmB,GAAG,CAAC,QAAgB,EAAE,KAAU,EAAE,EAAE;IACzD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC9E,OAAO,IAAI,QAAQ,YAAY,SAAS,qBAAqB,CAAA;AACjE,CAAC,CAAA;AAED,mEAAmE;AACnE,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC5B,OAAO;IACP,MAAM;IACN,WAAW;IACX,UAAU;IACV,SAAS;IACT,SAAS;IACT,MAAM;IACN,UAAU;IACV,OAAO;IACP,YAAY;IACZ,WAAW;IACX,OAAO;CACV,CAAC,CAAA;AAEF,4EAA4E;AAC5E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IACzB,6BAA6B;IAC7B,gCAAgC;IAChC,2CAA2C;IAC3C,wCAAwC;CAC3C,CAAC,CAAA;AAEF,SAAS,QAAQ,CAAC,GAAW,EAAE,MAAc;IACzC,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAA;IAC1B,IAAI,GAAG,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,GAAG,CAAA;IACpC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAA;AAC3C,CAAC;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAClC,KAAmB,EACnB,MAAc,EACd,MAAoB,EACpB,QAAqB,EACjB,EAAE;IACN,MAAM,iBAAiB,GAAG,MAAM,CAAC,UAAU,CAAC,sBAAsB,CAAA;IAElE,IAAI,CAAC,iBAAiB,EAAE,OAAO,EAAE,CAAC;QAC9B,OAAM;IACV,CAAC;IAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,UAAU,IAAI,CAAC,CAAA;IACpD,MAAM,eAAe,GAAG,iBAAiB,CAAC,eAAe,IAAI,GAAG,CAAA;IAChE,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,cAAc,IAAI,EAAE,CAAC,CAAA;IAE3E,IAAI,eAAe,GAAG,CAAC,CAAA;IACvB,IAAI,WAAW,GAAG,CAAC,CAAA;IAEnB,uCAAuC;IACvC,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAA;IAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;QAEvB,0BAA0B;QAC1B,IAAI,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;YACjC,SAAQ;QACZ,CAAC;QAED,uCAAuC;QACvC,MAAM,OAAO,GAAG,aAAa,GAAG,CAAC,GAAG,CAAC,CAAA;QAErC,mEAAmE;QACnE,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;YACvB,SAAQ;QACZ,CAAC;QAED,qBAAqB;QACrB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;QAEvD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,gDAAgD;YAChD,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACvB,SAAQ;YACZ,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAA;YAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAA;YAE5B,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS;gBAAE,SAAQ;YAErC,wDAAwD;YACxD,IAAI,SAAS,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBACnC,SAAQ;YACZ,CAAC;YAED,uBAAuB;YACvB,IAAI,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACrE,SAAQ;YACZ,CAAC;YAED,oBAAoB;YACpB,IAAI,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,SAAQ;YACZ,CAAC;YAED,iBAAiB;YACjB,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAA;YAC/B,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBAC1C,SAAQ;YACZ,CAAC;YAED,wBAAwB;YACxB,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;YAC9E,MAAM,YAAY,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;YAE3C,0CAA0C;YAC1C,IAAI,YAAY,GAAG,eAAe,EAAE,CAAC;gBACjC,SAAQ;YACZ,CAAC;YAED,uBAAuB;YACvB,MAAM,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAA;YAChD,MAAM,WAAW,GAAG,QAAQ;gBACxB,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC;gBAC3B,CAAC,CAAC,mBAAmB,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,CAAA;YAEpD,oBAAoB;YACpB,MAAM,iBAAiB,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;YAClD,MAAM,KAAK,GAAG,YAAY,GAAG,iBAAiB,CAAA;YAE9C,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACZ,kCAAkC;gBAClC,SAAS,CAAC,MAAM,GAAG,WAAW,CAAA;gBAE9B,WAAW,IAAI,KAAK,CAAA;gBACpB,eAAe,EAAE,CAAA;YACrB,CAAC;QACL,CAAC;IACL,CAAC;IAED,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,KAAK,CAAC,gBAAgB,IAAI,WAAW,CAAA;QAC3C,MAAM,CAAC,KAAK,CACR,uCAAuC,eAAe,4BAA4B,WAAW,gBAAgB,CAChH,CAAA;IACL,CAAC;AACL,CAAC,CAAA"}
@@ -1,15 +0,0 @@
1
- import { PluginConfig } from "../config";
2
- import { Logger } from "../logger";
3
- import type { SessionState, WithParts } from "../state";
4
- /**
5
- * Prune Thinking strategy - removes extended thinking tokens from assistant messages
6
- * after they are older than a configurable number of turns.
7
- *
8
- * Thinking tokens (Claude's <thinking> blocks, OpenAI's reasoning field) consume
9
- * significant context but provide no utility after the response is generated.
10
- *
11
- * This strategy strips thinking content from older messages to save context space.
12
- * Recent turns are preserved to maintain cache efficiency.
13
- */
14
- export declare const pruneThinking: (state: SessionState, logger: Logger, config: PluginConfig, messages: WithParts[]) => void;
15
- //# sourceMappingURL=prune-thinking.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prune-thinking.d.ts","sourceRoot":"","sources":["../../../lib/strategies/prune-thinking.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;AAEvD;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,GACtB,OAAO,YAAY,EACnB,QAAQ,MAAM,EACd,QAAQ,YAAY,EACpB,UAAU,SAAS,EAAE,KACtB,IA2EF,CAAA"}
@@ -1,79 +0,0 @@
1
- /**
2
- * Prune Thinking strategy - removes extended thinking tokens from assistant messages
3
- * after they are older than a configurable number of turns.
4
- *
5
- * Thinking tokens (Claude's <thinking> blocks, OpenAI's reasoning field) consume
6
- * significant context but provide no utility after the response is generated.
7
- *
8
- * This strategy strips thinking content from older messages to save context space.
9
- * Recent turns are preserved to maintain cache efficiency.
10
- */
11
- export const pruneThinking = (state, logger, config, messages) => {
12
- if (!config.strategies.pruneThinking?.enabled) {
13
- return;
14
- }
15
- const delayTurns = config.strategies.pruneThinking.delayTurns ?? 1;
16
- let prunedCount = 0;
17
- let tokensSaved = 0;
18
- for (let i = 0; i < messages.length; i++) {
19
- const msg = messages[i];
20
- // Only process assistant messages
21
- if (msg.info.role !== "assistant") {
22
- continue;
23
- }
24
- // Calculate turn age (messages are in chronological order)
25
- // Use message index as a proxy for turn age
26
- const turnAge = messages.length - 1 - i;
27
- // Skip recent turns to preserve cache
28
- if (turnAge < delayTurns) {
29
- continue;
30
- }
31
- // Handle array content (parts array)
32
- if (Array.isArray(msg.parts)) {
33
- const originalLength = msg.parts.length;
34
- // Filter out thinking blocks
35
- msg.parts = msg.parts.filter((part) => {
36
- // Anthropic thinking block format
37
- if (part.type === "thinking") {
38
- tokensSaved += estimateTokens(part.thinking || "");
39
- return false;
40
- }
41
- // Text part that contains thinking tags
42
- if (part.type === "text" && typeof part.text === "string") {
43
- const thinkingMatch = part.text.match(/<thinking>[\s\S]*?<\/thinking>/g);
44
- if (thinkingMatch) {
45
- for (const match of thinkingMatch) {
46
- tokensSaved += estimateTokens(match);
47
- }
48
- part.text = part.text.replace(/<thinking>[\s\S]*?<\/thinking>/g, "").trim();
49
- // Remove empty text parts
50
- if (!part.text) {
51
- return false;
52
- }
53
- }
54
- }
55
- return true;
56
- });
57
- if (msg.parts.length < originalLength) {
58
- prunedCount++;
59
- }
60
- }
61
- // Handle OpenAI reasoning field on the info object
62
- if (msg.info.reasoning) {
63
- tokensSaved += estimateTokens(msg.info.reasoning);
64
- delete msg.info.reasoning;
65
- prunedCount++;
66
- }
67
- }
68
- if (prunedCount > 0) {
69
- state.stats.totalPruneTokens += tokensSaved;
70
- logger.debug(`Pruned thinking tokens from ${prunedCount} messages (estimated ${tokensSaved} tokens saved)`);
71
- }
72
- };
73
- /**
74
- * Rough token estimation (1 token ≈ 4 characters for English text)
75
- */
76
- function estimateTokens(text) {
77
- return Math.ceil(text.length / 4);
78
- }
79
- //# sourceMappingURL=prune-thinking.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prune-thinking.js","sourceRoot":"","sources":["../../../lib/strategies/prune-thinking.ts"],"names":[],"mappings":"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"}
@@ -1,21 +0,0 @@
1
- import { PluginConfig } from "../config";
2
- import { Logger } from "../logger";
3
- import type { SessionState, WithParts } from "../state";
4
- /**
5
- * Read Consolidation Strategy
6
- *
7
- * When the same tool+parameter is called multiple times, older outputs
8
- * are replaced with pointers to the newer output (which has current state).
9
- *
10
- * This is different from deduplication:
11
- * - Deduplication removes exact duplicate calls entirely
12
- * - Consolidation keeps both calls visible as breadcrumbs, but only the
13
- * newest one has the full output
14
- *
15
- * Rationale:
16
- * - When same file is read multiple times, older reads become stale
17
- * - Newer read has current file state (may have been modified)
18
- * - Keep full output on newer read, pointer on older read
19
- */
20
- export declare function readConsolidation(state: SessionState, logger: Logger, config: PluginConfig, messages: WithParts[]): void;
21
- //# sourceMappingURL=read-consolidation.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"read-consolidation.d.ts","sourceRoot":"","sources":["../../../lib/strategies/read-consolidation.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,EAAsB,MAAM,UAAU,CAAA;AAe3E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,SAAS,EAAE,GACtB,IAAI,CAgKN"}