@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":"index.mjs","names":[],"sources":["../../../../src/llm/vertexai/index.ts"],"sourcesContent":["import { ChatGoogle } from '@langchain/google-gauth';\nimport { ChatConnection } from '@langchain/google-common';\nimport { AIMessageChunk, isAIMessage } from '@langchain/core/messages';\nimport type {\n GeminiContent,\n GeminiRequest,\n GoogleAIModelRequestParams,\n GoogleAbstractedClient,\n} from '@langchain/google-common';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { BaseMessage, UsageMetadata } from '@langchain/core/messages';\nimport type { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { GoogleThinkingConfig, VertexAIClientOptions } from '@/types';\n\n/**\n * `@langchain/google-common`'s `_streamResponseChunks` emits usage on TWO\n * different paths within the same stream:\n *\n * - Streaming chunks set `chunk.generationInfo.usage_metadata` via\n * `responseToUsageMetadata`, which correctly sums\n * `candidatesTokenCount + thoughtsTokenCount` and includes\n * `output_token_details.reasoning`.\n * - The trailing fallback chunk (emitted after the API stream exhausts)\n * attaches its own `chunk.message.usage_metadata` built inline as\n * `output_tokens = candidatesTokenCount` only — dropping\n * `thoughtsTokenCount` and `output_token_details` entirely.\n *\n * After `AIMessageChunk.concat`, only `message.usage_metadata` survives —\n * which is the buggy fallback value. This breaks the documented\n * `total_tokens === input_tokens + output_tokens` invariant and silently\n * undercharges thinking models for reasoning tokens.\n *\n * The repair: track the last `generationInfo.usage_metadata` we see, and\n * when the fallback chunk arrives with its buggy `message.usage_metadata`,\n * replace it with the tracked good value. `CustomChatGoogleGenerativeAI`\n * solves the same problem for the Google API path differently — by\n * overriding `_convertToUsageMetadata`.\n */\nexport function repairStreamUsageMetadata(\n current: UsageMetadata | undefined,\n generationInfoUsage: UsageMetadata | undefined\n): UsageMetadata | undefined {\n if (!current) return current;\n if (!generationInfoUsage) return current;\n if (generationInfoUsage.total_tokens !== current.total_tokens) return current;\n if (generationInfoUsage.output_tokens <= current.output_tokens)\n return current;\n return generationInfoUsage;\n}\n\ntype AdditionalKwargs =\n | undefined\n | (BaseMessage['additional_kwargs'] & {\n signatures?: Array<string | undefined>;\n });\n\n/**\n * Fixes thought signatures on functionCall parts in the formatted Gemini request.\n *\n * `@langchain/google-common` stores signatures as a flat array in\n * `additional_kwargs.signatures` (one per response part) and re-attaches them\n * by index only when `signatures.length === parts.length`. This fails when:\n * - The API omits a signature (length mismatch)\n * - Streaming chunks merge with different part counts\n * - The signature for a functionCall part is an empty string\n *\n * This function correlates each \"model\" content block in the formatted request\n * back to its originating AI message by *position*, then re-attaches non-empty\n * signatures that the library failed to apply. AI messages without signatures\n * still consume their slot — filtering them out shifted later messages onto\n * the wrong content block and dropped real signatures on the floor.\n */\nexport function fixThoughtSignatures(\n contents: GeminiContent[],\n input: BaseMessage[]\n): void {\n // All AI messages, in order — non-signature ones still consume positional\n // slots so later messages line up with their model content blocks.\n const aiMessages = input.filter(isAIMessage);\n const modelContents = contents.filter((c) => c.role === 'model');\n\n const count = Math.min(aiMessages.length, modelContents.length);\n for (let i = 0; i < count; i++) {\n const signatures = (aiMessages[i].additional_kwargs as AdditionalKwargs)\n ?.signatures;\n if (!Array.isArray(signatures) || signatures.length === 0) continue;\n\n const content = modelContents[i];\n const attachedSignatures = new Set(\n content.parts\n .map((p) => p.thoughtSignature)\n .filter((s): s is string => s != null && s !== '')\n );\n const availableSignatures = signatures.filter(\n (s): s is string => s != null && s !== '' && !attachedSignatures.has(s)\n );\n\n let sigIdx = 0;\n for (const part of content.parts) {\n if (\n 'functionCall' in part &&\n (part.thoughtSignature == null || part.thoughtSignature === '') &&\n sigIdx < availableSignatures.length\n ) {\n part.thoughtSignature = availableSignatures[sigIdx];\n sigIdx++;\n }\n }\n }\n}\n\nclass CustomChatConnection extends ChatConnection<VertexAIClientOptions> {\n thinkingConfig?: GoogleThinkingConfig;\n\n async formatData(\n input: BaseMessage[],\n parameters: GoogleAIModelRequestParams\n ): Promise<unknown> {\n const formattedData = (await super.formatData(\n input,\n parameters\n )) as GeminiRequest;\n if (formattedData.generationConfig?.thinkingConfig?.thinkingBudget === -1) {\n // -1 means \"let the model decide\" - delete the property so the API doesn't receive an invalid value\n if (\n formattedData.generationConfig.thinkingConfig.includeThoughts === false\n ) {\n formattedData.generationConfig.thinkingConfig.includeThoughts = true;\n }\n delete formattedData.generationConfig.thinkingConfig.thinkingBudget;\n }\n if (this.thinkingConfig?.thinkingLevel != null) {\n formattedData.generationConfig ??= {};\n // thinkingLevel and thinkingBudget cannot coexist — the API rejects the request.\n // Remove thinkingBudget when thinkingLevel is set.\n const { thinkingBudget: _, ...existingThinkingConfig } =\n (formattedData.generationConfig.thinkingConfig as\n | Record<string, unknown>\n | undefined) ?? {};\n (\n formattedData.generationConfig as Record<string, unknown>\n ).thinkingConfig = {\n ...existingThinkingConfig,\n thinkingLevel: this.thinkingConfig.thinkingLevel,\n ...(this.thinkingConfig.includeThoughts != null && {\n includeThoughts: this.thinkingConfig.includeThoughts,\n }),\n };\n }\n if (formattedData.contents) {\n fixThoughtSignatures(formattedData.contents, input);\n // gemini-3.1+ models reject role=\"function\"; convert to role=\"user\"\n for (const content of formattedData.contents) {\n if (content.role === 'function') {\n (content as { role: string }).role = 'user';\n }\n }\n }\n return formattedData;\n }\n}\n\n/**\n * Integration with Google Vertex AI chat models.\n *\n * Setup:\n * Install `@langchain/google-vertexai` and set your stringified\n * Vertex AI credentials as an environment variable named `GOOGLE_APPLICATION_CREDENTIALS`.\n *\n * ```bash\n * npm install @langchain/google-vertexai\n * export GOOGLE_APPLICATION_CREDENTIALS=\"path/to/credentials\"\n * ```\n *\n * ## [Constructor args](https://api.js.langchain.com/classes/_langchain_google_vertexai.index.ChatVertexAI.html#constructor.new_ChatVertexAI)\n *\n * ## [Runtime args](https://api.js.langchain.com/interfaces/langchain_google_common_types.GoogleAIBaseLanguageModelCallOptions.html)\n *\n * Runtime args can be passed as the second argument to any of the base runnable methods `.invoke`. `.stream`, `.batch`, etc.\n * They can also be passed via `.withConfig`, or the second arg in `.bindTools`, like shown in the examples below:\n *\n * ```typescript\n * // When calling `.withConfig`, call options should be passed via the first argument\n * const llmWithArgsBound = llm.withConfig({\n * stop: [\"\\n\"],\n * tools: [...],\n * });\n *\n * // When calling `.bindTools`, call options should be passed via the second argument\n * const llmWithTools = llm.bindTools(\n * [...],\n * {\n * tool_choice: \"auto\",\n * }\n * );\n * ```\n *\n * ## Examples\n *\n * <details open>\n * <summary><strong>Instantiate</strong></summary>\n *\n * ```typescript\n * import { ChatVertexAI } from '@langchain/google-vertexai';\n *\n * const llm = new ChatVertexAI({\n * model: \"gemini-1.5-pro\",\n * temperature: 0,\n * // other params...\n * });\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Invoking</strong></summary>\n *\n * ```typescript\n * const input = `Translate \"I love programming\" into French.`;\n *\n * // Models also accept a list of chat messages or a formatted prompt\n * const result = await llm.invoke(input);\n * console.log(result);\n * ```\n *\n * ```txt\n * AIMessageChunk {\n * \"content\": \"\\\"J'adore programmer\\\" \\n\\nHere's why this is the best translation:\\n\\n* **J'adore** means \\\"I love\\\" and conveys a strong passion.\\n* **Programmer** is the French verb for \\\"to program.\\\"\\n\\nThis translation is natural and idiomatic in French. \\n\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {},\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": [],\n * \"usage_metadata\": {\n * \"input_tokens\": 9,\n * \"output_tokens\": 63,\n * \"total_tokens\": 72\n * }\n * }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Streaming Chunks</strong></summary>\n *\n * ```typescript\n * for await (const chunk of await llm.stream(input)) {\n * console.log(chunk);\n * }\n * ```\n *\n * ```txt\n * AIMessageChunk {\n * \"content\": \"\\\"\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {},\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": []\n * }\n * AIMessageChunk {\n * \"content\": \"J'adore programmer\\\" \\n\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {},\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": []\n * }\n * AIMessageChunk {\n * \"content\": \"\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {},\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": []\n * }\n * AIMessageChunk {\n * \"content\": \"\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {\n * \"finishReason\": \"stop\"\n * },\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": [],\n * \"usage_metadata\": {\n * \"input_tokens\": 9,\n * \"output_tokens\": 8,\n * \"total_tokens\": 17\n * }\n * }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Aggregate Streamed Chunks</strong></summary>\n *\n * ```typescript\n * import { AIMessageChunk } from '@langchain/core/messages';\n * import { concat } from '@langchain/core/utils/stream';\n *\n * const stream = await llm.stream(input);\n * let full: AIMessageChunk | undefined;\n * for await (const chunk of stream) {\n * full = !full ? chunk : concat(full, chunk);\n * }\n * console.log(full);\n * ```\n *\n * ```txt\n * AIMessageChunk {\n * \"content\": \"\\\"J'adore programmer\\\" \\n\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {\n * \"finishReason\": \"stop\"\n * },\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": [],\n * \"usage_metadata\": {\n * \"input_tokens\": 9,\n * \"output_tokens\": 8,\n * \"total_tokens\": 17\n * }\n * }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Bind tools</strong></summary>\n *\n * ```typescript\n * import { z } from 'zod';\n *\n * const GetWeather = {\n * name: \"GetWeather\",\n * description: \"Get the current weather in a given location\",\n * schema: z.object({\n * location: z.string().describe(\"The city and state, e.g. San Francisco, CA\")\n * }),\n * }\n *\n * const GetPopulation = {\n * name: \"GetPopulation\",\n * description: \"Get the current population in a given location\",\n * schema: z.object({\n * location: z.string().describe(\"The city and state, e.g. San Francisco, CA\")\n * }),\n * }\n *\n * const llmWithTools = llm.bindTools([GetWeather, GetPopulation]);\n * const aiMsg = await llmWithTools.invoke(\n * \"Which city is hotter today and which is bigger: LA or NY?\"\n * );\n * console.log(aiMsg.tool_calls);\n * ```\n *\n * ```txt\n * [\n * {\n * name: 'GetPopulation',\n * args: { location: 'New York City, NY' },\n * id: '33c1c1f47e2f492799c77d2800a43912',\n * type: 'tool_call'\n * }\n * ]\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Structured Output</strong></summary>\n *\n * ```typescript\n * import { z } from 'zod';\n *\n * const Joke = z.object({\n * setup: z.string().describe(\"The setup of the joke\"),\n * punchline: z.string().describe(\"The punchline to the joke\"),\n * rating: z.number().optional().describe(\"How funny the joke is, from 1 to 10\")\n * }).describe('Joke to tell user.');\n *\n * const structuredLlm = llm.withStructuredOutput(Joke, { name: \"Joke\" });\n * const jokeResult = await structuredLlm.invoke(\"Tell me a joke about cats\");\n * console.log(jokeResult);\n * ```\n *\n * ```txt\n * {\n * setup: 'What do you call a cat that loves to bowl?',\n * punchline: 'An alley cat!'\n * }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Usage Metadata</strong></summary>\n *\n * ```typescript\n * const aiMsgForMetadata = await llm.invoke(input);\n * console.log(aiMsgForMetadata.usage_metadata);\n * ```\n *\n * ```txt\n * { input_tokens: 9, output_tokens: 8, total_tokens: 17 }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Stream Usage Metadata</strong></summary>\n *\n * ```typescript\n * const streamForMetadata = await llm.stream(\n * input,\n * {\n * streamUsage: true\n * }\n * );\n * let fullForMetadata: AIMessageChunk | undefined;\n * for await (const chunk of streamForMetadata) {\n * fullForMetadata = !fullForMetadata ? chunk : concat(fullForMetadata, chunk);\n * }\n * console.log(fullForMetadata?.usage_metadata);\n * ```\n *\n * ```txt\n * { input_tokens: 9, output_tokens: 8, total_tokens: 17 }\n * ```\n * </details>\n *\n * <br />\n */\nexport class ChatVertexAI extends ChatGoogle {\n lc_namespace = ['langchain', 'chat_models', 'vertexai'];\n dynamicThinkingBudget = false;\n thinkingConfig?: GoogleThinkingConfig;\n\n static lc_name(): 'LibreChatVertexAI' {\n return 'LibreChatVertexAI';\n }\n\n constructor(model: string, fields?: Omit<VertexAIClientOptions, 'model'>);\n constructor(fields?: VertexAIClientOptions);\n constructor(\n modelOrFields?: string | VertexAIClientOptions,\n params?: Omit<VertexAIClientOptions, 'model'>\n ) {\n const fields =\n typeof modelOrFields === 'string'\n ? { ...(params ?? {}), model: modelOrFields }\n : modelOrFields;\n const dynamicThinkingBudget = fields?.thinkingBudget === -1;\n super({\n ...fields,\n platformType: 'gcp',\n });\n this.dynamicThinkingBudget = dynamicThinkingBudget;\n this.thinkingConfig = fields?.thinkingConfig;\n }\n invocationParams(\n options?: this['ParsedCallOptions'] | undefined\n ): GoogleAIModelRequestParams {\n const params = super.invocationParams(options);\n if (this.dynamicThinkingBudget) {\n params.maxReasoningTokens = -1;\n }\n return params;\n }\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n let lastGoodUsage: UsageMetadata | undefined;\n for await (const chunk of super._streamResponseChunks(\n messages,\n options,\n runManager\n )) {\n const genUsage = (\n chunk.generationInfo as { usage_metadata?: UsageMetadata } | undefined\n )?.usage_metadata;\n if (genUsage) {\n lastGoodUsage = genUsage;\n }\n if (chunk.message instanceof AIMessageChunk) {\n const repaired = repairStreamUsageMetadata(\n chunk.message.usage_metadata,\n lastGoodUsage\n );\n if (repaired !== chunk.message.usage_metadata) {\n chunk.message.usage_metadata = repaired;\n }\n }\n yield chunk;\n }\n }\n buildConnection(\n fields: VertexAIClientOptions | undefined,\n client: GoogleAbstractedClient\n ): void {\n // Note: buildConnection is called from super() BEFORE this.thinkingConfig is set,\n // so we must read thinkingConfig from `fields` directly.\n const thinkingConfig = fields?.thinkingConfig ?? this.thinkingConfig;\n\n const connection = new CustomChatConnection(\n { ...fields, ...this },\n this.caller,\n client,\n false\n );\n connection.thinkingConfig = thinkingConfig;\n this.connection = connection;\n\n const streamedConnection = new CustomChatConnection(\n { ...fields, ...this },\n this.caller,\n client,\n true\n );\n streamedConnection.thinkingConfig = thinkingConfig;\n this.streamedConnection = streamedConnection;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,0BACd,SACA,qBAC2B;CAC3B,IAAI,CAAC,SAAS,OAAO;CACrB,IAAI,CAAC,qBAAqB,OAAO;CACjC,IAAI,oBAAoB,iBAAiB,QAAQ,cAAc,OAAO;CACtE,IAAI,oBAAoB,iBAAiB,QAAQ,eAC/C,OAAO;CACT,OAAO;AACT;;;;;;;;;;;;;;;;;AAwBA,SAAgB,qBACd,UACA,OACM;CAGN,MAAM,aAAa,MAAM,OAAO,WAAW;CAC3C,MAAM,gBAAgB,SAAS,QAAQ,MAAM,EAAE,SAAS,OAAO;CAE/D,MAAM,QAAQ,KAAK,IAAI,WAAW,QAAQ,cAAc,MAAM;CAC9D,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK;EAC9B,MAAM,aAAc,WAAW,EAAE,CAAC,mBAC9B;EACJ,IAAI,CAAC,MAAM,QAAQ,UAAU,KAAK,WAAW,WAAW,GAAG;EAE3D,MAAM,UAAU,cAAc;EAC9B,MAAM,qBAAqB,IAAI,IAC7B,QAAQ,MACL,KAAK,MAAM,EAAE,gBAAgB,CAAC,CAC9B,QAAQ,MAAmB,KAAK,QAAQ,MAAM,EAAE,CACrD;EACA,MAAM,sBAAsB,WAAW,QACpC,MAAmB,KAAK,QAAQ,MAAM,MAAM,CAAC,mBAAmB,IAAI,CAAC,CACxE;EAEA,IAAI,SAAS;EACb,KAAK,MAAM,QAAQ,QAAQ,OACzB,IACE,kBAAkB,SACjB,KAAK,oBAAoB,QAAQ,KAAK,qBAAqB,OAC5D,SAAS,oBAAoB,QAC7B;GACA,KAAK,mBAAmB,oBAAoB;GAC5C;EACF;CAEJ;AACF;AAEA,IAAM,uBAAN,cAAmC,eAAsC;CACvE;CAEA,MAAM,WACJ,OACA,YACkB;EAClB,MAAM,gBAAiB,MAAM,MAAM,WACjC,OACA,UACF;EACA,IAAI,cAAc,kBAAkB,gBAAgB,mBAAmB,IAAI;GAEzE,IACE,cAAc,iBAAiB,eAAe,oBAAoB,OAElE,cAAc,iBAAiB,eAAe,kBAAkB;GAElE,OAAO,cAAc,iBAAiB,eAAe;EACvD;EACA,IAAI,KAAK,gBAAgB,iBAAiB,MAAM;GAC9C,cAAc,qBAAqB,CAAC;GAGpC,MAAM,EAAE,gBAAgB,GAAG,GAAG,2BAC3B,cAAc,iBAAiB,kBAEd,CAAC;GACrB,cACgB,iBACd,iBAAiB;IACjB,GAAG;IACH,eAAe,KAAK,eAAe;IACnC,GAAI,KAAK,eAAe,mBAAmB,QAAQ,EACjD,iBAAiB,KAAK,eAAe,gBACvC;GACF;EACF;EACA,IAAI,cAAc,UAAU;GAC1B,qBAAqB,cAAc,UAAU,KAAK;GAElD,KAAK,MAAM,WAAW,cAAc,UAClC,IAAI,QAAQ,SAAS,YACnB,QAA8B,OAAO;EAG3C;EACA,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4RA,IAAa,eAAb,cAAkC,WAAW;CAC3C,eAAe;EAAC;EAAa;EAAe;CAAU;CACtD,wBAAwB;CACxB;CAEA,OAAO,UAA+B;EACpC,OAAO;CACT;CAIA,YACE,eACA,QACA;EACA,MAAM,SACJ,OAAO,kBAAkB,WACrB;GAAE,GAAI,UAAU,CAAC;GAAI,OAAO;EAAc,IAC1C;EACN,MAAM,wBAAwB,QAAQ,mBAAmB;EACzD,MAAM;GACJ,GAAG;GACH,cAAc;EAChB,CAAC;EACD,KAAK,wBAAwB;EAC7B,KAAK,iBAAiB,QAAQ;CAChC;CACA,iBACE,SAC4B;EAC5B,MAAM,SAAS,MAAM,iBAAiB,OAAO;EAC7C,IAAI,KAAK,uBACP,OAAO,qBAAqB;EAE9B,OAAO;CACT;CACA,OAAO,sBACL,UACA,SACA,YACqC;EACrC,IAAI;EACJ,WAAW,MAAM,SAAS,MAAM,sBAC9B,UACA,SACA,UACF,GAAG;GACD,MAAM,WACJ,MAAM,gBACL;GACH,IAAI,UACF,gBAAgB;GAElB,IAAI,MAAM,mBAAmB,gBAAgB;IAC3C,MAAM,WAAW,0BACf,MAAM,QAAQ,gBACd,aACF;IACA,IAAI,aAAa,MAAM,QAAQ,gBAC7B,MAAM,QAAQ,iBAAiB;GAEnC;GACA,MAAM;EACR;CACF;CACA,gBACE,QACA,QACM;EAGN,MAAM,iBAAiB,QAAQ,kBAAkB,KAAK;EAEtD,MAAM,aAAa,IAAI,qBACrB;GAAE,GAAG;GAAQ,GAAG;EAAK,GACrB,KAAK,QACL,QACA,KACF;EACA,WAAW,iBAAiB;EAC5B,KAAK,aAAa;EAElB,MAAM,qBAAqB,IAAI,qBAC7B;GAAE,GAAG;GAAQ,GAAG;EAAK,GACrB,KAAK,QACL,QACA,IACF;EACA,mBAAmB,iBAAiB;EACpC,KAAK,qBAAqB;CAC5B;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/llm/vertexai/index.ts"],"sourcesContent":["import { ChatGoogle } from '@langchain/google-gauth';\nimport { ChatConnection } from '@langchain/google-common';\nimport { AIMessageChunk, isAIMessage } from '@langchain/core/messages';\nimport type {\n GeminiContent,\n GeminiRequest,\n GoogleAIModelRequestParams,\n GoogleAbstractedClient,\n} from '@langchain/google-common';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { BaseMessage, UsageMetadata } from '@langchain/core/messages';\nimport type { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { GoogleThinkingConfig, VertexAIClientOptions } from '@/types';\nimport {\n STREAMED_TOOL_CALL_SEAL_METADATA_KEY,\n STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY,\n GOOGLE_STREAMED_TOOL_CALL_ADAPTER,\n} from '@/tools/streamedToolCallSeals';\n\n/**\n * `@langchain/google-common`'s `_streamResponseChunks` emits usage on TWO\n * different paths within the same stream:\n *\n * - Streaming chunks set `chunk.generationInfo.usage_metadata` via\n * `responseToUsageMetadata`, which correctly sums\n * `candidatesTokenCount + thoughtsTokenCount` and includes\n * `output_token_details.reasoning`.\n * - The trailing fallback chunk (emitted after the API stream exhausts)\n * attaches its own `chunk.message.usage_metadata` built inline as\n * `output_tokens = candidatesTokenCount` only — dropping\n * `thoughtsTokenCount` and `output_token_details` entirely.\n *\n * After `AIMessageChunk.concat`, only `message.usage_metadata` survives —\n * which is the buggy fallback value. This breaks the documented\n * `total_tokens === input_tokens + output_tokens` invariant and silently\n * undercharges thinking models for reasoning tokens.\n *\n * The repair: track the last `generationInfo.usage_metadata` we see, and\n * when the fallback chunk arrives with its buggy `message.usage_metadata`,\n * replace it with the tracked good value. `CustomChatGoogleGenerativeAI`\n * solves the same problem for the Google API path differently — by\n * overriding `_convertToUsageMetadata`.\n */\nexport function repairStreamUsageMetadata(\n current: UsageMetadata | undefined,\n generationInfoUsage: UsageMetadata | undefined\n): UsageMetadata | undefined {\n if (!current) return current;\n if (!generationInfoUsage) return current;\n if (generationInfoUsage.total_tokens !== current.total_tokens) return current;\n if (generationInfoUsage.output_tokens <= current.output_tokens)\n return current;\n return generationInfoUsage;\n}\n\n/**\n * The Gemini API delivers function calls as complete objects — never as\n * partial arg deltas. `@langchain/google-common` pre-parses each streamed\n * functionCall part into `tool_calls` (invalid args land in\n * `invalid_tool_calls` instead), so a chunk whose tool-call chunks all parsed\n * cleanly is sealed on arrival for eager tool execution. Anything that fails\n * the parse check is left unstamped and falls back to the lazy path.\n */\nexport function sealCompleteStreamedToolCalls(message: AIMessageChunk): void {\n const chunkCount = message.tool_call_chunks?.length ?? 0;\n if (\n chunkCount === 0 ||\n (message.invalid_tool_calls?.length ?? 0) > 0 ||\n (message.tool_calls?.length ?? 0) !== chunkCount\n ) {\n return;\n }\n message.response_metadata = {\n ...message.response_metadata,\n [STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY]:\n GOOGLE_STREAMED_TOOL_CALL_ADAPTER,\n [STREAMED_TOOL_CALL_SEAL_METADATA_KEY]: { kind: 'all' },\n };\n}\n\ntype AdditionalKwargs =\n | undefined\n | (BaseMessage['additional_kwargs'] & {\n signatures?: Array<string | undefined>;\n });\n\n/**\n * Fixes thought signatures on functionCall parts in the formatted Gemini request.\n *\n * `@langchain/google-common` stores signatures as a flat array in\n * `additional_kwargs.signatures` (one per response part) and re-attaches them\n * by index only when `signatures.length === parts.length`. This fails when:\n * - The API omits a signature (length mismatch)\n * - Streaming chunks merge with different part counts\n * - The signature for a functionCall part is an empty string\n *\n * This function correlates each \"model\" content block in the formatted request\n * back to its originating AI message by *position*, then re-attaches non-empty\n * signatures that the library failed to apply. AI messages without signatures\n * still consume their slot — filtering them out shifted later messages onto\n * the wrong content block and dropped real signatures on the floor.\n */\nexport function fixThoughtSignatures(\n contents: GeminiContent[],\n input: BaseMessage[]\n): void {\n // All AI messages, in order — non-signature ones still consume positional\n // slots so later messages line up with their model content blocks.\n const aiMessages = input.filter(isAIMessage);\n const modelContents = contents.filter((c) => c.role === 'model');\n\n const count = Math.min(aiMessages.length, modelContents.length);\n for (let i = 0; i < count; i++) {\n const signatures = (aiMessages[i].additional_kwargs as AdditionalKwargs)\n ?.signatures;\n if (!Array.isArray(signatures) || signatures.length === 0) continue;\n\n const content = modelContents[i];\n const attachedSignatures = new Set(\n content.parts\n .map((p) => p.thoughtSignature)\n .filter((s): s is string => s != null && s !== '')\n );\n const availableSignatures = signatures.filter(\n (s): s is string => s != null && s !== '' && !attachedSignatures.has(s)\n );\n\n let sigIdx = 0;\n for (const part of content.parts) {\n if (\n 'functionCall' in part &&\n (part.thoughtSignature == null || part.thoughtSignature === '') &&\n sigIdx < availableSignatures.length\n ) {\n part.thoughtSignature = availableSignatures[sigIdx];\n sigIdx++;\n }\n }\n }\n}\n\nclass CustomChatConnection extends ChatConnection<VertexAIClientOptions> {\n thinkingConfig?: GoogleThinkingConfig;\n\n async formatData(\n input: BaseMessage[],\n parameters: GoogleAIModelRequestParams\n ): Promise<unknown> {\n const formattedData = (await super.formatData(\n input,\n parameters\n )) as GeminiRequest;\n if (formattedData.generationConfig?.thinkingConfig?.thinkingBudget === -1) {\n // -1 means \"let the model decide\" - delete the property so the API doesn't receive an invalid value\n if (\n formattedData.generationConfig.thinkingConfig.includeThoughts === false\n ) {\n formattedData.generationConfig.thinkingConfig.includeThoughts = true;\n }\n delete formattedData.generationConfig.thinkingConfig.thinkingBudget;\n }\n if (this.thinkingConfig?.thinkingLevel != null) {\n formattedData.generationConfig ??= {};\n // thinkingLevel and thinkingBudget cannot coexist — the API rejects the request.\n // Remove thinkingBudget when thinkingLevel is set.\n const { thinkingBudget: _, ...existingThinkingConfig } =\n (formattedData.generationConfig.thinkingConfig as\n | Record<string, unknown>\n | undefined) ?? {};\n (\n formattedData.generationConfig as Record<string, unknown>\n ).thinkingConfig = {\n ...existingThinkingConfig,\n thinkingLevel: this.thinkingConfig.thinkingLevel,\n ...(this.thinkingConfig.includeThoughts != null && {\n includeThoughts: this.thinkingConfig.includeThoughts,\n }),\n };\n }\n if (formattedData.contents) {\n fixThoughtSignatures(formattedData.contents, input);\n // gemini-3.1+ models reject role=\"function\"; convert to role=\"user\"\n for (const content of formattedData.contents) {\n if (content.role === 'function') {\n (content as { role: string }).role = 'user';\n }\n }\n }\n return formattedData;\n }\n}\n\n/**\n * Integration with Google Vertex AI chat models.\n *\n * Setup:\n * Install `@langchain/google-vertexai` and set your stringified\n * Vertex AI credentials as an environment variable named `GOOGLE_APPLICATION_CREDENTIALS`.\n *\n * ```bash\n * npm install @langchain/google-vertexai\n * export GOOGLE_APPLICATION_CREDENTIALS=\"path/to/credentials\"\n * ```\n *\n * ## [Constructor args](https://api.js.langchain.com/classes/_langchain_google_vertexai.index.ChatVertexAI.html#constructor.new_ChatVertexAI)\n *\n * ## [Runtime args](https://api.js.langchain.com/interfaces/langchain_google_common_types.GoogleAIBaseLanguageModelCallOptions.html)\n *\n * Runtime args can be passed as the second argument to any of the base runnable methods `.invoke`. `.stream`, `.batch`, etc.\n * They can also be passed via `.withConfig`, or the second arg in `.bindTools`, like shown in the examples below:\n *\n * ```typescript\n * // When calling `.withConfig`, call options should be passed via the first argument\n * const llmWithArgsBound = llm.withConfig({\n * stop: [\"\\n\"],\n * tools: [...],\n * });\n *\n * // When calling `.bindTools`, call options should be passed via the second argument\n * const llmWithTools = llm.bindTools(\n * [...],\n * {\n * tool_choice: \"auto\",\n * }\n * );\n * ```\n *\n * ## Examples\n *\n * <details open>\n * <summary><strong>Instantiate</strong></summary>\n *\n * ```typescript\n * import { ChatVertexAI } from '@langchain/google-vertexai';\n *\n * const llm = new ChatVertexAI({\n * model: \"gemini-1.5-pro\",\n * temperature: 0,\n * // other params...\n * });\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Invoking</strong></summary>\n *\n * ```typescript\n * const input = `Translate \"I love programming\" into French.`;\n *\n * // Models also accept a list of chat messages or a formatted prompt\n * const result = await llm.invoke(input);\n * console.log(result);\n * ```\n *\n * ```txt\n * AIMessageChunk {\n * \"content\": \"\\\"J'adore programmer\\\" \\n\\nHere's why this is the best translation:\\n\\n* **J'adore** means \\\"I love\\\" and conveys a strong passion.\\n* **Programmer** is the French verb for \\\"to program.\\\"\\n\\nThis translation is natural and idiomatic in French. \\n\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {},\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": [],\n * \"usage_metadata\": {\n * \"input_tokens\": 9,\n * \"output_tokens\": 63,\n * \"total_tokens\": 72\n * }\n * }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Streaming Chunks</strong></summary>\n *\n * ```typescript\n * for await (const chunk of await llm.stream(input)) {\n * console.log(chunk);\n * }\n * ```\n *\n * ```txt\n * AIMessageChunk {\n * \"content\": \"\\\"\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {},\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": []\n * }\n * AIMessageChunk {\n * \"content\": \"J'adore programmer\\\" \\n\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {},\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": []\n * }\n * AIMessageChunk {\n * \"content\": \"\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {},\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": []\n * }\n * AIMessageChunk {\n * \"content\": \"\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {\n * \"finishReason\": \"stop\"\n * },\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": [],\n * \"usage_metadata\": {\n * \"input_tokens\": 9,\n * \"output_tokens\": 8,\n * \"total_tokens\": 17\n * }\n * }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Aggregate Streamed Chunks</strong></summary>\n *\n * ```typescript\n * import { AIMessageChunk } from '@langchain/core/messages';\n * import { concat } from '@langchain/core/utils/stream';\n *\n * const stream = await llm.stream(input);\n * let full: AIMessageChunk | undefined;\n * for await (const chunk of stream) {\n * full = !full ? chunk : concat(full, chunk);\n * }\n * console.log(full);\n * ```\n *\n * ```txt\n * AIMessageChunk {\n * \"content\": \"\\\"J'adore programmer\\\" \\n\",\n * \"additional_kwargs\": {},\n * \"response_metadata\": {\n * \"finishReason\": \"stop\"\n * },\n * \"tool_calls\": [],\n * \"tool_call_chunks\": [],\n * \"invalid_tool_calls\": [],\n * \"usage_metadata\": {\n * \"input_tokens\": 9,\n * \"output_tokens\": 8,\n * \"total_tokens\": 17\n * }\n * }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Bind tools</strong></summary>\n *\n * ```typescript\n * import { z } from 'zod';\n *\n * const GetWeather = {\n * name: \"GetWeather\",\n * description: \"Get the current weather in a given location\",\n * schema: z.object({\n * location: z.string().describe(\"The city and state, e.g. San Francisco, CA\")\n * }),\n * }\n *\n * const GetPopulation = {\n * name: \"GetPopulation\",\n * description: \"Get the current population in a given location\",\n * schema: z.object({\n * location: z.string().describe(\"The city and state, e.g. San Francisco, CA\")\n * }),\n * }\n *\n * const llmWithTools = llm.bindTools([GetWeather, GetPopulation]);\n * const aiMsg = await llmWithTools.invoke(\n * \"Which city is hotter today and which is bigger: LA or NY?\"\n * );\n * console.log(aiMsg.tool_calls);\n * ```\n *\n * ```txt\n * [\n * {\n * name: 'GetPopulation',\n * args: { location: 'New York City, NY' },\n * id: '33c1c1f47e2f492799c77d2800a43912',\n * type: 'tool_call'\n * }\n * ]\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Structured Output</strong></summary>\n *\n * ```typescript\n * import { z } from 'zod';\n *\n * const Joke = z.object({\n * setup: z.string().describe(\"The setup of the joke\"),\n * punchline: z.string().describe(\"The punchline to the joke\"),\n * rating: z.number().optional().describe(\"How funny the joke is, from 1 to 10\")\n * }).describe('Joke to tell user.');\n *\n * const structuredLlm = llm.withStructuredOutput(Joke, { name: \"Joke\" });\n * const jokeResult = await structuredLlm.invoke(\"Tell me a joke about cats\");\n * console.log(jokeResult);\n * ```\n *\n * ```txt\n * {\n * setup: 'What do you call a cat that loves to bowl?',\n * punchline: 'An alley cat!'\n * }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Usage Metadata</strong></summary>\n *\n * ```typescript\n * const aiMsgForMetadata = await llm.invoke(input);\n * console.log(aiMsgForMetadata.usage_metadata);\n * ```\n *\n * ```txt\n * { input_tokens: 9, output_tokens: 8, total_tokens: 17 }\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Stream Usage Metadata</strong></summary>\n *\n * ```typescript\n * const streamForMetadata = await llm.stream(\n * input,\n * {\n * streamUsage: true\n * }\n * );\n * let fullForMetadata: AIMessageChunk | undefined;\n * for await (const chunk of streamForMetadata) {\n * fullForMetadata = !fullForMetadata ? chunk : concat(fullForMetadata, chunk);\n * }\n * console.log(fullForMetadata?.usage_metadata);\n * ```\n *\n * ```txt\n * { input_tokens: 9, output_tokens: 8, total_tokens: 17 }\n * ```\n * </details>\n *\n * <br />\n */\nexport class ChatVertexAI extends ChatGoogle {\n lc_namespace = ['langchain', 'chat_models', 'vertexai'];\n dynamicThinkingBudget = false;\n thinkingConfig?: GoogleThinkingConfig;\n\n static lc_name(): 'LibreChatVertexAI' {\n return 'LibreChatVertexAI';\n }\n\n constructor(model: string, fields?: Omit<VertexAIClientOptions, 'model'>);\n constructor(fields?: VertexAIClientOptions);\n constructor(\n modelOrFields?: string | VertexAIClientOptions,\n params?: Omit<VertexAIClientOptions, 'model'>\n ) {\n const fields =\n typeof modelOrFields === 'string'\n ? { ...(params ?? {}), model: modelOrFields }\n : modelOrFields;\n const dynamicThinkingBudget = fields?.thinkingBudget === -1;\n super({\n ...fields,\n platformType: 'gcp',\n });\n this.dynamicThinkingBudget = dynamicThinkingBudget;\n this.thinkingConfig = fields?.thinkingConfig;\n }\n invocationParams(\n options?: this['ParsedCallOptions'] | undefined\n ): GoogleAIModelRequestParams {\n const params = super.invocationParams(options);\n if (this.dynamicThinkingBudget) {\n params.maxReasoningTokens = -1;\n }\n return params;\n }\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n let lastGoodUsage: UsageMetadata | undefined;\n for await (const chunk of super._streamResponseChunks(\n messages,\n options,\n runManager\n )) {\n const genUsage = (\n chunk.generationInfo as { usage_metadata?: UsageMetadata } | undefined\n )?.usage_metadata;\n if (genUsage) {\n lastGoodUsage = genUsage;\n }\n if (chunk.message instanceof AIMessageChunk) {\n const repaired = repairStreamUsageMetadata(\n chunk.message.usage_metadata,\n lastGoodUsage\n );\n if (repaired !== chunk.message.usage_metadata) {\n chunk.message.usage_metadata = repaired;\n }\n sealCompleteStreamedToolCalls(chunk.message);\n }\n yield chunk;\n }\n }\n buildConnection(\n fields: VertexAIClientOptions | undefined,\n client: GoogleAbstractedClient\n ): void {\n // Note: buildConnection is called from super() BEFORE this.thinkingConfig is set,\n // so we must read thinkingConfig from `fields` directly.\n const thinkingConfig = fields?.thinkingConfig ?? this.thinkingConfig;\n\n const connection = new CustomChatConnection(\n { ...fields, ...this },\n this.caller,\n client,\n false\n );\n connection.thinkingConfig = thinkingConfig;\n this.connection = connection;\n\n const streamedConnection = new CustomChatConnection(\n { ...fields, ...this },\n this.caller,\n client,\n true\n );\n streamedConnection.thinkingConfig = thinkingConfig;\n this.streamedConnection = streamedConnection;\n }\n}\n"],"mappings":"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"}
package/dist/esm/main.mjs CHANGED
@@ -2,7 +2,7 @@ import { isPresent, unescapeObject } from "./utils/misc.mjs";
2
2
  import { ANTHROPIC_TOOL_TOKEN_MULTIPLIER, DEFAULT_TOOL_TOKEN_MULTIPLIER } from "./common/constants.mjs";
3
3
  import { CODE_EXECUTION_TOOLS, Callback, CommonEvents, Constants, ContentTypes, EnvVar, GraphEvents, GraphNodeActions, GraphNodeKeys, LOCAL_CODING_BUNDLE_NAMES, LOCAL_CODING_TOOL_NAMES, Providers, StepTypes, TitleMethod, ToolCallTypes } from "./common/enum.mjs";
4
4
  import "./common/index.mjs";
5
- import { TokenEncoderManager, createTokenCounter, encodingForModel, estimateAnthropicImageTokens, estimateOpenAIImageTokens, extractImageDimensions, getTokenCountForMessage } from "./utils/tokens.mjs";
5
+ import { TokenEncoderManager, apportionTokenCounts, createTokenCounter, encodingForModel, estimateAnthropicImageTokens, estimateOpenAIImageTokens, extractImageDimensions, getTokenCountForMessage } from "./utils/tokens.mjs";
6
6
  import { convertMessagesToContent, findLastIndex, formatAnthropicArtifactContent, formatAnthropicMessage, formatArtifactPayload, getConverseOverrideMessage, modifyDeltaProperties } from "./messages/core.mjs";
7
7
  import { getMessageId } from "./messages/ids.mjs";
8
8
  import { HARD_MAX_TOOL_RESULT_CHARS, HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE, calculateMaxToolResultChars, calculateMaxTotalToolOutputSize, truncateToolInput, truncateToolResultContent } from "./utils/truncation.mjs";
@@ -12,7 +12,7 @@ import { DEFAULT_RESERVE_RATIO, ORIGINAL_CONTENT_MAX_CHARS, calculateTotalTokens
12
12
  import { ensureThinkingBlockInMessages, formatAgentMessages, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, labelContentByAgent, shiftIndexTokenCountMap, withMessageRole } from "./messages/format.mjs";
13
13
  import { addBedrockCacheControl, addCacheControl, addCacheControlToStablePrefixMessages, stripAnthropicCacheControl, stripBedrockCacheControl } from "./messages/cache.mjs";
14
14
  import { makeIsDeferred, partitionAndMarkAnthropicToolCache } from "./messages/anthropicToolCache.mjs";
15
- import { formatContentStrings } from "./messages/content.mjs";
15
+ import { formatContentStrings, isLegacyConvertible } from "./messages/content.mjs";
16
16
  import { extractToolDiscoveries, hasToolSearchInCurrentTurn } from "./messages/tools.mjs";
17
17
  import { REMOVE_ALL_MESSAGES, createRemoveAllMessage, messagesStateReducer } from "./messages/reducer.mjs";
18
18
  import { splitAtRecencyBoundary } from "./messages/recency.mjs";
@@ -96,4 +96,4 @@ import { Runnable, RunnableLambda, RunnableSequence } from "./langchain/runnable
96
96
  import { DynamicStructuredTool, StructuredTool, Tool, tool } from "./langchain/tools.mjs";
97
97
  import "./langchain/index.mjs";
98
98
  import { BaseCheckpointSaver, Command, INTERRUPT, MemorySaver, interrupt, isInterrupted } from "@langchain/langgraph";
99
- export { AIMessage, AIMessageChunk, ANTHROPIC_TOOL_TOKEN_MULTIPLIER, AgentSession, BASH_SHELL_GUIDANCE, BaseCheckpointSaver, BaseMessage, BaseMessageChunk, BashExecutionToolDefinition, BashExecutionToolDescription, BashExecutionToolName, BashExecutionToolSchema, BashProgrammaticToolCallingDefinition, BashProgrammaticToolCallingDescription, BashProgrammaticToolCallingName, BashProgrammaticToolCallingSchema, BashToolOutputReferencesGuide, CLOUDFLARE_BASH_CODING_TOOL_NAMES, CLOUDFLARE_CODING_TOOL_NAMES, CODE_ARTIFACT_PATH_GUIDANCE, CODE_EXECUTION_TOOLS, Calculator, CalculatorSchema, CalculatorToolDefinition, CalculatorToolDescription, CalculatorToolName, Callback, ChatModelStreamHandler, ChatOpenRouter, CloudflareBashExecutionToolDescription, CloudflareCodeExecutionToolDescription, CodeExecutionToolDefinition, CodeExecutionToolDescription, CodeExecutionToolName, CodeExecutionToolSchema, Command, CommonEvents, CompileCheckToolName, Constants, ContentTypes, CustomOpenAIClient, DATE_RANGE, DEFAULT_CONTEXT_PRUNING_SETTINGS, DEFAULT_COUNTRY_DESCRIPTION, DEFAULT_HOOK_TIMEOUT_MS, DEFAULT_QUERY_DESCRIPTION, DEFAULT_RESERVE_RATIO, DEFAULT_TOOL_TOKEN_MULTIPLIER, DynamicStructuredTool, EnvVar, FAILED_EXECUTION_FILE_REMINDER, FakeChatModel, Graph, GraphEvents, GraphNodeActions, GraphNodeKeys, HARD_MAX_TOOL_RESULT_CHARS, HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE, HOOK_EVENTS, HandlerRegistry, HookRegistry, HumanMessage, INTERRUPT, JsonlSessionStore, LLMStreamHandler, LOCAL_CODING_BUNDLE_NAMES, LOCAL_CODING_TOOL_NAMES, LOCAL_SPAWN_TIMEOUT_MS, LocalBashExecutionToolDescription, LocalCodeExecutionToolDescription, LocalEditFileToolName, LocalEditFileToolSchema, LocalFileCheckpointerImpl, LocalGlobSearchToolName, LocalGlobSearchToolSchema, LocalGrepSearchToolName, LocalGrepSearchToolSchema, LocalListDirectoryToolName, LocalListDirectoryToolSchema, LocalReadFileToolSchema, LocalWriteFileToolName, LocalWriteFileToolSchema, MAX_CACHE_SIZE, MAX_PATTERN_LENGTH, MemorySaver, ModelEndHandler, MultiAgentGraph, ORIGINAL_CONTENT_MAX_CHARS, ProgrammaticToolCallingDefinition, ProgrammaticToolCallingDescription, ProgrammaticToolCallingName, ProgrammaticToolCallingSchema, PromptTemplate, Providers, REMOVE_ALL_MESSAGES, ReadFileToolDefinition, ReadFileToolDescription, ReadFileToolName, ReadFileToolSchema, Run, Runnable, RunnableCallable, RunnableLambda, RunnableSequence, SEPARATORS, SessionManager, SkillToolDefinition, SkillToolDescription, SkillToolName, SkillToolSchema, SplitStreamHandler, StandardGraph, StepTypes, StructuredTool, SubagentExecutor, SubagentToolDefinition, SubagentToolDescription, SubagentToolName, SubagentToolSchema, SystemMessage, TMP_SCRATCH_OUTPUT_REMINDER, TestChatStreamHandler, TestLLMStreamHandler, TitleMethod, TokenEncoderManager, Tool, ToolCallTypes, ToolEndHandler, ToolMessage, ToolNode, ToolSearchToolDefinition, ToolSearchToolDescription, ToolSearchToolName, ToolSearchToolSchema, WebSearchToolDefinition, WebSearchToolDescription, WebSearchToolName, WebSearchToolSchema, _createBashProgramForTests, _resetLocalEngineWarningsForTests, _resetRipgrepCacheForTests, _resetSyntaxCheckProbeCacheForTests, _resetUnrecognizedTriggerWarnings, addBedrockCacheControl, addCacheControl, addCacheControlToStablePrefixMessages, appendCodeSessionFileSummary, appendFailedExecutionFileReminder, appendTmpScratchReminder, applyContextPruning, applyEdit, applyPreToolUseHooksForBridge, askUserQuestion, attemptInvoke, bashAstFindingsToErrors, buildBashExecutionToolDescription, buildChildInputs, buildCodeApiHttpErrorMessage, buildSandboxRuntimeConfig, buildSubagentToolParams, calculateMaxToolResultChars, calculateMaxTotalToolOutputSize, calculateTotalTokens, checkValidNumber, classifyAttachment, composeEventHandlers, convertMessagesToContent, countNestedGroups, countrySchema, createAgentSession, createBashExecutionTool, createBashProgrammaticToolCallingSchema, createBashProgrammaticToolCallingTool, createCloudflareBashExecutionTool, createCloudflareBashProgrammaticToolCallingTool, createCloudflareBridgeRuntime, createCloudflareCodeExecutionTool, createCloudflareCodingToolBundle, createCloudflareCodingTools, createCloudflareExecutionTool, createCloudflareLocalExecutionConfig, createCloudflareProgrammaticToolCallingTool, createCloudflareWorkspaceFS, createCodeExecutionTool, createCompileCheckTool, createCompileCheckToolDefinition, createContentAggregator, createFakeStreamingLLM, createHandlers, createLocalBashExecutionTool, createLocalBashProgrammaticToolCallingTool, createLocalCodeExecutionTool, createLocalCodingToolBundle, createLocalCodingToolDefinitions, createLocalCodingToolRegistry, createLocalCodingTools, createLocalEditFileTool, createLocalFileCheckpointer, createLocalGlobSearchTool, createLocalGrepSearchTool, createLocalListDirectoryTool, createLocalProgrammaticToolCallingTool, createLocalReadFileTool, createLocalWriteFileTool, createMetadataAggregator, createProgrammaticToolCallingSchema, createProgrammaticToolCallingTool, createPruneMessages, createRemoveAllMessage, createRunHandlers, createSchemaOnlyTool, createSchemaOnlyTools, createSearchTool, createSubagentToolDefinition, createTokenCounter, createToolPolicyHook, createToolSearch, createWorkspacePolicyHook, dateSchema, decodeFile, defaultOmitOptions, deserializeMessage, emptyOutputMessage, encodeFile, encodingForModel, enforceOriginalContentCap, ensureThinkingBlockInMessages, escapeRegexSpecialChars, estimateAnthropicImageTokens, estimateOpenAIImageTokens, executeCloudflareBash, executeCloudflareCode, executeHooks, executeLocalBash, executeLocalBashWithArgs, executeLocalCode, executeParallelSearches, executeTools, extractErrorMessage, extractImageDimensions, extractMcpServerName, extractTextFromContent, extractToolDiscoveries, extractUsedBashToolNames, extractUsedToolNames, fetchSessionFiles, filterBashToolsByUsage, filterSubagentResult, filterToolsByUsage, findLastIndex, formatAgentMessages, formatAnthropicArtifactContent, formatAnthropicMessage, formatArtifactPayload, formatCloudflareOutput, formatCompletedResponse, formatContentStrings, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, formatServerListing, formatSkillCatalog, getAvailableMcpServers, getBaseToolName, getBufferString, getChatModelClass, getChunkContent, getCloudflareWorkspaceRoot, getCodeBaseURL, getConverseOverrideMessage, getDeferredToolsListing, getLocalCwd, getLocalSessionId, getMaxOutputTokensKey, getMessageId, getMessagesWithinTokenLimit, getReadRoots, getSpawn, getTokenCountForMessage, getWorkspaceFS, getWorkspaceRoots, getWriteRoots, handleServerToolResult, handleToolCallChunks, handleToolCalls, hasNestedQuantifier, hasNestedQuantifiers, hasToolSearchInCurrentTurn, imageAttachmentContent, imagesSchema, initializeModel, interrupt, isAIMessage, isAnthropicLike, isBaseMessage, isContextOverflowError, isDangerousPattern, isFromAnyMcpServer, isFromMcpServer, isGoogleLike, isInterrupted, isLikelyContextOverflowError, isOpenAILike, isPresent, isThinkingEnabled, isToolMessage, isZodSchema, joinKeys, labelContentByAgent, locateEdit, makeIsDeferred, makeRequest, maskConsumedToolResults, matchesQuery, messagesStateReducer, modifyDeltaProperties, newsSchema, normalizeBashToolResultsForReplay, normalizeServerFilter, normalizeToBashIdentifier, normalizeToPythonIdentifier, partitionAndMarkAnthropicToolCache, performLocalSearch, preFlightTruncateToolCallInputs, preFlightTruncateToolResults, querySchema, repairOrphanedToolMessages, resetIfNotEmpty, resolveCloudflareSandbox, resolveCodeApiAuthHeaders, resolveContextPruningSettings, resolveLocalExecutionConfig, resolveLocalExecutionTools, resolveLocalToolRegistry, resolveLocalToolsForBinding, resolveSubagentConfigs, resolveWorkspacePath, resolveWorkspacePathSafe, runBashAstChecks, runPostEditSyntaxCheck, sanitizeOrphanToolBlocks, sanitizeRegex, serializeMessage, shellQuote, shiftIndexTokenCountMap, shouldTriggerSummarization, sleep, spawnLocalProcess, splitAtRecencyBoundary, stripAnthropicCacheControl, stripBedrockCacheControl, stripCodeSessionFileSummary, summarizeEvent, toJsonSchema, tool, toolResultTypes, toolsCondition, truncateLocalOutput, truncateToolInput, truncateToolResultContent, tryFallbackProviders, unescapeObject, unwrapToolResponse, validateBashCommand, validateCloudflareBashCommand, videosSchema, withMessageRole };
99
+ export { AIMessage, AIMessageChunk, ANTHROPIC_TOOL_TOKEN_MULTIPLIER, AgentSession, BASH_SHELL_GUIDANCE, BaseCheckpointSaver, BaseMessage, BaseMessageChunk, BashExecutionToolDefinition, BashExecutionToolDescription, BashExecutionToolName, BashExecutionToolSchema, BashProgrammaticToolCallingDefinition, BashProgrammaticToolCallingDescription, BashProgrammaticToolCallingName, BashProgrammaticToolCallingSchema, BashToolOutputReferencesGuide, CLOUDFLARE_BASH_CODING_TOOL_NAMES, CLOUDFLARE_CODING_TOOL_NAMES, CODE_ARTIFACT_PATH_GUIDANCE, CODE_EXECUTION_TOOLS, Calculator, CalculatorSchema, CalculatorToolDefinition, CalculatorToolDescription, CalculatorToolName, Callback, ChatModelStreamHandler, ChatOpenRouter, CloudflareBashExecutionToolDescription, CloudflareCodeExecutionToolDescription, CodeExecutionToolDefinition, CodeExecutionToolDescription, CodeExecutionToolName, CodeExecutionToolSchema, Command, CommonEvents, CompileCheckToolName, Constants, ContentTypes, CustomOpenAIClient, DATE_RANGE, DEFAULT_CONTEXT_PRUNING_SETTINGS, DEFAULT_COUNTRY_DESCRIPTION, DEFAULT_HOOK_TIMEOUT_MS, DEFAULT_QUERY_DESCRIPTION, DEFAULT_RESERVE_RATIO, DEFAULT_TOOL_TOKEN_MULTIPLIER, DynamicStructuredTool, EnvVar, FAILED_EXECUTION_FILE_REMINDER, FakeChatModel, Graph, GraphEvents, GraphNodeActions, GraphNodeKeys, HARD_MAX_TOOL_RESULT_CHARS, HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE, HOOK_EVENTS, HandlerRegistry, HookRegistry, HumanMessage, INTERRUPT, JsonlSessionStore, LLMStreamHandler, LOCAL_CODING_BUNDLE_NAMES, LOCAL_CODING_TOOL_NAMES, LOCAL_SPAWN_TIMEOUT_MS, LocalBashExecutionToolDescription, LocalCodeExecutionToolDescription, LocalEditFileToolName, LocalEditFileToolSchema, LocalFileCheckpointerImpl, LocalGlobSearchToolName, LocalGlobSearchToolSchema, LocalGrepSearchToolName, LocalGrepSearchToolSchema, LocalListDirectoryToolName, LocalListDirectoryToolSchema, LocalReadFileToolSchema, LocalWriteFileToolName, LocalWriteFileToolSchema, MAX_CACHE_SIZE, MAX_PATTERN_LENGTH, MemorySaver, ModelEndHandler, MultiAgentGraph, ORIGINAL_CONTENT_MAX_CHARS, ProgrammaticToolCallingDefinition, ProgrammaticToolCallingDescription, ProgrammaticToolCallingName, ProgrammaticToolCallingSchema, PromptTemplate, Providers, REMOVE_ALL_MESSAGES, ReadFileToolDefinition, ReadFileToolDescription, ReadFileToolName, ReadFileToolSchema, Run, Runnable, RunnableCallable, RunnableLambda, RunnableSequence, SEPARATORS, SessionManager, SkillToolDefinition, SkillToolDescription, SkillToolName, SkillToolSchema, SplitStreamHandler, StandardGraph, StepTypes, StructuredTool, SubagentExecutor, SubagentToolDefinition, SubagentToolDescription, SubagentToolName, SubagentToolSchema, SystemMessage, TMP_SCRATCH_OUTPUT_REMINDER, TestChatStreamHandler, TestLLMStreamHandler, TitleMethod, TokenEncoderManager, Tool, ToolCallTypes, ToolEndHandler, ToolMessage, ToolNode, ToolSearchToolDefinition, ToolSearchToolDescription, ToolSearchToolName, ToolSearchToolSchema, WebSearchToolDefinition, WebSearchToolDescription, WebSearchToolName, WebSearchToolSchema, _createBashProgramForTests, _resetLocalEngineWarningsForTests, _resetRipgrepCacheForTests, _resetSyntaxCheckProbeCacheForTests, _resetUnrecognizedTriggerWarnings, addBedrockCacheControl, addCacheControl, addCacheControlToStablePrefixMessages, appendCodeSessionFileSummary, appendFailedExecutionFileReminder, appendTmpScratchReminder, applyContextPruning, applyEdit, applyPreToolUseHooksForBridge, apportionTokenCounts, askUserQuestion, attemptInvoke, bashAstFindingsToErrors, buildBashExecutionToolDescription, buildChildInputs, buildCodeApiHttpErrorMessage, buildSandboxRuntimeConfig, buildSubagentToolParams, calculateMaxToolResultChars, calculateMaxTotalToolOutputSize, calculateTotalTokens, checkValidNumber, classifyAttachment, composeEventHandlers, convertMessagesToContent, countNestedGroups, countrySchema, createAgentSession, createBashExecutionTool, createBashProgrammaticToolCallingSchema, createBashProgrammaticToolCallingTool, createCloudflareBashExecutionTool, createCloudflareBashProgrammaticToolCallingTool, createCloudflareBridgeRuntime, createCloudflareCodeExecutionTool, createCloudflareCodingToolBundle, createCloudflareCodingTools, createCloudflareExecutionTool, createCloudflareLocalExecutionConfig, createCloudflareProgrammaticToolCallingTool, createCloudflareWorkspaceFS, createCodeExecutionTool, createCompileCheckTool, createCompileCheckToolDefinition, createContentAggregator, createFakeStreamingLLM, createHandlers, createLocalBashExecutionTool, createLocalBashProgrammaticToolCallingTool, createLocalCodeExecutionTool, createLocalCodingToolBundle, createLocalCodingToolDefinitions, createLocalCodingToolRegistry, createLocalCodingTools, createLocalEditFileTool, createLocalFileCheckpointer, createLocalGlobSearchTool, createLocalGrepSearchTool, createLocalListDirectoryTool, createLocalProgrammaticToolCallingTool, createLocalReadFileTool, createLocalWriteFileTool, createMetadataAggregator, createProgrammaticToolCallingSchema, createProgrammaticToolCallingTool, createPruneMessages, createRemoveAllMessage, createRunHandlers, createSchemaOnlyTool, createSchemaOnlyTools, createSearchTool, createSubagentToolDefinition, createTokenCounter, createToolPolicyHook, createToolSearch, createWorkspacePolicyHook, dateSchema, decodeFile, defaultOmitOptions, deserializeMessage, emptyOutputMessage, encodeFile, encodingForModel, enforceOriginalContentCap, ensureThinkingBlockInMessages, escapeRegexSpecialChars, estimateAnthropicImageTokens, estimateOpenAIImageTokens, executeCloudflareBash, executeCloudflareCode, executeHooks, executeLocalBash, executeLocalBashWithArgs, executeLocalCode, executeParallelSearches, executeTools, extractErrorMessage, extractImageDimensions, extractMcpServerName, extractTextFromContent, extractToolDiscoveries, extractUsedBashToolNames, extractUsedToolNames, fetchSessionFiles, filterBashToolsByUsage, filterSubagentResult, filterToolsByUsage, findLastIndex, formatAgentMessages, formatAnthropicArtifactContent, formatAnthropicMessage, formatArtifactPayload, formatCloudflareOutput, formatCompletedResponse, formatContentStrings, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, formatServerListing, formatSkillCatalog, getAvailableMcpServers, getBaseToolName, getBufferString, getChatModelClass, getChunkContent, getCloudflareWorkspaceRoot, getCodeBaseURL, getConverseOverrideMessage, getDeferredToolsListing, getLocalCwd, getLocalSessionId, getMaxOutputTokensKey, getMessageId, getMessagesWithinTokenLimit, getReadRoots, getSpawn, getTokenCountForMessage, getWorkspaceFS, getWorkspaceRoots, getWriteRoots, handleServerToolResult, handleToolCallChunks, handleToolCalls, hasNestedQuantifier, hasNestedQuantifiers, hasToolSearchInCurrentTurn, imageAttachmentContent, imagesSchema, initializeModel, interrupt, isAIMessage, isAnthropicLike, isBaseMessage, isContextOverflowError, isDangerousPattern, isFromAnyMcpServer, isFromMcpServer, isGoogleLike, isInterrupted, isLegacyConvertible, isLikelyContextOverflowError, isOpenAILike, isPresent, isThinkingEnabled, isToolMessage, isZodSchema, joinKeys, labelContentByAgent, locateEdit, makeIsDeferred, makeRequest, maskConsumedToolResults, matchesQuery, messagesStateReducer, modifyDeltaProperties, newsSchema, normalizeBashToolResultsForReplay, normalizeServerFilter, normalizeToBashIdentifier, normalizeToPythonIdentifier, partitionAndMarkAnthropicToolCache, performLocalSearch, preFlightTruncateToolCallInputs, preFlightTruncateToolResults, querySchema, repairOrphanedToolMessages, resetIfNotEmpty, resolveCloudflareSandbox, resolveCodeApiAuthHeaders, resolveContextPruningSettings, resolveLocalExecutionConfig, resolveLocalExecutionTools, resolveLocalToolRegistry, resolveLocalToolsForBinding, resolveSubagentConfigs, resolveWorkspacePath, resolveWorkspacePathSafe, runBashAstChecks, runPostEditSyntaxCheck, sanitizeOrphanToolBlocks, sanitizeRegex, serializeMessage, shellQuote, shiftIndexTokenCountMap, shouldTriggerSummarization, sleep, spawnLocalProcess, splitAtRecencyBoundary, stripAnthropicCacheControl, stripBedrockCacheControl, stripCodeSessionFileSummary, summarizeEvent, toJsonSchema, tool, toolResultTypes, toolsCondition, truncateLocalOutput, truncateToolInput, truncateToolResultContent, tryFallbackProviders, unescapeObject, unwrapToolResponse, validateBashCommand, validateCloudflareBashCommand, videosSchema, withMessageRole };
@@ -2,6 +2,16 @@ import "../common/enum.mjs";
2
2
  import "../common/index.mjs";
3
3
  //#region src/messages/content.ts
4
4
  /**
5
+ * Whether {@link formatContentStrings} will flatten this message's content:
6
+ * a human/ai/system message whose content is an array of text-only blocks.
7
+ */
8
+ const isLegacyConvertible = (message) => {
9
+ const messageType = message.getType();
10
+ if (!(messageType === "human" || messageType === "ai" || messageType === "system")) return false;
11
+ if (!Array.isArray(message.content)) return false;
12
+ return message.content.every((block) => block.type === "text");
13
+ };
14
+ /**
5
15
  * Formats an array of messages for LangChain, making sure all content fields are strings
6
16
  * @param {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} payload - The array of messages to format.
7
17
  * @returns {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} - The array of formatted LangChain messages, including ToolMessages for tool calls.
@@ -9,20 +19,7 @@ import "../common/index.mjs";
9
19
  const formatContentStrings = (payload) => {
10
20
  const result = [];
11
21
  for (const message of payload) {
12
- const messageType = message.getType();
13
- if (!(messageType === "human" || messageType === "ai" || messageType === "system")) {
14
- result.push(message);
15
- continue;
16
- }
17
- if (typeof message.content === "string") {
18
- result.push(message);
19
- continue;
20
- }
21
- if (!Array.isArray(message.content)) {
22
- result.push(message);
23
- continue;
24
- }
25
- if (!message.content.every((block) => block.type === "text")) {
22
+ if (!isLegacyConvertible(message)) {
26
23
  result.push(message);
27
24
  continue;
28
25
  }
@@ -35,6 +32,6 @@ const formatContentStrings = (payload) => {
35
32
  return result;
36
33
  };
37
34
  //#endregion
38
- export { formatContentStrings };
35
+ export { formatContentStrings, isLegacyConvertible };
39
36
 
40
37
  //# sourceMappingURL=content.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"content.mjs","names":[],"sources":["../../../src/messages/content.ts"],"sourcesContent":["import type { BaseMessage } from '@langchain/core/messages';\nimport { ContentTypes } from '@/common';\n\n/**\n * Formats an array of messages for LangChain, making sure all content fields are strings\n * @param {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} payload - The array of messages to format.\n * @returns {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} - The array of formatted LangChain messages, including ToolMessages for tool calls.\n */\nexport const formatContentStrings = (\n payload: Array<BaseMessage>\n): Array<BaseMessage> => {\n // Create a new array to store the processed messages\n const result: Array<BaseMessage> = [];\n\n for (const message of payload) {\n const messageType = message.getType();\n const isValidMessage =\n messageType === 'human' ||\n messageType === 'ai' ||\n messageType === 'system';\n\n if (!isValidMessage) {\n result.push(message);\n continue;\n }\n\n // If content is already a string, add as-is\n if (typeof message.content === 'string') {\n result.push(message);\n continue;\n }\n\n // If content is not an array, add as-is\n if (!Array.isArray(message.content)) {\n result.push(message);\n continue;\n }\n\n // Check if all content blocks are text type\n const allTextBlocks = message.content.every(\n (block) => block.type === ContentTypes.TEXT\n );\n\n // Only convert to string if all blocks are text type\n if (!allTextBlocks) {\n result.push(message);\n continue;\n }\n\n // Reduce text types to a single string\n const content = message.content.reduce((acc, curr) => {\n if (curr.type === ContentTypes.TEXT) {\n return `${acc}${curr[ContentTypes.TEXT] || ''}\\n`;\n }\n return acc;\n }, '');\n\n message.content = content.trim();\n result.push(message);\n }\n\n return result;\n};\n"],"mappings":";;;;;;;;AAQA,MAAa,wBACX,YACuB;CAEvB,MAAM,SAA6B,CAAC;CAEpC,KAAK,MAAM,WAAW,SAAS;EAC7B,MAAM,cAAc,QAAQ,QAAQ;EAMpC,IAAI,EAJF,gBAAgB,WAChB,gBAAgB,QAChB,gBAAgB,WAEG;GACnB,OAAO,KAAK,OAAO;GACnB;EACF;EAGA,IAAI,OAAO,QAAQ,YAAY,UAAU;GACvC,OAAO,KAAK,OAAO;GACnB;EACF;EAGA,IAAI,CAAC,MAAM,QAAQ,QAAQ,OAAO,GAAG;GACnC,OAAO,KAAK,OAAO;GACnB;EACF;EAQA,IAAI,CALkB,QAAQ,QAAQ,OACnC,UAAU,MAAM,SAAA,MAIF,GAAG;GAClB,OAAO,KAAK,OAAO;GACnB;EACF;EAUA,QAAQ,UAPQ,QAAQ,QAAQ,QAAQ,KAAK,SAAS;GACpD,IAAI,KAAK,SAAA,QACP,OAAO,GAAG,MAAM,KAAA,WAA2B,GAAG;GAEhD,OAAO;EACT,GAAG,EAEqB,CAAC,CAAC,KAAK;EAC/B,OAAO,KAAK,OAAO;CACrB;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"content.mjs","names":[],"sources":["../../../src/messages/content.ts"],"sourcesContent":["import type {\n BaseMessage,\n MessageContentComplex,\n} from '@langchain/core/messages';\nimport { ContentTypes } from '@/common';\n\n/**\n * Whether {@link formatContentStrings} will flatten this message's content:\n * a human/ai/system message whose content is an array of text-only blocks.\n */\nexport const isLegacyConvertible = (message: BaseMessage): boolean => {\n const messageType = message.getType();\n const isValidMessage =\n messageType === 'human' || messageType === 'ai' || messageType === 'system';\n if (!isValidMessage) {\n return false;\n }\n if (!Array.isArray(message.content)) {\n return false;\n }\n return message.content.every((block) => block.type === ContentTypes.TEXT);\n};\n\n/**\n * Formats an array of messages for LangChain, making sure all content fields are strings\n * @param {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} payload - The array of messages to format.\n * @returns {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} - The array of formatted LangChain messages, including ToolMessages for tool calls.\n */\nexport const formatContentStrings = (\n payload: Array<BaseMessage>\n): Array<BaseMessage> => {\n // Create a new array to store the processed messages\n const result: Array<BaseMessage> = [];\n\n for (const message of payload) {\n if (!isLegacyConvertible(message)) {\n result.push(message);\n continue;\n }\n\n // Reduce text types to a single string\n const blocks = message.content as MessageContentComplex[];\n const content = blocks.reduce((acc, curr) => {\n if (curr.type === ContentTypes.TEXT) {\n return `${acc}${curr[ContentTypes.TEXT] || ''}\\n`;\n }\n return acc;\n }, '');\n\n message.content = content.trim();\n result.push(message);\n }\n\n return result;\n};\n"],"mappings":";;;;;;;AAUA,MAAa,uBAAuB,YAAkC;CACpE,MAAM,cAAc,QAAQ,QAAQ;CAGpC,IAAI,EADF,gBAAgB,WAAW,gBAAgB,QAAQ,gBAAgB,WAEnE,OAAO;CAET,IAAI,CAAC,MAAM,QAAQ,QAAQ,OAAO,GAChC,OAAO;CAET,OAAO,QAAQ,QAAQ,OAAO,UAAU,MAAM,SAAA,MAA0B;AAC1E;;;;;;AAOA,MAAa,wBACX,YACuB;CAEvB,MAAM,SAA6B,CAAC;CAEpC,KAAK,MAAM,WAAW,SAAS;EAC7B,IAAI,CAAC,oBAAoB,OAAO,GAAG;GACjC,OAAO,KAAK,OAAO;GACnB;EACF;EAWA,QAAQ,UARO,QAAQ,QACA,QAAQ,KAAK,SAAS;GAC3C,IAAI,KAAK,SAAA,QACP,OAAO,GAAG,MAAM,KAAA,WAA2B,GAAG;GAEhD,OAAO;EACT,GAAG,EAEqB,CAAC,CAAC,KAAK;EAC/B,OAAO,KAAK,OAAO;CACrB;CAEA,OAAO;AACT"}
@@ -685,15 +685,24 @@ function createPruneMessages(factoryParams) {
685
685
  let originalToolContentSize = 0;
686
686
  const contextPruningSettings = resolveContextPruningSettings(factoryParams.contextPruningConfig);
687
687
  return function pruneMessages(params) {
688
- if (params.messages.length === 0) return {
689
- context: [],
690
- indexTokenCountMap,
691
- messagesToRefine: [],
692
- prePruneContextTokens: 0,
693
- remainingContextTokens: factoryParams.maxTokens,
694
- calibrationRatio,
695
- resolvedInstructionOverhead: bestInstructionOverhead
696
- };
688
+ if (params.messages.length === 0) {
689
+ /** Post-compaction calls still invoke the model — report the same
690
+ * reserve-adjusted budget fields as the populated paths */
691
+ const emptyInstructionTokens = factoryParams.getInstructionTokens?.() ?? 0;
692
+ const emptyReserveRatio = factoryParams.reserveRatio ?? .05;
693
+ const emptyBudget = factoryParams.maxTokens - (emptyReserveRatio > 0 && emptyReserveRatio < 1 ? Math.round(factoryParams.maxTokens * emptyReserveRatio) : 0);
694
+ return {
695
+ context: [],
696
+ indexTokenCountMap,
697
+ messagesToRefine: [],
698
+ prePruneContextTokens: 0,
699
+ remainingContextTokens: Math.max(0, emptyBudget - emptyInstructionTokens),
700
+ calibrationRatio,
701
+ resolvedInstructionOverhead: bestInstructionOverhead,
702
+ contextBudget: emptyBudget,
703
+ effectiveInstructionTokens: emptyInstructionTokens
704
+ };
705
+ }
697
706
  if (factoryParams.provider === "openAI" && factoryParams.thinkingEnabled === true) for (let i = lastTurnStartIndex; i < params.messages.length; i++) {
698
707
  const m = params.messages[i];
699
708
  if (m.getType() === "ai" && typeof m.additional_kwargs.reasoning_content === "string" && Array.isArray(m.additional_kwargs.provider_specific_fields?.thinking_blocks) && m.tool_calls && (m.tool_calls?.length ?? 0) > 0) {
@@ -799,7 +808,9 @@ function createPruneMessages(factoryParams) {
799
808
  remainingContextTokens: 0,
800
809
  contextPressure: pruningBudget > 0 ? calibratedTotalTokens / pruningBudget : 0,
801
810
  calibrationRatio,
802
- resolvedInstructionOverhead: bestInstructionOverhead
811
+ resolvedInstructionOverhead: bestInstructionOverhead,
812
+ contextBudget: pruningBudget,
813
+ effectiveInstructionTokens: currentInstructionTokens
803
814
  };
804
815
  }
805
816
  totalTokens = sumTokenCounts(indexTokenCountMap, params.messages.length);
@@ -892,7 +903,9 @@ function createPruneMessages(factoryParams) {
892
903
  contextPressure,
893
904
  originalToolContent: originalToolContent.size > 0 ? originalToolContent : void 0,
894
905
  calibrationRatio,
895
- resolvedInstructionOverhead: bestInstructionOverhead
906
+ resolvedInstructionOverhead: bestInstructionOverhead,
907
+ contextBudget: pruningBudget,
908
+ effectiveInstructionTokens: currentInstructionTokens
896
909
  };
897
910
  const rawSpaceBudget = calibrationRatio > 0 ? Math.round(pruningBudget / calibrationRatio) : pruningBudget;
898
911
  const rawSpaceInstructionTokens = calibrationRatio > 0 ? Math.round(currentInstructionTokens / calibrationRatio) : currentInstructionTokens;
@@ -1085,7 +1098,10 @@ function createPruneMessages(factoryParams) {
1085
1098
  for (const [key, value] of Object.entries(preEmergencyTokenCounts)) indexTokenCountMap[key] = value;
1086
1099
  }
1087
1100
  }
1088
- const remainingContextTokens = Math.max(0, Math.min(pruningBudget, initialRemainingContextTokens + reclaimedTokens));
1101
+ /** Scale raw-space remaining back to calibrated/provider units so it is
1102
+ * directly comparable with pruningBudget and prePruneContextTokens */
1103
+ const rawRemaining = Math.max(0, initialRemainingContextTokens + reclaimedTokens);
1104
+ const remainingContextTokens = Math.max(0, Math.min(pruningBudget, calibrationRatio > 0 ? Math.round(rawRemaining * calibrationRatio) : rawRemaining));
1089
1105
  runThinkingStartIndex = thinkingStartIndex ?? -1;
1090
1106
  /** The index is the first value of `context`, index relative to `params.messages` */
1091
1107
  lastCutOffIndex = Math.max(params.messages.length - (context.length - (context[0]?.getType() === "system" ? 1 : 0)), 0);
@@ -1098,7 +1114,9 @@ function createPruneMessages(factoryParams) {
1098
1114
  contextPressure,
1099
1115
  originalToolContent: originalToolContent.size > 0 ? originalToolContent : void 0,
1100
1116
  calibrationRatio,
1101
- resolvedInstructionOverhead: bestInstructionOverhead
1117
+ resolvedInstructionOverhead: bestInstructionOverhead,
1118
+ contextBudget: pruningBudget,
1119
+ effectiveInstructionTokens: currentInstructionTokens
1102
1120
  };
1103
1121
  };
1104
1122
  }