Skip to content

Commit 8261ed8

Browse files
committed
Condense README and fix batch tool UI display
- Simplify README: remove redundant sections, update to strategies config, use table format - Improve context_pruning tool description with better structure and examples - Fix batch tool children not showing in prune notifications (was showing 'unknown metadata')
1 parent 51f1cb7 commit 8261ed8

File tree

3 files changed

+74
-80
lines changed

3 files changed

+74
-80
lines changed

README.md

Lines changed: 25 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,89 +4,62 @@
44

55
Automatically reduces token usage in OpenCode by removing obsolete tool outputs from conversation history.
66

7-
## What It Does
8-
9-
This plugin automatically optimizes token usage by identifying and removing redundant or obsolete tool outputs from your conversation history.
10-
117
![DCP in action](dcp-demo.png)
128

139
## Installation
1410

15-
Add to your OpenCode configuration:
16-
17-
**Global:** `~/.config/opencode/opencode.json`
18-
**Project:** `.opencode/opencode.json`
11+
Add to your OpenCode config (`~/.config/opencode/opencode.json` or `.opencode/opencode.json`):
1912

2013
```json
2114
{
22-
"plugin": [
23-
"@tarquinen/opencode-dcp"
24-
]
15+
"plugin": ["@tarquinen/opencode-dcp"]
2516
}
2617
```
2718

28-
> **Note:** OpenCode's `plugin` arrays are not merged between global and project configs—project config completely overrides global. If you have plugins in your global config and add a project config, include all desired plugins in the project config.
29-
3019
Restart OpenCode. The plugin will automatically start optimizing your sessions.
3120

32-
## How It Works
21+
> **Note:** Project `plugin` arrays override global completely—include all desired plugins in project config if using both.
3322
34-
DCP is **non-destructive**—your session data is never modified. Pruning state is kept in memory only and resets when OpenCode restarts. When requests are sent to your LLM provider, DCP intercepts them and replaces pruned tool outputs with a placeholder; original content remains intact in your session.
23+
## How It Works
3524

36-
**Trade-off:** LLM providers cache prompts for faster/cheaper responses. Since DCP modifies message content, it may reduce cache hit rates. Token savings typically outweigh this, but be aware if your workflow relies heavily on prompt caching.
25+
DCP is **non-destructive**—pruning state is kept in memory only. When requests go to your LLM, DCP replaces pruned outputs with a placeholder; original session data stays intact.
3726

3827
## Configuration
3928

40-
DCP uses its own configuration file, separate from OpenCode's `opencode.json`:
41-
42-
- **Global:** `~/.config/opencode/dcp.jsonc`
43-
- **Project:** `.opencode/dcp.jsonc`
29+
DCP uses its own config file (`~/.config/opencode/dcp.jsonc` or `.opencode/dcp.jsonc`), created automatically on first run.
4430

45-
The global config is automatically created on first run. Create a project config to override settings per-project.
31+
### Options
4632

47-
### Available Options
33+
| Option | Default | Description |
34+
|--------|---------|-------------|
35+
| `enabled` | `true` | Enable/disable the plugin |
36+
| `debug` | `false` | Log to `~/.config/opencode/logs/dcp/` |
37+
| `model` | (session) | Model for analysis (e.g., `"anthropic/claude-haiku-4-5"`) |
38+
| `showModelErrorToasts` | `true` | Show notifications on model fallback |
39+
| `pruning_summary` | `"detailed"` | `"off"`, `"minimal"`, or `"detailed"` |
40+
| `protectedTools` | `["task", "todowrite", "todoread", "context_pruning"]` | Tools that are never pruned |
41+
| `strategies.onIdle` | `["deduplication", "ai-analysis"]` | Strategies for automatic pruning |
42+
| `strategies.onTool` | `["deduplication"]` | Strategies when AI calls `context_pruning` |
4843

