@librechat/agents 3.2.33 → 3.2.35

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.
Files changed (133) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +47 -10
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/common/enum.cjs +13 -0
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +121 -3
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/llm/bedrock/index.cjs +21 -2
  8. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  9. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +38 -2
  10. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -1
  11. package/dist/cjs/llm/google/utils/common.cjs +6 -0
  12. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  13. package/dist/cjs/llm/invoke.cjs +49 -8
  14. package/dist/cjs/llm/invoke.cjs.map +1 -1
  15. package/dist/cjs/llm/openai/index.cjs +48 -1
  16. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  17. package/dist/cjs/llm/vertexai/index.cjs +19 -0
  18. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  19. package/dist/cjs/main.cjs +2 -0
  20. package/dist/cjs/messages/content.cjs +12 -14
  21. package/dist/cjs/messages/content.cjs.map +1 -1
  22. package/dist/cjs/messages/prune.cjs +31 -13
  23. package/dist/cjs/messages/prune.cjs.map +1 -1
  24. package/dist/cjs/run.cjs +7 -2
  25. package/dist/cjs/run.cjs.map +1 -1
  26. package/dist/cjs/stream.cjs +20 -2
  27. package/dist/cjs/stream.cjs.map +1 -1
  28. package/dist/cjs/summarization/node.cjs +12 -1
  29. package/dist/cjs/summarization/node.cjs.map +1 -1
  30. package/dist/cjs/tools/ToolNode.cjs +41 -4
  31. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  32. package/dist/cjs/tools/streamedToolCallSeals.cjs +30 -1
  33. package/dist/cjs/tools/streamedToolCallSeals.cjs.map +1 -1
  34. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +138 -2
  35. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  36. package/dist/cjs/utils/tokens.cjs +30 -0
  37. package/dist/cjs/utils/tokens.cjs.map +1 -1
  38. package/dist/esm/agents/AgentContext.mjs +47 -10
  39. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  40. package/dist/esm/common/enum.mjs +13 -0
  41. package/dist/esm/common/enum.mjs.map +1 -1
  42. package/dist/esm/graphs/Graph.mjs +122 -4
  43. package/dist/esm/graphs/Graph.mjs.map +1 -1
  44. package/dist/esm/llm/bedrock/index.mjs +22 -3
  45. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  46. package/dist/esm/llm/bedrock/utils/message_outputs.mjs +38 -3
  47. package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -1
  48. package/dist/esm/llm/google/utils/common.mjs +6 -0
  49. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  50. package/dist/esm/llm/invoke.mjs +49 -8
  51. package/dist/esm/llm/invoke.mjs.map +1 -1
  52. package/dist/esm/llm/openai/index.mjs +48 -1
  53. package/dist/esm/llm/openai/index.mjs.map +1 -1
  54. package/dist/esm/llm/vertexai/index.mjs +19 -0
  55. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  56. package/dist/esm/main.mjs +3 -3
  57. package/dist/esm/messages/content.mjs +12 -15
  58. package/dist/esm/messages/content.mjs.map +1 -1
  59. package/dist/esm/messages/prune.mjs +31 -13
  60. package/dist/esm/messages/prune.mjs.map +1 -1
  61. package/dist/esm/run.mjs +7 -2
  62. package/dist/esm/run.mjs.map +1 -1
  63. package/dist/esm/stream.mjs +21 -3
  64. package/dist/esm/stream.mjs.map +1 -1
  65. package/dist/esm/summarization/node.mjs +12 -1
  66. package/dist/esm/summarization/node.mjs.map +1 -1
  67. package/dist/esm/tools/ToolNode.mjs +41 -4
  68. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  69. package/dist/esm/tools/streamedToolCallSeals.mjs +25 -2
  70. package/dist/esm/tools/streamedToolCallSeals.mjs.map +1 -1
  71. package/dist/esm/tools/subagent/SubagentExecutor.mjs +138 -2
  72. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  73. package/dist/esm/utils/tokens.mjs +30 -1
  74. package/dist/esm/utils/tokens.mjs.map +1 -1
  75. package/dist/types/agents/AgentContext.d.ts +7 -3
  76. package/dist/types/common/enum.d.ts +13 -0
  77. package/dist/types/graphs/Graph.d.ts +8 -1
  78. package/dist/types/llm/bedrock/utils/index.d.ts +1 -1
  79. package/dist/types/llm/bedrock/utils/message_outputs.d.ts +9 -0
  80. package/dist/types/llm/invoke.d.ts +1 -1
  81. package/dist/types/llm/vertexai/index.d.ts +10 -0
  82. package/dist/types/messages/content.d.ts +5 -0
  83. package/dist/types/messages/prune.d.ts +4 -0
  84. package/dist/types/run.d.ts +1 -0
  85. package/dist/types/tools/ToolNode.d.ts +8 -0
  86. package/dist/types/tools/streamedToolCallSeals.d.ts +5 -1
  87. package/dist/types/tools/subagent/SubagentExecutor.d.ts +11 -1
  88. package/dist/types/types/graph.d.ts +89 -3
  89. package/dist/types/types/run.d.ts +13 -0
  90. package/dist/types/types/tools.d.ts +10 -0
  91. package/dist/types/utils/tokens.d.ts +7 -0
  92. package/package.json +1 -1
  93. package/src/__tests__/stream.eagerEventExecution.test.ts +703 -0
  94. package/src/agents/AgentContext.ts +69 -6
  95. package/src/agents/__tests__/AgentContext.test.ts +6 -2
  96. package/src/common/enum.ts +13 -0
  97. package/src/graphs/Graph.ts +196 -0
  98. package/src/llm/bedrock/index.ts +40 -0
  99. package/src/llm/bedrock/streamSealDispatch.test.ts +158 -0
  100. package/src/llm/bedrock/utils/index.ts +1 -0
  101. package/src/llm/bedrock/utils/message_outputs.test.ts +85 -0
  102. package/src/llm/bedrock/utils/message_outputs.ts +43 -0
  103. package/src/llm/google/utils/common.test.ts +64 -0
  104. package/src/llm/google/utils/common.ts +18 -0
  105. package/src/llm/invoke.test.ts +79 -1
  106. package/src/llm/invoke.ts +58 -4
  107. package/src/llm/openai/index.ts +95 -1
  108. package/src/llm/openai/sequentialToolCallSeals.test.ts +199 -0
  109. package/src/llm/vertexai/index.ts +31 -0
  110. package/src/llm/vertexai/sealStreamedToolCalls.test.ts +88 -0
  111. package/src/llm/vertexai/streamSealDispatch.test.ts +148 -0
  112. package/src/messages/content.ts +24 -32
  113. package/src/messages/prune.ts +39 -2
  114. package/src/run.ts +5 -0
  115. package/src/scripts/subagent-usage-sink.ts +176 -0
  116. package/src/specs/context-accuracy.live.test.ts +409 -0
  117. package/src/specs/context-usage-event.test.ts +117 -0
  118. package/src/specs/context-usage.live.test.ts +297 -0
  119. package/src/specs/prune.test.ts +51 -1
  120. package/src/specs/subagent.test.ts +124 -1
  121. package/src/stream.ts +40 -6
  122. package/src/summarization/__tests__/node.test.ts +60 -1
  123. package/src/summarization/node.ts +20 -1
  124. package/src/tools/ToolNode.ts +85 -3
  125. package/src/tools/__tests__/SubagentExecutor.test.ts +443 -1
  126. package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +368 -0
  127. package/src/tools/streamedToolCallSeals.ts +37 -9
  128. package/src/tools/subagent/SubagentExecutor.ts +221 -3
  129. package/src/types/graph.ts +94 -1
  130. package/src/types/run.ts +13 -0
  131. package/src/types/tools.ts +10 -0
  132. package/src/utils/__tests__/apportion.test.ts +32 -0
  133. package/src/utils/tokens.ts +33 -0
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.cjs","names":["Tokenizer"],"sources":["../../../src/utils/tokens.ts"],"sourcesContent":["import { Tokenizer } from 'ai-tokenizer';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport { ContentTypes } from '@/common/enum';\n\nexport type EncodingName = 'o200k_base' | 'claude';\n\n/** Anthropic minimum image token cost. */\nconst ANTHROPIC_IMAGE_MIN_TOKENS = 1024;\n/** Anthropic divisor: tokens = width × height / 750. */\nconst ANTHROPIC_IMAGE_DIVISOR = 750;\n/** OpenAI low-detail fixed cost. */\nconst OPENAI_IMAGE_LOW_TOKENS = 85;\n/** OpenAI high-detail tile size. */\nconst OPENAI_IMAGE_TILE_SIZE = 512;\n/** OpenAI high-detail tokens per tile. */\nconst OPENAI_IMAGE_TOKENS_PER_TILE = 170;\n/** Google Gemini fixed per-image cost. */\nconst _GEMINI_IMAGE_TOKENS = 258;\n/** Safety margin for image and document token estimates (5% overestimate). */\nconst IMAGE_TOKEN_SAFETY_MARGIN = 1.05;\n\n/**\n * Anthropic PDF: each page costs image tokens + text tokens.\n * Typical range is 1500-3000 tokens/page. Using 2000 as midpoint.\n */\nconst ANTHROPIC_PDF_TOKENS_PER_PAGE = 2000;\n/** OpenAI PDF: each page rendered as high-detail image. ~1500 tokens typical. */\nconst OPENAI_PDF_TOKENS_PER_PAGE = 1500;\n/** Gemini PDF: fixed 258 tokens per page. */\nconst _GEMINI_PDF_TOKENS_PER_PAGE = 258;\n/** Approximate base64 bytes per PDF page for page count estimation. */\nconst BASE64_BYTES_PER_PDF_PAGE = 75_000;\n/** Fallback token cost for URL-referenced documents without local data. */\nconst URL_DOCUMENT_FALLBACK_TOKENS = 2000;\n\n/**\n * Extracts image dimensions from the first bytes of a base64-encoded\n * PNG, JPEG, GIF, or WebP without decoding the full image.\n * Returns null if the format is unrecognized or data is too short.\n */\nexport function extractImageDimensions(\n base64Data: string\n): { width: number; height: number } | null {\n const raw = base64Data.startsWith('data:')\n ? base64Data.slice(base64Data.indexOf(',') + 1)\n : base64Data;\n\n if (raw.length < 32) {\n return null;\n }\n\n const bytes = new Uint8Array(Buffer.from(raw.slice(0, 80), 'base64'));\n\n if (bytes[0] === 0x89 && bytes[1] === 0x50) {\n // PNG: width at bytes 16-19, height at 20-23 (big-endian)\n const width =\n (bytes[16] << 24) | (bytes[17] << 16) | (bytes[18] << 8) | bytes[19];\n const height =\n (bytes[20] << 24) | (bytes[21] << 16) | (bytes[22] << 8) | bytes[23];\n return { width, height };\n }\n\n if (bytes[0] === 0xff && bytes[1] === 0xd8) {\n // JPEG: scan for SOF0 (0xFFC0) or SOF2 (0xFFC2) marker\n for (let i = 2; i < bytes.length - 9; i++) {\n if (\n bytes[i] === 0xff &&\n (bytes[i + 1] === 0xc0 || bytes[i + 1] === 0xc2)\n ) {\n const height = (bytes[i + 5] << 8) | bytes[i + 6];\n const width = (bytes[i + 7] << 8) | bytes[i + 8];\n return { width, height };\n }\n }\n return null;\n }\n\n if (bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46) {\n // GIF: width at bytes 6-7, height at 8-9 (little-endian)\n const width = bytes[6] | (bytes[7] << 8);\n const height = bytes[8] | (bytes[9] << 8);\n return { width, height };\n }\n\n if (\n bytes[0] === 0x52 &&\n bytes[1] === 0x49 &&\n bytes[2] === 0x46 &&\n bytes[3] === 0x46 &&\n bytes[8] === 0x57 &&\n bytes[9] === 0x45 &&\n bytes[10] === 0x42 &&\n bytes[11] === 0x50\n ) {\n // WebP VP8: width at bytes 26-27, height at 28-29\n if (bytes.length > 29) {\n const width = (bytes[26] | (bytes[27] << 8)) & 0x3fff;\n const height = (bytes[28] | (bytes[29] << 8)) & 0x3fff;\n return { width, height };\n }\n return null;\n }\n\n return null;\n}\n\n/** Estimates image token cost for Anthropic/Bedrock (Claude). */\nexport function estimateAnthropicImageTokens(\n width: number,\n height: number\n): number {\n return Math.max(\n ANTHROPIC_IMAGE_MIN_TOKENS,\n Math.ceil((width * height) / ANTHROPIC_IMAGE_DIVISOR)\n );\n}\n\n/** Estimates image token cost for OpenAI (high detail). */\nexport function estimateOpenAIImageTokens(\n width: number,\n height: number,\n detail: string = 'high'\n): number {\n if (detail === 'low') {\n return OPENAI_IMAGE_LOW_TOKENS;\n }\n const tiles =\n Math.ceil(width / OPENAI_IMAGE_TILE_SIZE) *\n Math.ceil(height / OPENAI_IMAGE_TILE_SIZE);\n return OPENAI_IMAGE_LOW_TOKENS + tiles * OPENAI_IMAGE_TOKENS_PER_TILE;\n}\n\n/**\n * Estimates token cost for an image content block.\n * Extracts dimensions from base64 header when available.\n * Falls back to Anthropic minimum (1024) when dimensions can't be determined.\n */\nfunction estimateImageBlockTokens(\n block: Record<string, unknown>,\n encoding: EncodingName\n): number {\n let base64Data: string | undefined;\n\n if (block.type === ContentTypes.IMAGE_URL || block.type === 'image_url') {\n const imageUrl = block.image_url as string | { url?: string } | undefined;\n const url = typeof imageUrl === 'string' ? imageUrl : imageUrl?.url;\n if (typeof url === 'string' && url.startsWith('data:')) {\n base64Data = url;\n } else {\n return ANTHROPIC_IMAGE_MIN_TOKENS;\n }\n } else if (block.type === 'image') {\n const source = block.source as { type?: string; data?: string } | undefined;\n if (source?.type === 'base64' && typeof source.data === 'string') {\n base64Data = source.data;\n } else {\n return ANTHROPIC_IMAGE_MIN_TOKENS;\n }\n } else {\n return ANTHROPIC_IMAGE_MIN_TOKENS;\n }\n\n const dims = extractImageDimensions(base64Data);\n if (dims == null) {\n return ANTHROPIC_IMAGE_MIN_TOKENS;\n }\n\n if (encoding === 'claude') {\n return estimateAnthropicImageTokens(dims.width, dims.height);\n }\n return estimateOpenAIImageTokens(dims.width, dims.height);\n}\n\n/**\n * Estimates token cost for a document/file content block.\n * Handles both LangChain standard format (`type: 'file'` with `source_type`)\n * and Anthropic format (`type: 'document'` with `source`).\n *\n * - Plain text: tokenized directly via `getTokenCount`.\n * - Base64 PDF: page count estimated from base64 length × per-page cost.\n * - URL reference: conservative flat estimate.\n */\nfunction estimateDocumentBlockTokens(\n block: Record<string, unknown>,\n encoding: EncodingName,\n getTokenCount: (text: string) => number\n): number {\n const pdfTokensPerPage =\n encoding === 'claude'\n ? ANTHROPIC_PDF_TOKENS_PER_PAGE\n : OPENAI_PDF_TOKENS_PER_PAGE;\n\n // LangChain standard format: type='file', source_type, data/text/url, mime_type\n const sourceType = block.source_type as string | undefined;\n if (typeof sourceType === 'string') {\n const mimeType = ((block.mime_type as string | undefined) ?? '').split(\n ';'\n )[0];\n\n if (sourceType === 'text' && typeof block.text === 'string') {\n return getTokenCount(block.text as string);\n }\n\n if (sourceType === 'base64' && typeof block.data === 'string') {\n if (mimeType === 'application/pdf' || mimeType === '') {\n const pageEstimate = Math.max(\n 1,\n Math.ceil((block.data as string).length / BASE64_BYTES_PER_PDF_PAGE)\n );\n return pageEstimate * pdfTokensPerPage;\n }\n // Image inside a file block — delegate to image estimation\n if (mimeType.startsWith('image/')) {\n return estimateImageBlockTokens(\n {\n ...block,\n type: 'image',\n source: { type: 'base64', data: block.data },\n },\n encoding\n );\n }\n return getTokenCount(block.data as string);\n }\n\n if (sourceType === 'url') {\n return URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n return URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n // Anthropic format: type='document', source: { type, data, media_type }\n const source = block.source as\n | {\n type?: string;\n data?: string;\n media_type?: string;\n content?: unknown[];\n }\n | undefined;\n\n if (source == null) {\n return URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n if (source.type === 'text' && typeof source.data === 'string') {\n return getTokenCount(source.data);\n }\n\n if (source.type === 'base64' && typeof source.data === 'string') {\n const mediaType = (source.media_type ?? '').split(';')[0];\n if (mediaType === 'application/pdf' || mediaType === '') {\n const pageEstimate = Math.max(\n 1,\n Math.ceil(source.data.length / BASE64_BYTES_PER_PDF_PAGE)\n );\n return pageEstimate * pdfTokensPerPage;\n }\n if (mediaType.startsWith('image/')) {\n return estimateImageBlockTokens(\n { type: 'image', source: { type: 'base64', data: source.data } },\n encoding\n );\n }\n return getTokenCount(source.data);\n }\n\n if (source.type === 'url') {\n return URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n // content-type source (wraps other blocks like images)\n if (source.type === 'content' && Array.isArray(source.content)) {\n let total = 0;\n for (const inner of source.content) {\n if (inner != null && typeof inner === 'object' && 'type' in inner) {\n const innerBlock = inner as Record<string, unknown>;\n if (innerBlock.type === 'image') {\n total += estimateImageBlockTokens(innerBlock, encoding);\n }\n }\n }\n return total > 0 ? total : URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n return URL_DOCUMENT_FALLBACK_TOKENS;\n}\n\nconst tokenizers: Partial<Record<EncodingName, Tokenizer>> = {};\n\nasync function getTokenizer(\n encoding: EncodingName = 'o200k_base'\n): Promise<Tokenizer> {\n const cached = tokenizers[encoding];\n if (cached) {\n return cached;\n }\n const data =\n encoding === 'claude'\n ? await import('ai-tokenizer/encoding/claude')\n : await import('ai-tokenizer/encoding/o200k_base');\n const instance = new Tokenizer(data);\n tokenizers[encoding] = instance;\n return instance;\n}\n\nexport function encodingForModel(model: string): EncodingName {\n if (model.toLowerCase().includes('claude')) {\n return 'claude';\n }\n return 'o200k_base';\n}\n\nexport function getTokenCountForMessage(\n message: BaseMessage,\n getTokenCount: (text: string) => number,\n encoding: EncodingName = 'o200k_base'\n): number {\n const tokensPerMessage = 3;\n\n type ContentBlock = Record<string, unknown> & {\n type?: string;\n tool_call?: { name?: string; args?: string; output?: string };\n };\n\n const processValue = (value: unknown): void => {\n if (Array.isArray(value)) {\n for (const raw of value) {\n const item = raw as ContentBlock | null | undefined;\n if (item == null || typeof item.type !== 'string') {\n continue;\n }\n if (item.type === ContentTypes.ERROR) {\n continue;\n }\n\n if (\n item.type === ContentTypes.IMAGE_URL ||\n item.type === 'image_url' ||\n item.type === 'image'\n ) {\n numTokens += Math.ceil(\n estimateImageBlockTokens(item, encoding) * IMAGE_TOKEN_SAFETY_MARGIN\n );\n continue;\n }\n\n if (\n item.type === 'document' ||\n item.type === 'file' ||\n item.type === ContentTypes.IMAGE_FILE\n ) {\n numTokens += Math.ceil(\n estimateDocumentBlockTokens(item, encoding, getTokenCount) *\n IMAGE_TOKEN_SAFETY_MARGIN\n );\n continue;\n }\n\n if (item.type === ContentTypes.TOOL_CALL && item.tool_call != null) {\n const toolName = item.tool_call.name;\n if (typeof toolName === 'string' && toolName.length > 0) {\n numTokens += getTokenCount(toolName);\n }\n const args = item.tool_call.args;\n if (typeof args === 'string' && args.length > 0) {\n numTokens += getTokenCount(args);\n }\n const output = item.tool_call.output;\n if (typeof output === 'string' && output.length > 0) {\n numTokens += getTokenCount(output);\n }\n continue;\n }\n\n const nestedValue = item[item.type];\n if (nestedValue == null) {\n continue;\n }\n\n processValue(nestedValue);\n }\n } else if (typeof value === 'string') {\n numTokens += getTokenCount(value);\n } else if (typeof value === 'number') {\n numTokens += getTokenCount(value.toString());\n } else if (typeof value === 'boolean') {\n numTokens += getTokenCount(value.toString());\n }\n };\n\n let numTokens = tokensPerMessage;\n processValue(message.content);\n return numTokens;\n}\n\n/**\n * Anthropic's API consistently reports ~10% more tokens than the local\n * claude tokenizer due to internal message framing and content encoding.\n * Verified empirically across content types via the count_tokens endpoint.\n */\nconst CLAUDE_TOKEN_CORRECTION = 1.1;\n\n/**\n * Creates a token counter function using the specified encoding.\n * Lazily loads the encoding data on first use via dynamic import.\n */\nexport const createTokenCounter = async (\n encoding: EncodingName = 'o200k_base'\n): Promise<(message: BaseMessage) => number> => {\n const tok = await getTokenizer(encoding);\n const countTokens = (text: string): number => tok.count(text);\n const isClaude = encoding === 'claude';\n return (message: BaseMessage): number => {\n const count = getTokenCountForMessage(message, countTokens, encoding);\n return isClaude ? Math.ceil(count * CLAUDE_TOKEN_CORRECTION) : count;\n };\n};\n\n/** Utility to manage the token encoder lifecycle explicitly. */\nexport const TokenEncoderManager = {\n async initialize(): Promise<void> {\n // No-op: ai-tokenizer is synchronously initialized from bundled data.\n },\n\n reset(): void {\n for (const key of Object.keys(tokenizers)) {\n delete tokenizers[key as EncodingName];\n }\n },\n\n isInitialized(): boolean {\n return Object.keys(tokenizers).length > 0;\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"tokens.cjs","names":["Tokenizer"],"sources":["../../../src/utils/tokens.ts"],"sourcesContent":["import { Tokenizer } from 'ai-tokenizer';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport { ContentTypes } from '@/common/enum';\n\nexport type EncodingName = 'o200k_base' | 'claude';\n\n/** Anthropic minimum image token cost. */\nconst ANTHROPIC_IMAGE_MIN_TOKENS = 1024;\n/** Anthropic divisor: tokens = width × height / 750. */\nconst ANTHROPIC_IMAGE_DIVISOR = 750;\n/** OpenAI low-detail fixed cost. */\nconst OPENAI_IMAGE_LOW_TOKENS = 85;\n/** OpenAI high-detail tile size. */\nconst OPENAI_IMAGE_TILE_SIZE = 512;\n/** OpenAI high-detail tokens per tile. */\nconst OPENAI_IMAGE_TOKENS_PER_TILE = 170;\n/** Google Gemini fixed per-image cost. */\nconst _GEMINI_IMAGE_TOKENS = 258;\n/** Safety margin for image and document token estimates (5% overestimate). */\nconst IMAGE_TOKEN_SAFETY_MARGIN = 1.05;\n\n/**\n * Anthropic PDF: each page costs image tokens + text tokens.\n * Typical range is 1500-3000 tokens/page. Using 2000 as midpoint.\n */\nconst ANTHROPIC_PDF_TOKENS_PER_PAGE = 2000;\n/** OpenAI PDF: each page rendered as high-detail image. ~1500 tokens typical. */\nconst OPENAI_PDF_TOKENS_PER_PAGE = 1500;\n/** Gemini PDF: fixed 258 tokens per page. */\nconst _GEMINI_PDF_TOKENS_PER_PAGE = 258;\n/** Approximate base64 bytes per PDF page for page count estimation. */\nconst BASE64_BYTES_PER_PDF_PAGE = 75_000;\n/** Fallback token cost for URL-referenced documents without local data. */\nconst URL_DOCUMENT_FALLBACK_TOKENS = 2000;\n\n/**\n * Extracts image dimensions from the first bytes of a base64-encoded\n * PNG, JPEG, GIF, or WebP without decoding the full image.\n * Returns null if the format is unrecognized or data is too short.\n */\nexport function extractImageDimensions(\n base64Data: string\n): { width: number; height: number } | null {\n const raw = base64Data.startsWith('data:')\n ? base64Data.slice(base64Data.indexOf(',') + 1)\n : base64Data;\n\n if (raw.length < 32) {\n return null;\n }\n\n const bytes = new Uint8Array(Buffer.from(raw.slice(0, 80), 'base64'));\n\n if (bytes[0] === 0x89 && bytes[1] === 0x50) {\n // PNG: width at bytes 16-19, height at 20-23 (big-endian)\n const width =\n (bytes[16] << 24) | (bytes[17] << 16) | (bytes[18] << 8) | bytes[19];\n const height =\n (bytes[20] << 24) | (bytes[21] << 16) | (bytes[22] << 8) | bytes[23];\n return { width, height };\n }\n\n if (bytes[0] === 0xff && bytes[1] === 0xd8) {\n // JPEG: scan for SOF0 (0xFFC0) or SOF2 (0xFFC2) marker\n for (let i = 2; i < bytes.length - 9; i++) {\n if (\n bytes[i] === 0xff &&\n (bytes[i + 1] === 0xc0 || bytes[i + 1] === 0xc2)\n ) {\n const height = (bytes[i + 5] << 8) | bytes[i + 6];\n const width = (bytes[i + 7] << 8) | bytes[i + 8];\n return { width, height };\n }\n }\n return null;\n }\n\n if (bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46) {\n // GIF: width at bytes 6-7, height at 8-9 (little-endian)\n const width = bytes[6] | (bytes[7] << 8);\n const height = bytes[8] | (bytes[9] << 8);\n return { width, height };\n }\n\n if (\n bytes[0] === 0x52 &&\n bytes[1] === 0x49 &&\n bytes[2] === 0x46 &&\n bytes[3] === 0x46 &&\n bytes[8] === 0x57 &&\n bytes[9] === 0x45 &&\n bytes[10] === 0x42 &&\n bytes[11] === 0x50\n ) {\n // WebP VP8: width at bytes 26-27, height at 28-29\n if (bytes.length > 29) {\n const width = (bytes[26] | (bytes[27] << 8)) & 0x3fff;\n const height = (bytes[28] | (bytes[29] << 8)) & 0x3fff;\n return { width, height };\n }\n return null;\n }\n\n return null;\n}\n\n/** Estimates image token cost for Anthropic/Bedrock (Claude). */\nexport function estimateAnthropicImageTokens(\n width: number,\n height: number\n): number {\n return Math.max(\n ANTHROPIC_IMAGE_MIN_TOKENS,\n Math.ceil((width * height) / ANTHROPIC_IMAGE_DIVISOR)\n );\n}\n\n/** Estimates image token cost for OpenAI (high detail). */\nexport function estimateOpenAIImageTokens(\n width: number,\n height: number,\n detail: string = 'high'\n): number {\n if (detail === 'low') {\n return OPENAI_IMAGE_LOW_TOKENS;\n }\n const tiles =\n Math.ceil(width / OPENAI_IMAGE_TILE_SIZE) *\n Math.ceil(height / OPENAI_IMAGE_TILE_SIZE);\n return OPENAI_IMAGE_LOW_TOKENS + tiles * OPENAI_IMAGE_TOKENS_PER_TILE;\n}\n\n/**\n * Estimates token cost for an image content block.\n * Extracts dimensions from base64 header when available.\n * Falls back to Anthropic minimum (1024) when dimensions can't be determined.\n */\nfunction estimateImageBlockTokens(\n block: Record<string, unknown>,\n encoding: EncodingName\n): number {\n let base64Data: string | undefined;\n\n if (block.type === ContentTypes.IMAGE_URL || block.type === 'image_url') {\n const imageUrl = block.image_url as string | { url?: string } | undefined;\n const url = typeof imageUrl === 'string' ? imageUrl : imageUrl?.url;\n if (typeof url === 'string' && url.startsWith('data:')) {\n base64Data = url;\n } else {\n return ANTHROPIC_IMAGE_MIN_TOKENS;\n }\n } else if (block.type === 'image') {\n const source = block.source as { type?: string; data?: string } | undefined;\n if (source?.type === 'base64' && typeof source.data === 'string') {\n base64Data = source.data;\n } else {\n return ANTHROPIC_IMAGE_MIN_TOKENS;\n }\n } else {\n return ANTHROPIC_IMAGE_MIN_TOKENS;\n }\n\n const dims = extractImageDimensions(base64Data);\n if (dims == null) {\n return ANTHROPIC_IMAGE_MIN_TOKENS;\n }\n\n if (encoding === 'claude') {\n return estimateAnthropicImageTokens(dims.width, dims.height);\n }\n return estimateOpenAIImageTokens(dims.width, dims.height);\n}\n\n/**\n * Estimates token cost for a document/file content block.\n * Handles both LangChain standard format (`type: 'file'` with `source_type`)\n * and Anthropic format (`type: 'document'` with `source`).\n *\n * - Plain text: tokenized directly via `getTokenCount`.\n * - Base64 PDF: page count estimated from base64 length × per-page cost.\n * - URL reference: conservative flat estimate.\n */\nfunction estimateDocumentBlockTokens(\n block: Record<string, unknown>,\n encoding: EncodingName,\n getTokenCount: (text: string) => number\n): number {\n const pdfTokensPerPage =\n encoding === 'claude'\n ? ANTHROPIC_PDF_TOKENS_PER_PAGE\n : OPENAI_PDF_TOKENS_PER_PAGE;\n\n // LangChain standard format: type='file', source_type, data/text/url, mime_type\n const sourceType = block.source_type as string | undefined;\n if (typeof sourceType === 'string') {\n const mimeType = ((block.mime_type as string | undefined) ?? '').split(\n ';'\n )[0];\n\n if (sourceType === 'text' && typeof block.text === 'string') {\n return getTokenCount(block.text as string);\n }\n\n if (sourceType === 'base64' && typeof block.data === 'string') {\n if (mimeType === 'application/pdf' || mimeType === '') {\n const pageEstimate = Math.max(\n 1,\n Math.ceil((block.data as string).length / BASE64_BYTES_PER_PDF_PAGE)\n );\n return pageEstimate * pdfTokensPerPage;\n }\n // Image inside a file block — delegate to image estimation\n if (mimeType.startsWith('image/')) {\n return estimateImageBlockTokens(\n {\n ...block,\n type: 'image',\n source: { type: 'base64', data: block.data },\n },\n encoding\n );\n }\n return getTokenCount(block.data as string);\n }\n\n if (sourceType === 'url') {\n return URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n return URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n // Anthropic format: type='document', source: { type, data, media_type }\n const source = block.source as\n | {\n type?: string;\n data?: string;\n media_type?: string;\n content?: unknown[];\n }\n | undefined;\n\n if (source == null) {\n return URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n if (source.type === 'text' && typeof source.data === 'string') {\n return getTokenCount(source.data);\n }\n\n if (source.type === 'base64' && typeof source.data === 'string') {\n const mediaType = (source.media_type ?? '').split(';')[0];\n if (mediaType === 'application/pdf' || mediaType === '') {\n const pageEstimate = Math.max(\n 1,\n Math.ceil(source.data.length / BASE64_BYTES_PER_PDF_PAGE)\n );\n return pageEstimate * pdfTokensPerPage;\n }\n if (mediaType.startsWith('image/')) {\n return estimateImageBlockTokens(\n { type: 'image', source: { type: 'base64', data: source.data } },\n encoding\n );\n }\n return getTokenCount(source.data);\n }\n\n if (source.type === 'url') {\n return URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n // content-type source (wraps other blocks like images)\n if (source.type === 'content' && Array.isArray(source.content)) {\n let total = 0;\n for (const inner of source.content) {\n if (inner != null && typeof inner === 'object' && 'type' in inner) {\n const innerBlock = inner as Record<string, unknown>;\n if (innerBlock.type === 'image') {\n total += estimateImageBlockTokens(innerBlock, encoding);\n }\n }\n }\n return total > 0 ? total : URL_DOCUMENT_FALLBACK_TOKENS;\n }\n\n return URL_DOCUMENT_FALLBACK_TOKENS;\n}\n\nconst tokenizers: Partial<Record<EncodingName, Tokenizer>> = {};\n\nasync function getTokenizer(\n encoding: EncodingName = 'o200k_base'\n): Promise<Tokenizer> {\n const cached = tokenizers[encoding];\n if (cached) {\n return cached;\n }\n const data =\n encoding === 'claude'\n ? await import('ai-tokenizer/encoding/claude')\n : await import('ai-tokenizer/encoding/o200k_base');\n const instance = new Tokenizer(data);\n tokenizers[encoding] = instance;\n return instance;\n}\n\nexport function encodingForModel(model: string): EncodingName {\n if (model.toLowerCase().includes('claude')) {\n return 'claude';\n }\n return 'o200k_base';\n}\n\nexport function getTokenCountForMessage(\n message: BaseMessage,\n getTokenCount: (text: string) => number,\n encoding: EncodingName = 'o200k_base'\n): number {\n const tokensPerMessage = 3;\n\n type ContentBlock = Record<string, unknown> & {\n type?: string;\n tool_call?: { name?: string; args?: string; output?: string };\n };\n\n const processValue = (value: unknown): void => {\n if (Array.isArray(value)) {\n for (const raw of value) {\n const item = raw as ContentBlock | null | undefined;\n if (item == null || typeof item.type !== 'string') {\n continue;\n }\n if (item.type === ContentTypes.ERROR) {\n continue;\n }\n\n if (\n item.type === ContentTypes.IMAGE_URL ||\n item.type === 'image_url' ||\n item.type === 'image'\n ) {\n numTokens += Math.ceil(\n estimateImageBlockTokens(item, encoding) * IMAGE_TOKEN_SAFETY_MARGIN\n );\n continue;\n }\n\n if (\n item.type === 'document' ||\n item.type === 'file' ||\n item.type === ContentTypes.IMAGE_FILE\n ) {\n numTokens += Math.ceil(\n estimateDocumentBlockTokens(item, encoding, getTokenCount) *\n IMAGE_TOKEN_SAFETY_MARGIN\n );\n continue;\n }\n\n if (item.type === ContentTypes.TOOL_CALL && item.tool_call != null) {\n const toolName = item.tool_call.name;\n if (typeof toolName === 'string' && toolName.length > 0) {\n numTokens += getTokenCount(toolName);\n }\n const args = item.tool_call.args;\n if (typeof args === 'string' && args.length > 0) {\n numTokens += getTokenCount(args);\n }\n const output = item.tool_call.output;\n if (typeof output === 'string' && output.length > 0) {\n numTokens += getTokenCount(output);\n }\n continue;\n }\n\n const nestedValue = item[item.type];\n if (nestedValue == null) {\n continue;\n }\n\n processValue(nestedValue);\n }\n } else if (typeof value === 'string') {\n numTokens += getTokenCount(value);\n } else if (typeof value === 'number') {\n numTokens += getTokenCount(value.toString());\n } else if (typeof value === 'boolean') {\n numTokens += getTokenCount(value.toString());\n }\n };\n\n let numTokens = tokensPerMessage;\n processValue(message.content);\n return numTokens;\n}\n\n/**\n * Largest-remainder apportionment: scales each count by `multiplier` and\n * distributes the rounding remainder so the results sum exactly to\n * `targetTotal`. Keeps per-item breakdowns reconciled with an aggregate\n * computed as a single rounded product of the summed raw counts.\n */\nexport function apportionTokenCounts(\n rawCounts: Record<string, number>,\n multiplier: number,\n targetTotal: number\n): Record<string, number> {\n const result: Record<string, number> = Object.create(null);\n const remainders: Array<{ name: string; remainder: number }> = [];\n let floorSum = 0;\n for (const [name, rawCount] of Object.entries(rawCounts)) {\n const scaled = rawCount * multiplier;\n const floored = Math.floor(scaled);\n result[name] = floored;\n floorSum += floored;\n remainders.push({ name, remainder: scaled - floored });\n }\n let leftover = targetTotal - floorSum;\n if (leftover <= 0 || remainders.length === 0) {\n return result;\n }\n remainders.sort((a, b) => b.remainder - a.remainder);\n for (let i = 0; leftover > 0; i = (i + 1) % remainders.length) {\n result[remainders[i].name] += 1;\n leftover--;\n }\n return result;\n}\n\n/**\n * Anthropic's API consistently reports ~10% more tokens than the local\n * claude tokenizer due to internal message framing and content encoding.\n * Verified empirically across content types via the count_tokens endpoint.\n */\nconst CLAUDE_TOKEN_CORRECTION = 1.1;\n\n/**\n * Creates a token counter function using the specified encoding.\n * Lazily loads the encoding data on first use via dynamic import.\n */\nexport const createTokenCounter = async (\n encoding: EncodingName = 'o200k_base'\n): Promise<(message: BaseMessage) => number> => {\n const tok = await getTokenizer(encoding);\n const countTokens = (text: string): number => tok.count(text);\n const isClaude = encoding === 'claude';\n return (message: BaseMessage): number => {\n const count = getTokenCountForMessage(message, countTokens, encoding);\n return isClaude ? Math.ceil(count * CLAUDE_TOKEN_CORRECTION) : count;\n };\n};\n\n/** Utility to manage the token encoder lifecycle explicitly. */\nexport const TokenEncoderManager = {\n async initialize(): Promise<void> {\n // No-op: ai-tokenizer is synchronously initialized from bundled data.\n },\n\n reset(): void {\n for (const key of Object.keys(tokenizers)) {\n delete tokenizers[key as EncodingName];\n }\n },\n\n isInitialized(): boolean {\n return Object.keys(tokenizers).length > 0;\n },\n};\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { ANTHROPIC_TOOL_TOKEN_MULTIPLIER, DEFAULT_TOOL_TOKEN_MULTIPLIER } from "../common/constants.mjs";
2
2
  import "../common/enum.mjs";
3
3
  import "../common/index.mjs";
4
- import { DEFAULT_RESERVE_RATIO } from "../messages/prune.mjs";
4
+ import { apportionTokenCounts } from "../utils/tokens.mjs";
5
+ import "../messages/prune.mjs";
5
6
  import { addCacheControl, addCacheControlToStablePrefixMessages } from "../messages/cache.mjs";
6
7
  import "../messages/index.mjs";
7
8
  import { toJsonSchema } from "../utils/schema.mjs";
@@ -110,6 +111,11 @@ var AgentContext = class AgentContext {
110
111
  dynamicInstructionTokens = 0;
111
112
  /** Token count for tool schemas only. */
112
113
  toolSchemaTokens = 0;
114
+ /** Per-tool schema token counts (post-multiplier), keyed by tool name.
115
+ * `undefined` when not calculated (e.g. cached aggregate schema tokens). */
116
+ toolTokenCounts;
117
+ /** Names of counted tools that are deferred (`defer_loading`) and discovered. */
118
+ deferredToolNames = [];
113
119
  /** Running calibration ratio from the pruner — persisted across runs via contextMeta. */
114
120
  calibrationRatio = 1;
115
121
  /** Provider-observed instruction overhead from the pruner's best-variance turn. */
@@ -482,6 +488,8 @@ The following tools are available exclusively through the \`${programmaticTool.n
482
488
  this.systemMessageTokens = 0;
483
489
  this.dynamicInstructionTokens = 0;
484
490
  this.toolSchemaTokens = 0;
491
+ this.toolTokenCounts = void 0;
492
+ this.deferredToolNames = [];
485
493
  this.cachedSystemRunnable = void 0;
486
494
  this.systemRunnableStale = true;
487
495
  this.lastToken = void 0;
@@ -568,6 +576,10 @@ The following tools are available exclusively through the \`${programmaticTool.n
568
576
  async calculateInstructionTokens(tokenCounter) {
569
577
  let toolTokens = 0;
570
578
  const countedToolNames = /* @__PURE__ */ new Set();
579
+ /** Prototype-free: external tool names like `toString` must not hit
580
+ * inherited properties during accumulation */
581
+ const rawToolTokenCounts = Object.create(null);
582
+ const deferredCountedNames = /* @__PURE__ */ new Set();
571
583
  /**
572
584
  * Iterate both `tools` (user-provided instance tools) and `graphTools`
573
585
  * (graph-managed tools like handoff + subagent). `graphTools` is often
@@ -588,8 +600,12 @@ The following tools are available exclusively through the \`${programmaticTool.n
588
600
  if (genericTool.schema != null && typeof genericTool.schema === "object") {
589
601
  const toolName = genericTool.name ?? "";
590
602
  const jsonSchema = toJsonSchema(genericTool.schema, toolName, genericTool.description ?? "");
591
- toolTokens += tokenCounter(new SystemMessage(JSON.stringify(jsonSchema)));
592
- if (toolName) countedToolNames.add(toolName);
603
+ const schemaTokens = tokenCounter(new SystemMessage(JSON.stringify(jsonSchema)));
604
+ toolTokens += schemaTokens;
605
+ if (toolName) {
606
+ countedToolNames.add(toolName);
607
+ rawToolTokenCounts[toolName] = (rawToolTokenCounts[toolName] ?? 0) + schemaTokens;
608
+ }
593
609
  }
594
610
  }
595
611
  for (const def of this.getActiveToolDefinitions()) {
@@ -602,10 +618,21 @@ The following tools are available exclusively through the \`${programmaticTool.n
602
618
  parameters: def.parameters ?? {}
603
619
  }
604
620
  };
605
- toolTokens += tokenCounter(new SystemMessage(JSON.stringify(schema)));
621
+ const schemaTokens = tokenCounter(new SystemMessage(JSON.stringify(schema)));
622
+ toolTokens += schemaTokens;
623
+ countedToolNames.add(def.name);
624
+ rawToolTokenCounts[def.name] = (rawToolTokenCounts[def.name] ?? 0) + schemaTokens;
625
+ if (def.defer_loading === true) deferredCountedNames.add(def.name);
606
626
  }
607
627
  const toolTokenMultiplier = this.provider !== "bedrock" && (this.provider === "anthropic" || /anthropic|claude/i.test(String(this.clientOptions?.model ?? ""))) ? ANTHROPIC_TOOL_TOKEN_MULTIPLIER : DEFAULT_TOOL_TOKEN_MULTIPLIER;
608
628
  this.toolSchemaTokens = Math.ceil(toolTokens * toolTokenMultiplier);
629
+ /** Largest-remainder apportionment keeps the per-tool counts summing
630
+ * exactly to the aggregate despite per-entry rounding */
631
+ const toolTokenCounts = apportionTokenCounts(rawToolTokenCounts, toolTokenMultiplier, this.toolSchemaTokens);
632
+ const deferredToolNames = [];
633
+ for (const name of Object.keys(rawToolTokenCounts)) if (deferredCountedNames.has(name) || this.toolRegistry?.get(name)?.defer_loading === true) deferredToolNames.push(name);
634
+ this.toolTokenCounts = toolTokenCounts;
635
+ this.deferredToolNames = deferredToolNames;
609
636
  }
610
637
  /**
611
638
  * Gets the tool registry for deferred tools (for tool search).
@@ -718,9 +745,8 @@ The following tools are available exclusively through the \`${programmaticTool.n
718
745
  * Returns a structured breakdown of how the context token budget is consumed.
719
746
  * Useful for diagnostics when context overflow or pruning issues occur.
720
747
  *
721
- * Note: `toolCount` reflects discoveries immediately, but `toolSchemaTokens`
722
- * is a snapshot taken during `calculateInstructionTokens` and is not
723
- * recomputed when `markToolsAsDiscovered` is called mid-run.
748
+ * Note: `markToolsAsDiscovered` re-triggers `calculateInstructionTokens`,
749
+ * so `toolSchemaTokens`/`toolTokenCounts` refresh before the next call.
724
750
  */
725
751
  getTokenBudgetBreakdown(messages) {
726
752
  const maxContextTokens = this.maxContextTokens ?? 0;
@@ -737,7 +763,10 @@ The following tools are available exclusively through the \`${programmaticTool.n
737
763
  const messageCount = messages?.length ?? 0;
738
764
  let messageTokens = 0;
739
765
  if (messages != null) for (let i = 0; i < messages.length; i++) messageTokens += this.indexTokenCountMap[i] ?? 0;
740
- const reserveTokens = Math.round(maxContextTokens * DEFAULT_RESERVE_RATIO);
766
+ /** Mirror the pruner's reserve math so availableForMessages agrees
767
+ * with the contextBudget computed during pruning */
768
+ const reserveRatio = this.summarizationConfig?.reserveRatio ?? .05;
769
+ const reserveTokens = reserveRatio > 0 && reserveRatio < 1 ? Math.round(maxContextTokens * reserveRatio) : 0;
741
770
  const availableForMessages = Math.max(0, maxContextTokens - reserveTokens - this.instructionTokens);
742
771
  return {
743
772
  maxContextTokens,
@@ -749,7 +778,9 @@ The following tools are available exclusively through the \`${programmaticTool.n
749
778
  toolCount,
750
779
  messageCount,
751
780
  messageTokens,
752
- availableForMessages
781
+ availableForMessages,
782
+ toolTokenCounts: this.toolTokenCounts != null ? { ...this.toolTokenCounts } : void 0,
783
+ deferredToolNames: this.deferredToolNames.length > 0 ? [...this.deferredToolNames] : void 0
753
784
  };
754
785
  }
755
786
  /**
@@ -804,7 +835,13 @@ The following tools are available exclusively through the \`${programmaticTool.n
804
835
  this.discoveredToolNames.add(name);
805
836
  hasNewDiscoveries = true;
806
837
  }
807
- if (hasNewDiscoveries) this.systemRunnableStale = true;
838
+ if (hasNewDiscoveries) {
839
+ this.systemRunnableStale = true;
840
+ /** Refresh schema token accounting so the next call's budget and
841
+ * per-tool breakdown include the newly discovered tools; awaited
842
+ * via tokenCalculationPromise before the next model call */
843
+ if (this.tokenCounter) this.tokenCalculationPromise = this.calculateInstructionTokens(this.tokenCounter);
844
+ }
808
845
  return hasNewDiscoveries;
809
846
  }
810
847
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"AgentContext.mjs","names":[],"sources":["../../../src/agents/AgentContext.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport { RunnableLambda } from '@langchain/core/runnables';\nimport { HumanMessage, SystemMessage } from '@langchain/core/messages';\nimport type {\n UsageMetadata,\n BaseMessage,\n BaseMessageFields,\n} from '@langchain/core/messages';\nimport type { RunnableConfig, Runnable } from '@langchain/core/runnables';\nimport type { createPruneMessages } from '@/messages';\nimport type * as t from '@/types';\nimport {\n ANTHROPIC_TOOL_TOKEN_MULTIPLIER,\n DEFAULT_TOOL_TOKEN_MULTIPLIER,\n ContentTypes,\n Constants,\n Providers,\n} from '@/common';\nimport {\n addCacheControl,\n addCacheControlToStablePrefixMessages,\n} from '@/messages/cache';\nimport { createSchemaOnlyTools } from '@/tools/schema';\nimport { DEFAULT_RESERVE_RATIO } from '@/messages';\nimport { toJsonSchema } from '@/utils/schema';\n\ntype AgentSystemTextBlock = {\n type: 'text';\n text: string;\n cache_control?: { type: 'ephemeral' };\n};\n\ntype AgentSystemContentBlock =\n | AgentSystemTextBlock\n | { cachePoint: { type: 'default' } };\n\ntype PromptCacheProvider = Providers.ANTHROPIC | Providers.OPENROUTER;\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 name,\n provider,\n clientOptions,\n langfuse,\n tools,\n toolMap,\n toolEnd,\n toolRegistry,\n toolDefinitions,\n instructions,\n additional_instructions,\n streamBuffer,\n maxContextTokens,\n reasoningKey,\n useLegacyContent,\n discoveredTools,\n summarizationEnabled,\n summarizationConfig,\n initialSummary,\n contextPruningConfig,\n maxToolResultChars,\n toolSchemaTokens,\n subagentConfigs,\n maxSubagentDepth,\n } = agentConfig;\n\n const agentContext = new AgentContext({\n agentId,\n name: name ?? agentId,\n provider,\n clientOptions,\n langfuse,\n maxContextTokens,\n streamBuffer,\n tools,\n toolMap,\n toolRegistry,\n toolDefinitions,\n instructions,\n additionalInstructions: additional_instructions,\n reasoningKey,\n toolEnd,\n instructionTokens: 0,\n tokenCounter,\n useLegacyContent,\n discoveredTools,\n summarizationEnabled,\n summarizationConfig,\n contextPruningConfig,\n maxToolResultChars,\n });\n\n agentContext._sourceInputs = agentConfig;\n agentContext.subagentConfigs = subagentConfigs;\n agentContext.maxSubagentDepth = maxSubagentDepth;\n\n if (initialSummary?.text != null && initialSummary.text !== '') {\n agentContext.setInitialSummary(\n initialSummary.text,\n initialSummary.tokenCount\n );\n }\n\n if (tokenCounter) {\n agentContext.initializeSystemRunnable();\n\n const tokenMap = indexTokenCountMap || {};\n agentContext.baseIndexTokenCountMap = { ...tokenMap };\n agentContext.indexTokenCountMap = tokenMap;\n\n if (toolSchemaTokens != null && toolSchemaTokens > 0) {\n /** Use pre-computed (cached) tool schema tokens — skip calculateInstructionTokens */\n agentContext.toolSchemaTokens = toolSchemaTokens;\n agentContext.tokenCalculationPromise = Promise.resolve();\n agentContext.updateTokenMapWithInstructions(tokenMap);\n } else {\n agentContext.tokenCalculationPromise = agentContext\n .calculateInstructionTokens(tokenCounter)\n .then(() => {\n agentContext.updateTokenMapWithInstructions(tokenMap);\n })\n .catch((err) => {\n console.error('Error calculating instruction tokens:', err);\n });\n }\n } else if (indexTokenCountMap) {\n agentContext.baseIndexTokenCountMap = { ...indexTokenCountMap };\n agentContext.indexTokenCountMap = indexTokenCountMap;\n }\n\n return agentContext;\n }\n\n /** Agent identifier */\n agentId: string;\n /** Human-readable name for this agent (used in handoff context). Falls back to agentId if not provided. */\n name?: string;\n /** Provider for this specific agent */\n provider: Providers;\n /** Client options for this agent */\n clientOptions?: t.ClientOptions;\n /** Per-agent Langfuse tracing configuration. */\n langfuse?: t.LangfuseConfig;\n /** Token count map indexed by message position */\n indexTokenCountMap: Record<string, number | undefined> = {};\n /** Canonical pre-run token map used to restore token accounting on reset */\n baseIndexTokenCountMap: Record<string, number> = {};\n /** Maximum context tokens for this agent */\n maxContextTokens?: number;\n /** Current usage metadata for this agent */\n currentUsage?: Partial<UsageMetadata>;\n /**\n * Usage from the most recent LLM call only (not accumulated).\n * Used for accurate provider calibration in pruning.\n */\n lastCallUsage?: {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n cacheRead?: number;\n cacheCreation?: number;\n };\n /**\n * Whether totalTokens data is fresh (set true when provider usage arrives,\n * false at the start of each turn before the LLM responds).\n * Prevents stale token data from driving pruning/trigger decisions.\n */\n totalTokensFresh: boolean = false;\n /** Context pruning configuration. */\n contextPruningConfig?: t.ContextPruningConfig;\n maxToolResultChars?: number;\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 /** Token count for the system message (instructions text). */\n systemMessageTokens: number = 0;\n /** Token count for instruction text emitted outside the system message. */\n dynamicInstructionTokens: number = 0;\n /** Token count for tool schemas only. */\n toolSchemaTokens: number = 0;\n /** Running calibration ratio from the pruner — persisted across runs via contextMeta. */\n calibrationRatio: number = 1;\n /** Provider-observed instruction overhead from the pruner's best-variance turn. */\n resolvedInstructionOverhead?: number;\n /** Pre-masking tool content keyed by message index, consumed by the summarize node. */\n pendingOriginalToolContent?: Map<number, string>;\n\n /** Total instruction overhead: system message + tool schemas + pending summary. */\n get instructionTokens(): number {\n const summaryOverhead =\n this._summaryLocation === 'user_message' ? this.summaryTokenCount : 0;\n return (\n this.systemMessageTokens +\n this.dynamicInstructionTokens +\n this.toolSchemaTokens +\n summaryOverhead\n );\n }\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 /** Graph-managed tools (e.g., handoff tools created by MultiAgentGraph) that bypass event-driven dispatch */\n graphTools?: 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 /**\n * Serializable tool definitions for event-driven execution.\n * When provided, ToolNode operates in event-driven mode.\n */\n toolDefinitions?: t.LCTool[];\n /** Set of tool names discovered via tool search (to be loaded) */\n discoveredToolNames: Set<string> = new Set();\n /** Original AgentInputs used to create this context — used for self-spawn subagent resolution. */\n _sourceInputs?: t.AgentInputs;\n /** Subagent configurations for hierarchical delegation. */\n subagentConfigs?: t.SubagentConfig[];\n /** Maximum subagent nesting depth. */\n maxSubagentDepth?: number;\n /** Instructions for this agent */\n instructions?: string;\n /** Additional instructions for this agent */\n additionalInstructions?: 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 /** Tracks how many reasoning→text transitions have occurred (ensures unique post-reasoning step keys) */\n reasoningTransitionCount = 0;\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 /** Promise for token calculation initialization */\n tokenCalculationPromise?: Promise<void>;\n /** Format content blocks as strings (for legacy compatibility) */\n useLegacyContent: boolean = false;\n /** Enables graph-level summarization for this agent */\n summarizationEnabled?: boolean;\n /** Summarization runtime settings used by graph pruning hooks */\n summarizationConfig?: t.SummarizationConfig;\n /** Current summary text produced by the summarize node, integrated into system message */\n private summaryText?: string;\n /** Token count of the current summary (tracked for token accounting) */\n private summaryTokenCount: number = 0;\n /**\n * Where the summary should be injected:\n * - `'system_prompt'`: cross-run summary, included in the dynamic system tail\n * - `'user_message'`: mid-run compaction, injected as HumanMessage on clean slate\n * - `'none'`: no summary present\n */\n private _summaryLocation: 'system_prompt' | 'user_message' | 'none' = 'none';\n /**\n * Durable summary that survives reset() calls. Set from initialSummary\n * during fromConfig() and updated by setSummary() so that the latest\n * summary (whether cross-run or intra-run) is always restored after\n * processStream's resetValues() cycle.\n */\n private _durableSummaryText?: string;\n private _durableSummaryTokenCount: number = 0;\n /** Number of summarization cycles that have occurred for this agent context */\n private _summaryVersion: number = 0;\n /**\n * Message count at the time summarization was last triggered.\n * Used to prevent re-summarizing the same unchanged message set.\n * Summarization is allowed to fire again only when new messages appear.\n */\n private _lastSummarizationMsgCount: number = 0;\n /**\n * Handoff context when this agent receives control via handoff.\n * Contains source and parallel execution info for system message context.\n */\n handoffContext?: {\n /** Source agent that transferred control */\n sourceAgentName: string;\n /** Names of sibling agents executing in parallel (empty if sequential) */\n parallelSiblings: string[];\n };\n\n constructor({\n agentId,\n name,\n provider,\n clientOptions,\n langfuse,\n maxContextTokens,\n streamBuffer,\n tokenCounter,\n tools,\n toolMap,\n toolRegistry,\n toolDefinitions,\n instructions,\n additionalInstructions,\n reasoningKey,\n toolEnd,\n instructionTokens,\n useLegacyContent,\n discoveredTools,\n summarizationEnabled,\n summarizationConfig,\n contextPruningConfig,\n maxToolResultChars,\n }: {\n agentId: string;\n name?: string;\n provider: Providers;\n clientOptions?: t.ClientOptions;\n langfuse?: t.LangfuseConfig;\n maxContextTokens?: number;\n streamBuffer?: number;\n tokenCounter?: t.TokenCounter;\n tools?: t.GraphTools;\n toolMap?: t.ToolMap;\n toolRegistry?: t.LCToolRegistry;\n toolDefinitions?: t.LCTool[];\n instructions?: string;\n additionalInstructions?: string;\n reasoningKey?: 'reasoning_content' | 'reasoning';\n toolEnd?: boolean;\n instructionTokens?: number;\n useLegacyContent?: boolean;\n discoveredTools?: string[];\n summarizationEnabled?: boolean;\n summarizationConfig?: t.SummarizationConfig;\n contextPruningConfig?: t.ContextPruningConfig;\n maxToolResultChars?: number;\n }) {\n this.agentId = agentId;\n this.name = name;\n this.provider = provider;\n this.clientOptions = clientOptions;\n this.langfuse = langfuse;\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.toolDefinitions = toolDefinitions;\n this.instructions = instructions;\n this.additionalInstructions = additionalInstructions;\n if (reasoningKey) {\n this.reasoningKey = reasoningKey;\n }\n if (toolEnd !== undefined) {\n this.toolEnd = toolEnd;\n }\n if (instructionTokens !== undefined) {\n this.systemMessageTokens = instructionTokens;\n }\n\n this.useLegacyContent = useLegacyContent ?? false;\n this.summarizationEnabled = summarizationEnabled;\n this.summarizationConfig = summarizationConfig;\n this.contextPruningConfig = contextPruningConfig;\n this.maxToolResultChars = maxToolResultChars;\n\n if (discoveredTools && discoveredTools.length > 0) {\n for (const toolName of discoveredTools) {\n this.discoveredToolNames.add(toolName);\n }\n }\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 * configured programmatic 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 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 programmaticTool = this.getProgrammaticToolInstructionTarget();\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 \\`${programmaticTool.name}\\` tool. ` +\n `You cannot call these tools directly; instead, use \\`${programmaticTool.name}\\` with ${programmaticTool.language} code that invokes them.\\n\\n` +\n toolDescriptions\n );\n }\n\n private getProgrammaticToolInstructionTarget(): {\n name: string;\n language: 'bash' | 'Python';\n } {\n if (this.hasAvailableTool(Constants.BASH_PROGRAMMATIC_TOOL_CALLING)) {\n return {\n name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,\n language: 'bash',\n };\n }\n\n if (this.hasAvailableTool(Constants.PROGRAMMATIC_TOOL_CALLING)) {\n return { name: Constants.PROGRAMMATIC_TOOL_CALLING, language: 'Python' };\n }\n\n return { name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING, language: 'bash' };\n }\n\n private hasAvailableTool(name: string): boolean {\n if (this.toolDefinitions?.some((tool) => tool.name === name) === true)\n return true;\n if (\n this.tools?.some((tool) => 'name' in tool && tool.name === name) === true\n ) {\n return true;\n }\n if (this.toolMap?.has(name) === true) return true;\n return this.toolRegistry?.has(name) === true;\n }\n\n /**\n * Gets the system runnable, creating it lazily if needed.\n * Includes stable instructions, dynamic additional instructions, and\n * 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 if (!this.systemRunnableStale && this.cachedSystemRunnable !== undefined) {\n return this.cachedSystemRunnable;\n }\n\n this.cachedSystemRunnable = this.buildSystemRunnable({\n stableInstructions: this.buildStableInstructionsString(),\n dynamicInstructions: this.buildDynamicInstructionsString(),\n });\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 this.cachedSystemRunnable = this.buildSystemRunnable({\n stableInstructions: this.buildStableInstructionsString(),\n dynamicInstructions: this.buildDynamicInstructionsString(),\n });\n this.systemRunnableStale = false;\n }\n }\n\n /**\n * Builds the cacheable instructions string (without creating SystemMessage).\n * Includes agent identity preamble and handoff context when available.\n */\n private buildStableInstructionsString(): string {\n const parts: string[] = [];\n\n const identityPreamble = this.buildIdentityPreamble();\n if (identityPreamble) {\n parts.push(identityPreamble);\n }\n\n if (this.instructions != null && this.instructions !== '') {\n parts.push(this.instructions);\n }\n\n const programmaticToolsDoc = this.buildProgrammaticOnlyToolsInstructions();\n if (programmaticToolsDoc) {\n parts.push(programmaticToolsDoc);\n }\n\n return parts.join('\\n\\n');\n }\n\n /**\n * Builds the dynamic system-tail string (without creating SystemMessage).\n * Keep this out of prompt-cache-marked content so volatile context does not\n * invalidate the stable prefix.\n */\n private buildDynamicInstructionsString(): string {\n const parts: string[] = [];\n\n if (\n this.additionalInstructions != null &&\n this.additionalInstructions !== ''\n ) {\n parts.push(this.additionalInstructions);\n }\n\n // Cross-run summary: include in the system tail so the model has context\n // from the prior run without invalidating the cacheable prefix. Mid-run\n // summaries are injected as a HumanMessage on the post-compaction clean\n // slate instead (see buildSystemRunnable).\n if (\n this._summaryLocation === 'system_prompt' &&\n this.summaryText != null &&\n this.summaryText !== ''\n ) {\n parts.push('## Conversation Summary\\n\\n' + this.summaryText);\n }\n\n return parts.join('\\n\\n');\n }\n\n /**\n * Builds the agent identity preamble including handoff context if present.\n * This helps the agent understand its role in the multi-agent workflow.\n */\n private buildIdentityPreamble(): string {\n if (!this.handoffContext) return '';\n\n const displayName = this.name ?? this.agentId;\n const { sourceAgentName, parallelSiblings } = this.handoffContext;\n const isParallel = parallelSiblings.length > 0;\n\n const lines: string[] = [];\n lines.push('## Multi-Agent Workflow');\n lines.push(\n `You are \"${displayName}\", transferred from \"${sourceAgentName}\".`\n );\n\n if (isParallel) {\n lines.push(`Running in parallel with: ${parallelSiblings.join(', ')}.`);\n }\n\n lines.push(\n 'Execute only tasks relevant to your role. Routing is already handled if requested, unless you can route further.'\n );\n\n return lines.join('\\n');\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 stableInstructions,\n dynamicInstructions,\n }: {\n stableInstructions: string;\n dynamicInstructions: string;\n }):\n | Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >\n | undefined {\n const hasMidRunSummary =\n this._summaryLocation === 'user_message' &&\n this.summaryText != null &&\n this.summaryText !== '';\n\n if (!stableInstructions && !dynamicInstructions && !hasMidRunSummary) {\n this.systemMessageTokens = 0;\n this.dynamicInstructionTokens = 0;\n return undefined;\n }\n\n const promptCacheProvider = this.getPromptCacheProvider();\n const shouldMoveDynamicInstructions =\n promptCacheProvider != null &&\n stableInstructions !== '' &&\n dynamicInstructions !== '';\n const systemMessage = this.buildSystemMessage({\n stableInstructions,\n dynamicInstructions,\n promptCacheProvider,\n shouldMoveDynamicInstructions,\n });\n\n if (this.tokenCounter) {\n this.systemMessageTokens = systemMessage\n ? this.tokenCounter(systemMessage)\n : 0;\n this.dynamicInstructionTokens = shouldMoveDynamicInstructions\n ? this.tokenCounter(new HumanMessage(dynamicInstructions))\n : 0;\n }\n\n return RunnableLambda.from((messages: BaseMessage[]) => {\n const prefix: BaseMessage[] = systemMessage ? [systemMessage] : [];\n\n // Build the non-system portion (summary + conversation), then apply\n // cache markers separately so addCacheControl doesn't strip the\n // SystemMessage's own cache_control breakpoint set above.\n const hasSummaryBody =\n this._summaryLocation === 'user_message' &&\n this.summaryText != null &&\n this.summaryText !== '';\n\n const bodyWithSummary =\n hasSummaryBody && promptCacheProvider == null\n ? [this.buildSummaryHumanMessage(promptCacheProvider), ...messages]\n : messages;\n const dynamicTail = this.buildPromptCacheDynamicTail({\n dynamicInstructions,\n hasSummaryBody,\n promptCacheProvider,\n shouldMoveDynamicInstructions,\n });\n let body = this.buildBodyWithPromptCacheDynamicTail(\n bodyWithSummary,\n dynamicTail,\n promptCacheProvider\n );\n\n if (\n promptCacheProvider != null &&\n dynamicTail.length === 0 &&\n body.length >= 2\n ) {\n body = addCacheControl(body);\n }\n return [...prefix, ...body];\n }).withConfig({ runName: 'prompt' });\n }\n\n private buildSummaryHumanMessage(\n promptCacheProvider: PromptCacheProvider | undefined\n ): HumanMessage {\n const wrappedSummary =\n '<summary>\\n' +\n (this.summaryText as string) +\n '\\n</summary>\\n\\n' +\n 'This is your own checkpoint: you wrote it to preserve context after compaction. Pick up where you left off based on the summary above. Do not repeat prior tasks, information or acknowledge this checkpoint message directly.';\n\n if (promptCacheProvider !== Providers.ANTHROPIC) {\n return new HumanMessage(wrappedSummary);\n }\n\n return new HumanMessage({\n content: [\n {\n type: 'text',\n text: wrappedSummary,\n cache_control: { type: 'ephemeral' },\n },\n ],\n });\n }\n\n private buildPromptCacheDynamicTail({\n dynamicInstructions,\n hasSummaryBody,\n promptCacheProvider,\n shouldMoveDynamicInstructions,\n }: {\n dynamicInstructions: string;\n hasSummaryBody: boolean;\n promptCacheProvider: PromptCacheProvider | undefined;\n shouldMoveDynamicInstructions: boolean;\n }): BaseMessage[] {\n if (promptCacheProvider == null) {\n return [];\n }\n\n const dynamicTail = shouldMoveDynamicInstructions\n ? [new HumanMessage(dynamicInstructions)]\n : [];\n\n if (!hasSummaryBody) {\n return dynamicTail;\n }\n\n return [...dynamicTail, this.buildSummaryHumanMessage(undefined)];\n }\n\n private buildBodyWithPromptCacheDynamicTail(\n messages: BaseMessage[],\n tail: BaseMessage[],\n promptCacheProvider: PromptCacheProvider | undefined\n ): BaseMessage[] {\n if (tail.length === 0) {\n return messages;\n }\n\n const tailIndex = this.getPromptCacheDynamicTailIndex(\n messages,\n promptCacheProvider\n );\n const stablePrefix = messages.slice(0, tailIndex);\n const trailingMessages = messages.slice(tailIndex);\n const cacheablePrefix = this.addStablePromptCacheMarkers(stablePrefix);\n\n return [...cacheablePrefix, ...tail, ...trailingMessages];\n }\n\n private getPromptCacheDynamicTailIndex(\n messages: BaseMessage[],\n promptCacheProvider: PromptCacheProvider | undefined\n ): number {\n const lastIndex = messages.length - 1;\n\n if (lastIndex < 0) {\n return 0;\n }\n\n if (promptCacheProvider === Providers.OPENROUTER && messages.length === 1) {\n return messages.length;\n }\n\n for (let index = lastIndex; index >= 0; index--) {\n if (messages[index].getType() === 'human') {\n if (promptCacheProvider === Providers.OPENROUTER && index === 0) {\n return 1;\n }\n return index;\n }\n }\n\n return messages.length;\n }\n\n private addStablePromptCacheMarkers(messages: BaseMessage[]): BaseMessage[] {\n if (messages.length <= 1) {\n return messages;\n }\n\n return [\n messages[0],\n ...addCacheControlToStablePrefixMessages(messages.slice(1), 2),\n ];\n }\n\n private getPromptCacheProvider(): PromptCacheProvider | undefined {\n if (this.provider === Providers.ANTHROPIC) {\n const anthropicOptions = this.clientOptions as\n | t.AnthropicClientOptions\n | undefined;\n return anthropicOptions?.promptCache === true\n ? Providers.ANTHROPIC\n : undefined;\n }\n\n if (this.provider === Providers.OPENROUTER) {\n const openRouterOptions = this.clientOptions as\n | t.ProviderOptionsMap[Providers.OPENROUTER]\n | undefined;\n return openRouterOptions?.promptCache === true\n ? Providers.OPENROUTER\n : undefined;\n }\n\n return undefined;\n }\n\n private hasBedrockPromptCache(): boolean {\n if (this.provider !== Providers.BEDROCK) {\n return false;\n }\n const bedrockOptions = this.clientOptions as\n | t.BedrockAnthropicClientOptions\n | undefined;\n return bedrockOptions?.promptCache === true;\n }\n\n private buildSystemMessage({\n stableInstructions,\n dynamicInstructions,\n promptCacheProvider,\n shouldMoveDynamicInstructions,\n }: {\n stableInstructions: string;\n dynamicInstructions: string;\n promptCacheProvider: PromptCacheProvider | undefined;\n shouldMoveDynamicInstructions: boolean;\n }): SystemMessage | undefined {\n if (!stableInstructions && !dynamicInstructions) {\n return undefined;\n }\n\n if (promptCacheProvider === Providers.ANTHROPIC) {\n const content: AgentSystemContentBlock[] = [];\n if (stableInstructions) {\n content.push({\n type: 'text',\n text: stableInstructions,\n cache_control: { type: 'ephemeral' },\n });\n }\n if (dynamicInstructions && !shouldMoveDynamicInstructions) {\n content.push({ type: 'text', text: dynamicInstructions });\n }\n return new SystemMessage({ content } as BaseMessageFields);\n }\n\n if (promptCacheProvider === Providers.OPENROUTER && !stableInstructions) {\n return new SystemMessage(dynamicInstructions);\n }\n\n if (promptCacheProvider === Providers.OPENROUTER) {\n return new SystemMessage({\n content: [\n {\n type: 'text',\n text: stableInstructions,\n cache_control: { type: 'ephemeral' },\n },\n ],\n } as BaseMessageFields);\n }\n\n if (this.hasBedrockPromptCache() && stableInstructions) {\n const content: AgentSystemContentBlock[] = [\n { type: 'text', text: stableInstructions },\n { cachePoint: { type: 'default' } },\n ];\n if (dynamicInstructions) {\n content.push({ type: 'text', text: dynamicInstructions });\n }\n return new SystemMessage({ content } as BaseMessageFields);\n }\n\n return new SystemMessage(\n [stableInstructions, dynamicInstructions]\n .filter((part) => part !== '')\n .join('\\n\\n')\n );\n }\n\n /**\n * Reset context for a new run\n */\n reset(): void {\n this.systemMessageTokens = 0;\n this.dynamicInstructionTokens = 0;\n this.toolSchemaTokens = 0;\n this.cachedSystemRunnable = undefined;\n this.systemRunnableStale = true;\n this.lastToken = undefined;\n this.indexTokenCountMap = { ...this.baseIndexTokenCountMap };\n this.currentUsage = undefined;\n this.pruneMessages = undefined;\n this.lastStreamCall = undefined;\n this.tokenTypeSwitch = undefined;\n this.reasoningTransitionCount = 0;\n this.currentTokenType = ContentTypes.TEXT;\n this.discoveredToolNames.clear();\n this.handoffContext = undefined;\n\n this.summaryText = this._durableSummaryText;\n this.summaryTokenCount = this._durableSummaryTokenCount;\n this._lastSummarizationMsgCount = 0;\n this.lastCallUsage = undefined;\n this.totalTokensFresh = false;\n\n if (this.tokenCounter) {\n this.initializeSystemRunnable();\n const baseTokenMap = { ...this.baseIndexTokenCountMap };\n this.indexTokenCountMap = baseTokenMap;\n this.tokenCalculationPromise = this.calculateInstructionTokens(\n this.tokenCounter\n )\n .then(() => {\n this.updateTokenMapWithInstructions(baseTokenMap);\n })\n .catch((err) => {\n console.error('Error calculating instruction tokens:', err);\n });\n } else {\n this.tokenCalculationPromise = undefined;\n }\n }\n\n /**\n * Update the token count map from a base map.\n *\n * Previously this inflated index 0 with instructionTokens to indirectly\n * reserve budget for the system prompt. That approach was imprecise: with\n * large tool-schema overhead (e.g. 26 MCP tools ~5 000 tokens) the first\n * conversation message appeared enormous and was always pruned, while the\n * real available budget was never explicitly computed.\n *\n * Now instruction tokens are passed to getMessagesWithinTokenLimit via\n * the `getInstructionTokens` factory param so the pruner subtracts them\n * from the budget directly. The token map contains only real per-message\n * token counts.\n */\n updateTokenMapWithInstructions(baseTokenMap: Record<string, number>): void {\n this.indexTokenCountMap = { ...baseTokenMap };\n }\n\n /** Active tool definitions for token accounting (excludes deferred-and-undiscovered entries). */\n private getActiveToolDefinitions(): t.LCTool[] {\n if (!this.toolDefinitions) {\n return [];\n }\n /**\n * Mirror `getEventDrivenToolsForBinding`'s gate: a definition is only\n * bound to the model when its `allowed_callers` include `'direct'` and\n * (if deferred) it has been discovered. Filtering by `defer_loading`\n * alone left programmatic-only definitions counted in\n * `toolSchemaTokens` even though they were never bound.\n */\n return this.toolDefinitions.filter((def) => {\n const allowedCallers = def.allowed_callers ?? ['direct'];\n if (!allowedCallers.includes('direct')) {\n return false;\n }\n return (\n def.defer_loading !== true || this.discoveredToolNames.has(def.name)\n );\n });\n }\n\n /**\n * Single source of truth for \"which entries of `this.tools` should be\n * treated as actually bound\". Callers:\n * - `getToolsForBinding` (non-event-driven branch)\n * - `getEventDrivenToolsForBinding` (appends instance tools alongside\n * schema-only definitions)\n * - `calculateInstructionTokens` (counts schema bytes for accounting)\n *\n * In event-driven mode (`toolDefinitions` present) instance tools are\n * appended unfiltered; outside event-driven mode they pass through\n * `filterToolsForBinding`. Centralizing the decision here prevents the\n * accounting/binding paths from drifting apart, which was the root\n * cause of the original miscount.\n */\n private getEffectiveInstanceTools(): t.GraphTools | undefined {\n if (!this.tools) {\n return undefined;\n }\n const isEventDriven = (this.toolDefinitions?.length ?? 0) > 0;\n if (isEventDriven || !this.toolRegistry) {\n return this.tools;\n }\n return this.filterToolsForBinding(this.tools);\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 const countedToolNames = new Set<string>();\n\n /**\n * Iterate both `tools` (user-provided instance tools) and `graphTools`\n * (graph-managed tools like handoff + subagent). `graphTools` is often\n * populated after `fromConfig()` kicks off the initial calculation, so\n * callers that mutate `graphTools` must re-trigger this method to\n * refresh `toolSchemaTokens`.\n *\n * Use `getEffectiveInstanceTools()` so accounting reflects exactly the\n * subset that `getToolsForBinding` would emit — preventing the\n * worst-case-ceiling miscount that triggered spurious `empty_messages`\n * preflight rejections at low `maxContextTokens`. Deferred and\n * non-`'direct'` `toolDefinitions` are excluded by\n * `getActiveToolDefinitions()` below.\n */\n const instanceTools: t.GraphTools = [\n ...((this.getEffectiveInstanceTools() as t.GenericTool[] | undefined) ??\n []),\n ...((this.graphTools as t.GenericTool[] | undefined) ?? []),\n ];\n\n if (instanceTools.length > 0) {\n for (const tool of instanceTools) {\n const genericTool = tool as Record<string, unknown>;\n if (\n genericTool.schema != null &&\n typeof genericTool.schema === 'object'\n ) {\n const toolName = (genericTool.name as string | undefined) ?? '';\n const jsonSchema = toJsonSchema(\n genericTool.schema,\n toolName,\n (genericTool.description as string | undefined) ?? ''\n );\n toolTokens += tokenCounter(\n new SystemMessage(JSON.stringify(jsonSchema))\n );\n if (toolName) {\n countedToolNames.add(toolName);\n }\n }\n }\n }\n\n for (const def of this.getActiveToolDefinitions()) {\n if (countedToolNames.has(def.name)) {\n continue;\n }\n const schema = {\n type: 'function',\n function: {\n name: def.name,\n description: def.description ?? '',\n parameters: def.parameters ?? {},\n },\n };\n toolTokens += tokenCounter(new SystemMessage(JSON.stringify(schema)));\n }\n\n const isAnthropic =\n this.provider !== Providers.BEDROCK &&\n (this.provider === Providers.ANTHROPIC ||\n /anthropic|claude/i.test(\n String(\n (this.clientOptions as { model?: string } | undefined)?.model ?? ''\n )\n ));\n const toolTokenMultiplier = isAnthropic\n ? ANTHROPIC_TOOL_TOKEN_MULTIPLIER\n : DEFAULT_TOOL_TOKEN_MULTIPLIER;\n this.toolSchemaTokens = Math.ceil(toolTokens * toolTokenMultiplier);\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 * Sets the handoff context for this agent.\n * Call this when the agent receives control via handoff from another agent.\n * Marks system runnable as stale to include handoff context in system message.\n * @param sourceAgentName - Name of the agent that transferred control\n * @param parallelSiblings - Names of other agents executing in parallel with this one\n */\n setHandoffContext(sourceAgentName: string, parallelSiblings: string[]): void {\n this.handoffContext = { sourceAgentName, parallelSiblings };\n this.systemRunnableStale = true;\n }\n\n /**\n * Clears any handoff context.\n * Call this when resetting the agent or when handoff context is no longer relevant.\n */\n clearHandoffContext(): void {\n if (this.handoffContext) {\n this.handoffContext = undefined;\n this.systemRunnableStale = true;\n }\n }\n\n setSummary(text: string, tokenCount: number): void {\n this.summaryText = text;\n this.summaryTokenCount = tokenCount;\n this._summaryLocation = 'user_message';\n this._durableSummaryText = text;\n this._durableSummaryTokenCount = tokenCount;\n this._summaryVersion += 1;\n this.systemRunnableStale = true;\n this.pruneMessages = undefined;\n }\n\n /** Sets a cross-run summary that is injected into the system prompt. */\n setInitialSummary(text: string, tokenCount: number): void {\n this.summaryText = text;\n this.summaryTokenCount = tokenCount;\n this._summaryLocation = 'system_prompt';\n this._durableSummaryText = text;\n this._durableSummaryTokenCount = tokenCount;\n this._summaryVersion += 1;\n this.systemRunnableStale = true;\n }\n\n /**\n * Replaces the indexTokenCountMap with a fresh map keyed to the surviving\n * context messages after summarization. Called by the summarize node after\n * it emits RemoveMessage operations that shift message indices.\n */\n rebuildTokenMapAfterSummarization(newTokenMap: Record<string, number>): void {\n this.indexTokenCountMap = newTokenMap;\n this.baseIndexTokenCountMap = { ...newTokenMap };\n this._lastSummarizationMsgCount = Object.keys(newTokenMap).length;\n this.currentUsage = undefined;\n this.lastCallUsage = undefined;\n this.totalTokensFresh = false;\n }\n\n hasSummary(): boolean {\n return this.summaryText != null && this.summaryText !== '';\n }\n\n /** True when a mid-run compaction summary is ready to be injected as a HumanMessage. */\n hasPendingCompactionSummary(): boolean {\n return this._summaryLocation === 'user_message' && this.hasSummary();\n }\n\n getSummaryText(): string | undefined {\n return this.summaryText;\n }\n\n get summaryVersion(): number {\n return this._summaryVersion;\n }\n\n /**\n * Returns true when the message count hasn't changed since the last\n * summarization — re-summarizing would produce an identical result.\n * Oversized individual messages are handled by fit-to-budget truncation\n * in the pruner, which keeps them in context without triggering overflow.\n */\n shouldSkipSummarization(currentMsgCount: number): boolean {\n return (\n this._lastSummarizationMsgCount > 0 &&\n currentMsgCount <= this._lastSummarizationMsgCount\n );\n }\n\n /**\n * Records the message count at which summarization was triggered,\n * so subsequent calls with the same count are suppressed.\n */\n markSummarizationTriggered(msgCount: number): void {\n this._lastSummarizationMsgCount = msgCount;\n }\n\n clearSummary(): void {\n if (this.summaryText != null) {\n this.summaryText = undefined;\n this.summaryTokenCount = 0;\n this._durableSummaryText = undefined;\n this._durableSummaryTokenCount = 0;\n this._summaryLocation = 'none';\n this.systemRunnableStale = true;\n }\n }\n\n /**\n * Returns a structured breakdown of how the context token budget is consumed.\n * Useful for diagnostics when context overflow or pruning issues occur.\n *\n * Note: `toolCount` reflects discoveries immediately, but `toolSchemaTokens`\n * is a snapshot taken during `calculateInstructionTokens` and is not\n * recomputed when `markToolsAsDiscovered` is called mid-run.\n */\n getTokenBudgetBreakdown(messages?: BaseMessage[]): t.TokenBudgetBreakdown {\n const maxContextTokens = this.maxContextTokens ?? 0;\n /**\n * Derive `toolCount` from `getToolsForBinding()` so the diagnostic stays\n * aligned with what is actually bound to the model — and with what\n * `calculateInstructionTokens` counts into `toolSchemaTokens`. Using raw\n * `this.tools.length` would inflate the count whenever the registry\n * marks instance tools as deferred-undiscovered or non-`'direct'`,\n * producing the same misleading \"N tools\" diagnostic this fix is meant\n * to eliminate.\n */\n const toolCount = this.getToolsForBinding()?.length ?? 0;\n const messageCount = messages?.length ?? 0;\n\n let messageTokens = 0;\n if (messages != null) {\n for (let i = 0; i < messages.length; i++) {\n messageTokens +=\n (this.indexTokenCountMap[i] as number | undefined) ?? 0;\n }\n }\n\n const reserveTokens = Math.round(maxContextTokens * DEFAULT_RESERVE_RATIO);\n const availableForMessages = Math.max(\n 0,\n maxContextTokens - reserveTokens - this.instructionTokens\n );\n\n return {\n maxContextTokens,\n instructionTokens: this.instructionTokens,\n systemMessageTokens: this.systemMessageTokens,\n dynamicInstructionTokens: this.dynamicInstructionTokens,\n toolSchemaTokens: this.toolSchemaTokens,\n summaryTokens: this.summaryTokenCount,\n toolCount,\n messageCount,\n messageTokens,\n availableForMessages,\n };\n }\n\n /**\n * Returns a human-readable string of the token budget breakdown\n * for inclusion in error messages and diagnostics.\n */\n formatTokenBudgetBreakdown(messages?: BaseMessage[]): string {\n const b = this.getTokenBudgetBreakdown(messages);\n const lines = [\n 'Token budget breakdown:',\n ` maxContextTokens: ${b.maxContextTokens}`,\n ` instructionTokens: ${b.instructionTokens} (system: ${b.systemMessageTokens}, dynamic: ${b.dynamicInstructionTokens}, tools: ${b.toolSchemaTokens} [${b.toolCount} tools])`,\n ` summaryTokens: ${b.summaryTokens}`,\n ` messageTokens: ${b.messageTokens} (${b.messageCount} messages)`,\n ` availableForMessages: ${b.availableForMessages}`,\n ];\n return lines.join('\\n');\n }\n\n /**\n * Updates the last-call usage with data from the most recent LLM response.\n * Unlike `currentUsage` which accumulates, this captures only the single call.\n */\n updateLastCallUsage(usage: Partial<UsageMetadata>): void {\n const baseInputTokens = Number(usage.input_tokens) || 0;\n const cacheCreation =\n Number(usage.input_token_details?.cache_creation) || 0;\n const cacheRead = Number(usage.input_token_details?.cache_read) || 0;\n\n const outputTokens = Number(usage.output_tokens) || 0;\n const cacheSum = cacheCreation + cacheRead;\n const cacheIsAdditive = cacheSum > 0 && cacheSum > baseInputTokens;\n const totalInputTokens = cacheIsAdditive\n ? baseInputTokens + cacheSum\n : baseInputTokens;\n\n this.lastCallUsage = {\n inputTokens: totalInputTokens,\n outputTokens,\n totalTokens: totalInputTokens + outputTokens,\n cacheRead: cacheRead || undefined,\n cacheCreation: cacheCreation || undefined,\n };\n this.totalTokensFresh = true;\n }\n\n /** Marks token data as stale before a new LLM call. */\n markTokensStale(): void {\n this.totalTokensFresh = false;\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 * In event-driven mode (toolDefinitions present, tools empty), creates schema-only tools.\n * Otherwise filters tool instances based on:\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.toolDefinitions && this.toolDefinitions.length > 0) {\n return this.getEventDrivenToolsForBinding();\n }\n\n const filtered = this.getEffectiveInstanceTools();\n\n if (this.graphTools && this.graphTools.length > 0) {\n return [...(filtered ?? []), ...this.graphTools];\n }\n\n return filtered;\n }\n\n /** Creates schema-only tools from toolDefinitions for event-driven mode, merged with native tools */\n private getEventDrivenToolsForBinding(): t.GraphTools {\n if (!this.toolDefinitions) {\n return this.graphTools ?? [];\n }\n\n const schemaTools = createSchemaOnlyTools(\n this.getActiveToolDefinitions()\n ) as t.GraphTools;\n\n const allTools = [...schemaTools];\n\n if (this.graphTools && this.graphTools.length > 0) {\n allTools.push(...this.graphTools);\n }\n\n const instanceTools = this.getEffectiveInstanceTools();\n if (instanceTools && instanceTools.length > 0) {\n allTools.push(...instanceTools);\n }\n\n return allTools;\n }\n\n /** Filters tool instances for binding based on registry config */\n private filterToolsForBinding(tools: t.GraphTools): t.GraphTools {\n return tools.filter((tool) => {\n if (!('name' in tool)) {\n return true;\n }\n\n const toolDef = this.toolRegistry?.get(tool.name);\n if (!toolDef) {\n return true;\n }\n\n if (this.discoveredToolNames.has(tool.name)) {\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n return allowedCallers.includes('direct');\n }\n\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n return (\n allowedCallers.includes('direct') && toolDef.defer_loading !== true\n );\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentContext.mjs","names":[],"sources":["../../../src/agents/AgentContext.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport { RunnableLambda } from '@langchain/core/runnables';\nimport { HumanMessage, SystemMessage } from '@langchain/core/messages';\nimport type {\n UsageMetadata,\n BaseMessage,\n BaseMessageFields,\n} from '@langchain/core/messages';\nimport type { RunnableConfig, Runnable } from '@langchain/core/runnables';\nimport type { createPruneMessages } from '@/messages';\nimport type * as t from '@/types';\nimport {\n ANTHROPIC_TOOL_TOKEN_MULTIPLIER,\n DEFAULT_TOOL_TOKEN_MULTIPLIER,\n ContentTypes,\n Constants,\n Providers,\n} from '@/common';\nimport {\n addCacheControl,\n addCacheControlToStablePrefixMessages,\n} from '@/messages/cache';\nimport { createSchemaOnlyTools } from '@/tools/schema';\nimport { apportionTokenCounts } from '@/utils/tokens';\nimport { DEFAULT_RESERVE_RATIO } from '@/messages';\nimport { toJsonSchema } from '@/utils/schema';\n\ntype AgentSystemTextBlock = {\n type: 'text';\n text: string;\n cache_control?: { type: 'ephemeral' };\n};\n\ntype AgentSystemContentBlock =\n | AgentSystemTextBlock\n | { cachePoint: { type: 'default' } };\n\ntype PromptCacheProvider = Providers.ANTHROPIC | Providers.OPENROUTER;\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 name,\n provider,\n clientOptions,\n langfuse,\n tools,\n toolMap,\n toolEnd,\n toolRegistry,\n toolDefinitions,\n instructions,\n additional_instructions,\n streamBuffer,\n maxContextTokens,\n reasoningKey,\n useLegacyContent,\n discoveredTools,\n summarizationEnabled,\n summarizationConfig,\n initialSummary,\n contextPruningConfig,\n maxToolResultChars,\n toolSchemaTokens,\n subagentConfigs,\n maxSubagentDepth,\n } = agentConfig;\n\n const agentContext = new AgentContext({\n agentId,\n name: name ?? agentId,\n provider,\n clientOptions,\n langfuse,\n maxContextTokens,\n streamBuffer,\n tools,\n toolMap,\n toolRegistry,\n toolDefinitions,\n instructions,\n additionalInstructions: additional_instructions,\n reasoningKey,\n toolEnd,\n instructionTokens: 0,\n tokenCounter,\n useLegacyContent,\n discoveredTools,\n summarizationEnabled,\n summarizationConfig,\n contextPruningConfig,\n maxToolResultChars,\n });\n\n agentContext._sourceInputs = agentConfig;\n agentContext.subagentConfigs = subagentConfigs;\n agentContext.maxSubagentDepth = maxSubagentDepth;\n\n if (initialSummary?.text != null && initialSummary.text !== '') {\n agentContext.setInitialSummary(\n initialSummary.text,\n initialSummary.tokenCount\n );\n }\n\n if (tokenCounter) {\n agentContext.initializeSystemRunnable();\n\n const tokenMap = indexTokenCountMap || {};\n agentContext.baseIndexTokenCountMap = { ...tokenMap };\n agentContext.indexTokenCountMap = tokenMap;\n\n if (toolSchemaTokens != null && toolSchemaTokens > 0) {\n /** Use pre-computed (cached) tool schema tokens — skip calculateInstructionTokens */\n agentContext.toolSchemaTokens = toolSchemaTokens;\n agentContext.tokenCalculationPromise = Promise.resolve();\n agentContext.updateTokenMapWithInstructions(tokenMap);\n } else {\n agentContext.tokenCalculationPromise = agentContext\n .calculateInstructionTokens(tokenCounter)\n .then(() => {\n agentContext.updateTokenMapWithInstructions(tokenMap);\n })\n .catch((err) => {\n console.error('Error calculating instruction tokens:', err);\n });\n }\n } else if (indexTokenCountMap) {\n agentContext.baseIndexTokenCountMap = { ...indexTokenCountMap };\n agentContext.indexTokenCountMap = indexTokenCountMap;\n }\n\n return agentContext;\n }\n\n /** Agent identifier */\n agentId: string;\n /** Human-readable name for this agent (used in handoff context). Falls back to agentId if not provided. */\n name?: string;\n /** Provider for this specific agent */\n provider: Providers;\n /** Client options for this agent */\n clientOptions?: t.ClientOptions;\n /** Per-agent Langfuse tracing configuration. */\n langfuse?: t.LangfuseConfig;\n /** Token count map indexed by message position */\n indexTokenCountMap: Record<string, number | undefined> = {};\n /** Canonical pre-run token map used to restore token accounting on reset */\n baseIndexTokenCountMap: Record<string, number> = {};\n /** Maximum context tokens for this agent */\n maxContextTokens?: number;\n /** Current usage metadata for this agent */\n currentUsage?: Partial<UsageMetadata>;\n /**\n * Usage from the most recent LLM call only (not accumulated).\n * Used for accurate provider calibration in pruning.\n */\n lastCallUsage?: {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n cacheRead?: number;\n cacheCreation?: number;\n };\n /**\n * Whether totalTokens data is fresh (set true when provider usage arrives,\n * false at the start of each turn before the LLM responds).\n * Prevents stale token data from driving pruning/trigger decisions.\n */\n totalTokensFresh: boolean = false;\n /** Context pruning configuration. */\n contextPruningConfig?: t.ContextPruningConfig;\n maxToolResultChars?: number;\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 /** Token count for the system message (instructions text). */\n systemMessageTokens: number = 0;\n /** Token count for instruction text emitted outside the system message. */\n dynamicInstructionTokens: number = 0;\n /** Token count for tool schemas only. */\n toolSchemaTokens: number = 0;\n /** Per-tool schema token counts (post-multiplier), keyed by tool name.\n * `undefined` when not calculated (e.g. cached aggregate schema tokens). */\n toolTokenCounts?: Record<string, number>;\n /** Names of counted tools that are deferred (`defer_loading`) and discovered. */\n deferredToolNames: string[] = [];\n /** Running calibration ratio from the pruner — persisted across runs via contextMeta. */\n calibrationRatio: number = 1;\n /** Provider-observed instruction overhead from the pruner's best-variance turn. */\n resolvedInstructionOverhead?: number;\n /** Pre-masking tool content keyed by message index, consumed by the summarize node. */\n pendingOriginalToolContent?: Map<number, string>;\n\n /** Total instruction overhead: system message + tool schemas + pending summary. */\n get instructionTokens(): number {\n const summaryOverhead =\n this._summaryLocation === 'user_message' ? this.summaryTokenCount : 0;\n return (\n this.systemMessageTokens +\n this.dynamicInstructionTokens +\n this.toolSchemaTokens +\n summaryOverhead\n );\n }\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 /** Graph-managed tools (e.g., handoff tools created by MultiAgentGraph) that bypass event-driven dispatch */\n graphTools?: 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 /**\n * Serializable tool definitions for event-driven execution.\n * When provided, ToolNode operates in event-driven mode.\n */\n toolDefinitions?: t.LCTool[];\n /** Set of tool names discovered via tool search (to be loaded) */\n discoveredToolNames: Set<string> = new Set();\n /** Original AgentInputs used to create this context — used for self-spawn subagent resolution. */\n _sourceInputs?: t.AgentInputs;\n /** Subagent configurations for hierarchical delegation. */\n subagentConfigs?: t.SubagentConfig[];\n /** Maximum subagent nesting depth. */\n maxSubagentDepth?: number;\n /** Instructions for this agent */\n instructions?: string;\n /** Additional instructions for this agent */\n additionalInstructions?: 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 /** Tracks how many reasoning→text transitions have occurred (ensures unique post-reasoning step keys) */\n reasoningTransitionCount = 0;\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 /** Promise for token calculation initialization */\n tokenCalculationPromise?: Promise<void>;\n /** Format content blocks as strings (for legacy compatibility) */\n useLegacyContent: boolean = false;\n /** Enables graph-level summarization for this agent */\n summarizationEnabled?: boolean;\n /** Summarization runtime settings used by graph pruning hooks */\n summarizationConfig?: t.SummarizationConfig;\n /** Current summary text produced by the summarize node, integrated into system message */\n private summaryText?: string;\n /** Token count of the current summary (tracked for token accounting) */\n private summaryTokenCount: number = 0;\n /**\n * Where the summary should be injected:\n * - `'system_prompt'`: cross-run summary, included in the dynamic system tail\n * - `'user_message'`: mid-run compaction, injected as HumanMessage on clean slate\n * - `'none'`: no summary present\n */\n private _summaryLocation: 'system_prompt' | 'user_message' | 'none' = 'none';\n /**\n * Durable summary that survives reset() calls. Set from initialSummary\n * during fromConfig() and updated by setSummary() so that the latest\n * summary (whether cross-run or intra-run) is always restored after\n * processStream's resetValues() cycle.\n */\n private _durableSummaryText?: string;\n private _durableSummaryTokenCount: number = 0;\n /** Number of summarization cycles that have occurred for this agent context */\n private _summaryVersion: number = 0;\n /**\n * Message count at the time summarization was last triggered.\n * Used to prevent re-summarizing the same unchanged message set.\n * Summarization is allowed to fire again only when new messages appear.\n */\n private _lastSummarizationMsgCount: number = 0;\n /**\n * Handoff context when this agent receives control via handoff.\n * Contains source and parallel execution info for system message context.\n */\n handoffContext?: {\n /** Source agent that transferred control */\n sourceAgentName: string;\n /** Names of sibling agents executing in parallel (empty if sequential) */\n parallelSiblings: string[];\n };\n\n constructor({\n agentId,\n name,\n provider,\n clientOptions,\n langfuse,\n maxContextTokens,\n streamBuffer,\n tokenCounter,\n tools,\n toolMap,\n toolRegistry,\n toolDefinitions,\n instructions,\n additionalInstructions,\n reasoningKey,\n toolEnd,\n instructionTokens,\n useLegacyContent,\n discoveredTools,\n summarizationEnabled,\n summarizationConfig,\n contextPruningConfig,\n maxToolResultChars,\n }: {\n agentId: string;\n name?: string;\n provider: Providers;\n clientOptions?: t.ClientOptions;\n langfuse?: t.LangfuseConfig;\n maxContextTokens?: number;\n streamBuffer?: number;\n tokenCounter?: t.TokenCounter;\n tools?: t.GraphTools;\n toolMap?: t.ToolMap;\n toolRegistry?: t.LCToolRegistry;\n toolDefinitions?: t.LCTool[];\n instructions?: string;\n additionalInstructions?: string;\n reasoningKey?: 'reasoning_content' | 'reasoning';\n toolEnd?: boolean;\n instructionTokens?: number;\n useLegacyContent?: boolean;\n discoveredTools?: string[];\n summarizationEnabled?: boolean;\n summarizationConfig?: t.SummarizationConfig;\n contextPruningConfig?: t.ContextPruningConfig;\n maxToolResultChars?: number;\n }) {\n this.agentId = agentId;\n this.name = name;\n this.provider = provider;\n this.clientOptions = clientOptions;\n this.langfuse = langfuse;\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.toolDefinitions = toolDefinitions;\n this.instructions = instructions;\n this.additionalInstructions = additionalInstructions;\n if (reasoningKey) {\n this.reasoningKey = reasoningKey;\n }\n if (toolEnd !== undefined) {\n this.toolEnd = toolEnd;\n }\n if (instructionTokens !== undefined) {\n this.systemMessageTokens = instructionTokens;\n }\n\n this.useLegacyContent = useLegacyContent ?? false;\n this.summarizationEnabled = summarizationEnabled;\n this.summarizationConfig = summarizationConfig;\n this.contextPruningConfig = contextPruningConfig;\n this.maxToolResultChars = maxToolResultChars;\n\n if (discoveredTools && discoveredTools.length > 0) {\n for (const toolName of discoveredTools) {\n this.discoveredToolNames.add(toolName);\n }\n }\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 * configured programmatic 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 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 programmaticTool = this.getProgrammaticToolInstructionTarget();\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 \\`${programmaticTool.name}\\` tool. ` +\n `You cannot call these tools directly; instead, use \\`${programmaticTool.name}\\` with ${programmaticTool.language} code that invokes them.\\n\\n` +\n toolDescriptions\n );\n }\n\n private getProgrammaticToolInstructionTarget(): {\n name: string;\n language: 'bash' | 'Python';\n } {\n if (this.hasAvailableTool(Constants.BASH_PROGRAMMATIC_TOOL_CALLING)) {\n return {\n name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,\n language: 'bash',\n };\n }\n\n if (this.hasAvailableTool(Constants.PROGRAMMATIC_TOOL_CALLING)) {\n return { name: Constants.PROGRAMMATIC_TOOL_CALLING, language: 'Python' };\n }\n\n return { name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING, language: 'bash' };\n }\n\n private hasAvailableTool(name: string): boolean {\n if (this.toolDefinitions?.some((tool) => tool.name === name) === true)\n return true;\n if (\n this.tools?.some((tool) => 'name' in tool && tool.name === name) === true\n ) {\n return true;\n }\n if (this.toolMap?.has(name) === true) return true;\n return this.toolRegistry?.has(name) === true;\n }\n\n /**\n * Gets the system runnable, creating it lazily if needed.\n * Includes stable instructions, dynamic additional instructions, and\n * 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 if (!this.systemRunnableStale && this.cachedSystemRunnable !== undefined) {\n return this.cachedSystemRunnable;\n }\n\n this.cachedSystemRunnable = this.buildSystemRunnable({\n stableInstructions: this.buildStableInstructionsString(),\n dynamicInstructions: this.buildDynamicInstructionsString(),\n });\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 this.cachedSystemRunnable = this.buildSystemRunnable({\n stableInstructions: this.buildStableInstructionsString(),\n dynamicInstructions: this.buildDynamicInstructionsString(),\n });\n this.systemRunnableStale = false;\n }\n }\n\n /**\n * Builds the cacheable instructions string (without creating SystemMessage).\n * Includes agent identity preamble and handoff context when available.\n */\n private buildStableInstructionsString(): string {\n const parts: string[] = [];\n\n const identityPreamble = this.buildIdentityPreamble();\n if (identityPreamble) {\n parts.push(identityPreamble);\n }\n\n if (this.instructions != null && this.instructions !== '') {\n parts.push(this.instructions);\n }\n\n const programmaticToolsDoc = this.buildProgrammaticOnlyToolsInstructions();\n if (programmaticToolsDoc) {\n parts.push(programmaticToolsDoc);\n }\n\n return parts.join('\\n\\n');\n }\n\n /**\n * Builds the dynamic system-tail string (without creating SystemMessage).\n * Keep this out of prompt-cache-marked content so volatile context does not\n * invalidate the stable prefix.\n */\n private buildDynamicInstructionsString(): string {\n const parts: string[] = [];\n\n if (\n this.additionalInstructions != null &&\n this.additionalInstructions !== ''\n ) {\n parts.push(this.additionalInstructions);\n }\n\n // Cross-run summary: include in the system tail so the model has context\n // from the prior run without invalidating the cacheable prefix. Mid-run\n // summaries are injected as a HumanMessage on the post-compaction clean\n // slate instead (see buildSystemRunnable).\n if (\n this._summaryLocation === 'system_prompt' &&\n this.summaryText != null &&\n this.summaryText !== ''\n ) {\n parts.push('## Conversation Summary\\n\\n' + this.summaryText);\n }\n\n return parts.join('\\n\\n');\n }\n\n /**\n * Builds the agent identity preamble including handoff context if present.\n * This helps the agent understand its role in the multi-agent workflow.\n */\n private buildIdentityPreamble(): string {\n if (!this.handoffContext) return '';\n\n const displayName = this.name ?? this.agentId;\n const { sourceAgentName, parallelSiblings } = this.handoffContext;\n const isParallel = parallelSiblings.length > 0;\n\n const lines: string[] = [];\n lines.push('## Multi-Agent Workflow');\n lines.push(\n `You are \"${displayName}\", transferred from \"${sourceAgentName}\".`\n );\n\n if (isParallel) {\n lines.push(`Running in parallel with: ${parallelSiblings.join(', ')}.`);\n }\n\n lines.push(\n 'Execute only tasks relevant to your role. Routing is already handled if requested, unless you can route further.'\n );\n\n return lines.join('\\n');\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 stableInstructions,\n dynamicInstructions,\n }: {\n stableInstructions: string;\n dynamicInstructions: string;\n }):\n | Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >\n | undefined {\n const hasMidRunSummary =\n this._summaryLocation === 'user_message' &&\n this.summaryText != null &&\n this.summaryText !== '';\n\n if (!stableInstructions && !dynamicInstructions && !hasMidRunSummary) {\n this.systemMessageTokens = 0;\n this.dynamicInstructionTokens = 0;\n return undefined;\n }\n\n const promptCacheProvider = this.getPromptCacheProvider();\n const shouldMoveDynamicInstructions =\n promptCacheProvider != null &&\n stableInstructions !== '' &&\n dynamicInstructions !== '';\n const systemMessage = this.buildSystemMessage({\n stableInstructions,\n dynamicInstructions,\n promptCacheProvider,\n shouldMoveDynamicInstructions,\n });\n\n if (this.tokenCounter) {\n this.systemMessageTokens = systemMessage\n ? this.tokenCounter(systemMessage)\n : 0;\n this.dynamicInstructionTokens = shouldMoveDynamicInstructions\n ? this.tokenCounter(new HumanMessage(dynamicInstructions))\n : 0;\n }\n\n return RunnableLambda.from((messages: BaseMessage[]) => {\n const prefix: BaseMessage[] = systemMessage ? [systemMessage] : [];\n\n // Build the non-system portion (summary + conversation), then apply\n // cache markers separately so addCacheControl doesn't strip the\n // SystemMessage's own cache_control breakpoint set above.\n const hasSummaryBody =\n this._summaryLocation === 'user_message' &&\n this.summaryText != null &&\n this.summaryText !== '';\n\n const bodyWithSummary =\n hasSummaryBody && promptCacheProvider == null\n ? [this.buildSummaryHumanMessage(promptCacheProvider), ...messages]\n : messages;\n const dynamicTail = this.buildPromptCacheDynamicTail({\n dynamicInstructions,\n hasSummaryBody,\n promptCacheProvider,\n shouldMoveDynamicInstructions,\n });\n let body = this.buildBodyWithPromptCacheDynamicTail(\n bodyWithSummary,\n dynamicTail,\n promptCacheProvider\n );\n\n if (\n promptCacheProvider != null &&\n dynamicTail.length === 0 &&\n body.length >= 2\n ) {\n body = addCacheControl(body);\n }\n return [...prefix, ...body];\n }).withConfig({ runName: 'prompt' });\n }\n\n private buildSummaryHumanMessage(\n promptCacheProvider: PromptCacheProvider | undefined\n ): HumanMessage {\n const wrappedSummary =\n '<summary>\\n' +\n (this.summaryText as string) +\n '\\n</summary>\\n\\n' +\n 'This is your own checkpoint: you wrote it to preserve context after compaction. Pick up where you left off based on the summary above. Do not repeat prior tasks, information or acknowledge this checkpoint message directly.';\n\n if (promptCacheProvider !== Providers.ANTHROPIC) {\n return new HumanMessage(wrappedSummary);\n }\n\n return new HumanMessage({\n content: [\n {\n type: 'text',\n text: wrappedSummary,\n cache_control: { type: 'ephemeral' },\n },\n ],\n });\n }\n\n private buildPromptCacheDynamicTail({\n dynamicInstructions,\n hasSummaryBody,\n promptCacheProvider,\n shouldMoveDynamicInstructions,\n }: {\n dynamicInstructions: string;\n hasSummaryBody: boolean;\n promptCacheProvider: PromptCacheProvider | undefined;\n shouldMoveDynamicInstructions: boolean;\n }): BaseMessage[] {\n if (promptCacheProvider == null) {\n return [];\n }\n\n const dynamicTail = shouldMoveDynamicInstructions\n ? [new HumanMessage(dynamicInstructions)]\n : [];\n\n if (!hasSummaryBody) {\n return dynamicTail;\n }\n\n return [...dynamicTail, this.buildSummaryHumanMessage(undefined)];\n }\n\n private buildBodyWithPromptCacheDynamicTail(\n messages: BaseMessage[],\n tail: BaseMessage[],\n promptCacheProvider: PromptCacheProvider | undefined\n ): BaseMessage[] {\n if (tail.length === 0) {\n return messages;\n }\n\n const tailIndex = this.getPromptCacheDynamicTailIndex(\n messages,\n promptCacheProvider\n );\n const stablePrefix = messages.slice(0, tailIndex);\n const trailingMessages = messages.slice(tailIndex);\n const cacheablePrefix = this.addStablePromptCacheMarkers(stablePrefix);\n\n return [...cacheablePrefix, ...tail, ...trailingMessages];\n }\n\n private getPromptCacheDynamicTailIndex(\n messages: BaseMessage[],\n promptCacheProvider: PromptCacheProvider | undefined\n ): number {\n const lastIndex = messages.length - 1;\n\n if (lastIndex < 0) {\n return 0;\n }\n\n if (promptCacheProvider === Providers.OPENROUTER && messages.length === 1) {\n return messages.length;\n }\n\n for (let index = lastIndex; index >= 0; index--) {\n if (messages[index].getType() === 'human') {\n if (promptCacheProvider === Providers.OPENROUTER && index === 0) {\n return 1;\n }\n return index;\n }\n }\n\n return messages.length;\n }\n\n private addStablePromptCacheMarkers(messages: BaseMessage[]): BaseMessage[] {\n if (messages.length <= 1) {\n return messages;\n }\n\n return [\n messages[0],\n ...addCacheControlToStablePrefixMessages(messages.slice(1), 2),\n ];\n }\n\n private getPromptCacheProvider(): PromptCacheProvider | undefined {\n if (this.provider === Providers.ANTHROPIC) {\n const anthropicOptions = this.clientOptions as\n | t.AnthropicClientOptions\n | undefined;\n return anthropicOptions?.promptCache === true\n ? Providers.ANTHROPIC\n : undefined;\n }\n\n if (this.provider === Providers.OPENROUTER) {\n const openRouterOptions = this.clientOptions as\n | t.ProviderOptionsMap[Providers.OPENROUTER]\n | undefined;\n return openRouterOptions?.promptCache === true\n ? Providers.OPENROUTER\n : undefined;\n }\n\n return undefined;\n }\n\n private hasBedrockPromptCache(): boolean {\n if (this.provider !== Providers.BEDROCK) {\n return false;\n }\n const bedrockOptions = this.clientOptions as\n | t.BedrockAnthropicClientOptions\n | undefined;\n return bedrockOptions?.promptCache === true;\n }\n\n private buildSystemMessage({\n stableInstructions,\n dynamicInstructions,\n promptCacheProvider,\n shouldMoveDynamicInstructions,\n }: {\n stableInstructions: string;\n dynamicInstructions: string;\n promptCacheProvider: PromptCacheProvider | undefined;\n shouldMoveDynamicInstructions: boolean;\n }): SystemMessage | undefined {\n if (!stableInstructions && !dynamicInstructions) {\n return undefined;\n }\n\n if (promptCacheProvider === Providers.ANTHROPIC) {\n const content: AgentSystemContentBlock[] = [];\n if (stableInstructions) {\n content.push({\n type: 'text',\n text: stableInstructions,\n cache_control: { type: 'ephemeral' },\n });\n }\n if (dynamicInstructions && !shouldMoveDynamicInstructions) {\n content.push({ type: 'text', text: dynamicInstructions });\n }\n return new SystemMessage({ content } as BaseMessageFields);\n }\n\n if (promptCacheProvider === Providers.OPENROUTER && !stableInstructions) {\n return new SystemMessage(dynamicInstructions);\n }\n\n if (promptCacheProvider === Providers.OPENROUTER) {\n return new SystemMessage({\n content: [\n {\n type: 'text',\n text: stableInstructions,\n cache_control: { type: 'ephemeral' },\n },\n ],\n } as BaseMessageFields);\n }\n\n if (this.hasBedrockPromptCache() && stableInstructions) {\n const content: AgentSystemContentBlock[] = [\n { type: 'text', text: stableInstructions },\n { cachePoint: { type: 'default' } },\n ];\n if (dynamicInstructions) {\n content.push({ type: 'text', text: dynamicInstructions });\n }\n return new SystemMessage({ content } as BaseMessageFields);\n }\n\n return new SystemMessage(\n [stableInstructions, dynamicInstructions]\n .filter((part) => part !== '')\n .join('\\n\\n')\n );\n }\n\n /**\n * Reset context for a new run\n */\n reset(): void {\n this.systemMessageTokens = 0;\n this.dynamicInstructionTokens = 0;\n this.toolSchemaTokens = 0;\n this.toolTokenCounts = undefined;\n this.deferredToolNames = [];\n this.cachedSystemRunnable = undefined;\n this.systemRunnableStale = true;\n this.lastToken = undefined;\n this.indexTokenCountMap = { ...this.baseIndexTokenCountMap };\n this.currentUsage = undefined;\n this.pruneMessages = undefined;\n this.lastStreamCall = undefined;\n this.tokenTypeSwitch = undefined;\n this.reasoningTransitionCount = 0;\n this.currentTokenType = ContentTypes.TEXT;\n this.discoveredToolNames.clear();\n this.handoffContext = undefined;\n\n this.summaryText = this._durableSummaryText;\n this.summaryTokenCount = this._durableSummaryTokenCount;\n this._lastSummarizationMsgCount = 0;\n this.lastCallUsage = undefined;\n this.totalTokensFresh = false;\n\n if (this.tokenCounter) {\n this.initializeSystemRunnable();\n const baseTokenMap = { ...this.baseIndexTokenCountMap };\n this.indexTokenCountMap = baseTokenMap;\n this.tokenCalculationPromise = this.calculateInstructionTokens(\n this.tokenCounter\n )\n .then(() => {\n this.updateTokenMapWithInstructions(baseTokenMap);\n })\n .catch((err) => {\n console.error('Error calculating instruction tokens:', err);\n });\n } else {\n this.tokenCalculationPromise = undefined;\n }\n }\n\n /**\n * Update the token count map from a base map.\n *\n * Previously this inflated index 0 with instructionTokens to indirectly\n * reserve budget for the system prompt. That approach was imprecise: with\n * large tool-schema overhead (e.g. 26 MCP tools ~5 000 tokens) the first\n * conversation message appeared enormous and was always pruned, while the\n * real available budget was never explicitly computed.\n *\n * Now instruction tokens are passed to getMessagesWithinTokenLimit via\n * the `getInstructionTokens` factory param so the pruner subtracts them\n * from the budget directly. The token map contains only real per-message\n * token counts.\n */\n updateTokenMapWithInstructions(baseTokenMap: Record<string, number>): void {\n this.indexTokenCountMap = { ...baseTokenMap };\n }\n\n /** Active tool definitions for token accounting (excludes deferred-and-undiscovered entries). */\n private getActiveToolDefinitions(): t.LCTool[] {\n if (!this.toolDefinitions) {\n return [];\n }\n /**\n * Mirror `getEventDrivenToolsForBinding`'s gate: a definition is only\n * bound to the model when its `allowed_callers` include `'direct'` and\n * (if deferred) it has been discovered. Filtering by `defer_loading`\n * alone left programmatic-only definitions counted in\n * `toolSchemaTokens` even though they were never bound.\n */\n return this.toolDefinitions.filter((def) => {\n const allowedCallers = def.allowed_callers ?? ['direct'];\n if (!allowedCallers.includes('direct')) {\n return false;\n }\n return (\n def.defer_loading !== true || this.discoveredToolNames.has(def.name)\n );\n });\n }\n\n /**\n * Single source of truth for \"which entries of `this.tools` should be\n * treated as actually bound\". Callers:\n * - `getToolsForBinding` (non-event-driven branch)\n * - `getEventDrivenToolsForBinding` (appends instance tools alongside\n * schema-only definitions)\n * - `calculateInstructionTokens` (counts schema bytes for accounting)\n *\n * In event-driven mode (`toolDefinitions` present) instance tools are\n * appended unfiltered; outside event-driven mode they pass through\n * `filterToolsForBinding`. Centralizing the decision here prevents the\n * accounting/binding paths from drifting apart, which was the root\n * cause of the original miscount.\n */\n private getEffectiveInstanceTools(): t.GraphTools | undefined {\n if (!this.tools) {\n return undefined;\n }\n const isEventDriven = (this.toolDefinitions?.length ?? 0) > 0;\n if (isEventDriven || !this.toolRegistry) {\n return this.tools;\n }\n return this.filterToolsForBinding(this.tools);\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 const countedToolNames = new Set<string>();\n /** Prototype-free: external tool names like `toString` must not hit\n * inherited properties during accumulation */\n const rawToolTokenCounts: Record<string, number> = Object.create(null);\n const deferredCountedNames = new Set<string>();\n\n /**\n * Iterate both `tools` (user-provided instance tools) and `graphTools`\n * (graph-managed tools like handoff + subagent). `graphTools` is often\n * populated after `fromConfig()` kicks off the initial calculation, so\n * callers that mutate `graphTools` must re-trigger this method to\n * refresh `toolSchemaTokens`.\n *\n * Use `getEffectiveInstanceTools()` so accounting reflects exactly the\n * subset that `getToolsForBinding` would emit — preventing the\n * worst-case-ceiling miscount that triggered spurious `empty_messages`\n * preflight rejections at low `maxContextTokens`. Deferred and\n * non-`'direct'` `toolDefinitions` are excluded by\n * `getActiveToolDefinitions()` below.\n */\n const instanceTools: t.GraphTools = [\n ...((this.getEffectiveInstanceTools() as t.GenericTool[] | undefined) ??\n []),\n ...((this.graphTools as t.GenericTool[] | undefined) ?? []),\n ];\n\n if (instanceTools.length > 0) {\n for (const tool of instanceTools) {\n const genericTool = tool as Record<string, unknown>;\n if (\n genericTool.schema != null &&\n typeof genericTool.schema === 'object'\n ) {\n const toolName = (genericTool.name as string | undefined) ?? '';\n const jsonSchema = toJsonSchema(\n genericTool.schema,\n toolName,\n (genericTool.description as string | undefined) ?? ''\n );\n const schemaTokens = tokenCounter(\n new SystemMessage(JSON.stringify(jsonSchema))\n );\n toolTokens += schemaTokens;\n if (toolName) {\n countedToolNames.add(toolName);\n rawToolTokenCounts[toolName] =\n (rawToolTokenCounts[toolName] ?? 0) + schemaTokens;\n }\n }\n }\n }\n\n for (const def of this.getActiveToolDefinitions()) {\n if (countedToolNames.has(def.name)) {\n continue;\n }\n const schema = {\n type: 'function',\n function: {\n name: def.name,\n description: def.description ?? '',\n parameters: def.parameters ?? {},\n },\n };\n const schemaTokens = tokenCounter(\n new SystemMessage(JSON.stringify(schema))\n );\n toolTokens += schemaTokens;\n countedToolNames.add(def.name);\n rawToolTokenCounts[def.name] =\n (rawToolTokenCounts[def.name] ?? 0) + schemaTokens;\n if (def.defer_loading === true) {\n deferredCountedNames.add(def.name);\n }\n }\n\n const isAnthropic =\n this.provider !== Providers.BEDROCK &&\n (this.provider === Providers.ANTHROPIC ||\n /anthropic|claude/i.test(\n String(\n (this.clientOptions as { model?: string } | undefined)?.model ?? ''\n )\n ));\n const toolTokenMultiplier = isAnthropic\n ? ANTHROPIC_TOOL_TOKEN_MULTIPLIER\n : DEFAULT_TOOL_TOKEN_MULTIPLIER;\n this.toolSchemaTokens = Math.ceil(toolTokens * toolTokenMultiplier);\n\n /** Largest-remainder apportionment keeps the per-tool counts summing\n * exactly to the aggregate despite per-entry rounding */\n const toolTokenCounts = apportionTokenCounts(\n rawToolTokenCounts,\n toolTokenMultiplier,\n this.toolSchemaTokens\n );\n const deferredToolNames: string[] = [];\n for (const name of Object.keys(rawToolTokenCounts)) {\n if (\n deferredCountedNames.has(name) ||\n this.toolRegistry?.get(name)?.defer_loading === true\n ) {\n deferredToolNames.push(name);\n }\n }\n this.toolTokenCounts = toolTokenCounts;\n this.deferredToolNames = deferredToolNames;\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 * Sets the handoff context for this agent.\n * Call this when the agent receives control via handoff from another agent.\n * Marks system runnable as stale to include handoff context in system message.\n * @param sourceAgentName - Name of the agent that transferred control\n * @param parallelSiblings - Names of other agents executing in parallel with this one\n */\n setHandoffContext(sourceAgentName: string, parallelSiblings: string[]): void {\n this.handoffContext = { sourceAgentName, parallelSiblings };\n this.systemRunnableStale = true;\n }\n\n /**\n * Clears any handoff context.\n * Call this when resetting the agent or when handoff context is no longer relevant.\n */\n clearHandoffContext(): void {\n if (this.handoffContext) {\n this.handoffContext = undefined;\n this.systemRunnableStale = true;\n }\n }\n\n setSummary(text: string, tokenCount: number): void {\n this.summaryText = text;\n this.summaryTokenCount = tokenCount;\n this._summaryLocation = 'user_message';\n this._durableSummaryText = text;\n this._durableSummaryTokenCount = tokenCount;\n this._summaryVersion += 1;\n this.systemRunnableStale = true;\n this.pruneMessages = undefined;\n }\n\n /** Sets a cross-run summary that is injected into the system prompt. */\n setInitialSummary(text: string, tokenCount: number): void {\n this.summaryText = text;\n this.summaryTokenCount = tokenCount;\n this._summaryLocation = 'system_prompt';\n this._durableSummaryText = text;\n this._durableSummaryTokenCount = tokenCount;\n this._summaryVersion += 1;\n this.systemRunnableStale = true;\n }\n\n /**\n * Replaces the indexTokenCountMap with a fresh map keyed to the surviving\n * context messages after summarization. Called by the summarize node after\n * it emits RemoveMessage operations that shift message indices.\n */\n rebuildTokenMapAfterSummarization(newTokenMap: Record<string, number>): void {\n this.indexTokenCountMap = newTokenMap;\n this.baseIndexTokenCountMap = { ...newTokenMap };\n this._lastSummarizationMsgCount = Object.keys(newTokenMap).length;\n this.currentUsage = undefined;\n this.lastCallUsage = undefined;\n this.totalTokensFresh = false;\n }\n\n hasSummary(): boolean {\n return this.summaryText != null && this.summaryText !== '';\n }\n\n /** True when a mid-run compaction summary is ready to be injected as a HumanMessage. */\n hasPendingCompactionSummary(): boolean {\n return this._summaryLocation === 'user_message' && this.hasSummary();\n }\n\n getSummaryText(): string | undefined {\n return this.summaryText;\n }\n\n get summaryVersion(): number {\n return this._summaryVersion;\n }\n\n /**\n * Returns true when the message count hasn't changed since the last\n * summarization — re-summarizing would produce an identical result.\n * Oversized individual messages are handled by fit-to-budget truncation\n * in the pruner, which keeps them in context without triggering overflow.\n */\n shouldSkipSummarization(currentMsgCount: number): boolean {\n return (\n this._lastSummarizationMsgCount > 0 &&\n currentMsgCount <= this._lastSummarizationMsgCount\n );\n }\n\n /**\n * Records the message count at which summarization was triggered,\n * so subsequent calls with the same count are suppressed.\n */\n markSummarizationTriggered(msgCount: number): void {\n this._lastSummarizationMsgCount = msgCount;\n }\n\n clearSummary(): void {\n if (this.summaryText != null) {\n this.summaryText = undefined;\n this.summaryTokenCount = 0;\n this._durableSummaryText = undefined;\n this._durableSummaryTokenCount = 0;\n this._summaryLocation = 'none';\n this.systemRunnableStale = true;\n }\n }\n\n /**\n * Returns a structured breakdown of how the context token budget is consumed.\n * Useful for diagnostics when context overflow or pruning issues occur.\n *\n * Note: `markToolsAsDiscovered` re-triggers `calculateInstructionTokens`,\n * so `toolSchemaTokens`/`toolTokenCounts` refresh before the next call.\n */\n getTokenBudgetBreakdown(messages?: BaseMessage[]): t.TokenBudgetBreakdown {\n const maxContextTokens = this.maxContextTokens ?? 0;\n /**\n * Derive `toolCount` from `getToolsForBinding()` so the diagnostic stays\n * aligned with what is actually bound to the model — and with what\n * `calculateInstructionTokens` counts into `toolSchemaTokens`. Using raw\n * `this.tools.length` would inflate the count whenever the registry\n * marks instance tools as deferred-undiscovered or non-`'direct'`,\n * producing the same misleading \"N tools\" diagnostic this fix is meant\n * to eliminate.\n */\n const toolCount = this.getToolsForBinding()?.length ?? 0;\n const messageCount = messages?.length ?? 0;\n\n let messageTokens = 0;\n if (messages != null) {\n for (let i = 0; i < messages.length; i++) {\n messageTokens +=\n (this.indexTokenCountMap[i] as number | undefined) ?? 0;\n }\n }\n\n /** Mirror the pruner's reserve math so availableForMessages agrees\n * with the contextBudget computed during pruning */\n const reserveRatio =\n this.summarizationConfig?.reserveRatio ?? DEFAULT_RESERVE_RATIO;\n const reserveTokens =\n reserveRatio > 0 && reserveRatio < 1\n ? Math.round(maxContextTokens * reserveRatio)\n : 0;\n const availableForMessages = Math.max(\n 0,\n maxContextTokens - reserveTokens - this.instructionTokens\n );\n\n return {\n maxContextTokens,\n instructionTokens: this.instructionTokens,\n systemMessageTokens: this.systemMessageTokens,\n dynamicInstructionTokens: this.dynamicInstructionTokens,\n toolSchemaTokens: this.toolSchemaTokens,\n summaryTokens: this.summaryTokenCount,\n toolCount,\n messageCount,\n messageTokens,\n availableForMessages,\n toolTokenCounts:\n this.toolTokenCounts != null ? { ...this.toolTokenCounts } : undefined,\n deferredToolNames:\n this.deferredToolNames.length > 0\n ? [...this.deferredToolNames]\n : undefined,\n };\n }\n\n /**\n * Returns a human-readable string of the token budget breakdown\n * for inclusion in error messages and diagnostics.\n */\n formatTokenBudgetBreakdown(messages?: BaseMessage[]): string {\n const b = this.getTokenBudgetBreakdown(messages);\n const lines = [\n 'Token budget breakdown:',\n ` maxContextTokens: ${b.maxContextTokens}`,\n ` instructionTokens: ${b.instructionTokens} (system: ${b.systemMessageTokens}, dynamic: ${b.dynamicInstructionTokens}, tools: ${b.toolSchemaTokens} [${b.toolCount} tools])`,\n ` summaryTokens: ${b.summaryTokens}`,\n ` messageTokens: ${b.messageTokens} (${b.messageCount} messages)`,\n ` availableForMessages: ${b.availableForMessages}`,\n ];\n return lines.join('\\n');\n }\n\n /**\n * Updates the last-call usage with data from the most recent LLM response.\n * Unlike `currentUsage` which accumulates, this captures only the single call.\n */\n updateLastCallUsage(usage: Partial<UsageMetadata>): void {\n const baseInputTokens = Number(usage.input_tokens) || 0;\n const cacheCreation =\n Number(usage.input_token_details?.cache_creation) || 0;\n const cacheRead = Number(usage.input_token_details?.cache_read) || 0;\n\n const outputTokens = Number(usage.output_tokens) || 0;\n const cacheSum = cacheCreation + cacheRead;\n const cacheIsAdditive = cacheSum > 0 && cacheSum > baseInputTokens;\n const totalInputTokens = cacheIsAdditive\n ? baseInputTokens + cacheSum\n : baseInputTokens;\n\n this.lastCallUsage = {\n inputTokens: totalInputTokens,\n outputTokens,\n totalTokens: totalInputTokens + outputTokens,\n cacheRead: cacheRead || undefined,\n cacheCreation: cacheCreation || undefined,\n };\n this.totalTokensFresh = true;\n }\n\n /** Marks token data as stale before a new LLM call. */\n markTokensStale(): void {\n this.totalTokensFresh = false;\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 /** Refresh schema token accounting so the next call's budget and\n * per-tool breakdown include the newly discovered tools; awaited\n * via tokenCalculationPromise before the next model call */\n if (this.tokenCounter) {\n this.tokenCalculationPromise = this.calculateInstructionTokens(\n this.tokenCounter\n );\n }\n }\n return hasNewDiscoveries;\n }\n\n /**\n * Gets tools that should be bound to the LLM.\n * In event-driven mode (toolDefinitions present, tools empty), creates schema-only tools.\n * Otherwise filters tool instances based on:\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.toolDefinitions && this.toolDefinitions.length > 0) {\n return this.getEventDrivenToolsForBinding();\n }\n\n const filtered = this.getEffectiveInstanceTools();\n\n if (this.graphTools && this.graphTools.length > 0) {\n return [...(filtered ?? []), ...this.graphTools];\n }\n\n return filtered;\n }\n\n /** Creates schema-only tools from toolDefinitions for event-driven mode, merged with native tools */\n private getEventDrivenToolsForBinding(): t.GraphTools {\n if (!this.toolDefinitions) {\n return this.graphTools ?? [];\n }\n\n const schemaTools = createSchemaOnlyTools(\n this.getActiveToolDefinitions()\n ) as t.GraphTools;\n\n const allTools = [...schemaTools];\n\n if (this.graphTools && this.graphTools.length > 0) {\n allTools.push(...this.graphTools);\n }\n\n const instanceTools = this.getEffectiveInstanceTools();\n if (instanceTools && instanceTools.length > 0) {\n allTools.push(...instanceTools);\n }\n\n return allTools;\n }\n\n /** Filters tool instances for binding based on registry config */\n private filterToolsForBinding(tools: t.GraphTools): t.GraphTools {\n return tools.filter((tool) => {\n if (!('name' in tool)) {\n return true;\n }\n\n const toolDef = this.toolRegistry?.get(tool.name);\n if (!toolDef) {\n return true;\n }\n\n if (this.discoveredToolNames.has(tool.name)) {\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n return allowedCallers.includes('direct');\n }\n\n const allowedCallers = toolDef.allowed_callers ?? ['direct'];\n return (\n allowedCallers.includes('direct') && toolDef.defer_loading !== true\n );\n });\n }\n}\n"],"mappings":"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"}
@@ -30,6 +30,8 @@ let GraphEvents = /* @__PURE__ */ function(GraphEvents) {
30
30
  GraphEvents["ON_SUBAGENT_UPDATE"] = "on_subagent_update";
31
31
  /** [Custom] Diagnostic logging event for context management observability */
32
32
  GraphEvents["ON_AGENT_LOG"] = "on_agent_log";
33
+ /** [Custom] Per-model-call context window usage snapshot (post-prune token budget) */
34
+ GraphEvents["ON_CONTEXT_USAGE"] = "on_context_usage";
33
35
  /** Custom event, emitted by system */
34
36
  GraphEvents["ON_CUSTOM_EVENT"] = "on_custom_event";
35
37
  /** Emitted when a chat model starts processing. */
@@ -150,6 +152,17 @@ let Constants = /* @__PURE__ */ function(Constants) {
150
152
  /** Anthropic server tool ID prefix (web_search, code_execution, etc.) */
151
153
  Constants["ANTHROPIC_SERVER_TOOL_PREFIX"] = "srvtoolu_";
152
154
  Constants["SKILL_TOOL"] = "skill";
155
+ /**
156
+ * Callback-metadata keys stamped by `attemptInvoke` /
157
+ * `tryFallbackProviders` carrying the provider (SDK `Providers` enum
158
+ * value) and configured model that actually served a model invocation.
159
+ * Unlike `ls_provider` — which derived providers inherit from their base
160
+ * class (e.g. DeepSeek/OpenRouter report `'openai'`) — these reflect the
161
+ * SDK's own routing, including fallback-provider calls. Consumed by the
162
+ * subagent usage-capture handler to tag billing events.
163
+ */
164
+ Constants["INVOKED_PROVIDER"] = "__invoked_provider";
165
+ Constants["INVOKED_MODEL"] = "__invoked_model";
153
166
  Constants["READ_FILE"] = "read_file";
154
167
  Constants["BASH_TOOL"] = "bash_tool";
155
168
  Constants["BASH_PROGRAMMATIC_TOOL_CALLING"] = "run_tools_with_bash";