@langchain/anthropic 1.3.27 → 1.3.29
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/CHANGELOG.md +15 -0
- package/dist/chat_models.cjs +44 -8
- package/dist/chat_models.cjs.map +1 -1
- package/dist/chat_models.d.cts +21 -11
- package/dist/chat_models.d.cts.map +1 -1
- package/dist/chat_models.d.ts +21 -11
- package/dist/chat_models.d.ts.map +1 -1
- package/dist/chat_models.js +45 -9
- package/dist/chat_models.js.map +1 -1
- package/dist/utils/message_inputs.cjs +0 -51
- package/dist/utils/message_inputs.cjs.map +1 -1
- package/dist/utils/message_inputs.js +1 -51
- package/dist/utils/message_inputs.js.map +1 -1
- package/dist/utils/stream_events.cjs +301 -0
- package/dist/utils/stream_events.cjs.map +1 -0
- package/dist/utils/stream_events.js +301 -0
- package/dist/utils/stream_events.js.map +1 -0
- package/dist/utils/tools.cjs +1 -1
- package/package.json +4 -5
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
//#region src/utils/stream_events.ts
|
|
2
|
+
/**
|
|
3
|
+
* Convert an async iterable of raw Anthropic stream events into
|
|
4
|
+
* LangChain `ChatModelStreamEvent`s with typed deltas.
|
|
5
|
+
*/
|
|
6
|
+
async function* convertAnthropicStream(source, options = {}) {
|
|
7
|
+
const shouldStreamUsage = options.streamUsage ?? true;
|
|
8
|
+
const blockAccumulators = /* @__PURE__ */ new Map();
|
|
9
|
+
let usageSnapshot;
|
|
10
|
+
let stopReason = null;
|
|
11
|
+
for await (const data of source) switch (data.type) {
|
|
12
|
+
case "message_start": {
|
|
13
|
+
const { usage, id, model } = data.message;
|
|
14
|
+
if (usage && shouldStreamUsage) usageSnapshot = buildUsageSnapshot(usage);
|
|
15
|
+
yield {
|
|
16
|
+
event: "message-start",
|
|
17
|
+
id,
|
|
18
|
+
...usageSnapshot ? { usage: usageSnapshot } : {}
|
|
19
|
+
};
|
|
20
|
+
yield {
|
|
21
|
+
event: "provider",
|
|
22
|
+
provider: "anthropic",
|
|
23
|
+
name: "message_start",
|
|
24
|
+
payload: {
|
|
25
|
+
model,
|
|
26
|
+
id
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case "message_delta":
|
|
32
|
+
stopReason = data.delta.stop_reason;
|
|
33
|
+
if (shouldStreamUsage && data.usage) {
|
|
34
|
+
if (!usageSnapshot) usageSnapshot = {
|
|
35
|
+
input_tokens: 0,
|
|
36
|
+
output_tokens: data.usage.output_tokens,
|
|
37
|
+
total_tokens: data.usage.output_tokens
|
|
38
|
+
};
|
|
39
|
+
else usageSnapshot = {
|
|
40
|
+
...usageSnapshot,
|
|
41
|
+
output_tokens: usageSnapshot.output_tokens + data.usage.output_tokens,
|
|
42
|
+
total_tokens: usageSnapshot.input_tokens + usageSnapshot.output_tokens + data.usage.output_tokens
|
|
43
|
+
};
|
|
44
|
+
yield {
|
|
45
|
+
event: "usage",
|
|
46
|
+
usage: usageSnapshot
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if ("context_management" in data.delta && data.delta.context_management) yield {
|
|
50
|
+
event: "provider",
|
|
51
|
+
provider: "anthropic",
|
|
52
|
+
name: "context_management",
|
|
53
|
+
payload: data.delta.context_management
|
|
54
|
+
};
|
|
55
|
+
break;
|
|
56
|
+
case "message_stop":
|
|
57
|
+
yield {
|
|
58
|
+
event: "message-finish",
|
|
59
|
+
reason: mapStopReason(stopReason),
|
|
60
|
+
...usageSnapshot ? { usage: usageSnapshot } : {},
|
|
61
|
+
metadata: { model_provider: "anthropic" }
|
|
62
|
+
};
|
|
63
|
+
break;
|
|
64
|
+
case "content_block_start": {
|
|
65
|
+
const { index, content_block } = data;
|
|
66
|
+
const mapped = mapBlockToContentBlock(content_block, index);
|
|
67
|
+
blockAccumulators.set(index, { ...mapped });
|
|
68
|
+
yield {
|
|
69
|
+
event: "content-block-start",
|
|
70
|
+
index,
|
|
71
|
+
content: mapped
|
|
72
|
+
};
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case "content_block_delta": {
|
|
76
|
+
const { index, delta } = data;
|
|
77
|
+
const acc = blockAccumulators.get(index);
|
|
78
|
+
if (!acc) break;
|
|
79
|
+
const { contentDelta, accumulated } = applyAnthropicDelta(acc, delta);
|
|
80
|
+
blockAccumulators.set(index, accumulated);
|
|
81
|
+
yield {
|
|
82
|
+
event: "content-block-delta",
|
|
83
|
+
index,
|
|
84
|
+
delta: contentDelta
|
|
85
|
+
};
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case "content_block_stop": {
|
|
89
|
+
const { index } = data;
|
|
90
|
+
const acc = blockAccumulators.get(index);
|
|
91
|
+
if (!acc) break;
|
|
92
|
+
yield {
|
|
93
|
+
event: "content-block-finish",
|
|
94
|
+
index,
|
|
95
|
+
content: finalizeBlock(acc)
|
|
96
|
+
};
|
|
97
|
+
blockAccumulators.delete(index);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
default:
|
|
101
|
+
yield {
|
|
102
|
+
event: "provider",
|
|
103
|
+
provider: "anthropic",
|
|
104
|
+
name: data.type,
|
|
105
|
+
payload: data
|
|
106
|
+
};
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function mapStopReason(stopReason) {
|
|
111
|
+
switch (stopReason) {
|
|
112
|
+
case "end_turn":
|
|
113
|
+
case "stop_sequence": return "stop";
|
|
114
|
+
case "tool_use": return "tool_use";
|
|
115
|
+
case "max_tokens": return "length";
|
|
116
|
+
default: return "stop";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function buildUsageSnapshot(usage) {
|
|
120
|
+
const cacheCreation = usage.cache_creation_input_tokens ?? 0;
|
|
121
|
+
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
|
122
|
+
const totalInput = usage.input_tokens + cacheCreation + cacheRead;
|
|
123
|
+
return {
|
|
124
|
+
input_tokens: totalInput,
|
|
125
|
+
output_tokens: usage.output_tokens,
|
|
126
|
+
total_tokens: totalInput + usage.output_tokens,
|
|
127
|
+
input_token_details: {
|
|
128
|
+
cache_creation: cacheCreation,
|
|
129
|
+
cache_read: cacheRead
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function mapBlockToContentBlock(block, index) {
|
|
134
|
+
switch (block.type) {
|
|
135
|
+
case "text": return {
|
|
136
|
+
type: "text",
|
|
137
|
+
text: block.text ?? "",
|
|
138
|
+
index
|
|
139
|
+
};
|
|
140
|
+
case "thinking": return {
|
|
141
|
+
type: "reasoning",
|
|
142
|
+
reasoning: block.thinking ?? "",
|
|
143
|
+
index
|
|
144
|
+
};
|
|
145
|
+
case "redacted_thinking": return {
|
|
146
|
+
type: "non_standard",
|
|
147
|
+
value: { ...block },
|
|
148
|
+
index
|
|
149
|
+
};
|
|
150
|
+
case "tool_use": return {
|
|
151
|
+
type: "tool_call_chunk",
|
|
152
|
+
id: block.id,
|
|
153
|
+
name: block.name,
|
|
154
|
+
args: "",
|
|
155
|
+
index
|
|
156
|
+
};
|
|
157
|
+
case "server_tool_use": return {
|
|
158
|
+
type: "server_tool_call_chunk",
|
|
159
|
+
id: block.id,
|
|
160
|
+
name: block.name,
|
|
161
|
+
args: "",
|
|
162
|
+
index
|
|
163
|
+
};
|
|
164
|
+
default: return {
|
|
165
|
+
type: "non_standard",
|
|
166
|
+
value: { ...block },
|
|
167
|
+
index
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Map an Anthropic content_block_delta to a content block delta
|
|
173
|
+
* and update the accumulated state.
|
|
174
|
+
*/
|
|
175
|
+
function applyAnthropicDelta(accumulated, delta) {
|
|
176
|
+
switch (delta.type) {
|
|
177
|
+
case "text_delta": return {
|
|
178
|
+
contentDelta: {
|
|
179
|
+
type: "text-delta",
|
|
180
|
+
text: delta.text
|
|
181
|
+
},
|
|
182
|
+
accumulated: {
|
|
183
|
+
...accumulated,
|
|
184
|
+
text: (accumulated.text ?? "") + delta.text
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
case "thinking_delta": return {
|
|
188
|
+
contentDelta: {
|
|
189
|
+
type: "reasoning-delta",
|
|
190
|
+
reasoning: delta.thinking
|
|
191
|
+
},
|
|
192
|
+
accumulated: {
|
|
193
|
+
...accumulated,
|
|
194
|
+
reasoning: (accumulated.reasoning ?? "") + delta.thinking
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
case "input_json_delta": {
|
|
198
|
+
const newArgs = (accumulated.args ?? "") + delta.partial_json;
|
|
199
|
+
return {
|
|
200
|
+
contentDelta: {
|
|
201
|
+
type: "block-delta",
|
|
202
|
+
fields: {
|
|
203
|
+
type: accumulated.type,
|
|
204
|
+
args: newArgs
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
accumulated: {
|
|
208
|
+
...accumulated,
|
|
209
|
+
args: newArgs
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
case "citations_delta": {
|
|
214
|
+
const annotations = [...accumulated.annotations ?? [], delta.citation];
|
|
215
|
+
return {
|
|
216
|
+
contentDelta: {
|
|
217
|
+
type: "block-delta",
|
|
218
|
+
fields: {
|
|
219
|
+
type: accumulated.type,
|
|
220
|
+
annotations
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
accumulated: {
|
|
224
|
+
...accumulated,
|
|
225
|
+
annotations
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
case "signature_delta": return {
|
|
230
|
+
contentDelta: {
|
|
231
|
+
type: "block-delta",
|
|
232
|
+
fields: {
|
|
233
|
+
type: accumulated.type,
|
|
234
|
+
signature: delta.signature
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
accumulated: {
|
|
238
|
+
...accumulated,
|
|
239
|
+
signature: delta.signature
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
case "compaction_delta": return {
|
|
243
|
+
contentDelta: {
|
|
244
|
+
type: "block-delta",
|
|
245
|
+
fields: {
|
|
246
|
+
type: "non_standard",
|
|
247
|
+
value: {
|
|
248
|
+
...accumulated.value ?? {},
|
|
249
|
+
compaction: delta
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
accumulated: {
|
|
254
|
+
...accumulated,
|
|
255
|
+
value: {
|
|
256
|
+
...accumulated.value ?? {},
|
|
257
|
+
compaction: delta
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
default: return {
|
|
262
|
+
contentDelta: {
|
|
263
|
+
type: "block-delta",
|
|
264
|
+
fields: {
|
|
265
|
+
type: accumulated.type,
|
|
266
|
+
...delta
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
accumulated
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function finalizeBlock(accumulated) {
|
|
274
|
+
if (accumulated.type === "tool_call_chunk" || accumulated.type === "server_tool_call_chunk") {
|
|
275
|
+
const finalType = accumulated.type === "tool_call_chunk" ? "tool_call" : "server_tool_call";
|
|
276
|
+
let parsedArgs;
|
|
277
|
+
try {
|
|
278
|
+
parsedArgs = JSON.parse(accumulated.args || "{}");
|
|
279
|
+
} catch {
|
|
280
|
+
return {
|
|
281
|
+
type: "invalid_tool_call",
|
|
282
|
+
id: accumulated.id,
|
|
283
|
+
name: accumulated.name,
|
|
284
|
+
args: accumulated.args,
|
|
285
|
+
error: "Failed to parse tool call arguments as JSON"
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
type: finalType,
|
|
290
|
+
id: accumulated.id,
|
|
291
|
+
name: accumulated.name,
|
|
292
|
+
args: parsedArgs
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const { index: _index, ...rest } = accumulated;
|
|
296
|
+
return rest;
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
299
|
+
exports.convertAnthropicStream = convertAnthropicStream;
|
|
300
|
+
|
|
301
|
+
//# sourceMappingURL=stream_events.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream_events.cjs","names":[],"sources":["../../src/utils/stream_events.ts"],"sourcesContent":["/**\n * Converts a raw Anthropic SSE event stream into LangChain ChatModelStreamEvents.\n *\n * @module\n */\n\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport type {\n ChatModelStreamEvent,\n ContentBlockDelta,\n FinishReason,\n} from \"@langchain/core/language_models/event\";\nimport type { ContentBlock } from \"@langchain/core/messages/content\";\nimport type { UsageMetadata } from \"@langchain/core/messages/metadata\";\nimport type { AnthropicMessageStreamEvent } from \"../types.js\";\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<AnthropicMessageStreamEvent>,\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<\n number,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n Record<string, any>\n >();\n let usageSnapshot: UsageMetadata | 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 (usage && shouldStreamUsage) {\n usageSnapshot = buildUsageSnapshot(usage);\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 && data.usage) {\n if (!usageSnapshot) {\n usageSnapshot = {\n input_tokens: 0,\n output_tokens: data.usage.output_tokens,\n total_tokens: data.usage.output_tokens,\n };\n } else {\n usageSnapshot = {\n ...usageSnapshot,\n output_tokens:\n usageSnapshot.output_tokens + data.usage.output_tokens,\n total_tokens:\n usageSnapshot.input_tokens +\n usageSnapshot.output_tokens +\n data.usage.output_tokens,\n };\n }\n yield { event: \"usage\" as const, usage: usageSnapshot };\n }\n if (\n \"context_management\" in data.delta &&\n data.delta.context_management\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 yield {\n event: \"message-finish\" as const,\n reason: mapStopReason(stopReason),\n ...(usageSnapshot ? { usage: usageSnapshot } : {}),\n metadata: { model_provider: \"anthropic\" },\n };\n break;\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,\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 yield {\n event: \"provider\" as const,\n provider: \"anthropic\",\n name: data.type,\n payload: data,\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 return \"length\";\n default:\n return \"stop\";\n }\n}\n\nfunction buildUsageSnapshot(\n usage: Anthropic.Messages.Usage | Record<string, number>\n): UsageMetadata {\n const cacheCreation =\n (usage as Record<string, number>).cache_creation_input_tokens ?? 0;\n const cacheRead =\n (usage as Record<string, number>).cache_read_input_tokens ?? 0;\n const totalInput = usage.input_tokens + cacheCreation + cacheRead;\n return {\n input_tokens: totalInput,\n output_tokens: usage.output_tokens,\n total_tokens: totalInput + usage.output_tokens,\n input_token_details: {\n cache_creation: cacheCreation,\n cache_read: cacheRead,\n },\n };\n}\n\nfunction mapBlockToContentBlock(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n block: any,\n index: number\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, any> {\n switch (block.type) {\n case \"text\":\n return { type: \"text\" as const, text: block.text ?? \"\", index };\n case \"thinking\":\n return {\n type: \"reasoning\" as const,\n reasoning: block.thinking ?? \"\",\n index,\n };\n case \"redacted_thinking\":\n return { type: \"non_standard\" as const, value: { ...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 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 // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n accumulated: Record<string, any>,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n delta: any\n): {\n contentDelta: ContentBlockDelta;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n accumulated: Record<string, any>;\n} {\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: (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: (accumulated.reasoning ?? \"\") + delta.thinking,\n },\n };\n\n case \"input_json_delta\": {\n const newArgs = (accumulated.args ?? \"\") + delta.partial_json;\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: { type: accumulated.type, args: newArgs },\n },\n accumulated: { ...accumulated, args: newArgs },\n };\n }\n\n case \"citations_delta\": {\n const annotations = [...(accumulated.annotations ?? []), delta.citation];\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: {\n type: accumulated.type,\n annotations,\n },\n },\n accumulated: {\n ...accumulated,\n annotations,\n },\n };\n }\n\n case \"signature_delta\":\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: { type: accumulated.type, signature: delta.signature },\n },\n accumulated: { ...accumulated, signature: delta.signature },\n };\n\n case \"compaction_delta\":\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: {\n type: \"non_standard\",\n value: { ...(accumulated.value ?? {}), compaction: delta },\n },\n },\n accumulated: {\n ...accumulated,\n value: { ...(accumulated.value ?? {}), compaction: delta },\n },\n };\n\n default:\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: { type: accumulated.type, ...delta },\n },\n accumulated,\n };\n }\n}\n\nfunction finalizeBlock(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n accumulated: Record<string, any>\n): 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 let parsedArgs: unknown;\n try {\n parsedArgs = JSON.parse(accumulated.args || \"{}\");\n } catch {\n return {\n type: \"invalid_tool_call\" as const,\n id: accumulated.id,\n name: accumulated.name,\n args: accumulated.args,\n error: \"Failed to parse tool call arguments as JSON\",\n } as ContentBlock.Tools.InvalidToolCall;\n }\n return {\n type: finalType,\n id: accumulated.id,\n name: accumulated.name,\n args: parsedArgs,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n }\n\n const { index: _index, ...rest } = accumulated;\n return rest as ContentBlock;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
//#region src/utils/stream_events.ts
|
|
2
|
+
/**
|
|
3
|
+
* Convert an async iterable of raw Anthropic stream events into
|
|
4
|
+
* LangChain `ChatModelStreamEvent`s with typed deltas.
|
|
5
|
+
*/
|
|
6
|
+
async function* convertAnthropicStream(source, options = {}) {
|
|
7
|
+
const shouldStreamUsage = options.streamUsage ?? true;
|
|
8
|
+
const blockAccumulators = /* @__PURE__ */ new Map();
|
|
9
|
+
let usageSnapshot;
|
|
10
|
+
let stopReason = null;
|
|
11
|
+
for await (const data of source) switch (data.type) {
|
|
12
|
+
case "message_start": {
|
|
13
|
+
const { usage, id, model } = data.message;
|
|
14
|
+
if (usage && shouldStreamUsage) usageSnapshot = buildUsageSnapshot(usage);
|
|
15
|
+
yield {
|
|
16
|
+
event: "message-start",
|
|
17
|
+
id,
|
|
18
|
+
...usageSnapshot ? { usage: usageSnapshot } : {}
|
|
19
|
+
};
|
|
20
|
+
yield {
|
|
21
|
+
event: "provider",
|
|
22
|
+
provider: "anthropic",
|
|
23
|
+
name: "message_start",
|
|
24
|
+
payload: {
|
|
25
|
+
model,
|
|
26
|
+
id
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case "message_delta":
|
|
32
|
+
stopReason = data.delta.stop_reason;
|
|
33
|
+
if (shouldStreamUsage && data.usage) {
|
|
34
|
+
if (!usageSnapshot) usageSnapshot = {
|
|
35
|
+
input_tokens: 0,
|
|
36
|
+
output_tokens: data.usage.output_tokens,
|
|
37
|
+
total_tokens: data.usage.output_tokens
|
|
38
|
+
};
|
|
39
|
+
else usageSnapshot = {
|
|
40
|
+
...usageSnapshot,
|
|
41
|
+
output_tokens: usageSnapshot.output_tokens + data.usage.output_tokens,
|
|
42
|
+
total_tokens: usageSnapshot.input_tokens + usageSnapshot.output_tokens + data.usage.output_tokens
|
|
43
|
+
};
|
|
44
|
+
yield {
|
|
45
|
+
event: "usage",
|
|
46
|
+
usage: usageSnapshot
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if ("context_management" in data.delta && data.delta.context_management) yield {
|
|
50
|
+
event: "provider",
|
|
51
|
+
provider: "anthropic",
|
|
52
|
+
name: "context_management",
|
|
53
|
+
payload: data.delta.context_management
|
|
54
|
+
};
|
|
55
|
+
break;
|
|
56
|
+
case "message_stop":
|
|
57
|
+
yield {
|
|
58
|
+
event: "message-finish",
|
|
59
|
+
reason: mapStopReason(stopReason),
|
|
60
|
+
...usageSnapshot ? { usage: usageSnapshot } : {},
|
|
61
|
+
metadata: { model_provider: "anthropic" }
|
|
62
|
+
};
|
|
63
|
+
break;
|
|
64
|
+
case "content_block_start": {
|
|
65
|
+
const { index, content_block } = data;
|
|
66
|
+
const mapped = mapBlockToContentBlock(content_block, index);
|
|
67
|
+
blockAccumulators.set(index, { ...mapped });
|
|
68
|
+
yield {
|
|
69
|
+
event: "content-block-start",
|
|
70
|
+
index,
|
|
71
|
+
content: mapped
|
|
72
|
+
};
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case "content_block_delta": {
|
|
76
|
+
const { index, delta } = data;
|
|
77
|
+
const acc = blockAccumulators.get(index);
|
|
78
|
+
if (!acc) break;
|
|
79
|
+
const { contentDelta, accumulated } = applyAnthropicDelta(acc, delta);
|
|
80
|
+
blockAccumulators.set(index, accumulated);
|
|
81
|
+
yield {
|
|
82
|
+
event: "content-block-delta",
|
|
83
|
+
index,
|
|
84
|
+
delta: contentDelta
|
|
85
|
+
};
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case "content_block_stop": {
|
|
89
|
+
const { index } = data;
|
|
90
|
+
const acc = blockAccumulators.get(index);
|
|
91
|
+
if (!acc) break;
|
|
92
|
+
yield {
|
|
93
|
+
event: "content-block-finish",
|
|
94
|
+
index,
|
|
95
|
+
content: finalizeBlock(acc)
|
|
96
|
+
};
|
|
97
|
+
blockAccumulators.delete(index);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
default:
|
|
101
|
+
yield {
|
|
102
|
+
event: "provider",
|
|
103
|
+
provider: "anthropic",
|
|
104
|
+
name: data.type,
|
|
105
|
+
payload: data
|
|
106
|
+
};
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function mapStopReason(stopReason) {
|
|
111
|
+
switch (stopReason) {
|
|
112
|
+
case "end_turn":
|
|
113
|
+
case "stop_sequence": return "stop";
|
|
114
|
+
case "tool_use": return "tool_use";
|
|
115
|
+
case "max_tokens": return "length";
|
|
116
|
+
default: return "stop";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function buildUsageSnapshot(usage) {
|
|
120
|
+
const cacheCreation = usage.cache_creation_input_tokens ?? 0;
|
|
121
|
+
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
|
122
|
+
const totalInput = usage.input_tokens + cacheCreation + cacheRead;
|
|
123
|
+
return {
|
|
124
|
+
input_tokens: totalInput,
|
|
125
|
+
output_tokens: usage.output_tokens,
|
|
126
|
+
total_tokens: totalInput + usage.output_tokens,
|
|
127
|
+
input_token_details: {
|
|
128
|
+
cache_creation: cacheCreation,
|
|
129
|
+
cache_read: cacheRead
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function mapBlockToContentBlock(block, index) {
|
|
134
|
+
switch (block.type) {
|
|
135
|
+
case "text": return {
|
|
136
|
+
type: "text",
|
|
137
|
+
text: block.text ?? "",
|
|
138
|
+
index
|
|
139
|
+
};
|
|
140
|
+
case "thinking": return {
|
|
141
|
+
type: "reasoning",
|
|
142
|
+
reasoning: block.thinking ?? "",
|
|
143
|
+
index
|
|
144
|
+
};
|
|
145
|
+
case "redacted_thinking": return {
|
|
146
|
+
type: "non_standard",
|
|
147
|
+
value: { ...block },
|
|
148
|
+
index
|
|
149
|
+
};
|
|
150
|
+
case "tool_use": return {
|
|
151
|
+
type: "tool_call_chunk",
|
|
152
|
+
id: block.id,
|
|
153
|
+
name: block.name,
|
|
154
|
+
args: "",
|
|
155
|
+
index
|
|
156
|
+
};
|
|
157
|
+
case "server_tool_use": return {
|
|
158
|
+
type: "server_tool_call_chunk",
|
|
159
|
+
id: block.id,
|
|
160
|
+
name: block.name,
|
|
161
|
+
args: "",
|
|
162
|
+
index
|
|
163
|
+
};
|
|
164
|
+
default: return {
|
|
165
|
+
type: "non_standard",
|
|
166
|
+
value: { ...block },
|
|
167
|
+
index
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Map an Anthropic content_block_delta to a content block delta
|
|
173
|
+
* and update the accumulated state.
|
|
174
|
+
*/
|
|
175
|
+
function applyAnthropicDelta(accumulated, delta) {
|
|
176
|
+
switch (delta.type) {
|
|
177
|
+
case "text_delta": return {
|
|
178
|
+
contentDelta: {
|
|
179
|
+
type: "text-delta",
|
|
180
|
+
text: delta.text
|
|
181
|
+
},
|
|
182
|
+
accumulated: {
|
|
183
|
+
...accumulated,
|
|
184
|
+
text: (accumulated.text ?? "") + delta.text
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
case "thinking_delta": return {
|
|
188
|
+
contentDelta: {
|
|
189
|
+
type: "reasoning-delta",
|
|
190
|
+
reasoning: delta.thinking
|
|
191
|
+
},
|
|
192
|
+
accumulated: {
|
|
193
|
+
...accumulated,
|
|
194
|
+
reasoning: (accumulated.reasoning ?? "") + delta.thinking
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
case "input_json_delta": {
|
|
198
|
+
const newArgs = (accumulated.args ?? "") + delta.partial_json;
|
|
199
|
+
return {
|
|
200
|
+
contentDelta: {
|
|
201
|
+
type: "block-delta",
|
|
202
|
+
fields: {
|
|
203
|
+
type: accumulated.type,
|
|
204
|
+
args: newArgs
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
accumulated: {
|
|
208
|
+
...accumulated,
|
|
209
|
+
args: newArgs
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
case "citations_delta": {
|
|
214
|
+
const annotations = [...accumulated.annotations ?? [], delta.citation];
|
|
215
|
+
return {
|
|
216
|
+
contentDelta: {
|
|
217
|
+
type: "block-delta",
|
|
218
|
+
fields: {
|
|
219
|
+
type: accumulated.type,
|
|
220
|
+
annotations
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
accumulated: {
|
|
224
|
+
...accumulated,
|
|
225
|
+
annotations
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
case "signature_delta": return {
|
|
230
|
+
contentDelta: {
|
|
231
|
+
type: "block-delta",
|
|
232
|
+
fields: {
|
|
233
|
+
type: accumulated.type,
|
|
234
|
+
signature: delta.signature
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
accumulated: {
|
|
238
|
+
...accumulated,
|
|
239
|
+
signature: delta.signature
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
case "compaction_delta": return {
|
|
243
|
+
contentDelta: {
|
|
244
|
+
type: "block-delta",
|
|
245
|
+
fields: {
|
|
246
|
+
type: "non_standard",
|
|
247
|
+
value: {
|
|
248
|
+
...accumulated.value ?? {},
|
|
249
|
+
compaction: delta
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
accumulated: {
|
|
254
|
+
...accumulated,
|
|
255
|
+
value: {
|
|
256
|
+
...accumulated.value ?? {},
|
|
257
|
+
compaction: delta
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
default: return {
|
|
262
|
+
contentDelta: {
|
|
263
|
+
type: "block-delta",
|
|
264
|
+
fields: {
|
|
265
|
+
type: accumulated.type,
|
|
266
|
+
...delta
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
accumulated
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function finalizeBlock(accumulated) {
|
|
274
|
+
if (accumulated.type === "tool_call_chunk" || accumulated.type === "server_tool_call_chunk") {
|
|
275
|
+
const finalType = accumulated.type === "tool_call_chunk" ? "tool_call" : "server_tool_call";
|
|
276
|
+
let parsedArgs;
|
|
277
|
+
try {
|
|
278
|
+
parsedArgs = JSON.parse(accumulated.args || "{}");
|
|
279
|
+
} catch {
|
|
280
|
+
return {
|
|
281
|
+
type: "invalid_tool_call",
|
|
282
|
+
id: accumulated.id,
|
|
283
|
+
name: accumulated.name,
|
|
284
|
+
args: accumulated.args,
|
|
285
|
+
error: "Failed to parse tool call arguments as JSON"
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
type: finalType,
|
|
290
|
+
id: accumulated.id,
|
|
291
|
+
name: accumulated.name,
|
|
292
|
+
args: parsedArgs
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const { index: _index, ...rest } = accumulated;
|
|
296
|
+
return rest;
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
299
|
+
export { convertAnthropicStream };
|
|
300
|
+
|
|
301
|
+
//# sourceMappingURL=stream_events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream_events.js","names":[],"sources":["../../src/utils/stream_events.ts"],"sourcesContent":["/**\n * Converts a raw Anthropic SSE event stream into LangChain ChatModelStreamEvents.\n *\n * @module\n */\n\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport type {\n ChatModelStreamEvent,\n ContentBlockDelta,\n FinishReason,\n} from \"@langchain/core/language_models/event\";\nimport type { ContentBlock } from \"@langchain/core/messages/content\";\nimport type { UsageMetadata } from \"@langchain/core/messages/metadata\";\nimport type { AnthropicMessageStreamEvent } from \"../types.js\";\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<AnthropicMessageStreamEvent>,\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<\n number,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n Record<string, any>\n >();\n let usageSnapshot: UsageMetadata | 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 (usage && shouldStreamUsage) {\n usageSnapshot = buildUsageSnapshot(usage);\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 && data.usage) {\n if (!usageSnapshot) {\n usageSnapshot = {\n input_tokens: 0,\n output_tokens: data.usage.output_tokens,\n total_tokens: data.usage.output_tokens,\n };\n } else {\n usageSnapshot = {\n ...usageSnapshot,\n output_tokens:\n usageSnapshot.output_tokens + data.usage.output_tokens,\n total_tokens:\n usageSnapshot.input_tokens +\n usageSnapshot.output_tokens +\n data.usage.output_tokens,\n };\n }\n yield { event: \"usage\" as const, usage: usageSnapshot };\n }\n if (\n \"context_management\" in data.delta &&\n data.delta.context_management\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 yield {\n event: \"message-finish\" as const,\n reason: mapStopReason(stopReason),\n ...(usageSnapshot ? { usage: usageSnapshot } : {}),\n metadata: { model_provider: \"anthropic\" },\n };\n break;\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,\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 yield {\n event: \"provider\" as const,\n provider: \"anthropic\",\n name: data.type,\n payload: data,\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 return \"length\";\n default:\n return \"stop\";\n }\n}\n\nfunction buildUsageSnapshot(\n usage: Anthropic.Messages.Usage | Record<string, number>\n): UsageMetadata {\n const cacheCreation =\n (usage as Record<string, number>).cache_creation_input_tokens ?? 0;\n const cacheRead =\n (usage as Record<string, number>).cache_read_input_tokens ?? 0;\n const totalInput = usage.input_tokens + cacheCreation + cacheRead;\n return {\n input_tokens: totalInput,\n output_tokens: usage.output_tokens,\n total_tokens: totalInput + usage.output_tokens,\n input_token_details: {\n cache_creation: cacheCreation,\n cache_read: cacheRead,\n },\n };\n}\n\nfunction mapBlockToContentBlock(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n block: any,\n index: number\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, any> {\n switch (block.type) {\n case \"text\":\n return { type: \"text\" as const, text: block.text ?? \"\", index };\n case \"thinking\":\n return {\n type: \"reasoning\" as const,\n reasoning: block.thinking ?? \"\",\n index,\n };\n case \"redacted_thinking\":\n return { type: \"non_standard\" as const, value: { ...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 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 // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n accumulated: Record<string, any>,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n delta: any\n): {\n contentDelta: ContentBlockDelta;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n accumulated: Record<string, any>;\n} {\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: (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: (accumulated.reasoning ?? \"\") + delta.thinking,\n },\n };\n\n case \"input_json_delta\": {\n const newArgs = (accumulated.args ?? \"\") + delta.partial_json;\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: { type: accumulated.type, args: newArgs },\n },\n accumulated: { ...accumulated, args: newArgs },\n };\n }\n\n case \"citations_delta\": {\n const annotations = [...(accumulated.annotations ?? []), delta.citation];\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: {\n type: accumulated.type,\n annotations,\n },\n },\n accumulated: {\n ...accumulated,\n annotations,\n },\n };\n }\n\n case \"signature_delta\":\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: { type: accumulated.type, signature: delta.signature },\n },\n accumulated: { ...accumulated, signature: delta.signature },\n };\n\n case \"compaction_delta\":\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: {\n type: \"non_standard\",\n value: { ...(accumulated.value ?? {}), compaction: delta },\n },\n },\n accumulated: {\n ...accumulated,\n value: { ...(accumulated.value ?? {}), compaction: delta },\n },\n };\n\n default:\n return {\n contentDelta: {\n type: \"block-delta\" as const,\n fields: { type: accumulated.type, ...delta },\n },\n accumulated,\n };\n }\n}\n\nfunction finalizeBlock(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n accumulated: Record<string, any>\n): 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 let parsedArgs: unknown;\n try {\n parsedArgs = JSON.parse(accumulated.args || \"{}\");\n } catch {\n return {\n type: \"invalid_tool_call\" as const,\n id: accumulated.id,\n name: accumulated.name,\n args: accumulated.args,\n error: \"Failed to parse tool call arguments as JSON\",\n } as ContentBlock.Tools.InvalidToolCall;\n }\n return {\n type: finalType,\n id: accumulated.id,\n name: accumulated.name,\n args: parsedArgs,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n }\n\n const { index: _index, ...rest } = accumulated;\n return rest as ContentBlock;\n}\n"],"mappings":"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"}
|
package/dist/utils/tools.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
let zod_v4 = require("zod/v4");
|
|
3
|
-
zod_v4 = require_runtime.__toESM(zod_v4);
|
|
3
|
+
zod_v4 = require_runtime.__toESM(zod_v4, 1);
|
|
4
4
|
//#region src/utils/tools.ts
|
|
5
5
|
function handleToolChoice(toolChoice) {
|
|
6
6
|
if (!toolChoice) return;
|