@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,6 +1,6 @@
1
1
  import { insertBedrockToolCachePoint } from "./toolCache.mjs";
2
2
  import { convertToConverseMessages } from "./utils/message_inputs.mjs";
3
- import { handleConverseStreamContentBlockDelta, handleConverseStreamContentBlockStart, handleConverseStreamMetadata } from "./utils/message_outputs.mjs";
3
+ import { createConverseToolUseStopChunk, handleConverseStreamContentBlockDelta, handleConverseStreamContentBlockStart, handleConverseStreamMetadata } from "./utils/message_outputs.mjs";
4
4
  import "./utils/index.mjs";
5
5
  import { AIMessageChunk } from "@langchain/core/messages";
6
6
  import { ChatGenerationChunk } from "@langchain/core/outputs";
@@ -106,12 +106,24 @@ var CustomChatBedrockConverse = class extends ChatBedrockConverse {
106
106
  const response = await this.client.send(command, { abortSignal: options.signal });
107
107
  if (!response.stream) return;
108
108
  const seenBlockIndices = /* @__PURE__ */ new Set();
109
+ const toolUseBlockIndices = /* @__PURE__ */ new Set();
110
+ /**
111
+ * Guardrails can reject an already-streamed toolUse block at
112
+ * `messageStop` (`guardrail_intervened`), after `contentBlockStop` has
113
+ * passed. Only emit eager-execution seals when no guardrails are
114
+ * configured, so a later intervention can't race an eagerly started tool.
115
+ */
116
+ const sealToolUseOnStop = options.guardrailConfig == null && this.guardrailConfig == null;
109
117
  for await (const event of response.stream) if (event.contentBlockStart != null) {
110
118
  const startChunk = handleConverseStreamContentBlockStart(event.contentBlockStart);
111
119
  if (startChunk != null) {
112
120
  const idx = event.contentBlockStart.contentBlockIndex;
113
- if (idx != null) seenBlockIndices.add(idx);
121
+ if (idx != null) {
122
+ seenBlockIndices.add(idx);
123
+ if (event.contentBlockStart.start?.toolUse != null) toolUseBlockIndices.add(idx);
124
+ }
114
125
  yield this.enrichChunk(startChunk, seenBlockIndices);
126
+ await runManager?.handleLLMNewToken(startChunk.text, void 0, void 0, void 0, void 0, { chunk: startChunk });
115
127
  }
116
128
  } else if (event.contentBlockDelta != null) {
117
129
  const deltaChunk = handleConverseStreamContentBlockDelta(event.contentBlockDelta);
@@ -122,7 +134,14 @@ var CustomChatBedrockConverse = class extends ChatBedrockConverse {
122
134
  } else if (event.metadata != null) yield handleConverseStreamMetadata(event.metadata, { streamUsage });
123
135
  else if (event.contentBlockStop != null) {
124
136
  const stopIdx = event.contentBlockStop.contentBlockIndex;
125
- if (stopIdx != null) seenBlockIndices.add(stopIdx);
137
+ if (stopIdx != null) {
138
+ seenBlockIndices.add(stopIdx);
139
+ if (sealToolUseOnStop && toolUseBlockIndices.has(stopIdx)) {
140
+ const sealChunk = createConverseToolUseStopChunk(stopIdx);
141
+ yield sealChunk;
142
+ await runManager?.handleLLMNewToken(sealChunk.text, void 0, void 0, void 0, void 0, { chunk: sealChunk });
143
+ }
144
+ }
126
145
  } else yield new ChatGenerationChunk({
127
146
  text: "",
128
147
  message: new AIMessageChunk({
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/llm/bedrock/index.ts"],"sourcesContent":["/**\n * Optimized ChatBedrockConverse wrapper that fixes content block merging for\n * streaming responses and adds support for latest @langchain/aws features:\n *\n * - Application Inference Profiles (PR #9129)\n * - Service Tiers (Priority/Standard/Flex) (PR #9785) - requires AWS SDK 3.966.0+\n *\n * Bedrock's `@langchain/aws` library does not include an `index` property on content\n * blocks (unlike Anthropic/OpenAI), which causes LangChain's `_mergeLists` to append\n * each streaming chunk as a separate array entry instead of merging by index.\n *\n * This wrapper takes full ownership of the stream by directly interfacing with the\n * AWS SDK client (`this.client`) and using custom handlers from `./utils/` that\n * include `contentBlockIndex` in response_metadata for every delta type. It then\n * promotes `contentBlockIndex` to an `index` property on each content block\n * (mirroring Anthropic's pattern) and strips it from metadata to avoid\n * `_mergeDicts` conflicts.\n *\n * When multiple content block types are present (e.g. reasoning + text), text deltas\n * are promoted from strings to array form with `index` so they merge correctly once\n * the accumulated content is already an array.\n */\n\nimport { ChatBedrockConverse } from '@langchain/aws';\nimport { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';\nimport {\n ConverseStreamCommand,\n type GuardrailConfiguration,\n type GuardrailStreamConfiguration,\n} from '@aws-sdk/client-bedrock-runtime';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { BaseMessage, ResponseMetadata } from '@langchain/core/messages';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport {\n convertToConverseMessages,\n handleConverseStreamContentBlockStart,\n handleConverseStreamContentBlockDelta,\n handleConverseStreamMetadata,\n} from './utils';\nimport { insertBedrockToolCachePoint } from './toolCache';\n\n/**\n * Service tier type for Bedrock invocations.\n * Requires AWS SDK >= 3.966.0 to actually work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\nexport type ServiceTierType = 'priority' | 'default' | 'flex' | 'reserved';\n\nexport type CustomGuardrailConfiguration = GuardrailConfiguration &\n Pick<GuardrailStreamConfiguration, 'streamProcessingMode'>;\n\n/**\n * Extended input interface with additional features:\n * - applicationInferenceProfile: Use an inference profile ARN instead of model ID\n * - serviceTier: Specify service tier (Priority, Standard, Flex, Reserved)\n */\nexport interface CustomChatBedrockConverseInput\n extends ChatBedrockConverseInput {\n /**\n * Enables Bedrock prompt cache checkpoints for message and tool prefixes.\n */\n promptCache?: boolean;\n\n /**\n * Guardrail configuration for Converse and ConverseStream invocations.\n * `streamProcessingMode` is only used by ConverseStream.\n */\n guardrailConfig?: CustomGuardrailConfiguration;\n\n /**\n * Application Inference Profile ARN to use for the model.\n * For example, \"arn:aws:bedrock:eu-west-1:123456789102:application-inference-profile/fm16bt65tzgx\"\n * When provided, this ARN will be used for the actual inference calls instead of the model ID.\n * Must still provide `model` as normal modelId to benefit from all the metadata.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-create.html\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n * Specifies the processing tier type used for serving the request.\n * Supported values are 'priority', 'default', 'flex', and 'reserved'.\n *\n * - 'priority': Prioritized processing for lower latency\n * - 'default': Standard processing tier\n * - 'flex': Flexible processing tier with lower cost\n * - 'reserved': Reserved capacity for consistent performance\n *\n * If not provided, AWS uses the default tier.\n * Note: Requires AWS SDK >= 3.966.0 to work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\n serviceTier?: ServiceTierType;\n}\n\n/**\n * Extended call options with serviceTier override support.\n */\nexport interface CustomChatBedrockConverseCallOptions {\n serviceTier?: ServiceTierType;\n guardrailConfig?: CustomGuardrailConfiguration;\n}\n\nexport class CustomChatBedrockConverse extends ChatBedrockConverse {\n /**\n * Whether to insert Bedrock prompt cache checkpoints when available.\n */\n promptCache?: boolean;\n\n /**\n * Application Inference Profile ARN to use instead of model ID.\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n */\n serviceTier?: ServiceTierType;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.promptCache = fields?.promptCache;\n this.applicationInferenceProfile = fields?.applicationInferenceProfile;\n this.serviceTier = fields?.serviceTier;\n }\n\n static lc_name(): string {\n return 'LibreChatBedrockConverse';\n }\n\n /**\n * Get the model ID to use for API calls.\n * Returns applicationInferenceProfile if set, otherwise returns this.model.\n */\n protected getModelId(): string {\n return this.applicationInferenceProfile ?? this.model;\n }\n\n /**\n * Override invocationParams to add serviceTier support.\n */\n override invocationParams(\n options?: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions\n ): ReturnType<ChatBedrockConverse['invocationParams']> & {\n serviceTier?: { type: ServiceTierType };\n } {\n const baseParams = super.invocationParams(options);\n const toolConfig =\n this.promptCache === true\n ? insertBedrockToolCachePoint(baseParams.toolConfig, true)\n : baseParams.toolConfig;\n\n /** Service tier from options or fall back to class-level setting */\n const serviceTierType = options?.serviceTier ?? this.serviceTier;\n\n return {\n ...baseParams,\n toolConfig,\n serviceTier: serviceTierType ? { type: serviceTierType } : undefined,\n };\n }\n\n /**\n * Override _generateNonStreaming to use applicationInferenceProfile as modelId.\n * Uses the same model-swapping pattern as streaming for consistency.\n */\n override async _generateNonStreaming(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n const originalModel = this.model;\n if (\n this.applicationInferenceProfile != null &&\n this.applicationInferenceProfile !== ''\n ) {\n this.model = this.applicationInferenceProfile;\n }\n\n try {\n return await super._generateNonStreaming(messages, options, runManager);\n } finally {\n this.model = originalModel;\n }\n }\n\n /**\n * Own the stream end-to-end so we have direct access to every\n * `contentBlockDelta.contentBlockIndex` from the AWS SDK.\n *\n * This replaces the parent's implementation which strips contentBlockIndex\n * from text and reasoning deltas, making it impossible to merge correctly.\n */\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const { converseMessages, converseSystem } =\n convertToConverseMessages(messages);\n const params = this.invocationParams(options);\n\n let { streamUsage } = this;\n if ((options as Record<string, unknown>).streamUsage !== undefined) {\n streamUsage = (options as Record<string, unknown>).streamUsage as boolean;\n }\n\n const modelId = this.getModelId();\n\n const command = new ConverseStreamCommand({\n modelId,\n messages: converseMessages,\n system: converseSystem,\n ...(params as Record<string, unknown>),\n });\n\n const response = await this.client.send(command, {\n abortSignal: options.signal,\n });\n\n if (!response.stream) {\n return;\n }\n\n const seenBlockIndices = new Set<number>();\n\n for await (const event of response.stream) {\n if (event.contentBlockStart != null) {\n const startChunk = handleConverseStreamContentBlockStart(\n event.contentBlockStart\n );\n if (startChunk != null) {\n const idx = event.contentBlockStart.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n }\n yield this.enrichChunk(startChunk, seenBlockIndices);\n }\n } else if (event.contentBlockDelta != null) {\n const deltaChunk = handleConverseStreamContentBlockDelta(\n event.contentBlockDelta\n );\n\n const idx = event.contentBlockDelta.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n }\n\n yield this.enrichChunk(deltaChunk, seenBlockIndices);\n\n await runManager?.handleLLMNewToken(\n deltaChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: deltaChunk }\n );\n } else if (event.metadata != null) {\n yield handleConverseStreamMetadata(event.metadata, { streamUsage });\n } else if (event.contentBlockStop != null) {\n const stopIdx = event.contentBlockStop.contentBlockIndex;\n if (stopIdx != null) {\n seenBlockIndices.add(stopIdx);\n }\n } else {\n yield new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n response_metadata: { ...event } as ResponseMetadata,\n }),\n });\n }\n }\n }\n\n /**\n * Inject `index` on content blocks for proper merge behaviour, then strip\n * `contentBlockIndex` from response_metadata to prevent `_mergeDicts` conflicts.\n *\n * Text string content is promoted to array form only when the stream contains\n * multiple content block indices (e.g. reasoning at index 0, text at index 1),\n * ensuring text merges correctly with the already-array accumulated content.\n */\n private enrichChunk(\n chunk: ChatGenerationChunk,\n seenBlockIndices: Set<number>\n ): ChatGenerationChunk {\n const message = chunk.message;\n if (!(message instanceof AIMessageChunk)) {\n return chunk;\n }\n\n const metadata = message.response_metadata as Record<string, unknown>;\n const blockIndex = this.extractContentBlockIndex(metadata);\n const hasMetadataIndex = blockIndex != null;\n\n let content: AIMessageChunk['content'] = message.content;\n let contentModified = false;\n\n if (Array.isArray(content) && blockIndex != null) {\n content = content.map((block) =>\n typeof block === 'object' && !('index' in block)\n ? { ...block, index: blockIndex }\n : block\n );\n contentModified = true;\n } else if (\n typeof content === 'string' &&\n content !== '' &&\n blockIndex != null &&\n seenBlockIndices.size > 1\n ) {\n content = [{ type: 'text', text: content, index: blockIndex }];\n contentModified = true;\n }\n\n if (!contentModified && !hasMetadataIndex) {\n return chunk;\n }\n\n const cleanedMetadata = hasMetadataIndex\n ? (this.removeContentBlockIndex(metadata) as Record<string, unknown>)\n : metadata;\n\n return new ChatGenerationChunk({\n text: chunk.text,\n message: new AIMessageChunk({\n ...message,\n content,\n response_metadata: cleanedMetadata,\n }),\n generationInfo: chunk.generationInfo,\n });\n }\n\n /**\n * Extract `contentBlockIndex` from the top level of response_metadata.\n * Our custom handlers always place it at the top level.\n */\n private extractContentBlockIndex(\n metadata: Record<string, unknown>\n ): number | undefined {\n if (\n 'contentBlockIndex' in metadata &&\n typeof metadata.contentBlockIndex === 'number'\n ) {\n return metadata.contentBlockIndex;\n }\n return undefined;\n }\n\n private removeContentBlockIndex(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => this.removeContentBlockIndex(item));\n }\n\n if (typeof obj === 'object') {\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (key !== 'contentBlockIndex') {\n cleaned[key] = this.removeContentBlockIndex(value);\n }\n }\n return cleaned;\n }\n\n return obj;\n }\n}\n\nexport type { ChatBedrockConverseInput };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/llm/bedrock/index.ts"],"sourcesContent":["/**\n * Optimized ChatBedrockConverse wrapper that fixes content block merging for\n * streaming responses and adds support for latest @langchain/aws features:\n *\n * - Application Inference Profiles (PR #9129)\n * - Service Tiers (Priority/Standard/Flex) (PR #9785) - requires AWS SDK 3.966.0+\n *\n * Bedrock's `@langchain/aws` library does not include an `index` property on content\n * blocks (unlike Anthropic/OpenAI), which causes LangChain's `_mergeLists` to append\n * each streaming chunk as a separate array entry instead of merging by index.\n *\n * This wrapper takes full ownership of the stream by directly interfacing with the\n * AWS SDK client (`this.client`) and using custom handlers from `./utils/` that\n * include `contentBlockIndex` in response_metadata for every delta type. It then\n * promotes `contentBlockIndex` to an `index` property on each content block\n * (mirroring Anthropic's pattern) and strips it from metadata to avoid\n * `_mergeDicts` conflicts.\n *\n * When multiple content block types are present (e.g. reasoning + text), text deltas\n * are promoted from strings to array form with `index` so they merge correctly once\n * the accumulated content is already an array.\n */\n\nimport { ChatBedrockConverse } from '@langchain/aws';\nimport { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';\nimport {\n ConverseStreamCommand,\n type GuardrailConfiguration,\n type GuardrailStreamConfiguration,\n} from '@aws-sdk/client-bedrock-runtime';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { BaseMessage, ResponseMetadata } from '@langchain/core/messages';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport {\n convertToConverseMessages,\n createConverseToolUseStopChunk,\n handleConverseStreamContentBlockStart,\n handleConverseStreamContentBlockDelta,\n handleConverseStreamMetadata,\n} from './utils';\nimport { insertBedrockToolCachePoint } from './toolCache';\n\n/**\n * Service tier type for Bedrock invocations.\n * Requires AWS SDK >= 3.966.0 to actually work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\nexport type ServiceTierType = 'priority' | 'default' | 'flex' | 'reserved';\n\nexport type CustomGuardrailConfiguration = GuardrailConfiguration &\n Pick<GuardrailStreamConfiguration, 'streamProcessingMode'>;\n\n/**\n * Extended input interface with additional features:\n * - applicationInferenceProfile: Use an inference profile ARN instead of model ID\n * - serviceTier: Specify service tier (Priority, Standard, Flex, Reserved)\n */\nexport interface CustomChatBedrockConverseInput\n extends ChatBedrockConverseInput {\n /**\n * Enables Bedrock prompt cache checkpoints for message and tool prefixes.\n */\n promptCache?: boolean;\n\n /**\n * Guardrail configuration for Converse and ConverseStream invocations.\n * `streamProcessingMode` is only used by ConverseStream.\n */\n guardrailConfig?: CustomGuardrailConfiguration;\n\n /**\n * Application Inference Profile ARN to use for the model.\n * For example, \"arn:aws:bedrock:eu-west-1:123456789102:application-inference-profile/fm16bt65tzgx\"\n * When provided, this ARN will be used for the actual inference calls instead of the model ID.\n * Must still provide `model` as normal modelId to benefit from all the metadata.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-create.html\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n * Specifies the processing tier type used for serving the request.\n * Supported values are 'priority', 'default', 'flex', and 'reserved'.\n *\n * - 'priority': Prioritized processing for lower latency\n * - 'default': Standard processing tier\n * - 'flex': Flexible processing tier with lower cost\n * - 'reserved': Reserved capacity for consistent performance\n *\n * If not provided, AWS uses the default tier.\n * Note: Requires AWS SDK >= 3.966.0 to work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\n serviceTier?: ServiceTierType;\n}\n\n/**\n * Extended call options with serviceTier override support.\n */\nexport interface CustomChatBedrockConverseCallOptions {\n serviceTier?: ServiceTierType;\n guardrailConfig?: CustomGuardrailConfiguration;\n}\n\nexport class CustomChatBedrockConverse extends ChatBedrockConverse {\n /**\n * Whether to insert Bedrock prompt cache checkpoints when available.\n */\n promptCache?: boolean;\n\n /**\n * Application Inference Profile ARN to use instead of model ID.\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n */\n serviceTier?: ServiceTierType;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.promptCache = fields?.promptCache;\n this.applicationInferenceProfile = fields?.applicationInferenceProfile;\n this.serviceTier = fields?.serviceTier;\n }\n\n static lc_name(): string {\n return 'LibreChatBedrockConverse';\n }\n\n /**\n * Get the model ID to use for API calls.\n * Returns applicationInferenceProfile if set, otherwise returns this.model.\n */\n protected getModelId(): string {\n return this.applicationInferenceProfile ?? this.model;\n }\n\n /**\n * Override invocationParams to add serviceTier support.\n */\n override invocationParams(\n options?: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions\n ): ReturnType<ChatBedrockConverse['invocationParams']> & {\n serviceTier?: { type: ServiceTierType };\n } {\n const baseParams = super.invocationParams(options);\n const toolConfig =\n this.promptCache === true\n ? insertBedrockToolCachePoint(baseParams.toolConfig, true)\n : baseParams.toolConfig;\n\n /** Service tier from options or fall back to class-level setting */\n const serviceTierType = options?.serviceTier ?? this.serviceTier;\n\n return {\n ...baseParams,\n toolConfig,\n serviceTier: serviceTierType ? { type: serviceTierType } : undefined,\n };\n }\n\n /**\n * Override _generateNonStreaming to use applicationInferenceProfile as modelId.\n * Uses the same model-swapping pattern as streaming for consistency.\n */\n override async _generateNonStreaming(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n const originalModel = this.model;\n if (\n this.applicationInferenceProfile != null &&\n this.applicationInferenceProfile !== ''\n ) {\n this.model = this.applicationInferenceProfile;\n }\n\n try {\n return await super._generateNonStreaming(messages, options, runManager);\n } finally {\n this.model = originalModel;\n }\n }\n\n /**\n * Own the stream end-to-end so we have direct access to every\n * `contentBlockDelta.contentBlockIndex` from the AWS SDK.\n *\n * This replaces the parent's implementation which strips contentBlockIndex\n * from text and reasoning deltas, making it impossible to merge correctly.\n */\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const { converseMessages, converseSystem } =\n convertToConverseMessages(messages);\n const params = this.invocationParams(options);\n\n let { streamUsage } = this;\n if ((options as Record<string, unknown>).streamUsage !== undefined) {\n streamUsage = (options as Record<string, unknown>).streamUsage as boolean;\n }\n\n const modelId = this.getModelId();\n\n const command = new ConverseStreamCommand({\n modelId,\n messages: converseMessages,\n system: converseSystem,\n ...(params as Record<string, unknown>),\n });\n\n const response = await this.client.send(command, {\n abortSignal: options.signal,\n });\n\n if (!response.stream) {\n return;\n }\n\n const seenBlockIndices = new Set<number>();\n const toolUseBlockIndices = new Set<number>();\n /**\n * Guardrails can reject an already-streamed toolUse block at\n * `messageStop` (`guardrail_intervened`), after `contentBlockStop` has\n * passed. Only emit eager-execution seals when no guardrails are\n * configured, so a later intervention can't race an eagerly started tool.\n */\n const sealToolUseOnStop =\n options.guardrailConfig == null && this.guardrailConfig == null;\n\n for await (const event of response.stream) {\n if (event.contentBlockStart != null) {\n const startChunk = handleConverseStreamContentBlockStart(\n event.contentBlockStart\n );\n if (startChunk != null) {\n const idx = event.contentBlockStart.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n if (event.contentBlockStart.start?.toolUse != null) {\n toolUseBlockIndices.add(idx);\n }\n }\n yield this.enrichChunk(startChunk, seenBlockIndices);\n\n // Registered stream handlers receive chunks through callback\n // events, not the yielded generator — dispatch the start chunk so\n // they see the tool call's id/name (eager chunk state needs both).\n await runManager?.handleLLMNewToken(\n startChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: startChunk }\n );\n }\n } else if (event.contentBlockDelta != null) {\n const deltaChunk = handleConverseStreamContentBlockDelta(\n event.contentBlockDelta\n );\n\n const idx = event.contentBlockDelta.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n }\n\n yield this.enrichChunk(deltaChunk, seenBlockIndices);\n\n await runManager?.handleLLMNewToken(\n deltaChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: deltaChunk }\n );\n } else if (event.metadata != null) {\n yield handleConverseStreamMetadata(event.metadata, { streamUsage });\n } else if (event.contentBlockStop != null) {\n const stopIdx = event.contentBlockStop.contentBlockIndex;\n if (stopIdx != null) {\n seenBlockIndices.add(stopIdx);\n if (sealToolUseOnStop && toolUseBlockIndices.has(stopIdx)) {\n // Converse guarantees the block's input is complete at stop, so\n // emit an explicit seal chunk for eager tool execution — through\n // the callback path too, for registered stream handlers.\n const sealChunk = createConverseToolUseStopChunk(stopIdx);\n yield sealChunk;\n await runManager?.handleLLMNewToken(\n sealChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: sealChunk }\n );\n }\n }\n } else {\n yield new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n response_metadata: { ...event } as ResponseMetadata,\n }),\n });\n }\n }\n }\n\n /**\n * Inject `index` on content blocks for proper merge behaviour, then strip\n * `contentBlockIndex` from response_metadata to prevent `_mergeDicts` conflicts.\n *\n * Text string content is promoted to array form only when the stream contains\n * multiple content block indices (e.g. reasoning at index 0, text at index 1),\n * ensuring text merges correctly with the already-array accumulated content.\n */\n private enrichChunk(\n chunk: ChatGenerationChunk,\n seenBlockIndices: Set<number>\n ): ChatGenerationChunk {\n const message = chunk.message;\n if (!(message instanceof AIMessageChunk)) {\n return chunk;\n }\n\n const metadata = message.response_metadata as Record<string, unknown>;\n const blockIndex = this.extractContentBlockIndex(metadata);\n const hasMetadataIndex = blockIndex != null;\n\n let content: AIMessageChunk['content'] = message.content;\n let contentModified = false;\n\n if (Array.isArray(content) && blockIndex != null) {\n content = content.map((block) =>\n typeof block === 'object' && !('index' in block)\n ? { ...block, index: blockIndex }\n : block\n );\n contentModified = true;\n } else if (\n typeof content === 'string' &&\n content !== '' &&\n blockIndex != null &&\n seenBlockIndices.size > 1\n ) {\n content = [{ type: 'text', text: content, index: blockIndex }];\n contentModified = true;\n }\n\n if (!contentModified && !hasMetadataIndex) {\n return chunk;\n }\n\n const cleanedMetadata = hasMetadataIndex\n ? (this.removeContentBlockIndex(metadata) as Record<string, unknown>)\n : metadata;\n\n return new ChatGenerationChunk({\n text: chunk.text,\n message: new AIMessageChunk({\n ...message,\n content,\n response_metadata: cleanedMetadata,\n }),\n generationInfo: chunk.generationInfo,\n });\n }\n\n /**\n * Extract `contentBlockIndex` from the top level of response_metadata.\n * Our custom handlers always place it at the top level.\n */\n private extractContentBlockIndex(\n metadata: Record<string, unknown>\n ): number | undefined {\n if (\n 'contentBlockIndex' in metadata &&\n typeof metadata.contentBlockIndex === 'number'\n ) {\n return metadata.contentBlockIndex;\n }\n return undefined;\n }\n\n private removeContentBlockIndex(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => this.removeContentBlockIndex(item));\n }\n\n if (typeof obj === 'object') {\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (key !== 'contentBlockIndex') {\n cleaned[key] = this.removeContentBlockIndex(value);\n }\n }\n return cleaned;\n }\n\n return obj;\n }\n}\n\nexport type { ChatBedrockConverseInput };\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { toLangChainContent } from "../../../messages/langchain.mjs";
2
+ import { BEDROCK_CONVERSE_STREAMED_TOOL_CALL_ADAPTER, STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY, STREAMED_TOOL_CALL_SEAL_METADATA_KEY } from "../../../tools/streamedToolCallSeals.mjs";
2
3
  import { AIMessageChunk } from "@langchain/core/messages";
3
4
  import { ChatGenerationChunk } from "@langchain/core/outputs";
4
5
  //#region src/llm/bedrock/utils/message_outputs.ts
@@ -48,7 +49,10 @@ function handleConverseStreamContentBlockDelta(contentBlockDelta) {
48
49
  index,
49
50
  type: "tool_call_chunk"
50
51
  }],
51
- response_metadata: { contentBlockIndex: contentBlockDelta.contentBlockIndex }
52
+ response_metadata: {
53
+ contentBlockIndex: contentBlockDelta.contentBlockIndex,
54
+ [STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY]: BEDROCK_CONVERSE_STREAMED_TOOL_CALL_ADAPTER
55
+ }
52
56
  })
