@tuanhung303/opencode-acp 0.0.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.
- package/LICENSE +21 -0
- package/README.md +166 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/commands/budget.d.ts +15 -0
- package/dist/lib/commands/budget.d.ts.map +1 -0
- package/dist/lib/commands/budget.js +120 -0
- package/dist/lib/commands/budget.js.map +1 -0
- package/dist/lib/commands/context.d.ts +49 -0
- package/dist/lib/commands/context.d.ts.map +1 -0
- package/dist/lib/commands/context.js +191 -0
- package/dist/lib/commands/context.js.map +1 -0
- package/dist/lib/commands/help.d.ts +15 -0
- package/dist/lib/commands/help.d.ts.map +1 -0
- package/dist/lib/commands/help.js +28 -0
- package/dist/lib/commands/help.js.map +1 -0
- package/dist/lib/commands/protected.d.ts +17 -0
- package/dist/lib/commands/protected.d.ts.map +1 -0
- package/dist/lib/commands/protected.js +50 -0
- package/dist/lib/commands/protected.js.map +1 -0
- package/dist/lib/commands/stats.d.ts +15 -0
- package/dist/lib/commands/stats.d.ts.map +1 -0
- package/dist/lib/commands/stats.js +64 -0
- package/dist/lib/commands/stats.js.map +1 -0
- package/dist/lib/commands/sweep.d.ts +23 -0
- package/dist/lib/commands/sweep.d.ts.map +1 -0
- package/dist/lib/commands/sweep.js +194 -0
- package/dist/lib/commands/sweep.js.map +1 -0
- package/dist/lib/config-schema.d.ts +119 -0
- package/dist/lib/config-schema.d.ts.map +1 -0
- package/dist/lib/config-schema.js +97 -0
- package/dist/lib/config-schema.js.map +1 -0
- package/dist/lib/config.d.ts +59 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +426 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/hooks.d.ts +31 -0
- package/dist/lib/hooks.d.ts.map +1 -0
- package/dist/lib/hooks.js +230 -0
- package/dist/lib/hooks.js.map +1 -0
- package/dist/lib/logger.d.ts +55 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +230 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/messages/index.d.ts +3 -0
- package/dist/lib/messages/index.d.ts.map +1 -0
- package/dist/lib/messages/index.js +3 -0
- package/dist/lib/messages/index.js.map +1 -0
- package/dist/lib/messages/inject.d.ts +10 -0
- package/dist/lib/messages/inject.d.ts.map +1 -0
- package/dist/lib/messages/inject.js +10 -0
- package/dist/lib/messages/inject.js.map +1 -0
- package/dist/lib/messages/prune.d.ts +13 -0
- package/dist/lib/messages/prune.d.ts.map +1 -0
- package/dist/lib/messages/prune.js +173 -0
- package/dist/lib/messages/prune.js.map +1 -0
- package/dist/lib/messages/utils.d.ts +43 -0
- package/dist/lib/messages/utils.d.ts.map +1 -0
- package/dist/lib/messages/utils.js +262 -0
- package/dist/lib/messages/utils.js.map +1 -0
- package/dist/lib/prompts/discard-tool-spec.d.ts +2 -0
- package/dist/lib/prompts/discard-tool-spec.d.ts.map +1 -0
- package/dist/lib/prompts/discard-tool-spec.js +54 -0
- package/dist/lib/prompts/discard-tool-spec.js.map +1 -0
- package/dist/lib/prompts/extract-tool-spec.d.ts +2 -0
- package/dist/lib/prompts/extract-tool-spec.d.ts.map +1 -0
- package/dist/lib/prompts/extract-tool-spec.js +56 -0
- package/dist/lib/prompts/extract-tool-spec.js.map +1 -0
- package/dist/lib/prompts/index.d.ts +2 -0
- package/dist/lib/prompts/index.d.ts.map +1 -0
- package/dist/lib/prompts/index.js +29 -0
- package/dist/lib/prompts/index.js.map +1 -0
- package/dist/lib/prompts/restore-tool-spec.d.ts +2 -0
- package/dist/lib/prompts/restore-tool-spec.d.ts.map +1 -0
- package/dist/lib/prompts/restore-tool-spec.js +37 -0
- package/dist/lib/prompts/restore-tool-spec.js.map +1 -0
- package/dist/lib/prompts/system/both.d.ts +2 -0
- package/dist/lib/prompts/system/both.d.ts.map +1 -0
- package/dist/lib/prompts/system/both.js +65 -0
- package/dist/lib/prompts/system/both.js.map +1 -0
- package/dist/lib/prompts/system/discard.d.ts +2 -0
- package/dist/lib/prompts/system/discard.d.ts.map +1 -0
- package/dist/lib/prompts/system/discard.js +55 -0
- package/dist/lib/prompts/system/discard.js.map +1 -0
- package/dist/lib/prompts/system/extract.d.ts +2 -0
- package/dist/lib/prompts/system/extract.d.ts.map +1 -0
- package/dist/lib/prompts/system/extract.js +55 -0
- package/dist/lib/prompts/system/extract.js.map +1 -0
- package/dist/lib/protected-file-patterns.d.ts +12 -0
- package/dist/lib/protected-file-patterns.d.ts.map +1 -0
- package/dist/lib/protected-file-patterns.js +69 -0
- package/dist/lib/protected-file-patterns.js.map +1 -0
- package/dist/lib/safe-execute.d.ts +20 -0
- package/dist/lib/safe-execute.d.ts.map +1 -0
- package/dist/lib/safe-execute.js +38 -0
- package/dist/lib/safe-execute.js.map +1 -0
- package/dist/lib/shared-utils.d.ts +4 -0
- package/dist/lib/shared-utils.d.ts.map +1 -0
- package/dist/lib/shared-utils.js +14 -0
- package/dist/lib/shared-utils.js.map +1 -0
- package/dist/lib/state/index.d.ts +4 -0
- package/dist/lib/state/index.d.ts.map +1 -0
- package/dist/lib/state/index.js +4 -0
- package/dist/lib/state/index.js.map +1 -0
- package/dist/lib/state/persistence.d.ts +27 -0
- package/dist/lib/state/persistence.d.ts.map +1 -0
- package/dist/lib/state/persistence.js +165 -0
- package/dist/lib/state/persistence.js.map +1 -0
- package/dist/lib/state/state.d.ts +8 -0
- package/dist/lib/state/state.d.ts.map +1 -0
- package/dist/lib/state/state.js +166 -0
- package/dist/lib/state/state.js.map +1 -0
- package/dist/lib/state/tool-cache.d.ts +15 -0
- package/dist/lib/state/tool-cache.d.ts.map +1 -0
- package/dist/lib/state/tool-cache.js +99 -0
- package/dist/lib/state/tool-cache.js.map +1 -0
- package/dist/lib/state/types.d.ts +83 -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/state/utils.d.ts +2 -0
- package/dist/lib/state/utils.d.ts.map +1 -0
- package/dist/lib/state/utils.js +10 -0
- package/dist/lib/state/utils.js.map +1 -0
- package/dist/lib/strategies/deduplication.d.ts +11 -0
- package/dist/lib/strategies/deduplication.d.ts.map +1 -0
- package/dist/lib/strategies/deduplication.js +178 -0
- package/dist/lib/strategies/deduplication.js.map +1 -0
- package/dist/lib/strategies/index.d.ts +5 -0
- package/dist/lib/strategies/index.d.ts.map +1 -0
- package/dist/lib/strategies/index.js +5 -0
- package/dist/lib/strategies/index.js.map +1 -0
- package/dist/lib/strategies/purge-errors.d.ts +13 -0
- package/dist/lib/strategies/purge-errors.d.ts.map +1 -0
- package/dist/lib/strategies/purge-errors.js +62 -0
- package/dist/lib/strategies/purge-errors.js.map +1 -0
- package/dist/lib/strategies/supersede-writes.d.ts +13 -0
- package/dist/lib/strategies/supersede-writes.d.ts.map +1 -0
- package/dist/lib/strategies/supersede-writes.js +90 -0
- package/dist/lib/strategies/supersede-writes.js.map +1 -0
- package/dist/lib/strategies/tools.d.ts +15 -0
- package/dist/lib/strategies/tools.d.ts.map +1 -0
- package/dist/lib/strategies/tools.js +288 -0
- package/dist/lib/strategies/tools.js.map +1 -0
- package/dist/lib/strategies/utils.d.ts +11 -0
- package/dist/lib/strategies/utils.d.ts.map +1 -0
- package/dist/lib/strategies/utils.js +75 -0
- package/dist/lib/strategies/utils.js.map +1 -0
- package/dist/lib/ui/notification.d.ts +12 -0
- package/dist/lib/ui/notification.d.ts.map +1 -0
- package/dist/lib/ui/notification.js +81 -0
- package/dist/lib/ui/notification.js.map +1 -0
- package/dist/lib/ui/utils.d.ts +10 -0
- package/dist/lib/ui/utils.d.ts.map +1 -0
- package/dist/lib/ui/utils.js +113 -0
- package/dist/lib/ui/utils.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 tarquinen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Agentic Context Pruning Plugin
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@tarquinen/opencode-acp)
|
|
4
|
+
|
|
5
|
+
Automatically reduces token usage in OpenCode by removing obsolete tools from conversation history.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Add to your OpenCode config:
|
|
12
|
+
|
|
13
|
+
```jsonc
|
|
14
|
+
// opencode.jsonc
|
|
15
|
+
{
|
|
16
|
+
"plugin": ["@tarquinen/opencode-acp@latest"],
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Using `@latest` ensures you always get the newest version automatically when OpenCode starts.
|
|
21
|
+
|
|
22
|
+
Restart OpenCode. The plugin will automatically start optimizing your sessions.
|
|
23
|
+
|
|
24
|
+
## How Pruning Works
|
|
25
|
+
|
|
26
|
+
ACP uses multiple tools and strategies to reduce context size:
|
|
27
|
+
|
|
28
|
+
### Tools
|
|
29
|
+
|
|
30
|
+
**Discard** — Exposes a `discard` tool that the AI can call to remove completed or noisy tool content from context.
|
|
31
|
+
|
|
32
|
+
**Extract** — Exposes an `extract` tool that the AI can call to distill valuable context into concise summaries before removing the tool content.
|
|
33
|
+
|
|
34
|
+
### Strategies
|
|
35
|
+
|
|
36
|
+
**Deduplication** — Identifies repeated tool calls (e.g., reading the same file multiple times) and keeps only the most recent output. Runs automatically on every request with zero LLM cost.
|
|
37
|
+
|
|
38
|
+
**Supersede Writes** — Prunes write tool inputs for files that have subsequently been read. When a file is written and later read, the original write content becomes redundant since the current file state is captured in the read result. Runs automatically on every request with zero LLM cost.
|
|
39
|
+
|
|
40
|
+
**Purge Errors** — Prunes tool inputs for tools that returned errors after a configurable number of turns (default: 4). Error messages are preserved for context, but the potentially large input content is removed. Runs automatically on every request with zero LLM cost.
|
|
41
|
+
|
|
42
|
+
Your session history is never modified—ACP replaces pruned content with placeholders before sending requests to your LLM.
|
|
43
|
+
|
|
44
|
+
## Impact on Prompt Caching
|
|
45
|
+
|
|
46
|
+
LLM providers like Anthropic and OpenAI cache prompts based on exact prefix matching. When ACP prunes a tool output, it changes the message content, which invalidates cached prefixes from that point forward.
|
|
47
|
+
|
|
48
|
+
**Trade-off:** You lose some cache read benefits but gain larger token savings from reduced context size and performance improvements through reduced context poisoning. In most cases, the token savings outweigh the cache miss cost—especially in long sessions where context bloat becomes significant.
|
|
49
|
+
|
|
50
|
+
> **Note:** In testing, cache hit rates were approximately 65% with ACP enabled vs 85% without.
|
|
51
|
+
|
|
52
|
+
**Best use case:** Providers that count usage in requests, such as Github Copilot and Google Antigravity have no negative price impact.
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
ACP uses its own config file:
|
|
57
|
+
|
|
58
|
+
- Global: `~/.config/opencode/acp.jsonc` (or `acp.json`), created automatically on first run
|
|
59
|
+
- Custom config directory: `$OPENCODE_CONFIG_DIR/acp.jsonc` (or `acp.json`), if `OPENCODE_CONFIG_DIR` is set
|
|
60
|
+
- Project: `.opencode/acp.jsonc` (or `acp.json`) in your project's `.opencode` directory
|
|
61
|
+
|
|
62
|
+
<details>
|
|
63
|
+
<summary><strong>Default Configuration</strong> (click to expand)</summary>
|
|
64
|
+
|
|
65
|
+
```jsonc
|
|
66
|
+
{
|
|
67
|
+
"$schema": "https://raw.githubusercontent.com/opencode-acp/opencode-acp/master/acp.schema.json",
|
|
68
|
+
// Enable or disable the plugin
|
|
69
|
+
"enabled": true,
|
|
70
|
+
// Enable debug logging to ~/.config/opencode/logs/acp/
|
|
71
|
+
"debug": false,
|
|
72
|
+
// Notification display: "off", "minimal", or "detailed"
|
|
73
|
+
"pruneNotification": "detailed",
|
|
74
|
+
// Slash commands configuration
|
|
75
|
+
"commands": {
|
|
76
|
+
"enabled": true,
|
|
77
|
+
// Additional tools to protect from pruning via commands (e.g., /acp sweep)
|
|
78
|
+
"protectedTools": [],
|
|
79
|
+
},
|
|
80
|
+
// Protect from pruning for <turns> message turns
|
|
81
|
+
"turnProtection": {
|
|
82
|
+
"enabled": false,
|
|
83
|
+
"turns": 4,
|
|
84
|
+
},
|
|
85
|
+
// Protect file operations from pruning via glob patterns
|
|
86
|
+
// Patterns match tool parameters.filePath (e.g. read/write/edit)
|
|
87
|
+
"protectedFilePatterns": [],
|
|
88
|
+
// LLM-driven context pruning tools
|
|
89
|
+
"tools": {
|
|
90
|
+
// Shared settings for all prune tools
|
|
91
|
+
"settings": {
|
|
92
|
+
// Additional tools to protect from pruning
|
|
93
|
+
"protectedTools": [],
|
|
94
|
+
},
|
|
95
|
+
// Removes tool content from context without preservation (for completed tasks or noise)
|
|
96
|
+
"discard": {
|
|
97
|
+
"enabled": true,
|
|
98
|
+
},
|
|
99
|
+
// Distills key findings into preserved knowledge before removing raw content
|
|
100
|
+
"extract": {
|
|
101
|
+
"enabled": true,
|
|
102
|
+
// Show distillation content as an ignored message notification
|
|
103
|
+
"showDistillation": false,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
// Automatic pruning strategies
|
|
107
|
+
"strategies": {
|
|
108
|
+
// Remove duplicate tool calls (same tool with same arguments)
|
|
109
|
+
"deduplication": {
|
|
110
|
+
"enabled": true,
|
|
111
|
+
// Additional tools to protect from pruning
|
|
112
|
+
"protectedTools": [],
|
|
113
|
+
},
|
|
114
|
+
// Prune write tool inputs when the file has been subsequently read
|
|
115
|
+
"supersedeWrites": {
|
|
116
|
+
"enabled": false,
|
|
117
|
+
},
|
|
118
|
+
// Prune tool inputs for errored tools after X turns
|
|
119
|
+
"purgeErrors": {
|
|
120
|
+
"enabled": true,
|
|
121
|
+
// Number of turns before errored tool inputs are pruned
|
|
122
|
+
"turns": 4,
|
|
123
|
+
// Additional tools to protect from pruning
|
|
124
|
+
"protectedTools": [],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
</details>
|
|
131
|
+
|
|
132
|
+
### Commands
|
|
133
|
+
|
|
134
|
+
ACP provides a `/acp` slash command:
|
|
135
|
+
|
|
136
|
+
- `/acp` — Shows available ACP commands
|
|
137
|
+
- `/acp context` — Shows a breakdown of your current session's token usage by category (system, user, assistant, tools, etc.) and how much has been saved through pruning.
|
|
138
|
+
- `/acp stats` — Shows cumulative pruning statistics across all sessions.
|
|
139
|
+
- `/acp sweep` — Prunes all tools since the last user message. Accepts an optional count: `/acp sweep 10` prunes the last 10 tools. Respects `commands.protectedTools`.
|
|
140
|
+
|
|
141
|
+
### Turn Protection
|
|
142
|
+
|
|
143
|
+
When enabled, turn protection prevents tool outputs from being pruned for a configurable number of message turns. This gives the AI time to reference recent tool outputs before they become prunable. Applies to both `discard` and `extract` tools, as well as automatic strategies.
|
|
144
|
+
|
|
145
|
+
### Protected Tools
|
|
146
|
+
|
|
147
|
+
By default, these tools are always protected from pruning across all strategies:
|
|
148
|
+
`task`, `todowrite`, `todoread`, `discard`, `extract`, `batch`, `write`, `edit`, `plan_enter`, `plan_exit`
|
|
149
|
+
|
|
150
|
+
The `protectedTools` arrays in each section add to this default list.
|
|
151
|
+
|
|
152
|
+
### Config Precedence
|
|
153
|
+
|
|
154
|
+
Settings are merged in order:
|
|
155
|
+
Defaults → Global (`~/.config/opencode/acp.jsonc`) → Config Dir (`$OPENCODE_CONFIG_DIR/acp.jsonc`) → Project (`.opencode/acp.jsonc`).
|
|
156
|
+
Each level overrides the previous, so project settings take priority over config-dir and global, which take priority over defaults.
|
|
157
|
+
|
|
158
|
+
Restart OpenCode after making config changes.
|
|
159
|
+
|
|
160
|
+
## Limitations
|
|
161
|
+
|
|
162
|
+
**Subagents** — ACP is disabled for subagents. Subagents are not designed to be token efficient; what matters is that the final message returned to the main agent is a concise summary of findings. ACP's pruning could interfere with this summarization behavior.
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAYjD,QAAA,MAAM,MAAM,EAAE,MAwGK,CAAA;AAEnB,eAAe,MAAM,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { getConfig } from "./lib/config";
|
|
2
|
+
import { Logger } from "./lib/logger";
|
|
3
|
+
import { createSessionState } from "./lib/state";
|
|
4
|
+
import { createDiscardTool, createExtractTool, createRestoreTool } from "./lib/strategies";
|
|
5
|
+
import { createChatMessageTransformHandler, createCommandExecuteHandler, createSystemPromptHandler, createToolExecuteAfterHandler, } from "./lib/hooks";
|
|
6
|
+
const plugin = (async (ctx) => {
|
|
7
|
+
const config = getConfig(ctx);
|
|
8
|
+
if (!config.enabled) {
|
|
9
|
+
return {};
|
|
10
|
+
}
|
|
11
|
+
const logger = new Logger(config.debug);
|
|
12
|
+
const state = createSessionState();
|
|
13
|
+
logger.info("ACP initialized", {
|
|
14
|
+
strategies: config.strategies,
|
|
15
|
+
});
|
|
16
|
+
return {
|
|
17
|
+
"experimental.chat.system.transform": createSystemPromptHandler(state, logger, config),
|
|
18
|
+
"experimental.chat.messages.transform": createChatMessageTransformHandler(ctx.client, state, logger, config),
|
|
19
|
+
"chat.message": async (input, _output) => {
|
|
20
|
+
// Cache variant from real user messages (not synthetic)
|
|
21
|
+
// This avoids scanning all messages to find variant
|
|
22
|
+
state.variant = input.variant;
|
|
23
|
+
logger.debug("Cached variant from chat.message hook", { variant: input.variant });
|
|
24
|
+
},
|
|
25
|
+
"command.execute.before": createCommandExecuteHandler(ctx.client, state, logger, config, ctx.directory),
|
|
26
|
+
"tool.execute.after": createToolExecuteAfterHandler(ctx.client, state, logger, config, ctx.directory),
|
|
27
|
+
tool: {
|
|
28
|
+
...(config.tools.discard.enabled && {
|
|
29
|
+
discard: createDiscardTool({
|
|
30
|
+
client: ctx.client,
|
|
31
|
+
state,
|
|
32
|
+
logger,
|
|
33
|
+
config,
|
|
34
|
+
workingDirectory: ctx.directory,
|
|
35
|
+
}),
|
|
36
|
+
}),
|
|
37
|
+
...(config.tools.extract.enabled && {
|
|
38
|
+
extract: createExtractTool({
|
|
39
|
+
client: ctx.client,
|
|
40
|
+
state,
|
|
41
|
+
logger,
|
|
42
|
+
config,
|
|
43
|
+
workingDirectory: ctx.directory,
|
|
44
|
+
}),
|
|
45
|
+
}),
|
|
46
|
+
restore: createRestoreTool({
|
|
47
|
+
client: ctx.client,
|
|
48
|
+
state,
|
|
49
|
+
logger,
|
|
50
|
+
config,
|
|
51
|
+
workingDirectory: ctx.directory,
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
config: async (opencodeConfig) => {
|
|
55
|
+
if (config.commands.enabled) {
|
|
56
|
+
opencodeConfig.command ??= {};
|
|
57
|
+
opencodeConfig.command["acp"] = {
|
|
58
|
+
template: "",
|
|
59
|
+
description: "Show available ACP commands",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const toolsToAdd = [];
|
|
63
|
+
if (config.tools.discard.enabled)
|
|
64
|
+
toolsToAdd.push("discard");
|
|
65
|
+
if (config.tools.extract.enabled)
|
|
66
|
+
toolsToAdd.push("extract");
|
|
67
|
+
if (toolsToAdd.length > 0) {
|
|
68
|
+
const existingPrimaryTools = opencodeConfig.experimental?.primary_tools ?? [];
|
|
69
|
+
opencodeConfig.experimental = {
|
|
70
|
+
...opencodeConfig.experimental,
|
|
71
|
+
primary_tools: [...existingPrimaryTools, ...toolsToAdd],
|
|
72
|
+
};
|
|
73
|
+
logger.info(`Added ${toolsToAdd.map((t) => `'${t}'`).join(" and ")} to experimental.primary_tools via config mutation`);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
export default plugin;
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACP Budget command handler.
|
|
3
|
+
* Shows context budget, usage, and recommendations.
|
|
4
|
+
*/
|
|
5
|
+
import type { Logger } from "../logger";
|
|
6
|
+
import type { SessionState, WithParts } from "../state";
|
|
7
|
+
export interface BudgetCommandContext {
|
|
8
|
+
client: any;
|
|
9
|
+
state: SessionState;
|
|
10
|
+
logger: Logger;
|
|
11
|
+
sessionId: string;
|
|
12
|
+
messages: WithParts[];
|
|
13
|
+
}
|
|
14
|
+
export declare function handleBudgetCommand(ctx: BudgetCommandContext): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../../lib/commands/budget.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAKvD,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,GAAG,CAAA;IACX,KAAK,EAAE,YAAY,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,SAAS,EAAE,CAAA;CACxB;AAgID,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CASlF"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACP Budget command handler.
|
|
3
|
+
* Shows context budget, usage, and recommendations.
|
|
4
|
+
*/
|
|
5
|
+
import { sendIgnoredMessage } from "../ui/notification";
|
|
6
|
+
import { formatTokenCount } from "../ui/utils";
|
|
7
|
+
import { getCurrentParams } from "../strategies/utils";
|
|
8
|
+
// Estimate tokens from message content (rough approximation)
|
|
9
|
+
function estimateTokens(text) {
|
|
10
|
+
// Rough estimate: 1 token ≈ 4 characters for English text
|
|
11
|
+
return Math.ceil(text.length / 4);
|
|
12
|
+
}
|
|
13
|
+
function calculateContextStats(messages) {
|
|
14
|
+
let systemTokens = 0;
|
|
15
|
+
let userTokens = 0;
|
|
16
|
+
let assistantTokens = 0;
|
|
17
|
+
let toolTokens = 0;
|
|
18
|
+
let toolCount = 0;
|
|
19
|
+
for (const msg of messages) {
|
|
20
|
+
const role = msg.info.role;
|
|
21
|
+
const parts = msg.parts || [];
|
|
22
|
+
for (const part of parts) {
|
|
23
|
+
let text = "";
|
|
24
|
+
if (part.type === "text" && "text" in part && part.text) {
|
|
25
|
+
text = part.text;
|
|
26
|
+
}
|
|
27
|
+
else if (part.type === "tool" &&
|
|
28
|
+
"state" in part &&
|
|
29
|
+
part.state &&
|
|
30
|
+
"output" in part.state &&
|
|
31
|
+
part.state.output) {
|
|
32
|
+
text = part.state.output;
|
|
33
|
+
toolCount++;
|
|
34
|
+
toolTokens += estimateTokens(text);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const tokens = estimateTokens(text);
|
|
38
|
+
if (role === "user") {
|
|
39
|
+
userTokens += tokens;
|
|
40
|
+
}
|
|
41
|
+
else if (role === "assistant") {
|
|
42
|
+
assistantTokens += tokens;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
totalTokens: systemTokens + userTokens + assistantTokens + toolTokens,
|
|
48
|
+
systemTokens,
|
|
49
|
+
userTokens,
|
|
50
|
+
assistantTokens,
|
|
51
|
+
toolTokens,
|
|
52
|
+
toolCount,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function getBatchRecommendation(toolCount) {
|
|
56
|
+
if (toolCount < 20) {
|
|
57
|
+
return "Discard individually as needed";
|
|
58
|
+
}
|
|
59
|
+
else if (toolCount < 50) {
|
|
60
|
+
return "Batch 5-10 tools at a time";
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return "Batch 10-20 tools at a time";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function getPruningRecommendation(stats) {
|
|
67
|
+
const toolRatio = stats.toolCount > 0 ? stats.toolTokens / stats.totalTokens : 0;
|
|
68
|
+
if (toolRatio > 0.6) {
|
|
69
|
+
return "⚠️ Tools dominate context. Consider pruning 10+ tools.";
|
|
70
|
+
}
|
|
71
|
+
else if (stats.totalTokens > 10000) {
|
|
72
|
+
return "💡 Large context. Prune completed tasks to improve performance.";
|
|
73
|
+
}
|
|
74
|
+
else if (stats.toolCount > 30) {
|
|
75
|
+
return "💡 Many tools in context. Review for pruning candidates.";
|
|
76
|
+
}
|
|
77
|
+
return "✅ Context size is healthy.";
|
|
78
|
+
}
|
|
79
|
+
function formatBudgetMessage(state, messages) {
|
|
80
|
+
const lines = [];
|
|
81
|
+
const stats = calculateContextStats(messages);
|
|
82
|
+
lines.push("╭───────────────────────────────────────────────────────────╮");
|
|
83
|
+
lines.push("│ Context Budget │");
|
|
84
|
+
lines.push("╰───────────────────────────────────────────────────────────╯");
|
|
85
|
+
lines.push("");
|
|
86
|
+
// Current usage breakdown
|
|
87
|
+
lines.push("📊 Current Usage:");
|
|
88
|
+
lines.push(` Total: ${formatTokenCount(stats.totalTokens)} tokens`);
|
|
89
|
+
lines.push(` System: ${formatTokenCount(stats.systemTokens)} tokens`);
|
|
90
|
+
lines.push(` User: ${formatTokenCount(stats.userTokens)} tokens`);
|
|
91
|
+
lines.push(` Assistant: ${formatTokenCount(stats.assistantTokens)} tokens`);
|
|
92
|
+
lines.push(` Tools: ${formatTokenCount(stats.toolTokens)} tokens (${stats.toolCount} tools)`);
|
|
93
|
+
lines.push("");
|
|
94
|
+
// Pruning history
|
|
95
|
+
lines.push("✂️ Pruning History:");
|
|
96
|
+
lines.push(` Total tokens saved: ${formatTokenCount(state.stats.totalPruneTokens)}`);
|
|
97
|
+
lines.push(` Total tools pruned: ${state.stats.totalPruneMessages}`);
|
|
98
|
+
lines.push(` Recent discards: ${state.discardHistory.length}`);
|
|
99
|
+
lines.push("");
|
|
100
|
+
// Recommendations
|
|
101
|
+
lines.push("💡 Recommendations:");
|
|
102
|
+
lines.push(` ${getPruningRecommendation(stats)}`);
|
|
103
|
+
lines.push(` Batch size guide: ${getBatchRecommendation(stats.toolCount)}`);
|
|
104
|
+
lines.push("");
|
|
105
|
+
// Quick actions
|
|
106
|
+
lines.push("⚡ Quick Actions:");
|
|
107
|
+
lines.push(" • Run '/acp sweep' to prune since last message");
|
|
108
|
+
lines.push(" • Run '/acp context' for detailed breakdown");
|
|
109
|
+
lines.push(" • Use discard({hashes: [...], reason: 'completion'})");
|
|
110
|
+
lines.push("");
|
|
111
|
+
return lines.join("\n");
|
|
112
|
+
}
|
|
113
|
+
export async function handleBudgetCommand(ctx) {
|
|
114
|
+
const { client, state, logger, sessionId, messages } = ctx;
|
|
115
|
+
const message = formatBudgetMessage(state, messages);
|
|
116
|
+
const params = getCurrentParams(state, messages, logger);
|
|
117
|
+
await sendIgnoredMessage(client, sessionId, message, params, logger);
|
|
118
|
+
logger.info("Budget command executed");
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget.js","sourceRoot":"","sources":["../../../lib/commands/budget.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACP Context Command
|
|
3
|
+
* Shows a visual breakdown of token usage in the current session.
|
|
4
|
+
*
|
|
5
|
+
* TOKEN CALCULATION STRATEGY
|
|
6
|
+
* ==========================
|
|
7
|
+
* We minimize tokenizer estimation by leveraging API-reported values wherever possible.
|
|
8
|
+
*
|
|
9
|
+
* WHAT WE GET FROM THE API (exact):
|
|
10
|
+
* - tokens.input : Input tokens for each assistant response
|
|
11
|
+
* - tokens.output : Output tokens generated (includes text + tool calls)
|
|
12
|
+
* - tokens.reasoning: Reasoning tokens used
|
|
13
|
+
* - tokens.cache : Cache read/write tokens
|
|
14
|
+
*
|
|
15
|
+
* HOW WE CALCULATE EACH CATEGORY:
|
|
16
|
+
*
|
|
17
|
+
* SYSTEM = firstAssistant.input + cache.read - tokenizer(firstUserMessage)
|
|
18
|
+
* The first response's input contains system + first user message.
|
|
19
|
+
*
|
|
20
|
+
* TOOLS = tokenizer(toolInputs + toolOutputs) - prunedTokens
|
|
21
|
+
* We must tokenize tools anyway for pruning decisions.
|
|
22
|
+
*
|
|
23
|
+
* USER = tokenizer(all user messages)
|
|
24
|
+
* User messages are typically small, so estimation is acceptable.
|
|
25
|
+
*
|
|
26
|
+
* ASSISTANT = total - system - user - tools
|
|
27
|
+
* Calculated as residual. This absorbs:
|
|
28
|
+
* - Assistant text output tokens
|
|
29
|
+
* - Reasoning tokens (if persisted by the model)
|
|
30
|
+
* - Any estimation errors
|
|
31
|
+
*
|
|
32
|
+
* TOTAL = input + output + reasoning + cache.read + cache.write
|
|
33
|
+
* Matches opencode's UI display.
|
|
34
|
+
*
|
|
35
|
+
* WHY ASSISTANT IS THE RESIDUAL:
|
|
36
|
+
* If reasoning tokens persist in context (model-dependent), they semantically
|
|
37
|
+
* belong with "Assistant" since reasoning IS assistant-generated content.
|
|
38
|
+
*/
|
|
39
|
+
import type { Logger } from "../logger";
|
|
40
|
+
import type { SessionState, WithParts } from "../state";
|
|
41
|
+
export interface ContextCommandContext {
|
|
42
|
+
client: any;
|
|
43
|
+
state: SessionState;
|
|
44
|
+
logger: Logger;
|
|
45
|
+
sessionId: string;
|
|
46
|
+
messages: WithParts[];
|
|
47
|
+
}
|
|
48
|
+
export declare function handleContextCommand(ctx: ContextCommandContext): Promise<void>;
|
|
49
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../lib/commands/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAQvD,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,GAAG,CAAA;IACX,KAAK,EAAE,YAAY,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,SAAS,EAAE,CAAA;CACxB;AAuLD,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CASpF"}
|