Skip to content

Commit 003b25d

Browse files
committed
Replace protected tool callIDs with <protected> placeholder in janitor prompt
1 parent 52284ed commit 003b25d

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

lib/janitor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ export class Janitor {
337337
pruned_tool_call_ids: z.array(z.string()),
338338
reasoning: z.string(),
339339
}),
340-
prompt: buildAnalysisPrompt(prunableToolCallIds, sanitizedMessages, this.protectedTools)
340+
prompt: buildAnalysisPrompt(prunableToolCallIds, sanitizedMessages, this.protectedTools, allPrunedSoFar, protectedToolCallIds)
341341
})
342342

343343
// Filter LLM results to only include IDs that were actually candidates

lib/prompt.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
/**
22
* Minimize message structure for AI analysis - keep only what's needed
33
* to determine if tool calls are obsolete
4+
* Also replaces callIDs of already-pruned tools with "<already-pruned>"
5+
* and protected tools with "<protected>"
46
*/
5-
function minimizeMessages(messages: any[]): any[] {
7+
function minimizeMessages(messages: any[], alreadyPrunedIds?: string[], protectedToolCallIds?: string[]): any[] {
8+
const prunedIdsSet = alreadyPrunedIds ? new Set(alreadyPrunedIds.map(id => id.toLowerCase())) : new Set()
9+
const protectedIdsSet = protectedToolCallIds ? new Set(protectedToolCallIds.map(id => id.toLowerCase())) : new Set()
10+
611
return messages.map(msg => {
712
const minimized: any = {
813
role: msg.info?.role
@@ -29,9 +34,20 @@ function minimizeMessages(messages: any[]): any[] {
2934

3035
// For tool parts, keep what's needed for pruning decisions
3136
if (part.type === 'tool') {
37+
const callIDLower = part.callID?.toLowerCase()
38+
const isAlreadyPruned = prunedIdsSet.has(callIDLower)
39+
const isProtected = protectedIdsSet.has(callIDLower)
40+
41+
let displayCallID = part.callID
42+
if (isAlreadyPruned) {
43+
displayCallID = '<already-pruned>'
44+
} else if (isProtected) {
45+
displayCallID = '<protected>'
46+
}
47+
3248
const toolPart: any = {
3349
type: 'tool',
34-
callID: part.callID,
50+
callID: displayCallID,
3551
tool: part.tool
3652
}
3753

@@ -75,24 +91,26 @@ function minimizeMessages(messages: any[]): any[] {
7591
})
7692
}
7793

78-
export function buildAnalysisPrompt(unprunedToolCallIds: string[], messages: any[], protectedTools: string[]): string {
94+
export function buildAnalysisPrompt(unprunedToolCallIds: string[], messages: any[], protectedTools: string[], alreadyPrunedIds?: string[], protectedToolCallIds?: string[]): string {
7995
const protectedToolsText = protectedTools.length > 0
8096
? `- NEVER prune tool calls from these protected tools: ${protectedTools.join(", ")}\n`
8197
: '';
8298

83-
// Minimize messages to reduce token usage
84-
const minimizedMessages = minimizeMessages(messages)
99+
// Minimize messages to reduce token usage, passing already-pruned and protected IDs for replacement
100+
const minimizedMessages = minimizeMessages(messages, alreadyPrunedIds, protectedToolCallIds)
101+
102+
// Stringify with pretty-printing, then replace escaped newlines with actual newlines
103+
// This makes the logged prompts much more readable
104+
const messagesJson = JSON.stringify(minimizedMessages, null, 2).replace(/\\n/g, '\n')
85105

86106
return `You are a conversation analyzer that identifies obsolete tool outputs in a coding session.
87107
88108
Your task: Analyze the session history and identify tool call IDs whose outputs are NO LONGER RELEVANT to the current conversation context.
89109
90110
Guidelines for identifying obsolete tool calls:
91-
1. Tool outputs that were superseded by newer reads of the same file/resource
92-
2. Exploratory reads that didn't lead to actual edits or meaningful discussion AND were not explicitly requested to be retained
93-
3. Tool calls from >10 turns ago that are no longer referenced and have served their purpose
94-
4. Error outputs that were subsequently fixed
95-
5. Tool calls whose information has been replaced by more recent operations
111+
1. Exploratory reads that didn't lead to actual edits or meaningful discussion AND were not explicitly requested to be retained
112+
2. Tool outputs from debugging/fixing an error that has now been resolved
113+
3. Failed or incorrect tool attempts that were immediately corrected (e.g., reading a file from the wrong path, then reading from the correct path)
96114
97115
DO NOT prune:
98116
${protectedToolsText}
@@ -104,10 +122,14 @@ ${protectedToolsText}
104122
105123
IMPORTANT: Available tool call IDs for analysis: ${unprunedToolCallIds.join(", ")}
106124
107-
You may see additional tool call IDs in the session history below, but those have already been pruned (either by automatic deduplication or previous analysis runs) and their outputs replaced with placeholders. ONLY return IDs from the available list above.
125+
The session history below may contain tool calls with IDs not in the available list above. These are either:
126+
1. Protected tools (marked with callID "<protected>")
127+
2. Already-pruned tools (marked with callID "<already-pruned>")
128+
129+
ONLY return IDs from the available list above.
108130
109131
Session history:
110-
${JSON.stringify(minimizedMessages, null, 2)}
132+
${messagesJson}
111133
112134
You MUST respond with valid JSON matching this exact schema:
113135
{

0 commit comments

Comments
 (0)