Skip to content

Commit d916429

Browse files
committed
Remove unused variables to fix TypeScript diagnostics
1 parent e37e15e commit d916429

File tree

2 files changed

+150
-21
lines changed

2 files changed

+150
-21
lines changed

index.ts

Lines changed: 104 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -105,33 +105,41 @@ const plugin: Plugin = (async (ctx) => {
105105
// Cache tool parameters for janitor metadata
106106
cacheToolParameters(body.messages, "global-fetch")
107107

108+
// Always save wrapped context if debug is enabled (even when no tool messages)
109+
// This captures janitor's AI inference which has messageCount=1 (just prompt)
110+
const shouldLogAllRequests = logger.enabled
111+
108112
// Check for tool messages that might need pruning
109113
const toolMessages = body.messages.filter((m: any) => m.role === 'tool')
114+
115+
// Collect all pruned IDs across all sessions (excluding subagents)
116+
// This is safe because tool_call_ids are globally unique
117+
const allSessions = await ctx.client.session.list()
118+
const allPrunedIds = new Set<string>()
119+
120+
if (allSessions.data) {
121+
for (const session of allSessions.data) {
122+
// Skip subagent sessions (don't log - it's normal and would spam logs)
123+
if (session.parentID) {
124+
continue
125+
}
126+
127+
const prunedIds = await stateManager.get(session.id)
128+
prunedIds.forEach(id => allPrunedIds.add(id))
129+
}
130+
}
131+
132+
// Only process tool message replacement if there are tool messages
110133
if (toolMessages.length > 0) {
111134
logger.debug("global-fetch", "Found tool messages in request", {
112135
toolMessageCount: toolMessages.length,
113136
toolCallIds: toolMessages.map((m: any) => m.tool_call_id).slice(0, 5)
114137
})
115-
116-
// Collect all pruned IDs across all sessions (excluding subagents)
117-
// This is safe because tool_call_ids are globally unique
118-
const allSessions = await ctx.client.session.list()
119-
const allPrunedIds = new Set<string>()
120-
121-
if (allSessions.data) {
122-
for (const session of allSessions.data) {
123-
// Skip subagent sessions (don't log - it's normal and would spam logs)
124-
if (session.parentID) {
125-
continue
126-
}
127-
128-
const prunedIds = await stateManager.get(session.id)
129-
prunedIds.forEach(id => allPrunedIds.add(id))
130-
}
131-
}
132-
138+
133139
if (allPrunedIds.size > 0) {
134140
let replacedCount = 0
141+
const originalMessages = JSON.parse(JSON.stringify(body.messages)) // Deep copy for logging
142+
135143
body.messages = body.messages.map((m: any) => {
136144
// Normalize ID to lowercase for case-insensitive matching
137145
if (m.role === 'tool' && allPrunedIds.has(m.tool_call_id?.toLowerCase())) {
@@ -151,10 +159,75 @@ const plugin: Plugin = (async (ctx) => {
151159
totalMessages: body.messages.length
152160
})
153161

162+
// Save wrapped context to file if debug is enabled
163+
await logger.saveWrappedContext(
164+
"global", // Use "global" as session ID since we don't know which session this is
165+
body.messages,
166+
{
167+
url: typeof input === 'string' ? input : 'URL object',
168+
totalPrunedIds: allPrunedIds.size,
169+
replacedCount,
170+
totalMessages: body.messages.length,
171+
originalMessageCount: originalMessages.length
172+
}
173+
)
174+
154175
// Update the request body with modified messages
155176
init.body = JSON.stringify(body)
177+
} else if (shouldLogAllRequests) {
178+
// Log even when no replacements occurred (tool messages exist but none were pruned)
179+
await logger.saveWrappedContext(
180+
"global",
181+
body.messages,
182+
{
183+
url: typeof input === 'string' ? input : 'URL object',
184+
totalPrunedIds: allPrunedIds.size,
185+
replacedCount: 0,
186+
totalMessages: body.messages.length,
187+
toolMessageCount: toolMessages.length,
188+
note: "Tool messages exist but none were replaced"
189+
}
190+
)
156191
}
192+
} else if (shouldLogAllRequests) {
193+
// Log when tool messages exist but no pruned IDs exist yet
194+
await logger.saveWrappedContext(
195+
"global",
196+
body.messages,
197+
{
198+
url: typeof input === 'string' ? input : 'URL object',
199+
totalPrunedIds: 0,
200+
replacedCount: 0,
201+
totalMessages: body.messages.length,
202+
toolMessageCount: toolMessages.length,
203+
note: "No pruned IDs exist yet"
204+
}
205+
)
157206
}
207+
} else if (shouldLogAllRequests) {
208+
// Log requests with NO tool messages (e.g., janitor's shadow inference)
209+
// Detect if this is a janitor request by checking the prompt content
210+
const isJanitorRequest = body.messages.length === 1 &&
211+
body.messages[0]?.role === 'user' &&
212+
typeof body.messages[0]?.content === 'string' &&
213+
body.messages[0].content.includes('conversation analyzer that identifies obsolete tool outputs')
214+
215+
const sessionId = isJanitorRequest ? "janitor-shadow" : "global"
216+
217+
await logger.saveWrappedContext(
218+
sessionId,
219+
body.messages,
220+
{
221+
url: typeof input === 'string' ? input : 'URL object',
222+
totalPrunedIds: allPrunedIds.size,
223+
replacedCount: 0,
224+
totalMessages: body.messages.length,
225+
toolMessageCount: 0,
226+
note: isJanitorRequest
227+
? "Janitor shadow inference with embedded session history in prompt"
228+
: "No tool messages in request (likely title generation or other inference)"
229+
}
230+
)
158231
}
159232
}
160233
} catch (e) {
@@ -363,6 +436,19 @@ const plugin: Plugin = (async (ctx) => {
363436
toolCallIds: remainingToolMessages.map((m: any) => m.tool_call_id)
364437
})
365438

439+
// Save wrapped context to file if debug is enabled
440+
await logger.saveWrappedContext(
441+
sessionId,
442+
body.messages,
443+
{
444+
url: typeof fetchInput === 'string' ? fetchInput : 'URL object',
445+
totalMessages: originalMessageCount,
446+
replacedCount: prunedThisRequest,
447+
prunedIds,
448+
wrapper: 'session-specific'
449+
}
450+
)
451+
366452
// Update the request body with modified messages
367453
init.body = JSON.stringify(body)
368454
parsedBody = body

lib/janitor.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -318,14 +318,24 @@ export class Janitor {
318318

319319
this.logger.debug("janitor", "Starting shadow inference", { sessionID })
320320

321+
// Replace already-pruned tool outputs to save tokens in janitor context
322+
const allPrunedSoFar = [...alreadyPrunedIds, ...deduplicatedIds]
323+
const sanitizedMessages = this.replacePrunedToolOutputs(messages, allPrunedSoFar)
324+
325+
this.logger.debug("janitor", "Sanitized messages for analysis", {
326+
sessionID,
327+
totalPrunedBeforeAnalysis: allPrunedSoFar.length,
328+
prunedIds: allPrunedSoFar.slice(0, 5) // Show first 5
329+
})
330+
321331
// Analyze which tool calls are obsolete
322332
const result = await generateObject({
323333
model: modelSelection.model,
324334
schema: z.object({
325335
pruned_tool_call_ids: z.array(z.string()),
326336
reasoning: z.string(),
327337
}),
328-
prompt: buildAnalysisPrompt(prunableToolCallIds, messages, this.protectedTools)
338+
prompt: buildAnalysisPrompt(prunableToolCallIds, sanitizedMessages, this.protectedTools)
329339
})
330340

331341
// Filter LLM results to only include IDs that were actually candidates
@@ -425,7 +435,6 @@ export class Janitor {
425435
sessionID,
426436
deduplicatedIds,
427437
deduplicationDetails,
428-
toolMetadata,
429438
toolOutputs
430439
)
431440
} else {
@@ -481,6 +490,41 @@ export class Janitor {
481490
return path
482491
}
483492

493+
/**
494+
* Replace pruned tool outputs with placeholder text to save tokens in janitor context
495+
* This applies the same replacement logic as the global fetch wrapper, but for the
496+
* janitor's shadow inference to avoid sending already-pruned content to the LLM
497+
*/
498+
private replacePrunedToolOutputs(messages: any[], prunedIds: string[]): any[] {
499+
if (prunedIds.length === 0) return messages
500+
501+
const prunedIdsSet = new Set(prunedIds.map(id => id.toLowerCase()))
502+
503+
return messages.map(msg => {
504+
if (!msg.parts) return msg
505+
506+
return {
507+
...msg,
508+
parts: msg.parts.map((part: any) => {
509+
if (part.type === 'tool' &&
510+
part.callID &&
511+
prunedIdsSet.has(part.callID.toLowerCase()) &&
512+
part.state?.output) {
513+
// Replace with the same placeholder used by the global fetch wrapper
514+
return {
515+
...part,
516+
state: {
517+
...part.state,
518+
output: '[Output removed to save context - information superseded or no longer needed]'
519+
}
520+
}
521+
}
522+
return part
523+
})
524+
}
525+
})
526+
}
527+
484528
/**
485529
* Helper function to calculate token savings from tool outputs
486530
*/
@@ -544,7 +588,6 @@ export class Janitor {
544588
sessionID: string,
545589
deduplicatedIds: string[],
546590
deduplicationDetails: Map<string, any>,
547-
toolMetadata: Map<string, any>,
548591
toolOutputs: Map<string, string>
549592
) {
550593
if (deduplicatedIds.length === 0) return

0 commit comments

Comments
 (0)