53
57
  });
54
58
  } else if (contentBlockDelta.delta.reasoningContent != null) {
@@ -81,12 +85,43 @@ function handleConverseStreamContentBlockStart(contentBlockStart) {
81
85
  index,
82
86
  type: "tool_call_chunk"
83
87
  }],
84
- response_metadata: { contentBlockIndex: index }
88
+ response_metadata: {
89
+ contentBlockIndex: index,
90
+ [STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY]: BEDROCK_CONVERSE_STREAMED_TOOL_CALL_ADAPTER
91
+ }
85
92
  })
86
93
  });
87
94
  return null;
88
95
  }
89
96
  /**
97
+ * Build the chunk emitted when a Converse `contentBlockStop` event closes a
98
+ * toolUse block. The Converse protocol guarantees a block's input is complete
99
+ * at `contentBlockStop`, so this chunk carries an explicit streamed tool-call
100
+ * seal for that block index. The empty `args` delta merges as a no-op into the
101
+ * accumulated tool call; id/name are omitted so the chunk matches the existing
102
+ * entry purely by index.
103
+ */
104
+ function createConverseToolUseStopChunk(contentBlockIndex) {
105
+ return new ChatGenerationChunk({
106
+ text: "",
107
+ message: new AIMessageChunk({
108
+ content: "",
109
+ tool_call_chunks: [{
110
+ args: "",
111
+ index: contentBlockIndex,
112
+ type: "tool_call_chunk"
113
+ }],
114
+ response_metadata: {
115
+ [STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY]: BEDROCK_CONVERSE_STREAMED_TOOL_CALL_ADAPTER,
116
+ [STREAMED_TOOL_CALL_SEAL_METADATA_KEY]: {
117
+ kind: "single",
118
+ index: contentBlockIndex
119
+ }
120
+ }
121
+ })
122
+ });
123
+ }
124
+ /**
90
125
  * Handle a metadata event from Bedrock Converse stream.
91
126
  */
