@librechat/agents 3.3.4 → 3.3.5

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 (159) hide show
  1. package/dist/cjs/common/constants.cjs +21 -0
  2. package/dist/cjs/common/constants.cjs.map +1 -1
  3. package/dist/cjs/events.cjs +10 -1
  4. package/dist/cjs/events.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +456 -7
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/hooks/HookRegistry.cjs +25 -0
  8. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  9. package/dist/cjs/hooks/index.cjs +12 -0
  10. package/dist/cjs/hooks/index.cjs.map +1 -1
  11. package/dist/cjs/hooks/types.cjs +1 -0
  12. package/dist/cjs/hooks/types.cjs.map +1 -1
  13. package/dist/cjs/langfuse.cjs +8 -0
  14. package/dist/cjs/langfuse.cjs.map +1 -1
  15. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +1 -3
  16. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  17. package/dist/cjs/llm/invoke.cjs +268 -3
  18. package/dist/cjs/llm/invoke.cjs.map +1 -1
  19. package/dist/cjs/llm/preempt.cjs +132 -0
  20. package/dist/cjs/llm/preempt.cjs.map +1 -0
  21. package/dist/cjs/main.cjs +17 -3
  22. package/dist/cjs/messages/alternation.cjs +92 -0
  23. package/dist/cjs/messages/alternation.cjs.map +1 -0
  24. package/dist/cjs/messages/format.cjs +72 -0
  25. package/dist/cjs/messages/format.cjs.map +1 -1
  26. package/dist/cjs/messages/handoffCue.cjs +63 -0
  27. package/dist/cjs/messages/handoffCue.cjs.map +1 -0
  28. package/dist/cjs/messages/index.cjs +3 -0
  29. package/dist/cjs/messages/injected.cjs +60 -0
  30. package/dist/cjs/messages/injected.cjs.map +1 -0
  31. package/dist/cjs/run.cjs +80 -7
  32. package/dist/cjs/run.cjs.map +1 -1
  33. package/dist/cjs/session/handlers.cjs +18 -9
  34. package/dist/cjs/session/handlers.cjs.map +1 -1
  35. package/dist/cjs/stream.cjs +28 -7
  36. package/dist/cjs/stream.cjs.map +1 -1
  37. package/dist/cjs/tools/ToolNode.cjs +3 -23
  38. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  39. package/dist/cjs/tools/search/keenable-scraper.cjs +90 -0
  40. package/dist/cjs/tools/search/keenable-scraper.cjs.map +1 -0
  41. package/dist/cjs/tools/search/tool.cjs +9 -1
  42. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  43. package/dist/esm/common/constants.mjs +19 -1
  44. package/dist/esm/common/constants.mjs.map +1 -1
  45. package/dist/esm/events.mjs +10 -1
  46. package/dist/esm/events.mjs.map +1 -1
  47. package/dist/esm/graphs/Graph.mjs +455 -6
  48. package/dist/esm/graphs/Graph.mjs.map +1 -1
  49. package/dist/esm/hooks/HookRegistry.mjs +25 -0
  50. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  51. package/dist/esm/hooks/index.mjs +12 -1
  52. package/dist/esm/hooks/index.mjs.map +1 -1
  53. package/dist/esm/hooks/types.mjs +1 -0
  54. package/dist/esm/hooks/types.mjs.map +1 -1
  55. package/dist/esm/langfuse.mjs +9 -1
  56. package/dist/esm/langfuse.mjs.map +1 -1
  57. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +1 -3
  58. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  59. package/dist/esm/llm/invoke.mjs +270 -6
  60. package/dist/esm/llm/invoke.mjs.map +1 -1
  61. package/dist/esm/llm/preempt.mjs +131 -0
  62. package/dist/esm/llm/preempt.mjs.map +1 -0
  63. package/dist/esm/main.mjs +8 -5
  64. package/dist/esm/messages/alternation.mjs +91 -0
  65. package/dist/esm/messages/alternation.mjs.map +1 -0
  66. package/dist/esm/messages/format.mjs +72 -0
  67. package/dist/esm/messages/format.mjs.map +1 -1
  68. package/dist/esm/messages/handoffCue.mjs +61 -0
  69. package/dist/esm/messages/handoffCue.mjs.map +1 -0
  70. package/dist/esm/messages/index.mjs +3 -0
  71. package/dist/esm/messages/injected.mjs +60 -0
  72. package/dist/esm/messages/injected.mjs.map +1 -0
  73. package/dist/esm/run.mjs +80 -7
  74. package/dist/esm/run.mjs.map +1 -1
  75. package/dist/esm/session/handlers.mjs +19 -10
  76. package/dist/esm/session/handlers.mjs.map +1 -1
  77. package/dist/esm/stream.mjs +27 -8
  78. package/dist/esm/stream.mjs.map +1 -1
  79. package/dist/esm/tools/ToolNode.mjs +3 -23
  80. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  81. package/dist/esm/tools/search/keenable-scraper.mjs +88 -0
  82. package/dist/esm/tools/search/keenable-scraper.mjs.map +1 -0
  83. package/dist/esm/tools/search/tool.mjs +9 -1
  84. package/dist/esm/tools/search/tool.mjs.map +1 -1
  85. package/dist/types/common/constants.d.ts +18 -0
  86. package/dist/types/graphs/Graph.d.ts +138 -1
  87. package/dist/types/hooks/HookRegistry.d.ts +15 -0
  88. package/dist/types/hooks/index.d.ts +12 -1
  89. package/dist/types/hooks/types.d.ts +45 -6
  90. package/dist/types/index.d.ts +1 -1
  91. package/dist/types/llm/invoke.d.ts +7 -0
  92. package/dist/types/llm/preempt.d.ts +40 -0
  93. package/dist/types/messages/alternation.d.ts +23 -0
  94. package/dist/types/messages/handoffCue.d.ts +40 -0
  95. package/dist/types/messages/index.d.ts +3 -0
  96. package/dist/types/messages/injected.d.ts +3 -0
  97. package/dist/types/run.d.ts +7 -0
  98. package/dist/types/stream.d.ts +14 -0
  99. package/dist/types/tools/ToolNode.d.ts +0 -7
  100. package/dist/types/tools/search/keenable-scraper.d.ts +15 -0
  101. package/dist/types/tools/search/types.d.ts +31 -2
  102. package/dist/types/types/graph.d.ts +8 -1
  103. package/dist/types/types/run.d.ts +65 -0
  104. package/dist/types/types/stream.d.ts +0 -25
  105. package/package.json +1 -1
  106. package/src/{splitStream.test.ts → aggregator.test.ts} +59 -666
  107. package/src/common/constants.ts +21 -0
  108. package/src/events.ts +15 -1
  109. package/src/graphs/Graph.ts +568 -3
  110. package/src/graphs/__tests__/Graph.contextOverflow.test.ts +18 -7
  111. package/src/graphs/__tests__/Graph.preemptSignal.test.ts +126 -0
  112. package/src/hooks/HookRegistry.ts +40 -0
  113. package/src/hooks/__tests__/preemptBoundary.test.ts +152 -0
  114. package/src/hooks/index.ts +16 -2
  115. package/src/hooks/types.ts +47 -3
  116. package/src/index.ts +1 -1
  117. package/src/langfuse.ts +26 -1
  118. package/src/llm/bedrock/utils/message_inputs.test.ts +82 -0
  119. package/src/llm/bedrock/utils/message_inputs.ts +14 -11
  120. package/src/llm/bedrock/utils/toolResultCachePoint.test.ts +15 -0
  121. package/src/llm/invoke.alternation.test.ts +87 -0
  122. package/src/llm/invoke.handoffCue.test.ts +112 -0
  123. package/src/llm/invoke.ts +417 -8
  124. package/src/llm/preempt.test.ts +323 -0
  125. package/src/llm/preempt.ts +178 -0
  126. package/src/messages/alternation.test.ts +212 -0
  127. package/src/messages/alternation.ts +112 -0
  128. package/src/messages/format.ts +91 -0
  129. package/src/messages/formatAgentMessages.steer.test.ts +267 -0
  130. package/src/messages/handoffCue.test.ts +96 -0
  131. package/src/messages/handoffCue.ts +78 -0
  132. package/src/messages/index.ts +3 -0
  133. package/src/messages/injected.test.ts +90 -0
  134. package/src/messages/injected.ts +74 -0
  135. package/src/run.ts +91 -6
  136. package/src/scripts/preempt-probe.ts +330 -0
  137. package/src/scripts/preempt-scenarios.ts +388 -0
  138. package/src/session/handlers.ts +32 -12
  139. package/src/specs/handoffCue.test.ts +165 -0
  140. package/src/specs/langfuse-callbacks.test.ts +352 -2
  141. package/src/specs/preemptSeal.test.ts +309 -0
  142. package/src/stream.dispatch.test.ts +63 -0
  143. package/src/stream.ts +36 -8
  144. package/src/tools/ToolNode.ts +3 -31
  145. package/src/tools/search/keenable-scraper.test.ts +153 -0
  146. package/src/tools/search/keenable-scraper.ts +137 -0
  147. package/src/tools/search/tool.ts +13 -2
  148. package/src/tools/search/types.ts +50 -3
  149. package/src/types/graph.ts +12 -1
  150. package/src/types/run.ts +67 -0
  151. package/src/types/stream.ts +0 -41
  152. package/dist/cjs/splitStream.cjs +0 -151
  153. package/dist/cjs/splitStream.cjs.map +0 -1
  154. package/dist/esm/splitStream.mjs +0 -150
  155. package/dist/esm/splitStream.mjs.map +0 -1
  156. package/dist/types/mockStream.d.ts +0 -32
  157. package/dist/types/splitStream.d.ts +0 -37
  158. package/src/mockStream.ts +0 -99
  159. package/src/splitStream.ts +0 -234
