diff --git a/lib/messages/utils.ts b/lib/messages/utils.ts index 54abbd8..26b2c60 100644 --- a/lib/messages/utils.ts +++ b/lib/messages/utils.ts @@ -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 -} +} \ No newline at end of file diff --git a/lib/prompts/tool.txt b/lib/prompts/tool.txt index 87149f4..2eda4e8 100644 --- a/lib/prompts/tool.txt +++ b/lib/prompts/tool.txt @@ -1,7 +1,7 @@ Prunes tool outputs from context to manage conversation size and reduce noise. ## IMPORTANT: The Prunable List -A `` 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 `` 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 diff --git a/lib/strategies/prune-tool.ts b/lib/strategies/prune-tool.ts index c162e08..c546363 100644 --- a/lib/strategies/prune-tool.ts +++ b/lib/strategies/prune-tool.ts @@ -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" @@ -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 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 list." + } + } + + const pruneToolIds: string[] = numericToolIds.map(index => toolIdList[index]) state.prune.toolIds.push(...pruneToolIds) const toolMetadata = new Map()