92
127
  function handleConverseStreamMetadata(metadata, extra) {
@@ -114,6 +149,6 @@ function handleConverseStreamMetadata(metadata, extra) {
114
149
  });
115
150
  }
116
151
  //#endregion
117
- export { bedrockReasoningDeltaToLangchainPartialReasoningBlock, handleConverseStreamContentBlockDelta, handleConverseStreamContentBlockStart, handleConverseStreamMetadata };
152
+ export { bedrockReasoningDeltaToLangchainPartialReasoningBlock, createConverseToolUseStopChunk, handleConverseStreamContentBlockDelta, handleConverseStreamContentBlockStart, handleConverseStreamMetadata };
118
153
 
119
154
  //# sourceMappingURL=message_outputs.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"message_outputs.mjs","names":[],"sources":["../../../../../src/llm/bedrock/utils/message_outputs.ts"],"sourcesContent":["/**\n * Utility functions for converting Bedrock Converse responses to LangChain messages.\n * Ported from @langchain/aws common.js\n */\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport { AIMessage, AIMessageChunk } from '@langchain/core/messages';\nimport type { UsageMetadata } from '@langchain/core/messages';\nimport type {\n BedrockMessage,\n ConverseResponse,\n ContentBlockDeltaEvent,\n ConverseStreamMetadataEvent,\n ContentBlockStartEvent,\n ReasoningContentBlock,\n ReasoningContentBlockDelta,\n MessageContentReasoningBlock,\n MessageContentReasoningBlockReasoningTextPartial,\n MessageContentReasoningBlockRedacted,\n} from '../types';\nimport { toLangChainContent } from '@/messages/langchain';\n\n/**\n * Convert a Bedrock reasoning block delta to a LangChain partial reasoning block.\n */\nexport function bedrockReasoningDeltaToLangchainPartialReasoningBlock(\n reasoningContent: ReasoningContentBlockDelta\n):\n | MessageContentReasoningBlockReasoningTextPartial\n | MessageContentReasoningBlockRedacted {\n const { text, redactedContent, signature } =\n reasoningContent as ReasoningContentBlockDelta & {\n text?: string;\n redactedContent?: Uint8Array;\n signature?: string;\n };\n\n if (typeof text === 'string') {\n return {\n type: 'reasoning_content',\n reasoningText: { text },\n };\n }\n if (signature != null) {\n return {\n type: 'reasoning_content',\n reasoningText: { signature },\n };\n }\n if (redactedContent != null) {\n return {\n type: 'reasoning_content',\n redactedContent: Buffer.from(redactedContent).toString('base64'),\n };\n }\n throw new Error('Invalid reasoning content');\n}\n\n/**\n * Convert a Bedrock reasoning block to a LangChain reasoning block.\n */\nexport function bedrockReasoningBlockToLangchainReasoningBlock(\n reasoningContent: ReasoningContentBlock\n): MessageContentReasoningBlock {\n const { reasoningText, redactedContent } =\n reasoningContent as ReasoningContentBlock & {\n reasoningText?: { text?: string; signature?: string };\n redactedContent?: Uint8Array;\n };\n\n if (reasoningText != null) {\n return {\n type: 'reasoning_content',\n reasoningText: reasoningText,\n };\n }\n if (redactedContent != null) {\n return {\n type: 'reasoning_content',\n redactedContent: Buffer.from(redactedContent).toString('base64'),\n };\n }\n throw new Error('Invalid reasoning content');\n}\n\n/**\n * Convert a Bedrock Converse message to a LangChain message.\n */\nexport function convertConverseMessageToLangChainMessage(\n message: BedrockMessage,\n responseMetadata: Omit<ConverseResponse, 'output'>\n): AIMessage {\n if (message.content == null) {\n throw new Error('No message content found in response.');\n }\n if (message.role !== 'assistant') {\n throw new Error(\n `Unsupported message role received in ChatBedrockConverse response: ${message.role}`\n );\n }\n\n let requestId: string | undefined;\n if (\n '$metadata' in responseMetadata &&\n responseMetadata.$metadata != null &&\n typeof responseMetadata.$metadata === 'object' &&\n 'requestId' in responseMetadata.$metadata\n ) {\n requestId = responseMetadata.$metadata.requestId as string;\n }\n\n let tokenUsage:\n | {\n input_tokens: number;\n output_tokens: number;\n total_tokens: number;\n input_token_details?: {\n cache_read: number;\n cache_creation: number;\n };\n }\n | undefined;\n if (responseMetadata.usage != null) {\n const usage = responseMetadata.usage as NonNullable<\n typeof responseMetadata.usage\n > & {\n cacheReadInputTokens?: number;\n cacheWriteInputTokens?: number;\n };\n const input_tokens = usage.inputTokens ?? 0;\n const output_tokens = usage.outputTokens ?? 0;\n const cacheRead = usage.cacheReadInputTokens;\n const cacheWrite = usage.cacheWriteInputTokens;\n tokenUsage = {\n input_tokens,\n output_tokens,\n total_tokens: usage.totalTokens ?? input_tokens + output_tokens,\n };\n if (cacheRead != null || cacheWrite != null) {\n tokenUsage.input_token_details = {\n cache_read: cacheRead ?? 0,\n cache_creation: cacheWrite ?? 0,\n };\n }\n }\n\n if (\n message.content.length === 1 &&\n 'text' in message.content[0] &&\n typeof message.content[0].text === 'string'\n ) {\n return new AIMessage({\n content: message.content[0].text,\n response_metadata: responseMetadata,\n usage_metadata: tokenUsage,\n id: requestId,\n });\n } else {\n const toolCalls: Array<{\n id?: string;\n name: string;\n args: Record<string, unknown>;\n type: 'tool_call';\n }> = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const content: any[] = [];\n\n message.content.forEach((c) => {\n if (\n 'toolUse' in c &&\n c.toolUse != null &&\n c.toolUse.name != null &&\n c.toolUse.name !== '' &&\n c.toolUse.input != null &&\n typeof c.toolUse.input === 'object'\n ) {\n toolCalls.push({\n id: c.toolUse.toolUseId,\n name: c.toolUse.name,\n args: c.toolUse.input as Record<string, unknown>,\n type: 'tool_call',\n });\n } else if ('text' in c && typeof c.text === 'string') {\n content.push({ type: 'text', text: c.text });\n } else if ('reasoningContent' in c && c.reasoningContent != null) {\n content.push(\n bedrockReasoningBlockToLangchainReasoningBlock(c.reasoningContent)\n );\n } else {\n content.push(c);\n }\n });\n\n return new AIMessage({\n content: content.length ? content : '',\n tool_calls: toolCalls.length ? toolCalls : undefined,\n response_metadata: responseMetadata,\n usage_metadata: tokenUsage,\n id: requestId,\n });\n }\n}\n\n/**\n * Handle a content block delta event from Bedrock Converse stream.\n */\nexport function handleConverseStreamContentBlockDelta(\n contentBlockDelta: ContentBlockDeltaEvent\n): ChatGenerationChunk {\n if (contentBlockDelta.delta == null) {\n throw new Error('No delta found in content block.');\n }\n\n if (typeof contentBlockDelta.delta.text === 'string') {\n return new ChatGenerationChunk({\n text: contentBlockDelta.delta.text,\n message: new AIMessageChunk({\n content: contentBlockDelta.delta.text,\n response_metadata: {\n contentBlockIndex: contentBlockDelta.contentBlockIndex,\n },\n }),\n });\n } else if (contentBlockDelta.delta.toolUse != null) {\n const index = contentBlockDelta.contentBlockIndex;\n return new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n tool_call_chunks: [\n {\n args: contentBlockDelta.delta.toolUse.input as string,\n index,\n type: 'tool_call_chunk',\n },\n ],\n response_metadata: {\n contentBlockIndex: contentBlockDelta.contentBlockIndex,\n },\n }),\n });\n } else if (contentBlockDelta.delta.reasoningContent != null) {\n const reasoningBlock =\n bedrockReasoningDeltaToLangchainPartialReasoningBlock(\n contentBlockDelta.delta.reasoningContent\n );\n let reasoningText = '';\n if ('reasoningText' in reasoningBlock) {\n reasoningText = reasoningBlock.reasoningText.text ?? '';\n } else if ('redactedContent' in reasoningBlock) {\n reasoningText = reasoningBlock.redactedContent;\n }\n return new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: toLangChainContent([reasoningBlock]),\n additional_kwargs: {\n // Set reasoning_content for stream handler to detect reasoning mode\n reasoning_content: reasoningText,\n },\n response_metadata: {\n contentBlockIndex: contentBlockDelta.contentBlockIndex,\n },\n }),\n });\n } else {\n throw new Error(\n `Unsupported content block type(s): ${JSON.stringify(contentBlockDelta.delta, null, 2)}`\n );\n }\n}\n\n/**\n * Handle a content block start event from Bedrock Converse stream.\n */\nexport function handleConverseStreamContentBlockStart(\n contentBlockStart: ContentBlockStartEvent\n): ChatGenerationChunk | null {\n const index = contentBlockStart.contentBlockIndex;\n\n if (contentBlockStart.start?.toolUse != null) {\n return new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n tool_call_chunks: [\n {\n name: contentBlockStart.start.toolUse.name,\n id: contentBlockStart.start.toolUse.toolUseId,\n index,\n type: 'tool_call_chunk',\n },\n ],\n response_metadata: {\n contentBlockIndex: index,\n },\n }),\n });\n }\n\n // Return null for non-tool content block starts (text blocks don't need special handling)\n return null;\n}\n\n/**\n * Handle a metadata event from Bedrock Converse stream.\n */\nexport function handleConverseStreamMetadata(\n metadata: ConverseStreamMetadataEvent,\n extra: { streamUsage: boolean }\n): ChatGenerationChunk {\n const usage = metadata.usage as\n | (NonNullable<ConverseStreamMetadataEvent['usage']> & {\n cacheReadInputTokens?: number;\n cacheWriteInputTokens?: number;\n })\n | undefined;\n const inputTokens = usage?.inputTokens ?? 0;\n const outputTokens = usage?.outputTokens ?? 0;\n const cacheRead = usage?.cacheReadInputTokens;\n const cacheWrite = usage?.cacheWriteInputTokens;\n\n const usage_metadata: Record<string, unknown> = {\n input_tokens: inputTokens,\n output_tokens: outputTokens,\n total_tokens: usage?.totalTokens ?? inputTokens + outputTokens,\n };\n\n if (cacheRead != null || cacheWrite != null) {\n usage_metadata.input_token_details = {\n cache_read: cacheRead ?? 0,\n cache_creation: cacheWrite ?? 0,\n };\n }\n\n return new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n usage_metadata: extra.streamUsage\n ? (usage_metadata as UsageMetadata)\n : undefined,\n response_metadata: {\n // Use the same key as returned from the Converse API\n metadata,\n },\n }),\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"message_outputs.mjs","names":[],"sources":["../../../../../src/llm/bedrock/utils/message_outputs.ts"],"sourcesContent":["/**\n * Utility functions for converting Bedrock Converse responses to LangChain messages.\n * Ported from @langchain/aws common.js\n */\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport { AIMessage, AIMessageChunk } from '@langchain/core/messages';\nimport type { UsageMetadata } from '@langchain/core/messages';\nimport type {\n BedrockMessage,\n ConverseResponse,\n ContentBlockDeltaEvent,\n ConverseStreamMetadataEvent,\n ContentBlockStartEvent,\n ReasoningContentBlock,\n ReasoningContentBlockDelta,\n MessageContentReasoningBlock,\n MessageContentReasoningBlockReasoningTextPartial,\n MessageContentReasoningBlockRedacted,\n} from '../types';\nimport {\n STREAMED_TOOL_CALL_SEAL_METADATA_KEY,\n STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY,\n BEDROCK_CONVERSE_STREAMED_TOOL_CALL_ADAPTER,\n} from '@/tools/streamedToolCallSeals';\nimport { toLangChainContent } from '@/messages/langchain';\n\n/**\n * Convert a Bedrock reasoning block delta to a LangChain partial reasoning block.\n */\nexport function bedrockReasoningDeltaToLangchainPartialReasoningBlock(\n reasoningContent: ReasoningContentBlockDelta\n):\n | MessageContentReasoningBlockReasoningTextPartial\n | MessageContentReasoningBlockRedacted {\n const { text, redactedContent, signature } =\n reasoningContent as ReasoningContentBlockDelta & {\n text?: string;\n redactedContent?: Uint8Array;\n signature?: string;\n };\n\n if (typeof text === 'string') {\n return {\n type: 'reasoning_content',\n reasoningText: { text },\n };\n }\n if (signature != null) {\n return {\n type: 'reasoning_content',\n reasoningText: { signature },\n };\n }\n if (redactedContent != null) {\n return {\n type: 'reasoning_content',\n redactedContent: Buffer.from(redactedContent).toString('base64'),\n };\n }\n throw new Error('Invalid reasoning content');\n}\n\n/**\n * Convert a Bedrock reasoning block to a LangChain reasoning block.\n */\nexport function bedrockReasoningBlockToLangchainReasoningBlock(\n reasoningContent: ReasoningContentBlock\n): MessageContentReasoningBlock {\n const { reasoningText, redactedContent } =\n reasoningContent as ReasoningContentBlock & {\n reasoningText?: { text?: string; signature?: string };\n redactedContent?: Uint8Array;\n };\n\n if (reasoningText != null) {\n return {\n type: 'reasoning_content',\n reasoningText: reasoningText,\n };\n }\n if (redactedContent != null) {\n return {\n type: 'reasoning_content',\n redactedContent: Buffer.from(redactedContent).toString('base64'),\n };\n }\n throw new Error('Invalid reasoning content');\n}\n\n/**\n * Convert a Bedrock Converse message to a LangChain message.\n */\nexport function convertConverseMessageToLangChainMessage(\n message: BedrockMessage,\n responseMetadata: Omit<ConverseResponse, 'output'>\n): AIMessage {\n if (message.content == null) {\n throw new Error('No message content found in response.');\n }\n if (message.role !== 'assistant') {\n throw new Error(\n `Unsupported message role received in ChatBedrockConverse response: ${message.role}`\n );\n }\n\n let requestId: string | undefined;\n if (\n '$metadata' in responseMetadata &&\n responseMetadata.$metadata != null &&\n typeof responseMetadata.$metadata === 'object' &&\n 'requestId' in responseMetadata.$metadata\n ) {\n requestId = responseMetadata.$metadata.requestId as string;\n }\n\n let tokenUsage:\n | {\n input_tokens: number;\n output_tokens: number;\n total_tokens: number;\n input_token_details?: {\n cache_read: number;\n cache_creation: number;\n };\n }\n | undefined;\n if (responseMetadata.usage != null) {\n const usage = responseMetadata.usage as NonNullable<\n typeof responseMetadata.usage\n > & {\n cacheReadInputTokens?: number;\n cacheWriteInputTokens?: number;\n };\n const input_tokens = usage.inputTokens ?? 0;\n const output_tokens = usage.outputTokens ?? 0;\n const cacheRead = usage.cacheReadInputTokens;\n const cacheWrite = usage.cacheWriteInputTokens;\n tokenUsage = {\n input_tokens,\n output_tokens,\n total_tokens: usage.totalTokens ?? input_tokens + output_tokens,\n };\n if (cacheRead != null || cacheWrite != null) {\n tokenUsage.input_token_details = {\n cache_read: cacheRead ?? 0,\n cache_creation: cacheWrite ?? 0,\n };\n }\n }\n\n if (\n message.content.length === 1 &&\n 'text' in message.content[0] &&\n typeof message.content[0].text === 'string'\n ) {\n return new AIMessage({\n content: message.content[0].text,\n response_metadata: responseMetadata,\n usage_metadata: tokenUsage,\n id: requestId,\n });\n } else {\n const toolCalls: Array<{\n id?: string;\n name: string;\n args: Record<string, unknown>;\n type: 'tool_call';\n }> = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const content: any[] = [];\n\n message.content.forEach((c) => {\n if (\n 'toolUse' in c &&\n c.toolUse != null &&\n c.toolUse.name != null &&\n c.toolUse.name !== '' &&\n c.toolUse.input != null &&\n typeof c.toolUse.input === 'object'\n ) {\n toolCalls.push({\n id: c.toolUse.toolUseId,\n name: c.toolUse.name,\n args: c.toolUse.input as Record<string, unknown>,\n type: 'tool_call',\n });\n } else if ('text' in c && typeof c.text === 'string') {\n content.push({ type: 'text', text: c.text });\n } else if ('reasoningContent' in c && c.reasoningContent != null) {\n content.push(\n bedrockReasoningBlockToLangchainReasoningBlock(c.reasoningContent)\n );\n } else {\n content.push(c);\n }\n });\n\n return new AIMessage({\n content: content.length ? content : '',\n tool_calls: toolCalls.length ? toolCalls : undefined,\n response_metadata: responseMetadata,\n usage_metadata: tokenUsage,\n id: requestId,\n });\n }\n}\n\n/**\n * Handle a content block delta event from Bedrock Converse stream.\n */\nexport function handleConverseStreamContentBlockDelta(\n contentBlockDelta: ContentBlockDeltaEvent\n): ChatGenerationChunk {\n if (contentBlockDelta.delta == null) {\n throw new Error('No delta found in content block.');\n }\n\n if (typeof contentBlockDelta.delta.text === 'string') {\n return new ChatGenerationChunk({\n text: contentBlockDelta.delta.text,\n message: new AIMessageChunk({\n content: contentBlockDelta.delta.text,\n response_metadata: {\n contentBlockIndex: contentBlockDelta.contentBlockIndex,\n },\n }),\n });\n } else if (contentBlockDelta.delta.toolUse != null) {\n const index = contentBlockDelta.contentBlockIndex;\n return new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n tool_call_chunks: [\n {\n args: contentBlockDelta.delta.toolUse.input as string,\n index,\n type: 'tool_call_chunk',\n },\n ],\n response_metadata: {\n contentBlockIndex: contentBlockDelta.contentBlockIndex,\n [STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY]:\n BEDROCK_CONVERSE_STREAMED_TOOL_CALL_ADAPTER,\n },\n }),\n });\n } else if (contentBlockDelta.delta.reasoningContent != null) {\n const reasoningBlock =\n bedrockReasoningDeltaToLangchainPartialReasoningBlock(\n contentBlockDelta.delta.reasoningContent\n );\n let reasoningText = '';\n if ('reasoningText' in reasoningBlock) {\n reasoningText = reasoningBlock.reasoningText.text ?? '';\n } else if ('redactedContent' in reasoningBlock) {\n reasoningText = reasoningBlock.redactedContent;\n }\n return new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: toLangChainContent([reasoningBlock]),\n additional_kwargs: {\n // Set reasoning_content for stream handler to detect reasoning mode\n reasoning_content: reasoningText,\n },\n response_metadata: {\n contentBlockIndex: contentBlockDelta.contentBlockIndex,\n },\n }),\n });\n } else {\n throw new Error(\n `Unsupported content block type(s): ${JSON.stringify(contentBlockDelta.delta, null, 2)}`\n );\n }\n}\n\n/**\n * Handle a content block start event from Bedrock Converse stream.\n */\nexport function handleConverseStreamContentBlockStart(\n contentBlockStart: ContentBlockStartEvent\n): ChatGenerationChunk | null {\n const index = contentBlockStart.contentBlockIndex;\n\n if (contentBlockStart.start?.toolUse != null) {\n return new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n tool_call_chunks: [\n {\n name: contentBlockStart.start.toolUse.name,\n id: contentBlockStart.start.toolUse.toolUseId,\n index,\n type: 'tool_call_chunk',\n },\n ],\n response_metadata: {\n contentBlockIndex: index,\n [STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY]:\n BEDROCK_CONVERSE_STREAMED_TOOL_CALL_ADAPTER,\n },\n }),\n });\n }\n\n // Return null for non-tool content block starts (text blocks don't need special handling)\n return null;\n}\n\n/**\n * Build the chunk emitted when a Converse `contentBlockStop` event closes a\n * toolUse block. The Converse protocol guarantees a block's input is complete\n * at `contentBlockStop`, so this chunk carries an explicit streamed tool-call\n * seal for that block index. The empty `args` delta merges as a no-op into the\n * accumulated tool call; id/name are omitted so the chunk matches the existing\n * entry purely by index.\n */\nexport function createConverseToolUseStopChunk(\n contentBlockIndex: number\n): ChatGenerationChunk {\n return new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n tool_call_chunks: [\n {\n args: '',\n index: contentBlockIndex,\n type: 'tool_call_chunk',\n },\n ],\n response_metadata: {\n [STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY]:\n BEDROCK_CONVERSE_STREAMED_TOOL_CALL_ADAPTER,\n [STREAMED_TOOL_CALL_SEAL_METADATA_KEY]: {\n kind: 'single',\n index: contentBlockIndex,\n },\n },\n }),\n });\n}\n\n/**\n * Handle a metadata event from Bedrock Converse stream.\n */\nexport function handleConverseStreamMetadata(\n metadata: ConverseStreamMetadataEvent,\n extra: { streamUsage: boolean }\n): ChatGenerationChunk {\n const usage = metadata.usage as\n | (NonNullable<ConverseStreamMetadataEvent['usage']> & {\n cacheReadInputTokens?: number;\n cacheWriteInputTokens?: number;\n })\n | undefined;\n const inputTokens = usage?.inputTokens ?? 0;\n const outputTokens = usage?.outputTokens ?? 0;\n const cacheRead = usage?.cacheReadInputTokens;\n const cacheWrite = usage?.cacheWriteInputTokens;\n\n const usage_metadata: Record<string, unknown> = {\n input_tokens: inputTokens,\n output_tokens: outputTokens,\n total_tokens: usage?.totalTokens ?? inputTokens + outputTokens,\n };\n\n if (cacheRead != null || cacheWrite != null) {\n usage_metadata.input_token_details = {\n cache_read: cacheRead ?? 0,\n cache_creation: cacheWrite ?? 0,\n };\n }\n\n return new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n usage_metadata: extra.streamUsage\n ? (usage_metadata as UsageMetadata)\n : undefined,\n response_metadata: {\n // Use the same key as returned from the Converse API\n metadata,\n },\n }),\n });\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { toLangChainContent } from "../../../messages/langchain.mjs";
