Skip to content

Commit 83e4703

Browse files
authored
Merge pull request #136 from Opencode-DCP/fix/protected-tool-pruning
fix: prevent protected tools from being pruned
2 parents cecaff1 + 551f0d8 commit 83e4703

File tree

3 files changed

+19
-14
lines changed

3 files changed

+19
-14
lines changed

lib/messages/utils.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,4 @@ export function buildToolIdList(messages: WithParts[]): string[] {
101101
}
102102
}
103103
return toolIds
104-
}
105-
106-
export function getPruneToolIds(numericToolIds: number[], toolIdList: string[]): string[] {
107-
const pruneToolIds: string[] = []
108-
for (const index of numericToolIds) {
109-
if (!isNaN(index) && index >= 0 && index < toolIdList.length) {
110-
pruneToolIds.push(toolIdList[index])
111-
}
112-
}
113-
return pruneToolIds
114-
}
104+
}

lib/prompts/tool.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Prunes tool outputs from context to manage conversation size and reduce noise.
22

33
## IMPORTANT: The Prunable List
4-
A `<prunable-tools>` list is injected into user messages showing available tool outputs you can prune. Each line has the format `ID: tool, parameter` (e.g., `20: read, /path/to/file.ts`). Use these numeric IDs to select which tools to prune.
4+
A `<prunable-tools>` list is injected into user messages showing available tool outputs you can prune. Each line has the format `ID: tool, parameter` (e.g., `20: read, /path/to/file.ts`). You MUST only use numeric IDs that appear in this list to select which tools to prune.
55

66
## CRITICAL: When and How to Prune
77

lib/strategies/prune-tool.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { tool } from "@opencode-ai/plugin"
22
import type { SessionState, ToolParameterEntry, WithParts } from "../state"
33
import type { PluginConfig } from "../config"
4-
import { findCurrentAgent, buildToolIdList, getPruneToolIds } from "../messages/utils"
4+
import { findCurrentAgent, buildToolIdList } from "../messages/utils"
55
import { calculateTokensSaved } from "../utils"
66
import { PruneReason, sendUnifiedNotification } from "../ui/notification"
77
import { formatPruningResultForTool } from "../ui/display-utils"
@@ -70,7 +70,22 @@ export function createPruneTool(
7070

7171
const currentAgent: string | undefined = findCurrentAgent(messages)
7272
const toolIdList: string[] = buildToolIdList(messages)
73-
const pruneToolIds: string[] = getPruneToolIds(numericToolIds, toolIdList)
73+
74+
// Validate that all numeric IDs are within bounds
75+
if (numericToolIds.some(id => id < 0 || id >= toolIdList.length)) {
76+
return "Invalid IDs provided. Only use numeric IDs from the <prunable-tools> list."
77+
}
78+
79+
// Check for protected tools (model hallucinated an ID not in the prunable list)
80+
for (const index of numericToolIds) {
81+
const id = toolIdList[index]
82+
const metadata = state.toolParameters.get(id)
83+
if (metadata && config.strategies.pruneTool.protectedTools.includes(metadata.tool)) {
84+
return "Invalid IDs provided. Only use numeric IDs from the <prunable-tools> list."
85+
}
86+
}
87+
88+
const pruneToolIds: string[] = numericToolIds.map(index => toolIdList[index])
7489
state.prune.toolIds.push(...pruneToolIds)
7590

7691
const toolMetadata = new Map<string, ToolParameterEntry>()

0 commit comments

Comments
 (0)