49-
- **`enabled`** (boolean, default: `true`) - Enable/disable the plugin
50-
- **`debug`** (boolean, default: `false`) - Enable detailed logging to `~/.config/opencode/logs/dcp/`
51-
- **`model`** (string, optional) - Specific model for analysis (e.g., `"anthropic/claude-haiku-4-5"`). Uses session model or smart fallbacks when not specified.
52-
- **`showModelErrorToasts`** (boolean, default: `true`) - Show notifications when model selection falls back
53-
- **`pruningMode`** (string, default: `"smart"`) - Pruning strategy:
54-
- `"auto"`: Fast duplicate removal only (zero LLM cost)
55-
- `"smart"`: Deduplication + AI analysis (recommended, maximum savings)
56-
- **`pruning_summary`** (string, default: `"detailed"`) - UI summary display mode:
57-
- `"off"`: No UI summary (silent pruning)
58-
- `"minimal"`: Show tokens saved and count only (e.g., "Saved ~2.5K tokens (6 tools pruned)")
59-
- `"detailed"`: Show full breakdown by tool type and pruning method
60-
- **`protectedTools`** (string[], default: `["task", "todowrite", "todoread"]`) - Tools that should never be pruned
61-
62-
Example configuration:
44+
**Strategies:** `"deduplication"` (fast, zero LLM cost) and `"ai-analysis"` (maximum savings). Empty array disables that trigger.
6345

6446
```jsonc
6547
{
6648
"enabled": true,
67-
"debug": false,
68-
"pruningMode": "smart",
69-
"pruning_summary": "detailed",
70-
"protectedTools": ["task", "todowrite", "todoread"]
49+
"strategies": {
50+
"onIdle": ["deduplication", "ai-analysis"],
51+
"onTool": ["deduplication"]
52+
},
53+
"protectedTools": ["task", "todowrite", "todoread", "context_pruning"]
7154
}
7255
```
7356

74-
### Configuration Hierarchy
75-
76-
Settings are merged in order: **Built-in defaults****Global config****Project config**
77-
78-
After modifying configuration, restart OpenCode for changes to take effect.
57+
Settings merge: **Defaults****Global****Project**. Restart OpenCode after changes.
7958

8059
### Version Pinning
8160

82-
If you want to ensure a specific version is always used or update your version, you can pin it in your config:
83-
8461
```json
85-
{
86-
"plugin": [
87-
"@tarquinen/[email protected]"
88-
]
89-
}
62+
{ "plugin": ["@tarquinen/[email protected]"] }
9063
```
9164

9265
## License