2
+ import { GOOGLE_STREAMED_TOOL_CALL_ADAPTER, STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY, STREAMED_TOOL_CALL_SEAL_METADATA_KEY } from "../../../tools/streamedToolCallSeals.mjs";
2
3
  import "./zod_to_genai_parameters.mjs";
3
4
  import { AIMessage, AIMessageChunk, ChatMessage, convertToProviderContentBlock, isAIMessage, isBaseMessage, isDataContentBlock, isToolMessage, parseBase64DataUrl } from "@langchain/core/messages";
4
5
  import { v4 } from "uuid";
@@ -338,6 +339,10 @@ function convertResponseContentToChatGenerationChunk(response, extra) {
338
339
  if (reasoningParts.length > 0) additional_kwargs.reasoning = reasoningParts.join("");
339
340
  if (candidate?.groundingMetadata) additional_kwargs.groundingMetadata = candidate.groundingMetadata;
340
341
  const isFinalChunk = response.candidates[0]?.finishReason === "STOP" || response.candidates[0]?.finishReason === "MAX_TOKENS" || response.candidates[0]?.finishReason === "SAFETY";
342
+ const response_metadata = toolCallChunks.length > 0 ? {
343
+ [STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY]: GOOGLE_STREAMED_TOOL_CALL_ADAPTER,
344
+ [STREAMED_TOOL_CALL_SEAL_METADATA_KEY]: { kind: "all" }
345
+ } : void 0;
341
346
  return new ChatGenerationChunk({
342
347
  text,
343
348
  message: new AIMessageChunk({
@@ -345,6 +350,7 @@ function convertResponseContentToChatGenerationChunk(response, extra) {
345
350
  name: !candidateContent ? void 0 : candidateContent.role,
346
351
  tool_call_chunks: toolCallChunks,
347
352
  additional_kwargs,
353
+ response_metadata,
348
354
  usage_metadata: isFinalChunk ? extra.usageMetadata : void 0
349
355
  }),
350
356
  generationInfo
@@ -1 +1 @@
1
- {"version":3,"file":"common.mjs","names":["uuidv4"],"sources":["../../../../../src/llm/google/utils/common.ts"],"sourcesContent":["import { v4 as uuidv4 } from 'uuid';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport { ToolCallChunk } from '@langchain/core/messages/tool';\nimport { isOpenAITool } from '@langchain/core/language_models/base';\nimport { isLangChainTool } from '@langchain/core/utils/function_calling';\nimport {\n AIMessage,\n AIMessageChunk,\n BaseMessage,\n ChatMessage,\n ToolMessage,\n ToolMessageChunk,\n MessageContent,\n MessageContentComplex,\n UsageMetadata,\n isAIMessage,\n isBaseMessage,\n isToolMessage,\n StandardContentBlockConverter,\n parseBase64DataUrl,\n convertToProviderContentBlock,\n isDataContentBlock,\n} from '@langchain/core/messages';\nimport {\n POSSIBLE_ROLES,\n type Part,\n type Content,\n type TextPart,\n type FileDataPart,\n type InlineDataPart,\n type FunctionCallPart,\n type GenerateContentCandidate,\n type EnhancedGenerateContentResponse,\n type FunctionDeclaration as GenerativeAIFunctionDeclaration,\n type FunctionDeclarationsTool as GoogleGenerativeAIFunctionDeclarationsTool,\n} from '@google/generative-ai';\nimport type { ChatGeneration, ChatResult } from '@langchain/core/outputs';\nimport {\n jsonSchemaToGeminiParameters,\n schemaToGenerativeAIParameters,\n} from './zod_to_genai_parameters';\nimport { toLangChainContent } from '@/messages/langchain';\nimport { GoogleGenerativeAIToolType } from '../types';\n\nexport const _FUNCTION_CALL_THOUGHT_SIGNATURES_MAP_KEY =\n '__gemini_function_call_thought_signatures__';\n\nconst DUMMY_SIGNATURE =\n 'ErYCCrMCAdHtim9kOoOkrPiCNVsmlpMIKd7ZMxgiFbVQOkgp7nlLcDMzVsZwIzvuT7nQROivoXA72ccC2lSDvR0Gh7dkWaGuj7ctv6t7ZceHnecx0QYa+ix8tYpRfjhyWozQ49lWiws6+YGjCt10KRTyWsZ2h6O7iHTYJwKIRwGUHRKy/qK/6kFxJm5ML00gLq4D8s5Z6DBpp2ZlR+uF4G8jJgeWQgyHWVdx2wGYElaceVAc66tZdPQRdOHpWtgYSI1YdaXgVI8KHY3/EfNc2YqqMIulvkDBAnuMhkAjV9xmBa54Tq+ih3Im4+r3DzqhGqYdsSkhS0kZMwte4Hjs65dZzCw9lANxIqYi1DJ639WNPYihp/DCJCos7o+/EeSPJaio5sgWDyUnMGkY1atsJZ+m7pj7DD5tvQ==';\n\ntype GoogleServerSideToolPart = Part & {\n type?: 'toolCall' | 'toolResponse';\n toolCall?: object;\n toolResponse?: object;\n};\n\ntype GoogleServerSideToolPartMetadata = {\n thought?: boolean;\n thoughtSignature?: string;\n};\n\ntype GoogleFunctionCallWithId = FunctionCallPart['functionCall'] & {\n id?: string;\n};\n\ntype GoogleFunctionResponseWithId = {\n name: string;\n response: object;\n id?: string;\n};\n\nfunction getGoogleFunctionId(id?: string): string | undefined {\n return id != null && id !== '' ? id : undefined;\n}\n\nfunction createGoogleFunctionResponsePart({\n name,\n response,\n id,\n}: {\n name: string;\n response: object;\n id?: string;\n}): Part {\n const functionId = getGoogleFunctionId(id);\n const functionResponse: GoogleFunctionResponseWithId = {\n name,\n response,\n ...(functionId != null ? { id: functionId } : {}),\n };\n return { functionResponse };\n}\n\n/**\n * Executes a function immediately and returns its result.\n * Functional utility similar to an Immediately Invoked Function Expression (IIFE).\n * @param fn The function to execute.\n * @returns The result of invoking fn.\n */\nexport const iife = <T>(fn: () => T): T => fn();\n\nexport function getMessageAuthor(message: BaseMessage): string {\n const type = message._getType();\n if (ChatMessage.isInstance(message)) {\n return message.role;\n }\n if (type === 'tool') {\n return type;\n }\n return message.name ?? type;\n}\n\n/**\n * Maps a message type to a Google Generative AI chat author.\n * @param message The message to map.\n * @param model The model to use for mapping.\n * @returns The message type mapped to a Google Generative AI chat author.\n */\nexport function convertAuthorToRole(\n author: string\n): (typeof POSSIBLE_ROLES)[number] {\n switch (author) {\n /**\n * Note: Gemini currently is not supporting system messages\n * we will convert them to human messages and merge with following\n * */\n case 'supervisor':\n case 'ai':\n case 'model': // getMessageAuthor returns message.name. code ex.: return message.name ?? type;\n return 'model';\n case 'system':\n return 'system';\n case 'human':\n return 'user';\n case 'tool':\n case 'function':\n return 'function';\n default:\n throw new Error(`Unknown / unsupported author: ${author}`);\n }\n}\n\nfunction messageContentMedia(content: MessageContentComplex): Part {\n if ('mimeType' in content && 'data' in content) {\n return {\n inlineData: {\n mimeType: content.mimeType,\n data: content.data,\n },\n };\n }\n if ('mimeType' in content && 'fileUri' in content) {\n return {\n fileData: {\n mimeType: content.mimeType,\n fileUri: content.fileUri,\n },\n };\n }\n\n throw new Error('Invalid media content');\n}\n\nfunction isGoogleServerSideToolPart(\n content: MessageContentComplex\n): content is MessageContentComplex & GoogleServerSideToolPart {\n return (\n 'toolCall' in content ||\n 'toolResponse' in content ||\n content.type === 'toolCall' ||\n content.type === 'toolResponse'\n );\n}\n\nfunction convertGoogleServerSideToolPart(\n content: MessageContentComplex & GoogleServerSideToolPart\n): Part {\n const metadata: GoogleServerSideToolPartMetadata = {};\n if ('thought' in content && typeof content.thought === 'boolean') {\n metadata.thought = content.thought;\n }\n if (\n 'thoughtSignature' in content &&\n typeof content.thoughtSignature === 'string'\n ) {\n metadata.thoughtSignature = content.thoughtSignature;\n }\n if ('toolCall' in content && content.toolCall != null) {\n return { toolCall: content.toolCall, ...metadata } as unknown as Part;\n }\n if ('toolResponse' in content && content.toolResponse != null) {\n return {\n toolResponse: content.toolResponse,\n ...metadata,\n } as unknown as Part;\n }\n\n return content as Part;\n}\n\nfunction convertGoogleServerSideToolResponsePart(\n part: Part\n): GoogleServerSideToolPart | undefined {\n if (\n 'toolCall' in part &&\n typeof part.toolCall === 'object' &&\n part.toolCall != null\n ) {\n return { ...part, type: 'toolCall', toolCall: part.toolCall };\n }\n if (\n 'toolResponse' in part &&\n typeof part.toolResponse === 'object' &&\n part.toolResponse != null\n ) {\n return { ...part, type: 'toolResponse', toolResponse: part.toolResponse };\n }\n return undefined;\n}\n\nfunction inferToolNameFromPreviousMessages(\n message: ToolMessage | ToolMessageChunk,\n previousMessages: BaseMessage[]\n): string | undefined {\n return previousMessages\n .map((msg) => {\n if (isAIMessage(msg)) {\n return msg.tool_calls ?? [];\n }\n return [];\n })\n .flat()\n .find((toolCall) => {\n return toolCall.id === message.tool_call_id;\n })?.name;\n}\n\nfunction _getStandardContentBlockConverter(\n isMultimodalModel: boolean\n): StandardContentBlockConverter<{\n text: TextPart;\n image: FileDataPart | InlineDataPart;\n audio: FileDataPart | InlineDataPart;\n file: FileDataPart | InlineDataPart | TextPart;\n}> {\n const standardContentBlockConverter: StandardContentBlockConverter<{\n text: TextPart;\n image: FileDataPart | InlineDataPart;\n audio: FileDataPart | InlineDataPart;\n file: FileDataPart | InlineDataPart | TextPart;\n }> = {\n providerName: 'Google Gemini',\n\n fromStandardTextBlock(block) {\n return {\n text: block.text,\n };\n },\n\n fromStandardImageBlock(block): FileDataPart | InlineDataPart {\n if (!isMultimodalModel) {\n throw new Error('This model does not support images');\n }\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (data) {\n return {\n inlineData: {\n mimeType: data.mime_type,\n data: data.data,\n },\n };\n } else {\n return {\n fileData: {\n mimeType: block.mime_type ?? '',\n fileUri: block.url,\n },\n };\n }\n }\n\n if (block.source_type === 'base64') {\n return {\n inlineData: {\n mimeType: block.mime_type ?? '',\n data: block.data,\n },\n };\n }\n\n throw new Error(`Unsupported source type: ${block.source_type}`);\n },\n\n fromStandardAudioBlock(block): FileDataPart | InlineDataPart {\n if (!isMultimodalModel) {\n throw new Error('This model does not support audio');\n }\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (data) {\n return {\n inlineData: {\n mimeType: data.mime_type,\n data: data.data,\n },\n };\n } else {\n return {\n fileData: {\n mimeType: block.mime_type ?? '',\n fileUri: block.url,\n },\n };\n }\n }\n\n if (block.source_type === 'base64') {\n return {\n inlineData: {\n mimeType: block.mime_type ?? '',\n data: block.data,\n },\n };\n }\n\n throw new Error(`Unsupported source type: ${block.source_type}`);\n },\n\n fromStandardFileBlock(block): FileDataPart | InlineDataPart | TextPart {\n if (!isMultimodalModel) {\n throw new Error('This model does not support files');\n }\n if (block.source_type === 'text') {\n return {\n text: block.text,\n };\n }\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (data) {\n return {\n inlineData: {\n mimeType: data.mime_type,\n data: data.data,\n },\n };\n } else {\n return {\n fileData: {\n mimeType: block.mime_type ?? '',\n fileUri: block.url,\n },\n };\n }\n }\n\n if (block.source_type === 'base64') {\n return {\n inlineData: {\n mimeType: block.mime_type ?? '',\n data: block.data,\n },\n };\n }\n throw new Error(`Unsupported source type: ${block.source_type}`);\n },\n };\n return standardContentBlockConverter;\n}\n\nfunction _convertLangChainContentToPart(\n content: MessageContentComplex,\n isMultimodalModel: boolean\n): Part | undefined {\n if (isDataContentBlock(content)) {\n return convertToProviderContentBlock(\n content,\n _getStandardContentBlockConverter(isMultimodalModel)\n );\n }\n\n if (isGoogleServerSideToolPart(content)) {\n return convertGoogleServerSideToolPart(content);\n }\n\n if (content.type === 'text') {\n return { text: content.text };\n } else if (content.type === 'executableCode') {\n return { executableCode: content.executableCode };\n } else if (content.type === 'codeExecutionResult') {\n return { codeExecutionResult: content.codeExecutionResult };\n } else if (content.type === 'image_url') {\n if (!isMultimodalModel) {\n throw new Error('This model does not support images');\n }\n let source: string;\n if (typeof content.image_url === 'string') {\n source = content.image_url;\n } else if (\n typeof content.image_url === 'object' &&\n 'url' in content.image_url\n ) {\n source = content.image_url.url;\n } else {\n throw new Error('Please provide image as base64 encoded data URL');\n }\n const [dm, data] = source.split(',');\n if (!dm.startsWith('data:')) {\n throw new Error('Please provide image as base64 encoded data URL');\n }\n\n const [mimeType, encoding] = dm.replace(/^data:/, '').split(';');\n if (encoding !== 'base64') {\n throw new Error('Please provide image as base64 encoded data URL');\n }\n\n return {\n inlineData: {\n data,\n mimeType,\n },\n };\n } else if (content.type === 'media') {\n return messageContentMedia(content);\n } else if (content.type === 'tool_use') {\n return {\n functionCall: {\n name: content.name,\n args: content.input,\n },\n };\n } else if (\n content.type?.includes('/') === true &&\n // Ensure it's a single slash.\n content.type.split('/').length === 2 &&\n 'data' in content &&\n typeof content.data === 'string'\n ) {\n return {\n inlineData: {\n mimeType: content.type,\n data: content.data,\n },\n };\n } else if ('functionCall' in content) {\n // No action needed here — function calls will be added later from message.tool_calls\n return undefined;\n } else {\n if ('type' in content) {\n throw new Error(`Unknown content type ${content.type}`);\n } else {\n throw new Error(`Unknown content ${JSON.stringify(content)}`);\n }\n }\n}\n\nexport function convertMessageContentToParts(\n message: BaseMessage,\n isMultimodalModel: boolean,\n previousMessages: BaseMessage[],\n model?: string\n): Part[] {\n if (isToolMessage(message)) {\n const messageName =\n message.name ??\n inferToolNameFromPreviousMessages(message, previousMessages);\n if (messageName === undefined) {\n throw new Error(\n `Google requires a tool name for each tool call response, and we could not infer a called tool name for ToolMessage \"${message.id}\" from your passed messages. Please populate a \"name\" field on that ToolMessage explicitly.`\n );\n }\n\n const result = Array.isArray(message.content)\n ? (message.content\n .map((c) => _convertLangChainContentToPart(c, isMultimodalModel))\n .filter((p) => p !== undefined) as Part[])\n : message.content;\n\n if (message.status === 'error') {\n return [\n createGoogleFunctionResponsePart({\n name: messageName,\n // The API expects an object with an `error` field if the function call fails.\n // `error` must be a valid object (not a string or array), so we wrap `message.content` here\n response: { error: { details: result } },\n id: message.tool_call_id,\n }),\n ];\n }\n\n return [\n createGoogleFunctionResponsePart({\n name: messageName,\n // again, can't have a string or array value for `response`, so we wrap it as an object here\n response: { result },\n id: message.tool_call_id,\n }),\n ];\n }\n\n let functionCalls: FunctionCallPart[] = [];\n const messageParts: Part[] = [];\n\n if (typeof message.content === 'string' && message.content) {\n messageParts.push({ text: message.content });\n }\n\n if (Array.isArray(message.content)) {\n messageParts.push(\n ...(message.content\n .map((c) => _convertLangChainContentToPart(c, isMultimodalModel))\n .filter((p) => p !== undefined) as Part[])\n );\n }\n\n const functionThoughtSignatures = (\n message.additional_kwargs as BaseMessage['additional_kwargs'] | undefined\n )?.[_FUNCTION_CALL_THOUGHT_SIGNATURES_MAP_KEY] as\n | Record<string, string>\n | undefined;\n\n if (isAIMessage(message) && (message.tool_calls?.length ?? 0) > 0) {\n functionCalls = (message.tool_calls ?? []).map((tc) => {\n const thoughtSignature = iife(() => {\n if (tc.id != null && tc.id !== '') {\n const signature = functionThoughtSignatures?.[tc.id];\n if (signature != null && signature !== '') {\n return signature;\n }\n }\n if (model?.includes('gemini-3') === true) {\n return DUMMY_SIGNATURE;\n }\n return '';\n });\n const functionId = getGoogleFunctionId(tc.id);\n const functionCall: GoogleFunctionCallWithId = {\n name: tc.name,\n args: tc.args,\n ...(functionId != null ? { id: functionId } : {}),\n };\n\n return {\n functionCall,\n ...(thoughtSignature ? { thoughtSignature } : {}),\n };\n });\n }\n\n return [...messageParts, ...functionCalls];\n}\n\nexport function convertBaseMessagesToContent(\n messages: BaseMessage[],\n isMultimodalModel: boolean,\n convertSystemMessageToHumanContent: boolean = false,\n\n model?: string\n): Content[] | undefined {\n return messages.reduce<{\n content: Content[] | undefined;\n mergeWithPreviousContent: boolean;\n }>(\n (acc, message, index) => {\n if (!isBaseMessage(message)) {\n throw new Error('Unsupported message input');\n }\n const author = getMessageAuthor(message);\n if (author === 'system' && index !== 0) {\n throw new Error('System message should be the first one');\n }\n const role = convertAuthorToRole(author);\n\n const prevContent = acc.content?.[acc.content.length];\n if (\n !acc.mergeWithPreviousContent &&\n prevContent &&\n prevContent.role === role\n ) {\n throw new Error(\n 'Google Generative AI requires alternate messages between authors'\n );\n }\n\n const parts = convertMessageContentToParts(\n message,\n isMultimodalModel,\n messages.slice(0, index),\n model\n );\n\n if (acc.mergeWithPreviousContent) {\n const prevContent = acc.content?.[acc.content.length - 1];\n if (!prevContent) {\n throw new Error(\n 'There was a problem parsing your system message. Please try a prompt without one.'\n );\n }\n prevContent.parts.push(...parts);\n\n return {\n mergeWithPreviousContent: false,\n content: acc.content,\n };\n }\n let actualRole = role;\n if (\n actualRole === 'function' ||\n (actualRole === 'system' && !convertSystemMessageToHumanContent)\n ) {\n // GenerativeAI API will throw an error if the role is not \"user\" or \"model.\"\n actualRole = 'user';\n }\n const content: Content = {\n role: actualRole,\n parts,\n };\n return {\n mergeWithPreviousContent:\n author === 'system' && !convertSystemMessageToHumanContent,\n content: [...(acc.content ?? []), content],\n };\n },\n { content: [], mergeWithPreviousContent: false }\n ).content;\n}\n\nexport function convertResponseContentToChatGenerationChunk(\n response: EnhancedGenerateContentResponse,\n extra: {\n usageMetadata?: UsageMetadata | undefined;\n index: number;\n }\n): ChatGenerationChunk | null {\n if (!response.candidates || response.candidates.length === 0) {\n return null;\n }\n const [candidate] = response.candidates as [\n Partial<GenerateContentCandidate> | undefined,\n ];\n const { content: candidateContent, ...generationInfo } = candidate ?? {};\n\n // Extract function calls directly from parts to preserve thoughtSignature\n const functionCalls =\n (candidateContent?.parts as Part[] | undefined)?.reduce(\n (acc, p) => {\n if ('functionCall' in p && p.functionCall) {\n acc.push({\n ...p,\n id:\n 'id' in p.functionCall && typeof p.functionCall.id === 'string'\n ? p.functionCall.id\n : uuidv4(),\n });\n }\n return acc;\n },\n [] as (\n | undefined\n | (FunctionCallPart & { id: string; thoughtSignature?: string })\n )[]\n ) ?? [];\n\n let content: MessageContent | undefined;\n // Checks if some parts do not have text. If false, it means that the content is a string.\n const reasoningParts: string[] = [];\n if (\n candidateContent != null &&\n Array.isArray(candidateContent.parts) &&\n candidateContent.parts.every((p) => 'text' in p)\n ) {\n // content = candidateContent.parts.map((p) => p.text).join('');\n const textParts: string[] = [];\n for (const part of candidateContent.parts) {\n if ('thought' in part && part.thought === true) {\n reasoningParts.push(part.text ?? '');\n continue;\n }\n textParts.push(part.text ?? '');\n }\n content = textParts.join('');\n } else if (candidateContent && Array.isArray(candidateContent.parts)) {\n content = toLangChainContent(\n candidateContent.parts\n .map((p) => {\n if ('text' in p && 'thought' in p && p.thought === true) {\n reasoningParts.push(p.text ?? '');\n return undefined;\n } else if ('text' in p) {\n return {\n type: 'text',\n text: p.text,\n };\n } else if ('executableCode' in p) {\n return {\n type: 'executableCode',\n executableCode: p.executableCode,\n };\n } else if ('codeExecutionResult' in p) {\n return {\n type: 'codeExecutionResult',\n codeExecutionResult: p.codeExecutionResult,\n };\n }\n const serverSideToolPart = convertGoogleServerSideToolResponsePart(p);\n if (serverSideToolPart !== undefined) {\n return serverSideToolPart;\n }\n return p;\n })\n .filter((p) => p !== undefined)\n );\n } else {\n // no content returned - likely due to abnormal stop reason, e.g. malformed function call\n content = [];\n }\n\n let text = '';\n if (typeof content === 'string' && content) {\n text = content;\n } else if (Array.isArray(content)) {\n const block = content.find((b) => 'text' in b) as\n | { text: string }\n | undefined;\n text = block?.text ?? '';\n }\n\n const toolCallChunks: ToolCallChunk[] = [];\n if (functionCalls.length > 0) {\n toolCallChunks.push(\n ...functionCalls.map((fc) => ({\n type: 'tool_call_chunk' as const,\n id: fc?.id,\n name: fc?.functionCall.name,\n args: JSON.stringify(fc?.functionCall.args),\n }))\n );\n }\n\n // Extract thought signatures from function calls for Gemini 3+\n const functionThoughtSignatures = functionCalls.reduce(\n (acc, fc) => {\n if (\n fc &&\n 'thoughtSignature' in fc &&\n typeof fc.thoughtSignature === 'string'\n ) {\n acc[fc.id] = fc.thoughtSignature;\n }\n return acc;\n },\n {} as Record<string, string>\n );\n\n const additional_kwargs: ChatGeneration['message']['additional_kwargs'] = {\n [_FUNCTION_CALL_THOUGHT_SIGNATURES_MAP_KEY]: functionThoughtSignatures,\n };\n\n if (reasoningParts.length > 0) {\n additional_kwargs.reasoning = reasoningParts.join('');\n }\n\n if (candidate?.groundingMetadata) {\n additional_kwargs.groundingMetadata = candidate.groundingMetadata;\n }\n\n const isFinalChunk =\n response.candidates[0]?.finishReason === 'STOP' ||\n response.candidates[0]?.finishReason === 'MAX_TOKENS' ||\n response.candidates[0]?.finishReason === 'SAFETY';\n\n return new ChatGenerationChunk({\n text,\n message: new AIMessageChunk({\n content: content,\n name: !candidateContent ? undefined : candidateContent.role,\n tool_call_chunks: toolCallChunks,\n // Each chunk can have unique \"generationInfo\", and merging strategy is unclear,\n // so leave blank for now.\n additional_kwargs,\n usage_metadata: isFinalChunk ? extra.usageMetadata : undefined,\n }),\n generationInfo,\n });\n}\n\n/**\n * Maps a Google GenerateContentResult to a LangChain ChatResult\n */\nexport function mapGenerateContentResultToChatResult(\n response: EnhancedGenerateContentResponse,\n extra?: {\n usageMetadata: UsageMetadata | undefined;\n }\n): ChatResult {\n if (!response.candidates || response.candidates.length === 0) {\n return {\n generations: [],\n llmOutput: {\n filters: response.promptFeedback,\n },\n };\n }\n const [candidate] = response.candidates as [\n Partial<GenerateContentCandidate> | undefined,\n ];\n const { content: candidateContent, ...generationInfo } = candidate ?? {};\n\n // Extract function calls directly from parts to preserve thoughtSignature\n const functionCalls =\n candidateContent?.parts.reduce(\n (acc, p) => {\n if ('functionCall' in p && p.functionCall) {\n acc.push({\n ...p,\n id:\n 'id' in p.functionCall && typeof p.functionCall.id === 'string'\n ? p.functionCall.id\n : uuidv4(),\n });\n }\n return acc;\n },\n [] as (FunctionCallPart & { id: string; thoughtSignature?: string })[]\n ) ?? [];\n\n let content: MessageContent | undefined;\n const reasoningParts: string[] = [];\n if (\n Array.isArray(candidateContent?.parts) &&\n candidateContent.parts.length === 1 &&\n (candidateContent.parts[0].text ?? '') !== '' &&\n !(\n 'thought' in candidateContent.parts[0] &&\n candidateContent.parts[0].thought === true\n )\n ) {\n content = candidateContent.parts[0].text;\n } else if (\n Array.isArray(candidateContent?.parts) &&\n candidateContent.parts.length > 0\n ) {\n content = toLangChainContent(\n candidateContent.parts\n .map((p) => {\n if ('text' in p && 'thought' in p && p.thought === true) {\n reasoningParts.push(p.text ?? '');\n return undefined;\n } else if ('text' in p) {\n return {\n type: 'text',\n text: p.text,\n };\n } else if ('executableCode' in p) {\n return {\n type: 'executableCode',\n executableCode: p.executableCode,\n };\n } else if ('codeExecutionResult' in p) {\n return {\n type: 'codeExecutionResult',\n codeExecutionResult: p.codeExecutionResult,\n };\n }\n const serverSideToolPart = convertGoogleServerSideToolResponsePart(p);\n if (serverSideToolPart !== undefined) {\n return serverSideToolPart;\n }\n return p;\n })\n .filter((p) => p !== undefined)\n );\n } else {\n content = [];\n }\n let text = '';\n if (typeof content === 'string') {\n text = content;\n } else if (Array.isArray(content) && content.length > 0) {\n const block = content.find((b) => 'text' in b) as\n | { text: string }\n | undefined;\n text = block?.text ?? text;\n }\n\n const additional_kwargs: ChatGeneration['message']['additional_kwargs'] = {\n ...generationInfo,\n };\n if (reasoningParts.length > 0) {\n additional_kwargs.reasoning = reasoningParts.join('');\n }\n\n // Extract thought signatures from function calls for Gemini 3+\n const functionThoughtSignatures = functionCalls.reduce(\n (acc, fc) => {\n if ('thoughtSignature' in fc && typeof fc.thoughtSignature === 'string') {\n acc[fc.id] = fc.thoughtSignature;\n }\n return acc;\n },\n {} as Record<string, string>\n );\n\n const tool_calls = functionCalls.map((fc) => ({\n type: 'tool_call' as const,\n id: fc.id,\n name: fc.functionCall.name,\n args: fc.functionCall.args,\n }));\n\n // Store thought signatures map for later retrieval\n additional_kwargs[_FUNCTION_CALL_THOUGHT_SIGNATURES_MAP_KEY] =\n functionThoughtSignatures;\n\n const generation: ChatGeneration = {\n text,\n message: new AIMessage({\n content,\n tool_calls,\n additional_kwargs,\n usage_metadata: extra?.usageMetadata,\n }),\n generationInfo,\n };\n return {\n generations: [generation],\n llmOutput: {\n tokenUsage: {\n promptTokens: extra?.usageMetadata?.input_tokens,\n completionTokens: extra?.usageMetadata?.output_tokens,\n totalTokens: extra?.usageMetadata?.total_tokens,\n },\n },\n };\n}\n\nexport function convertToGenerativeAITools(\n tools: GoogleGenerativeAIToolType[]\n): GoogleGenerativeAIFunctionDeclarationsTool[] {\n if (\n tools.every(\n (tool) =>\n 'functionDeclarations' in tool &&\n Array.isArray(tool.functionDeclarations)\n )\n ) {\n return tools as GoogleGenerativeAIFunctionDeclarationsTool[];\n }\n return [\n {\n functionDeclarations: tools.map(\n (tool): GenerativeAIFunctionDeclaration => {\n if (isLangChainTool(tool)) {\n const jsonSchema = schemaToGenerativeAIParameters(tool.schema);\n if (\n jsonSchema.type === 'object' &&\n 'properties' in jsonSchema &&\n Object.keys(jsonSchema.properties).length === 0\n ) {\n return {\n name: tool.name,\n description: tool.description,\n };\n }\n return {\n name: tool.name,\n description: tool.description,\n parameters: jsonSchema,\n };\n }\n if (isOpenAITool(tool)) {\n return {\n name: tool.function.name,\n description:\n tool.function.description ?? 'A function available to call.',\n parameters: jsonSchemaToGeminiParameters(\n tool.function.parameters\n ),\n };\n }\n return tool as unknown as GenerativeAIFunctionDeclaration;\n }\n ),\n },\n ];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"common.mjs","names":["uuidv4"],"sources":["../../../../../src/llm/google/utils/common.ts"],"sourcesContent":["import { v4 as uuidv4 } from 'uuid';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport { ToolCallChunk } from '@langchain/core/messages/tool';\nimport { isOpenAITool } from '@langchain/core/language_models/base';\nimport { isLangChainTool } from '@langchain/core/utils/function_calling';\nimport {\n AIMessage,\n AIMessageChunk,\n BaseMessage,\n ChatMessage,\n ToolMessage,\n ToolMessageChunk,\n MessageContent,\n MessageContentComplex,\n UsageMetadata,\n isAIMessage,\n isBaseMessage,\n isToolMessage,\n StandardContentBlockConverter,\n parseBase64DataUrl,\n convertToProviderContentBlock,\n isDataContentBlock,\n} from '@langchain/core/messages';\nimport {\n POSSIBLE_ROLES,\n type Part,\n type Content,\n type TextPart,\n type FileDataPart,\n type InlineDataPart,\n type FunctionCallPart,\n type GenerateContentCandidate,\n type EnhancedGenerateContentResponse,\n type FunctionDeclaration as GenerativeAIFunctionDeclaration,\n type FunctionDeclarationsTool as GoogleGenerativeAIFunctionDeclarationsTool,\n} from '@google/generative-ai';\nimport type { ChatGeneration, ChatResult } from '@langchain/core/outputs';\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';\nimport {\n jsonSchemaToGeminiParameters,\n schemaToGenerativeAIParameters,\n} from './zod_to_genai_parameters';\nimport { toLangChainContent } from '@/messages/langchain';\nimport { GoogleGenerativeAIToolType } from '../types';\n\nexport const _FUNCTION_CALL_THOUGHT_SIGNATURES_MAP_KEY =\n '__gemini_function_call_thought_signatures__';\n\nconst DUMMY_SIGNATURE =\n 'ErYCCrMCAdHtim9kOoOkrPiCNVsmlpMIKd7ZMxgiFbVQOkgp7nlLcDMzVsZwIzvuT7nQROivoXA72ccC2lSDvR0Gh7dkWaGuj7ctv6t7ZceHnecx0QYa+ix8tYpRfjhyWozQ49lWiws6+YGjCt10KRTyWsZ2h6O7iHTYJwKIRwGUHRKy/qK/6kFxJm5ML00gLq4D8s5Z6DBpp2ZlR+uF4G8jJgeWQgyHWVdx2wGYElaceVAc66tZdPQRdOHpWtgYSI1YdaXgVI8KHY3/EfNc2YqqMIulvkDBAnuMhkAjV9xmBa54Tq+ih3Im4+r3DzqhGqYdsSkhS0kZMwte4Hjs65dZzCw9lANxIqYi1DJ639WNPYihp/DCJCos7o+/EeSPJaio5sgWDyUnMGkY1atsJZ+m7pj7DD5tvQ==';\n\ntype GoogleServerSideToolPart = Part & {\n type?: 'toolCall' | 'toolResponse';\n toolCall?: object;\n toolResponse?: object;\n};\n\ntype GoogleServerSideToolPartMetadata = {\n thought?: boolean;\n thoughtSignature?: string;\n};\n\ntype GoogleFunctionCallWithId = FunctionCallPart['functionCall'] & {\n id?: string;\n};\n\ntype GoogleFunctionResponseWithId = {\n name: string;\n response: object;\n id?: string;\n};\n\nfunction getGoogleFunctionId(id?: string): string | undefined {\n return id != null && id !== '' ? id : undefined;\n}\n\nfunction createGoogleFunctionResponsePart({\n name,\n response,\n id,\n}: {\n name: string;\n response: object;\n id?: string;\n}): Part {\n const functionId = getGoogleFunctionId(id);\n const functionResponse: GoogleFunctionResponseWithId = {\n name,\n response,\n ...(functionId != null ? { id: functionId } : {}),\n };\n return { functionResponse };\n}\n\n/**\n * Executes a function immediately and returns its result.\n * Functional utility similar to an Immediately Invoked Function Expression (IIFE).\n * @param fn The function to execute.\n * @returns The result of invoking fn.\n */\nexport const iife = <T>(fn: () => T): T => fn();\n\nexport function getMessageAuthor(message: BaseMessage): string {\n const type = message._getType();\n if (ChatMessage.isInstance(message)) {\n return message.role;\n }\n if (type === 'tool') {\n return type;\n }\n return message.name ?? type;\n}\n\n/**\n * Maps a message type to a Google Generative AI chat author.\n * @param message The message to map.\n * @param model The model to use for mapping.\n * @returns The message type mapped to a Google Generative AI chat author.\n */\nexport function convertAuthorToRole(\n author: string\n): (typeof POSSIBLE_ROLES)[number] {\n switch (author) {\n /**\n * Note: Gemini currently is not supporting system messages\n * we will convert them to human messages and merge with following\n * */\n case 'supervisor':\n case 'ai':\n case 'model': // getMessageAuthor returns message.name. code ex.: return message.name ?? type;\n return 'model';\n case 'system':\n return 'system';\n case 'human':\n return 'user';\n case 'tool':\n case 'function':\n return 'function';\n default:\n throw new Error(`Unknown / unsupported author: ${author}`);\n }\n}\n\nfunction messageContentMedia(content: MessageContentComplex): Part {\n if ('mimeType' in content && 'data' in content) {\n return {\n inlineData: {\n mimeType: content.mimeType,\n data: content.data,\n },\n };\n }\n if ('mimeType' in content && 'fileUri' in content) {\n return {\n fileData: {\n mimeType: content.mimeType,\n fileUri: content.fileUri,\n },\n };\n }\n\n throw new Error('Invalid media content');\n}\n\nfunction isGoogleServerSideToolPart(\n content: MessageContentComplex\n): content is MessageContentComplex & GoogleServerSideToolPart {\n return (\n 'toolCall' in content ||\n 'toolResponse' in content ||\n content.type === 'toolCall' ||\n content.type === 'toolResponse'\n );\n}\n\nfunction convertGoogleServerSideToolPart(\n content: MessageContentComplex & GoogleServerSideToolPart\n): Part {\n const metadata: GoogleServerSideToolPartMetadata = {};\n if ('thought' in content && typeof content.thought === 'boolean') {\n metadata.thought = content.thought;\n }\n if (\n 'thoughtSignature' in content &&\n typeof content.thoughtSignature === 'string'\n ) {\n metadata.thoughtSignature = content.thoughtSignature;\n }\n if ('toolCall' in content && content.toolCall != null) {\n return { toolCall: content.toolCall, ...metadata } as unknown as Part;\n }\n if ('toolResponse' in content && content.toolResponse != null) {\n return {\n toolResponse: content.toolResponse,\n ...metadata,\n } as unknown as Part;\n }\n\n return content as Part;\n}\n\nfunction convertGoogleServerSideToolResponsePart(\n part: Part\n): GoogleServerSideToolPart | undefined {\n if (\n 'toolCall' in part &&\n typeof part.toolCall === 'object' &&\n part.toolCall != null\n ) {\n return { ...part, type: 'toolCall', toolCall: part.toolCall };\n }\n if (\n 'toolResponse' in part &&\n typeof part.toolResponse === 'object' &&\n part.toolResponse != null\n ) {\n return { ...part, type: 'toolResponse', toolResponse: part.toolResponse };\n }\n return undefined;\n}\n\nfunction inferToolNameFromPreviousMessages(\n message: ToolMessage | ToolMessageChunk,\n previousMessages: BaseMessage[]\n): string | undefined {\n return previousMessages\n .map((msg) => {\n if (isAIMessage(msg)) {\n return msg.tool_calls ?? [];\n }\n return [];\n })\n .flat()\n .find((toolCall) => {\n return toolCall.id === message.tool_call_id;\n })?.name;\n}\n\nfunction _getStandardContentBlockConverter(\n isMultimodalModel: boolean\n): StandardContentBlockConverter<{\n text: TextPart;\n image: FileDataPart | InlineDataPart;\n audio: FileDataPart | InlineDataPart;\n file: FileDataPart | InlineDataPart | TextPart;\n}> {\n const standardContentBlockConverter: StandardContentBlockConverter<{\n text: TextPart;\n image: FileDataPart | InlineDataPart;\n audio: FileDataPart | InlineDataPart;\n file: FileDataPart | InlineDataPart | TextPart;\n }> = {\n providerName: 'Google Gemini',\n\n fromStandardTextBlock(block) {\n return {\n text: block.text,\n };\n },\n\n fromStandardImageBlock(block): FileDataPart | InlineDataPart {\n if (!isMultimodalModel) {\n throw new Error('This model does not support images');\n }\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (data) {\n return {\n inlineData: {\n mimeType: data.mime_type,\n data: data.data,\n },\n };\n } else {\n return {\n fileData: {\n mimeType: block.mime_type ?? '',\n fileUri: block.url,\n },\n };\n }\n }\n\n if (block.source_type === 'base64') {\n return {\n inlineData: {\n mimeType: block.mime_type ?? '',\n data: block.data,\n },\n };\n }\n\n throw new Error(`Unsupported source type: ${block.source_type}`);\n },\n\n fromStandardAudioBlock(block): FileDataPart | InlineDataPart {\n if (!isMultimodalModel) {\n throw new Error('This model does not support audio');\n }\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (data) {\n return {\n inlineData: {\n mimeType: data.mime_type,\n data: data.data,\n },\n };\n } else {\n return {\n fileData: {\n mimeType: block.mime_type ?? '',\n fileUri: block.url,\n },\n };\n }\n }\n\n if (block.source_type === 'base64') {\n return {\n inlineData: {\n mimeType: block.mime_type ?? '',\n data: block.data,\n },\n };\n }\n\n throw new Error(`Unsupported source type: ${block.source_type}`);\n },\n\n fromStandardFileBlock(block): FileDataPart | InlineDataPart | TextPart {\n if (!isMultimodalModel) {\n throw new Error('This model does not support files');\n }\n if (block.source_type === 'text') {\n return {\n text: block.text,\n };\n }\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (data) {\n return {\n inlineData: {\n mimeType: data.mime_type,\n data: data.data,\n },\n };\n } else {\n return {\n fileData: {\n mimeType: block.mime_type ?? '',\n fileUri: block.url,\n },\n };\n }\n }\n\n if (block.source_type === 'base64') {\n return {\n inlineData: {\n mimeType: block.mime_type ?? '',\n data: block.data,\n },\n };\n }\n throw new Error(`Unsupported source type: ${block.source_type}`);\n },\n };\n return standardContentBlockConverter;\n}\n\nfunction _convertLangChainContentToPart(\n content: MessageContentComplex,\n isMultimodalModel: boolean\n): Part | undefined {\n if (isDataContentBlock(content)) {\n return convertToProviderContentBlock(\n content,\n _getStandardContentBlockConverter(isMultimodalModel)\n );\n }\n\n if (isGoogleServerSideToolPart(content)) {\n return convertGoogleServerSideToolPart(content);\n }\n\n if (content.type === 'text') {\n return { text: content.text };\n } else if (content.type === 'executableCode') {\n return { executableCode: content.executableCode };\n } else if (content.type === 'codeExecutionResult') {\n return { codeExecutionResult: content.codeExecutionResult };\n } else if (content.type === 'image_url') {\n if (!isMultimodalModel) {\n throw new Error('This model does not support images');\n }\n let source: string;\n if (typeof content.image_url === 'string') {\n source = content.image_url;\n } else if (\n typeof content.image_url === 'object' &&\n 'url' in content.image_url\n ) {\n source = content.image_url.url;\n } else {\n throw new Error('Please provide image as base64 encoded data URL');\n }\n const [dm, data] = source.split(',');\n if (!dm.startsWith('data:')) {\n throw new Error('Please provide image as base64 encoded data URL');\n }\n\n const [mimeType, encoding] = dm.replace(/^data:/, '').split(';');\n if (encoding !== 'base64') {\n throw new Error('Please provide image as base64 encoded data URL');\n }\n\n return {\n inlineData: {\n data,\n mimeType,\n },\n };\n } else if (content.type === 'media') {\n return messageContentMedia(content);\n } else if (content.type === 'tool_use') {\n return {\n functionCall: {\n name: content.name,\n args: content.input,\n },\n };\n } else if (\n content.type?.includes('/') === true &&\n // Ensure it's a single slash.\n content.type.split('/').length === 2 &&\n 'data' in content &&\n typeof content.data === 'string'\n ) {\n return {\n inlineData: {\n mimeType: content.type,\n data: content.data,\n },\n };\n } else if ('functionCall' in content) {\n // No action needed here — function calls will be added later from message.tool_calls\n return undefined;\n } else {\n if ('type' in content) {\n throw new Error(`Unknown content type ${content.type}`);\n } else {\n throw new Error(`Unknown content ${JSON.stringify(content)}`);\n }\n }\n}\n\nexport function convertMessageContentToParts(\n message: BaseMessage,\n isMultimodalModel: boolean,\n previousMessages: BaseMessage[],\n model?: string\n): Part[] {\n if (isToolMessage(message)) {\n const messageName =\n message.name ??\n inferToolNameFromPreviousMessages(message, previousMessages);\n if (messageName === undefined) {\n throw new Error(\n `Google requires a tool name for each tool call response, and we could not infer a called tool name for ToolMessage \"${message.id}\" from your passed messages. Please populate a \"name\" field on that ToolMessage explicitly.`\n );\n }\n\n const result = Array.isArray(message.content)\n ? (message.content\n .map((c) => _convertLangChainContentToPart(c, isMultimodalModel))\n .filter((p) => p !== undefined) as Part[])\n : message.content;\n\n if (message.status === 'error') {\n return [\n createGoogleFunctionResponsePart({\n name: messageName,\n // The API expects an object with an `error` field if the function call fails.\n // `error` must be a valid object (not a string or array), so we wrap `message.content` here\n response: { error: { details: result } },\n id: message.tool_call_id,\n }),\n ];\n }\n\n return [\n createGoogleFunctionResponsePart({\n name: messageName,\n // again, can't have a string or array value for `response`, so we wrap it as an object here\n response: { result },\n id: message.tool_call_id,\n }),\n ];\n }\n\n let functionCalls: FunctionCallPart[] = [];\n const messageParts: Part[] = [];\n\n if (typeof message.content === 'string' && message.content) {\n messageParts.push({ text: message.content });\n }\n\n if (Array.isArray(message.content)) {\n messageParts.push(\n ...(message.content\n .map((c) => _convertLangChainContentToPart(c, isMultimodalModel))\n .filter((p) => p !== undefined) as Part[])\n );\n }\n\n const functionThoughtSignatures = (\n message.additional_kwargs as BaseMessage['additional_kwargs'] | undefined\n )?.[_FUNCTION_CALL_THOUGHT_SIGNATURES_MAP_KEY] as\n | Record<string, string>\n | undefined;\n\n if (isAIMessage(message) && (message.tool_calls?.length ?? 0) > 0) {\n functionCalls = (message.tool_calls ?? []).map((tc) => {\n const thoughtSignature = iife(() => {\n if (tc.id != null && tc.id !== '') {\n const signature = functionThoughtSignatures?.[tc.id];\n if (signature != null && signature !== '') {\n return signature;\n }\n }\n if (model?.includes('gemini-3') === true) {\n return DUMMY_SIGNATURE;\n }\n return '';\n });\n const functionId = getGoogleFunctionId(tc.id);\n const functionCall: GoogleFunctionCallWithId = {\n name: tc.name,\n args: tc.args,\n ...(functionId != null ? { id: functionId } : {}),\n };\n\n return {\n functionCall,\n ...(thoughtSignature ? { thoughtSignature } : {}),\n };\n });\n }\n\n return [...messageParts, ...functionCalls];\n}\n\nexport function convertBaseMessagesToContent(\n messages: BaseMessage[],\n isMultimodalModel: boolean,\n convertSystemMessageToHumanContent: boolean = false,\n\n model?: string\n): Content[] | undefined {\n return messages.reduce<{\n content: Content[] | undefined;\n mergeWithPreviousContent: boolean;\n }>(\n (acc, message, index) => {\n if (!isBaseMessage(message)) {\n throw new Error('Unsupported message input');\n }\n const author = getMessageAuthor(message);\n if (author === 'system' && index !== 0) {\n throw new Error('System message should be the first one');\n }\n const role = convertAuthorToRole(author);\n\n const prevContent = acc.content?.[acc.content.length];\n if (\n !acc.mergeWithPreviousContent &&\n prevContent &&\n prevContent.role === role\n ) {\n throw new Error(\n 'Google Generative AI requires alternate messages between authors'\n );\n }\n\n const parts = convertMessageContentToParts(\n message,\n isMultimodalModel,\n messages.slice(0, index),\n model\n );\n\n if (acc.mergeWithPreviousContent) {\n const prevContent = acc.content?.[acc.content.length - 1];\n if (!prevContent) {\n throw new Error(\n 'There was a problem parsing your system message. Please try a prompt without one.'\n );\n }\n prevContent.parts.push(...parts);\n\n return {\n mergeWithPreviousContent: false,\n content: acc.content,\n };\n }\n let actualRole = role;\n if (\n actualRole === 'function' ||\n (actualRole === 'system' && !convertSystemMessageToHumanContent)\n ) {\n // GenerativeAI API will throw an error if the role is not \"user\" or \"model.\"\n actualRole = 'user';\n }\n const content: Content = {\n role: actualRole,\n parts,\n };\n return {\n mergeWithPreviousContent:\n author === 'system' && !convertSystemMessageToHumanContent,\n content: [...(acc.content ?? []), content],\n };\n },\n { content: [], mergeWithPreviousContent: false }\n ).content;\n}\n\nexport function convertResponseContentToChatGenerationChunk(\n response: EnhancedGenerateContentResponse,\n extra: {\n usageMetadata?: UsageMetadata | undefined;\n index: number;\n }\n): ChatGenerationChunk | null {\n if (!response.candidates || response.candidates.length === 0) {\n return null;\n }\n const [candidate] = response.candidates as [\n Partial<GenerateContentCandidate> | undefined,\n ];\n const { content: candidateContent, ...generationInfo } = candidate ?? {};\n\n // Extract function calls directly from parts to preserve thoughtSignature\n const functionCalls =\n (candidateContent?.parts as Part[] | undefined)?.reduce(\n (acc, p) => {\n if ('functionCall' in p && p.functionCall) {\n acc.push({\n ...p,\n id:\n 'id' in p.functionCall && typeof p.functionCall.id === 'string'\n ? p.functionCall.id\n : uuidv4(),\n });\n }\n return acc;\n },\n [] as (\n | undefined\n | (FunctionCallPart & { id: string; thoughtSignature?: string })\n )[]\n ) ?? [];\n\n let content: MessageContent | undefined;\n // Checks if some parts do not have text. If false, it means that the content is a string.\n const reasoningParts: string[] = [];\n if (\n candidateContent != null &&\n Array.isArray(candidateContent.parts) &&\n candidateContent.parts.every((p) => 'text' in p)\n ) {\n // content = candidateContent.parts.map((p) => p.text).join('');\n const textParts: string[] = [];\n for (const part of candidateContent.parts) {\n if ('thought' in part && part.thought === true) {\n reasoningParts.push(part.text ?? '');\n continue;\n }\n textParts.push(part.text ?? '');\n }\n content = textParts.join('');\n } else if (candidateContent && Array.isArray(candidateContent.parts)) {\n content = toLangChainContent(\n candidateContent.parts\n .map((p) => {\n if ('text' in p && 'thought' in p && p.thought === true) {\n reasoningParts.push(p.text ?? '');\n return undefined;\n } else if ('text' in p) {\n return {\n type: 'text',\n text: p.text,\n };\n } else if ('executableCode' in p) {\n return {\n type: 'executableCode',\n executableCode: p.executableCode,\n };\n } else if ('codeExecutionResult' in p) {\n return {\n type: 'codeExecutionResult',\n codeExecutionResult: p.codeExecutionResult,\n };\n }\n const serverSideToolPart = convertGoogleServerSideToolResponsePart(p);\n if (serverSideToolPart !== undefined) {\n return serverSideToolPart;\n }\n return p;\n })\n .filter((p) => p !== undefined)\n );\n } else {\n // no content returned - likely due to abnormal stop reason, e.g. malformed function call\n content = [];\n }\n\n let text = '';\n if (typeof content === 'string' && content) {\n text = content;\n } else if (Array.isArray(content)) {\n const block = content.find((b) => 'text' in b) as\n | { text: string }\n | undefined;\n text = block?.text ?? '';\n }\n\n const toolCallChunks: ToolCallChunk[] = [];\n if (functionCalls.length > 0) {\n toolCallChunks.push(\n ...functionCalls.map((fc) => ({\n type: 'tool_call_chunk' as const,\n id: fc?.id,\n name: fc?.functionCall.name,\n args: JSON.stringify(fc?.functionCall.args),\n }))\n );\n }\n\n // Extract thought signatures from function calls for Gemini 3+\n const functionThoughtSignatures = functionCalls.reduce(\n (acc, fc) => {\n if (\n fc &&\n 'thoughtSignature' in fc &&\n typeof fc.thoughtSignature === 'string'\n ) {\n acc[fc.id] = fc.thoughtSignature;\n }\n return acc;\n },\n {} as Record<string, string>\n );\n\n const additional_kwargs: ChatGeneration['message']['additional_kwargs'] = {\n [_FUNCTION_CALL_THOUGHT_SIGNATURES_MAP_KEY]: functionThoughtSignatures,\n };\n\n if (reasoningParts.length > 0) {\n additional_kwargs.reasoning = reasoningParts.join('');\n }\n\n if (candidate?.groundingMetadata) {\n additional_kwargs.groundingMetadata = candidate.groundingMetadata;\n }\n\n const isFinalChunk =\n response.candidates[0]?.finishReason === 'STOP' ||\n response.candidates[0]?.finishReason === 'MAX_TOKENS' ||\n response.candidates[0]?.finishReason === 'SAFETY';\n\n // The GenAI API delivers function calls as complete objects (never partial\n // arg deltas), so every call on this chunk is sealed on arrival for eager\n // tool execution.\n const response_metadata: Record<string, unknown> | undefined =\n toolCallChunks.length > 0\n ? {\n [STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY]:\n GOOGLE_STREAMED_TOOL_CALL_ADAPTER,\n [STREAMED_TOOL_CALL_SEAL_METADATA_KEY]: { kind: 'all' },\n }\n : undefined;\n\n return new ChatGenerationChunk({\n text,\n message: new AIMessageChunk({\n content: content,\n name: !candidateContent ? undefined : candidateContent.role,\n tool_call_chunks: toolCallChunks,\n // Each chunk can have unique \"generationInfo\", and merging strategy is unclear,\n // so leave blank for now.\n additional_kwargs,\n response_metadata,\n usage_metadata: isFinalChunk ? extra.usageMetadata : undefined,\n }),\n generationInfo,\n });\n}\n\n/**\n * Maps a Google GenerateContentResult to a LangChain ChatResult\n */\nexport function mapGenerateContentResultToChatResult(\n response: EnhancedGenerateContentResponse,\n extra?: {\n usageMetadata: UsageMetadata | undefined;\n }\n): ChatResult {\n if (!response.candidates || response.candidates.length === 0) {\n return {\n generations: [],\n llmOutput: {\n filters: response.promptFeedback,\n },\n };\n }\n const [candidate] = response.candidates as [\n Partial<GenerateContentCandidate> | undefined,\n ];\n const { content: candidateContent, ...generationInfo } = candidate ?? {};\n\n // Extract function calls directly from parts to preserve thoughtSignature\n const functionCalls =\n candidateContent?.parts.reduce(\n (acc, p) => {\n if ('functionCall' in p && p.functionCall) {\n acc.push({\n ...p,\n id:\n 'id' in p.functionCall && typeof p.functionCall.id === 'string'\n ? p.functionCall.id\n : uuidv4(),\n });\n }\n return acc;\n },\n [] as (FunctionCallPart & { id: string; thoughtSignature?: string })[]\n ) ?? [];\n\n let content: MessageContent | undefined;\n const reasoningParts: string[] = [];\n if (\n Array.isArray(candidateContent?.parts) &&\n candidateContent.parts.length === 1 &&\n (candidateContent.parts[0].text ?? '') !== '' &&\n !(\n 'thought' in candidateContent.parts[0] &&\n candidateContent.parts[0].thought === true\n )\n ) {\n content = candidateContent.parts[0].text;\n } else if (\n Array.isArray(candidateContent?.parts) &&\n candidateContent.parts.length > 0\n ) {\n content = toLangChainContent(\n candidateContent.parts\n .map((p) => {\n if ('text' in p && 'thought' in p && p.thought === true) {\n reasoningParts.push(p.text ?? '');\n return undefined;\n } else if ('text' in p) {\n return {\n type: 'text',\n text: p.text,\n };\n } else if ('executableCode' in p) {\n return {\n type: 'executableCode',\n executableCode: p.executableCode,\n };\n } else if ('codeExecutionResult' in p) {\n return {\n type: 'codeExecutionResult',\n codeExecutionResult: p.codeExecutionResult,\n };\n }\n const serverSideToolPart = convertGoogleServerSideToolResponsePart(p);\n if (serverSideToolPart !== undefined) {\n return serverSideToolPart;\n }\n return p;\n })\n .filter((p) => p !== undefined)\n );\n } else {\n content = [];\n }\n let text = '';\n if (typeof content === 'string') {\n text = content;\n } else if (Array.isArray(content) && content.length > 0) {\n const block = content.find((b) => 'text' in b) as\n | { text: string }\n | undefined;\n text = block?.text ?? text;\n }\n\n const additional_kwargs: ChatGeneration['message']['additional_kwargs'] = {\n ...generationInfo,\n };\n if (reasoningParts.length > 0) {\n additional_kwargs.reasoning = reasoningParts.join('');\n }\n\n // Extract thought signatures from function calls for Gemini 3+\n const functionThoughtSignatures = functionCalls.reduce(\n (acc, fc) => {\n if ('thoughtSignature' in fc && typeof fc.thoughtSignature === 'string') {\n acc[fc.id] = fc.thoughtSignature;\n }\n return acc;\n },\n {} as Record<string, string>\n );\n\n const tool_calls = functionCalls.map((fc) => ({\n type: 'tool_call' as const,\n id: fc.id,\n name: fc.functionCall.name,\n args: fc.functionCall.args,\n }));\n\n // Store thought signatures map for later retrieval\n additional_kwargs[_FUNCTION_CALL_THOUGHT_SIGNATURES_MAP_KEY] =\n functionThoughtSignatures;\n\n const generation: ChatGeneration = {\n text,\n message: new AIMessage({\n content,\n tool_calls,\n additional_kwargs,\n usage_metadata: extra?.usageMetadata,\n }),\n generationInfo,\n };\n return {\n generations: [generation],\n llmOutput: {\n tokenUsage: {\n promptTokens: extra?.usageMetadata?.input_tokens,\n completionTokens: extra?.usageMetadata?.output_tokens,\n totalTokens: extra?.usageMetadata?.total_tokens,\n },\n },\n };\n}\n\nexport function convertToGenerativeAITools(\n tools: GoogleGenerativeAIToolType[]\n): GoogleGenerativeAIFunctionDeclarationsTool[] {\n if (\n tools.every(\n (tool) =>\n 'functionDeclarations' in tool &&\n Array.isArray(tool.functionDeclarations)\n )\n ) {\n return tools as GoogleGenerativeAIFunctionDeclarationsTool[];\n }\n return [\n {\n functionDeclarations: tools.map(\n (tool): GenerativeAIFunctionDeclaration => {\n if (isLangChainTool(tool)) {\n const jsonSchema = schemaToGenerativeAIParameters(tool.schema);\n if (\n jsonSchema.type === 'object' &&\n 'properties' in jsonSchema &&\n Object.keys(jsonSchema.properties).length === 0\n ) {\n return {\n name: tool.name,\n description: tool.description,\n };\n }\n return {\n name: tool.name,\n description: tool.description,\n parameters: jsonSchema,\n };\n }\n if (isOpenAITool(tool)) {\n return {\n name: tool.function.name,\n description:\n tool.function.description ?? 'A function available to call.',\n parameters: jsonSchemaToGeminiParameters(\n tool.function.parameters\n ),\n };\n }\n return tool as unknown as GenerativeAIFunctionDeclaration;\n }\n ),\n },\n ];\n}\n"],"mappings":"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"}
@@ -75,6 +75,22 @@ async function attemptInvoke({ model, messages, provider, context, onChunk }, co
75
75
  const registry = context?.getOrCreateToolOutputRegistry();
76
76
  const runId = config?.configurable?.run_id;
77
77
  const messagesForProvider = annotateMessagesForLLM(messages, registry, runId);
78
+ /**
79
+ * Stamp the provider that is ACTUALLY serving this invocation onto the
80
+ * callback metadata. `attemptInvoke` is the single funnel for primary,
81
+ * fallback, and summarization model calls, so consumers that need
82
+ * provider attribution per call (the subagent usage-capture handler)
83
+ * read this key instead of trusting static agent config — which is
84
+ * wrong for fallback-served calls — or `ls_provider` — which derived
85
+ * providers inherit from their base class.
86
+ */
87
+ config = {
88
+ ...config,
89
+ metadata: {
90
+ ...config?.metadata ?? {},
91
+ ["__invoked_provider"]: provider
92
+ }
93
+ };
78
94
  if (model.stream) {
79
95
  const stream = await model.stream(messagesForProvider, config);
80
96
  let finalChunk;
@@ -88,7 +104,7 @@ async function attemptInvoke({ model, messages, provider, context, onChunk }, co
88
104
  });
89
105
  }
90
106
  else if (registeredStreamHandler == null) {
91
- const metadata = config?.metadata;
107
+ const metadata = config.metadata;
92
108
  const streamHandler = new ChatModelStreamHandler();
93
109
  for await (const chunk of stream) {
94
110
  const handlingChunk = getStreamHandlingChunk({
@@ -104,7 +120,7 @@ async function attemptInvoke({ model, messages, provider, context, onChunk }, co
104
120
  });
105
121
  }
106
122
  } else {
107
- const metadata = config?.metadata;
123
+ const metadata = config.metadata;
108
124
  for await (const chunk of stream) {
109
125
  const handlingChunk = getStreamHandlingChunk({
110
126
  current: finalChunk,
@@ -128,23 +144,48 @@ async function attemptInvoke({ model, messages, provider, context, onChunk }, co
128
144
  return { messages: [finalMessage] };
129
145
  }
130
146
  /**
147
+ * Best-effort read of the configured model name from client options.
148
+ * Providers disagree on the key (`model` vs `modelName`).
149
+ */
150
+ function extractClientOptionsModel(clientOptions) {
151
+ const options = clientOptions;
152
+ if (typeof options?.model === "string" && options.model !== "") return options.model;
153
+ if (typeof options?.modelName === "string" && options.modelName !== "") return options.modelName;
154
+ }
155
+ /**
131
156
  * Attempts each fallback provider in order until one succeeds.
132
157
  * Throws the last error if all fallbacks fail.
133
158
  */
134
159
  async function tryFallbackProviders({ fallbacks, tools, messages, config, primaryError, context, onChunk }) {
135
160
  let lastError = primaryError;
136
161
  for (const fb of fallbacks) try {
162
+ const fbModel = initializeModel({
163
+ provider: fb.provider,
164
+ clientOptions: fb.clientOptions,
165
+ tools
166
+ });
167
+ /**
168
+ * Stamp the fallback's configured model onto callback metadata so
169
+ * per-call attribution (subagent usage capture) doesn't fall back to
170
+ * the PRIMARY config's model when the provider reports no
171
+ * `ls_model_name`. The serving provider is stamped uniformly by
172
+ * `attemptInvoke` (`INVOKED_PROVIDER`).
173
+ */
174
+ const fbModelName = extractClientOptionsModel(fb.clientOptions);
175
+ const fbConfig = fbModelName == null ? config : {
176
+ ...config,
177
+ metadata: {
178
+ ...config?.metadata ?? {},
179
+ ["__invoked_model"]: fbModelName
180
+ }
181
+ };
137
182
  return await attemptInvoke({
138
- model: initializeModel({
139
- provider: fb.provider,
140
- clientOptions: fb.clientOptions,
141
- tools
142
- }),
183
+ model: fbModel,
143
184
  messages,
144
185
  provider: fb.provider,
145
186
  context,
146
187
  onChunk
147
- }, config);
188
+ }, fbConfig);
148
189
  } catch (e) {
149
190
  lastError = e;
150
191
  continue;