@librechat/agents 3.2.63 → 3.2.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/cjs/graphs/Graph.cjs +3 -0
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/llm/anthropic/index.cjs +73 -9
  4. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  5. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  6. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +41 -9
  7. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  8. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +3 -1
  9. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  10. package/dist/cjs/llm/anthropic/utils/stream_events.cjs +337 -0
  11. package/dist/cjs/llm/anthropic/utils/stream_events.cjs.map +1 -0
  12. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +82 -34
  13. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  14. package/dist/cjs/tools/search/crw-scraper.cjs +165 -0
  15. package/dist/cjs/tools/search/crw-scraper.cjs.map +1 -0
  16. package/dist/cjs/tools/search/crw-search.cjs +105 -0
  17. package/dist/cjs/tools/search/crw-search.cjs.map +1 -0
  18. package/dist/cjs/tools/search/search.cjs +4 -2
  19. package/dist/cjs/tools/search/search.cjs.map +1 -1
  20. package/dist/cjs/tools/search/tool.cjs +15 -3
  21. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  22. package/dist/esm/graphs/Graph.mjs +3 -0
  23. package/dist/esm/graphs/Graph.mjs.map +1 -1
  24. package/dist/esm/llm/anthropic/index.mjs +73 -9
  25. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  26. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  27. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +41 -9
  28. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  29. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +3 -2
  30. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  31. package/dist/esm/llm/anthropic/utils/stream_events.mjs +337 -0
  32. package/dist/esm/llm/anthropic/utils/stream_events.mjs.map +1 -0
  33. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +82 -34
  34. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  35. package/dist/esm/tools/search/crw-scraper.mjs +163 -0
  36. package/dist/esm/tools/search/crw-scraper.mjs.map +1 -0
  37. package/dist/esm/tools/search/crw-search.mjs +103 -0
  38. package/dist/esm/tools/search/crw-search.mjs.map +1 -0
  39. package/dist/esm/tools/search/search.mjs +4 -2
  40. package/dist/esm/tools/search/search.mjs.map +1 -1
  41. package/dist/esm/tools/search/tool.mjs +15 -3
  42. package/dist/esm/tools/search/tool.mjs.map +1 -1
  43. package/dist/types/llm/anthropic/index.d.ts +2 -0
  44. package/dist/types/llm/anthropic/types.d.ts +2 -0
  45. package/dist/types/llm/anthropic/utils/message_outputs.d.ts +1 -2
  46. package/dist/types/llm/anthropic/utils/stream_events.d.ts +25 -0
  47. package/dist/types/tools/search/crw-scraper.d.ts +41 -0
  48. package/dist/types/tools/search/crw-search.d.ts +4 -0
  49. package/dist/types/tools/search/types.d.ts +88 -3
  50. package/package.json +1 -1
  51. package/src/graphs/Graph.ts +15 -0
  52. package/src/llm/anthropic/index.ts +134 -10
  53. package/src/llm/anthropic/inherited-content-utils.spec.ts +10 -5
  54. package/src/llm/anthropic/inherited-stream-events.spec.ts +513 -9
  55. package/src/llm/anthropic/llm.spec.ts +100 -16
  56. package/src/llm/anthropic/types.ts +3 -0
  57. package/src/llm/anthropic/utils/message_inputs.ts +60 -3
  58. package/src/llm/anthropic/utils/message_outputs.ts +10 -2
  59. package/src/llm/anthropic/utils/stream_events.ts +471 -0
  60. package/src/llm/bedrock/utils/message_inputs.test.ts +276 -1
  61. package/src/llm/bedrock/utils/message_inputs.ts +121 -73
  62. package/src/tools/search/crw-scraper.ts +244 -0
  63. package/src/tools/search/crw-search.ts +167 -0
  64. package/src/tools/search/crw.test.ts +836 -0
  65. package/src/tools/search/search.ts +7 -1
  66. package/src/tools/search/tool.ts +23 -3
  67. package/src/tools/search/types.ts +103 -3