@@ -1 +1 @@
1
- {"version":3,"file":"message_inputs.mjs","names":[],"sources":["../../../../../src/llm/bedrock/utils/message_inputs.ts"],"sourcesContent":["/**\n * Utility functions for converting LangChain messages to Bedrock Converse messages.\n * Ported from @langchain/aws common.js\n */\nimport {\n type BaseMessage,\n type ToolMessage,\n isAIMessage,\n type Data,\n parseBase64DataUrl,\n parseMimeType,\n MessageContentComplex,\n type StandardContentBlockConverter,\n convertToProviderContentBlock,\n isDataContentBlock,\n} from '@langchain/core/messages';\nimport type {\n AudioFormat,\n AudioSource,\n DocumentFormat,\n DocumentSource,\n VideoFormat,\n VideoSource,\n} from '@aws-sdk/client-bedrock-runtime';\nimport type {\n BedrockMessage,\n BedrockSystemContentBlock,\n BedrockContentBlock,\n MessageContentReasoningBlock,\n} from '../types';\nimport { serializeStructuredValueBounded } from '@/utils/toolContent';\nimport { HARD_MAX_TOOL_RESULT_CHARS } from '@/utils/truncation';\n\n/**\n * Reasoning blocks from other providers, relative to Bedrock. Bedrock's native\n * reasoning format is `reasoning_content`; these carry provider-specific\n * signatures Bedrock cannot validate, so they are dropped on a cross-provider\n * handoff (e.g. Anthropic → Bedrock) rather than crashing the conversion.\n */\nconst FOREIGN_REASONING_TYPES = [\n 'thinking',\n 'redacted_thinking',\n 'reasoning',\n 'think',\n];\n\n/**\n * Google server-side tool blocks (`toolCall`/`toolResponse` parts from e.g.\n * URL context or Google Search). Only Google can execute these and validate\n * their thought signatures, so they are dropped on a cross-provider handoff\n * (e.g. Google → Bedrock); the assistant's answer text is kept.\n */\nconst FOREIGN_SERVER_TOOL_TYPES = ['toolCall', 'toolResponse'];\n\n/**\n * Bedrock Converse rejects assistant messages with no content blocks. When\n * filtering (e.g. dropping foreign reasoning) empties an assistant turn that\n * also has no tool calls, fall back to this placeholder text.\n */\nconst BEDROCK_EMPTY_TEXT_PLACEHOLDER = '_';\n\n/**\n * Convert a LangChain reasoning block to a Bedrock reasoning block.\n */\nexport function langchainReasoningBlockToBedrockReasoningBlock(\n content: MessageContentReasoningBlock\n): {\n reasoningText?: { text?: string; signature?: string };\n redactedContent?: Uint8Array;\n} {\n if (content.reasoningText != null) {\n return {\n reasoningText: content.reasoningText,\n };\n }\n if (content.redactedContent != null && content.redactedContent !== '') {\n return {\n redactedContent: new Uint8Array(\n Buffer.from(content.redactedContent, 'base64')\n ),\n };\n }\n throw new Error('Invalid reasoning content');\n}\n\n/**\n * Whether a reasoning block can be serialized to a valid Bedrock\n * `reasoningContent`. Bedrock Converse rejects `reasoningText` with a null/empty\n * `text` (e.g. a signature-only block that never merged with its text), so such\n * blocks must be dropped rather than sent.\n */\nfunction isSerializableBedrockReasoningBlock(\n content: MessageContentReasoningBlock\n): boolean {\n if (content.reasoningText != null) {\n const text = content.reasoningText.text;\n return text != null && text !== '';\n }\n return content.redactedContent != null && content.redactedContent !== '';\n}\n\nfunction appendSerializableBedrockTextBlock(\n contentBlocks: BedrockContentBlock[],\n text: string\n): boolean {\n if (text === '') {\n return false;\n }\n const cleanedText = text.replace(/\\n/g, '').trim();\n if (cleanedText !== '') {\n contentBlocks.push({ text });\n return true;\n }\n const lastBlock = contentBlocks[contentBlocks.length - 1] as\n | BedrockContentBlock\n | undefined;\n if (lastBlock == null || !('text' in lastBlock)) {\n return false;\n }\n const mergedTextContent = `${lastBlock.text}${text}`;\n (lastBlock as { text: string }).text = mergedTextContent;\n return true;\n}\n\n/**\n * Concatenate consecutive reasoning blocks in content array.\n */\nexport function concatenateLangchainReasoningBlocks(\n content: Array<MessageContentComplex | MessageContentReasoningBlock>\n): Array<MessageContentComplex | MessageContentReasoningBlock> {\n const result: Array<MessageContentComplex | MessageContentReasoningBlock> =\n [];\n let pendingReasoning: MessageContentReasoningBlock | undefined;\n\n const flushPendingReasoning = (): void => {\n if (pendingReasoning != null) {\n result.push(pendingReasoning);\n pendingReasoning = undefined;\n }\n };\n\n for (const block of content) {\n if (block.type !== 'reasoning_content') {\n flushPendingReasoning();\n result.push(block);\n continue;\n }\n\n const currentReasoning = block as MessageContentReasoningBlock;\n if (currentReasoning.reasoningText != null) {\n const previousText = pendingReasoning?.reasoningText?.text;\n const previousSignature = pendingReasoning?.reasoningText?.signature;\n const { text, signature } = currentReasoning.reasoningText;\n const mergedReasoningText: { text?: string; signature?: string } = {};\n if (previousText !== undefined || text !== undefined) {\n mergedReasoningText.text = (previousText ?? '') + (text ?? '');\n }\n if (previousSignature !== undefined || signature !== undefined) {\n mergedReasoningText.signature =\n (previousSignature ?? '') + (signature ?? '');\n }\n pendingReasoning = {\n type: 'reasoning_content',\n reasoningText: mergedReasoningText,\n };\n\n // A signature seals the accumulated reasoning text. Any following\n // reasoning block starts a new independently signed Bedrock block.\n if ('signature' in currentReasoning.reasoningText) {\n flushPendingReasoning();\n }\n }\n\n if (currentReasoning.redactedContent != null) {\n flushPendingReasoning();\n result.push({\n type: 'reasoning_content',\n redactedContent: currentReasoning.redactedContent,\n });\n }\n }\n\n flushPendingReasoning();\n return result;\n}\n\n/**\n * Extract image info from a base64 string or URL.\n */\nexport function extractImageInfo(base64: string): BedrockContentBlock {\n // Extract the format from the base64 string\n const formatMatch = base64.match(/^data:image\\/(\\w+);base64,/);\n let format: 'gif' | 'jpeg' | 'png' | 'webp' | undefined;\n if (formatMatch) {\n const extractedFormat = formatMatch[1].toLowerCase();\n if (['gif', 'jpeg', 'png', 'webp'].includes(extractedFormat)) {\n format = extractedFormat as typeof format;\n }\n }\n\n // Remove the data URL prefix if present\n const base64Data = base64.replace(/^data:image\\/\\w+;base64,/, '');\n\n // Convert base64 to Uint8Array\n const binaryString = atob(base64Data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i += 1) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n\n return {\n image: {\n format,\n source: {\n bytes,\n },\n },\n };\n}\n\ntype MediaContentBlock = MessageContentComplex & {\n data?: string | Uint8Array;\n url?: string;\n fileId?: string;\n mimeType?: string;\n};\n\nconst mimeTypeToVideoFormat: Record<string, VideoFormat> = {\n 'video/flv': 'flv',\n 'video/mkv': 'mkv',\n 'video/mov': 'mov',\n 'video/mp4': 'mp4',\n 'video/mpeg': 'mpeg',\n 'video/mpg': 'mpg',\n 'video/three_gp': 'three_gp',\n 'video/webm': 'webm',\n 'video/wmv': 'wmv',\n};\n\nconst mimeTypeToAudioFormat: Record<string, AudioFormat> = {\n 'audio/aac': 'aac',\n 'audio/flac': 'flac',\n 'audio/m4a': 'm4a',\n 'audio/mka': 'mka',\n 'audio/mkv': 'mkv',\n 'audio/mp3': 'mp3',\n 'audio/mp4': 'mp4',\n 'audio/mpeg': 'mpeg',\n 'audio/mpga': 'mpga',\n 'audio/ogg': 'ogg',\n 'audio/opus': 'opus',\n 'audio/pcm': 'pcm',\n 'audio/wav': 'wav',\n 'audio/webm': 'webm',\n 'audio/x-aac': 'x-aac',\n};\n\nconst mimeTypeToDocumentFormat: Partial<Record<string, DocumentFormat>> = {\n 'text/csv': 'csv',\n 'application/msword': 'doc',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':\n 'docx',\n 'text/html': 'html',\n 'text/markdown': 'md',\n 'application/pdf': 'pdf',\n 'text/plain': 'txt',\n 'application/vnd.ms-excel': 'xls',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',\n};\n\nfunction base64ToBytes(data: string): Uint8Array {\n return Uint8Array.from(atob(data), (char) => char.charCodeAt(0));\n}\n\nfunction getMediaFormat<T extends string>(\n mimeType: string | undefined,\n formatMap: Record<string, T>\n): T | undefined {\n if (mimeType == null || mimeType === '') {\n return undefined;\n }\n return formatMap[mimeType] ?? (parseMimeType(mimeType).subtype as T);\n}\n\nfunction resolveMediaSource(\n block: MediaContentBlock\n): AudioSource | VideoSource {\n if (typeof block.data === 'string') {\n return { bytes: base64ToBytes(block.data) };\n }\n if (block.data instanceof Uint8Array) {\n return { bytes: block.data };\n }\n if (typeof block.url === 'string') {\n const parsedData = parseBase64DataUrl({\n dataUrl: block.url,\n asTypedArray: true,\n });\n if (parsedData != null) {\n return { bytes: parsedData.data as Uint8Array };\n }\n throw new Error(\n `Only base64 data URLs are supported for ${block.type} blocks with 'url' field with ChatBedrockConverse.`\n );\n }\n if (typeof block.fileId === 'string') {\n return { s3Location: { uri: block.fileId } };\n }\n throw new Error(\n `${block.type} block must include one of: 'data' (base64 string or Uint8Array), 'url' (base64 data URL), or 'fileId' (S3 URI).`\n );\n}\n\nfunction convertMultimodalVideoBlock(\n block: MediaContentBlock\n): BedrockContentBlock {\n return {\n video: {\n format: getMediaFormat(block.mimeType, mimeTypeToVideoFormat),\n source: resolveMediaSource(block) as VideoSource,\n },\n } as BedrockContentBlock;\n}\n\nfunction convertMultimodalAudioBlock(\n block: MediaContentBlock\n): BedrockContentBlock {\n return {\n audio: {\n format: getMediaFormat(block.mimeType, mimeTypeToAudioFormat),\n source: resolveMediaSource(block) as AudioSource,\n },\n } as BedrockContentBlock;\n}\n\nfunction getDocumentName(block: Data.StandardFileBlock): string {\n return (\n (block.metadata?.name as string | undefined) ??\n (block.metadata?.filename as string | undefined) ??\n (block.metadata?.title as string | undefined) ??\n globalThis.crypto.randomUUID().replace(/-/g, '').slice(0, 12)\n );\n}\n\nfunction getDocumentFormat(\n mimeType: string | undefined\n): DocumentFormat | undefined {\n if (mimeType == null || mimeType === '') {\n return undefined;\n }\n const parsedMimeType = parseMimeType(mimeType);\n const format =\n mimeTypeToDocumentFormat[\n `${parsedMimeType.type}/${parsedMimeType.subtype}`\n ];\n if (format === undefined) {\n throw new Error(\n `Unsupported file mime type: \"${mimeType}\" ChatBedrockConverse only supports ${Object.keys(\n mimeTypeToDocumentFormat\n ).join(', ')} formats.`\n );\n }\n return format;\n}\n\nconst standardContentBlockConverter: StandardContentBlockConverter<{\n text: BedrockContentBlock;\n image: BedrockContentBlock;\n file: BedrockContentBlock;\n}> = {\n providerName: 'ChatBedrockConverse',\n\n fromStandardTextBlock(block: Data.StandardTextBlock): BedrockContentBlock {\n return { text: block.text };\n },\n\n fromStandardImageBlock(block: Data.StandardImageBlock): BedrockContentBlock {\n if (block.source_type === 'url') {\n const parsedData = parseBase64DataUrl({\n dataUrl: block.url,\n asTypedArray: true,\n });\n if (parsedData == null) {\n throw new Error(\n [\n 'Only base64 data URLs are supported for image blocks with source type ',\n 'url',\n ' with ChatBedrockConverse.',\n ].join(String.fromCharCode(39))\n );\n }\n return {\n image: {\n format: parseMimeType(parsedData.mime_type).subtype as\n | 'gif'\n | 'jpeg'\n | 'png'\n | 'webp',\n source: { bytes: parsedData.data as Uint8Array },\n },\n };\n }\n if (block.source_type === 'base64') {\n let format: 'gif' | 'jpeg' | 'png' | 'webp' | undefined;\n if (block.mime_type != null && block.mime_type !== '') {\n format = parseMimeType(block.mime_type).subtype as typeof format;\n }\n if (format != null && !['gif', 'jpeg', 'png', 'webp'].includes(format)) {\n throw new Error(\n `Unsupported image mime type: \"${block.mime_type}\" ChatBedrockConverse only supports \"image/gif\", \"image/jpeg\", \"image/png\", and \"image/webp\" formats.`\n );\n }\n return {\n image: {\n format,\n source: { bytes: base64ToBytes(block.data) },\n },\n };\n }\n throw new Error(\n `Image source type '${block.source_type}' not supported with ChatBedrockConverse.`\n );\n },\n\n fromStandardFileBlock(block: Data.StandardFileBlock): BedrockContentBlock {\n const name = getDocumentName(block);\n if (block.source_type === 'text') {\n return {\n document: {\n name,\n format: 'txt',\n source: { bytes: new TextEncoder().encode(block.text) },\n },\n } as BedrockContentBlock;\n }\n if (block.source_type === 'url') {\n const parsedData = parseBase64DataUrl({\n dataUrl: block.url,\n asTypedArray: true,\n });\n if (parsedData == null) {\n throw new Error(\n [\n 'Only base64 data URLs are supported for file blocks with source type ',\n 'url',\n ' with ChatBedrockConverse.',\n ].join(String.fromCharCode(39))\n );\n }\n return {\n document: {\n name,\n format: getDocumentFormat(parsedData.mime_type),\n source: { bytes: parsedData.data as Uint8Array } as DocumentSource,\n },\n } as BedrockContentBlock;\n }\n if (block.source_type === 'base64') {\n return {\n document: {\n name,\n format: getDocumentFormat(block.mime_type),\n source: { bytes: base64ToBytes(block.data) } as DocumentSource,\n },\n } as BedrockContentBlock;\n }\n throw new Error(\n `File source type '${block.source_type}' not supported with ChatBedrockConverse.`\n );\n },\n};\n\ntype BedrockPromptCacheTtl = '5m' | '1h';\ntype NormalizedBedrockCachePoint = {\n type: 'default';\n ttl?: BedrockPromptCacheTtl;\n};\n\n/**\n * Check if a block has a default cache point and return its normalized form,\n * preserving an optional extended-TTL `ttl` (`'5m'` | `'1h'`). Returns\n * `undefined` when the block is not a default cache point.\n */\nfunction getDefaultCachePoint(\n block: unknown\n): NormalizedBedrockCachePoint | undefined {\n if (typeof block !== 'object' || block === null) {\n return undefined;\n }\n if (!('cachePoint' in block)) {\n return undefined;\n }\n const cachePoint = (block as { cachePoint?: unknown }).cachePoint;\n if (typeof cachePoint !== 'object' || cachePoint === null) {\n return undefined;\n }\n if (!('type' in cachePoint)) {\n return undefined;\n }\n if ((cachePoint as { type?: string }).type !== 'default') {\n return undefined;\n }\n const ttl = (cachePoint as { ttl?: unknown }).ttl;\n return ttl === '5m' || ttl === '1h'\n ? { type: 'default', ttl }\n : { type: 'default' };\n}\n\n/**\n * Convert a LangChain content block to a Bedrock Converse content block.\n */\nfunction convertLangChainContentBlockToConverseContentBlock({\n block,\n onUnknown = 'throw',\n}: {\n block: string | MessageContentComplex;\n onUnknown?: 'throw' | 'passthrough';\n}): BedrockContentBlock {\n if (typeof block === 'string') {\n return { text: block };\n }\n\n if (isDataContentBlock(block)) {\n return convertToProviderContentBlock(block, standardContentBlockConverter);\n }\n\n if (block.type === 'text') {\n return { text: (block as { text: string }).text };\n }\n\n if (block.type === 'image_url') {\n const imageUrl =\n typeof (block as { image_url: string | { url: string } }).image_url ===\n 'string'\n ? (block as { image_url: string }).image_url\n : (block as { image_url: { url: string } }).image_url.url;\n return extractImageInfo(imageUrl);\n }\n\n if (block.type === 'image') {\n // Handle standard image block format\n const imageBlock = block as {\n source_type?: string;\n url?: string;\n data?: string;\n mime_type?: string;\n };\n if (\n imageBlock.source_type === 'url' &&\n imageBlock.url != null &&\n imageBlock.url !== ''\n ) {\n const parsedData = parseBase64DataUrl({\n dataUrl: imageBlock.url,\n asTypedArray: true,\n });\n if (parsedData != null) {\n const parsedMimeType = parseMimeType(parsedData.mime_type);\n return {\n image: {\n format: parsedMimeType.subtype as 'gif' | 'jpeg' | 'png' | 'webp',\n source: {\n bytes: parsedData.data as Uint8Array,\n },\n },\n };\n }\n } else if (\n imageBlock.source_type === 'base64' &&\n imageBlock.data != null &&\n imageBlock.data !== ''\n ) {\n let format: 'gif' | 'jpeg' | 'png' | 'webp' | undefined;\n if (imageBlock.mime_type != null && imageBlock.mime_type !== '') {\n const parsedMimeType = parseMimeType(imageBlock.mime_type);\n format = parsedMimeType.subtype as typeof format;\n }\n return {\n image: {\n format,\n source: {\n bytes: Uint8Array.from(atob(imageBlock.data), (c) =>\n c.charCodeAt(0)\n ),\n },\n },\n };\n }\n // If it already has the Bedrock image structure, pass through\n if ((block as { image?: unknown }).image !== undefined) {\n return {\n image: (block as { image: unknown }).image,\n } as BedrockContentBlock;\n }\n }\n\n if (\n block.type === 'video' &&\n (block as { video?: unknown }).video !== undefined\n ) {\n return {\n video: (block as { video: unknown }).video,\n } as BedrockContentBlock;\n }\n\n if (block.type === 'video') {\n return convertMultimodalVideoBlock(block as MediaContentBlock);\n }\n\n if (\n block.type === 'audio' &&\n (block as { audio?: unknown }).audio !== undefined\n ) {\n return {\n audio: (block as { audio: unknown }).audio,\n } as BedrockContentBlock;\n }\n\n if (block.type === 'audio') {\n return convertMultimodalAudioBlock(block as MediaContentBlock);\n }\n\n if (\n block.type === 'document' &&\n (block as { document?: unknown }).document !== undefined\n ) {\n return {\n document: (block as { document: unknown }).document,\n } as BedrockContentBlock;\n }\n\n const cachePoint = getDefaultCachePoint(block);\n if (cachePoint != null) {\n return {\n cachePoint,\n } as BedrockContentBlock;\n }\n\n if (onUnknown === 'throw') {\n throw new Error(`Unsupported content block type: ${block.type}`);\n } else {\n return block as unknown as BedrockContentBlock;\n }\n}\n\n/**\n * Convert a system message to Bedrock system content blocks.\n */\nfunction convertSystemMessageToConverseMessage(\n msg: BaseMessage\n): BedrockSystemContentBlock[] {\n if (typeof msg.content === 'string') {\n return [{ text: msg.content }];\n } else if (Array.isArray(msg.content) && msg.content.length > 0) {\n const contentBlocks: BedrockSystemContentBlock[] = [];\n for (const block of msg.content) {\n if (\n typeof block === 'object' &&\n block.type === 'text' &&\n typeof (block as { text?: string }).text === 'string'\n ) {\n contentBlocks.push({\n text: (block as { text: string }).text,\n });\n } else {\n const cachePoint = getDefaultCachePoint(block);\n if (cachePoint == null) {\n break;\n }\n contentBlocks.push({\n cachePoint,\n } as BedrockSystemContentBlock);\n }\n }\n if (msg.content.length === contentBlocks.length) {\n return contentBlocks;\n }\n }\n throw new Error(\n 'System message content must be either a string, or an array of text blocks, optionally including a cache point.'\n );\n}\n\n/**\n * Convert an AI message to a Bedrock message.\n */\nfunction convertAIMessageToConverseMessage(msg: BaseMessage): BedrockMessage {\n // Check for v1 format from other providers (PR #9766 fix)\n const responseMetadata = msg.response_metadata as\n | { output_version?: string }\n | undefined;\n if (responseMetadata?.output_version === 'v1') {\n return convertFromV1ToChatBedrockConverseMessage(msg);\n }\n\n const assistantMsg: BedrockMessage = {\n role: 'assistant',\n content: [],\n };\n\n if (typeof msg.content === 'string' && msg.content !== '') {\n assistantMsg.content?.push({ text: msg.content });\n } else if (Array.isArray(msg.content)) {\n const parsedToolCallIds = new Set(\n isAIMessage(msg)\n ? (msg.tool_calls ?? []).flatMap((toolCall) =>\n toolCall.id != null ? [toolCall.id] : []\n )\n : []\n );\n const concatenatedBlocks = concatenateLangchainReasoningBlocks(\n msg.content as Array<MessageContentComplex | MessageContentReasoningBlock>\n );\n const contentBlocks: BedrockContentBlock[] = [];\n\n concatenatedBlocks.forEach((block) => {\n if (block.type === 'text') {\n const text = (block as { text?: string }).text ?? '';\n appendSerializableBedrockTextBlock(contentBlocks, text);\n } else if (block.type === 'tool_use') {\n const toolUse = block as {\n id?: unknown;\n name?: unknown;\n input?: unknown;\n };\n if (\n typeof toolUse.id === 'string' &&\n parsedToolCallIds.has(toolUse.id)\n ) {\n return;\n }\n if (\n typeof toolUse.id !== 'string' ||\n typeof toolUse.name !== 'string' ||\n toolUse.input == null ||\n typeof toolUse.input !== 'object'\n ) {\n throw new Error('Invalid Anthropic tool_use content block');\n }\n contentBlocks.push({\n toolUse: {\n toolUseId: toolUse.id,\n name: toolUse.name,\n input: toolUse.input as Record<string, unknown>,\n },\n } as BedrockContentBlock);\n } else if (block.type === 'reasoning_content') {\n const reasoningBlock = block as MessageContentReasoningBlock;\n // Bedrock Converse rejects reasoningContent whose reasoningText.text is\n // null/empty (a signature-only block that never merged with its text).\n // Drop it rather than emit an invalid request; the empty-turn\n // placeholder below covers a turn left with no content.\n if (!isSerializableBedrockReasoningBlock(reasoningBlock)) {\n return;\n }\n contentBlocks.push({\n reasoningContent:\n langchainReasoningBlockToBedrockReasoningBlock(reasoningBlock),\n } as BedrockContentBlock);\n } else {\n const cachePoint = getDefaultCachePoint(block);\n if (cachePoint != null) {\n contentBlocks.push({\n cachePoint,\n } as BedrockContentBlock);\n } else if (FOREIGN_REASONING_TYPES.some((t) => t === block.type)) {\n // Reasoning from another provider (Anthropic `thinking`/\n // `redacted_thinking`, Google `reasoning`, LibreChat `think`).\n // Bedrock's native reasoning is `reasoning_content` (handled above); a\n // foreign block carries a signature Bedrock cannot validate, so drop\n // it on a cross-provider handoff (e.g. Anthropic → Bedrock) rather\n // than crash. The Bedrock model produces its own reasoning. Anything\n // else unknown still throws below — real content must be surfaced.\n return;\n } else if (FOREIGN_SERVER_TOOL_TYPES.some((t) => t === block.type)) {\n // Google server-side tool call/response (e.g. URL context) — only\n // Google can execute it or validate its thought signature; drop it\n // on a cross-provider handoff rather than crash.\n return;\n } else {\n const blockValues = Object.fromEntries(\n Object.entries(block).filter(([key]) => key !== 'type')\n );\n throw new Error(\n `Unsupported content block type: ${block.type} with content of ${JSON.stringify(blockValues, null, 2)}`\n );\n }\n }\n });\n\n assistantMsg.content = [...(assistantMsg.content ?? []), ...contentBlocks];\n }\n\n // Important: this must be placed after any reasoning content blocks\n if (isAIMessage(msg) && msg.tool_calls != null && msg.tool_calls.length > 0) {\n const existingToolUseIds = new Set(\n (assistantMsg.content ?? [])\n .filter((content) => 'toolUse' in content)\n .map((content) => content.toolUse?.toolUseId)\n );\n const toolUseBlocks = msg.tool_calls\n .filter((toolCall) => !existingToolUseIds.has(toolCall.id))\n .map((toolCall) => ({\n toolUse: {\n toolUseId: toolCall.id,\n name: toolCall.name,\n input: toolCall.args as Record<string, unknown>,\n },\n }));\n assistantMsg.content = [\n ...(assistantMsg.content ?? []),\n ...toolUseBlocks,\n ] as BedrockContentBlock[];\n }\n\n // Bedrock rejects an assistant message with no content blocks; if filtering\n // (e.g. dropping foreign reasoning) left it empty, emit a placeholder.\n if (assistantMsg.content == null || assistantMsg.content.length === 0) {\n assistantMsg.content = [{ text: BEDROCK_EMPTY_TEXT_PLACEHOLDER }];\n }\n\n return assistantMsg;\n}\n\n/**\n * Convert a v1 format message from other providers to Bedrock format.\n * This handles messages with standard content blocks like tool_call and reasoning.\n * (Implements PR #9766 fix for output_version v1 detection)\n */\nfunction convertFromV1ToChatBedrockConverseMessage(\n msg: BaseMessage\n): BedrockMessage {\n const contentBlocks: BedrockContentBlock[] = [];\n const assistantMsg: BedrockMessage = {\n role: 'assistant',\n content: contentBlocks,\n };\n let droppedUnserializableContent = false;\n let unconvertedContentType: string | undefined;\n\n if (Array.isArray(msg.content)) {\n const concatenatedBlocks = concatenateLangchainReasoningBlocks(\n msg.content as Array<MessageContentComplex | MessageContentReasoningBlock>\n );\n for (const block of concatenatedBlocks) {\n if (typeof block === 'string') {\n if (!appendSerializableBedrockTextBlock(contentBlocks, block)) {\n droppedUnserializableContent = true;\n }\n } else if (block.type === 'text') {\n const text = (block as { text?: string }).text ?? '';\n if (!appendSerializableBedrockTextBlock(contentBlocks, text)) {\n droppedUnserializableContent = true;\n }\n } else if (block.type === 'tool_call') {\n const toolCall = block as {\n id: string;\n name: string;\n args: Record<string, unknown>;\n };\n contentBlocks.push({\n toolUse: {\n toolUseId: toolCall.id,\n name: toolCall.name,\n input: toolCall.args as Record<string, unknown>,\n },\n } as BedrockContentBlock);\n } else if (block.type === 'reasoning') {\n const reasoning = block as { reasoning?: string };\n /** Bedrock Converse rejects `reasoningText` with a null/empty `text`\n * (`Member must not be null`), e.g. when the producing model omitted\n * reasoning text (`thinking.display: \"omitted\"`) — drop rather than send. */\n if (reasoning.reasoning == null || reasoning.reasoning === '') {\n droppedUnserializableContent = true;\n continue;\n }\n contentBlocks.push({\n reasoningContent: {\n reasoningText: { text: reasoning.reasoning },\n },\n } as BedrockContentBlock);\n } else if (block.type === 'reasoning_content') {\n const reasoningBlock = block as MessageContentReasoningBlock;\n if (!isSerializableBedrockReasoningBlock(reasoningBlock)) {\n droppedUnserializableContent = true;\n continue;\n }\n contentBlocks.push({\n reasoningContent:\n langchainReasoningBlockToBedrockReasoningBlock(reasoningBlock),\n } as BedrockContentBlock);\n } else {\n unconvertedContentType ??= block.type;\n }\n }\n } else if (typeof msg.content === 'string') {\n if (!appendSerializableBedrockTextBlock(contentBlocks, msg.content)) {\n droppedUnserializableContent = true;\n }\n }\n\n // Also handle tool_calls from the message\n if (isAIMessage(msg) && msg.tool_calls != null && msg.tool_calls.length > 0) {\n // Check if tool calls are already in content\n const existingToolUseIds = new Set(\n contentBlocks\n .filter((c) => 'toolUse' in c)\n .map((c) => (c as { toolUse: { toolUseId: string } }).toolUse.toolUseId)\n );\n\n for (const tc of msg.tool_calls) {\n if (!existingToolUseIds.has(tc.id ?? '')) {\n contentBlocks.push({\n toolUse: {\n toolUseId: tc.id,\n name: tc.name,\n input: tc.args as Record<string, unknown>,\n },\n } as BedrockContentBlock);\n }\n }\n }\n\n const hasNoContent = contentBlocks.length === 0;\n if (hasNoContent && unconvertedContentType != null) {\n throw new Error(\n `Unsupported v1 content block type: ${unconvertedContentType}`\n );\n }\n if (hasNoContent && droppedUnserializableContent) {\n contentBlocks.push({ text: BEDROCK_EMPTY_TEXT_PLACEHOLDER });\n }\n\n return assistantMsg;\n}\n\n/**\n * Convert a human message to a Bedrock message.\n */\nfunction convertHumanMessageToConverseMessage(\n msg: BaseMessage\n): BedrockMessage {\n const userMessage: BedrockMessage = {\n role: 'user',\n content: [],\n };\n\n if (typeof msg.content === 'string') {\n userMessage.content = [{ text: msg.content }];\n } else if (Array.isArray(msg.content)) {\n userMessage.content = msg.content.map((block) =>\n convertLangChainContentBlockToConverseContentBlock({ block })\n );\n }\n\n return userMessage;\n}\n\n/**\n * Convert a tool message to a Bedrock message.\n */\nfunction convertToolMessageToConverseMessage(msg: BaseMessage): BedrockMessage {\n const toolCallId = (msg as { tool_call_id?: string }).tool_call_id;\n let isError = (msg as ToolMessage).status === 'error';\n\n let content: BedrockContentBlock[];\n if (typeof msg.content === 'string') {\n content = [{ text: msg.content }];\n } else if (Array.isArray(msg.content)) {\n content = msg.content.flatMap((block) => {\n if (typeof block === 'object' && block.type === 'tool_result') {\n if ((block as { is_error?: unknown }).is_error === true) {\n isError = true;\n }\n const toolResultContent = (block as { content?: unknown }).content;\n if (typeof toolResultContent === 'string') {\n return [{ text: toolResultContent }];\n }\n if (Array.isArray(toolResultContent)) {\n return toolResultContent.map((nestedBlock) =>\n convertLangChainContentBlockToConverseContentBlock({\n block: nestedBlock,\n onUnknown: 'passthrough',\n })\n );\n }\n return [\n {\n text: serializeStructuredValueBounded(\n toolResultContent,\n HARD_MAX_TOOL_RESULT_CHARS\n ).content,\n },\n ];\n }\n return [\n convertLangChainContentBlockToConverseContentBlock({\n block,\n onUnknown: 'passthrough',\n }),\n ];\n });\n } else {\n content = [{ text: String(msg.content) }];\n }\n\n // A `cachePoint` is a message-level ContentBlock — it is NOT a valid\n // ToolResultContentBlock. A tail prompt-cache breakpoint that anchors on a\n // tool result therefore ends up nested inside `toolResult.content`, which\n // Bedrock silently ignores (no cache write, no cache read). Hoist any\n // cachePoint(s) out of the tool result body so they sit as siblings after\n // it, which is the only position Bedrock honors.\n const toolResultContent: BedrockContentBlock[] = [];\n const trailingCachePoints: BedrockContentBlock[] = [];\n for (const block of content) {\n const cachePoint = getDefaultCachePoint(block);\n if (cachePoint != null) {\n trailingCachePoints.push({\n cachePoint,\n } as BedrockContentBlock);\n } else {\n toolResultContent.push(block);\n }\n }\n\n return {\n role: 'user',\n content: [\n {\n toolResult: {\n toolUseId: toolCallId,\n content: toolResultContent as { text: string }[],\n ...(isError ? { status: 'error' as const } : {}),\n },\n },\n ...trailingCachePoints,\n ],\n };\n}\n\n/**\n * Convert LangChain messages to Bedrock Converse messages.\n */\nexport function convertToConverseMessages(messages: BaseMessage[]): {\n converseMessages: BedrockMessage[];\n converseSystem: BedrockSystemContentBlock[];\n} {\n const converseSystem = messages\n .filter((msg) => msg._getType() === 'system')\n .flatMap((msg) => convertSystemMessageToConverseMessage(msg));\n\n const converseMessages = messages\n .filter((msg) => msg._getType() !== 'system')\n .map((msg) => {\n if (msg._getType() === 'ai') {\n return convertAIMessageToConverseMessage(msg);\n } else if (msg._getType() === 'human' || msg._getType() === 'generic') {\n return convertHumanMessageToConverseMessage(msg);\n } else if (msg._getType() === 'tool') {\n return convertToolMessageToConverseMessage(msg);\n } else {\n throw new Error(`Unsupported message type: ${msg._getType()}`);\n }\n });\n\n // Combine consecutive user tool result messages into a single message\n const combinedConverseMessages = converseMessages.reduce<BedrockMessage[]>(\n (acc, curr) => {\n if (acc.length === 0) {\n acc.push(curr);\n return acc;\n }\n const lastMessage = acc[acc.length - 1];\n const lastHasToolResult =\n lastMessage.content?.some((c) => 'toolResult' in c) === true;\n const currHasToolResult =\n curr.content?.some((c) => 'toolResult' in c) === true;\n if (\n lastMessage.role === 'user' &&\n lastHasToolResult &&\n curr.role === 'user' &&\n currHasToolResult\n ) {\n lastMessage.content = lastMessage.content?.concat(curr.content ?? []);\n } else {\n acc.push(curr);\n }\n return acc;\n },\n []\n );\n\n return { converseMessages: combinedConverseMessages, converseSystem };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"message_inputs.mjs","names":[],"sources":["../../../../../src/llm/bedrock/utils/message_inputs.ts"],"sourcesContent":["/**\n * Utility functions for converting LangChain messages to Bedrock Converse messages.\n * Ported from @langchain/aws common.js\n */\nimport {\n type BaseMessage,\n type ToolMessage,\n isAIMessage,\n type Data,\n parseBase64DataUrl,\n parseMimeType,\n MessageContentComplex,\n type StandardContentBlockConverter,\n convertToProviderContentBlock,\n isDataContentBlock,\n} from '@langchain/core/messages';\nimport type {\n AudioFormat,\n AudioSource,\n DocumentFormat,\n DocumentSource,\n VideoFormat,\n VideoSource,\n} from '@aws-sdk/client-bedrock-runtime';\nimport type {\n BedrockMessage,\n BedrockSystemContentBlock,\n BedrockContentBlock,\n MessageContentReasoningBlock,\n} from '../types';\nimport { serializeStructuredValueBounded } from '@/utils/toolContent';\nimport { HARD_MAX_TOOL_RESULT_CHARS } from '@/utils/truncation';\n\n/**\n * Reasoning blocks from other providers, relative to Bedrock. Bedrock's native\n * reasoning format is `reasoning_content`; these carry provider-specific\n * signatures Bedrock cannot validate, so they are dropped on a cross-provider\n * handoff (e.g. Anthropic → Bedrock) rather than crashing the conversion.\n */\nconst FOREIGN_REASONING_TYPES = [\n 'thinking',\n 'redacted_thinking',\n 'reasoning',\n 'think',\n];\n\n/**\n * Google server-side tool blocks (`toolCall`/`toolResponse` parts from e.g.\n * URL context or Google Search). Only Google can execute these and validate\n * their thought signatures, so they are dropped on a cross-provider handoff\n * (e.g. Google → Bedrock); the assistant's answer text is kept.\n */\nconst FOREIGN_SERVER_TOOL_TYPES = ['toolCall', 'toolResponse'];\n\n/**\n * Bedrock Converse rejects assistant messages with no content blocks. When\n * filtering (e.g. dropping foreign reasoning) empties an assistant turn that\n * also has no tool calls, fall back to this placeholder text.\n */\nconst BEDROCK_EMPTY_TEXT_PLACEHOLDER = '_';\n\n/**\n * Convert a LangChain reasoning block to a Bedrock reasoning block.\n */\nexport function langchainReasoningBlockToBedrockReasoningBlock(\n content: MessageContentReasoningBlock\n): {\n reasoningText?: { text?: string; signature?: string };\n redactedContent?: Uint8Array;\n} {\n if (content.reasoningText != null) {\n return {\n reasoningText: content.reasoningText,\n };\n }\n if (content.redactedContent != null && content.redactedContent !== '') {\n return {\n redactedContent: new Uint8Array(\n Buffer.from(content.redactedContent, 'base64')\n ),\n };\n }\n throw new Error('Invalid reasoning content');\n}\n\n/**\n * Whether a reasoning block can be serialized to a valid Bedrock\n * `reasoningContent`. Bedrock Converse rejects `reasoningText` with a null/empty\n * `text` (e.g. a signature-only block that never merged with its text), so such\n * blocks must be dropped rather than sent.\n */\nfunction isSerializableBedrockReasoningBlock(\n content: MessageContentReasoningBlock\n): boolean {\n if (content.reasoningText != null) {\n const text = content.reasoningText.text;\n return text != null && text !== '';\n }\n return content.redactedContent != null && content.redactedContent !== '';\n}\n\nfunction appendSerializableBedrockTextBlock(\n contentBlocks: BedrockContentBlock[],\n text: string\n): boolean {\n if (text === '') {\n return false;\n }\n const cleanedText = text.replace(/\\n/g, '').trim();\n if (cleanedText !== '') {\n contentBlocks.push({ text });\n return true;\n }\n const lastBlock = contentBlocks[contentBlocks.length - 1] as\n | BedrockContentBlock\n | undefined;\n if (lastBlock == null || !('text' in lastBlock)) {\n return false;\n }\n const mergedTextContent = `${lastBlock.text}${text}`;\n (lastBlock as { text: string }).text = mergedTextContent;\n return true;\n}\n\n/**\n * Concatenate consecutive reasoning blocks in content array.\n */\nexport function concatenateLangchainReasoningBlocks(\n content: Array<MessageContentComplex | MessageContentReasoningBlock>\n): Array<MessageContentComplex | MessageContentReasoningBlock> {\n const result: Array<MessageContentComplex | MessageContentReasoningBlock> =\n [];\n let pendingReasoning: MessageContentReasoningBlock | undefined;\n\n const flushPendingReasoning = (): void => {\n if (pendingReasoning != null) {\n result.push(pendingReasoning);\n pendingReasoning = undefined;\n }\n };\n\n for (const block of content) {\n if (block.type !== 'reasoning_content') {\n flushPendingReasoning();\n result.push(block);\n continue;\n }\n\n const currentReasoning = block as MessageContentReasoningBlock;\n if (currentReasoning.reasoningText != null) {\n const previousText = pendingReasoning?.reasoningText?.text;\n const previousSignature = pendingReasoning?.reasoningText?.signature;\n const { text, signature } = currentReasoning.reasoningText;\n const mergedReasoningText: { text?: string; signature?: string } = {};\n if (previousText !== undefined || text !== undefined) {\n mergedReasoningText.text = (previousText ?? '') + (text ?? '');\n }\n if (previousSignature !== undefined || signature !== undefined) {\n mergedReasoningText.signature =\n (previousSignature ?? '') + (signature ?? '');\n }\n pendingReasoning = {\n type: 'reasoning_content',\n reasoningText: mergedReasoningText,\n };\n\n // A signature seals the accumulated reasoning text. Any following\n // reasoning block starts a new independently signed Bedrock block.\n if ('signature' in currentReasoning.reasoningText) {\n flushPendingReasoning();\n }\n }\n\n if (currentReasoning.redactedContent != null) {\n flushPendingReasoning();\n result.push({\n type: 'reasoning_content',\n redactedContent: currentReasoning.redactedContent,\n });\n }\n }\n\n flushPendingReasoning();\n return result;\n}\n\n/**\n * Extract image info from a base64 string or URL.\n */\nexport function extractImageInfo(base64: string): BedrockContentBlock {\n // Extract the format from the base64 string\n const formatMatch = base64.match(/^data:image\\/(\\w+);base64,/);\n let format: 'gif' | 'jpeg' | 'png' | 'webp' | undefined;\n if (formatMatch) {\n const extractedFormat = formatMatch[1].toLowerCase();\n if (['gif', 'jpeg', 'png', 'webp'].includes(extractedFormat)) {\n format = extractedFormat as typeof format;\n }\n }\n\n // Remove the data URL prefix if present\n const base64Data = base64.replace(/^data:image\\/\\w+;base64,/, '');\n\n // Convert base64 to Uint8Array\n const binaryString = atob(base64Data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i += 1) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n\n return {\n image: {\n format,\n source: {\n bytes,\n },\n },\n };\n}\n\ntype MediaContentBlock = MessageContentComplex & {\n data?: string | Uint8Array;\n url?: string;\n fileId?: string;\n mimeType?: string;\n};\n\nconst mimeTypeToVideoFormat: Record<string, VideoFormat> = {\n 'video/flv': 'flv',\n 'video/mkv': 'mkv',\n 'video/mov': 'mov',\n 'video/mp4': 'mp4',\n 'video/mpeg': 'mpeg',\n 'video/mpg': 'mpg',\n 'video/three_gp': 'three_gp',\n 'video/webm': 'webm',\n 'video/wmv': 'wmv',\n};\n\nconst mimeTypeToAudioFormat: Record<string, AudioFormat> = {\n 'audio/aac': 'aac',\n 'audio/flac': 'flac',\n 'audio/m4a': 'm4a',\n 'audio/mka': 'mka',\n 'audio/mkv': 'mkv',\n 'audio/mp3': 'mp3',\n 'audio/mp4': 'mp4',\n 'audio/mpeg': 'mpeg',\n 'audio/mpga': 'mpga',\n 'audio/ogg': 'ogg',\n 'audio/opus': 'opus',\n 'audio/pcm': 'pcm',\n 'audio/wav': 'wav',\n 'audio/webm': 'webm',\n 'audio/x-aac': 'x-aac',\n};\n\nconst mimeTypeToDocumentFormat: Partial<Record<string, DocumentFormat>> = {\n 'text/csv': 'csv',\n 'application/msword': 'doc',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':\n 'docx',\n 'text/html': 'html',\n 'text/markdown': 'md',\n 'application/pdf': 'pdf',\n 'text/plain': 'txt',\n 'application/vnd.ms-excel': 'xls',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',\n};\n\nfunction base64ToBytes(data: string): Uint8Array {\n return Uint8Array.from(atob(data), (char) => char.charCodeAt(0));\n}\n\nfunction getMediaFormat<T extends string>(\n mimeType: string | undefined,\n formatMap: Record<string, T>\n): T | undefined {\n if (mimeType == null || mimeType === '') {\n return undefined;\n }\n return formatMap[mimeType] ?? (parseMimeType(mimeType).subtype as T);\n}\n\nfunction resolveMediaSource(\n block: MediaContentBlock\n): AudioSource | VideoSource {\n if (typeof block.data === 'string') {\n return { bytes: base64ToBytes(block.data) };\n }\n if (block.data instanceof Uint8Array) {\n return { bytes: block.data };\n }\n if (typeof block.url === 'string') {\n const parsedData = parseBase64DataUrl({\n dataUrl: block.url,\n asTypedArray: true,\n });\n if (parsedData != null) {\n return { bytes: parsedData.data as Uint8Array };\n }\n throw new Error(\n `Only base64 data URLs are supported for ${block.type} blocks with 'url' field with ChatBedrockConverse.`\n );\n }\n if (typeof block.fileId === 'string') {\n return { s3Location: { uri: block.fileId } };\n }\n throw new Error(\n `${block.type} block must include one of: 'data' (base64 string or Uint8Array), 'url' (base64 data URL), or 'fileId' (S3 URI).`\n );\n}\n\nfunction convertMultimodalVideoBlock(\n block: MediaContentBlock\n): BedrockContentBlock {\n return {\n video: {\n format: getMediaFormat(block.mimeType, mimeTypeToVideoFormat),\n source: resolveMediaSource(block) as VideoSource,\n },\n } as BedrockContentBlock;\n}\n\nfunction convertMultimodalAudioBlock(\n block: MediaContentBlock\n): BedrockContentBlock {\n return {\n audio: {\n format: getMediaFormat(block.mimeType, mimeTypeToAudioFormat),\n source: resolveMediaSource(block) as AudioSource,\n },\n } as BedrockContentBlock;\n}\n\nfunction getDocumentName(block: Data.StandardFileBlock): string {\n return (\n (block.metadata?.name as string | undefined) ??\n (block.metadata?.filename as string | undefined) ??\n (block.metadata?.title as string | undefined) ??\n globalThis.crypto.randomUUID().replace(/-/g, '').slice(0, 12)\n );\n}\n\nfunction getDocumentFormat(\n mimeType: string | undefined\n): DocumentFormat | undefined {\n if (mimeType == null || mimeType === '') {\n return undefined;\n }\n const parsedMimeType = parseMimeType(mimeType);\n const format =\n mimeTypeToDocumentFormat[\n `${parsedMimeType.type}/${parsedMimeType.subtype}`\n ];\n if (format === undefined) {\n throw new Error(\n `Unsupported file mime type: \"${mimeType}\" ChatBedrockConverse only supports ${Object.keys(\n mimeTypeToDocumentFormat\n ).join(', ')} formats.`\n );\n }\n return format;\n}\n\nconst standardContentBlockConverter: StandardContentBlockConverter<{\n text: BedrockContentBlock;\n image: BedrockContentBlock;\n file: BedrockContentBlock;\n}> = {\n providerName: 'ChatBedrockConverse',\n\n fromStandardTextBlock(block: Data.StandardTextBlock): BedrockContentBlock {\n return { text: block.text };\n },\n\n fromStandardImageBlock(block: Data.StandardImageBlock): BedrockContentBlock {\n if (block.source_type === 'url') {\n const parsedData = parseBase64DataUrl({\n dataUrl: block.url,\n asTypedArray: true,\n });\n if (parsedData == null) {\n throw new Error(\n [\n 'Only base64 data URLs are supported for image blocks with source type ',\n 'url',\n ' with ChatBedrockConverse.',\n ].join(String.fromCharCode(39))\n );\n }\n return {\n image: {\n format: parseMimeType(parsedData.mime_type).subtype as\n | 'gif'\n | 'jpeg'\n | 'png'\n | 'webp',\n source: { bytes: parsedData.data as Uint8Array },\n },\n };\n }\n if (block.source_type === 'base64') {\n let format: 'gif' | 'jpeg' | 'png' | 'webp' | undefined;\n if (block.mime_type != null && block.mime_type !== '') {\n format = parseMimeType(block.mime_type).subtype as typeof format;\n }\n if (format != null && !['gif', 'jpeg', 'png', 'webp'].includes(format)) {\n throw new Error(\n `Unsupported image mime type: \"${block.mime_type}\" ChatBedrockConverse only supports \"image/gif\", \"image/jpeg\", \"image/png\", and \"image/webp\" formats.`\n );\n }\n return {\n image: {\n format,\n source: { bytes: base64ToBytes(block.data) },\n },\n };\n }\n throw new Error(\n `Image source type '${block.source_type}' not supported with ChatBedrockConverse.`\n );\n },\n\n fromStandardFileBlock(block: Data.StandardFileBlock): BedrockContentBlock {\n const name = getDocumentName(block);\n if (block.source_type === 'text') {\n return {\n document: {\n name,\n format: 'txt',\n source: { bytes: new TextEncoder().encode(block.text) },\n },\n } as BedrockContentBlock;\n }\n if (block.source_type === 'url') {\n const parsedData = parseBase64DataUrl({\n dataUrl: block.url,\n asTypedArray: true,\n });\n if (parsedData == null) {\n throw new Error(\n [\n 'Only base64 data URLs are supported for file blocks with source type ',\n 'url',\n ' with ChatBedrockConverse.',\n ].join(String.fromCharCode(39))\n );\n }\n return {\n document: {\n name,\n format: getDocumentFormat(parsedData.mime_type),\n source: { bytes: parsedData.data as Uint8Array } as DocumentSource,\n },\n } as BedrockContentBlock;\n }\n if (block.source_type === 'base64') {\n return {\n document: {\n name,\n format: getDocumentFormat(block.mime_type),\n source: { bytes: base64ToBytes(block.data) } as DocumentSource,\n },\n } as BedrockContentBlock;\n }\n throw new Error(\n `File source type '${block.source_type}' not supported with ChatBedrockConverse.`\n );\n },\n};\n\ntype BedrockPromptCacheTtl = '5m' | '1h';\ntype NormalizedBedrockCachePoint = {\n type: 'default';\n ttl?: BedrockPromptCacheTtl;\n};\n\n/**\n * Check if a block has a default cache point and return its normalized form,\n * preserving an optional extended-TTL `ttl` (`'5m'` | `'1h'`). Returns\n * `undefined` when the block is not a default cache point.\n */\nfunction getDefaultCachePoint(\n block: unknown\n): NormalizedBedrockCachePoint | undefined {\n if (typeof block !== 'object' || block === null) {\n return undefined;\n }\n if (!('cachePoint' in block)) {\n return undefined;\n }\n const cachePoint = (block as { cachePoint?: unknown }).cachePoint;\n if (typeof cachePoint !== 'object' || cachePoint === null) {\n return undefined;\n }\n if (!('type' in cachePoint)) {\n return undefined;\n }\n if ((cachePoint as { type?: string }).type !== 'default') {\n return undefined;\n }\n const ttl = (cachePoint as { ttl?: unknown }).ttl;\n return ttl === '5m' || ttl === '1h'\n ? { type: 'default', ttl }\n : { type: 'default' };\n}\n\n/**\n * Convert a LangChain content block to a Bedrock Converse content block.\n */\nfunction convertLangChainContentBlockToConverseContentBlock({\n block,\n onUnknown = 'throw',\n}: {\n block: string | MessageContentComplex;\n onUnknown?: 'throw' | 'passthrough';\n}): BedrockContentBlock {\n if (typeof block === 'string') {\n return { text: block };\n }\n\n if (isDataContentBlock(block)) {\n return convertToProviderContentBlock(block, standardContentBlockConverter);\n }\n\n if (block.type === 'text') {\n return { text: (block as { text: string }).text };\n }\n\n if (block.type === 'image_url') {\n const imageUrl =\n typeof (block as { image_url: string | { url: string } }).image_url ===\n 'string'\n ? (block as { image_url: string }).image_url\n : (block as { image_url: { url: string } }).image_url.url;\n return extractImageInfo(imageUrl);\n }\n\n if (block.type === 'image') {\n // Handle standard image block format\n const imageBlock = block as {\n source_type?: string;\n url?: string;\n data?: string;\n mime_type?: string;\n };\n if (\n imageBlock.source_type === 'url' &&\n imageBlock.url != null &&\n imageBlock.url !== ''\n ) {\n const parsedData = parseBase64DataUrl({\n dataUrl: imageBlock.url,\n asTypedArray: true,\n });\n if (parsedData != null) {\n const parsedMimeType = parseMimeType(parsedData.mime_type);\n return {\n image: {\n format: parsedMimeType.subtype as 'gif' | 'jpeg' | 'png' | 'webp',\n source: {\n bytes: parsedData.data as Uint8Array,\n },\n },\n };\n }\n } else if (\n imageBlock.source_type === 'base64' &&\n imageBlock.data != null &&\n imageBlock.data !== ''\n ) {\n let format: 'gif' | 'jpeg' | 'png' | 'webp' | undefined;\n if (imageBlock.mime_type != null && imageBlock.mime_type !== '') {\n const parsedMimeType = parseMimeType(imageBlock.mime_type);\n format = parsedMimeType.subtype as typeof format;\n }\n return {\n image: {\n format,\n source: {\n bytes: Uint8Array.from(atob(imageBlock.data), (c) =>\n c.charCodeAt(0)\n ),\n },\n },\n };\n }\n // If it already has the Bedrock image structure, pass through\n if ((block as { image?: unknown }).image !== undefined) {\n return {\n image: (block as { image: unknown }).image,\n } as BedrockContentBlock;\n }\n }\n\n if (\n block.type === 'video' &&\n (block as { video?: unknown }).video !== undefined\n ) {\n return {\n video: (block as { video: unknown }).video,\n } as BedrockContentBlock;\n }\n\n if (block.type === 'video') {\n return convertMultimodalVideoBlock(block as MediaContentBlock);\n }\n\n if (\n block.type === 'audio' &&\n (block as { audio?: unknown }).audio !== undefined\n ) {\n return {\n audio: (block as { audio: unknown }).audio,\n } as BedrockContentBlock;\n }\n\n if (block.type === 'audio') {\n return convertMultimodalAudioBlock(block as MediaContentBlock);\n }\n\n if (\n block.type === 'document' &&\n (block as { document?: unknown }).document !== undefined\n ) {\n return {\n document: (block as { document: unknown }).document,\n } as BedrockContentBlock;\n }\n\n const cachePoint = getDefaultCachePoint(block);\n if (cachePoint != null) {\n return {\n cachePoint,\n } as BedrockContentBlock;\n }\n\n if (onUnknown === 'throw') {\n throw new Error(`Unsupported content block type: ${block.type}`);\n } else {\n return block as unknown as BedrockContentBlock;\n }\n}\n\n/**\n * Convert a system message to Bedrock system content blocks.\n */\nfunction convertSystemMessageToConverseMessage(\n msg: BaseMessage\n): BedrockSystemContentBlock[] {\n if (typeof msg.content === 'string') {\n return [{ text: msg.content }];\n } else if (Array.isArray(msg.content) && msg.content.length > 0) {\n const contentBlocks: BedrockSystemContentBlock[] = [];\n for (const block of msg.content) {\n if (\n typeof block === 'object' &&\n block.type === 'text' &&\n typeof (block as { text?: string }).text === 'string'\n ) {\n contentBlocks.push({\n text: (block as { text: string }).text,\n });\n } else {\n const cachePoint = getDefaultCachePoint(block);\n if (cachePoint == null) {\n break;\n }\n contentBlocks.push({\n cachePoint,\n } as BedrockSystemContentBlock);\n }\n }\n if (msg.content.length === contentBlocks.length) {\n return contentBlocks;\n }\n }\n throw new Error(\n 'System message content must be either a string, or an array of text blocks, optionally including a cache point.'\n );\n}\n\n/**\n * Convert an AI message to a Bedrock message.\n */\nfunction convertAIMessageToConverseMessage(msg: BaseMessage): BedrockMessage {\n // Check for v1 format from other providers (PR #9766 fix)\n const responseMetadata = msg.response_metadata as\n | { output_version?: string }\n | undefined;\n if (responseMetadata?.output_version === 'v1') {\n return convertFromV1ToChatBedrockConverseMessage(msg);\n }\n\n const assistantMsg: BedrockMessage = {\n role: 'assistant',\n content: [],\n };\n\n if (typeof msg.content === 'string' && msg.content !== '') {\n assistantMsg.content?.push({ text: msg.content });\n } else if (Array.isArray(msg.content)) {\n const parsedToolCallIds = new Set(\n isAIMessage(msg)\n ? (msg.tool_calls ?? []).flatMap((toolCall) =>\n toolCall.id != null ? [toolCall.id] : []\n )\n : []\n );\n const concatenatedBlocks = concatenateLangchainReasoningBlocks(\n msg.content as Array<MessageContentComplex | MessageContentReasoningBlock>\n );\n const contentBlocks: BedrockContentBlock[] = [];\n\n concatenatedBlocks.forEach((block) => {\n if (block.type === 'text') {\n const text = (block as { text?: string }).text ?? '';\n appendSerializableBedrockTextBlock(contentBlocks, text);\n } else if (block.type === 'tool_use') {\n const toolUse = block as {\n id?: unknown;\n name?: unknown;\n input?: unknown;\n };\n if (\n typeof toolUse.id === 'string' &&\n parsedToolCallIds.has(toolUse.id)\n ) {\n return;\n }\n if (\n typeof toolUse.id !== 'string' ||\n typeof toolUse.name !== 'string' ||\n toolUse.input == null ||\n typeof toolUse.input !== 'object'\n ) {\n throw new Error('Invalid Anthropic tool_use content block');\n }\n contentBlocks.push({\n toolUse: {\n toolUseId: toolUse.id,\n name: toolUse.name,\n input: toolUse.input as Record<string, unknown>,\n },\n } as BedrockContentBlock);\n } else if (block.type === 'reasoning_content') {\n const reasoningBlock = block as MessageContentReasoningBlock;\n // Bedrock Converse rejects reasoningContent whose reasoningText.text is\n // null/empty (a signature-only block that never merged with its text).\n // Drop it rather than emit an invalid request; the empty-turn\n // placeholder below covers a turn left with no content.\n if (!isSerializableBedrockReasoningBlock(reasoningBlock)) {\n return;\n }\n contentBlocks.push({\n reasoningContent:\n langchainReasoningBlockToBedrockReasoningBlock(reasoningBlock),\n } as BedrockContentBlock);\n } else {\n const cachePoint = getDefaultCachePoint(block);\n if (cachePoint != null) {\n contentBlocks.push({\n cachePoint,\n } as BedrockContentBlock);\n } else if (FOREIGN_REASONING_TYPES.some((t) => t === block.type)) {\n // Reasoning from another provider (Anthropic `thinking`/\n // `redacted_thinking`, Google `reasoning`, LibreChat `think`).\n // Bedrock's native reasoning is `reasoning_content` (handled above); a\n // foreign block carries a signature Bedrock cannot validate, so drop\n // it on a cross-provider handoff (e.g. Anthropic → Bedrock) rather\n // than crash. The Bedrock model produces its own reasoning. Anything\n // else unknown still throws below — real content must be surfaced.\n return;\n } else if (FOREIGN_SERVER_TOOL_TYPES.some((t) => t === block.type)) {\n // Google server-side tool call/response (e.g. URL context) — only\n // Google can execute it or validate its thought signature; drop it\n // on a cross-provider handoff rather than crash.\n return;\n } else {\n const blockValues = Object.fromEntries(\n Object.entries(block).filter(([key]) => key !== 'type')\n );\n throw new Error(\n `Unsupported content block type: ${block.type} with content of ${JSON.stringify(blockValues, null, 2)}`\n );\n }\n }\n });\n\n assistantMsg.content = [...(assistantMsg.content ?? []), ...contentBlocks];\n }\n\n // Important: this must be placed after any reasoning content blocks\n if (isAIMessage(msg) && msg.tool_calls != null && msg.tool_calls.length > 0) {\n const existingToolUseIds = new Set(\n (assistantMsg.content ?? [])\n .filter((content) => 'toolUse' in content)\n .map((content) => content.toolUse?.toolUseId)\n );\n const toolUseBlocks = msg.tool_calls\n .filter((toolCall) => !existingToolUseIds.has(toolCall.id))\n .map((toolCall) => ({\n toolUse: {\n toolUseId: toolCall.id,\n name: toolCall.name,\n input: toolCall.args as Record<string, unknown>,\n },\n }));\n assistantMsg.content = [\n ...(assistantMsg.content ?? []),\n ...toolUseBlocks,\n ] as BedrockContentBlock[];\n }\n\n // Bedrock rejects an assistant message with no content blocks; if filtering\n // (e.g. dropping foreign reasoning) left it empty, emit a placeholder.\n if (assistantMsg.content == null || assistantMsg.content.length === 0) {\n assistantMsg.content = [{ text: BEDROCK_EMPTY_TEXT_PLACEHOLDER }];\n }\n\n return assistantMsg;\n}\n\n/**\n * Convert a v1 format message from other providers to Bedrock format.\n * This handles messages with standard content blocks like tool_call and reasoning.\n * (Implements PR #9766 fix for output_version v1 detection)\n */\nfunction convertFromV1ToChatBedrockConverseMessage(\n msg: BaseMessage\n): BedrockMessage {\n const contentBlocks: BedrockContentBlock[] = [];\n const assistantMsg: BedrockMessage = {\n role: 'assistant',\n content: contentBlocks,\n };\n let droppedUnserializableContent = false;\n let unconvertedContentType: string | undefined;\n\n if (Array.isArray(msg.content)) {\n const concatenatedBlocks = concatenateLangchainReasoningBlocks(\n msg.content as Array<MessageContentComplex | MessageContentReasoningBlock>\n );\n for (const block of concatenatedBlocks) {\n if (typeof block === 'string') {\n if (!appendSerializableBedrockTextBlock(contentBlocks, block)) {\n droppedUnserializableContent = true;\n }\n } else if (block.type === 'text') {\n const text = (block as { text?: string }).text ?? '';\n if (!appendSerializableBedrockTextBlock(contentBlocks, text)) {\n droppedUnserializableContent = true;\n }\n } else if (block.type === 'tool_call') {\n const toolCall = block as {\n id: string;\n name: string;\n args: Record<string, unknown>;\n };\n contentBlocks.push({\n toolUse: {\n toolUseId: toolCall.id,\n name: toolCall.name,\n input: toolCall.args as Record<string, unknown>,\n },\n } as BedrockContentBlock);\n } else if (block.type === 'reasoning') {\n const reasoning = block as { reasoning?: string };\n /** Bedrock Converse rejects `reasoningText` with a null/empty `text`\n * (`Member must not be null`), e.g. when the producing model omitted\n * reasoning text (`thinking.display: \"omitted\"`) — drop rather than send. */\n if (reasoning.reasoning == null || reasoning.reasoning === '') {\n droppedUnserializableContent = true;\n continue;\n }\n contentBlocks.push({\n reasoningContent: {\n reasoningText: { text: reasoning.reasoning },\n },\n } as BedrockContentBlock);\n } else if (block.type === 'reasoning_content') {\n const reasoningBlock = block as MessageContentReasoningBlock;\n if (!isSerializableBedrockReasoningBlock(reasoningBlock)) {\n droppedUnserializableContent = true;\n continue;\n }\n contentBlocks.push({\n reasoningContent:\n langchainReasoningBlockToBedrockReasoningBlock(reasoningBlock),\n } as BedrockContentBlock);\n } else {\n unconvertedContentType ??= block.type;\n }\n }\n } else if (typeof msg.content === 'string') {\n if (!appendSerializableBedrockTextBlock(contentBlocks, msg.content)) {\n droppedUnserializableContent = true;\n }\n }\n\n // Also handle tool_calls from the message\n if (isAIMessage(msg) && msg.tool_calls != null && msg.tool_calls.length > 0) {\n // Check if tool calls are already in content\n const existingToolUseIds = new Set(\n contentBlocks\n .filter((c) => 'toolUse' in c)\n .map((c) => (c as { toolUse: { toolUseId: string } }).toolUse.toolUseId)\n );\n\n for (const tc of msg.tool_calls) {\n if (!existingToolUseIds.has(tc.id ?? '')) {\n contentBlocks.push({\n toolUse: {\n toolUseId: tc.id,\n name: tc.name,\n input: tc.args as Record<string, unknown>,\n },\n } as BedrockContentBlock);\n }\n }\n }\n\n const hasNoContent = contentBlocks.length === 0;\n if (hasNoContent && unconvertedContentType != null) {\n throw new Error(\n `Unsupported v1 content block type: ${unconvertedContentType}`\n );\n }\n if (hasNoContent && droppedUnserializableContent) {\n contentBlocks.push({ text: BEDROCK_EMPTY_TEXT_PLACEHOLDER });\n }\n\n return assistantMsg;\n}\n\n/**\n * Convert a human message to a Bedrock message.\n */\nfunction convertHumanMessageToConverseMessage(\n msg: BaseMessage\n): BedrockMessage {\n const userMessage: BedrockMessage = {\n role: 'user',\n content: [],\n };\n\n if (typeof msg.content === 'string') {\n userMessage.content = [{ text: msg.content }];\n } else if (Array.isArray(msg.content)) {\n userMessage.content = msg.content.map((block) =>\n convertLangChainContentBlockToConverseContentBlock({ block })\n );\n }\n\n return userMessage;\n}\n\n/**\n * Convert a tool message to a Bedrock message.\n */\nfunction convertToolMessageToConverseMessage(msg: BaseMessage): BedrockMessage {\n const toolCallId = (msg as { tool_call_id?: string }).tool_call_id;\n let isError = (msg as ToolMessage).status === 'error';\n\n let content: BedrockContentBlock[];\n if (typeof msg.content === 'string') {\n content = [{ text: msg.content }];\n } else if (Array.isArray(msg.content)) {\n content = msg.content.flatMap((block) => {\n if (typeof block === 'object' && block.type === 'tool_result') {\n if ((block as { is_error?: unknown }).is_error === true) {\n isError = true;\n }\n const toolResultContent = (block as { content?: unknown }).content;\n if (typeof toolResultContent === 'string') {\n return [{ text: toolResultContent }];\n }\n if (Array.isArray(toolResultContent)) {\n return toolResultContent.map((nestedBlock) =>\n convertLangChainContentBlockToConverseContentBlock({\n block: nestedBlock,\n onUnknown: 'passthrough',\n })\n );\n }\n return [\n {\n text: serializeStructuredValueBounded(\n toolResultContent,\n HARD_MAX_TOOL_RESULT_CHARS\n ).content,\n },\n ];\n }\n return [\n convertLangChainContentBlockToConverseContentBlock({\n block,\n onUnknown: 'passthrough',\n }),\n ];\n });\n } else {\n content = [{ text: String(msg.content) }];\n }\n\n // A `cachePoint` is a message-level ContentBlock — it is NOT a valid\n // ToolResultContentBlock. A tail prompt-cache breakpoint that anchors on a\n // tool result therefore ends up nested inside `toolResult.content`, which\n // Bedrock silently ignores (no cache write, no cache read). Hoist any\n // cachePoint(s) out of the tool result body so they sit as siblings after\n // it, which is the only position Bedrock honors.\n const toolResultContent: BedrockContentBlock[] = [];\n const trailingCachePoints: BedrockContentBlock[] = [];\n for (const block of content) {\n const cachePoint = getDefaultCachePoint(block);\n if (cachePoint != null) {\n trailingCachePoints.push({\n cachePoint,\n } as BedrockContentBlock);\n } else {\n toolResultContent.push(block);\n }\n }\n\n return {\n role: 'user',\n content: [\n {\n toolResult: {\n toolUseId: toolCallId,\n content: toolResultContent as { text: string }[],\n ...(isError ? { status: 'error' as const } : {}),\n },\n },\n ...trailingCachePoints,\n ],\n };\n}\n\n/**\n * Convert LangChain messages to Bedrock Converse messages.\n */\nexport function convertToConverseMessages(messages: BaseMessage[]): {\n converseMessages: BedrockMessage[];\n converseSystem: BedrockSystemContentBlock[];\n} {\n const converseSystem = messages\n .filter((msg) => msg._getType() === 'system')\n .flatMap((msg) => convertSystemMessageToConverseMessage(msg));\n\n const converseMessages = messages\n .filter((msg) => msg._getType() !== 'system')\n .map((msg) => {\n if (msg._getType() === 'ai') {\n return convertAIMessageToConverseMessage(msg);\n } else if (msg._getType() === 'human' || msg._getType() === 'generic') {\n return convertHumanMessageToConverseMessage(msg);\n } else if (msg._getType() === 'tool') {\n return convertToolMessageToConverseMessage(msg);\n } else {\n throw new Error(`Unsupported message type: ${msg._getType()}`);\n }\n });\n\n /**\n * Combine ALL consecutive user messages into one, not just tool-result\n * pairs. The Converse API documents strict role alternation; enforcement\n * varies by model family (Claude on Converse currently tolerates adjacent\n * user messages — verified live, 2026-07-28 — but the docs promise nothing\n * for the others), so the converter never emits the shape. The case that\n * matters: a `PostToolBatch`/`PreemptBoundary` hook injection lands a text\n * turn directly after tool results, and `ToolMessage` and `HumanMessage`\n * both convert to `role: 'user'` above. Block order is preserved\n * (toolResult blocks, then text) — verified live that Converse accepts the\n * mixed user message and answers both halves — and the toolUse/toolResult\n * pairing stays intact.\n */\n const combinedConverseMessages = converseMessages.reduce<BedrockMessage[]>(\n (acc, curr) => {\n if (acc.length === 0) {\n acc.push(curr);\n return acc;\n }\n const lastMessage = acc[acc.length - 1];\n if (lastMessage.role === 'user' && curr.role === 'user') {\n lastMessage.content = lastMessage.content?.concat(curr.content ?? []);\n } else {\n acc.push(curr);\n }\n return acc;\n },\n []\n );\n\n return { converseMessages: combinedConverseMessages, converseSystem };\n}\n"],"mappings":"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"}
@@ -1,16 +1,23 @@
1
+ import { appendCallbacks } from "../utils/callbacks.mjs";
1
2
  import "../common/enum.mjs";
2
3
  import "../common/index.mjs";
4
+ import { canSealPreempt } from "./preempt.mjs";
3
5
  import { stripAnthropicCacheControl, stripBedrockCacheControl } from "../messages/cache.mjs";
4
6
  import { modifyDeltaProperties, projectCacheControlledToolOutputsToText, projectComputerCallOutputsToText, projectOpenAIChatToolMessageContent, projectOpenAIResponsesToolMessageContent, projectOpenRouterToolMessageContent, projectSingleTextToolOutputsToText, projectStructuredToolOutputsToText, projectToolStreamContentForProvider } from "../messages/core.mjs";
7
+ import { safeDispatchCustomEvent } from "../utils/events.mjs";
8
+ import { coalesceAdjacentUserTurns, strictAlternationProviders } from "../messages/alternation.mjs";
9
+ import { appendPredecessorHandoffCue, removePredecessorHandoffCue } from "../messages/handoffCue.mjs";
5
10
  import "../messages/index.mjs";
6
- import { isOpenAILike } from "../utils/llm.mjs";
11
+ import { isAnthropicLike, isOpenAILike } from "../utils/llm.mjs";
7
12
  import { annotateMessagesForLLM } from "../tools/toolOutputReferences.mjs";
8
- import { ChatModelStreamHandler } from "../stream.mjs";
13
+ import { ChatModelStreamHandler, dispatchesChatModelStream } from "../stream.mjs";
9
14
  import { getContextOverflowInfo } from "../utils/errors.mjs";
10
15
  import { assertNotTruncatedToolCall } from "./truncation.mjs";
11
16
  import { manualToolStreamProviders } from "./providers.mjs";
12
17
  import { initializeModel } from "./init.mjs";
18
+ import { getCallbackManagerForConfig } from "@langchain/core/runnables";
13
19
  import { AIMessageChunk } from "@langchain/core/messages";
20
+ import { CallbackManager, CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
14
21
  import { concat } from "@langchain/core/utils/stream";
15
22
  //#region src/llm/invoke.ts
16
23
  function usesNativeOpenAIResponses(model, provider, callOptions) {
@@ -58,9 +65,19 @@ function projectMessagesForProvider({ model, messages, provider, maxToolResultCh
58
65
  if (provider === "bedrock") return stripAnthropicCacheControl(projectComputerCallOutputsToText(projectCacheControlledToolOutputsToText(providerInputMessages, maxToolResultChars)));
59
66
  return projectComputerCallOutputsToText(projectStructuredToolOutputsToText(projectSingleTextToolOutputsToText(stripAnthropicCacheControl(stripBedrockCacheControl(providerInputMessages)), maxToolResultChars), maxToolResultChars));
60
67
  }
68
+ /**
69
+ * The registered handler that owns content-part dispatch, if any.
70
+ *
71
+ * Detected by brand rather than by `instanceof`: a host that registers
72
+ * `new ChatModelStreamHandler()` to opt out of sealing gets wrapped by
73
+ * `createRunHandlers` on every `AgentSession` run, and by
74
+ * `composeEventHandlers` on a key collision. Both wrappers forward to the same
75
+ * dispatcher while failing an identity check, so an identity test would
76
+ * silently revoke the opt-out documented on `StreamPreemption`.
77
+ */
61
78
  function getRegisteredDefaultChatStreamHandler(context) {
62
79
  const handler = context?.handlerRegistry?.getHandler("on_chat_model_stream");
63
- return handler instanceof ChatModelStreamHandler ? handler : void 0;
80
+ return dispatchesChatModelStream(handler) ? handler : void 0;
64
81
  }
65
82
  function hasReasoningDetails(chunk) {
66
83
  const reasoningDetails = chunk.additional_kwargs.reasoning_details;
@@ -96,6 +113,183 @@ function getStreamHandlingChunk({ current, next, provider }) {
96
113
  additional_kwargs: removeReasoningDetails(next.additional_kwargs)
97
114
  }));
98
115
  }
116
+ /**
117
+ * Best-effort output-token count for a sealed turn, used only when the
118
+ * provider never got to send its usage chunk.
119
+ */
120
+ function countSealedTokens(context, metadata, messages) {
121
+ try {
122
+ const counter = context?.getAgentContext(metadata).tokenCounter;
123
+ if (counter == null) return;
124
+ let total = 0;
125
+ for (const message of messages) total += counter(message);
126
+ return total;
127
+ } catch {
128
+ return;
129
+ }
130
+ }
131
+ /**
132
+ * Instruction overhead the provider processed but that never appears in the
133
+ * message array: `createCallModel` pipes the model through
134
+ * `agentContext.systemRunnable` and binds tool schemas AFTER `messages` is
135
+ * formed, so the system prompt, dynamic instructions, summary and tool
136
+ * schemas are all billed yet invisible here.
137
+ *
138
+ * Read per-node via `getAgentContext(metadata)` rather than the graph-level
139
+ * accessor, which is hardcoded to `defaultAgentId` and would report the wrong
140
+ * agent's overhead in a `MultiAgentGraph`.
141
+ */
142
+ function sealedInstructionOverhead(context, metadata) {
143
+ try {
144
+ const agentContext = context?.getAgentContext(metadata);
145
+ return agentContext?.resolvedInstructionOverhead ?? agentContext?.instructionTokens ?? 0;
146
+ } catch {
147
+ return 0;
148
+ }
149
+ }
150
+ /**
151
+ * Best-effort usage for a turn the provider never got to bill us for.
152
+ *
153
+ * The prompt matters as much as the completion: the provider processed the
154
+ * ENTIRE prompt — messages plus instruction overhead — before we sealed, and
155
+ * every resume re-sends it, so under-counting input hides the expensive half
156
+ * of a preempted run.
157
+ *
158
+ * ESTIMATE, NOT MEASUREMENT. Messages are counted with the host's tokenizer
159
+ * rather than the provider's, and `toolSchemaTokens` applies a heuristic
160
+ * multiplier. It is also an over-count on the fallback path, where
161
+ * `tryFallbackProviders` builds a bare model with no `systemRunnable` pipe so
162
+ * the system prompt genuinely is not sent. Accepted rather than threaded
163
+ * through a flag: only the fallback-plus-seal combination is affected, and an
164
+ * over-count is safer than the previous fabricated `input_tokens: 0`.
165
+ *
166
+ * Marked `estimated_usage` so calibration can refuse to learn from it — a
167
+ * ratio derived from the same counter that produced the estimate is
168
+ * self-consistent by construction and would drag a provider's real
169
+ * calibration toward 1.0.
170
+ */
171
+ function synthesizeSealedUsage(context, chunk, prompt, metadata) {
172
+ if (chunk.usage_metadata != null) return;
173
+ const outputTokens = countSealedTokens(context, metadata, [chunk]);
174
+ if (outputTokens == null) return;
175
+ const inputTokens = (countSealedTokens(context, metadata, prompt) ?? 0) + sealedInstructionOverhead(context, metadata);
176
+ chunk.usage_metadata = {
177
+ input_tokens: inputTokens,
178
+ output_tokens: outputTokens,
179
+ total_tokens: inputTokens + outputTokens
180
+ };
181
+ chunk.response_metadata = {
182
+ ...chunk.response_metadata,
183
+ estimated_usage: true
184
+ };
185
+ }
186
+ function getMessageText(chunk) {
187
+ if (typeof chunk.content === "string") return chunk.content;
188
+ let text = "";
189
+ for (const block of chunk.content) if (block.type === "text") {
190
+ const value = block["text"];
191
+ if (typeof value === "string") text += value;
192
+ }
193
+ return text;
194
+ }
195
+ /**
196
+ * Ends the real model run for a turn that was sealed mid-stream.
197
+ *
198
+ * Mandatory, not cosmetic. `@langchain/core`'s `_streamIterator` calls
199
+ * `handleLLMEnd` after its try/catch with no `finally`, so breaking out of the
200
+ * consumer's `for await` produces a *return* completion that fires neither
201
+ * `handleLLMError` nor `handleLLMEnd`. The run would stay open in every
202
+ * callback handler: the host records no usage — and since each seal re-sends
203
+ * the whole prompt, N preemptions cost N unrecorded prompts — while LangSmith
204
+ * and Langfuse hold a span that never closes.
205
+ *
206
+ * `runId` cannot be dictated from here (the bound runnable consumes
207
+ * `config.runId` for its own run and hands the chat model a fresh one), but it
208
+ * can be OBSERVED: the capture handler installed at the `model.stream` call
209
+ * records it from `handleChatModelStart`, which fires before the first chunk.
210
+ * Rebuilding the manager against that id closes the real run, and the host's
211
+ * `on_chat_model_end` then arrives through the ordinary `streamEvents` path.
212
+ *
213
+ * Falls back to a custom-event dispatch if the id was never observed, so the
214
+ * host still records usage even when the native close is unavailable.
215
+ */
216
+ /**
217
+ * Every callbacks source the real model run would compose beyond the per-call
218
+ * config. `model` here is whatever `createCallModel` produced — with tools
219
+ * that is `bindTools(...)`'s `RunnableBinding`, and a system runnable pipes a
220
+ * `RunnableSequence` on top — while `clientOptions.callbacks` lives on the
221
+ * chat model at the BOTTOM of that stack. Walks `bound` (bindings) and
222
+ * `last`/`steps` (sequences), collecting each wrapper's own `callbacks` and
223
+ * any binding-config callbacks along the way, since the binding merges its
224
+ * config into the call before the chat model composes.
225
+ */
226
+ function collectModelCallbackSources(model) {
227
+ const sources = [];
228
+ const seen = /* @__PURE__ */ new Set();
229
+ let current = model;
230
+ while (current != null && typeof current === "object" && !seen.has(current)) {
231
+ seen.add(current);
232
+ const wrapper = current;
233
+ if (wrapper.callbacks != null) sources.push(wrapper.callbacks);
234
+ if (wrapper.config?.callbacks != null) sources.push(wrapper.config.callbacks);
235
+ current = wrapper.bound ?? wrapper.last ?? (Array.isArray(wrapper.steps) ? wrapper.steps[wrapper.steps.length - 1] : void 0);
236
+ }
237
+ return sources;
238
+ }
239
+ /**
240
+ * The serving model's id, read through the same wrapper stack
241
+ * `collectModelCallbackSources` walks — `bindTools` returns a
242
+ * `RunnableBinding` and a system runnable pipes a `RunnableSequence`, and
243
+ * neither exposes the chat model's `model` at the top level.
244
+ */
245
+ function resolveServingModelId(model) {
246
+ const seen = /* @__PURE__ */ new Set();
247
+ let current = model;
248
+ while (current != null && typeof current === "object" && !seen.has(current)) {
249
+ seen.add(current);
250
+ const wrapper = current;
251
+ if (typeof wrapper.model === "string" && wrapper.model !== "") return wrapper.model;
252
+ current = wrapper.bound ?? wrapper.last ?? (Array.isArray(wrapper.steps) ? wrapper.steps[wrapper.steps.length - 1] : void 0);
253
+ }
254
+ }
255
+ async function endSealedModelRun(context, chunk, prompt, llmRunId, config, model) {
256
+ const metadata = config?.metadata;
257
+ synthesizeSealedUsage(context, chunk, prompt, metadata);
258
+ if (llmRunId != null) try {
259
+ let callbackManager = await getCallbackManagerForConfig(config);
260
+ /**
261
+ * The real model run composes the per-call config's callbacks WITH the
262
+ * model's own (`CallbackManager.configure(config.callbacks,
263
+ * this.callbacks, …)` in `@langchain/core`'s base chat model), so a
264
+ * handler supplied via `clientOptions.callbacks` received
265
+ * `handleChatModelStart` for this run. Rebuilding from the config alone
266
+ * would close the run for every handler EXCEPT those — leaving their
267
+ * span open forever. Composed the same way the real run composes:
268
+ * model callbacks appended non-inheritable, parent run id preserved by
269
+ * `copy`, tracers deduped by `configure`.
270
+ */
271
+ for (const source of collectModelCallbackSources(model)) callbackManager = CallbackManager.configure(callbackManager ?? void 0, source) ?? callbackManager;
272
+ if (callbackManager != null) {
273
+ const runManager = new CallbackManagerForLLMRun(llmRunId, callbackManager.handlers, callbackManager.inheritableHandlers, callbackManager.tags, callbackManager.inheritableTags, callbackManager.metadata, callbackManager.inheritableMetadata, callbackManager.getParentRunId());
274
+ const generation = {
275
+ text: getMessageText(chunk),
276
+ message: chunk
277
+ };
278
+ await runManager.handleLLMEnd({
279
+ generations: [[generation]],
280
+ llmOutput: {}
281
+ });
282
+ return;
283
+ }
284
+ } catch (e) {
285
+ /**
286
+ * A sealed answer that reaches the user is worth more than a tidy
287
+ * trace. Fall through to the custom event rather than failing the run.
288
+ */
289
+ console.warn("[attemptInvoke] Native close of the sealed model run failed; falling back to a custom event:", e instanceof Error ? e.message : e);
290
+ }
291
+ await safeDispatchCustomEvent("on_chat_model_end", { output: chunk }, config);
292
+ }
99
293
  function appendStreamChunk({ current, next, provider }) {
100
294
  if (current == null) return next;
101
295
  return concat(current, removeOpenRouterFinalReasoningReplayContent({
@@ -129,7 +323,39 @@ async function attemptInvoke({ model, messages, provider, context, onChunk }, co
129
323
  });
130
324
  const registry = context?.getOrCreateToolOutputRegistry();
131
325
  const runId = config?.configurable?.run_id;
132
- const messagesForProvider = annotateMessagesForLLM(invocationMessages, registry, runId);
326
+ const annotated = annotateMessagesForLLM(invocationMessages, registry, runId);
327
+ /**
328
+ * Keyed on the provider ACTUALLY serving this call, not the agent's primary.
329
+ * `createCallModel` normalizes for the primary, but `tryFallbackProviders`
330
+ * re-sends the same array — so an OpenAI primary that fails after a boundary
331
+ * injected two human turns would hand a Bedrock or Mistral fallback the
332
+ * consecutive user turns those APIs reject, and the recovery request would
333
+ * fail for a reason unrelated to the original failure.
334
+ *
335
+ * `attemptInvoke` is the single funnel for primary, fallback and
336
+ * summarization calls, so applying it here covers all three. Idempotent, so
337
+ * the primary simply re-runs a no-op over already-coalesced messages.
338
+ */
339
+ /**
340
+ * Serving-provider re-keying for the predecessor handoff cue (#345). The
341
+ * PRIMARY's cue is baked in createCallModel's measured transform stage —
342
+ * appending after measurement could push a just-fits prompt over budget —
343
+ * so this funnel only corrects for fallbacks crossing provider families:
344
+ * a tolerant primary falling back to a Claude surface gains the cue here,
345
+ * and an Anthropic primary falling back to OpenAI/Mistral/Nova has the
346
+ * Claude-only synthetic turn stripped. Both helpers are identity on their
347
+ * no-op paths, so the primary's own pass re-runs for free.
348
+ *
349
+ * The serving model id is read through the wrapper stack (`bindTools`'
350
+ * binding, a system runnable's sequence) — a wrapper's top-level `.model`
351
+ * is undefined, and `isAnthropicLike` would otherwise default a wrapped
352
+ * Bedrock-Nova model to Claude. The context cast is widened deliberately:
353
+ * the type says every context is a full Graph, but summarization passes
354
+ * none and long-standing tests pass partial stubs.
355
+ */
356
+ const isRunProduced = context?.isRunProducedMessage;
357
+ const cued = isAnthropicLike(provider, { model: resolveServingModelId(model) }) ? appendPredecessorHandoffCue(annotated, isRunProduced == null ? void 0 : (message) => isRunProduced.call(context, message)) : removePredecessorHandoffCue(annotated);
358
+ const messagesForProvider = strictAlternationProviders.has(provider) ? coalesceAdjacentUserTurns(cued) : cued;
133
359
  /**
134
360
  * Stamp the provider that is ACTUALLY serving this invocation onto the
135
361
  * callback metadata. `attemptInvoke` is the single funnel for primary,
@@ -147,8 +373,23 @@ async function attemptInvoke({ model, messages, provider, context, onChunk }, co
147
373
  }
148
374
  };
149
375
  if (model.stream) {
150
- const stream = await model.stream(messagesForProvider, config);
376
+ /**
377
+ * Observed, not dictated. `handleChatModelStart` fires with the chat
378
+ * model's real run id before the first chunk, which is the only way to
379
+ * name the run a seal has to close — pinning `config.runId` does not
380
+ * survive the bound runnable. Installed only when preemption is
381
+ * configured, so a run that cannot seal carries no extra handler.
382
+ */
383
+ let sealedRunId;
384
+ const streamConfig = context?.preemption == null ? config : {
385
+ ...config,
386
+ callbacks: appendCallbacks(config.callbacks, [{ handleChatModelStart: (_llm, _messages, runId) => {
387
+ sealedRunId ??= runId;
388
+ } }])
389
+ };
390
+ const stream = await model.stream(messagesForProvider, streamConfig);
151
391
  let finalChunk;
392
+ let preempted = false;
152
393
  const registeredStreamHandler = getRegisteredDefaultChatStreamHandler(context);
153
394
  if (onChunk) for await (const chunk of stream) {
154
395
  await onChunk(chunk);
@@ -173,6 +414,22 @@ async function attemptInvoke({ model, messages, provider, context, onChunk }, co
173
414
  next: chunk,
174
415
  provider
175
416
  });
417
+ /**
418
+ * Only this loop may seal. The registered-handler branch below
419
+ * dispatches through `run.ts`'s decoupled `streamEvents` consumer,
420
+ * which can lag the accumulated chunk — sealing there would let the
421
+ * host index a content part the user has not been shown yet.
422
+ */
423
+ /**
424
+ * Cheap poll first, shape check second, budget claim last. The claim
425
+ * is what makes this safe under a parallel `MultiAgentGraph`: several
426
+ * agents share one graph and can each see the poll as true, but only
427
+ * one can take the slot, and a chunk that cannot seal never spends it.
428
+ */
429
+ if (context?.shouldPreemptStream() === true && canSealPreempt(finalChunk) && context.claimPreemptSeal()) {
430
+ preempted = true;
431
+ break;
432
+ }
176
433
  }
177
434
  } else {
178
435
  const metadata = config.metadata;
@@ -191,6 +448,13 @@ async function attemptInvoke({ model, messages, provider, context, onChunk }, co
191
448
  }
192
449
  }
193
450
  if (manualToolStreamProviders.has(provider)) finalChunk = modifyDeltaProperties(provider, finalChunk);
451
+ if (preempted && finalChunk != null) {
452
+ finalChunk.response_metadata = {
453
+ ...finalChunk.response_metadata,
454
+ preempted: true
455
+ };
456
+ await endSealedModelRun(context, finalChunk, messagesForProvider, sealedRunId, config, model);
457
+ }
194
458
  if ((finalChunk?.tool_calls?.length ?? 0) > 0) finalChunk.tool_calls = finalChunk.tool_calls?.filter((tool_call) => !!tool_call.name);
195
459
  assertNotTruncatedToolCall(finalChunk, provider);
196
460
  return { messages: [finalChunk] };
@@ -311,6 +575,6 @@ async function tryFallbackProviders({ fallbacks, tools, messages, config, primar
311
575
  if (preferred !== void 0) throw preferred;
312
576
  }
313
577
  //#endregion
314
- export { attemptInvoke, getFallbackErrorContext, getFallbackOverflowCandidates, projectMessagesForProvider, tryFallbackProviders };
578
+ export { attemptInvoke, getFallbackErrorContext, getFallbackOverflowCandidates, projectMessagesForProvider, resolveServingModelId, tryFallbackProviders };
315
579
 
316
580
  //# sourceMappingURL=invoke.mjs.map