Skip to content

Commit e0ea460

Browse files
committed
fix: cache toolIdList to prevent prune ID mismatch
1 parent 6e12c5a commit e0ea460

File tree

9 files changed

+14
-16
lines changed

9 files changed

+14
-16
lines changed

lib/hooks.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { PluginConfig } from "./config"
44
import { syncToolCache } from "./state/tool-cache"
55
import { deduplicate, supersedeWrites, purgeErrors } from "./strategies"
66
import { prune, insertPruneToolContext } from "./messages"
7+
import { buildToolIdList } from "./messages/utils"
78
import { checkSession } from "./state"
89
import { renderSystemPrompt } from "./prompts"
910
import { handleStatsCommand } from "./commands/stats"
@@ -70,6 +71,7 @@ export function createChatMessageTransformHandler(
7071
}
7172

7273
syncToolCache(state, config, logger, output.messages)
74+
buildToolIdList(state, output.messages, logger)
7375

7476
deduplicate(state, logger, config, output.messages)
7577
supersedeWrites(state, logger, config, output.messages)

lib/messages/inject.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import type { UserMessage } from "@opencode-ai/sdk/v2"
55
import { renderNudge, renderCompressNudge } from "../prompts"
66
import {
77
extractParameterKey,
8-
buildToolIdList,
98
createSyntheticTextPart,
109
createSyntheticToolPart,
1110
isIgnoredUserMessage,
@@ -110,10 +109,9 @@ const buildPrunableToolsList = (
110109
state: SessionState,
111110
config: PluginConfig,
112111
logger: Logger,
113-
messages: WithParts[],
114112
): string => {
115113
const lines: string[] = []
116-
const toolIdList: string[] = buildToolIdList(state, messages, logger)
114+
const toolIdList = state.toolIdList
117115

118116
state.toolParameters.forEach((toolParameterEntry, toolCallId) => {
119117
if (state.prune.toolIds.has(toolCallId)) {
@@ -184,7 +182,7 @@ export const insertPruneToolContext = (
184182
contentParts.push(getCooldownMessage(config))
185183
} else {
186184
if (pruneOrDistillEnabled) {
187-
const prunableToolsList = buildPrunableToolsList(state, config, logger, messages)
185+
const prunableToolsList = buildPrunableToolsList(state, config, logger)
188186
if (prunableToolsList) {
189187
// logger.debug("prunable-tools: \n" + prunableToolsList)
190188
contentParts.push(prunableToolsList)

lib/messages/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ export function buildToolIdList(
245245
}
246246
}
247247
}
248+
state.toolIdList = toolIds
248249
return toolIds
249250
}
250251

lib/state/state.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export function createSessionState(): SessionState {
5757
totalPruneTokens: 0,
5858
},
5959
toolParameters: new Map<string, ToolParameterEntry>(),
60+
toolIdList: [],
6061
nudgeCounter: 0,
6162
lastToolPrune: false,
6263
lastCompaction: 0,
@@ -79,6 +80,7 @@ export function resetSessionState(state: SessionState): void {
7980
totalPruneTokens: 0,
8081
}
8182
state.toolParameters.clear()
83+
state.toolIdList = []
8284
state.nudgeCounter = 0
8385
state.lastToolPrune = false
8486
state.lastCompaction = 0

lib/state/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export interface SessionState {
3838
compressSummaries: CompressSummary[]
3939
stats: SessionStats
4040
toolParameters: Map<string, ToolParameterEntry>
41+
toolIdList: string[]
4142
nudgeCounter: number
4243
lastToolPrune: boolean
4344
lastCompaction: number

lib/strategies/deduplication.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { PluginConfig } from "../config"
22
import { Logger } from "../logger"
33
import type { SessionState, WithParts } from "../state"
4-
import { buildToolIdList } from "../messages/utils"
54
import { getFilePathsFromParameters, isProtected } from "../protected-file-patterns"
65
import { calculateTokensSaved } from "./utils"
76

@@ -20,8 +19,7 @@ export const deduplicate = (
2019
return
2120
}
2221

23-
// Build list of all tool call IDs from messages (chronological order)
24-
const allToolIds = buildToolIdList(state, messages, logger)
22+
const allToolIds = state.toolIdList
2523
if (allToolIds.length === 0) {
2624
return
2725
}

lib/strategies/purge-errors.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { PluginConfig } from "../config"
22
import { Logger } from "../logger"
33
import type { SessionState, WithParts } from "../state"
4-
import { buildToolIdList } from "../messages/utils"
54
import { getFilePathsFromParameters, isProtected } from "../protected-file-patterns"
65
import { calculateTokensSaved } from "./utils"
76

@@ -23,8 +22,7 @@ export const purgeErrors = (
2322
return
2423
}
2524

26-
// Build list of all tool call IDs from messages (chronological order)
27-
const allToolIds = buildToolIdList(state, messages, logger)
25+
const allToolIds = state.toolIdList
2826
if (allToolIds.length === 0) {
2927
return
3028
}

lib/strategies/supersede-writes.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { PluginConfig } from "../config"
22
import { Logger } from "../logger"
33
import type { SessionState, WithParts } from "../state"
4-
import { buildToolIdList } from "../messages/utils"
54
import { getFilePathsFromParameters, isProtected } from "../protected-file-patterns"
65
import { calculateTokensSaved } from "./utils"
76

@@ -23,8 +22,7 @@ export const supersedeWrites = (
2322
return
2423
}
2524

26-
// Build list of all tool call IDs from messages (chronological order)
27-
const allToolIds = buildToolIdList(state, messages, logger)
25+
const allToolIds = state.toolIdList
2826
if (allToolIds.length === 0) {
2927
return
3028
}

lib/tools/prune-shared.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { SessionState, ToolParameterEntry, WithParts } from "../state"
22
import type { PluginConfig } from "../config"
33
import type { Logger } from "../logger"
44
import type { PruneToolContext } from "./types"
5-
import { buildToolIdList } from "../messages/utils"
65
import { syncToolCache } from "../state/tool-cache"
76
import { PruneReason, sendUnifiedNotification } from "../ui/notification"
87
import { formatPruningResultForTool } from "../ui/utils"
@@ -52,14 +51,15 @@ export async function executePruneOperation(
5251
await syncToolCache(state, config, logger, messages)
5352

5453
const currentParams = getCurrentParams(state, messages, logger)
55-
const toolIdList: string[] = buildToolIdList(state, messages, logger)
54+
55+
const toolIdList = state.toolIdList
5656

5757
const validNumericIds: number[] = []
5858
const skippedIds: string[] = []
5959

6060
// Validate and filter IDs
6161
for (const index of numericToolIds) {
62-
// Validate that all numeric IDs are within bounds
62+
// Validate that index is within bounds
6363
if (index < 0 || index >= toolIdList.length) {
6464
logger.debug(`Rejecting prune request - index out of bounds: ${index}`)
6565
skippedIds.push(index.toString())

0 commit comments

Comments
 (0)