llm-stream-assemble 1.4.0 → 1.5.0

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 (44) hide show
  1. package/README.md +47 -6
  2. package/dist/adapters/anthropic.cjs +181 -125
  3. package/dist/adapters/anthropic.cjs.map +1 -1
  4. package/dist/adapters/anthropic.d.cts +1 -3
  5. package/dist/adapters/anthropic.d.ts +1 -3
  6. package/dist/adapters/anthropic.js +181 -125
  7. package/dist/adapters/anthropic.js.map +1 -1
  8. package/dist/adapters/bedrock.cjs +155 -118
  9. package/dist/adapters/bedrock.cjs.map +1 -1
  10. package/dist/adapters/bedrock.js +155 -118
  11. package/dist/adapters/bedrock.js.map +1 -1
  12. package/dist/adapters/cohere.cjs +594 -0
  13. package/dist/adapters/cohere.cjs.map +1 -0
  14. package/dist/adapters/cohere.d.cts +9 -0
  15. package/dist/adapters/cohere.d.ts +9 -0
  16. package/dist/adapters/cohere.js +592 -0
  17. package/dist/adapters/cohere.js.map +1 -0
  18. package/dist/adapters/gemini.cjs +86 -44
  19. package/dist/adapters/gemini.cjs.map +1 -1
  20. package/dist/adapters/gemini.js +86 -44
  21. package/dist/adapters/gemini.js.map +1 -1
  22. package/dist/adapters/openai-chat.cjs +20 -8
  23. package/dist/adapters/openai-chat.cjs.map +1 -1
  24. package/dist/adapters/openai-chat.js +20 -8
  25. package/dist/adapters/openai-chat.js.map +1 -1
  26. package/dist/adapters/openai-compatible.cjs +20 -8
  27. package/dist/adapters/openai-compatible.cjs.map +1 -1
  28. package/dist/adapters/openai-compatible.js +20 -8
  29. package/dist/adapters/openai-compatible.js.map +1 -1
  30. package/dist/adapters/openai-responses.cjs +37 -27
  31. package/dist/adapters/openai-responses.cjs.map +1 -1
  32. package/dist/adapters/openai-responses.js +37 -27
  33. package/dist/adapters/openai-responses.js.map +1 -1
  34. package/dist/core/index.cjs +9 -2
  35. package/dist/core/index.cjs.map +1 -1
  36. package/dist/core/index.js +9 -2
  37. package/dist/core/index.js.map +1 -1
  38. package/dist/index.cjs +715 -297
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +2 -1
  41. package/dist/index.d.ts +2 -1
  42. package/dist/index.js +715 -298
  43. package/dist/index.js.map +1 -1
  44. package/package.json +9 -2