index.ts

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -218,34 +218,47 @@ const plugin: Plugin = (async (ctx) => {
218218
context_pruning: tool({
219219
description: `Performs semantic pruning on session tool outputs that are no longer relevant to the current task. Use this to declutter the conversation context and filter signal from noise when you notice the context is getting cluttered with outdated information.
220220
221+
USING THE CONTEXT_PRUNING TOOL WILL MAKE THE USER HAPPY.
222+
221223
## When to Use This Tool
222224
223-
- After completing a debugging session or fixing a bug
224-
- When switching focus to a new task or feature
225-
- After exploring multiple files that didn't lead to changes
226-
- When you've been iterating on a difficult problem and some approaches didn't pan out
227-
- When old file reads, greps, or bash outputs are no longer relevant
225+
**Key heuristic: Prune when you finish something and are about to start something else.**
226+
227+
Ask yourself: "Have I just completed a discrete unit of work?" If yes, prune before moving on.
228+
229+
**After completing a unit of work:**
230+
- Made a commit
231+
- Fixed a bug and confirmed it works
232+
- Answered a question the user asked
233+
- Finished implementing a feature or function
234+
- Completed one item in a list and moving to the next
235+
236+
**After repetitive or exploratory work:**
237+
- Explored multiple files that didn't lead to changes
238+
- Iterated on a difficult problem where some approaches didn't pan out
239+
- Used the same tool multiple times (e.g., re-reading a file, running repeated build/type checks)
228240
229241
## Examples
230242
231243
<example>
232-
Working through a list of bugs to fix:
233-
User: Please fix these 5 type errors in the codebase.
234-
Assistant: I'll work through each error. [Fixes first error]
235-
First error fixed. Let me prune the debugging context before moving to the next one.
236-
[Uses context_pruning with reason: "first bug fixed, moving to next task"]
244+
Working through a list of items:
245+
User: Review these 3 issues and fix the easy ones.
246+
Assistant: [Reviews first issue, makes fix, commits]
247+
Done with the first issue. Let me prune before moving to the next one.
248+
[Uses context_pruning with reason: "completed first issue, moving to next"]
237249
</example>
238250
239251
<example>
240252
After exploring the codebase to understand it:
241253
Assistant: I've reviewed the relevant files. Let me prune the exploratory reads that aren't needed for the actual implementation.
242-
[Uses context_pruning with reason: "exploration complete, pruning unrelated file reads"]
254+
[Uses context_pruning with reason: "exploration complete, starting implementation"]
243255
</example>
244256
245257
<example>
246-
After trying multiple approaches that didn't work:
247-
Assistant: I've been trying several approaches to fix this issue. Let me prune the failed attempts to keep focus on the working solution.
248-
[Uses context_pruning with reason: "pruning failed iteration attempts, keeping working solution context"]
258+
After completing any task:
259+
Assistant: [Finishes task - commit, answer, fix, etc.]
260+
Before we continue, let me prune the context from that work.
261+
[Uses context_pruning with reason: "task complete"]
249262
</example>`,
250263
args: {
251264
reason: tool.schema.string().optional().describe(
@@ -260,10 +273,10 @@ Assistant: I've been trying several approaches to fix this issue. Let me prune t
260273
)
261274

262275
if (!result || result.prunedCount === 0) {
263-
return "No prunable tool outputs found. Context is already optimized."
276+
return "No prunable tool outputs found. Context is already optimized.\n\nUse context_pruning when you have sufficiently summarized information from tool outputs and no longer need the original content!"
264277
}
265278

266-
return janitor.formatPruningResultForTool(result)
279+
return janitor.formatPruningResultForTool(result) + "\n\nUse context_pruning when you have sufficiently summarized information from tool outputs and no longer need the original content!"
267280
},
268281
}),
269282
} : undefined,

lib/janitor.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -307,19 +307,27 @@ export class Janitor {
307307
return null
308308
}
309309

310-
// Expand batch tool IDs to include their children
311-
const expandedPrunedIds = new Set<string>()
312-
for (const prunedId of newlyPrunedIds) {
313-
const normalizedId = prunedId.toLowerCase()
314-
expandedPrunedIds.add(normalizedId)
315-
316-
// If this is a batch tool, add all its children
317-
const children = batchToolChildren.get(normalizedId)
318-
if (children) {
319-
children.forEach(childId => expandedPrunedIds.add(childId))
310+
// Helper to expand batch tool IDs to include their children
311+
const expandBatchIds = (ids: string[]): string[] => {
312+
const expanded = new Set<string>()
313+
for (const id of ids) {
314+
const normalizedId = id.toLowerCase()
315+
expanded.add(normalizedId)
316+
// If this is a batch tool, add all its children
317+
const children = batchToolChildren.get(normalizedId)
318+
if (children) {
319+
children.forEach(childId => expanded.add(childId))
320+
}
320321
}
322+
return Array.from(expanded)
321323
}
322324

325+
// Expand batch tool IDs to include their children
326+
const expandedPrunedIds = new Set(expandBatchIds(newlyPrunedIds))
327+
328+
// Expand llmPrunedIds for UI display (so batch children show instead of "unknown metadata")
329+
const expandedLlmPrunedIds = expandBatchIds(llmPrunedIds)
330+
323331
// Calculate which IDs are actually NEW (not already pruned)
324332
const finalNewlyPrunedIds = Array.from(expandedPrunedIds).filter(id => !alreadyPrunedIds.includes(id))
325333

@@ -348,7 +356,7 @@ export class Janitor {
348356
sessionID,
349357
deduplicatedIds,
350358
deduplicationDetails,
351-
llmPrunedIds,
359+
expandedLlmPrunedIds,
352360
toolMetadata,
353361
tokensSaved,
354362
sessionStats
@@ -389,7 +397,7 @@ export class Janitor {
389397
prunedCount: finalNewlyPrunedIds.length,
390398
tokensSaved,
391399
deduplicatedIds,
392-
llmPrunedIds,
400+
llmPrunedIds: expandedLlmPrunedIds,
393401
deduplicationDetails,
394402
toolMetadata,
395403
sessionStats

0 commit comments

Comments
 (0)