@@ -0,0 +1,337 @@
1
+ const require_message_outputs = require("./message_outputs.cjs");
2
+ //#region src/llm/anthropic/utils/stream_events.ts
3
+ /**
4
+ * Convert an async iterable of raw Anthropic stream events into
5
+ * LangChain `ChatModelStreamEvent`s with typed deltas.
6
+ */
7
+ async function* convertAnthropicStream(source, options = {}) {
8
+ const shouldStreamUsage = options.streamUsage ?? true;
9
+ const blockAccumulators = /* @__PURE__ */ new Map();
10
+ let usageSnapshot;
11
+ let eventUsage;
12
+ let stopReason = null;
13
+ for await (const data of source) switch (data.type) {
14
+ case "message_start": {
15
+ const { usage, id, model } = data.message;
16
+ if (shouldStreamUsage) {
17
+ eventUsage = {
18
+ inputTokens: usage.input_tokens,
19
+ cacheCreationInputTokens: usage.cache_creation_input_tokens ?? 0,
20
+ cacheReadInputTokens: usage.cache_read_input_tokens ?? 0,
21
+ outputTokens: usage.output_tokens
22
+ };
23
+ usageSnapshot = buildUsageSnapshot(eventUsage);
24
+ }
25
+ yield {
26
+ event: "message-start",
27
+ id,
28
+ ...usageSnapshot ? { usage: usageSnapshot } : {}
29
+ };
30
+ yield {
31
+ event: "provider",
32
+ provider: "anthropic",
33
+ name: "message_start",
34
+ payload: {
35
+ model,
36
+ id
37
+ }
38
+ };
39
+ break;
40
+ }
41
+ case "message_delta":
42
+ stopReason = data.delta.stop_reason;
43
+ if (shouldStreamUsage) {
44
+ eventUsage = updateEventUsage(eventUsage, data.usage);
45
+ usageSnapshot = buildUsageSnapshot(eventUsage);
46
+ yield {
47
+ event: "usage",
48
+ usage: usageSnapshot
49
+ };
50
+ }
51
+ if ("context_management" in data.delta && data.delta.context_management != null) yield {
52
+ event: "provider",
53
+ provider: "anthropic",
54
+ name: "context_management",
55
+ payload: data.delta.context_management
56
+ };
57
+ break;
58
+ case "message_stop":
59
+ yield {
60
+ event: "message-finish",
61
+ reason: mapStopReason(stopReason),
62
+ ...usageSnapshot ? { usage: usageSnapshot } : {},
63
+ responseMetadata: { model_provider: "anthropic" }
64
+ };
65
+ break;
66
+ case "error": {
67
+ const streamError = new Error(data.error.message);
68
+ streamError.name = data.error.type;
69
+ throw streamError;
70
+ }
71
+ case "content_block_start": {
72
+ const { index, content_block } = data;
73
+ const mapped = mapBlockToContentBlock(content_block, index);
74
+ blockAccumulators.set(index, { ...mapped });
75
+ yield {
76
+ event: "content-block-start",
77
+ index,
78
+ content: mapped
79
+ };
80
+ break;
81
+ }
82
+ case "content_block_delta": {
83
+ const { index, delta } = data;
84
+ const acc = blockAccumulators.get(index);
85
+ if (!acc) break;
86
+ const { contentDelta, accumulated } = applyAnthropicDelta(acc, delta);
87
+ blockAccumulators.set(index, accumulated);
88
+ yield {
89
+ event: "content-block-delta",
90
+ index,
91
+ delta: contentDelta
92
+ };
93
+ break;
94
+ }
95
+ case "content_block_stop": {
96
+ const { index } = data;
97
+ const acc = blockAccumulators.get(index);
98
+ if (!acc) break;
99
+ yield {
100
+ event: "content-block-finish",
101
+ index,
102
+ content: finalizeBlock(acc)
103
+ };
104
+ blockAccumulators.delete(index);
105
+ break;
106
+ }
107
+ default: {
108
+ const providerData = data;
109
+ yield {
110
+ event: "provider",
111
+ provider: "anthropic",
112
+ name: providerData.type,
113
+ payload: providerData
114
+ };
115
+ break;
116
+ }
117
+ }
118
+ }
119
+ function mapStopReason(stopReason) {
120
+ switch (stopReason) {
121
+ case "end_turn":
122
+ case "stop_sequence": return "stop";
123
+ case "tool_use": return "tool_use";
124
+ case "max_tokens":
125
+ case "model_context_window_exceeded": return "length";
126
+ case "refusal": return "content_filter";
127
+ default: return "stop";
128
+ }
129
+ }
130
+ function updateEventUsage(previous, current) {
131
+ return {
132
+ inputTokens: getCumulativeUsageValue(current.input_tokens, previous?.inputTokens),
133
+ cacheCreationInputTokens: getCumulativeUsageValue(current.cache_creation_input_tokens, previous?.cacheCreationInputTokens),
134
+ cacheReadInputTokens: getCumulativeUsageValue(current.cache_read_input_tokens, previous?.cacheReadInputTokens),
135
+ outputTokens: getCumulativeUsageValue(current.output_tokens, previous?.outputTokens)
136
+ };
137
+ }
138
+ function getCumulativeUsageValue(current, previous) {
139
+ return Math.max(previous ?? 0, current ?? 0);
140
+ }
141
+ function buildUsageSnapshot(usage) {
142
+ const metadata = require_message_outputs.getAnthropicUsageMetadata({
143
+ input_tokens: usage.inputTokens,
144
+ output_tokens: usage.outputTokens,
145
+ cache_creation_input_tokens: usage.cacheCreationInputTokens,
146
+ cache_read_input_tokens: usage.cacheReadInputTokens
147
+ });
148
+ if (metadata == null) throw new Error("Anthropic usage metadata was not created");
149
+ return metadata;
150
+ }
151
+ function getStringField(record, key) {
152
+ const value = record[key];
153
+ return typeof value === "string" ? value : "";
154
+ }
155
+ function getArrayField(record, key) {
156
+ const value = record[key];
157
+ return Array.isArray(value) ? value : [];
158
+ }
159
+ function mapBlockToContentBlock(block, index) {
160
+ switch (block.type) {
161
+ case "text": return {
162
+ type: "text",
163
+ text: block.text,
164
+ ...block.citations != null ? { citations: block.citations } : {},
165
+ index
166
+ };
167
+ case "thinking": return {
168
+ type: "reasoning",
169
+ reasoning: block.thinking,
170
+ index
171
+ };
172
+ case "redacted_thinking": return {
173
+ ...block,
174
+ index
175
+ };
176
+ case "tool_use": return {
177
+ type: "tool_call_chunk",
178
+ id: block.id,
179
+ name: block.name,
180
+ args: "",
181
+ index
182
+ };
183
+ case "server_tool_use": return {
184
+ type: "server_tool_call_chunk",
185
+ id: block.id,
186
+ name: block.name,
187
+ args: "",
188
+ index
189
+ };
190
+ case "web_search_tool_result": return {
191
+ ...block,
192
+ index
193
+ };
194
+ case "compaction": return {
195
+ ...block,
196
+ index
197
+ };
198
+ default: return {
199
+ type: "non_standard",
200
+ value: { ...block },
201
+ index
202
+ };
203
+ }
204
+ }
205
+ /**
206
+ * Map an Anthropic content_block_delta to a content block delta
207
+ * and update the accumulated state.
208
+ */
209
+ function applyAnthropicDelta(accumulated, delta) {
210
+ const rawDelta = delta;
211
+ switch (delta.type) {
212
+ case "text_delta": return {
213
+ contentDelta: {
214
+ type: "text-delta",
215
+ text: delta.text
216
+ },
217
+ accumulated: {
218
+ ...accumulated,
219
+ text: getStringField(accumulated, "text") + delta.text
220
+ }
221
+ };
222
+ case "thinking_delta": return {
223
+ contentDelta: {
224
+ type: "reasoning-delta",
225
+ reasoning: delta.thinking
226
+ },
227
+ accumulated: {
228
+ ...accumulated,
229
+ reasoning: getStringField(accumulated, "reasoning") + delta.thinking
230
+ }
231
+ };
232
+ case "input_json_delta": {
233
+ const newArgs = getStringField(accumulated, "args") + delta.partial_json;
234
+ return {
235
+ contentDelta: {
236
+ type: "block-delta",
237
+ fields: {
238
+ type: getStringField(accumulated, "type"),
239
+ args: newArgs
240
+ }
241
+ },
242
+ accumulated: {
243
+ ...accumulated,
244
+ args: newArgs
245
+ }
246
+ };
247
+ }
248
+ case "citations_delta": {
249
+ const citations = [...getArrayField(accumulated, "citations"), delta.citation];
250
+ return {
251
+ contentDelta: {
252
+ type: "block-delta",
253
+ fields: {
254
+ type: getStringField(accumulated, "type"),
255
+ citations
256
+ }
257
+ },
258
+ accumulated: {
259
+ ...accumulated,
260
+ citations
261
+ }
262
+ };
263
+ }
264
+ case "signature_delta": return {
265
+ contentDelta: {
266
+ type: "block-delta",
267
+ fields: {
268
+ type: getStringField(accumulated, "type"),
269
+ signature: delta.signature
270
+ }
271
+ },
272
+ accumulated: {
273
+ ...accumulated,
274
+ signature: delta.signature
275
+ }
276
+ };
277
+ case "compaction_delta": {
278
+ const previousContent = accumulated.content;
279
+ const content = delta.content == null ? previousContent ?? null : getStringField(accumulated, "content") + delta.content;
280
+ return {
281
+ contentDelta: {
282
+ type: "block-delta",
283
+ fields: {
284
+ type: "compaction",
285
+ content,
286
+ encrypted_content: delta.encrypted_content
287
+ }
288
+ },
289
+ accumulated: {
290
+ ...accumulated,
291
+ content,
292
+ encrypted_content: delta.encrypted_content
293
+ }
294
+ };
295
+ }
296
+ default: return {
297
+ contentDelta: {
298
+ type: "block-delta",
299
+ fields: {
300
+ type: getStringField(accumulated, "type"),
301
+ ...rawDelta
302
+ }
303
+ },
304
+ accumulated
305
+ };
306
+ }
307
+ }
308
+ function finalizeBlock(accumulated) {
309
+ if (accumulated.type === "tool_call_chunk" || accumulated.type === "server_tool_call_chunk") {
310
+ const finalType = accumulated.type === "tool_call_chunk" ? "tool_call" : "server_tool_call";
311
+ const args = getStringField(accumulated, "args");
312
+ let parsedArgs;
313
+ try {
314
+ parsedArgs = JSON.parse(args || "{}");
315
+ } catch {
316
+ return {
317
+ type: "invalid_tool_call",
318
+ id: getStringField(accumulated, "id"),
319
+ name: getStringField(accumulated, "name"),
320
+ args,
321
+ error: "Failed to parse tool call arguments as JSON"
322
+ };
323
+ }
324
+ return {
325
+ type: finalType,
326
+ id: getStringField(accumulated, "id"),
327
+ name: getStringField(accumulated, "name"),
328
+ args: parsedArgs
329
+ };
330
+ }
331
+ const { index: _index, ...rest } = accumulated;
332
+ return rest;
333
+ }
334
+ //#endregion
335
+ exports.convertAnthropicStream = convertAnthropicStream;
336
+
337
+ //# sourceMappingURL=stream_events.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream_events.cjs","names":["getAnthropicUsageMetadata"],"sources":["../../../../../src/llm/anthropic/utils/stream_events.ts"],"sourcesContent":["/**\n * Converts a raw Anthropic SSE event stream into LangChain ChatModelStreamEvents.\n *\n * @module\n */\n\nimport type {\n ChatModelStreamEvent,\n ContentBlockDelta,\n FinishReason,\n} from '@langchain/core/language_models/event';\nimport type { ContentBlock, UsageMetadata } from '@langchain/core/messages';\nimport type {\n AnthropicCompactionBlock,\n AnthropicCompactionContentBlockDelta,\n AnthropicMessageStreamEvent,\n} from '../types';\nimport type { AnthropicUsageData } from './message_outputs';\nimport { getAnthropicUsageMetadata } from './message_outputs';\n\ntype AnthropicContentBlock =\n | Extract<\n AnthropicMessageStreamEvent,\n { type: 'content_block_start' }\n >['content_block']\n | AnthropicCompactionBlock;\n\ntype AnthropicContentDelta =\n | Extract<\n AnthropicMessageStreamEvent,\n { type: 'content_block_delta' }\n >['delta']\n | AnthropicCompactionContentBlockDelta;\n\ninterface AnthropicStreamErrorEvent {\n type: 'error';\n error: {\n type: string;\n message: string;\n };\n request_id?: string | null;\n}\n\ntype AnthropicStreamInputEvent =\n | AnthropicMessageStreamEvent\n | AnthropicStreamErrorEvent;\n\ntype BlockAccumulator = Record<string, unknown>;\n\ninterface AnthropicEventUsage {\n inputTokens: number;\n cacheCreationInputTokens: number;\n cacheReadInputTokens: number;\n outputTokens: number;\n}\n\n// ─── Public API ─────────────────────────────────────────────────\n\nexport interface ConvertAnthropicStreamOptions {\n streamUsage?: boolean;\n}\n\n/**\n * Convert an async iterable of raw Anthropic stream events into\n * LangChain `ChatModelStreamEvent`s with typed deltas.\n */\nexport async function* convertAnthropicStream(\n source: AsyncIterable<AnthropicStreamInputEvent>,\n options: ConvertAnthropicStreamOptions = {}\n): AsyncGenerator<ChatModelStreamEvent> {\n const shouldStreamUsage = options.streamUsage ?? true;\n\n // Track accumulated state per content block (for finalization)\n const blockAccumulators = new Map<number, BlockAccumulator>();\n let usageSnapshot: UsageMetadata | undefined;\n let eventUsage: AnthropicEventUsage | undefined;\n let stopReason: string | null = null;\n\n for await (const data of source) {\n switch (data.type) {\n // ── Message lifecycle ──────────────────────────────────\n case 'message_start': {\n const { usage, id, model } = data.message;\n if (shouldStreamUsage) {\n eventUsage = {\n inputTokens: usage.input_tokens,\n cacheCreationInputTokens: usage.cache_creation_input_tokens ?? 0,\n cacheReadInputTokens: usage.cache_read_input_tokens ?? 0,\n outputTokens: usage.output_tokens,\n };\n usageSnapshot = buildUsageSnapshot(eventUsage);\n }\n yield {\n event: 'message-start' as const,\n id,\n ...(usageSnapshot ? { usage: usageSnapshot } : {}),\n };\n yield {\n event: 'provider' as const,\n provider: 'anthropic',\n name: 'message_start',\n payload: { model, id },\n };\n break;\n }\n\n case 'message_delta': {\n stopReason = data.delta.stop_reason;\n if (shouldStreamUsage) {\n eventUsage = updateEventUsage(eventUsage, data.usage);\n usageSnapshot = buildUsageSnapshot(eventUsage);\n yield { event: 'usage' as const, usage: usageSnapshot };\n }\n if (\n 'context_management' in data.delta &&\n data.delta.context_management != null\n ) {\n yield {\n event: 'provider' as const,\n provider: 'anthropic',\n name: 'context_management',\n payload: data.delta.context_management,\n };\n }\n break;\n }\n\n case 'message_stop': {\n const finishEvent = {\n event: 'message-finish' as const,\n reason: mapStopReason(stopReason),\n ...(usageSnapshot ? { usage: usageSnapshot } : {}),\n responseMetadata: { model_provider: 'anthropic' },\n };\n yield finishEvent;\n break;\n }\n\n case 'error': {\n const streamError = new Error(data.error.message);\n streamError.name = data.error.type;\n throw streamError;\n }\n\n // ── Content block lifecycle ───────────────────────────\n case 'content_block_start': {\n const { index, content_block } = data;\n const mapped = mapBlockToContentBlock(content_block, index);\n blockAccumulators.set(index, { ...mapped });\n yield {\n event: 'content-block-start' as const,\n index,\n content: mapped as unknown as ContentBlock,\n };\n break;\n }\n\n case 'content_block_delta': {\n const { index, delta } = data;\n const acc = blockAccumulators.get(index);\n if (!acc) break;\n\n const { contentDelta, accumulated } = applyAnthropicDelta(acc, delta);\n blockAccumulators.set(index, accumulated);\n\n yield {\n event: 'content-block-delta' as const,\n index,\n delta: contentDelta,\n };\n break;\n }\n\n case 'content_block_stop': {\n const { index } = data;\n const acc = blockAccumulators.get(index);\n if (!acc) break;\n\n const finalized = finalizeBlock(acc);\n yield {\n event: 'content-block-finish' as const,\n index,\n content: finalized,\n };\n blockAccumulators.delete(index);\n break;\n }\n\n // ── Unhandled → provider passthrough ───────────────────\n default: {\n const providerData = data as AnthropicMessageStreamEvent;\n yield {\n event: 'provider' as const,\n provider: 'anthropic',\n name: providerData.type,\n payload: providerData,\n };\n break;\n }\n }\n }\n}\n\n// ─── Internal helpers ───────────────────────────────────────────\n\nfunction mapStopReason(stopReason: string | null | undefined): FinishReason {\n switch (stopReason) {\n case 'end_turn':\n case 'stop_sequence':\n return 'stop';\n case 'tool_use':\n return 'tool_use';\n case 'max_tokens':\n case 'model_context_window_exceeded':\n return 'length';\n case 'refusal':\n return 'content_filter';\n default:\n return 'stop';\n }\n}\n\nfunction updateEventUsage(\n previous: AnthropicEventUsage | undefined,\n current: AnthropicUsageData\n): AnthropicEventUsage {\n return {\n inputTokens: getCumulativeUsageValue(\n current.input_tokens,\n previous?.inputTokens\n ),\n cacheCreationInputTokens: getCumulativeUsageValue(\n current.cache_creation_input_tokens,\n previous?.cacheCreationInputTokens\n ),\n cacheReadInputTokens: getCumulativeUsageValue(\n current.cache_read_input_tokens,\n previous?.cacheReadInputTokens\n ),\n outputTokens: getCumulativeUsageValue(\n current.output_tokens,\n previous?.outputTokens\n ),\n };\n}\n\nfunction getCumulativeUsageValue(\n current: number | null | undefined,\n previous: number | undefined\n): number {\n return Math.max(previous ?? 0, current ?? 0);\n}\n\nfunction buildUsageSnapshot(usage: AnthropicEventUsage): UsageMetadata {\n const metadata = getAnthropicUsageMetadata({\n input_tokens: usage.inputTokens,\n output_tokens: usage.outputTokens,\n cache_creation_input_tokens: usage.cacheCreationInputTokens,\n cache_read_input_tokens: usage.cacheReadInputTokens,\n });\n if (metadata == null) {\n throw new Error('Anthropic usage metadata was not created');\n }\n return metadata;\n}\n\nfunction getStringField(record: BlockAccumulator, key: string): string {\n const value = record[key];\n return typeof value === 'string' ? value : '';\n}\n\nfunction getArrayField(record: BlockAccumulator, key: string): unknown[] {\n const value = record[key];\n return Array.isArray(value) ? value : [];\n}\n\nfunction mapBlockToContentBlock(\n block: AnthropicContentBlock,\n index: number\n): BlockAccumulator {\n switch (block.type) {\n case 'text':\n return {\n type: 'text' as const,\n text: block.text,\n ...(block.citations != null ? { citations: block.citations } : {}),\n index,\n };\n case 'thinking':\n return {\n type: 'reasoning' as const,\n reasoning: block.thinking,\n index,\n };\n case 'redacted_thinking':\n return { ...block, index };\n case 'tool_use':\n return {\n type: 'tool_call_chunk' as const,\n id: block.id,\n name: block.name,\n args: '',\n index,\n };\n case 'server_tool_use':\n return {\n type: 'server_tool_call_chunk' as const,\n id: block.id,\n name: block.name,\n args: '',\n index,\n };\n case 'web_search_tool_result':\n return { ...block, index };\n case 'compaction':\n return { ...block, index };\n default:\n return { type: 'non_standard' as const, value: { ...block }, index };\n }\n}\n\n/**\n * Map an Anthropic content_block_delta to a content block delta\n * and update the accumulated state.\n */\nfunction applyAnthropicDelta(\n accumulated: BlockAccumulator,\n delta: AnthropicContentDelta\n): {\n contentDelta: ContentBlockDelta;\n accumulated: BlockAccumulator;\n} {\n const rawDelta = delta as unknown as Record<string, unknown>;\n switch (delta.type) {\n case 'text_delta':\n return {\n contentDelta: { type: 'text-delta' as const, text: delta.text },\n accumulated: {\n ...accumulated,\n text: getStringField(accumulated, 'text') + delta.text,\n },\n };\n\n case 'thinking_delta':\n return {\n contentDelta: {\n type: 'reasoning-delta' as const,\n reasoning: delta.thinking,\n },\n accumulated: {\n ...accumulated,\n reasoning: getStringField(accumulated, 'reasoning') + delta.thinking,\n },\n };\n\n case 'input_json_delta': {\n const newArgs = getStringField(accumulated, 'args') + delta.partial_json;\n return {\n contentDelta: {\n type: 'block-delta' as const,\n fields: {\n type: getStringField(accumulated, 'type'),\n args: newArgs,\n },\n },\n accumulated: { ...accumulated, args: newArgs },\n };\n }\n\n case 'citations_delta': {\n const citations = [\n ...getArrayField(accumulated, 'citations'),\n delta.citation,\n ];\n return {\n contentDelta: {\n type: 'block-delta' as const,\n fields: {\n type: getStringField(accumulated, 'type'),\n citations,\n },\n },\n accumulated: {\n ...accumulated,\n citations,\n },\n };\n }\n\n case 'signature_delta':\n return {\n contentDelta: {\n type: 'block-delta' as const,\n fields: {\n type: getStringField(accumulated, 'type'),\n signature: delta.signature,\n },\n },\n accumulated: { ...accumulated, signature: delta.signature },\n };\n\n case 'compaction_delta': {\n const previousContent = accumulated.content;\n const content =\n delta.content == null\n ? (previousContent ?? null)\n : getStringField(accumulated, 'content') + delta.content;\n return {\n contentDelta: {\n type: 'block-delta' as const,\n fields: {\n type: 'compaction',\n content,\n encrypted_content: delta.encrypted_content,\n },\n },\n accumulated: {\n ...accumulated,\n content,\n encrypted_content: delta.encrypted_content,\n },\n };\n }\n\n default:\n return {\n contentDelta: {\n type: 'block-delta' as const,\n fields: {\n type: getStringField(accumulated, 'type'),\n ...rawDelta,\n },\n },\n accumulated,\n };\n }\n}\n\nfunction finalizeBlock(accumulated: BlockAccumulator): ContentBlock {\n if (\n accumulated.type === 'tool_call_chunk' ||\n accumulated.type === 'server_tool_call_chunk'\n ) {\n const finalType =\n accumulated.type === 'tool_call_chunk'\n ? ('tool_call' as const)\n : ('server_tool_call' as const);\n const args = getStringField(accumulated, 'args');\n let parsedArgs: unknown;\n try {\n parsedArgs = JSON.parse(args || '{}');\n } catch {\n return {\n type: 'invalid_tool_call' as const,\n id: getStringField(accumulated, 'id'),\n name: getStringField(accumulated, 'name'),\n args,\n error: 'Failed to parse tool call arguments as JSON',\n } as ContentBlock.Tools.InvalidToolCall;\n }\n return {\n type: finalType,\n id: getStringField(accumulated, 'id'),\n name: getStringField(accumulated, 'name'),\n args: parsedArgs,\n } as ContentBlock;\n }\n\n const { index: _index, ...rest } = accumulated;\n return rest as ContentBlock;\n}\n"],"mappings":"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"}
@@ -43,27 +43,58 @@ function isSerializableBedrockReasoningBlock(content) {
43
43
  }
