Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions lib/messages/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,4 @@ export function buildToolIdList(messages: WithParts[]): string[] {
}
}
return toolIds
}

export function getPruneToolIds(numericToolIds: number[], toolIdList: string[]): string[] {
const pruneToolIds: string[] = []
for (const index of numericToolIds) {
if (!isNaN(index) && index >= 0 && index < toolIdList.length) {
pruneToolIds.push(toolIdList[index])
}
}
return pruneToolIds
}
}
2 changes: 1 addition & 1 deletion lib/prompts/tool.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Prunes tool outputs from context to manage conversation size and reduce noise.

## IMPORTANT: The Prunable List
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.
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.

## CRITICAL: When and How to Prune

Expand Down
19 changes: 17 additions & 2 deletions lib/strategies/prune-tool.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { tool } from "@opencode-ai/plugin"
import type { SessionState, ToolParameterEntry, WithParts } from "../state"
import type { PluginConfig } from "../config"
import { findCurrentAgent, buildToolIdList, getPruneToolIds } from "../messages/utils"
import { findCurrentAgent, buildToolIdList } from "../messages/utils"
import { calculateTokensSaved } from "../utils"
import { PruneReason, sendUnifiedNotification } from "../ui/notification"
import { formatPruningResultForTool } from "../ui/display-utils"
Expand Down Expand Up @@ -70,7 +70,22 @@ export function createPruneTool(

const currentAgent: string | undefined = findCurrentAgent(messages)
const toolIdList: string[] = buildToolIdList(messages)
const pruneToolIds: string[] = getPruneToolIds(numericToolIds, toolIdList)

// Validate that all numeric IDs are within bounds
if (numericToolIds.some(id => id < 0 || id >= toolIdList.length)) {
return "Invalid IDs provided. Only use numeric IDs from the <prunable-tools> list."
}

// Check for protected tools (model hallucinated an ID not in the prunable list)
for (const index of numericToolIds) {
const id = toolIdList[index]
const metadata = state.toolParameters.get(id)
if (metadata && config.strategies.pruneTool.protectedTools.includes(metadata.tool)) {
return "Invalid IDs provided. Only use numeric IDs from the <prunable-tools> list."
}
}

const pruneToolIds: string[] = numericToolIds.map(index => toolIdList[index])
state.prune.toolIds.push(...pruneToolIds)

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