illuma-agents 1.0.12 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/llm/bedrock/index.ts"],"sourcesContent":["/**\n * Optimized ChatBedrockConverse wrapper that fixes contentBlockIndex conflicts\n * and adds prompt caching support for Bedrock Converse API.\n *\n * Bedrock sends the same contentBlockIndex for both text and tool_use content blocks,\n * causing LangChain's merge logic to fail with \"field[contentBlockIndex] already exists\"\n * errors. This wrapper simply strips contentBlockIndex from response_metadata to avoid\n * the conflict.\n *\n * The contentBlockIndex field is only used internally by Bedrock's streaming protocol\n * and isn't needed by application logic - the index field on tool_call_chunks serves\n * the purpose of tracking tool call ordering.\n *\n * PROMPT CACHING:\n * When promptCache: true is set, this wrapper adds cachePoint markers to the tools array\n * to enable Bedrock prompt caching for tool definitions. This allows tool schemas to be\n * cached and reused across requests, reducing latency and costs.\n *\n * CACHE TOKEN EXTRACTION:\n * LangChain AWS doesn't extract cacheReadInputTokens/cacheWriteInputTokens from Bedrock's\n * response. This wrapper adds input_token_details to usage_metadata with cache information.\n */\n\nimport { ChatBedrockConverse } from '@langchain/aws';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport { AIMessageChunk } from '@langchain/core/messages';\nimport type { BaseMessage, UsageMetadata } from '@langchain/core/messages';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\n\n/** Extended input type with promptCache option */\nexport interface CustomChatBedrockConverseInput extends ChatBedrockConverseInput {\n promptCache?: boolean;\n}\n\nexport class CustomChatBedrockConverse extends ChatBedrockConverse {\n promptCache: boolean;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.promptCache = fields?.promptCache ?? false;\n }\n\n static lc_name(): string {\n return 'IllumaBedrockConverse';\n }\n\n /**\n * Override invocationParams to add cachePoint to tools when promptCache is enabled.\n * This enables Bedrock prompt caching for tool definitions.\n * \n * STRATEGY: Separate cachePoints for core tools and MCP tools\n * - Core tools (web_search, execute_code, etc.) are stable → cache first\n * - MCP tools (have '_mcp_' in name) are dynamic → cache separately after\n * - This allows core tools to stay cached when MCP selection changes\n * \n * NOTE: Only Claude models support cachePoint - Nova and other models will reject it.\n */\n invocationParams(\n options?: this['ParsedCallOptions']\n ): ReturnType<ChatBedrockConverse['invocationParams']> {\n const params = super.invocationParams(options);\n\n // Add cachePoint to tools array if promptCache is enabled and tools exist\n // Only Claude models support cachePoint - check model name\n const modelId = this.model?.toLowerCase() ?? '';\n const isClaudeModel = modelId.includes('claude') || modelId.includes('anthropic');\n\n if (\n this.promptCache &&\n isClaudeModel &&\n params.toolConfig?.tools &&\n Array.isArray(params.toolConfig.tools) &&\n params.toolConfig.tools.length > 0\n ) {\n // Separate core tools from MCP tools\n // MCP tools have '_mcp_' in their name (e.g., 'search_emails_mcp_Google-Workspace')\n const coreTools: typeof params.toolConfig.tools = [];\n const mcpTools: typeof params.toolConfig.tools = [];\n const coreToolNames: string[] = [];\n const mcpToolNames: string[] = [];\n \n for (const tool of params.toolConfig.tools) {\n // Check if tool has a name property with '_mcp_' pattern\n const toolName = (tool as { toolSpec?: { name?: string } })?.toolSpec?.name ?? '';\n if (toolName.includes('_mcp_')) {\n mcpTools.push(tool);\n mcpToolNames.push(toolName);\n } else {\n coreTools.push(tool);\n coreToolNames.push(toolName);\n }\n }\n\n // Always log cache structure (INFO level for tracking)\n console.log(`[Cache] 🔧 Tools | Core: [${coreToolNames.join(', ')}] (${coreTools.length}) | MCP: [${mcpToolNames.join(', ')}] (${mcpTools.length})`);\n\n // Build tools array with strategic cachePoints:\n // [CoreTool1, CoreTool2, cachePoint] + [MCPTool1, MCPTool2, cachePoint]\n const toolsWithCache: typeof params.toolConfig.tools = [];\n let cachePointCount = 0;\n \n // Add core tools with cachePoint (if any)\n if (coreTools.length > 0) {\n toolsWithCache.push(...coreTools);\n toolsWithCache.push({ cachePoint: { type: 'default' } });\n cachePointCount++;\n }\n \n // Add MCP tools with their own cachePoint (if any)\n if (mcpTools.length > 0) {\n toolsWithCache.push(...mcpTools);\n toolsWithCache.push({ cachePoint: { type: 'default' } });\n cachePointCount++;\n }\n \n // If no tools at all (shouldn't happen but safety check)\n if (toolsWithCache.length === 0) {\n toolsWithCache.push({ cachePoint: { type: 'default' } });\n cachePointCount++;\n }\n \n console.log(`[Cache] 📍 Tool cachePoints: ${cachePointCount} | Order: [${coreToolNames.length > 0 ? 'CoreTools→CP' : ''}${mcpToolNames.length > 0 ? '→MCPTools→CP' : ''}]`);\n \n params.toolConfig.tools = toolsWithCache;\n }\n\n return params;\n }\n\n /**\n * Override _streamResponseChunks to:\n * 1. Strip contentBlockIndex from response_metadata to prevent merge conflicts\n * 2. Extract cacheReadInputTokens/cacheWriteInputTokens and add to usage_metadata\n */\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const baseStream = super._streamResponseChunks(\n messages,\n options,\n runManager\n );\n\n for await (const chunk of baseStream) {\n // Only process if we have response_metadata\n if (\n chunk.message instanceof AIMessageChunk &&\n (chunk.message as Partial<AIMessageChunk>).response_metadata &&\n typeof chunk.message.response_metadata === 'object'\n ) {\n const responseMetadata = chunk.message.response_metadata as Record<string, unknown>;\n let needsModification = false;\n let cleanedMetadata = responseMetadata;\n\n // Check if contentBlockIndex exists anywhere in response_metadata\n const hasContentBlockIndex = this.hasContentBlockIndex(responseMetadata);\n if (hasContentBlockIndex) {\n cleanedMetadata = this.removeContentBlockIndex(responseMetadata) as Record<string, unknown>;\n needsModification = true;\n }\n\n // Extract cache tokens from metadata.usage (Bedrock streaming format)\n // The metadata chunk contains usage with cacheReadInputTokens/cacheWriteInputTokens\n const metadata = responseMetadata.metadata as Record<string, unknown> | undefined;\n const usage = (metadata?.usage ?? responseMetadata.usage) as Record<string, unknown> | undefined;\n \n let enhancedUsageMetadata: UsageMetadata | undefined = chunk.message.usage_metadata;\n \n if (usage) {\n const cacheRead = (usage.cacheReadInputTokens as number) ?? 0;\n const cacheWrite = (usage.cacheWriteInputTokens as number) ?? 0;\n const inputTokens = (usage.inputTokens as number) ?? 0;\n const outputTokens = (usage.outputTokens as number) ?? 0;\n \n if (cacheRead > 0 || cacheWrite > 0) {\n // Always log cache results for tracking\n const cacheStatus = cacheRead > 0 && cacheWrite === 0 ? '✅ HIT' : \n cacheWrite > 0 && cacheRead === 0 ? '📝 WRITE' :\n cacheRead > 0 && cacheWrite > 0 ? '🔄 PARTIAL' : '❌ MISS';\n console.log(`[Cache] ${cacheStatus} | read=${cacheRead} | write=${cacheWrite} | input=${inputTokens} | output=${outputTokens}`);\n \n needsModification = true;\n enhancedUsageMetadata = {\n input_tokens: chunk.message.usage_metadata?.input_tokens ?? inputTokens,\n output_tokens: chunk.message.usage_metadata?.output_tokens ?? outputTokens,\n total_tokens: chunk.message.usage_metadata?.total_tokens ?? (usage.totalTokens as number) ?? 0,\n input_token_details: {\n cache_read: cacheRead,\n cache_creation: cacheWrite,\n },\n };\n }\n }\n\n if (needsModification) {\n yield new ChatGenerationChunk({\n text: chunk.text,\n message: new AIMessageChunk({\n ...chunk.message,\n response_metadata: cleanedMetadata,\n usage_metadata: enhancedUsageMetadata,\n }),\n generationInfo: chunk.generationInfo,\n });\n continue;\n }\n }\n\n yield chunk;\n }\n }\n\n /**\n * Check if contentBlockIndex exists at any level in the object\n */\n private hasContentBlockIndex(obj: unknown): boolean {\n if (obj === null || obj === undefined || typeof obj !== 'object') {\n return false;\n }\n\n if ('contentBlockIndex' in obj) {\n return true;\n }\n\n for (const value of Object.values(obj)) {\n if (typeof value === 'object' && value !== null) {\n if (this.hasContentBlockIndex(value)) {\n return true;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Recursively remove contentBlockIndex from all levels of an object\n */\n private removeContentBlockIndex(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => this.removeContentBlockIndex(item));\n }\n\n if (typeof obj === 'object') {\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (key !== 'contentBlockIndex') {\n cleaned[key] = this.removeContentBlockIndex(value);\n }\n }\n return cleaned;\n }\n\n return obj;\n }\n}\n\nexport type { ChatBedrockConverseInput };\n"],"names":["ChatBedrockConverse","messages","AIMessageChunk","ChatGenerationChunk"],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;AAqBG;AAcG,MAAO,yBAA0B,SAAQA,uBAAmB,CAAA;AAChE,IAAA,WAAW;AAEX,IAAA,WAAA,CAAY,MAAuC,EAAA;QACjD,KAAK,CAAC,MAAM,CAAC;QACb,IAAI,CAAC,WAAW,GAAG,MAAM,EAAE,WAAW,IAAI,KAAK;;AAGjD,IAAA,OAAO,OAAO,GAAA;AACZ,QAAA,OAAO,uBAAuB;;AAGhC;;;;;;;;;;AAUG;AACH,IAAA,gBAAgB,CACd,OAAmC,EAAA;QAEnC,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC;;;QAI9C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE;AAC/C,QAAA,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;QAEjF,IACE,IAAI,CAAC,WAAW;YAChB,aAAa;YACb,MAAM,CAAC,UAAU,EAAE,KAAK;YACxB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;YACtC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAClC;;;YAGA,MAAM,SAAS,GAAmC,EAAE;YACpD,MAAM,QAAQ,GAAmC,EAAE;YACnD,MAAM,aAAa,GAAa,EAAE;YAClC,MAAM,YAAY,GAAa,EAAE;YAEjC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE;;gBAE1C,MAAM,QAAQ,GAAI,IAAyC,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE;AACjF,gBAAA,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;AAC9B,oBAAA,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;AACnB,oBAAA,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC;;qBACtB;AACL,oBAAA,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;AACpB,oBAAA,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;;;;YAKhC,OAAO,CAAC,GAAG,CAAC,CAA6B,0BAAA,EAAA,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,GAAA,EAAM,SAAS,CAAC,MAAM,CAAA,UAAA,EAAa,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAM,GAAA,EAAA,QAAQ,CAAC,MAAM,CAAG,CAAA,CAAA,CAAC;;;YAIpJ,MAAM,cAAc,GAAmC,EAAE;YACzD,IAAI,eAAe,GAAG,CAAC;;AAGvB,YAAA,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;AACxB,gBAAA,cAAc,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;AACjC,gBAAA,cAAc,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;AACxD,gBAAA,eAAe,EAAE;;;AAInB,YAAA,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;AACvB,gBAAA,cAAc,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;AAChC,gBAAA,cAAc,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;AACxD,gBAAA,eAAe,EAAE;;;AAInB,YAAA,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE;AAC/B,gBAAA,cAAc,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;AACxD,gBAAA,eAAe,EAAE;;AAGnB,YAAA,OAAO,CAAC,GAAG,CAAC,CAAA,6BAAA,EAAgC,eAAe,CAAc,WAAA,EAAA,aAAa,CAAC,MAAM,GAAG,CAAC,GAAG,cAAc,GAAG,EAAE,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,cAAc,GAAG,EAAE,CAAA,CAAA,CAAG,CAAC;AAE3K,YAAA,MAAM,CAAC,UAAU,CAAC,KAAK,GAAG,cAAc;;AAG1C,QAAA,OAAO,MAAM;;AAGf;;;;AAIG;IACH,OAAO,qBAAqB,CAC1BC,UAAuB,EACvB,OAAkC,EAClC,UAAqC,EAAA;AAErC,QAAA,MAAM,UAAU,GAAG,KAAK,CAAC,qBAAqB,CAC5CA,UAAQ,EACR,OAAO,EACP,UAAU,CACX;AAED,QAAA,WAAW,MAAM,KAAK,IAAI,UAAU,EAAE;;AAEpC,YAAA,IACE,KAAK,CAAC,OAAO,YAAYC,uBAAc;gBACtC,KAAK,CAAC,OAAmC,CAAC,iBAAiB;gBAC5D,OAAO,KAAK,CAAC,OAAO,CAAC,iBAAiB,KAAK,QAAQ,EACnD;AACA,gBAAA,MAAM,gBAAgB,GAAG,KAAK,CAAC,OAAO,CAAC,iBAA4C;gBACnF,IAAI,iBAAiB,GAAG,KAAK;gBAC7B,IAAI,eAAe,GAAG,gBAAgB;;gBAGtC,MAAM,oBAAoB,GAAG,IAAI,CAAC,oBAAoB,CAAC,gBAAgB,CAAC;gBACxE,IAAI,oBAAoB,EAAE;AACxB,oBAAA,eAAe,GAAG,IAAI,CAAC,uBAAuB,CAAC,gBAAgB,CAA4B;oBAC3F,iBAAiB,GAAG,IAAI;;;;AAK1B,gBAAA,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAA+C;gBACjF,MAAM,KAAK,IAAI,QAAQ,EAAE,KAAK,IAAI,gBAAgB,CAAC,KAAK,CAAwC;AAEhG,gBAAA,IAAI,qBAAqB,GAA8B,KAAK,CAAC,OAAO,CAAC,cAAc;gBAEnF,IAAI,KAAK,EAAE;AACT,oBAAA,MAAM,SAAS,GAAI,KAAK,CAAC,oBAA+B,IAAI,CAAC;AAC7D,oBAAA,MAAM,UAAU,GAAI,KAAK,CAAC,qBAAgC,IAAI,CAAC;AAC/D,oBAAA,MAAM,WAAW,GAAI,KAAK,CAAC,WAAsB,IAAI,CAAC;AACtD,oBAAA,MAAM,YAAY,GAAI,KAAK,CAAC,YAAuB,IAAI,CAAC;oBAExD,IAAI,SAAS,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE;;AAEnC,wBAAA,MAAM,WAAW,GAAG,SAAS,GAAG,CAAC,IAAI,UAAU,KAAK,CAAC,GAAG,OAAO;4BAC5C,UAAU,GAAG,CAAC,IAAI,SAAS,KAAK,CAAC,GAAG,UAAU;AAC9C,gCAAA,SAAS,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,GAAG,YAAY,GAAG,QAAQ;AAC5E,wBAAA,OAAO,CAAC,GAAG,CAAC,CAAA,QAAA,EAAW,WAAW,CAAW,QAAA,EAAA,SAAS,CAAY,SAAA,EAAA,UAAU,YAAY,WAAW,CAAA,UAAA,EAAa,YAAY,CAAA,CAAE,CAAC;wBAE/H,iBAAiB,GAAG,IAAI;AACxB,wBAAA,qBAAqB,GAAG;4BACtB,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,YAAY,IAAI,WAAW;4BACvE,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,aAAa,IAAI,YAAY;AAC1E,4BAAA,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,YAAY,IAAK,KAAK,CAAC,WAAsB,IAAI,CAAC;AAC9F,4BAAA,mBAAmB,EAAE;AACnB,gCAAA,UAAU,EAAE,SAAS;AACrB,gCAAA,cAAc,EAAE,UAAU;AAC3B,6BAAA;yBACF;;;gBAIL,IAAI,iBAAiB,EAAE;oBACrB,MAAM,IAAIC,2BAAmB,CAAC;wBAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,OAAO,EAAE,IAAID,uBAAc,CAAC;4BAC1B,GAAG,KAAK,CAAC,OAAO;AAChB,4BAAA,iBAAiB,EAAE,eAAe;AAClC,4BAAA,cAAc,EAAE,qBAAqB;yBACtC,CAAC;wBACF,cAAc,EAAE,KAAK,CAAC,cAAc;AACrC,qBAAA,CAAC;oBACF;;;AAIJ,YAAA,MAAM,KAAK;;;AAIf;;AAEG;AACK,IAAA,oBAAoB,CAAC,GAAY,EAAA;AACvC,QAAA,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAChE,YAAA,OAAO,KAAK;;AAGd,QAAA,IAAI,mBAAmB,IAAI,GAAG,EAAE;AAC9B,YAAA,OAAO,IAAI;;QAGb,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;YACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE;AAC/C,gBAAA,IAAI,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,EAAE;AACpC,oBAAA,OAAO,IAAI;;;;AAKjB,QAAA,OAAO,KAAK;;AAGd;;AAEG;AACK,IAAA,uBAAuB,CAAC,GAAY,EAAA;QAC1C,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,EAAE;AACrC,YAAA,OAAO,GAAG;;AAGZ,QAAA,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AACtB,YAAA,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;;AAG9D,QAAA,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;YAC3B,MAAM,OAAO,GAA4B,EAAE;AAC3C,YAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AAC9C,gBAAA,IAAI,GAAG,KAAK,mBAAmB,EAAE;oBAC/B,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC;;;AAGtD,YAAA,OAAO,OAAO;;AAGhB,QAAA,OAAO,GAAG;;AAEb;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/llm/bedrock/index.ts"],"sourcesContent":["/**\n * Optimized ChatBedrockConverse wrapper that fixes contentBlockIndex conflicts\n * and adds prompt caching support for Bedrock Converse API.\n *\n * Bedrock sends the same contentBlockIndex for both text and tool_use content blocks,\n * causing LangChain's merge logic to fail with \"field[contentBlockIndex] already exists\"\n * errors. This wrapper simply strips contentBlockIndex from response_metadata to avoid\n * the conflict.\n *\n * The contentBlockIndex field is only used internally by Bedrock's streaming protocol\n * and isn't needed by application logic - the index field on tool_call_chunks serves\n * the purpose of tracking tool call ordering.\n *\n * PROMPT CACHING:\n * When promptCache: true is set, this wrapper adds cachePoint markers to the tools array\n * to enable Bedrock prompt caching for tool definitions. This allows tool schemas to be\n * cached and reused across requests, reducing latency and costs.\n *\n * CACHE TOKEN EXTRACTION:\n * LangChain AWS doesn't extract cacheReadInputTokens/cacheWriteInputTokens from Bedrock's\n * response. This wrapper adds input_token_details to usage_metadata with cache information.\n */\n\nimport { ChatBedrockConverse } from '@langchain/aws';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport { AIMessageChunk } from '@langchain/core/messages';\nimport type { BaseMessage, UsageMetadata } from '@langchain/core/messages';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\n\n/** Extended input type with promptCache option */\nexport interface CustomChatBedrockConverseInput extends ChatBedrockConverseInput {\n promptCache?: boolean;\n}\n\nexport class CustomChatBedrockConverse extends ChatBedrockConverse {\n promptCache: boolean;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.promptCache = fields?.promptCache ?? false;\n }\n\n static lc_name(): string {\n return 'IllumaBedrockConverse';\n }\n\n /**\n * Override invocationParams to add cachePoint to tools when promptCache is enabled.\n * This enables Bedrock prompt caching for tool definitions.\n * \n * STRATEGY: Separate cachePoints for core tools and MCP tools\n * - Core tools (web_search, execute_code, etc.) are stable → cache first\n * - MCP tools (have '_mcp_' in name) are dynamic → cache separately after\n * - This allows core tools to stay cached when MCP selection changes\n * \n * NOTE: Only Claude models support cachePoint - Nova and other models will reject it.\n */\n invocationParams(\n options?: this['ParsedCallOptions']\n ): ReturnType<ChatBedrockConverse['invocationParams']> {\n const params = super.invocationParams(options);\n\n // Add cachePoint to tools array if promptCache is enabled and tools exist\n // Only Claude models support cachePoint - check model name\n const modelId = this.model?.toLowerCase() ?? '';\n const isClaudeModel = modelId.includes('claude') || modelId.includes('anthropic');\n\n if (\n this.promptCache &&\n isClaudeModel &&\n params.toolConfig?.tools &&\n Array.isArray(params.toolConfig.tools) &&\n params.toolConfig.tools.length > 0\n ) {\n // Separate core tools from MCP tools\n // MCP tools have '_mcp_' in their name (e.g., 'search_emails_mcp_Google-Workspace')\n const coreTools: typeof params.toolConfig.tools = [];\n const mcpTools: typeof params.toolConfig.tools = [];\n const coreToolNames: string[] = [];\n const mcpToolNames: string[] = [];\n \n for (const tool of params.toolConfig.tools) {\n // Check if tool has a name property with '_mcp_' pattern\n const toolName = (tool as { toolSpec?: { name?: string } })?.toolSpec?.name ?? '';\n if (toolName.includes('_mcp_')) {\n mcpTools.push(tool);\n mcpToolNames.push(toolName);\n } else {\n coreTools.push(tool);\n coreToolNames.push(toolName);\n }\n }\n\n\n\n // Build tools array with strategic cachePoints:\n // [CoreTool1, CoreTool2, cachePoint] + [MCPTool1, MCPTool2, cachePoint]\n const toolsWithCache: typeof params.toolConfig.tools = [];\n let cachePointCount = 0;\n \n // Add core tools with cachePoint (if any)\n if (coreTools.length > 0) {\n toolsWithCache.push(...coreTools);\n toolsWithCache.push({ cachePoint: { type: 'default' } });\n cachePointCount++;\n }\n \n // Add MCP tools with their own cachePoint (if any)\n if (mcpTools.length > 0) {\n toolsWithCache.push(...mcpTools);\n toolsWithCache.push({ cachePoint: { type: 'default' } });\n cachePointCount++;\n }\n \n // If no tools at all (shouldn't happen but safety check)\n if (toolsWithCache.length === 0) {\n toolsWithCache.push({ cachePoint: { type: 'default' } });\n cachePointCount++;\n }\n \n\n \n params.toolConfig.tools = toolsWithCache;\n }\n\n return params;\n }\n\n /**\n * Override _streamResponseChunks to:\n * 1. Strip contentBlockIndex from response_metadata to prevent merge conflicts\n * 2. Extract cacheReadInputTokens/cacheWriteInputTokens and add to usage_metadata\n */\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const baseStream = super._streamResponseChunks(\n messages,\n options,\n runManager\n );\n\n for await (const chunk of baseStream) {\n // Only process if we have response_metadata\n if (\n chunk.message instanceof AIMessageChunk &&\n (chunk.message as Partial<AIMessageChunk>).response_metadata &&\n typeof chunk.message.response_metadata === 'object'\n ) {\n const responseMetadata = chunk.message.response_metadata as Record<string, unknown>;\n let needsModification = false;\n let cleanedMetadata = responseMetadata;\n\n // Check if contentBlockIndex exists anywhere in response_metadata\n const hasContentBlockIndex = this.hasContentBlockIndex(responseMetadata);\n if (hasContentBlockIndex) {\n cleanedMetadata = this.removeContentBlockIndex(responseMetadata) as Record<string, unknown>;\n needsModification = true;\n }\n\n // Extract cache tokens from metadata.usage (Bedrock streaming format)\n // The metadata chunk contains usage with cacheReadInputTokens/cacheWriteInputTokens\n const metadata = responseMetadata.metadata as Record<string, unknown> | undefined;\n const usage = (metadata?.usage ?? responseMetadata.usage) as Record<string, unknown> | undefined;\n \n let enhancedUsageMetadata: UsageMetadata | undefined = chunk.message.usage_metadata;\n \n if (usage) {\n const cacheRead = (usage.cacheReadInputTokens as number) ?? 0;\n const cacheWrite = (usage.cacheWriteInputTokens as number) ?? 0;\n const inputTokens = (usage.inputTokens as number) ?? 0;\n const outputTokens = (usage.outputTokens as number) ?? 0;\n \n if (cacheRead > 0 || cacheWrite > 0) {\n \n needsModification = true;\n enhancedUsageMetadata = {\n input_tokens: chunk.message.usage_metadata?.input_tokens ?? inputTokens,\n output_tokens: chunk.message.usage_metadata?.output_tokens ?? outputTokens,\n total_tokens: chunk.message.usage_metadata?.total_tokens ?? (usage.totalTokens as number) ?? 0,\n input_token_details: {\n cache_read: cacheRead,\n cache_creation: cacheWrite,\n },\n };\n }\n }\n\n if (needsModification) {\n yield new ChatGenerationChunk({\n text: chunk.text,\n message: new AIMessageChunk({\n ...chunk.message,\n response_metadata: cleanedMetadata,\n usage_metadata: enhancedUsageMetadata,\n }),\n generationInfo: chunk.generationInfo,\n });\n continue;\n }\n }\n\n yield chunk;\n }\n }\n\n /**\n * Check if contentBlockIndex exists at any level in the object\n */\n private hasContentBlockIndex(obj: unknown): boolean {\n if (obj === null || obj === undefined || typeof obj !== 'object') {\n return false;\n }\n\n if ('contentBlockIndex' in obj) {\n return true;\n }\n\n for (const value of Object.values(obj)) {\n if (typeof value === 'object' && value !== null) {\n if (this.hasContentBlockIndex(value)) {\n return true;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Recursively remove contentBlockIndex from all levels of an object\n */\n private removeContentBlockIndex(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => this.removeContentBlockIndex(item));\n }\n\n if (typeof obj === 'object') {\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (key !== 'contentBlockIndex') {\n cleaned[key] = this.removeContentBlockIndex(value);\n }\n }\n return cleaned;\n }\n\n return obj;\n }\n}\n\nexport type { ChatBedrockConverseInput };\n"],"names":["ChatBedrockConverse","messages","AIMessageChunk","ChatGenerationChunk"],"mappings":"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"}
@@ -2,13 +2,10 @@
2
2
 
3
3
  var _enum = require('../common/enum.cjs');
4
4
 
5
- /** Always-on logger for cache operations */
6
- const logCache = (message) => {
7
- console.log(`[Cache] ${message}`);
8
- };
9
5
  /** Debug logger for cache operations - set ILLUMA_DEBUG_CACHE=true to enable */
10
6
  const debugCache = (message, data) => {
11
7
  if (process.env.ILLUMA_DEBUG_CACHE === 'true') {
8
+ // eslint-disable-next-line no-console
12
9
  console.log(`[Cache] ${message}`, data !== undefined ? JSON.stringify(data, null, 2) : '');
13
10
  }
14
11
  };
@@ -214,11 +211,11 @@ function addBedrockCacheControl(messages) {
214
211
  }
215
212
  }
