@librechat/agents 3.2.37 → 3.2.39
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.
- package/dist/cjs/agents/AgentContext.cjs +25 -8
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +7 -4
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +20 -4
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +7 -1
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/toolCache.cjs +5 -4
- package/dist/cjs/llm/bedrock/toolCache.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +34 -17
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +1 -0
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/toolCache.cjs +18 -5
- package/dist/cjs/llm/openrouter/toolCache.cjs.map +1 -1
- package/dist/cjs/main.cjs +4 -0
- package/dist/cjs/messages/anthropicToolCache.cjs +75 -13
- package/dist/cjs/messages/anthropicToolCache.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +91 -35
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +3 -2
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +26 -9
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +8 -5
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +20 -4
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +7 -1
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/bedrock/toolCache.mjs +5 -4
- package/dist/esm/llm/bedrock/toolCache.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +34 -17
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +1 -0
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/toolCache.mjs +18 -5
- package/dist/esm/llm/openrouter/toolCache.mjs.map +1 -1
- package/dist/esm/main.mjs +2 -2
- package/dist/esm/messages/anthropicToolCache.mjs +75 -13
- package/dist/esm/messages/anthropicToolCache.mjs.map +1 -1
- package/dist/esm/messages/cache.mjs +88 -36
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +4 -3
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +11 -0
- package/dist/types/agents/__tests__/promptCacheLiveHelpers.d.ts +2 -0
- package/dist/types/llm/bedrock/index.d.ts +13 -0
- package/dist/types/llm/bedrock/toolCache.d.ts +2 -1
- package/dist/types/llm/openrouter/index.d.ts +8 -0
- package/dist/types/llm/openrouter/toolCache.d.ts +2 -1
- package/dist/types/messages/anthropicToolCache.d.ts +2 -1
- package/dist/types/messages/cache.d.ts +49 -5
- package/dist/types/types/llm.d.ts +14 -0
- package/package.json +7 -5
- package/src/agents/AgentContext.ts +64 -17
- package/src/agents/__tests__/AgentContext.anthropic.live.test.ts +6 -2
- package/src/agents/__tests__/AgentContext.bedrock.live.test.ts +7 -5
- package/src/agents/__tests__/AgentContext.openrouter.live.test.ts +1 -1
- package/src/agents/__tests__/AgentContext.test.ts +31 -19
- package/src/agents/__tests__/promptCacheLiveHelpers.ts +6 -2
- package/src/graphs/Graph.ts +40 -4
- package/src/llm/anthropic/utils/message_inputs.ts +33 -6
- package/src/llm/bedrock/index.ts +21 -1
- package/src/llm/bedrock/llm.spec.ts +61 -0
- package/src/llm/bedrock/toolCache.test.ts +24 -0
- package/src/llm/bedrock/toolCache.ts +12 -7
- package/src/llm/bedrock/utils/message_inputs.ts +57 -40
- package/src/llm/openrouter/index.ts +9 -0
- package/src/llm/openrouter/toolCache.test.ts +52 -1
- package/src/llm/openrouter/toolCache.ts +40 -6
- package/src/messages/__tests__/anthropicToolCache.test.ts +168 -0
- package/src/messages/anthropicToolCache.ts +118 -15
- package/src/messages/cache.test.ts +175 -0
- package/src/messages/cache.ts +133 -48
- package/src/summarization/node.ts +21 -2
- package/src/types/llm.ts +14 -0
|
@@ -241,15 +241,22 @@ const standardContentBlockConverter = {
|
|
|
241
241
|
}
|
|
242
242
|
};
|
|
243
243
|
/**
|
|
244
|
-
* Check if a block has a cache point
|
|
244
|
+
* Check if a block has a default cache point and return its normalized form,
|
|
245
|
+
* preserving an optional extended-TTL `ttl` (`'5m'` | `'1h'`). Returns
|
|
246
|
+
* `undefined` when the block is not a default cache point.
|
|
245
247
|
*/
|
|
246
|
-
function
|
|
247
|
-
if (typeof block !== "object" || block === null) return
|
|
248
|
-
if (!("cachePoint" in block)) return
|
|
248
|
+
function getDefaultCachePoint(block) {
|
|
249
|
+
if (typeof block !== "object" || block === null) return;
|
|
250
|
+
if (!("cachePoint" in block)) return;
|
|
249
251
|
const cachePoint = block.cachePoint;
|
|
250
|
-
if (typeof cachePoint !== "object" || cachePoint === null) return
|
|
251
|
-
if (!("type" in cachePoint)) return
|
|
252
|
-
|
|
252
|
+
if (typeof cachePoint !== "object" || cachePoint === null) return;
|
|
253
|
+
if (!("type" in cachePoint)) return;
|
|
254
|
+
if (cachePoint.type !== "default") return;
|
|
255
|
+
const ttl = cachePoint.ttl;
|
|
256
|
+
return ttl === "5m" || ttl === "1h" ? {
|
|
257
|
+
type: "default",
|
|
258
|
+
ttl
|
|
259
|
+
} : { type: "default" };
|
|
253
260
|
}
|
|
254
261
|
/**
|
|
255
262
|
* Convert a LangChain content block to a Bedrock Converse content block.
|
|
@@ -285,7 +292,8 @@ function convertLangChainContentBlockToConverseContentBlock({ block, onUnknown =
|
|
|
285
292
|
if (block.type === "audio" && block.audio !== void 0) return { audio: block.audio };
|
|
286
293
|
if (block.type === "audio") return convertMultimodalAudioBlock(block);
|
|
287
294
|
if (block.type === "document" && block.document !== void 0) return { document: block.document };
|
|
288
|
-
|
|
295
|
+
const cachePoint = getDefaultCachePoint(block);
|
|
296
|
+
if (cachePoint != null) return { cachePoint };
|
|
289
297
|
if (onUnknown === "throw") throw new Error(`Unsupported content block type: ${block.type}`);
|
|
290
298
|
else return block;
|
|
291
299
|
}
|
|
@@ -297,8 +305,11 @@ function convertSystemMessageToConverseMessage(msg) {
|
|
|
297
305
|
else if (Array.isArray(msg.content) && msg.content.length > 0) {
|
|
298
306
|
const contentBlocks = [];
|
|
299
307
|
for (const block of msg.content) if (typeof block === "object" && block.type === "text" && typeof block.text === "string") contentBlocks.push({ text: block.text });
|
|
300
|
-
else
|
|
301
|
-
|
|
308
|
+
else {
|
|
309
|
+
const cachePoint = getDefaultCachePoint(block);
|
|
310
|
+
if (cachePoint == null) break;
|
|
311
|
+
contentBlocks.push({ cachePoint });
|
|
312
|
+
}
|
|
302
313
|
if (msg.content.length === contentBlocks.length) return contentBlocks;
|
|
303
314
|
}
|
|
304
315
|
throw new Error("System message content must be either a string, or an array of text blocks, optionally including a cache point.");
|
|
@@ -330,11 +341,14 @@ function convertAIMessageToConverseMessage(msg) {
|
|
|
330
341
|
const reasoningBlock = block;
|
|
331
342
|
if (!isSerializableBedrockReasoningBlock(reasoningBlock)) return;
|
|
332
343
|
contentBlocks.push({ reasoningContent: langchainReasoningBlockToBedrockReasoningBlock(reasoningBlock) });
|
|
333
|
-
} else
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
344
|
+
} else {
|
|
345
|
+
const cachePoint = getDefaultCachePoint(block);
|
|
346
|
+
if (cachePoint != null) contentBlocks.push({ cachePoint });
|
|
347
|
+
else if (FOREIGN_REASONING_TYPES.some((t) => t === block.type)) return;
|
|
348
|
+
else {
|
|
349
|
+
const blockValues = Object.fromEntries(Object.entries(block).filter(([key]) => key !== "type"));
|
|
350
|
+
throw new Error(`Unsupported content block type: ${block.type} with content of ${JSON.stringify(blockValues, null, 2)}`);
|
|
351
|
+
}
|
|
338
352
|
}
|
|
339
353
|
});
|
|
340
354
|
assistantMsg.content = [...assistantMsg.content ?? [], ...contentBlocks];
|
|
@@ -411,8 +425,11 @@ function convertToolMessageToConverseMessage(msg) {
|
|
|
411
425
|
else content = [{ text: String(msg.content) }];
|
|
412
426
|
const toolResultContent = [];
|
|
413
427
|
const trailingCachePoints = [];
|
|
414
|
-
for (const block of content)
|
|
415
|
-
|
|
428
|
+
for (const block of content) {
|
|
429
|
+
const cachePoint = getDefaultCachePoint(block);
|
|
430
|
+
if (cachePoint != null) trailingCachePoints.push({ cachePoint });
|
|
431
|
+
else toolResultContent.push(block);
|
|
432
|
+
}
|
|
416
433
|
return {
|
|
417
434
|
role: "user",
|
|
418
435
|
content: [{ toolResult: {
|
|
@@ -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 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';\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 * 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\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\n for (const block of content) {\n if (block.type === 'reasoning_content') {\n const currentReasoning = block as MessageContentReasoningBlock;\n const lastIndex = result.length - 1;\n\n // Check if we can merge with the previous block\n if (lastIndex >= 0) {\n const lastBlock = result[lastIndex];\n if (\n lastBlock.type === 'reasoning_content' &&\n (lastBlock as MessageContentReasoningBlock).reasoningText != null &&\n currentReasoning.reasoningText != null\n ) {\n const lastReasoning = lastBlock as MessageContentReasoningBlock;\n // Merge consecutive reasoning text blocks\n const lastText = lastReasoning.reasoningText?.text;\n const currentText = currentReasoning.reasoningText.text;\n if (\n lastText != null &&\n lastText !== '' &&\n currentText != null &&\n currentText !== ''\n ) {\n lastReasoning.reasoningText!.text = lastText + currentText;\n } else if (\n currentReasoning.reasoningText.signature != null &&\n currentReasoning.reasoningText.signature !== ''\n ) {\n lastReasoning.reasoningText!.signature =\n currentReasoning.reasoningText.signature;\n }\n continue;\n }\n }\n\n result.push({ ...block } as MessageContentReasoningBlock);\n } else {\n result.push(block);\n }\n }\n\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\n/**\n * Check if a block has a cache point.\n */\nfunction isDefaultCachePoint(block: unknown): boolean {\n if (typeof block !== 'object' || block === null) {\n return false;\n }\n if (!('cachePoint' in block)) {\n return false;\n }\n const cachePoint = (block as { cachePoint?: unknown }).cachePoint;\n if (typeof cachePoint !== 'object' || cachePoint === null) {\n return false;\n }\n if (!('type' in cachePoint)) {\n return false;\n }\n return (cachePoint as { type?: string }).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 if (isDefaultCachePoint(block)) {\n return {\n cachePoint: {\n type: 'default',\n },\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 if (isDefaultCachePoint(block)) {\n contentBlocks.push({\n cachePoint: {\n type: 'default',\n },\n } as BedrockSystemContentBlock);\n } else {\n break;\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 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 // Skip completely empty text blocks (common in AI messages with tool_use blocks)\n if (text === '') {\n return;\n }\n // Merge whitespace/newlines with previous text blocks to avoid validation errors.\n const cleanedText = text.replace(/\\n/g, '').trim();\n if (cleanedText === '') {\n if (contentBlocks.length > 0) {\n const lastBlock = contentBlocks[contentBlocks.length - 1];\n if ('text' in lastBlock) {\n const mergedTextContent = `${lastBlock.text}${text}`;\n (lastBlock as { text: string }).text = mergedTextContent;\n }\n }\n } else {\n contentBlocks.push({ text });\n }\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 if (isDefaultCachePoint(block)) {\n contentBlocks.push({\n cachePoint: {\n type: 'default',\n },\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`). Bedrock's\n // native reasoning is `reasoning_content` (handled above); a foreign\n // block carries a signature Bedrock cannot validate, so drop it on a\n // cross-provider handoff (e.g. Anthropic → Bedrock) rather than crash.\n // The Bedrock model produces its own reasoning. Anything else unknown\n // still throws below — real content must be surfaced, not dropped.\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 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 toolUseBlocks = msg.tool_calls.map((tc) => ({\n toolUse: {\n toolUseId: tc.id,\n name: tc.name,\n input: tc.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 assistantMsg: BedrockMessage = {\n role: 'assistant',\n content: [],\n };\n\n if (Array.isArray(msg.content)) {\n for (const block of msg.content as Array<\n MessageContentComplex | MessageContentReasoningBlock\n >) {\n if (typeof block === 'string') {\n assistantMsg.content?.push({ text: block });\n } else if (block.type === 'text') {\n assistantMsg.content?.push({ text: (block as { text: string }).text });\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 assistantMsg.content?.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 assistantMsg.content?.push({\n reasoningContent: {\n reasoningText: { text: reasoning.reasoning },\n },\n } as BedrockContentBlock);\n } else if (block.type === 'reasoning_content') {\n assistantMsg.content?.push({\n reasoningContent: langchainReasoningBlockToBedrockReasoningBlock(\n block as MessageContentReasoningBlock\n ),\n } as BedrockContentBlock);\n }\n }\n } else if (typeof msg.content === 'string' && msg.content !== '') {\n assistantMsg.content?.push({ text: msg.content });\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 assistantMsg.content\n ?.filter((c) => 'toolUse' in c)\n .map(\n (c) => (c as { toolUse: { toolUseId: string } }).toolUse.toolUseId\n ) ?? []\n );\n\n for (const tc of msg.tool_calls) {\n if (!existingToolUseIds.has(tc.id ?? '')) {\n assistantMsg.content?.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 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\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.map((block) =>\n convertLangChainContentBlockToConverseContentBlock({\n block,\n onUnknown: 'passthrough',\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 if (isDefaultCachePoint(block)) {\n trailingCachePoints.push({\n cachePoint: { type: 'default' },\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 },\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 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';\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 * 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\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\n for (const block of content) {\n if (block.type === 'reasoning_content') {\n const currentReasoning = block as MessageContentReasoningBlock;\n const lastIndex = result.length - 1;\n\n // Check if we can merge with the previous block\n if (lastIndex >= 0) {\n const lastBlock = result[lastIndex];\n if (\n lastBlock.type === 'reasoning_content' &&\n (lastBlock as MessageContentReasoningBlock).reasoningText != null &&\n currentReasoning.reasoningText != null\n ) {\n const lastReasoning = lastBlock as MessageContentReasoningBlock;\n // Merge consecutive reasoning text blocks\n const lastText = lastReasoning.reasoningText?.text;\n const currentText = currentReasoning.reasoningText.text;\n if (\n lastText != null &&\n lastText !== '' &&\n currentText != null &&\n currentText !== ''\n ) {\n lastReasoning.reasoningText!.text = lastText + currentText;\n } else if (\n currentReasoning.reasoningText.signature != null &&\n currentReasoning.reasoningText.signature !== ''\n ) {\n lastReasoning.reasoningText!.signature =\n currentReasoning.reasoningText.signature;\n }\n continue;\n }\n }\n\n result.push({ ...block } as MessageContentReasoningBlock);\n } else {\n result.push(block);\n }\n }\n\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 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 // Skip completely empty text blocks (common in AI messages with tool_use blocks)\n if (text === '') {\n return;\n }\n // Merge whitespace/newlines with previous text blocks to avoid validation errors.\n const cleanedText = text.replace(/\\n/g, '').trim();\n if (cleanedText === '') {\n if (contentBlocks.length > 0) {\n const lastBlock = contentBlocks[contentBlocks.length - 1];\n if ('text' in lastBlock) {\n const mergedTextContent = `${lastBlock.text}${text}`;\n (lastBlock as { text: string }).text = mergedTextContent;\n }\n }\n } else {\n contentBlocks.push({ text });\n }\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 {\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 toolUseBlocks = msg.tool_calls.map((tc) => ({\n toolUse: {\n toolUseId: tc.id,\n name: tc.name,\n input: tc.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 assistantMsg: BedrockMessage = {\n role: 'assistant',\n content: [],\n };\n\n if (Array.isArray(msg.content)) {\n for (const block of msg.content as Array<\n MessageContentComplex | MessageContentReasoningBlock\n >) {\n if (typeof block === 'string') {\n assistantMsg.content?.push({ text: block });\n } else if (block.type === 'text') {\n assistantMsg.content?.push({ text: (block as { text: string }).text });\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 assistantMsg.content?.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 assistantMsg.content?.push({\n reasoningContent: {\n reasoningText: { text: reasoning.reasoning },\n },\n } as BedrockContentBlock);\n } else if (block.type === 'reasoning_content') {\n assistantMsg.content?.push({\n reasoningContent: langchainReasoningBlockToBedrockReasoningBlock(\n block as MessageContentReasoningBlock\n ),\n } as BedrockContentBlock);\n }\n }\n } else if (typeof msg.content === 'string' && msg.content !== '') {\n assistantMsg.content?.push({ text: msg.content });\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 assistantMsg.content\n ?.filter((c) => 'toolUse' in c)\n .map(\n (c) => (c as { toolUse: { toolUseId: string } }).toolUse.toolUseId\n ) ?? []\n );\n\n for (const tc of msg.tool_calls) {\n if (!existingToolUseIds.has(tc.id ?? '')) {\n assistantMsg.content?.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 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\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.map((block) =>\n convertLangChainContentBlockToConverseContentBlock({\n block,\n onUnknown: 'passthrough',\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 },\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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"}
|
|
@@ -17,6 +17,7 @@ var ChatOpenRouter = class extends ChatOpenAI {
|
|
|
17
17
|
constructor(_fields) {
|
|
18
18
|
const fieldsWithoutPromptCache = { ..._fields };
|
|
19
19
|
delete fieldsWithoutPromptCache.promptCache;
|
|
20
|
+
delete fieldsWithoutPromptCache.promptCacheTtl;
|
|
20
21
|
const { include_reasoning, reasoning: openRouterReasoning, modelKwargs = {}, ...fields } = fieldsWithoutPromptCache;
|
|
21
22
|
const { reasoning: mkReasoning, ...restModelKwargs } = modelKwargs;
|
|
22
23
|
const mergedReasoning = mkReasoning != null || openRouterReasoning != null ? {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/llm/openrouter/index.ts"],"sourcesContent":["import type {\n ChatOpenAICallOptions,\n OpenAIChatInput,\n OpenAIClient,\n} from '@langchain/openai';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport { ChatOpenAI, emitStreamChunkCallback } from '@/llm/openai';\n\nexport type OpenRouterReasoningEffort =\n | 'xhigh'\n | 'high'\n | 'medium'\n | 'low'\n | 'minimal'\n | 'none';\n\nexport interface OpenRouterReasoning {\n effort?: OpenRouterReasoningEffort;\n max_tokens?: number;\n exclude?: boolean;\n enabled?: boolean;\n}\n\nexport interface ChatOpenRouterCallOptions\n extends Omit<ChatOpenAICallOptions, 'reasoning'> {\n /** @deprecated Use `reasoning` object instead */\n include_reasoning?: boolean;\n reasoning?: OpenRouterReasoning;\n modelKwargs?: OpenAIChatInput['modelKwargs'];\n promptCache?: boolean;\n}\n\nexport type ChatOpenRouterInput = Partial<\n ChatOpenRouterCallOptions & OpenAIChatInput\n>;\n\n/** invocationParams return type extended with OpenRouter reasoning */\nexport type OpenRouterInvocationParams = Omit<\n OpenAIClient.Chat.ChatCompletionCreateParams,\n 'messages'\n> & {\n reasoning?: OpenRouterReasoning;\n};\n\ntype InvocationParamsExtra = {\n streaming?: boolean;\n};\n\ninterface OpenRouterReasoningTextDetail {\n type: 'reasoning.text';\n text?: string;\n format?: string;\n index?: number;\n}\n\ninterface OpenRouterReasoningEncryptedDetail {\n type: 'reasoning.encrypted';\n id?: string;\n data?: string;\n format?: string;\n index?: number;\n}\n\ntype OpenRouterReasoningDetail =\n | OpenRouterReasoningTextDetail\n | OpenRouterReasoningEncryptedDetail;\n\nfunction isReasoningTextDetail(\n value: unknown\n): value is OpenRouterReasoningTextDetail {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n value.type === 'reasoning.text'\n );\n}\n\nfunction isReasoningEncryptedDetail(\n value: unknown\n): value is OpenRouterReasoningEncryptedDetail {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n value.type === 'reasoning.encrypted'\n );\n}\n\nfunction getReasoningDetails(value: unknown): OpenRouterReasoningDetail[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value.filter(\n (detail): detail is OpenRouterReasoningDetail =>\n isReasoningTextDetail(detail) || isReasoningEncryptedDetail(detail)\n );\n}\n\nexport class ChatOpenRouter extends ChatOpenAI {\n private openRouterReasoning?: OpenRouterReasoning;\n /** @deprecated Use `reasoning` object instead */\n private includeReasoning?: boolean;\n\n constructor(_fields: ChatOpenRouterInput) {\n const fieldsWithoutPromptCache: ChatOpenRouterInput = { ..._fields };\n delete fieldsWithoutPromptCache.promptCache;\n\n const {\n include_reasoning,\n reasoning: openRouterReasoning,\n modelKwargs = {},\n ...fields\n } = fieldsWithoutPromptCache;\n\n // Extract reasoning from modelKwargs if provided there (e.g., from LLMConfig)\n const { reasoning: mkReasoning, ...restModelKwargs } = modelKwargs as {\n reasoning?: OpenRouterReasoning;\n } & Record<string, unknown>;\n const mergedReasoning =\n mkReasoning != null || openRouterReasoning != null\n ? {\n ...mkReasoning,\n ...openRouterReasoning,\n }\n : undefined;\n const runtimeReasoning =\n mergedReasoning ??\n (include_reasoning === true ? { enabled: true } : undefined);\n const parentModelKwargs =\n runtimeReasoning == null\n ? restModelKwargs\n : { ...restModelKwargs, reasoning: runtimeReasoning };\n\n super({\n ...fields,\n modelKwargs: parentModelKwargs,\n includeReasoningDetails: true,\n convertReasoningDetailsToContent: true,\n });\n\n // Merge reasoning config: modelKwargs.reasoning < constructor reasoning\n if (mergedReasoning != null) {\n this.openRouterReasoning = mergedReasoning;\n }\n\n this.includeReasoning = include_reasoning;\n }\n static lc_name(): 'LibreChatOpenRouter' {\n return 'LibreChatOpenRouter';\n }\n\n // @ts-expect-error - OpenRouter reasoning extends OpenAI Reasoning with additional\n // effort levels ('xhigh' | 'none' | 'minimal') not in ReasoningEffort.\n // The parent's generic conditional return type cannot be widened in an override.\n override invocationParams(\n options?: this['ParsedCallOptions'],\n extra?: InvocationParamsExtra\n ): OpenRouterInvocationParams {\n type MutableParams = Omit<\n OpenAIClient.Chat.ChatCompletionCreateParams,\n 'messages'\n > & { reasoning_effort?: string; reasoning?: OpenRouterReasoning };\n\n const optionsWithDefaults = this._combineCallOptions(options);\n const params = (\n this._useResponsesApi(options)\n ? this.responses.invocationParams(optionsWithDefaults)\n : this.completions.invocationParams(optionsWithDefaults, extra)\n ) as MutableParams;\n\n // Remove the OpenAI-native reasoning_effort that the parent sets;\n // OpenRouter uses a `reasoning` object instead\n delete params.reasoning_effort;\n\n // Build the OpenRouter reasoning config\n const reasoning = this.buildOpenRouterReasoning(optionsWithDefaults);\n if (reasoning != null) {\n params.reasoning = reasoning;\n } else {\n delete params.reasoning;\n }\n\n return params;\n }\n\n private buildOpenRouterReasoning(\n options?: this['ParsedCallOptions']\n ): OpenRouterReasoning | undefined {\n let reasoning: OpenRouterReasoning | undefined;\n\n // 1. Instance-level reasoning config (from constructor)\n if (this.openRouterReasoning != null) {\n reasoning = { ...this.openRouterReasoning };\n }\n\n // 2. LangChain-style reasoning params (from parent's `this.reasoning`)\n const lcReasoning = this.getReasoningParams(options);\n if (lcReasoning?.effort != null) {\n reasoning = {\n ...reasoning,\n effort: lcReasoning.effort as OpenRouterReasoningEffort,\n };\n }\n\n // 3. Call-level reasoning override\n const callReasoning = (options as ChatOpenRouterCallOptions | undefined)\n ?.reasoning;\n if (callReasoning != null) {\n reasoning = { ...reasoning, ...callReasoning };\n }\n\n // 4. Legacy include_reasoning backward compatibility\n if (reasoning == null && this.includeReasoning === true) {\n reasoning = { enabled: true };\n }\n\n return reasoning;\n }\n\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const reasoningTextByIndex = new Map<\n number,\n OpenRouterReasoningTextDetail\n >();\n const reasoningEncryptedById = new Map<\n string,\n OpenRouterReasoningEncryptedDetail\n >();\n\n for await (const generationChunk of super._streamResponseChunks(\n messages,\n options,\n undefined\n )) {\n let currentReasoningText = '';\n const reasoningDetails = getReasoningDetails(\n generationChunk.message.additional_kwargs.reasoning_details\n );\n\n for (const detail of reasoningDetails) {\n if (detail.type === 'reasoning.text') {\n currentReasoningText += detail.text ?? '';\n const index = detail.index ?? 0;\n const existing = reasoningTextByIndex.get(index);\n if (existing != null) {\n existing.text = `${existing.text ?? ''}${detail.text ?? ''}`;\n continue;\n }\n reasoningTextByIndex.set(index, {\n ...detail,\n text: detail.text ?? '',\n });\n continue;\n }\n if (detail.id != null) {\n reasoningEncryptedById.set(detail.id, { ...detail });\n }\n }\n\n if (\n currentReasoningText.length > 0 &&\n generationChunk.message.additional_kwargs.reasoning == null\n ) {\n generationChunk.message.additional_kwargs.reasoning =\n currentReasoningText;\n }\n\n if (generationChunk.generationInfo?.finish_reason != null) {\n const finalReasoningDetails = [\n ...reasoningTextByIndex.values(),\n ...reasoningEncryptedById.values(),\n ];\n if (finalReasoningDetails.length > 0) {\n generationChunk.message.additional_kwargs.reasoning_details =\n finalReasoningDetails;\n } else {\n delete generationChunk.message.additional_kwargs.reasoning_details;\n }\n await emitStreamChunkCallback(generationChunk, runManager);\n yield generationChunk;\n continue;\n }\n\n delete generationChunk.message.additional_kwargs.reasoning_details;\n await emitStreamChunkCallback(generationChunk, runManager);\n yield generationChunk;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/llm/openrouter/index.ts"],"sourcesContent":["import type {\n ChatOpenAICallOptions,\n OpenAIChatInput,\n OpenAIClient,\n} from '@langchain/openai';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type { PromptCacheTtl } from '@/messages/cache';\nimport { ChatOpenAI, emitStreamChunkCallback } from '@/llm/openai';\n\nexport type OpenRouterReasoningEffort =\n | 'xhigh'\n | 'high'\n | 'medium'\n | 'low'\n | 'minimal'\n | 'none';\n\nexport interface OpenRouterReasoning {\n effort?: OpenRouterReasoningEffort;\n max_tokens?: number;\n exclude?: boolean;\n enabled?: boolean;\n}\n\nexport interface ChatOpenRouterCallOptions\n extends Omit<ChatOpenAICallOptions, 'reasoning'> {\n /** @deprecated Use `reasoning` object instead */\n include_reasoning?: boolean;\n reasoning?: OpenRouterReasoning;\n modelKwargs?: OpenAIChatInput['modelKwargs'];\n promptCache?: boolean;\n /**\n * Prompt-cache breakpoint TTL. Defaults to `'1h'` (extended cache) when\n * `promptCache` is enabled; set `'5m'` for the legacy 5-minute behavior.\n * OpenRouter forwards this to Claude upstreams (Anthropic / Bedrock / Vertex),\n * which downgrade to 5m where the extended TTL isn't supported.\n */\n promptCacheTtl?: PromptCacheTtl;\n}\n\nexport type ChatOpenRouterInput = Partial<\n ChatOpenRouterCallOptions & OpenAIChatInput\n>;\n\n/** invocationParams return type extended with OpenRouter reasoning */\nexport type OpenRouterInvocationParams = Omit<\n OpenAIClient.Chat.ChatCompletionCreateParams,\n 'messages'\n> & {\n reasoning?: OpenRouterReasoning;\n};\n\ntype InvocationParamsExtra = {\n streaming?: boolean;\n};\n\ninterface OpenRouterReasoningTextDetail {\n type: 'reasoning.text';\n text?: string;\n format?: string;\n index?: number;\n}\n\ninterface OpenRouterReasoningEncryptedDetail {\n type: 'reasoning.encrypted';\n id?: string;\n data?: string;\n format?: string;\n index?: number;\n}\n\ntype OpenRouterReasoningDetail =\n | OpenRouterReasoningTextDetail\n | OpenRouterReasoningEncryptedDetail;\n\nfunction isReasoningTextDetail(\n value: unknown\n): value is OpenRouterReasoningTextDetail {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n value.type === 'reasoning.text'\n );\n}\n\nfunction isReasoningEncryptedDetail(\n value: unknown\n): value is OpenRouterReasoningEncryptedDetail {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n value.type === 'reasoning.encrypted'\n );\n}\n\nfunction getReasoningDetails(value: unknown): OpenRouterReasoningDetail[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value.filter(\n (detail): detail is OpenRouterReasoningDetail =>\n isReasoningTextDetail(detail) || isReasoningEncryptedDetail(detail)\n );\n}\n\nexport class ChatOpenRouter extends ChatOpenAI {\n private openRouterReasoning?: OpenRouterReasoning;\n /** @deprecated Use `reasoning` object instead */\n private includeReasoning?: boolean;\n\n constructor(_fields: ChatOpenRouterInput) {\n const fieldsWithoutPromptCache: ChatOpenRouterInput = { ..._fields };\n delete fieldsWithoutPromptCache.promptCache;\n delete fieldsWithoutPromptCache.promptCacheTtl;\n\n const {\n include_reasoning,\n reasoning: openRouterReasoning,\n modelKwargs = {},\n ...fields\n } = fieldsWithoutPromptCache;\n\n // Extract reasoning from modelKwargs if provided there (e.g., from LLMConfig)\n const { reasoning: mkReasoning, ...restModelKwargs } = modelKwargs as {\n reasoning?: OpenRouterReasoning;\n } & Record<string, unknown>;\n const mergedReasoning =\n mkReasoning != null || openRouterReasoning != null\n ? {\n ...mkReasoning,\n ...openRouterReasoning,\n }\n : undefined;\n const runtimeReasoning =\n mergedReasoning ??\n (include_reasoning === true ? { enabled: true } : undefined);\n const parentModelKwargs =\n runtimeReasoning == null\n ? restModelKwargs\n : { ...restModelKwargs, reasoning: runtimeReasoning };\n\n super({\n ...fields,\n modelKwargs: parentModelKwargs,\n includeReasoningDetails: true,\n convertReasoningDetailsToContent: true,\n });\n\n // Merge reasoning config: modelKwargs.reasoning < constructor reasoning\n if (mergedReasoning != null) {\n this.openRouterReasoning = mergedReasoning;\n }\n\n this.includeReasoning = include_reasoning;\n }\n static lc_name(): 'LibreChatOpenRouter' {\n return 'LibreChatOpenRouter';\n }\n\n // @ts-expect-error - OpenRouter reasoning extends OpenAI Reasoning with additional\n // effort levels ('xhigh' | 'none' | 'minimal') not in ReasoningEffort.\n // The parent's generic conditional return type cannot be widened in an override.\n override invocationParams(\n options?: this['ParsedCallOptions'],\n extra?: InvocationParamsExtra\n ): OpenRouterInvocationParams {\n type MutableParams = Omit<\n OpenAIClient.Chat.ChatCompletionCreateParams,\n 'messages'\n > & { reasoning_effort?: string; reasoning?: OpenRouterReasoning };\n\n const optionsWithDefaults = this._combineCallOptions(options);\n const params = (\n this._useResponsesApi(options)\n ? this.responses.invocationParams(optionsWithDefaults)\n : this.completions.invocationParams(optionsWithDefaults, extra)\n ) as MutableParams;\n\n // Remove the OpenAI-native reasoning_effort that the parent sets;\n // OpenRouter uses a `reasoning` object instead\n delete params.reasoning_effort;\n\n // Build the OpenRouter reasoning config\n const reasoning = this.buildOpenRouterReasoning(optionsWithDefaults);\n if (reasoning != null) {\n params.reasoning = reasoning;\n } else {\n delete params.reasoning;\n }\n\n return params;\n }\n\n private buildOpenRouterReasoning(\n options?: this['ParsedCallOptions']\n ): OpenRouterReasoning | undefined {\n let reasoning: OpenRouterReasoning | undefined;\n\n // 1. Instance-level reasoning config (from constructor)\n if (this.openRouterReasoning != null) {\n reasoning = { ...this.openRouterReasoning };\n }\n\n // 2. LangChain-style reasoning params (from parent's `this.reasoning`)\n const lcReasoning = this.getReasoningParams(options);\n if (lcReasoning?.effort != null) {\n reasoning = {\n ...reasoning,\n effort: lcReasoning.effort as OpenRouterReasoningEffort,\n };\n }\n\n // 3. Call-level reasoning override\n const callReasoning = (options as ChatOpenRouterCallOptions | undefined)\n ?.reasoning;\n if (callReasoning != null) {\n reasoning = { ...reasoning, ...callReasoning };\n }\n\n // 4. Legacy include_reasoning backward compatibility\n if (reasoning == null && this.includeReasoning === true) {\n reasoning = { enabled: true };\n }\n\n return reasoning;\n }\n\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const reasoningTextByIndex = new Map<\n number,\n OpenRouterReasoningTextDetail\n >();\n const reasoningEncryptedById = new Map<\n string,\n OpenRouterReasoningEncryptedDetail\n >();\n\n for await (const generationChunk of super._streamResponseChunks(\n messages,\n options,\n undefined\n )) {\n let currentReasoningText = '';\n const reasoningDetails = getReasoningDetails(\n generationChunk.message.additional_kwargs.reasoning_details\n );\n\n for (const detail of reasoningDetails) {\n if (detail.type === 'reasoning.text') {\n currentReasoningText += detail.text ?? '';\n const index = detail.index ?? 0;\n const existing = reasoningTextByIndex.get(index);\n if (existing != null) {\n existing.text = `${existing.text ?? ''}${detail.text ?? ''}`;\n continue;\n }\n reasoningTextByIndex.set(index, {\n ...detail,\n text: detail.text ?? '',\n });\n continue;\n }\n if (detail.id != null) {\n reasoningEncryptedById.set(detail.id, { ...detail });\n }\n }\n\n if (\n currentReasoningText.length > 0 &&\n generationChunk.message.additional_kwargs.reasoning == null\n ) {\n generationChunk.message.additional_kwargs.reasoning =\n currentReasoningText;\n }\n\n if (generationChunk.generationInfo?.finish_reason != null) {\n const finalReasoningDetails = [\n ...reasoningTextByIndex.values(),\n ...reasoningEncryptedById.values(),\n ];\n if (finalReasoningDetails.length > 0) {\n generationChunk.message.additional_kwargs.reasoning_details =\n finalReasoningDetails;\n } else {\n delete generationChunk.message.additional_kwargs.reasoning_details;\n }\n await emitStreamChunkCallback(generationChunk, runManager);\n yield generationChunk;\n continue;\n }\n\n delete generationChunk.message.additional_kwargs.reasoning_details;\n await emitStreamChunkCallback(generationChunk, runManager);\n yield generationChunk;\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { buildAnthropicCacheControl } from "../../messages/cache.mjs";
|
|
1
2
|
import { _convertToOpenAITool } from "../openai/index.mjs";
|
|
2
3
|
//#region src/llm/openrouter/toolCache.ts
|
|
3
|
-
const CACHE_CONTROL = { type: "ephemeral" };
|
|
4
4
|
function getToolName(tool) {
|
|
5
5
|
const candidate = tool;
|
|
6
6
|
if (typeof candidate.name === "string") return candidate.name;
|
|
@@ -17,13 +17,24 @@ function toOpenRouterTool(tool) {
|
|
|
17
17
|
};
|
|
18
18
|
return converted;
|
|
19
19
|
}
|
|
20
|
-
function markCacheControl(tool) {
|
|
20
|
+
function markCacheControl(tool, ttl) {
|
|
21
21
|
return {
|
|
22
22
|
...tool,
|
|
23
|
-
cache_control:
|
|
23
|
+
cache_control: buildAnthropicCacheControl(ttl)
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Drop any existing `cache_control` from a tool. Reused/caller-supplied tools
|
|
28
|
+
* can carry a stale marker (e.g. from a prior `promptCacheTtl: '5m'` run); since
|
|
29
|
+
* all tools serialize before system/messages, a leftover 5-minute marker ahead
|
|
30
|
+
* of the resolved breakpoint would violate the longer-TTL-first ordering.
|
|
31
|
+
*/
|
|
32
|
+
function stripCacheControl(tool) {
|
|
33
|
+
if (tool.cache_control == null) return tool;
|
|
34
|
+
const { cache_control: _omit, ...rest } = tool;
|
|
35
|
+
return rest;
|
|
36
|
+
}
|
|
37
|
+
function partitionAndMarkOpenRouterToolCache(tools, isDeferred, ttl) {
|
|
27
38
|
if (tools == null || tools.length === 0) return tools;
|
|
28
39
|
const staticTools = [];
|
|
29
40
|
const deferredTools = [];
|
|
@@ -36,8 +47,10 @@ function partitionAndMarkOpenRouterToolCache(tools, isDeferred) {
|
|
|
36
47
|
}
|
|
37
48
|
staticTools.push(converted);
|
|
38
49
|
}
|
|
50
|
+
for (let i = 0; i < deferredTools.length; i++) deferredTools[i] = stripCacheControl(deferredTools[i]);
|
|
39
51
|
if (staticTools.length === 0) return [...deferredTools];
|
|
40
|
-
staticTools
|
|
52
|
+
for (let i = 0; i < staticTools.length - 1; i++) staticTools[i] = stripCacheControl(staticTools[i]);
|
|
53
|
+
staticTools[staticTools.length - 1] = markCacheControl(staticTools[staticTools.length - 1], ttl);
|
|
41
54
|
return [...staticTools, ...deferredTools];
|
|
42
55
|
}
|
|
43
56
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolCache.mjs","names":[],"sources":["../../../../src/llm/openrouter/toolCache.ts"],"sourcesContent":["import type { BindToolsInput } from '@langchain/core/language_models/chat_models';\nimport type { OpenAIClient } from '@langchain/openai';\nimport type { GraphTools } from '@/types';\nimport { _convertToOpenAITool } from '@/llm/openai';\n\
|
|
1
|
+
{"version":3,"file":"toolCache.mjs","names":[],"sources":["../../../../src/llm/openrouter/toolCache.ts"],"sourcesContent":["import type { BindToolsInput } from '@langchain/core/language_models/chat_models';\nimport type { OpenAIClient } from '@langchain/openai';\nimport type { GraphTools } from '@/types';\nimport {\n buildAnthropicCacheControl,\n type PromptCacheTtl,\n} from '@/messages/cache';\nimport { _convertToOpenAITool } from '@/llm/openai';\n\ntype OpenRouterCacheControl = { type: 'ephemeral'; ttl?: '1h' };\n\ntype OpenRouterToolWithCacheControl = OpenAIClient.ChatCompletionTool & {\n cache_control?: OpenRouterCacheControl;\n defer_loading?: boolean;\n};\n\ntype ToolNameCandidate = {\n name?: unknown;\n function?: {\n name?: unknown;\n };\n defer_loading?: unknown;\n};\n\nfunction getToolName(tool: unknown): string | undefined {\n const candidate = tool as ToolNameCandidate;\n if (typeof candidate.name === 'string') {\n return candidate.name;\n }\n if (typeof candidate.function?.name === 'string') {\n return candidate.function.name;\n }\n return undefined;\n}\n\nfunction hasDeferredMarker(tool: unknown): boolean {\n return (tool as ToolNameCandidate).defer_loading === true;\n}\n\nfunction toOpenRouterTool(tool: unknown): OpenRouterToolWithCacheControl {\n const converted = _convertToOpenAITool(\n tool as BindToolsInput\n ) as OpenRouterToolWithCacheControl;\n\n if (hasDeferredMarker(tool)) {\n return { ...converted, defer_loading: true };\n }\n\n return converted;\n}\n\nfunction markCacheControl(\n tool: OpenRouterToolWithCacheControl,\n ttl?: PromptCacheTtl\n): OpenRouterToolWithCacheControl {\n return {\n ...tool,\n cache_control: buildAnthropicCacheControl(ttl),\n };\n}\n\n/**\n * Drop any existing `cache_control` from a tool. Reused/caller-supplied tools\n * can carry a stale marker (e.g. from a prior `promptCacheTtl: '5m'` run); since\n * all tools serialize before system/messages, a leftover 5-minute marker ahead\n * of the resolved breakpoint would violate the longer-TTL-first ordering.\n */\nfunction stripCacheControl(\n tool: OpenRouterToolWithCacheControl\n): OpenRouterToolWithCacheControl {\n if (tool.cache_control == null) {\n return tool;\n }\n const { cache_control: _omit, ...rest } = tool;\n return rest;\n}\n\nexport function partitionAndMarkOpenRouterToolCache(\n tools: GraphTools | undefined,\n isDeferred: (toolName: string) => boolean,\n ttl?: PromptCacheTtl\n): GraphTools | undefined {\n if (tools == null || tools.length === 0) {\n return tools;\n }\n\n const staticTools: OpenRouterToolWithCacheControl[] = [];\n const deferredTools: OpenRouterToolWithCacheControl[] = [];\n\n for (const tool of tools as readonly unknown[]) {\n const converted = toOpenRouterTool(tool);\n const name = getToolName(converted) ?? getToolName(tool);\n\n if (name != null && isDeferred(name)) {\n deferredTools.push(converted);\n continue;\n }\n\n staticTools.push(converted);\n }\n\n // Deferred tools sit after the breakpoint but still before system/messages,\n // so strip any stale marker off them.\n for (let i = 0; i < deferredTools.length; i++) {\n deferredTools[i] = stripCacheControl(deferredTools[i]);\n }\n\n if (staticTools.length === 0) {\n return [...deferredTools] as GraphTools;\n }\n\n // Strip stale markers off the earlier static tools, then stamp only the last\n // static tool with the resolved TTL (markCacheControl overwrites any marker).\n for (let i = 0; i < staticTools.length - 1; i++) {\n staticTools[i] = stripCacheControl(staticTools[i]);\n }\n staticTools[staticTools.length - 1] = markCacheControl(\n staticTools[staticTools.length - 1],\n ttl\n );\n\n return [...staticTools, ...deferredTools] as GraphTools;\n}\n"],"mappings":";;;AAwBA,SAAS,YAAY,MAAmC;CACtD,MAAM,YAAY;CAClB,IAAI,OAAO,UAAU,SAAS,UAC5B,OAAO,UAAU;CAEnB,IAAI,OAAO,UAAU,UAAU,SAAS,UACtC,OAAO,UAAU,SAAS;AAG9B;AAEA,SAAS,kBAAkB,MAAwB;CACjD,OAAQ,KAA2B,kBAAkB;AACvD;AAEA,SAAS,iBAAiB,MAA+C;CACvE,MAAM,YAAY,qBAChB,IACF;CAEA,IAAI,kBAAkB,IAAI,GACxB,OAAO;EAAE,GAAG;EAAW,eAAe;CAAK;CAG7C,OAAO;AACT;AAEA,SAAS,iBACP,MACA,KACgC;CAChC,OAAO;EACL,GAAG;EACH,eAAe,2BAA2B,GAAG;CAC/C;AACF;;;;;;;AAQA,SAAS,kBACP,MACgC;CAChC,IAAI,KAAK,iBAAiB,MACxB,OAAO;CAET,MAAM,EAAE,eAAe,OAAO,GAAG,SAAS;CAC1C,OAAO;AACT;AAEA,SAAgB,oCACd,OACA,YACA,KACwB;CACxB,IAAI,SAAS,QAAQ,MAAM,WAAW,GACpC,OAAO;CAGT,MAAM,cAAgD,CAAC;CACvD,MAAM,gBAAkD,CAAC;CAEzD,KAAK,MAAM,QAAQ,OAA6B;EAC9C,MAAM,YAAY,iBAAiB,IAAI;EACvC,MAAM,OAAO,YAAY,SAAS,KAAK,YAAY,IAAI;EAEvD,IAAI,QAAQ,QAAQ,WAAW,IAAI,GAAG;GACpC,cAAc,KAAK,SAAS;GAC5B;EACF;EAEA,YAAY,KAAK,SAAS;CAC5B;CAIA,KAAK,IAAI,IAAI,GAAG,IAAI,cAAc,QAAQ,KACxC,cAAc,KAAK,kBAAkB,cAAc,EAAE;CAGvD,IAAI,YAAY,WAAW,GACzB,OAAO,CAAC,GAAG,aAAa;CAK1B,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,SAAS,GAAG,KAC1C,YAAY,KAAK,kBAAkB,YAAY,EAAE;CAEnD,YAAY,YAAY,SAAS,KAAK,iBACpC,YAAY,YAAY,SAAS,IACjC,GACF;CAEA,OAAO,CAAC,GAAG,aAAa,GAAG,aAAa;AAC1C"}
|
package/dist/esm/main.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import { applyContextPruning } from "./messages/contextPruning.mjs";
|
|
|
11
11
|
import { DEFAULT_RESERVE_RATIO, ORIGINAL_CONTENT_MAX_CHARS, calculateTotalTokens, checkValidNumber, createPruneMessages, enforceOriginalContentCap, getMessagesWithinTokenLimit, maskConsumedToolResults, preFlightTruncateToolCallInputs, preFlightTruncateToolResults, repairOrphanedToolMessages, sanitizeOrphanToolBlocks } from "./messages/prune.mjs";
|
|
12
12
|
import { syncBudgetDerivedFields } from "./messages/budget.mjs";
|
|
13
13
|
import { ensureThinkingBlockInMessages, formatAgentMessages, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, labelContentByAgent, shiftIndexTokenCountMap, withMessageRole } from "./messages/format.mjs";
|
|
14
|
-
import { addBedrockCacheControl, addBedrockTailCacheControl, addCacheControl, addCacheControlToStablePrefixMessages, addTailCacheControl, cloneMessage, stripAnthropicCacheControl, stripBedrockCacheControl } from "./messages/cache.mjs";
|
|
14
|
+
import { DEFAULT_PROMPT_CACHE_TTL, addBedrockCacheControl, addBedrockTailCacheControl, addCacheControl, addCacheControlToStablePrefixMessages, addTailCacheControl, buildAnthropicCacheControl, buildBedrockCachePoint, cloneMessage, resolvePromptCacheTtl, stripAnthropicCacheControl, stripBedrockCacheControl } from "./messages/cache.mjs";
|
|
15
15
|
import { makeIsDeferred, partitionAndMarkAnthropicToolCache } from "./messages/anthropicToolCache.mjs";
|
|
16
16
|
import { formatContentStrings, isLegacyConvertible } from "./messages/content.mjs";
|
|
17
17
|
import { extractToolDiscoveries, hasToolSearchInCurrentTurn } from "./messages/tools.mjs";
|
|
@@ -98,4 +98,4 @@ import { Runnable, RunnableLambda, RunnableSequence } from "./langchain/runnable
|
|
|
98
98
|
import { DynamicStructuredTool, StructuredTool, Tool, tool } from "./langchain/tools.mjs";
|
|
99
99
|
import "./langchain/index.mjs";
|
|
100
100
|
import { BaseCheckpointSaver, Command, INTERRUPT, MemorySaver, interrupt, isInterrupted } from "@langchain/langgraph";
|
|
101
|
-
export { AIMessage, AIMessageChunk, ANTHROPIC_TOOL_TOKEN_MULTIPLIER, AgentSession, BASH_SHELL_GUIDANCE, BaseCheckpointSaver, BaseMessage, BaseMessageChunk, BashExecutionToolDefinition, BashExecutionToolDescription, BashExecutionToolName, BashExecutionToolSchema, BashProgrammaticToolCallingDefinition, BashProgrammaticToolCallingDescription, BashProgrammaticToolCallingName, BashProgrammaticToolCallingSchema, BashToolOutputReferencesGuide, CLOUDFLARE_BASH_CODING_TOOL_NAMES, CLOUDFLARE_CODING_TOOL_NAMES, CODE_ARTIFACT_PATH_GUIDANCE, CODE_EXECUTION_TOOLS, Calculator, CalculatorSchema, CalculatorToolDefinition, CalculatorToolDescription, CalculatorToolName, Callback, ChatModelStreamHandler, ChatOpenRouter, CloudflareBashExecutionToolDescription, CloudflareCodeExecutionToolDescription, CodeExecutionToolDefinition, CodeExecutionToolDescription, CodeExecutionToolName, CodeExecutionToolSchema, Command, CommonEvents, CompileCheckToolName, Constants, ContentTypes, CustomOpenAIClient, DATE_RANGE, DEFAULT_CONTEXT_PRUNING_SETTINGS, DEFAULT_COUNTRY_DESCRIPTION, DEFAULT_HOOK_TIMEOUT_MS, DEFAULT_QUERY_DESCRIPTION, DEFAULT_RESERVE_RATIO, DEFAULT_TOOL_TOKEN_MULTIPLIER, DynamicStructuredTool, EnvVar, FAILED_EXECUTION_FILE_REMINDER, FakeChatModel, Graph, GraphEvents, GraphNodeActions, GraphNodeKeys, HARD_MAX_TOOL_RESULT_CHARS, HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE, HOOK_EVENTS, HandlerRegistry, HookRegistry, HumanMessage, INTERRUPT, JsonlSessionStore, LLMStreamHandler, LOCAL_CODING_BUNDLE_NAMES, LOCAL_CODING_TOOL_NAMES, LOCAL_SPAWN_TIMEOUT_MS, LocalBashExecutionToolDescription, LocalCodeExecutionToolDescription, LocalEditFileToolName, LocalEditFileToolSchema, LocalFileCheckpointerImpl, LocalGlobSearchToolName, LocalGlobSearchToolSchema, LocalGrepSearchToolName, LocalGrepSearchToolSchema, LocalListDirectoryToolName, LocalListDirectoryToolSchema, LocalReadFileToolSchema, LocalWriteFileToolName, LocalWriteFileToolSchema, MAX_CACHE_SIZE, MAX_PATTERN_LENGTH, MemorySaver, ModelEndHandler, MultiAgentGraph, ORIGINAL_CONTENT_MAX_CHARS, ProgrammaticToolCallingDefinition, ProgrammaticToolCallingDescription, ProgrammaticToolCallingName, ProgrammaticToolCallingSchema, PromptTemplate, Providers, REMOVE_ALL_MESSAGES, ReadFileToolDefinition, ReadFileToolDescription, ReadFileToolName, ReadFileToolSchema, Run, Runnable, RunnableCallable, RunnableLambda, RunnableSequence, SEPARATORS, SessionManager, SkillToolDefinition, SkillToolDescription, SkillToolName, SkillToolSchema, SplitStreamHandler, StandardGraph, StepTypes, StructuredTool, SubagentExecutor, SubagentToolDefinition, SubagentToolDescription, SubagentToolName, SubagentToolSchema, SystemMessage, TMP_SCRATCH_OUTPUT_REMINDER, TestChatStreamHandler, TestLLMStreamHandler, TitleMethod, TokenEncoderManager, Tool, ToolCallTypes, ToolEndHandler, ToolMessage, ToolNode, ToolSearchToolDefinition, ToolSearchToolDescription, ToolSearchToolName, ToolSearchToolSchema, WebSearchToolDefinition, WebSearchToolDescription, WebSearchToolName, WebSearchToolSchema, _createBashProgramForTests, _resetLocalEngineWarningsForTests, _resetRipgrepCacheForTests, _resetSyntaxCheckProbeCacheForTests, _resetUnrecognizedTriggerWarnings, addBedrockCacheControl, addBedrockTailCacheControl, addCacheControl, addCacheControlToStablePrefixMessages, addTailCacheControl, appendCodeSessionFileSummary, appendFailedExecutionFileReminder, appendTmpScratchReminder, applyContextPruning, applyEdit, applyPreToolUseHooksForBridge, apportionTokenCounts, askUserQuestion, attemptInvoke, bashAstFindingsToErrors, buildBashExecutionToolDescription, buildChildInputs, buildCodeApiHttpErrorMessage, buildSandboxRuntimeConfig, buildSubagentToolParams, calculateMaxToolResultChars, calculateMaxTotalToolOutputSize, calculateTotalTokens, checkValidNumber, classifyAttachment, cloneMessage, composeEventHandlers, convertMessagesToContent, countNestedGroups, countrySchema, createAgentSession, createBashExecutionTool, createBashProgrammaticToolCallingSchema, createBashProgrammaticToolCallingTool, createCloudflareBashExecutionTool, createCloudflareBashProgrammaticToolCallingTool, createCloudflareBridgeRuntime, createCloudflareCodeExecutionTool, createCloudflareCodingToolBundle, createCloudflareCodingTools, createCloudflareExecutionTool, createCloudflareLocalExecutionConfig, createCloudflareProgrammaticToolCallingTool, createCloudflareWorkspaceFS, createCodeExecutionTool, createCompileCheckTool, createCompileCheckToolDefinition, createContentAggregator, createFakeStreamingLLM, createHandlers, createLocalBashExecutionTool, createLocalBashProgrammaticToolCallingTool, createLocalCodeExecutionTool, createLocalCodingToolBundle, createLocalCodingToolDefinitions, createLocalCodingToolRegistry, createLocalCodingTools, createLocalEditFileTool, createLocalFileCheckpointer, createLocalGlobSearchTool, createLocalGrepSearchTool, createLocalListDirectoryTool, createLocalProgrammaticToolCallingTool, createLocalReadFileTool, createLocalWriteFileTool, createMetadataAggregator, createProgrammaticToolCallingSchema, createProgrammaticToolCallingTool, createPruneMessages, createRemoveAllMessage, createRunHandlers, createSchemaOnlyTool, createSchemaOnlyTools, createSearchTool, createSubagentToolDefinition, createTokenCounter, createToolPolicyHook, createToolSearch, createWorkspacePolicyHook, dateSchema, decodeFile, defaultOmitOptions, deserializeMessage, emptyOutputMessage, encodeFile, encodingForModel, enforceOriginalContentCap, ensureThinkingBlockInMessages, escapeRegexSpecialChars, estimateAnthropicImageTokens, estimateOpenAIImageTokens, executeCloudflareBash, executeCloudflareCode, executeHooks, executeLocalBash, executeLocalBashWithArgs, executeLocalCode, executeParallelSearches, executeTools, extractErrorMessage, extractImageDimensions, extractMcpServerName, extractTextFromContent, extractToolDiscoveries, extractUsedBashToolNames, extractUsedToolNames, fetchSessionFiles, filterBashToolsByUsage, filterSubagentResult, filterToolsByUsage, findLastIndex, formatAgentMessages, formatAnthropicArtifactContent, formatAnthropicMessage, formatArtifactPayload, formatCloudflareOutput, formatCompletedResponse, formatContentStrings, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, formatServerListing, formatSkillCatalog, getAvailableMcpServers, getBaseToolName, getBufferString, getChatModelClass, getChunkContent, getCloudflareWorkspaceRoot, getCodeBaseURL, getConverseOverrideMessage, getDeferredToolsListing, getLocalCwd, getLocalSessionId, getMaxOutputTokensKey, getMessageId, getMessagesWithinTokenLimit, getReadRoots, getSpawn, getTokenCountForMessage, getWorkspaceFS, getWorkspaceRoots, getWriteRoots, handleServerToolResult, handleToolCallChunks, handleToolCalls, hasNestedQuantifier, hasNestedQuantifiers, hasToolSearchInCurrentTurn, imageAttachmentContent, imagesSchema, initializeModel, interrupt, isAIMessage, isAnthropicLike, isBaseMessage, isContextOverflowError, isDangerousPattern, isFromAnyMcpServer, isFromMcpServer, isGoogleLike, isInterrupted, isLegacyConvertible, isLikelyContextOverflowError, isOpenAILike, isPresent, isThinkingEnabled, isToolMessage, isZodSchema, joinKeys, labelContentByAgent, locateEdit, makeIsDeferred, makeRequest, maskConsumedToolResults, matchesQuery, messagesStateReducer, modifyDeltaProperties, newsSchema, normalizeBashToolResultsForReplay, normalizeServerFilter, normalizeToBashIdentifier, normalizeToPythonIdentifier, partitionAndMarkAnthropicToolCache, performLocalSearch, preFlightTruncateToolCallInputs, preFlightTruncateToolResults, projectAgentContextUsage, querySchema, repairOrphanedToolMessages, resetIfNotEmpty, resolveCloudflareSandbox, resolveCodeApiAuthHeaders, resolveContextPruningSettings, resolveLocalExecutionConfig, resolveLocalExecutionTools, resolveLocalToolRegistry, resolveLocalToolsForBinding, resolveSubagentConfigs, resolveWorkspacePath, resolveWorkspacePathSafe, runBashAstChecks, runPostEditSyntaxCheck, sanitizeOrphanToolBlocks, sanitizeRegex, serializeMessage, shellQuote, shiftIndexTokenCountMap, shouldTriggerSummarization, sleep, spawnLocalProcess, splitAtRecencyBoundary, stripAnthropicCacheControl, stripBedrockCacheControl, stripCodeSessionFileSummary, summarizeEvent, syncBudgetDerivedFields, toJsonSchema, tool, toolResultTypes, toolsCondition, truncateLocalOutput, truncateToolInput, truncateToolResultContent, tryFallbackProviders, unescapeObject, unwrapToolResponse, validateBashCommand, validateCloudflareBashCommand, videosSchema, withMessageRole };
|
|
101
|
+
export { AIMessage, AIMessageChunk, ANTHROPIC_TOOL_TOKEN_MULTIPLIER, AgentSession, BASH_SHELL_GUIDANCE, BaseCheckpointSaver, BaseMessage, BaseMessageChunk, BashExecutionToolDefinition, BashExecutionToolDescription, BashExecutionToolName, BashExecutionToolSchema, BashProgrammaticToolCallingDefinition, BashProgrammaticToolCallingDescription, BashProgrammaticToolCallingName, BashProgrammaticToolCallingSchema, BashToolOutputReferencesGuide, CLOUDFLARE_BASH_CODING_TOOL_NAMES, CLOUDFLARE_CODING_TOOL_NAMES, CODE_ARTIFACT_PATH_GUIDANCE, CODE_EXECUTION_TOOLS, Calculator, CalculatorSchema, CalculatorToolDefinition, CalculatorToolDescription, CalculatorToolName, Callback, ChatModelStreamHandler, ChatOpenRouter, CloudflareBashExecutionToolDescription, CloudflareCodeExecutionToolDescription, CodeExecutionToolDefinition, CodeExecutionToolDescription, CodeExecutionToolName, CodeExecutionToolSchema, Command, CommonEvents, CompileCheckToolName, Constants, ContentTypes, CustomOpenAIClient, DATE_RANGE, DEFAULT_CONTEXT_PRUNING_SETTINGS, DEFAULT_COUNTRY_DESCRIPTION, DEFAULT_HOOK_TIMEOUT_MS, DEFAULT_PROMPT_CACHE_TTL, DEFAULT_QUERY_DESCRIPTION, DEFAULT_RESERVE_RATIO, DEFAULT_TOOL_TOKEN_MULTIPLIER, DynamicStructuredTool, EnvVar, FAILED_EXECUTION_FILE_REMINDER, FakeChatModel, Graph, GraphEvents, GraphNodeActions, GraphNodeKeys, HARD_MAX_TOOL_RESULT_CHARS, HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE, HOOK_EVENTS, HandlerRegistry, HookRegistry, HumanMessage, INTERRUPT, JsonlSessionStore, LLMStreamHandler, LOCAL_CODING_BUNDLE_NAMES, LOCAL_CODING_TOOL_NAMES, LOCAL_SPAWN_TIMEOUT_MS, LocalBashExecutionToolDescription, LocalCodeExecutionToolDescription, LocalEditFileToolName, LocalEditFileToolSchema, LocalFileCheckpointerImpl, LocalGlobSearchToolName, LocalGlobSearchToolSchema, LocalGrepSearchToolName, LocalGrepSearchToolSchema, LocalListDirectoryToolName, LocalListDirectoryToolSchema, LocalReadFileToolSchema, LocalWriteFileToolName, LocalWriteFileToolSchema, MAX_CACHE_SIZE, MAX_PATTERN_LENGTH, MemorySaver, ModelEndHandler, MultiAgentGraph, ORIGINAL_CONTENT_MAX_CHARS, ProgrammaticToolCallingDefinition, ProgrammaticToolCallingDescription, ProgrammaticToolCallingName, ProgrammaticToolCallingSchema, PromptTemplate, Providers, REMOVE_ALL_MESSAGES, ReadFileToolDefinition, ReadFileToolDescription, ReadFileToolName, ReadFileToolSchema, Run, Runnable, RunnableCallable, RunnableLambda, RunnableSequence, SEPARATORS, SessionManager, SkillToolDefinition, SkillToolDescription, SkillToolName, SkillToolSchema, SplitStreamHandler, StandardGraph, StepTypes, StructuredTool, SubagentExecutor, SubagentToolDefinition, SubagentToolDescription, SubagentToolName, SubagentToolSchema, SystemMessage, TMP_SCRATCH_OUTPUT_REMINDER, TestChatStreamHandler, TestLLMStreamHandler, TitleMethod, TokenEncoderManager, Tool, ToolCallTypes, ToolEndHandler, ToolMessage, ToolNode, ToolSearchToolDefinition, ToolSearchToolDescription, ToolSearchToolName, ToolSearchToolSchema, WebSearchToolDefinition, WebSearchToolDescription, WebSearchToolName, WebSearchToolSchema, _createBashProgramForTests, _resetLocalEngineWarningsForTests, _resetRipgrepCacheForTests, _resetSyntaxCheckProbeCacheForTests, _resetUnrecognizedTriggerWarnings, addBedrockCacheControl, addBedrockTailCacheControl, addCacheControl, addCacheControlToStablePrefixMessages, addTailCacheControl, appendCodeSessionFileSummary, appendFailedExecutionFileReminder, appendTmpScratchReminder, applyContextPruning, applyEdit, applyPreToolUseHooksForBridge, apportionTokenCounts, askUserQuestion, attemptInvoke, bashAstFindingsToErrors, buildAnthropicCacheControl, buildBashExecutionToolDescription, buildBedrockCachePoint, buildChildInputs, buildCodeApiHttpErrorMessage, buildSandboxRuntimeConfig, buildSubagentToolParams, calculateMaxToolResultChars, calculateMaxTotalToolOutputSize, calculateTotalTokens, checkValidNumber, classifyAttachment, cloneMessage, composeEventHandlers, convertMessagesToContent, countNestedGroups, countrySchema, createAgentSession, createBashExecutionTool, createBashProgrammaticToolCallingSchema, createBashProgrammaticToolCallingTool, createCloudflareBashExecutionTool, createCloudflareBashProgrammaticToolCallingTool, createCloudflareBridgeRuntime, createCloudflareCodeExecutionTool, createCloudflareCodingToolBundle, createCloudflareCodingTools, createCloudflareExecutionTool, createCloudflareLocalExecutionConfig, createCloudflareProgrammaticToolCallingTool, createCloudflareWorkspaceFS, createCodeExecutionTool, createCompileCheckTool, createCompileCheckToolDefinition, createContentAggregator, createFakeStreamingLLM, createHandlers, createLocalBashExecutionTool, createLocalBashProgrammaticToolCallingTool, createLocalCodeExecutionTool, createLocalCodingToolBundle, createLocalCodingToolDefinitions, createLocalCodingToolRegistry, createLocalCodingTools, createLocalEditFileTool, createLocalFileCheckpointer, createLocalGlobSearchTool, createLocalGrepSearchTool, createLocalListDirectoryTool, createLocalProgrammaticToolCallingTool, createLocalReadFileTool, createLocalWriteFileTool, createMetadataAggregator, createProgrammaticToolCallingSchema, createProgrammaticToolCallingTool, createPruneMessages, createRemoveAllMessage, createRunHandlers, createSchemaOnlyTool, createSchemaOnlyTools, createSearchTool, createSubagentToolDefinition, createTokenCounter, createToolPolicyHook, createToolSearch, createWorkspacePolicyHook, dateSchema, decodeFile, defaultOmitOptions, deserializeMessage, emptyOutputMessage, encodeFile, encodingForModel, enforceOriginalContentCap, ensureThinkingBlockInMessages, escapeRegexSpecialChars, estimateAnthropicImageTokens, estimateOpenAIImageTokens, executeCloudflareBash, executeCloudflareCode, executeHooks, executeLocalBash, executeLocalBashWithArgs, executeLocalCode, executeParallelSearches, executeTools, extractErrorMessage, extractImageDimensions, extractMcpServerName, extractTextFromContent, extractToolDiscoveries, extractUsedBashToolNames, extractUsedToolNames, fetchSessionFiles, filterBashToolsByUsage, filterSubagentResult, filterToolsByUsage, findLastIndex, formatAgentMessages, formatAnthropicArtifactContent, formatAnthropicMessage, formatArtifactPayload, formatCloudflareOutput, formatCompletedResponse, formatContentStrings, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, formatServerListing, formatSkillCatalog, getAvailableMcpServers, getBaseToolName, getBufferString, getChatModelClass, getChunkContent, getCloudflareWorkspaceRoot, getCodeBaseURL, getConverseOverrideMessage, getDeferredToolsListing, getLocalCwd, getLocalSessionId, getMaxOutputTokensKey, getMessageId, getMessagesWithinTokenLimit, getReadRoots, getSpawn, getTokenCountForMessage, getWorkspaceFS, getWorkspaceRoots, getWriteRoots, handleServerToolResult, handleToolCallChunks, handleToolCalls, hasNestedQuantifier, hasNestedQuantifiers, hasToolSearchInCurrentTurn, imageAttachmentContent, imagesSchema, initializeModel, interrupt, isAIMessage, isAnthropicLike, isBaseMessage, isContextOverflowError, isDangerousPattern, isFromAnyMcpServer, isFromMcpServer, isGoogleLike, isInterrupted, isLegacyConvertible, isLikelyContextOverflowError, isOpenAILike, isPresent, isThinkingEnabled, isToolMessage, isZodSchema, joinKeys, labelContentByAgent, locateEdit, makeIsDeferred, makeRequest, maskConsumedToolResults, matchesQuery, messagesStateReducer, modifyDeltaProperties, newsSchema, normalizeBashToolResultsForReplay, normalizeServerFilter, normalizeToBashIdentifier, normalizeToPythonIdentifier, partitionAndMarkAnthropicToolCache, performLocalSearch, preFlightTruncateToolCallInputs, preFlightTruncateToolResults, projectAgentContextUsage, querySchema, repairOrphanedToolMessages, resetIfNotEmpty, resolveCloudflareSandbox, resolveCodeApiAuthHeaders, resolveContextPruningSettings, resolveLocalExecutionConfig, resolveLocalExecutionTools, resolveLocalToolRegistry, resolveLocalToolsForBinding, resolvePromptCacheTtl, resolveSubagentConfigs, resolveWorkspacePath, resolveWorkspacePathSafe, runBashAstChecks, runPostEditSyntaxCheck, sanitizeOrphanToolBlocks, sanitizeRegex, serializeMessage, shellQuote, shiftIndexTokenCountMap, shouldTriggerSummarization, sleep, spawnLocalProcess, splitAtRecencyBoundary, stripAnthropicCacheControl, stripBedrockCacheControl, stripCodeSessionFileSummary, summarizeEvent, syncBudgetDerivedFields, toJsonSchema, tool, toolResultTypes, toolsCondition, truncateLocalOutput, truncateToolInput, truncateToolResultContent, tryFallbackProviders, unescapeObject, unwrapToolResponse, validateBashCommand, validateCloudflareBashCommand, videosSchema, withMessageRole };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildAnthropicCacheControl } from "./cache.mjs";
|
|
1
2
|
//#region src/messages/anthropicToolCache.ts
|
|
2
3
|
const ANTHROPIC_BUILT_IN_TOOL_PREFIXES = [
|
|
3
4
|
"text_editor_",
|
|
@@ -12,25 +13,69 @@ const ANTHROPIC_BUILT_IN_TOOL_PREFIXES = [
|
|
|
12
13
|
"tool_search_",
|
|
13
14
|
"mcp_toolset"
|
|
14
15
|
];
|
|
15
|
-
const CACHE_CONTROL = { type: "ephemeral" };
|
|
16
16
|
function isAnthropicBuiltInTool(tool) {
|
|
17
17
|
const { type } = tool;
|
|
18
18
|
return typeof type === "string" && ANTHROPIC_BUILT_IN_TOOL_PREFIXES.some((prefix) => type.startsWith(prefix));
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Whether a tool already carries a cache breakpoint. Built-ins use a direct
|
|
22
|
+
* `cache_control`; custom tools normally carry it under `extras`, but a
|
|
23
|
+
* caller-supplied Anthropic-native tool object can also put it directly on the
|
|
24
|
+
* block — check both so stale markers are never missed.
|
|
25
|
+
*/
|
|
20
26
|
function hasCacheControl(tool) {
|
|
21
27
|
if (isAnthropicBuiltInTool(tool)) return tool.cache_control != null;
|
|
22
|
-
return tool.extras?.cache_control != null;
|
|
28
|
+
return tool.cache_control != null || tool.extras?.cache_control != null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Return the `cache_control` from the location that actually reaches the
|
|
32
|
+
* Anthropic payload for this tool's shape: directly on the block for
|
|
33
|
+
* provider-shaped tools (built-ins and raw Anthropic tools), or under `extras`
|
|
34
|
+
* for LangChain custom tools (the adapter promotes only that). Returns
|
|
35
|
+
* `undefined` when no marker sits in the effective location — a marker in the
|
|
36
|
+
* wrong place (e.g. a direct marker on a custom tool) does not count.
|
|
37
|
+
*/
|
|
38
|
+
function getEffectiveCacheControl(tool) {
|
|
39
|
+
return isProviderShapedTool(tool) ? tool.cache_control : tool.extras?.cache_control;
|
|
23
40
|
}
|
|
24
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Return a clone of `tool` with any `cache_control` removed — both the direct
|
|
43
|
+
* block marker and the `extras` marker — preserving the prototype chain. Used
|
|
44
|
+
* to clear stray markers off tools that must not anchor a competing breakpoint.
|
|
45
|
+
*/
|
|
46
|
+
function stripCacheControl(tool) {
|
|
25
47
|
const prototype = Object.getPrototypeOf(tool) ?? Object.prototype;
|
|
26
|
-
|
|
48
|
+
const wrapped = { ...tool };
|
|
49
|
+
delete wrapped.cache_control;
|
|
50
|
+
if (wrapped.extras != null) {
|
|
51
|
+
wrapped.extras = { ...wrapped.extras };
|
|
52
|
+
delete wrapped.extras.cache_control;
|
|
53
|
+
}
|
|
54
|
+
return Object.assign(Object.create(prototype), wrapped);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Whether `tool` is already in the Anthropic provider payload shape — an
|
|
58
|
+
* Anthropic built-in or a raw Anthropic tool object (has `input_schema`). These
|
|
59
|
+
* carry `cache_control` directly on the block; the LangChain adapter does NOT
|
|
60
|
+
* promote `extras.cache_control` for them. LangChain StructuredTools, by
|
|
61
|
+
* contrast, expose the marker via `extras`.
|
|
62
|
+
*/
|
|
63
|
+
function isProviderShapedTool(tool) {
|
|
64
|
+
return isAnthropicBuiltInTool(tool) || "input_schema" in tool;
|
|
65
|
+
}
|
|
66
|
+
function markCacheControl(tool, ttl) {
|
|
67
|
+
const cacheControl = buildAnthropicCacheControl(ttl);
|
|
68
|
+
const prototype = Object.getPrototypeOf(tool) ?? Object.prototype;
|
|
69
|
+
if (isProviderShapedTool(tool)) {
|
|
27
70
|
const wrapped = { ...tool };
|
|
28
71
|
delete wrapped.extras;
|
|
29
|
-
return Object.assign(Object.create(prototype), wrapped, { cache_control:
|
|
72
|
+
return Object.assign(Object.create(prototype), wrapped, { cache_control: cacheControl });
|
|
30
73
|
}
|
|
31
|
-
|
|
74
|
+
const wrapped = { ...tool };
|
|
75
|
+
delete wrapped.cache_control;
|
|
76
|
+
return Object.assign(Object.create(prototype), wrapped, { extras: {
|
|
32
77
|
...tool.extras ?? {},
|
|
33
|
-
cache_control:
|
|
78
|
+
cache_control: cacheControl
|
|
34
79
|
} });
|
|
35
80
|
}
|
|
36
81
|
/**
|
|
@@ -59,7 +104,7 @@ function makeIsDeferred(toolDefinitions) {
|
|
|
59
104
|
* `instanceof` checks still pass. For custom tools, `extras` is merged
|
|
60
105
|
* so any existing `providerToolDefinition` / other extras are kept.
|
|
61
106
|
*/
|
|
62
|
-
function partitionAndMarkAnthropicToolCache(tools, isDeferred) {
|
|
107
|
+
function partitionAndMarkAnthropicToolCache(tools, isDeferred, ttl) {
|
|
63
108
|
if (tools == null || tools.length === 0) return tools;
|
|
64
109
|
const staticTools = [];
|
|
65
110
|
const deferredTools = [];
|
|
@@ -68,13 +113,30 @@ function partitionAndMarkAnthropicToolCache(tools, isDeferred) {
|
|
|
68
113
|
if (typeof name === "string" && isDeferred(name)) deferredTools.push(tool);
|
|
69
114
|
else staticTools.push(tool);
|
|
70
115
|
}
|
|
71
|
-
|
|
116
|
+
let mutated = false;
|
|
117
|
+
for (let i = 0; i < deferredTools.length; i++) {
|
|
118
|
+
const candidate = deferredTools[i];
|
|
119
|
+
if (hasCacheControl(candidate)) {
|
|
120
|
+
deferredTools[i] = stripCacheControl(candidate);
|
|
121
|
+
mutated = true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (staticTools.length === 0) return mutated ? [...deferredTools] : tools;
|
|
125
|
+
for (let i = 0; i < staticTools.length - 1; i++) {
|
|
126
|
+
const candidate = staticTools[i];
|
|
127
|
+
if (hasCacheControl(candidate)) {
|
|
128
|
+
staticTools[i] = stripCacheControl(candidate);
|
|
129
|
+
mutated = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
72
132
|
const last = staticTools[staticTools.length - 1];
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
133
|
+
const desiredTtl = ttl === "1h" ? "1h" : void 0;
|
|
134
|
+
const effective = getEffectiveCacheControl(last);
|
|
135
|
+
if (!(effective != null && (effective.ttl === "1h" ? "1h" : void 0) === desiredTtl)) {
|
|
136
|
+
staticTools[staticTools.length - 1] = markCacheControl(last, ttl);
|
|
137
|
+
mutated = true;
|
|
76
138
|
}
|
|
77
|
-
|
|
139
|
+
if (!mutated && deferredTools.length === 0) return tools;
|
|
78
140
|
return [...staticTools, ...deferredTools];
|
|
79
141
|
}
|
|
80
142
|
//#endregion
|