44
44
  return content.redactedContent != null && content.redactedContent !== "";
45
45
  }
46
+ function appendSerializableBedrockTextBlock(contentBlocks, text) {
47
+ if (text === "") return false;
48
+ if (text.replace(/\n/g, "").trim() !== "") {
49
+ contentBlocks.push({ text });
50
+ return true;
51
+ }
52
+ const lastBlock = contentBlocks[contentBlocks.length - 1];
53
+ if (lastBlock == null || !("text" in lastBlock)) return false;
54
+ lastBlock.text = `${lastBlock.text}${text}`;
55
+ return true;
56
+ }
46
57
  /**
47
58
  * Concatenate consecutive reasoning blocks in content array.
48
59
  */
49
60
  function concatenateLangchainReasoningBlocks(content) {
50
61
  const result = [];
51
- for (const block of content) if (block.type === "reasoning_content") {
62
+ let pendingReasoning;
63
+ const flushPendingReasoning = () => {
64
+ if (pendingReasoning != null) {
65
+ result.push(pendingReasoning);
66
+ pendingReasoning = void 0;
67
+ }
68
+ };
69
+ for (const block of content) {
70
+ if (block.type !== "reasoning_content") {
71
+ flushPendingReasoning();
72
+ result.push(block);
73
+ continue;
74
+ }
52
75
  const currentReasoning = block;
53
- const lastIndex = result.length - 1;
54
- if (lastIndex >= 0) {
55
- const lastBlock = result[lastIndex];
56
- if (lastBlock.type === "reasoning_content" && lastBlock.reasoningText != null && currentReasoning.reasoningText != null) {
57
- const lastReasoning = lastBlock;
58
- const lastText = lastReasoning.reasoningText?.text;
59
- const currentText = currentReasoning.reasoningText.text;
60
- if (lastText != null && lastText !== "" && currentText != null && currentText !== "") lastReasoning.reasoningText.text = lastText + currentText;
61
- else if (currentReasoning.reasoningText.signature != null && currentReasoning.reasoningText.signature !== "") lastReasoning.reasoningText.signature = currentReasoning.reasoningText.signature;
62
- continue;
63
- }
76
+ if (currentReasoning.reasoningText != null) {
77
+ const previousText = pendingReasoning?.reasoningText?.text;
78
+ const previousSignature = pendingReasoning?.reasoningText?.signature;
79
+ const { text, signature } = currentReasoning.reasoningText;
80
+ const mergedReasoningText = {};
81
+ if (previousText !== void 0 || text !== void 0) mergedReasoningText.text = (previousText ?? "") + (text ?? "");
82
+ if (previousSignature !== void 0 || signature !== void 0) mergedReasoningText.signature = (previousSignature ?? "") + (signature ?? "");
83
+ pendingReasoning = {
84
+ type: "reasoning_content",
85
+ reasoningText: mergedReasoningText
86
+ };
87
+ if ("signature" in currentReasoning.reasoningText) flushPendingReasoning();
88
+ }
89
+ if (currentReasoning.redactedContent != null) {
90
+ flushPendingReasoning();
91
+ result.push({
92
+ type: "reasoning_content",
93
+ redactedContent: currentReasoning.redactedContent
94
+ });
64
95
  }
65
- result.push({ ...block });
66
- } else result.push(block);
96
+ }
97
+ flushPendingReasoning();
67
98
  return result;
68
99
  }
69
100
  /**
@@ -328,16 +359,8 @@ function convertAIMessageToConverseMessage(msg) {
328
359
  const concatenatedBlocks = concatenateLangchainReasoningBlocks(msg.content);
329
360
  const contentBlocks = [];
330
361
  concatenatedBlocks.forEach((block) => {
331
- if (block.type === "text") {
332
- const text = block.text ?? "";
333
- if (text === "") return;
334
- if (text.replace(/\n/g, "").trim() === "") {
335
- if (contentBlocks.length > 0) {
336
- const lastBlock = contentBlocks[contentBlocks.length - 1];
337
- if ("text" in lastBlock) lastBlock.text = `${lastBlock.text}${text}`;
338
- }
339
- } else contentBlocks.push({ text });
340
- } else if (block.type === "reasoning_content") {
362
+ if (block.type === "text") appendSerializableBedrockTextBlock(contentBlocks, block.text ?? "");
363
+ else if (block.type === "reasoning_content") {
341
364
  const reasoningBlock = block;
342
365
  if (!isSerializableBedrockReasoningBlock(reasoningBlock)) return;
343
366
  contentBlocks.push({ reasoningContent: langchainReasoningBlockToBedrockReasoningBlock(reasoningBlock) });
@@ -370,33 +393,58 @@ function convertAIMessageToConverseMessage(msg) {
370
393
  * (Implements PR #9766 fix for output_version v1 detection)
371
394
  */
372
395
  function convertFromV1ToChatBedrockConverseMessage(msg) {
396
+ const contentBlocks = [];
373
397
  const assistantMsg = {
374
398
  role: "assistant",
375
- content: []
399
+ content: contentBlocks
376
400
  };
401
+ let droppedUnserializableContent = false;
402
+ let unconvertedContentType;
377
403
  if (Array.isArray(msg.content)) {
378
- for (const block of msg.content) if (typeof block === "string") assistantMsg.content?.push({ text: block });
379
- else if (block.type === "text") assistantMsg.content?.push({ text: block.text });
380
- else if (block.type === "tool_call") {
404
+ const concatenatedBlocks = concatenateLangchainReasoningBlocks(msg.content);
405
+ for (const block of concatenatedBlocks) if (typeof block === "string") {
406
+ if (!appendSerializableBedrockTextBlock(contentBlocks, block)) droppedUnserializableContent = true;
407
+ } else if (block.type === "text") {
408
+ if (!appendSerializableBedrockTextBlock(contentBlocks, block.text ?? "")) droppedUnserializableContent = true;
409
+ } else if (block.type === "tool_call") {
381
410
  const toolCall = block;
382
- assistantMsg.content?.push({ toolUse: {
411
+ contentBlocks.push({ toolUse: {
383
412
  toolUseId: toolCall.id,
384
413
  name: toolCall.name,
385
414
  input: toolCall.args
386
415
  } });
387
416
  } else if (block.type === "reasoning") {
388
417
  const reasoning = block;
389
- assistantMsg.content?.push({ reasoningContent: { reasoningText: { text: reasoning.reasoning } } });
390
- } else if (block.type === "reasoning_content") assistantMsg.content?.push({ reasoningContent: langchainReasoningBlockToBedrockReasoningBlock(block) });
391
- } else if (typeof msg.content === "string" && msg.content !== "") assistantMsg.content?.push({ text: msg.content });
418
+ /** Bedrock Converse rejects `reasoningText` with a null/empty `text`
419
+ * (`Member must not be null`), e.g. when the producing model omitted
420
+ * reasoning text (`thinking.display: "omitted"`) drop rather than send. */
421
+ if (reasoning.reasoning == null || reasoning.reasoning === "") {
422
+ droppedUnserializableContent = true;
423
+ continue;
424
+ }
425
+ contentBlocks.push({ reasoningContent: { reasoningText: { text: reasoning.reasoning } } });
426
+ } else if (block.type === "reasoning_content") {
427
+ const reasoningBlock = block;
428
+ if (!isSerializableBedrockReasoningBlock(reasoningBlock)) {
429
+ droppedUnserializableContent = true;
430
+ continue;
431
+ }
432
+ contentBlocks.push({ reasoningContent: langchainReasoningBlockToBedrockReasoningBlock(reasoningBlock) });
433
+ } else unconvertedContentType ??= block.type;
434
+ } else if (typeof msg.content === "string") {
435
+ if (!appendSerializableBedrockTextBlock(contentBlocks, msg.content)) droppedUnserializableContent = true;
436
+ }
392
437
  if ((0, _langchain_core_messages.isAIMessage)(msg) && msg.tool_calls != null && msg.tool_calls.length > 0) {
393
- const existingToolUseIds = new Set(assistantMsg.content?.filter((c) => "toolUse" in c).map((c) => c.toolUse.toolUseId) ?? []);
394
- for (const tc of msg.tool_calls) if (!existingToolUseIds.has(tc.id ?? "")) assistantMsg.content?.push({ toolUse: {
438
+ const existingToolUseIds = new Set(contentBlocks.filter((c) => "toolUse" in c).map((c) => c.toolUse.toolUseId));
439
+ for (const tc of msg.tool_calls) if (!existingToolUseIds.has(tc.id ?? "")) contentBlocks.push({ toolUse: {
395
440
  toolUseId: tc.id,
396
441
  name: tc.name,
397
442
  input: tc.args
398
443
  } });
399
444
  }
445
+ const hasNoContent = contentBlocks.length === 0;
446
+ if (hasNoContent && unconvertedContentType != null) throw new Error(`Unsupported v1 content block type: ${unconvertedContentType}`);
447
+ if (hasNoContent && droppedUnserializableContent) contentBlocks.push({ text: BEDROCK_EMPTY_TEXT_PLACEHOLDER });
400
448
  return assistantMsg;
401
449
  }
402
450
  /**