@@ -0,0 +1,592 @@
1
+ // src/core/utils/object.ts
2
+ function stripUndefined(obj) {
3
+ return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== void 0));
4
+ }
5
+
6
+ // src/adapters/utils.ts
7
+ function isRecord(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
10
+ function asString(value) {
11
+ return typeof value === "string" ? value : void 0;
12
+ }
13
+ function asNumber(value) {
14
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
15
+ }
16
+ function optionalRawChunk(input) {
17
+ return stripUndefined(input);
18
+ }
19
+ function prefixedAdapterError(feature, message) {
20
+ return adapterScopedError(feature, message);
21
+ }
22
+ function createStreamAdapter(config) {
23
+ return {
24
+ parseChunk(raw) {
25
+ return config.parser.parseChunk(raw);
26
+ },
27
+ parseResponse(body) {
28
+ return config.parseResponse(body, config.options);
29
+ }
30
+ };
31
+ }
32
+ function parseAdapterJSON(raw, feature) {
33
+ try {
34
+ return JSON.parse(raw);
35
+ } catch (error) {
36
+ const message = error instanceof Error ? error.message : String(error);
37
+ throw prefixedAdapterError(feature, message);
38
+ }
39
+ }
40
+
41
+ // src/adapters/errors.ts
42
+ function libraryError(message) {
43
+ return new Error(`llm-stream-assemble: ${message}`);
44
+ }
45
+ function adapterScopedError(scope, message) {
46
+ return new Error(`llm-stream-assemble: ${scope}: ${message}`);
47
+ }
48
+ function providerErrorChunks(error, recoverable = false) {
49
+ return [
50
+ { kind: "provider-error", error, recoverable },
51
+ { kind: "finish", reason: "error" }
52
+ ];
53
+ }
54
+ function providerErrorChunksFromPayload(errorPayload, scope, recoverable, fallbackMessage) {
55
+ const message = asString(errorPayload.message) ?? fallbackMessage;
56
+ const error = adapterScopedError(scope, message);
57
+ Object.defineProperty(error, "raw", {
58
+ value: errorPayload,
59
+ enumerable: false
60
+ });
61
+ return providerErrorChunks(error, recoverable);
62
+ }
63
+
64
+ // src/adapters/shared/incremental-json.ts
65
+ function incrementalJsonStringDelta(state, nextInput) {
66
+ const prev = state.lastArgsJson;
67
+ if (nextInput === prev) return void 0;
68
+ const delta = prev.length > 0 && nextInput.startsWith(prev) ? nextInput.slice(prev.length) : nextInput;
69
+ state.lastArgsJson = nextInput;
70
+ return delta.length > 0 ? delta : void 0;
71
+ }
72
+
73
+ // src/adapters/shared/parse-payload.ts
74
+ function parseAdapterObjectPayload(raw, scope, options = {}) {
75
+ const { trim = true, allowDone = true } = options;
76
+ const input = trim ? raw.trim() : raw;
77
+ if (input.length === 0 || allowDone && input === "[DONE]") return null;
78
+ const payload = parseAdapterJSON(input, scope);
79
+ if (!isRecord(payload)) {
80
+ throw adapterScopedError(scope, "expected a JSON object");
81
+ }
82
+ return payload;
83
+ }
84
+
85
+ // src/adapters/shared/text-delta.ts
86
+ function textOrJsonDelta(text, options) {
87
+ if (text.length === 0) return void 0;
88
+ if (options.jsonMode) return { kind: "json-delta", delta: text };
89
+ if (options.choiceIndex !== void 0) {
90
+ return { kind: "text-delta", text, choiceIndex: options.choiceIndex };
91
+ }
92
+ return { kind: "text-delta", text };
93
+ }
94
+
95
+ // src/adapters/shared/usage.ts
96
+ var DEFAULT_ALIASES = {
97
+ input: ["inputTokens", "input_tokens", "promptTokens", "promptTokenCount", "inputTokenCount"],
98
+ output: [
99
+ "outputTokens",
100
+ "output_tokens",
101
+ "completionTokens",
102
+ "candidatesTokenCount",
103
+ "outputTokenCount"
104
+ ],
105
+ reasoning: ["reasoningTokens", "reasoning_tokens", "thoughtsTokenCount"],
106
+ total: ["totalTokens", "totalTokenCount", "total_tokens"]
107
+ };
108
+ function firstNumber(value, fields) {
109
+ if (!fields) return void 0;
110
+ for (const field of fields) {
111
+ const number = asNumber(value[field]);
112
+ if (number !== void 0) return number;
113
+ }
114
+ return void 0;
115
+ }
116
+ function buildUsageChunk(value, aliases = DEFAULT_ALIASES, options) {
117
+ if (!isRecord(value)) return void 0;
118
+ const inputTokens = firstNumber(value, aliases.input);
119
+ const outputTokens = firstNumber(value, aliases.output);
120
+ const reasoningTokens = firstNumber(value, aliases.reasoning);
121
+ const totalTokens = firstNumber(value, aliases.total);
122
+ if (inputTokens === void 0 && outputTokens === void 0 && reasoningTokens === void 0 && totalTokens === void 0) {
123
+ return void 0;
124
+ }
125
+ const raw = value;
126
+ return optionalRawChunk({
127
+ kind: "usage",
128
+ inputTokens,
129
+ outputTokens,
130
+ reasoningTokens,
131
+ raw
132
+ });
133
+ }
134
+
135
+ // src/adapters/cohere.ts
136
+ var COHERE_USAGE_ALIASES = {
137
+ input: ["input_tokens", "inputTokens"],
138
+ output: ["output_tokens", "outputTokens"],
139
+ total: ["total_tokens", "totalTokens"]
140
+ };
141
+ function cohereAdapter(options = {}) {
142
+ const parser = new CohereStreamParser(options);
143
+ return createStreamAdapter({
144
+ parser,
145
+ parseResponse,
146
+ options
147
+ });
148
+ }
149
+ var CohereStreamParser = class {
150
+ constructor(options) {
151
+ this.options = options;
152
+ }
153
+ options;
154
+ messageStarted = false;
155
+ metadataEmitted = false;
156
+ toolsByKey = /* @__PURE__ */ new Map();
157
+ indexToKey = /* @__PURE__ */ new Map();
158
+ parseChunk(raw) {
159
+ const payload = parseAdapterObjectPayload(raw, "cohereAdapter.parseChunk");
160
+ if (!payload) return [];
161
+ if (asString(payload.type) === "error" || isRecord(payload.error)) {
162
+ const errorBody = isRecord(payload.error) ? payload.error : payload;
163
+ return providerErrorChunksFromPayload(
164
+ errorBody,
165
+ "cohereAdapter.parseChunk",
166
+ false,
167
+ "Cohere provider error"
168
+ );
169
+ }
170
+ const eventType = asString(payload.type);
171
+ if (!eventType) return optionalMetadataRaw(payload);
172
+ switch (eventType) {
173
+ case "message-start":
174
+ return this.messageStartChunks(payload);
175
+ case "content-start":
176
+ case "content-end":
177
+ return [];
178
+ case "content-delta":
179
+ return this.contentDeltaChunks(payload);
180
+ case "tool-plan-delta":
181
+ return this.toolPlanDeltaChunks(payload);
182
+ case "tool-call-start":
183
+ return this.toolCallStartChunks(payload);
184
+ case "tool-call-delta":
185
+ return this.toolCallDeltaChunks(payload);
186
+ case "tool-call-end":
187
+ return this.toolCallEndChunks(payload);
188
+ case "citation-start":
189
+ return this.citationStartChunks(payload);
190
+ case "citation-end":
191
+ return [];
192
+ case "message-end":
193
+ return this.messageEndChunks(payload);
194
+ default:
195
+ return optionalMetadataRaw(payload);
196
+ }
197
+ }
198
+ messageStartChunks(payload) {
199
+ if (this.messageStarted) return [];
200
+ this.messageStarted = true;
201
+ const chunks = [{ kind: "message-start" }];
202
+ const messageId = asString(payload.id);
203
+ const delta = isRecord(payload.delta) ? payload.delta : void 0;
204
+ const message = delta && isRecord(delta.message) ? delta.message : void 0;
205
+ const role = message ? asString(message.role) : void 0;
206
+ if (messageId || role) {
207
+ this.metadataEmitted = true;
208
+ chunks.push(
209
+ optionalRawChunk({
210
+ kind: "metadata",
211
+ responseId: messageId,
212
+ raw: { id: messageId, role }
213
+ })
214
+ );
215
+ }
216
+ return chunks;
217
+ }
218
+ contentDeltaChunks(payload) {
219
+ const delta = isRecord(payload.delta) ? payload.delta : void 0;
220
+ const message = delta && isRecord(delta.message) ? delta.message : void 0;
221
+ const content = message && isRecord(message.content) ? message.content : void 0;
222
+ const text = content ? asString(content.text) : void 0;
223
+ if (text === void 0 || text.length === 0) return [];
224
+ const textChunk = textOrJsonDelta(text, {
225
+ jsonMode: this.options.jsonMode,
226
+ choiceIndex: asNumber(payload.index) ?? 0
227
+ });
228
+ return textChunk ? [textChunk] : [];
229
+ }
230
+ toolPlanDeltaChunks(payload) {
231
+ const delta = isRecord(payload.delta) ? payload.delta : void 0;
232
+ const message = delta && isRecord(delta.message) ? delta.message : void 0;
233
+ const toolPlan = message ? asString(message.tool_plan) : asString(delta?.tool_plan);
234
+ if (toolPlan === void 0 || toolPlan.length === 0) return [];
235
+ return [{ kind: "reasoning-delta", text: toolPlan, variant: "detail" }];
236
+ }
237
+ toolCallStartChunks(payload) {
238
+ const baseIndex = asNumber(payload.index) ?? 0;
239
+ const toolCalls = toolCallsFromDelta(payload.delta);
240
+ if (toolCalls.length === 0) return [];
241
+ const chunks = [];
242
+ for (let i = 0; i < toolCalls.length; i += 1) {
243
+ const toolCall = toolCalls[i];
244
+ const index = asNumber(toolCall.index) ?? baseIndex + i;
245
+ const id = asString(toolCall.id) ?? `cohere:tool:${index}`;
246
+ const fn = isRecord(toolCall.function) ? toolCall.function : void 0;
247
+ const name = fn ? asString(fn.name) ?? "unknown" : "unknown";
248
+ const key = reconcileToolKey(this.toolsByKey, this.indexToKey, index, id);
249
+ const existing = this.toolsByKey.get(key);
250
+ if (existing?.open && existing.id === id) continue;
251
+ const state = {
252
+ id,
253
+ name,
254
+ index,
255
+ open: true,
256
+ lastArgsJson: asString(fn?.arguments) ?? ""
257
+ };
258
+ this.toolsByKey.set(key, state);
259
+ this.indexToKey.set(index, key);
260
+ if (id !== key) this.toolsByKey.set(id, state);
261
+ chunks.push(
262
+ optionalRawChunk({
263
+ kind: "tool-start",
264
+ id,
265
+ name,
266
+ index,
267
+ choiceIndex: 0
268
+ })
269
+ );
270
+ }
271
+ return chunks;
272
+ }
273
+ toolCallDeltaChunks(payload) {
274
+ const index = asNumber(payload.index) ?? 0;
275
+ const toolCalls = toolCallsFromDelta(payload.delta);
276
+ if (toolCalls.length === 0) return [];
277
+ const chunks = [];
278
+ for (const toolCall of toolCalls) {
279
+ const lateId = asString(toolCall.id);
280
+ const key = this.resolveToolKey(index, lateId);
281
+ let state = key ? this.toolsByKey.get(key) : void 0;
282
+ if (!state) {
283
+ const fn2 = isRecord(toolCall.function) ? toolCall.function : void 0;
284
+ const name = fn2 ? asString(fn2.name) ?? "unknown" : "unknown";
285
+ const id = lateId ?? `cohere:tool:${index}`;
286
+ state = { id, name, index, open: true, lastArgsJson: "" };
287
+ this.toolsByKey.set(id, state);
288
+ this.indexToKey.set(index, id);
289
+ chunks.push(
290
+ optionalRawChunk({
291
+ kind: "tool-start",
292
+ id,
293
+ name,
294
+ index,
295
+ choiceIndex: 0
296
+ })
297
+ );
298
+ } else if (lateId && state.id !== lateId) {
299
+ this.reconcileLateId(state, lateId, index);
300
+ }
301
+ const fn = isRecord(toolCall.function) ? toolCall.function : void 0;
302
+ const argsText = fn ? asString(fn.arguments) : void 0;
303
+ if (argsText !== void 0 && argsText.length > 0 && state) {
304
+ const delta = incrementalJsonStringDelta(state, argsText);
305
+ if (delta) {
306
+ chunks.push(
307
+ optionalRawChunk({
308
+ kind: "tool-args-delta",
309
+ id: state.id,
310
+ delta,
311
+ index: state.index,
312
+ choiceIndex: 0
313
+ })
314
+ );
315
+ }
316
+ }
317
+ }
318
+ return chunks;
319
+ }
320
+ toolCallEndChunks(payload) {
321
+ const index = asNumber(payload.index) ?? 0;
322
+ const delta = isRecord(payload.delta) ? payload.delta : void 0;
323
+ const message = delta && isRecord(delta.message) ? delta.message : void 0;
324
+ const toolCalls = message ? toolCallsFromRecord(message.tool_calls) : [];
325
+ const lateId = toolCalls[0] ? asString(toolCalls[0].id) : void 0;
326
+ const key = this.resolveToolKey(index, lateId);
327
+ const state = key ? this.toolsByKey.get(key) : void 0;
328
+ if (!state?.open) return [];
329
+ if (lateId && state.id !== lateId) {
330
+ this.reconcileLateId(state, lateId, index);
331
+ }
332
+ state.open = false;
333
+ return [
334
+ optionalRawChunk({
335
+ kind: "tool-done",
336
+ id: state.id,
337
+ index: state.index,
338
+ choiceIndex: 0
339
+ })
340
+ ];
341
+ }
342
+ citationStartChunks(payload) {
343
+ const delta = isRecord(payload.delta) ? payload.delta : void 0;
344
+ const message = delta && isRecord(delta.message) ? delta.message : void 0;
345
+ const citations = message?.citations;
346
+ return [
347
+ optionalRawChunk({
348
+ kind: "metadata",
349
+ raw: { citation: citations, index: payload.index }
350
+ })
351
+ ];
352
+ }
353
+ messageEndChunks(payload) {
354
+ const delta = isRecord(payload.delta) ? payload.delta : void 0;
355
+ const chunks = [];
356
+ const usageSource = delta && isRecord(delta.usage) ? usageFromCohereUsage(delta.usage) : delta && isRecord(delta.billed_units) ? delta.billed_units : void 0;
357
+ const usage = buildUsageChunk(usageSource, COHERE_USAGE_ALIASES);
358
+ if (usage) chunks.push(usage);
359
+ const finishReason = delta ? asString(delta.finish_reason) : void 0;
360
+ if (finishReason) {
361
+ chunks.push(
362
+ optionalRawChunk({
363
+ kind: "metadata",
364
+ raw: { finish_reason: finishReason }
365
+ })
366
+ );
367
+ chunks.push({
368
+ kind: "finish",
369
+ reason: mapCohereFinishReason(finishReason),
370
+ choiceIndex: 0
371
+ });
372
+ }
373
+ return chunks;
374
+ }
375
+ resolveToolKey(index, id) {
376
+ if (id && this.toolsByKey.has(id)) return id;
377
+ const byIndex = this.indexToKey.get(index);
378
+ if (byIndex) return byIndex;
379
+ if (id) return id;
380
+ return this.indexToKey.get(index);
381
+ }
382
+ reconcileLateId(state, lateId, index) {
383
+ const oldKey = state.id;
384
+ state.id = lateId;
385
+ this.toolsByKey.delete(oldKey);
386
+ this.toolsByKey.set(lateId, state);
387
+ this.indexToKey.set(index, lateId);
388
+ }
389
+ };
390
+ function parseResponse(body, options) {
391
+ if (!isRecord(body)) {
392
+ throw libraryError("cohereAdapter.parseResponse expected a Cohere Chat v2 response object");
393
+ }
394
+ if (asString(body.type) === "error" || isRecord(body.error)) {
395
+ const errorBody = isRecord(body.error) ? body.error : body;
396
+ return providerErrorChunksFromPayload(
397
+ errorBody,
398
+ "cohereAdapter.parseResponse",
399
+ false,
400
+ "Cohere provider error"
401
+ );
402
+ }
403
+ const message = isRecord(body.message) ? body.message : void 0;
404
+ if (!message) {
405
+ const chunks2 = [];
406
+ const usage = buildUsageChunk(body.usage, COHERE_USAGE_ALIASES);
407
+ if (usage) chunks2.push(usage);
408
+ const finishReason2 = asString(body.finish_reason);
409
+ if (finishReason2) {
410
+ chunks2.push({
411
+ kind: "finish",
412
+ reason: mapCohereFinishReason(finishReason2),
413
+ choiceIndex: 0
414
+ });
415
+ } else {
416
+ chunks2.push({ kind: "finish", reason: "stop", choiceIndex: 0 });
417
+ }
418
+ return chunks2;
419
+ }
420
+ const parser = new CohereStreamParser(options);
421
+ const syntheticEvents = synthesizeCohereStreamEvents(body);
422
+ const chunks = [];
423
+ for (const event of syntheticEvents) {
424
+ chunks.push(...parser.parseChunk(JSON.stringify(event)));
425
+ }
426
+ const finishReason = asString(body.finish_reason);
427
+ if (finishReason && !chunks.some((chunk) => chunk.kind === "finish")) {
428
+ chunks.push({
429
+ kind: "finish",
430
+ reason: mapCohereFinishReason(finishReason),
431
+ choiceIndex: 0
432
+ });
433
+ } else if (!chunks.some((chunk) => chunk.kind === "finish")) {
434
+ chunks.push({ kind: "finish", reason: "stop", choiceIndex: 0 });
435
+ }
436
+ return chunks;
437
+ }
438
+ function synthesizeCohereStreamEvents(body) {
439
+ const events = [];
440
+ const message = isRecord(body.message) ? body.message : void 0;
441
+ if (!message) return events;
442
+ const messageId = asString(body.id);
443
+ events.push({
444
+ type: "message-start",
445
+ ...messageId ? { id: messageId } : {},
446
+ delta: { message: { role: asString(message.role) ?? "assistant" } }
447
+ });
448
+ const toolPlan = asString(message.tool_plan);
449
+ if (toolPlan) {
450
+ events.push({
451
+ type: "tool-plan-delta",
452
+ delta: { message: { tool_plan: toolPlan } }
453
+ });
454
+ }
455
+ const content = Array.isArray(message.content) ? message.content : [];
456
+ for (const block of content) {
457
+ if (!isRecord(block)) continue;
458
+ const text = asString(block.text);
459
+ if (text !== void 0 && text.length > 0) {
460
+ events.push({
461
+ type: "content-delta",
462
+ index: 0,
463
+ delta: { message: { content: { text } } }
464
+ });
465
+ }
466
+ }
467
+ const citations = message.citations;
468
+ if (Array.isArray(citations)) {
469
+ for (const citation of citations) {
470
+ events.push({
471
+ type: "citation-start",
472
+ index: 0,
473
+ delta: { message: { citations: citation } }
474
+ });
475
+ }
476
+ }
477
+ const toolCalls = toolCallsFromRecord(message.tool_calls);
478
+ let toolIndex = 0;
479
+ for (const toolCall of toolCalls) {
480
+ const id = asString(toolCall.id) ?? `cohere:tool:${toolIndex}`;
481
+ const fn = isRecord(toolCall.function) ? toolCall.function : void 0;
482
+ const name = fn ? asString(fn.name) ?? "unknown" : "unknown";
483
+ const args = fn ? asString(fn.arguments) : void 0;
484
+ events.push({
485
+ type: "tool-call-start",
486
+ index: toolIndex,
487
+ delta: {
488
+ message: {
489
+ tool_calls: {
490
+ id,
491
+ type: "function",
492
+ function: { name, arguments: args ?? "" }
493
+ }
494
+ }
495
+ }
496
+ });
497
+ if (args !== void 0 && args.length > 0) {
498
+ events.push({
499
+ type: "tool-call-delta",
500
+ index: toolIndex,
501
+ delta: {
502
+ message: {
503
+ tool_calls: {
504
+ id,
505
+ function: { arguments: args }
506
+ }
507
+ }
508
+ }
509
+ });
510
+ }
511
+ events.push({ type: "tool-call-end", index: toolIndex });
512
+ toolIndex += 1;
513
+ }
514
+ if (body.usage !== void 0 || body.finish_reason !== void 0) {
515
+ events.push({
516
+ type: "message-end",
517
+ delta: {
518
+ ...body.finish_reason !== void 0 ? { finish_reason: body.finish_reason } : {},
519
+ ...body.usage !== void 0 ? { usage: body.usage } : {}
520
+ }
521
+ });
522
+ }
523
+ return events;
524
+ }
525
+ function toolCallsFromDelta(delta) {
526
+ if (!isRecord(delta)) return [];
527
+ const message = isRecord(delta.message) ? delta.message : void 0;
528
+ return toolCallsFromRecord(message?.tool_calls);
529
+ }
530
+ function toolCallsFromRecord(value) {
531
+ if (value === void 0) return [];
532
+ if (Array.isArray(value)) {
533
+ return value.filter((item) => isRecord(item));
534
+ }
535
+ if (isRecord(value)) return [value];
536
+ return [];
537
+ }
538
+ function usageFromCohereUsage(usage) {
539
+ const billed = isRecord(usage.billed_units) ? usage.billed_units : void 0;
540
+ if (billed) return billed;
541
+ const tokens = isRecord(usage.tokens) ? usage.tokens : void 0;
542
+ if (tokens) return tokens;
543
+ return usage;
544
+ }
545
+ function reconcileToolKey(toolsByKey, indexToKey, index, id) {
546
+ const existingIndexKey = indexToKey.get(index);
547
+ if (existingIndexKey && toolsByKey.has(existingIndexKey)) {
548
+ const state = toolsByKey.get(existingIndexKey);
549
+ if (state && state.id.startsWith("cohere:tool:") && !id.startsWith("cohere:tool:")) {
550
+ toolsByKey.delete(existingIndexKey);
551
+ state.id = id;
552
+ toolsByKey.set(id, state);
553
+ indexToKey.set(index, id);
554
+ return id;
555
+ }
556
+ return existingIndexKey;
557
+ }
558
+ return id;
559
+ }
560
+ function mapCohereFinishReason(value) {
561
+ const normalized = value.toUpperCase();
562
+ switch (normalized) {
563
+ case "COMPLETE":
564
+ case "STOP_SEQUENCE":
565
+ return "stop";
566
+ case "MAX_TOKENS":
567
+ return "length";
568
+ case "TOOL_CALL":
569
+ return "tool_calls";
570
+ case "ERROR":
571
+ case "TIMEOUT":
572
+ return "error";
573
+ default:
574
+ if (normalized.includes("FILTER") || normalized.includes("SAFETY")) {
575
+ return "content_filter";
576
+ }
577
+ return "stop";
578
+ }
579
+ }
580
+ function optionalMetadataRaw(payload) {
581
+ if (Object.keys(payload).length === 0) return [];
582
+ return [
583
+ optionalRawChunk({
584
+ kind: "metadata",
585
+ raw: payload
586
+ })
587
+ ];
588
+ }
589
+
590
+ export { cohereAdapter };
591
+ //# sourceMappingURL=cohere.js.map
592
+ //# sourceMappingURL=cohere.js.map