216
213
  // Log message summary
217
- logCache(`📨 Messages | total=${updatedMessages.length} | ${Object.entries(messageTypes).map(([k, v]) => `${k}:${v}`).join(' ')} | skippedReasoning=${skippedWithReasoning}`);
214
+ debugCache(`📨 Messages | total=${updatedMessages.length} | ${Object.entries(messageTypes).map(([k, v]) => `${k}:${v}`).join(' ')} | skippedReasoning=${skippedWithReasoning}`);
218
215
  // If no suitable assistant message found, skip conversation caching
219
216
  // (System and Tools caching are still handled separately)
220
217
  if (lastAssistantIndex === -1) {
221
- logCache('📨 Messages | No suitable assistant message for cachePoint (first turn or all have reasoning)');
218
+ debugCache('📨 Messages | No suitable assistant message for cachePoint (first turn or all have reasoning)');
222
219
  return updatedMessages;
223
220
  }
224
221
  // Add cache point to the last assistant message (without reasoning blocks)
@@ -229,7 +226,7 @@ function addBedrockCacheControl(messages) {
229
226
  { type: _enum.ContentTypes.TEXT, text: content },
230
227
  { cachePoint: { type: 'default' } },
231
228
  ];
232
- logCache(`📍 Message cachePoint at index ${lastAssistantIndex} (string, ${content.length} chars)`);
229
+ debugCache(`📍 Message cachePoint at index ${lastAssistantIndex} (string, ${content.length} chars)`);
233
230
  debugCache('addBedrockCacheControl: Added cachePoint to assistant message (string content)', {
234
231
  index: lastAssistantIndex,
235
232
  contentLength: content.length,
@@ -239,7 +236,7 @@ function addBedrockCacheControl(messages) {
239
236
  // Double-check: If this message has reasoning blocks, skip adding cache point entirely
240
237
  // This handles edge cases where the initial skip check might have missed it
241
238
  if (hasReasoningBlock(assistantMessage)) {
242
- logCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (has reasoning blocks)`);
239
+ debugCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (has reasoning blocks)`);
243
240
  debugCache('addBedrockCacheControl: Skipping - assistant message has reasoning blocks (safety check)', {
244
241
  index: lastAssistantIndex,
245
242
  });
@@ -257,7 +254,7 @@ function addBedrockCacheControl(messages) {
257
254
  cachePoint: { type: 'default' },
258
255
  });
259
256
  inserted = true;
260
- logCache(`📍 Message cachePoint at index ${lastAssistantIndex} (array, block ${j}, ${text.length} chars)`);
257
+ debugCache(`📍 Message cachePoint at index ${lastAssistantIndex} (array, block ${j}, ${text.length} chars)`);
261
258
  debugCache('addBedrockCacheControl: Added cachePoint after text block in assistant message', {
262
259
  index: lastAssistantIndex,
263
260
  textBlockIndex: j,
@@ -270,7 +267,7 @@ function addBedrockCacheControl(messages) {
270
267
  // If no text block found, don't append cache point as the message structure is unexpected
271
268
  if (!inserted) {
272
269
  const contentTypes = assistantMessage.content.map((b) => b.type);
273
- logCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (no text block, types: ${contentTypes.join(',')})`);
270
+ debugCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (no text block, types: ${contentTypes.join(',')})`);
274
271
  debugCache('addBedrockCacheControl: No suitable text block found, skipping cache point', {
275
272
  index: lastAssistantIndex,
276
273
  contentTypes,
@@ -1 +1 @@
1
- {"version":3,"file":"cache.cjs","sources":["../../../src/messages/cache.ts"],"sourcesContent":["import { BaseMessage, MessageContentComplex } from '@langchain/core/messages';\nimport type { AnthropicMessage } from '@/types/messages';\nimport type Anthropic from '@anthropic-ai/sdk';\nimport { ContentTypes } from '@/common/enum';\n\ntype MessageWithContent = {\n content?: string | MessageContentComplex[];\n};\n\n/** Always-on logger for cache operations */\nconst logCache = (message: string) => {\n console.log(`[Cache] ${message}`);\n};\n\n/** Debug logger for cache operations - set ILLUMA_DEBUG_CACHE=true to enable */\nconst debugCache = (message: string, data?: unknown) => {\n if (process.env.ILLUMA_DEBUG_CACHE === 'true') {\n console.log(`[Cache] ${message}`, data !== undefined ? JSON.stringify(data, null, 2) : '');\n }\n};\n\n/**\n * Anthropic API: Adds cache control to the appropriate user messages in the payload.\n * Strips ALL existing cache control (both Anthropic and Bedrock formats) from all messages,\n * then adds fresh cache control to the last 2 user messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * @param messages - The array of message objects.\n * @returns - The updated array of message objects with cache control added.\n */\nexport function addCacheControl<T extends AnthropicMessage | BaseMessage>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages = [...messages];\n let userMessagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const message = updatedMessages[i];\n const isUserMessage =\n ('getType' in message && message.getType() === 'human') ||\n ('role' in message && message.role === 'user');\n\n if (Array.isArray(message.content)) {\n message.content = message.content.filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof message.content;\n\n for (let j = 0; j < message.content.length; j++) {\n const block = message.content[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n if (userMessagesModified >= 2 || !isUserMessage) {\n continue;\n }\n\n if (typeof message.content === 'string') {\n message.content = [\n {\n type: 'text',\n text: message.content,\n cache_control: { type: 'ephemeral' },\n },\n ];\n userMessagesModified++;\n } else if (Array.isArray(message.content)) {\n for (let j = message.content.length - 1; j >= 0; j--) {\n const contentPart = message.content[j];\n if ('type' in contentPart && contentPart.type === 'text') {\n (contentPart as Anthropic.TextBlockParam).cache_control = {\n type: 'ephemeral',\n };\n userMessagesModified++;\n break;\n }\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a content block is a cache point\n */\nfunction isCachePoint(block: MessageContentComplex): boolean {\n return 'cachePoint' in block && !('type' in block);\n}\n\n/**\n * Removes all Anthropic cache_control fields from messages\n * Used when switching from Anthropic to Bedrock provider\n */\nexport function stripAnthropicCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const message = updatedMessages[i];\n const content = message.content;\n\n if (Array.isArray(content)) {\n for (let j = 0; j < content.length; j++) {\n const block = content[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Removes all Bedrock cachePoint blocks from messages\n * Used when switching from Bedrock to Anthropic provider\n */\nexport function stripBedrockCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const message = updatedMessages[i];\n const content = message.content;\n\n if (Array.isArray(content)) {\n message.content = content.filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof content;\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Adds Bedrock Converse API cache points using \"Stable Prefix Caching\" strategy.\n * \n * STRATEGY: Place cache point after the LAST ASSISTANT message only.\n * This ensures the prefix (everything before the cache point) remains STABLE\n * as the conversation grows, maximizing cache hits.\n * \n * Why this works:\n * - System message has its own cachePoint (added in AgentContext)\n * - Tools have their own cachePoint (added in CustomChatBedrockConverse)\n * - Conversation history grows, but the PREFIX stays the same\n * - Only the NEW user message is uncached (it's always different)\n * \n * Example conversation flow:\n * Request 1: [System+cachePoint][Tools+cachePoint][User1] → No conversation cache yet\n * Request 2: [System][Tools][User1][Assistant1+cachePoint][User2] → Cache User1+Assistant1\n * Request 3: [System][Tools][User1][Assistant1][User2][Assistant2+cachePoint][User3]\n * → Cache reads User1+A1+User2+A2, cache writes new portion\n * \n * Claude's \"Simplified Cache Management\" automatically looks back up to 20 content\n * blocks from the cache checkpoint to find the longest matching prefix.\n * \n * @param messages - The array of message objects (excluding system message).\n * @returns - The updated array with a single cache point after the last assistant message.\n */\nexport function addBedrockCacheControl<\n T extends Partial<BaseMessage> & MessageWithContent,\n>(messages: T[]): T[] {\n if (!Array.isArray(messages) || messages.length < 1) {\n debugCache('addBedrockCacheControl: Skipping - no messages', { count: messages?.length });\n return messages;\n }\n\n debugCache('addBedrockCacheControl: Processing messages with stable prefix strategy', { \n count: messages.length \n });\n \n const updatedMessages: T[] = messages.slice();\n \n // First pass: Remove ALL existing cache points to ensure clean state\n // This prevents accumulation of stale cache points\n for (const message of updatedMessages) {\n const content = message.content;\n if (Array.isArray(content)) {\n message.content = content.filter(\n (block) => !isCachePoint(block)\n ) as typeof content;\n\n // Also remove Anthropic-style cache_control\n for (let j = 0; j < message.content.length; j++) {\n const block = message.content[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n }\n\n // Helper function to check if a message contains reasoning/thinking blocks\n const hasReasoningBlock = (message: T): boolean => {\n const content = message.content;\n if (!Array.isArray(content)) {\n return false;\n }\n for (const block of content) {\n const type = (block as { type?: string }).type;\n // Check for all reasoning/thinking block types:\n // - reasoning_content: Bedrock Anthropic extended thinking\n // - reasoning: Generic reasoning format \n // - thinking: Anthropic direct API thinking\n // - redacted_thinking: Anthropic redacted thinking blocks\n if (\n type === 'reasoning_content' ||\n type === 'reasoning' ||\n type === 'thinking' ||\n type === 'redacted_thinking'\n ) {\n return true;\n }\n }\n return false;\n };\n\n // Second pass: Find the LAST assistant message WITHOUT reasoning blocks and add a cache point there\n // Messages with reasoning/thinking blocks cannot have cache points after them (Bedrock limitation)\n let lastAssistantIndex = -1;\n let skippedWithReasoning = 0;\n \n // Count message types for logging\n const messageTypes: Record<string, number> = {};\n for (const message of updatedMessages) {\n const msgType = 'getType' in message && typeof message.getType === 'function' \n ? message.getType() \n : 'unknown';\n messageTypes[msgType] = (messageTypes[msgType] || 0) + 1;\n }\n \n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const message = updatedMessages[i];\n const messageType = 'getType' in message && typeof message.getType === 'function' \n ? message.getType() \n : 'unknown';\n \n if (messageType === 'ai') {\n // Skip assistant messages with reasoning blocks - cache points not allowed after them\n if (hasReasoningBlock(message)) {\n skippedWithReasoning++;\n debugCache('addBedrockCacheControl: Skipping assistant message with reasoning block', { index: i });\n continue;\n }\n lastAssistantIndex = i;\n break;\n }\n }\n\n // Log message summary\n logCache(`📨 Messages | total=${updatedMessages.length} | ${Object.entries(messageTypes).map(([k,v]) => `${k}:${v}`).join(' ')} | skippedReasoning=${skippedWithReasoning}`);\n\n // If no suitable assistant message found, skip conversation caching\n // (System and Tools caching are still handled separately)\n if (lastAssistantIndex === -1) {\n logCache('📨 Messages | No suitable assistant message for cachePoint (first turn or all have reasoning)');\n return updatedMessages;\n }\n\n // Add cache point to the last assistant message (without reasoning blocks)\n const assistantMessage = updatedMessages[lastAssistantIndex];\n const content = assistantMessage.content;\n\n if (typeof content === 'string' && content !== '') {\n assistantMessage.content = [\n { type: ContentTypes.TEXT, text: content },\n { cachePoint: { type: 'default' } },\n ] as MessageContentComplex[];\n logCache(`📍 Message cachePoint at index ${lastAssistantIndex} (string, ${content.length} chars)`);\n debugCache('addBedrockCacheControl: Added cachePoint to assistant message (string content)', {\n index: lastAssistantIndex,\n contentLength: content.length,\n });\n } else if (Array.isArray(assistantMessage.content) && assistantMessage.content.length > 0) {\n // Double-check: If this message has reasoning blocks, skip adding cache point entirely\n // This handles edge cases where the initial skip check might have missed it\n if (hasReasoningBlock(assistantMessage)) {\n logCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (has reasoning blocks)`);\n debugCache('addBedrockCacheControl: Skipping - assistant message has reasoning blocks (safety check)', {\n index: lastAssistantIndex,\n });\n return updatedMessages;\n }\n \n // Find the last text block and insert cache point after it\n let inserted = false;\n for (let j = assistantMessage.content.length - 1; j >= 0; j--) {\n const block = assistantMessage.content[j] as MessageContentComplex;\n const type = (block as { type?: string }).type;\n if (type === ContentTypes.TEXT || type === 'text') {\n const text = (block as { text?: string }).text;\n if (text && text !== '') {\n assistantMessage.content.splice(j + 1, 0, {\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n inserted = true;\n logCache(`📍 Message cachePoint at index ${lastAssistantIndex} (array, block ${j}, ${text.length} chars)`);\n debugCache('addBedrockCacheControl: Added cachePoint after text block in assistant message', {\n index: lastAssistantIndex,\n textBlockIndex: j,\n contentLength: text.length,\n });\n break;\n }\n }\n }\n \n // If no text block found, don't append cache point as the message structure is unexpected\n if (!inserted) {\n const contentTypes = assistantMessage.content.map((b) => (b as { type?: string }).type);\n logCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (no text block, types: ${contentTypes.join(',')})`);\n debugCache('addBedrockCacheControl: No suitable text block found, skipping cache point', {\n index: lastAssistantIndex,\n contentTypes,\n });\n }\n }\n\n debugCache('addBedrockCacheControl: Complete - stable prefix caching applied', { \n lastAssistantIndex,\n totalMessages: updatedMessages.length,\n });\n\n return updatedMessages;\n}\n"],"names":["ContentTypes"],"mappings":"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"}
1
+ {"version":3,"file":"cache.cjs","sources":["../../../src/messages/cache.ts"],"sourcesContent":["import { BaseMessage, MessageContentComplex } from '@langchain/core/messages';\nimport type { AnthropicMessage } from '@/types/messages';\nimport type Anthropic from '@anthropic-ai/sdk';\nimport { ContentTypes } from '@/common/enum';\n\ntype MessageWithContent = {\n content?: string | MessageContentComplex[];\n};\n\n/** Debug logger for cache operations - set ILLUMA_DEBUG_CACHE=true to enable */\nconst debugCache = (message: string, data?: unknown) => {\n if (process.env.ILLUMA_DEBUG_CACHE === 'true') {\n // eslint-disable-next-line no-console\n console.log(`[Cache] ${message}`, data !== undefined ? JSON.stringify(data, null, 2) : '');\n }\n};\n\n/**\n * Anthropic API: Adds cache control to the appropriate user messages in the payload.\n * Strips ALL existing cache control (both Anthropic and Bedrock formats) from all messages,\n * then adds fresh cache control to the last 2 user messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * @param messages - The array of message objects.\n * @returns - The updated array of message objects with cache control added.\n */\nexport function addCacheControl<T extends AnthropicMessage | BaseMessage>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages = [...messages];\n let userMessagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const message = updatedMessages[i];\n const isUserMessage =\n ('getType' in message && message.getType() === 'human') ||\n ('role' in message && message.role === 'user');\n\n if (Array.isArray(message.content)) {\n message.content = message.content.filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof message.content;\n\n for (let j = 0; j < message.content.length; j++) {\n const block = message.content[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n if (userMessagesModified >= 2 || !isUserMessage) {\n continue;\n }\n\n if (typeof message.content === 'string') {\n message.content = [\n {\n type: 'text',\n text: message.content,\n cache_control: { type: 'ephemeral' },\n },\n ];\n userMessagesModified++;\n } else if (Array.isArray(message.content)) {\n for (let j = message.content.length - 1; j >= 0; j--) {\n const contentPart = message.content[j];\n if ('type' in contentPart && contentPart.type === 'text') {\n (contentPart as Anthropic.TextBlockParam).cache_control = {\n type: 'ephemeral',\n };\n userMessagesModified++;\n break;\n }\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a content block is a cache point\n */\nfunction isCachePoint(block: MessageContentComplex): boolean {\n return 'cachePoint' in block && !('type' in block);\n}\n\n/**\n * Removes all Anthropic cache_control fields from messages\n * Used when switching from Anthropic to Bedrock provider\n */\nexport function stripAnthropicCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const message = updatedMessages[i];\n const content = message.content;\n\n if (Array.isArray(content)) {\n for (let j = 0; j < content.length; j++) {\n const block = content[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Removes all Bedrock cachePoint blocks from messages\n * Used when switching from Bedrock to Anthropic provider\n */\nexport function stripBedrockCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const message = updatedMessages[i];\n const content = message.content;\n\n if (Array.isArray(content)) {\n message.content = content.filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof content;\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Adds Bedrock Converse API cache points using \"Stable Prefix Caching\" strategy.\n * \n * STRATEGY: Place cache point after the LAST ASSISTANT message only.\n * This ensures the prefix (everything before the cache point) remains STABLE\n * as the conversation grows, maximizing cache hits.\n * \n * Why this works:\n * - System message has its own cachePoint (added in AgentContext)\n * - Tools have their own cachePoint (added in CustomChatBedrockConverse)\n * - Conversation history grows, but the PREFIX stays the same\n * - Only the NEW user message is uncached (it's always different)\n * \n * Example conversation flow:\n * Request 1: [System+cachePoint][Tools+cachePoint][User1] → No conversation cache yet\n * Request 2: [System][Tools][User1][Assistant1+cachePoint][User2] → Cache User1+Assistant1\n * Request 3: [System][Tools][User1][Assistant1][User2][Assistant2+cachePoint][User3]\n * → Cache reads User1+A1+User2+A2, cache writes new portion\n * \n * Claude's \"Simplified Cache Management\" automatically looks back up to 20 content\n * blocks from the cache checkpoint to find the longest matching prefix.\n * \n * @param messages - The array of message objects (excluding system message).\n * @returns - The updated array with a single cache point after the last assistant message.\n */\nexport function addBedrockCacheControl<\n T extends Partial<BaseMessage> & MessageWithContent,\n>(messages: T[]): T[] {\n if (!Array.isArray(messages) || messages.length < 1) {\n debugCache('addBedrockCacheControl: Skipping - no messages', { count: messages?.length });\n return messages;\n }\n\n debugCache('addBedrockCacheControl: Processing messages with stable prefix strategy', { \n count: messages.length \n });\n \n const updatedMessages: T[] = messages.slice();\n \n // First pass: Remove ALL existing cache points to ensure clean state\n // This prevents accumulation of stale cache points\n for (const message of updatedMessages) {\n const content = message.content;\n if (Array.isArray(content)) {\n message.content = content.filter(\n (block) => !isCachePoint(block)\n ) as typeof content;\n\n // Also remove Anthropic-style cache_control\n for (let j = 0; j < message.content.length; j++) {\n const block = message.content[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n }\n\n // Helper function to check if a message contains reasoning/thinking blocks\n const hasReasoningBlock = (message: T): boolean => {\n const content = message.content;\n if (!Array.isArray(content)) {\n return false;\n }\n for (const block of content) {\n const type = (block as { type?: string }).type;\n // Check for all reasoning/thinking block types:\n // - reasoning_content: Bedrock Anthropic extended thinking\n // - reasoning: Generic reasoning format \n // - thinking: Anthropic direct API thinking\n // - redacted_thinking: Anthropic redacted thinking blocks\n if (\n type === 'reasoning_content' ||\n type === 'reasoning' ||\n type === 'thinking' ||\n type === 'redacted_thinking'\n ) {\n return true;\n }\n }\n return false;\n };\n\n // Second pass: Find the LAST assistant message WITHOUT reasoning blocks and add a cache point there\n // Messages with reasoning/thinking blocks cannot have cache points after them (Bedrock limitation)\n let lastAssistantIndex = -1;\n let skippedWithReasoning = 0;\n \n // Count message types for logging\n const messageTypes: Record<string, number> = {};\n for (const message of updatedMessages) {\n const msgType = 'getType' in message && typeof message.getType === 'function' \n ? message.getType() \n : 'unknown';\n messageTypes[msgType] = (messageTypes[msgType] || 0) + 1;\n }\n \n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const message = updatedMessages[i];\n const messageType = 'getType' in message && typeof message.getType === 'function' \n ? message.getType() \n : 'unknown';\n \n if (messageType === 'ai') {\n // Skip assistant messages with reasoning blocks - cache points not allowed after them\n if (hasReasoningBlock(message)) {\n skippedWithReasoning++;\n debugCache('addBedrockCacheControl: Skipping assistant message with reasoning block', { index: i });\n continue;\n }\n lastAssistantIndex = i;\n break;\n }\n }\n\n // Log message summary\n debugCache(`📨 Messages | total=${updatedMessages.length} | ${Object.entries(messageTypes).map(([k,v]) => `${k}:${v}`).join(' ')} | skippedReasoning=${skippedWithReasoning}`);\n\n // If no suitable assistant message found, skip conversation caching\n // (System and Tools caching are still handled separately)\n if (lastAssistantIndex === -1) {\n debugCache('📨 Messages | No suitable assistant message for cachePoint (first turn or all have reasoning)');\n return updatedMessages;\n }\n\n // Add cache point to the last assistant message (without reasoning blocks)\n const assistantMessage = updatedMessages[lastAssistantIndex];\n const content = assistantMessage.content;\n\n if (typeof content === 'string' && content !== '') {\n assistantMessage.content = [\n { type: ContentTypes.TEXT, text: content },\n { cachePoint: { type: 'default' } },\n ] as MessageContentComplex[];\n debugCache(`📍 Message cachePoint at index ${lastAssistantIndex} (string, ${content.length} chars)`);\n debugCache('addBedrockCacheControl: Added cachePoint to assistant message (string content)', {\n index: lastAssistantIndex,\n contentLength: content.length,\n });\n } else if (Array.isArray(assistantMessage.content) && assistantMessage.content.length > 0) {\n // Double-check: If this message has reasoning blocks, skip adding cache point entirely\n // This handles edge cases where the initial skip check might have missed it\n if (hasReasoningBlock(assistantMessage)) {\n debugCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (has reasoning blocks)`);\n debugCache('addBedrockCacheControl: Skipping - assistant message has reasoning blocks (safety check)', {\n index: lastAssistantIndex,\n });\n return updatedMessages;\n }\n \n // Find the last text block and insert cache point after it\n let inserted = false;\n for (let j = assistantMessage.content.length - 1; j >= 0; j--) {\n const block = assistantMessage.content[j] as MessageContentComplex;\n const type = (block as { type?: string }).type;\n if (type === ContentTypes.TEXT || type === 'text') {\n const text = (block as { text?: string }).text;\n if (text && text !== '') {\n assistantMessage.content.splice(j + 1, 0, {\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n inserted = true;\n debugCache(`📍 Message cachePoint at index ${lastAssistantIndex} (array, block ${j}, ${text.length} chars)`);\n debugCache('addBedrockCacheControl: Added cachePoint after text block in assistant message', {\n index: lastAssistantIndex,\n textBlockIndex: j,\n contentLength: text.length,\n });\n break;\n }\n }\n }\n \n // If no text block found, don't append cache point as the message structure is unexpected\n if (!inserted) {\n const contentTypes = assistantMessage.content.map((b) => (b as { type?: string }).type);\n debugCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (no text block, types: ${contentTypes.join(',')})`);\n debugCache('addBedrockCacheControl: No suitable text block found, skipping cache point', {\n index: lastAssistantIndex,\n contentTypes,\n });\n }\n }\n\n debugCache('addBedrockCacheControl: Complete - stable prefix caching applied', { \n lastAssistantIndex,\n totalMessages: updatedMessages.length,\n });\n\n return updatedMessages;\n}\n"],"names":["ContentTypes"],"mappings":"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"}
@@ -117,6 +117,10 @@ class AgentContext {
117
117
  tokenCalculationPromise;
118
118
  /** Format content blocks as strings (for legacy compatibility) */
119
119
  useLegacyContent = false;
120
+ /** Detailed per-tool token breakdown for admin tracking */
121
+ toolsDetail = [];
122
+ /** Total tool tokens (sum of all toolsDetail) */
123
+ toolTokensTotal = 0;
120
124
  constructor({ agentId, provider, clientOptions, maxContextTokens, streamBuffer, tokenCounter, tools, toolMap, toolRegistry, instructions, additionalInstructions, dynamicContext, reasoningKey, toolEnd, instructionTokens, useLegacyContent, }) {
121
125
  this.agentId = agentId;
122
126
  this.provider = provider;
@@ -271,8 +275,6 @@ class AgentContext {
271
275
  const modelId = bedrockOptions?.model?.toLowerCase() ?? '';
272
276
  const supportsCaching = modelId.includes('claude') || modelId.includes('anthropic') || modelId.includes('nova');
273
277
  if (bedrockOptions?.promptCache === true && supportsCaching) {
274
- // Always log system cache structure
275
- console.log(`[Cache] 📝 System | chars=${instructionsString.length} | tokens=${this.systemMessageTokens} | model=${modelId}`);
276
278
  finalInstructions = {
277
279
  content: [
278
280
  {
@@ -303,6 +305,8 @@ class AgentContext {
303
305
  reset() {
304
306
  this.instructionTokens = 0;
305
307
  this.systemMessageTokens = 0;
308
+ this.toolsDetail = [];
309
+ this.toolTokensTotal = 0;
306
310
  this.cachedSystemRunnable = undefined;
307
311
  this.systemRunnableStale = true;
308
312
  this.lastToken = undefined;
@@ -337,9 +341,11 @@ class AgentContext {
337
341
  /**
338
342
  * Calculate tool tokens and add to instruction tokens
339
343
  * Note: System message tokens are calculated during systemRunnable creation
344
+ * Also tracks per-tool token breakdown for admin reporting
340
345
  */
341
346
  async calculateInstructionTokens(tokenCounter) {
342
347
  let toolTokens = 0;
348
+ this.toolsDetail = []; // Reset per-tool breakdown
343
349
  if (this.tools && this.tools.length > 0) {
344
350
  for (const tool of this.tools) {
345
351
  const genericTool = tool;
@@ -348,13 +354,44 @@ class AgentContext {
348
354
  const schema = genericTool.schema;
349
355
  const describedSchema = schema.describe(genericTool.description || '');
350
356
  const jsonSchema = zodToJsonSchema(describedSchema, genericTool.name || '');
351
- toolTokens += tokenCounter(new SystemMessage(JSON.stringify(jsonSchema)));
357
+ const toolName = genericTool.name || 'unknown';
358
+ const tokens = tokenCounter(new SystemMessage(JSON.stringify(jsonSchema)));
359
+ // Track per-tool breakdown
360
+ this.toolsDetail.push({ name: toolName, tokens });
361
+ toolTokens += tokens;
352
362
  }
353
363
  }
354
364
  }
365
+ // Store total tool tokens for breakdown reporting
366
+ this.toolTokensTotal = toolTokens;
355
367
  // Add tool tokens to existing instruction tokens (which may already include system message tokens)
356
368
  this.instructionTokens += toolTokens;
357
369
  }
370
+ /**
371
+ * Get a detailed breakdown of context tokens for admin reporting.
372
+ * This provides visibility into what's consuming the input token budget.
373
+ * @returns ContextBreakdown object with per-component token counts
374
+ */
375
+ getContextBreakdown() {
376
+ return {
377
+ // System message tokens (instructions + additional_instructions)
378
+ instructions: this.systemMessageTokens,
379
+ // Artifacts are not currently tracked separately, set to 0
380
+ artifacts: 0,
381
+ // Total tool definition tokens
382
+ tools: this.toolTokensTotal,
383
+ // Number of tools
384
+ toolCount: this.toolsDetail.length,
385
+ // Tool context/usage instructions (currently embedded in system message)
386
+ toolContext: 0,
387
+ // Total tracked context tokens
388
+ total: this.instructionTokens,
389
+ // Per-tool token breakdown
390
+ toolsDetail: [...this.toolsDetail],
391
+ // Tool context detail (currently not tracked separately)
392
+ toolContextDetail: [],
393
+ };
394
+ }
358
395
  /**
359
396
  * Gets the tool registry for deferred tools (for tool search).
360
397
  * @param onlyDeferred If true, only returns tools with defer_loading=true
@@ -1 +1 @@
1
- {"version":3,"file":"AgentContext.mjs","sources":["../../../src/agents/AgentContext.ts"],"sourcesContent":["/* eslint-disable no-console */\n// src/agents/AgentContext.ts\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport { SystemMessage } from '@langchain/core/messages';\nimport { RunnableLambda } from '@langchain/core/runnables';\nimport type {\n UsageMetadata,\n BaseMessage,\n BaseMessageFields,\n} from '@langchain/core/messages';\nimport type { RunnableConfig, Runnable } from '@langchain/core/runnables';\nimport type * as t from '@/types';\nimport type { createPruneMessages } from '@/messages';\nimport { ContentTypes, Providers } from '@/common';\n\n/**\n * Encapsulates agent-specific state that can vary between agents in a multi-agent system\n */\nexport class AgentContext {\n /**\n * Create an AgentContext from configuration with token accounting initialization\n */\n static fromConfig(\n agentConfig: t.AgentInputs,\n tokenCounter?: t.TokenCounter,\n indexTokenCountMap?: Record<string, number>\n ): AgentContext {\n const {\n agentId,\n provider,\n clientOptions,\n tools,\n toolMap,\n toolEnd,\n toolRegistry,\n instructions,\n additional_instructions,\n streamBuffer,\n maxContextTokens,\n reasoningKey,\n useLegacyContent,\n dynamicContext,\n } = agentConfig;\n\n const agentContext = new AgentContext({\n agentId,\n provider,\n clientOptions,\n maxContextTokens,\n streamBuffer,\n tools,\n toolMap,\n toolRegistry,\n instructions,\n additionalInstructions: additional_instructions,\n reasoningKey,\n toolEnd,\n instructionTokens: 0,\n tokenCounter,\n useLegacyContent,\n dynamicContext,\n });\n\n if (tokenCounter) {\n // Initialize system runnable BEFORE async tool token calculation\n // This ensures system message tokens are in instructionTokens before\n // updateTokenMapWithInstructions is called\n agentContext.initializeSystemRunnable();\n\n const tokenMap = indexTokenCountMap || {};\n agentContext.indexTokenCountMap = tokenMap;\n agentContext.tokenCalculationPromise = agentContext\n .calculateInstructionTokens(tokenCounter)\n .then(() => {\n // Update token map with instruction tokens (includes system + tool tokens)\n agentContext.updateTokenMapWithInstructions(tokenMap);\n })\n .catch((err) => {\n console.error('Error calculating instruction tokens:', err);\n });\n } else if (indexTokenCountMap) {\n agentContext.indexTokenCountMap = indexTokenCountMap;\n }\n\n return agentContext;\n }\n\n /** Agent identifier */\n agentId: string;\n /** Provider for this specific agent */\n provider: Providers;\n /** Client options for this agent */\n clientOptions?: t.ClientOptions;\n /** Token count map indexed by message position */\n indexTokenCountMap: Record<string, number | undefined> = {};\n /** Maximum context tokens for this agent */\n maxContextTokens?: number;\n /** Current usage metadata for this agent */\n currentUsage?: Partial<UsageMetadata>;\n /** Prune messages function configured for this agent */\n pruneMessages?: ReturnType<typeof createPruneMessages>;\n /** Token counter function for this agent */\n tokenCounter?: t.TokenCounter;\n /** Instructions/system message token count */\n instructionTokens: number = 0;\n /** The amount of time that should pass before another consecutive API call */\n streamBuffer?: number;\n /** Last stream call timestamp for rate limiting */\n lastStreamCall?: number;\n /** Tools available to this agent */\n tools?: t.GraphTools;\n /** Tool map for this agent */\n toolMap?: t.ToolMap;\n /**\n * Tool definitions registry (includes deferred and programmatic tool metadata).\n * Used for tool search and programmatic tool calling.\n */\n toolRegistry?: t.LCToolRegistry;\n /** Set of tool names discovered via tool search (to be loaded) */\n discoveredToolNames: Set<string> = new Set();\n /** Instructions for this agent */\n instructions?: string;\n /** Additional instructions for this agent */\n additionalInstructions?: string;\n /**\n * Dynamic context that changes per-request (e.g., current time, user info).\n * This is NOT included in the system message to preserve cache.\n * Instead, it's injected as a user message at the start of the conversation.\n */\n dynamicContext?: string;\n /** Reasoning key for this agent */\n reasoningKey: 'reasoning_content' | 'reasoning' = 'reasoning_content';\n /** Last token for reasoning detection */\n lastToken?: string;\n /** Token type switch state */\n tokenTypeSwitch?: 'reasoning' | 'content';\n /** Current token type being processed */\n currentTokenType: ContentTypes.TEXT | ContentTypes.THINK | 'think_and_text' =\n ContentTypes.TEXT;\n /** Whether tools should end the workflow */\n toolEnd: boolean = false;\n /** Cached system runnable (created lazily) */\n private cachedSystemRunnable?: Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >;\n /** Whether system runnable needs rebuild (set when discovered tools change) */\n private systemRunnableStale: boolean = true;\n /** Cached system message token count (separate from tool tokens) */\n private systemMessageTokens: number = 0;\n /** Promise for token calculation initialization */\n tokenCalculationPromise?: Promise<void>;\n /** Format content blocks as strings (for legacy compatibility) */\n useLegacyContent: boolean = false;\n\n constructor({\n agentId,\n provider,\n clientOptions,\n maxContextTokens,\n streamBuffer,\n tokenCounter,\n tools,\n toolMap,\n toolRegistry,\n instructions,\n additionalInstructions,\n dynamicContext,\n reasoningKey,\n toolEnd,\n instructionTokens,\n useLegacyContent,\n }: {\n agentId: string;\n provider: Providers;\n clientOptions?: t.ClientOptions;\n maxContextTokens?: number;\n streamBuffer?: number;\n tokenCounter?: t.TokenCounter;\n tools?: t.GraphTools;\n toolMap?: t.ToolMap;\n toolRegistry?: t.LCToolRegistry;\n instructions?: string;\n additionalInstructions?: string;\n dynamicContext?: string;\n reasoningKey?: 'reasoning_content' | 'reasoning';\n toolEnd?: boolean;\n instructionTokens?: number;\n useLegacyContent?: boolean;\n }) {\n this.agentId = agentId;\n this.provider = provider;\n this.clientOptions = clientOptions;\n this.maxContextTokens = maxContextTokens;\n this.streamBuffer = streamBuffer;\n this.tokenCounter = tokenCounter;\n this.tools = tools;\n this.toolMap = toolMap;\n this.toolRegistry = toolRegistry;\n this.instructions = instructions;\n this.additionalInstructions = additionalInstructions;\n this.dynamicContext = dynamicContext;\n if (reasoningKey) {\n this.reasoningKey = reasoningKey;\n }\n if (toolEnd !== undefined) {\n this.toolEnd = toolEnd;\n }\n if (instructionTokens !== undefined) {\n this.instructionTokens = instructionTokens;\n }\n\n this.useLegacyContent = useLegacyContent ?? false;\n }\n\n /**\n * Builds instructions text for tools that are ONLY callable via programmatic code execution.\n * These tools cannot be called directly by the LLM but are available through the\n * run_tools_with_code tool.\n *\n * Includes:\n * - Code_execution-only tools that are NOT deferred\n * - Code_execution-only tools that ARE deferred but have been discovered via tool search\n */\n private buildProgrammaticOnlyToolsInstructions(): string {\n if (!this.toolRegistry) return '';\n\n const programmaticOnlyTools: t.LCTool[] = [];\n for (const [name, toolDef] of this.toolRegistry) {\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n const isCodeExecutionOnly =\n allowedCallers.includes('code_execution') &&\n !allowedCallers.includes('direct');\n\n if (!isCodeExecutionOnly) continue;\n\n // Include if: not deferred OR deferred but discovered\n const isDeferred = toolDef.defer_loading === true;\n const isDiscovered = this.discoveredToolNames.has(name);\n if (!isDeferred || isDiscovered) {\n programmaticOnlyTools.push(toolDef);\n }\n }\n\n if (programmaticOnlyTools.length === 0) return '';\n\n const toolDescriptions = programmaticOnlyTools\n .map((tool) => {\n let desc = `- **${tool.name}**`;\n if (tool.description != null && tool.description !== '') {\n desc += `: ${tool.description}`;\n }\n if (tool.parameters) {\n desc += `\\n Parameters: ${JSON.stringify(tool.parameters, null, 2).replace(/\\n/g, '\\n ')}`;\n }\n return desc;\n })\n .join('\\n\\n');\n\n return (\n '\\n\\n## Programmatic-Only Tools\\n\\n' +\n 'The following tools are available exclusively through the `run_tools_with_code` tool. ' +\n 'You cannot call these tools directly; instead, use `run_tools_with_code` with Python code that invokes them.\\n\\n' +\n toolDescriptions\n );\n }\n\n /**\n * Gets the system runnable, creating it lazily if needed.\n * Includes instructions, additional instructions, and programmatic-only tools documentation.\n * Only rebuilds when marked stale (via markToolsAsDiscovered).\n */\n get systemRunnable():\n | Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >\n | undefined {\n // Return cached if not stale\n if (!this.systemRunnableStale && this.cachedSystemRunnable !== undefined) {\n return this.cachedSystemRunnable;\n }\n\n // Stale or first access - rebuild\n const instructionsString = this.buildInstructionsString();\n this.cachedSystemRunnable = this.buildSystemRunnable(instructionsString);\n this.systemRunnableStale = false;\n return this.cachedSystemRunnable;\n }\n\n /**\n * Explicitly initializes the system runnable.\n * Call this before async token calculation to ensure system message tokens are counted first.\n */\n initializeSystemRunnable(): void {\n if (this.systemRunnableStale || this.cachedSystemRunnable === undefined) {\n const instructionsString = this.buildInstructionsString();\n this.cachedSystemRunnable = this.buildSystemRunnable(instructionsString);\n this.systemRunnableStale = false;\n }\n }\n\n /**\n * Builds the raw instructions string (without creating SystemMessage).\n */\n private buildInstructionsString(): string {\n let result = this.instructions ?? '';\n\n if (\n this.additionalInstructions != null &&\n this.additionalInstructions !== ''\n ) {\n result = result\n ? `${result}\\n\\n${this.additionalInstructions}`\n : this.additionalInstructions;\n }\n\n const programmaticToolsDoc = this.buildProgrammaticOnlyToolsInstructions();\n if (programmaticToolsDoc) {\n result = result\n ? `${result}${programmaticToolsDoc}`\n : programmaticToolsDoc;\n }\n\n return result;\n }\n\n /**\n * Build system runnable from pre-built instructions string.\n * Only called when content has actually changed.\n */\n private buildSystemRunnable(\n instructionsString: string\n ):\n | Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >\n | undefined {\n if (!instructionsString) {\n // Remove previous tokens if we had a system message before\n this.instructionTokens -= this.systemMessageTokens;\n this.systemMessageTokens = 0;\n return undefined;\n }\n\n let finalInstructions: string | BaseMessageFields = instructionsString;\n\n // Handle Anthropic prompt caching (Direct API)\n if (this.provider === Providers.ANTHROPIC) {\n const anthropicOptions = this.clientOptions as\n | t.AnthropicClientOptions\n | undefined;\n const defaultHeaders = anthropicOptions?.clientOptions?.defaultHeaders as\n | Record<string, string>\n | undefined;\n const anthropicBeta = defaultHeaders?.['anthropic-beta'];\n if (\n typeof anthropicBeta === 'string' &&\n anthropicBeta.includes('prompt-caching')\n ) {\n finalInstructions = {\n content: [\n {\n type: 'text',\n text: instructionsString,\n cache_control: { type: 'ephemeral' },\n },\n ],\n };\n }\n }\n\n // Handle Bedrock prompt caching (Converse API)\n // Adds cachePoint block after text content for system message caching\n // NOTE: Both Claude and Nova models support cachePoint in system and messages\n // (Nova does NOT support cachePoint in tools - that check is in bedrock/index.ts)\n if (this.provider === Providers.BEDROCK) {\n const bedrockOptions = this.clientOptions as\n | t.BedrockAnthropicInput\n | undefined;\n const modelId = bedrockOptions?.model?.toLowerCase() ?? '';\n const supportsCaching = modelId.includes('claude') || modelId.includes('anthropic') || modelId.includes('nova');\n\n if (bedrockOptions?.promptCache === true && supportsCaching) {\n // Always log system cache structure\n console.log(`[Cache] 📝 System | chars=${instructionsString.length} | tokens=${this.systemMessageTokens} | model=${modelId}`);\n \n finalInstructions = {\n content: [\n {\n type: 'text',\n text: instructionsString,\n },\n {\n cachePoint: { type: 'default' },\n },\n ],\n };\n }\n }\n\n const systemMessage = new SystemMessage(finalInstructions);\n\n // Update token counts (subtract old, add new)\n if (this.tokenCounter) {\n this.instructionTokens -= this.systemMessageTokens;\n this.systemMessageTokens = this.tokenCounter(systemMessage);\n this.instructionTokens += this.systemMessageTokens;\n }\n\n return RunnableLambda.from((messages: BaseMessage[]) => {\n return [systemMessage, ...messages];\n }).withConfig({ runName: 'prompt' });\n }\n\n /**\n * Reset context for a new run\n */\n reset(): void {\n this.instructionTokens = 0;\n this.systemMessageTokens = 0;\n this.cachedSystemRunnable = undefined;\n this.systemRunnableStale = true;\n this.lastToken = undefined;\n this.indexTokenCountMap = {};\n this.currentUsage = undefined;\n this.pruneMessages = undefined;\n this.lastStreamCall = undefined;\n this.tokenTypeSwitch = undefined;\n this.currentTokenType = ContentTypes.TEXT;\n this.discoveredToolNames.clear();\n }\n\n /**\n * Update the token count map with instruction tokens\n */\n updateTokenMapWithInstructions(baseTokenMap: Record<string, number>): void {\n if (this.instructionTokens > 0) {\n // Shift all indices by the instruction token count\n const shiftedMap: Record<string, number> = {};\n for (const [key, value] of Object.entries(baseTokenMap)) {\n const index = parseInt(key, 10);\n if (!isNaN(index)) {\n shiftedMap[String(index)] =\n value + (index === 0 ? this.instructionTokens : 0);\n }\n }\n this.indexTokenCountMap = shiftedMap;\n } else {\n this.indexTokenCountMap = { ...baseTokenMap };\n }\n }\n\n /**\n * Calculate tool tokens and add to instruction tokens\n * Note: System message tokens are calculated during systemRunnable creation\n */\n async calculateInstructionTokens(\n tokenCounter: t.TokenCounter\n ): Promise<void> {\n let toolTokens = 0;\n if (this.tools && this.tools.length > 0) {\n for (const tool of this.tools) {\n const genericTool = tool as Record<string, unknown>;\n if (\n genericTool.schema != null &&\n typeof genericTool.schema === 'object'\n ) {\n const schema = genericTool.schema as {\n describe: (desc: string) => unknown;\n };\n const describedSchema = schema.describe(\n (genericTool.description as string) || ''\n );\n const jsonSchema = zodToJsonSchema(\n describedSchema as Parameters<typeof zodToJsonSchema>[0],\n (genericTool.name as string) || ''\n );\n toolTokens += tokenCounter(\n new SystemMessage(JSON.stringify(jsonSchema))\n );\n }\n }\n }\n\n // Add tool tokens to existing instruction tokens (which may already include system message tokens)\n this.instructionTokens += toolTokens;\n }\n\n /**\n * Gets the tool registry for deferred tools (for tool search).\n * @param onlyDeferred If true, only returns tools with defer_loading=true\n * @returns LCToolRegistry with tool definitions\n */\n getDeferredToolRegistry(onlyDeferred: boolean = true): t.LCToolRegistry {\n const registry: t.LCToolRegistry = new Map();\n\n if (!this.toolRegistry) {\n return registry;\n }\n\n for (const [name, toolDef] of this.toolRegistry) {\n if (!onlyDeferred || toolDef.defer_loading === true) {\n registry.set(name, toolDef);\n }\n }\n\n return registry;\n }\n\n /**\n * Marks tools as discovered via tool search.\n * Discovered tools will be included in the next model binding.\n * Only marks system runnable stale if NEW tools were actually added.\n * @param toolNames - Array of discovered tool names\n * @returns true if any new tools were discovered\n */\n markToolsAsDiscovered(toolNames: string[]): boolean {\n let hasNewDiscoveries = false;\n for (const name of toolNames) {\n if (!this.discoveredToolNames.has(name)) {\n this.discoveredToolNames.add(name);\n hasNewDiscoveries = true;\n }\n }\n if (hasNewDiscoveries) {\n this.systemRunnableStale = true;\n }\n return hasNewDiscoveries;\n }\n\n /**\n * Gets tools that should be bound to the LLM.\n * Includes:\n * 1. Non-deferred tools with allowed_callers: ['direct']\n * 2. Discovered tools (from tool search)\n * @returns Array of tools to bind to model\n */\n getToolsForBinding(): t.GraphTools | undefined {\n if (!this.tools || !this.toolRegistry) {\n return this.tools;\n }\n\n const toolsToInclude = this.tools.filter((tool) => {\n if (!('name' in tool)) {\n return true; // No name, include by default\n }\n\n const toolDef = this.toolRegistry?.get(tool.name);\n if (!toolDef) {\n return true; // Not in registry, include by default\n }\n\n // Check if discovered (overrides defer_loading)\n if (this.discoveredToolNames.has(tool.name)) {\n // Discovered tools must still have allowed_callers: ['direct']\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n return allowedCallers.includes('direct');\n }\n\n // Not discovered: must be direct-callable AND not deferred\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n return (\n allowedCallers.includes('direct') && toolDef.defer_loading !== true\n );\n });\n\n return toolsToInclude;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AgentContext.mjs","sources":["../../../src/agents/AgentContext.ts"],"sourcesContent":["/* eslint-disable no-console */\n// src/agents/AgentContext.ts\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport { SystemMessage } from '@langchain/core/messages';\nimport { RunnableLambda } from '@langchain/core/runnables';\nimport type {\n UsageMetadata,\n BaseMessage,\n BaseMessageFields,\n} from '@langchain/core/messages';\nimport type { RunnableConfig, Runnable } from '@langchain/core/runnables';\nimport type * as t from '@/types';\nimport type { createPruneMessages } from '@/messages';\nimport { ContentTypes, Providers } from '@/common';\n\n/**\n * Encapsulates agent-specific state that can vary between agents in a multi-agent system\n */\nexport class AgentContext {\n /**\n * Create an AgentContext from configuration with token accounting initialization\n */\n static fromConfig(\n agentConfig: t.AgentInputs,\n tokenCounter?: t.TokenCounter,\n indexTokenCountMap?: Record<string, number>\n ): AgentContext {\n const {\n agentId,\n provider,\n clientOptions,\n tools,\n toolMap,\n toolEnd,\n toolRegistry,\n instructions,\n additional_instructions,\n streamBuffer,\n maxContextTokens,\n reasoningKey,\n useLegacyContent,\n dynamicContext,\n } = agentConfig;\n\n const agentContext = new AgentContext({\n agentId,\n provider,\n clientOptions,\n maxContextTokens,\n streamBuffer,\n tools,\n toolMap,\n toolRegistry,\n instructions,\n additionalInstructions: additional_instructions,\n reasoningKey,\n toolEnd,\n instructionTokens: 0,\n tokenCounter,\n useLegacyContent,\n dynamicContext,\n });\n\n if (tokenCounter) {\n // Initialize system runnable BEFORE async tool token calculation\n // This ensures system message tokens are in instructionTokens before\n // updateTokenMapWithInstructions is called\n agentContext.initializeSystemRunnable();\n\n const tokenMap = indexTokenCountMap || {};\n agentContext.indexTokenCountMap = tokenMap;\n agentContext.tokenCalculationPromise = agentContext\n .calculateInstructionTokens(tokenCounter)\n .then(() => {\n // Update token map with instruction tokens (includes system + tool tokens)\n agentContext.updateTokenMapWithInstructions(tokenMap);\n })\n .catch((err) => {\n console.error('Error calculating instruction tokens:', err);\n });\n } else if (indexTokenCountMap) {\n agentContext.indexTokenCountMap = indexTokenCountMap;\n }\n\n return agentContext;\n }\n\n /** Agent identifier */\n agentId: string;\n /** Provider for this specific agent */\n provider: Providers;\n /** Client options for this agent */\n clientOptions?: t.ClientOptions;\n /** Token count map indexed by message position */\n indexTokenCountMap: Record<string, number | undefined> = {};\n /** Maximum context tokens for this agent */\n maxContextTokens?: number;\n /** Current usage metadata for this agent */\n currentUsage?: Partial<UsageMetadata>;\n /** Prune messages function configured for this agent */\n pruneMessages?: ReturnType<typeof createPruneMessages>;\n /** Token counter function for this agent */\n tokenCounter?: t.TokenCounter;\n /** Instructions/system message token count */\n instructionTokens: number = 0;\n /** The amount of time that should pass before another consecutive API call */\n streamBuffer?: number;\n /** Last stream call timestamp for rate limiting */\n lastStreamCall?: number;\n /** Tools available to this agent */\n tools?: t.GraphTools;\n /** Tool map for this agent */\n toolMap?: t.ToolMap;\n /**\n * Tool definitions registry (includes deferred and programmatic tool metadata).\n * Used for tool search and programmatic tool calling.\n */\n toolRegistry?: t.LCToolRegistry;\n /** Set of tool names discovered via tool search (to be loaded) */\n discoveredToolNames: Set<string> = new Set();\n /** Instructions for this agent */\n instructions?: string;\n /** Additional instructions for this agent */\n additionalInstructions?: string;\n /**\n * Dynamic context that changes per-request (e.g., current time, user info).\n * This is NOT included in the system message to preserve cache.\n * Instead, it's injected as a user message at the start of the conversation.\n */\n dynamicContext?: string;\n /** Reasoning key for this agent */\n reasoningKey: 'reasoning_content' | 'reasoning' = 'reasoning_content';\n /** Last token for reasoning detection */\n lastToken?: string;\n /** Token type switch state */\n tokenTypeSwitch?: 'reasoning' | 'content';\n /** Current token type being processed */\n currentTokenType: ContentTypes.TEXT | ContentTypes.THINK | 'think_and_text' =\n ContentTypes.TEXT;\n /** Whether tools should end the workflow */\n toolEnd: boolean = false;\n /** Cached system runnable (created lazily) */\n private cachedSystemRunnable?: Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >;\n /** Whether system runnable needs rebuild (set when discovered tools change) */\n private systemRunnableStale: boolean = true;\n /** Cached system message token count (separate from tool tokens) */\n private systemMessageTokens: number = 0;\n /** Promise for token calculation initialization */\n tokenCalculationPromise?: Promise<void>;\n /** Format content blocks as strings (for legacy compatibility) */\n useLegacyContent: boolean = false;\n /** Detailed per-tool token breakdown for admin tracking */\n private toolsDetail: Array<{ name: string; tokens: number }> = [];\n /** Total tool tokens (sum of all toolsDetail) */\n private toolTokensTotal: number = 0;\n\n constructor({\n agentId,\n provider,\n clientOptions,\n maxContextTokens,\n streamBuffer,\n tokenCounter,\n tools,\n toolMap,\n toolRegistry,\n instructions,\n additionalInstructions,\n dynamicContext,\n reasoningKey,\n toolEnd,\n instructionTokens,\n useLegacyContent,\n }: {\n agentId: string;\n provider: Providers;\n clientOptions?: t.ClientOptions;\n maxContextTokens?: number;\n streamBuffer?: number;\n tokenCounter?: t.TokenCounter;\n tools?: t.GraphTools;\n toolMap?: t.ToolMap;\n toolRegistry?: t.LCToolRegistry;\n instructions?: string;\n additionalInstructions?: string;\n dynamicContext?: string;\n reasoningKey?: 'reasoning_content' | 'reasoning';\n toolEnd?: boolean;\n instructionTokens?: number;\n useLegacyContent?: boolean;\n }) {\n this.agentId = agentId;\n this.provider = provider;\n this.clientOptions = clientOptions;\n this.maxContextTokens = maxContextTokens;\n this.streamBuffer = streamBuffer;\n this.tokenCounter = tokenCounter;\n this.tools = tools;\n this.toolMap = toolMap;\n this.toolRegistry = toolRegistry;\n this.instructions = instructions;\n this.additionalInstructions = additionalInstructions;\n this.dynamicContext = dynamicContext;\n if (reasoningKey) {\n this.reasoningKey = reasoningKey;\n }\n if (toolEnd !== undefined) {\n this.toolEnd = toolEnd;\n }\n if (instructionTokens !== undefined) {\n this.instructionTokens = instructionTokens;\n }\n\n this.useLegacyContent = useLegacyContent ?? false;\n }\n\n /**\n * Builds instructions text for tools that are ONLY callable via programmatic code execution.\n * These tools cannot be called directly by the LLM but are available through the\n * run_tools_with_code tool.\n *\n * Includes:\n * - Code_execution-only tools that are NOT deferred\n * - Code_execution-only tools that ARE deferred but have been discovered via tool search\n */\n private buildProgrammaticOnlyToolsInstructions(): string {\n if (!this.toolRegistry) return '';\n\n const programmaticOnlyTools: t.LCTool[] = [];\n for (const [name, toolDef] of this.toolRegistry) {\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n const isCodeExecutionOnly =\n allowedCallers.includes('code_execution') &&\n !allowedCallers.includes('direct');\n\n if (!isCodeExecutionOnly) continue;\n\n // Include if: not deferred OR deferred but discovered\n const isDeferred = toolDef.defer_loading === true;\n const isDiscovered = this.discoveredToolNames.has(name);\n if (!isDeferred || isDiscovered) {\n programmaticOnlyTools.push(toolDef);\n }\n }\n\n if (programmaticOnlyTools.length === 0) return '';\n\n const toolDescriptions = programmaticOnlyTools\n .map((tool) => {\n let desc = `- **${tool.name}**`;\n if (tool.description != null && tool.description !== '') {\n desc += `: ${tool.description}`;\n }\n if (tool.parameters) {\n desc += `\\n Parameters: ${JSON.stringify(tool.parameters, null, 2).replace(/\\n/g, '\\n ')}`;\n }\n return desc;\n })\n .join('\\n\\n');\n\n return (\n '\\n\\n## Programmatic-Only Tools\\n\\n' +\n 'The following tools are available exclusively through the `run_tools_with_code` tool. ' +\n 'You cannot call these tools directly; instead, use `run_tools_with_code` with Python code that invokes them.\\n\\n' +\n toolDescriptions\n );\n }\n\n /**\n * Gets the system runnable, creating it lazily if needed.\n * Includes instructions, additional instructions, and programmatic-only tools documentation.\n * Only rebuilds when marked stale (via markToolsAsDiscovered).\n */\n get systemRunnable():\n | Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >\n | undefined {\n // Return cached if not stale\n if (!this.systemRunnableStale && this.cachedSystemRunnable !== undefined) {\n return this.cachedSystemRunnable;\n }\n\n // Stale or first access - rebuild\n const instructionsString = this.buildInstructionsString();\n this.cachedSystemRunnable = this.buildSystemRunnable(instructionsString);\n this.systemRunnableStale = false;\n return this.cachedSystemRunnable;\n }\n\n /**\n * Explicitly initializes the system runnable.\n * Call this before async token calculation to ensure system message tokens are counted first.\n */\n initializeSystemRunnable(): void {\n if (this.systemRunnableStale || this.cachedSystemRunnable === undefined) {\n const instructionsString = this.buildInstructionsString();\n this.cachedSystemRunnable = this.buildSystemRunnable(instructionsString);\n this.systemRunnableStale = false;\n }\n }\n\n /**\n * Builds the raw instructions string (without creating SystemMessage).\n */\n private buildInstructionsString(): string {\n let result = this.instructions ?? '';\n\n if (\n this.additionalInstructions != null &&\n this.additionalInstructions !== ''\n ) {\n result = result\n ? `${result}\\n\\n${this.additionalInstructions}`\n : this.additionalInstructions;\n }\n\n const programmaticToolsDoc = this.buildProgrammaticOnlyToolsInstructions();\n if (programmaticToolsDoc) {\n result = result\n ? `${result}${programmaticToolsDoc}`\n : programmaticToolsDoc;\n }\n\n return result;\n }\n\n /**\n * Build system runnable from pre-built instructions string.\n * Only called when content has actually changed.\n */\n private buildSystemRunnable(\n instructionsString: string\n ):\n | Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >\n | undefined {\n if (!instructionsString) {\n // Remove previous tokens if we had a system message before\n this.instructionTokens -= this.systemMessageTokens;\n this.systemMessageTokens = 0;\n return undefined;\n }\n\n let finalInstructions: string | BaseMessageFields = instructionsString;\n\n // Handle Anthropic prompt caching (Direct API)\n if (this.provider === Providers.ANTHROPIC) {\n const anthropicOptions = this.clientOptions as\n | t.AnthropicClientOptions\n | undefined;\n const defaultHeaders = anthropicOptions?.clientOptions?.defaultHeaders as\n | Record<string, string>\n | undefined;\n const anthropicBeta = defaultHeaders?.['anthropic-beta'];\n if (\n typeof anthropicBeta === 'string' &&\n anthropicBeta.includes('prompt-caching')\n ) {\n finalInstructions = {\n content: [\n {\n type: 'text',\n text: instructionsString,\n cache_control: { type: 'ephemeral' },\n },\n ],\n };\n }\n }\n\n // Handle Bedrock prompt caching (Converse API)\n // Adds cachePoint block after text content for system message caching\n // NOTE: Both Claude and Nova models support cachePoint in system and messages\n // (Nova does NOT support cachePoint in tools - that check is in bedrock/index.ts)\n if (this.provider === Providers.BEDROCK) {\n const bedrockOptions = this.clientOptions as\n | t.BedrockAnthropicInput\n | undefined;\n const modelId = bedrockOptions?.model?.toLowerCase() ?? '';\n const supportsCaching = modelId.includes('claude') || modelId.includes('anthropic') || modelId.includes('nova');\n\n if (bedrockOptions?.promptCache === true && supportsCaching) {\n \n finalInstructions = {\n content: [\n {\n type: 'text',\n text: instructionsString,\n },\n {\n cachePoint: { type: 'default' },\n },\n ],\n };\n }\n }\n\n const systemMessage = new SystemMessage(finalInstructions);\n\n // Update token counts (subtract old, add new)\n if (this.tokenCounter) {\n this.instructionTokens -= this.systemMessageTokens;\n this.systemMessageTokens = this.tokenCounter(systemMessage);\n this.instructionTokens += this.systemMessageTokens;\n }\n\n return RunnableLambda.from((messages: BaseMessage[]) => {\n return [systemMessage, ...messages];\n }).withConfig({ runName: 'prompt' });\n }\n\n /**\n * Reset context for a new run\n */\n reset(): void {\n this.instructionTokens = 0;\n this.systemMessageTokens = 0;\n this.toolsDetail = [];\n this.toolTokensTotal = 0;\n this.cachedSystemRunnable = undefined;\n this.systemRunnableStale = true;\n this.lastToken = undefined;\n this.indexTokenCountMap = {};\n this.currentUsage = undefined;\n this.pruneMessages = undefined;\n this.lastStreamCall = undefined;\n this.tokenTypeSwitch = undefined;\n this.currentTokenType = ContentTypes.TEXT;\n this.discoveredToolNames.clear();\n }\n\n /**\n * Update the token count map with instruction tokens\n */\n updateTokenMapWithInstructions(baseTokenMap: Record<string, number>): void {\n if (this.instructionTokens > 0) {\n // Shift all indices by the instruction token count\n const shiftedMap: Record<string, number> = {};\n for (const [key, value] of Object.entries(baseTokenMap)) {\n const index = parseInt(key, 10);\n if (!isNaN(index)) {\n shiftedMap[String(index)] =\n value + (index === 0 ? this.instructionTokens : 0);\n }\n }\n this.indexTokenCountMap = shiftedMap;\n } else {\n this.indexTokenCountMap = { ...baseTokenMap };\n }\n }\n\n /**\n * Calculate tool tokens and add to instruction tokens\n * Note: System message tokens are calculated during systemRunnable creation\n * Also tracks per-tool token breakdown for admin reporting\n */\n async calculateInstructionTokens(\n tokenCounter: t.TokenCounter\n ): Promise<void> {\n let toolTokens = 0;\n this.toolsDetail = []; // Reset per-tool breakdown\n \n if (this.tools && this.tools.length > 0) {\n for (const tool of this.tools) {\n const genericTool = tool as Record<string, unknown>;\n if (\n genericTool.schema != null &&\n typeof genericTool.schema === 'object'\n ) {\n const schema = genericTool.schema as {\n describe: (desc: string) => unknown;\n };\n const describedSchema = schema.describe(\n (genericTool.description as string) || ''\n );\n const jsonSchema = zodToJsonSchema(\n describedSchema as Parameters<typeof zodToJsonSchema>[0],\n (genericTool.name as string) || ''\n );\n const toolName = (genericTool.name as string) || 'unknown';\n const tokens = tokenCounter(\n new SystemMessage(JSON.stringify(jsonSchema))\n );\n \n // Track per-tool breakdown\n this.toolsDetail.push({ name: toolName, tokens });\n toolTokens += tokens;\n }\n }\n }\n\n // Store total tool tokens for breakdown reporting\n this.toolTokensTotal = toolTokens;\n \n // Add tool tokens to existing instruction tokens (which may already include system message tokens)\n this.instructionTokens += toolTokens;\n }\n\n /**\n * Get a detailed breakdown of context tokens for admin reporting.\n * This provides visibility into what's consuming the input token budget.\n * @returns ContextBreakdown object with per-component token counts\n */\n getContextBreakdown(): {\n instructions: number;\n artifacts: number;\n tools: number;\n toolCount: number;\n toolContext: number;\n total: number;\n toolsDetail: Array<{ name: string; tokens: number }>;\n toolContextDetail: Array<{ name: string; tokens: number }>;\n } {\n return {\n // System message tokens (instructions + additional_instructions)\n instructions: this.systemMessageTokens,\n // Artifacts are not currently tracked separately, set to 0\n artifacts: 0,\n // Total tool definition tokens\n tools: this.toolTokensTotal,\n // Number of tools\n toolCount: this.toolsDetail.length,\n // Tool context/usage instructions (currently embedded in system message)\n toolContext: 0,\n // Total tracked context tokens\n total: this.instructionTokens,\n // Per-tool token breakdown\n toolsDetail: [...this.toolsDetail],\n // Tool context detail (currently not tracked separately)\n toolContextDetail: [],\n };\n }\n\n /**\n * Gets the tool registry for deferred tools (for tool search).\n * @param onlyDeferred If true, only returns tools with defer_loading=true\n * @returns LCToolRegistry with tool definitions\n */\n getDeferredToolRegistry(onlyDeferred: boolean = true): t.LCToolRegistry {\n const registry: t.LCToolRegistry = new Map();\n\n if (!this.toolRegistry) {\n return registry;\n }\n\n for (const [name, toolDef] of this.toolRegistry) {\n if (!onlyDeferred || toolDef.defer_loading === true) {\n registry.set(name, toolDef);\n }\n }\n\n return registry;\n }\n\n /**\n * Marks tools as discovered via tool search.\n * Discovered tools will be included in the next model binding.\n * Only marks system runnable stale if NEW tools were actually added.\n * @param toolNames - Array of discovered tool names\n * @returns true if any new tools were discovered\n */\n markToolsAsDiscovered(toolNames: string[]): boolean {\n let hasNewDiscoveries = false;\n for (const name of toolNames) {\n if (!this.discoveredToolNames.has(name)) {\n this.discoveredToolNames.add(name);\n hasNewDiscoveries = true;\n }\n }\n if (hasNewDiscoveries) {\n this.systemRunnableStale = true;\n }\n return hasNewDiscoveries;\n }\n\n /**\n * Gets tools that should be bound to the LLM.\n * Includes:\n * 1. Non-deferred tools with allowed_callers: ['direct']\n * 2. Discovered tools (from tool search)\n * @returns Array of tools to bind to model\n */\n getToolsForBinding(): t.GraphTools | undefined {\n if (!this.tools || !this.toolRegistry) {\n return this.tools;\n }\n\n const toolsToInclude = this.tools.filter((tool) => {\n if (!('name' in tool)) {\n return true; // No name, include by default\n }\n\n const toolDef = this.toolRegistry?.get(tool.name);\n if (!toolDef) {\n return true; // Not in registry, include by default\n }\n\n // Check if discovered (overrides defer_loading)\n if (this.discoveredToolNames.has(tool.name)) {\n // Discovered tools must still have allowed_callers: ['direct']\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n return allowedCallers.includes('direct');\n }\n\n // Not discovered: must be direct-callable AND not deferred\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n return (\n allowedCallers.includes('direct') && toolDef.defer_loading !== true\n );\n });\n\n return toolsToInclude;\n }\n}\n"],"names":[],"mappings":";;;;;AAAA;AACA;AAcA;;AAEG;MACU,YAAY,CAAA;AACvB;;AAEG;AACH,IAAA,OAAO,UAAU,CACf,WAA0B,EAC1B,YAA6B,EAC7B,kBAA2C,EAAA;AAE3C,QAAA,MAAM,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,KAAK,EACL,OAAO,EACP,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,uBAAuB,EACvB,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,cAAc,GACf,GAAG,WAAW;AAEf,QAAA,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC;YACpC,OAAO;YACP,QAAQ;YACR,aAAa;YACb,gBAAgB;YAChB,YAAY;YACZ,KAAK;YACL,OAAO;YACP,YAAY;YACZ,YAAY;AACZ,YAAA,sBAAsB,EAAE,uBAAuB;YAC/C,YAAY;YACZ,OAAO;AACP,YAAA,iBAAiB,EAAE,CAAC;YACpB,YAAY;YACZ,gBAAgB;YAChB,cAAc;AACf,SAAA,CAAC;QAEF,IAAI,YAAY,EAAE;;;;YAIhB,YAAY,CAAC,wBAAwB,EAAE;AAEvC,YAAA,MAAM,QAAQ,GAAG,kBAAkB,IAAI,EAAE;AACzC,YAAA,YAAY,CAAC,kBAAkB,GAAG,QAAQ;YAC1C,YAAY,CAAC,uBAAuB,GAAG;iBACpC,0BAA0B,CAAC,YAAY;iBACvC,IAAI,CAAC,MAAK;;AAET,gBAAA,YAAY,CAAC,8BAA8B,CAAC,QAAQ,CAAC;AACvD,aAAC;AACA,iBAAA,KAAK,CAAC,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC;AAC7D,aAAC,CAAC;;aACC,IAAI,kBAAkB,EAAE;AAC7B,YAAA,YAAY,CAAC,kBAAkB,GAAG,kBAAkB;;AAGtD,QAAA,OAAO,YAAY;;;AAIrB,IAAA,OAAO;;AAEP,IAAA,QAAQ;;AAER,IAAA,aAAa;;IAEb,kBAAkB,GAAuC,EAAE;;AAE3D,IAAA,gBAAgB;;AAEhB,IAAA,YAAY;;AAEZ,IAAA,aAAa;;AAEb,IAAA,YAAY;;IAEZ,iBAAiB,GAAW,CAAC;;AAE7B,IAAA,YAAY;;AAEZ,IAAA,cAAc;;AAEd,IAAA,KAAK;;AAEL,IAAA,OAAO;AACP;;;AAGG;AACH,IAAA,YAAY;;AAEZ,IAAA,mBAAmB,GAAgB,IAAI,GAAG,EAAE;;AAE5C,IAAA,YAAY;;AAEZ,IAAA,sBAAsB;AACtB;;;;AAIG;AACH,IAAA,cAAc;;IAEd,YAAY,GAAsC,mBAAmB;;AAErE,IAAA,SAAS;;AAET,IAAA,eAAe;;AAEf,IAAA,gBAAgB,GACd,YAAY,CAAC,IAAI;;IAEnB,OAAO,GAAY,KAAK;;AAEhB,IAAA,oBAAoB;;IAMpB,mBAAmB,GAAY,IAAI;;IAEnC,mBAAmB,GAAW,CAAC;;AAEvC,IAAA,uBAAuB;;IAEvB,gBAAgB,GAAY,KAAK;;IAEzB,WAAW,GAA4C,EAAE;;IAEzD,eAAe,GAAW,CAAC;AAEnC,IAAA,WAAA,CAAY,EACV,OAAO,EACP,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,KAAK,EACL,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,YAAY,EACZ,OAAO,EACP,iBAAiB,EACjB,gBAAgB,GAkBjB,EAAA;AACC,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;AACtB,QAAA,IAAI,CAAC,QAAQ,GAAG,QAAQ;AACxB,QAAA,IAAI,CAAC,aAAa,GAAG,aAAa;AAClC,QAAA,IAAI,CAAC,gBAAgB,GAAG,gBAAgB;AACxC,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY;AAChC,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY;AAChC,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;AAClB,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;AACtB,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY;AAChC,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY;AAChC,QAAA,IAAI,CAAC,sBAAsB,GAAG,sBAAsB;AACpD,QAAA,IAAI,CAAC,cAAc,GAAG,cAAc;QACpC,IAAI,YAAY,EAAE;AAChB,YAAA,IAAI,CAAC,YAAY,GAAG,YAAY;;AAElC,QAAA,IAAI,OAAO,KAAK,SAAS,EAAE;AACzB,YAAA,IAAI,CAAC,OAAO,GAAG,OAAO;;AAExB,QAAA,IAAI,iBAAiB,KAAK,SAAS,EAAE;AACnC,YAAA,IAAI,CAAC,iBAAiB,GAAG,iBAAiB;;AAG5C,QAAA,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,IAAI,KAAK;;AAGnD;;;;;;;;AAQG;IACK,sCAAsC,GAAA;QAC5C,IAAI,CAAC,IAAI,CAAC,YAAY;AAAE,YAAA,OAAO,EAAE;QAEjC,MAAM,qBAAqB,GAAe,EAAE;QAC5C,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE;YAC/C,MAAM,cAAc,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,QAAQ,CAAC;AAC5D,YAAA,MAAM,mBAAmB,GACvB,cAAc,CAAC,QAAQ,CAAC,gBAAgB,CAAC;AACzC,gBAAA,CAAC,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAEpC,YAAA,IAAI,CAAC,mBAAmB;gBAAE;;AAG1B,YAAA,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,KAAK,IAAI;YACjD,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;AACvD,YAAA,IAAI,CAAC,UAAU,IAAI,YAAY,EAAE;AAC/B,gBAAA,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC;;;AAIvC,QAAA,IAAI,qBAAqB,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,OAAO,EAAE;QAEjD,MAAM,gBAAgB,GAAG;AACtB,aAAA,GAAG,CAAC,CAAC,IAAI,KAAI;AACZ,YAAA,IAAI,IAAI,GAAG,CAAA,IAAA,EAAO,IAAI,CAAC,IAAI,IAAI;AAC/B,YAAA,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,EAAE,EAAE;AACvD,gBAAA,IAAI,IAAI,CAAK,EAAA,EAAA,IAAI,CAAC,WAAW,EAAE;;AAEjC,YAAA,IAAI,IAAI,CAAC,UAAU,EAAE;gBACnB,IAAI,IAAI,mBAAmB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA,CAAE;;AAE9F,YAAA,OAAO,IAAI;AACb,SAAC;aACA,IAAI,CAAC,MAAM,CAAC;AAEf,QAAA,QACE,oCAAoC;YACpC,wFAAwF;YACxF,kHAAkH;AAClH,YAAA,gBAAgB;;AAIpB;;;;AAIG;AACH,IAAA,IAAI,cAAc,GAAA;;QAQhB,IAAI,CAAC,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC,oBAAoB,KAAK,SAAS,EAAE;YACxE,OAAO,IAAI,CAAC,oBAAoB;;;AAIlC,QAAA,MAAM,kBAAkB,GAAG,IAAI,CAAC,uBAAuB,EAAE;QACzD,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,CAAC;AACxE,QAAA,IAAI,CAAC,mBAAmB,GAAG,KAAK;QAChC,OAAO,IAAI,CAAC,oBAAoB;;AAGlC;;;AAGG;IACH,wBAAwB,GAAA;QACtB,IAAI,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC,oBAAoB,KAAK,SAAS,EAAE;AACvE,YAAA,MAAM,kBAAkB,GAAG,IAAI,CAAC,uBAAuB,EAAE;YACzD,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,CAAC;AACxE,YAAA,IAAI,CAAC,mBAAmB,GAAG,KAAK;;;AAIpC;;AAEG;IACK,uBAAuB,GAAA;AAC7B,QAAA,IAAI,MAAM,GAAG,IAAI,CAAC,YAAY,IAAI,EAAE;AAEpC,QAAA,IACE,IAAI,CAAC,sBAAsB,IAAI,IAAI;AACnC,YAAA,IAAI,CAAC,sBAAsB,KAAK,EAAE,EAClC;AACA,YAAA,MAAM,GAAG;AACP,kBAAE,CAAG,EAAA,MAAM,OAAO,IAAI,CAAC,sBAAsB,CAAE;AAC/C,kBAAE,IAAI,CAAC,sBAAsB;;AAGjC,QAAA,MAAM,oBAAoB,GAAG,IAAI,CAAC,sCAAsC,EAAE;QAC1E,IAAI,oBAAoB,EAAE;AACxB,YAAA,MAAM,GAAG;AACP,kBAAE,CAAA,EAAG,MAAM,CAAA,EAAG,oBAAoB,CAAE;kBAClC,oBAAoB;;AAG1B,QAAA,OAAO,MAAM;;AAGf;;;AAGG;AACK,IAAA,mBAAmB,CACzB,kBAA0B,EAAA;QAQ1B,IAAI,CAAC,kBAAkB,EAAE;;AAEvB,YAAA,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,mBAAmB;AAClD,YAAA,IAAI,CAAC,mBAAmB,GAAG,CAAC;AAC5B,YAAA,OAAO,SAAS;;QAGlB,IAAI,iBAAiB,GAA+B,kBAAkB;;QAGtE,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,SAAS,EAAE;AACzC,YAAA,MAAM,gBAAgB,GAAG,IAAI,CAAC,aAEjB;AACb,YAAA,MAAM,cAAc,GAAG,gBAAgB,EAAE,aAAa,EAAE,cAE3C;AACb,YAAA,MAAM,aAAa,GAAG,cAAc,GAAG,gBAAgB,CAAC;YACxD,IACE,OAAO,aAAa,KAAK,QAAQ;AACjC,gBAAA,aAAa,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EACxC;AACA,gBAAA,iBAAiB,GAAG;AAClB,oBAAA,OAAO,EAAE;AACP,wBAAA;AACE,4BAAA,IAAI,EAAE,MAAM;AACZ,4BAAA,IAAI,EAAE,kBAAkB;AACxB,4BAAA,aAAa,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;AACrC,yBAAA;AACF,qBAAA;iBACF;;;;;;;QAQL,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,OAAO,EAAE;AACvC,YAAA,MAAM,cAAc,GAAG,IAAI,CAAC,aAEf;YACb,MAAM,OAAO,GAAG,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE;YAC1D,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAE/G,IAAI,cAAc,EAAE,WAAW,KAAK,IAAI,IAAI,eAAe,EAAE;AAE3D,gBAAA,iBAAiB,GAAG;AAClB,oBAAA,OAAO,EAAE;AACP,wBAAA;AACE,4BAAA,IAAI,EAAE,MAAM;AACZ,4BAAA,IAAI,EAAE,kBAAkB;AACzB,yBAAA;AACD,wBAAA;AACE,4BAAA,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;AAChC,yBAAA;AACF,qBAAA;iBACF;;;AAIL,QAAA,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,iBAAiB,CAAC;;AAG1D,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,mBAAmB;YAClD,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC;AAC3D,YAAA,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,mBAAmB;;AAGpD,QAAA,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,QAAuB,KAAI;AACrD,YAAA,OAAO,CAAC,aAAa,EAAE,GAAG,QAAQ,CAAC;SACpC,CAAC,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;;AAGtC;;AAEG;IACH,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,iBAAiB,GAAG,CAAC;AAC1B,QAAA,IAAI,CAAC,mBAAmB,GAAG,CAAC;AAC5B,QAAA,IAAI,CAAC,WAAW,GAAG,EAAE;AACrB,QAAA,IAAI,CAAC,eAAe,GAAG,CAAC;AACxB,QAAA,IAAI,CAAC,oBAAoB,GAAG,SAAS;AACrC,QAAA,IAAI,CAAC,mBAAmB,GAAG,IAAI;AAC/B,QAAA,IAAI,CAAC,SAAS,GAAG,SAAS;AAC1B,QAAA,IAAI,CAAC,kBAAkB,GAAG,EAAE;AAC5B,QAAA,IAAI,CAAC,YAAY,GAAG,SAAS;AAC7B,QAAA,IAAI,CAAC,aAAa,GAAG,SAAS;AAC9B,QAAA,IAAI,CAAC,cAAc,GAAG,SAAS;AAC/B,QAAA,IAAI,CAAC,eAAe,GAAG,SAAS;AAChC,QAAA,IAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC,IAAI;AACzC,QAAA,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE;;AAGlC;;AAEG;AACH,IAAA,8BAA8B,CAAC,YAAoC,EAAA;AACjE,QAAA,IAAI,IAAI,CAAC,iBAAiB,GAAG,CAAC,EAAE;;YAE9B,MAAM,UAAU,GAA2B,EAAE;AAC7C,YAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;gBACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;AAC/B,gBAAA,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;AACjB,oBAAA,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,wBAAA,KAAK,IAAI,KAAK,KAAK,CAAC,GAAG,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;;;AAGxD,YAAA,IAAI,CAAC,kBAAkB,GAAG,UAAU;;aAC/B;AACL,YAAA,IAAI,CAAC,kBAAkB,GAAG,EAAE,GAAG,YAAY,EAAE;;;AAIjD;;;;AAIG;IACH,MAAM,0BAA0B,CAC9B,YAA4B,EAAA;QAE5B,IAAI,UAAU,GAAG,CAAC;AAClB,QAAA,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;AAEtB,QAAA,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AACvC,YAAA,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE;gBAC7B,MAAM,WAAW,GAAG,IAA+B;AACnD,gBAAA,IACE,WAAW,CAAC,MAAM,IAAI,IAAI;AAC1B,oBAAA,OAAO,WAAW,CAAC,MAAM,KAAK,QAAQ,EACtC;AACA,oBAAA,MAAM,MAAM,GAAG,WAAW,CAAC,MAE1B;AACD,oBAAA,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,CACpC,WAAW,CAAC,WAAsB,IAAI,EAAE,CAC1C;AACD,oBAAA,MAAM,UAAU,GAAG,eAAe,CAChC,eAAwD,EACvD,WAAW,CAAC,IAAe,IAAI,EAAE,CACnC;AACD,oBAAA,MAAM,QAAQ,GAAI,WAAW,CAAC,IAAe,IAAI,SAAS;AAC1D,oBAAA,MAAM,MAAM,GAAG,YAAY,CACzB,IAAI,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAC9C;;AAGD,oBAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;oBACjD,UAAU,IAAI,MAAM;;;;;AAM1B,QAAA,IAAI,CAAC,eAAe,GAAG,UAAU;;AAGjC,QAAA,IAAI,CAAC,iBAAiB,IAAI,UAAU;;AAGtC;;;;AAIG;IACH,mBAAmB,GAAA;QAUjB,OAAO;;YAEL,YAAY,EAAE,IAAI,CAAC,mBAAmB;;AAEtC,YAAA,SAAS,EAAE,CAAC;;YAEZ,KAAK,EAAE,IAAI,CAAC,eAAe;;AAE3B,YAAA,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;;AAElC,YAAA,WAAW,EAAE,CAAC;;YAEd,KAAK,EAAE,IAAI,CAAC,iBAAiB;;AAE7B,YAAA,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;;AAElC,YAAA,iBAAiB,EAAE,EAAE;SACtB;;AAGH;;;;AAIG;IACH,uBAAuB,CAAC,eAAwB,IAAI,EAAA;AAClD,QAAA,MAAM,QAAQ,GAAqB,IAAI,GAAG,EAAE;AAE5C,QAAA,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;AACtB,YAAA,OAAO,QAAQ;;QAGjB,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE;YAC/C,IAAI,CAAC,YAAY,IAAI,OAAO,CAAC,aAAa,KAAK,IAAI,EAAE;AACnD,gBAAA,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC;;;AAI/B,QAAA,OAAO,QAAQ;;AAGjB;;;;;;AAMG;AACH,IAAA,qBAAqB,CAAC,SAAmB,EAAA;QACvC,IAAI,iBAAiB,GAAG,KAAK;AAC7B,QAAA,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE;YAC5B,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACvC,gBAAA,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;gBAClC,iBAAiB,GAAG,IAAI;;;QAG5B,IAAI,iBAAiB,EAAE;AACrB,YAAA,IAAI,CAAC,mBAAmB,GAAG,IAAI;;AAEjC,QAAA,OAAO,iBAAiB;;AAG1B;;;;;;AAMG;IACH,kBAAkB,GAAA;QAChB,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;YACrC,OAAO,IAAI,CAAC,KAAK;;QAGnB,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAI;AAChD,YAAA,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC,EAAE;gBACrB,OAAO,IAAI,CAAC;;AAGd,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YACjD,IAAI,CAAC,OAAO,EAAE;gBACZ,OAAO,IAAI,CAAC;;;YAId,IAAI,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;;gBAE3C,MAAM,cAAc,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,QAAQ,CAAC;AAC5D,gBAAA,OAAO,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC;;;YAI1C,MAAM,cAAc,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,QAAQ,CAAC;AAC5D,YAAA,QACE,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,aAAa,KAAK,IAAI;AAEvE,SAAC,CAAC;AAEF,QAAA,OAAO,cAAc;;AAExB;;;;"}
@@ -231,6 +231,17 @@ class StandardGraph extends Graph {
231
231
  }
232
232
  return contentPartAgentMap;
233
233
  }
234
+ /**
235
+ * Get the context breakdown from the primary agent for admin token tracking.
236
+ * Returns detailed token counts for instructions, tools, etc.
237
+ */
238
+ getContextBreakdown() {
239
+ const primaryContext = this.agentContexts.get(this.defaultAgentId);
240
+ if (!primaryContext) {
241
+ return null;
242
+ }
243
+ return primaryContext.getContextBreakdown();
244
+ }
234
245
  /* Graph */
235
246
  createSystemRunnable({ provider, clientOptions, instructions, additional_instructions, }) {
236
247
  let finalInstructions = instructions;