llm-stream-assemble 1.0.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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +390 -0
  3. package/dist/adapters/anthropic.cjs +312 -0
  4. package/dist/adapters/anthropic.cjs.map +1 -0
  5. package/dist/adapters/anthropic.d.cts +11 -0
  6. package/dist/adapters/anthropic.d.ts +11 -0
  7. package/dist/adapters/anthropic.js +310 -0
  8. package/dist/adapters/anthropic.js.map +1 -0
  9. package/dist/adapters/openai-chat.cjs +499 -0
  10. package/dist/adapters/openai-chat.cjs.map +1 -0
  11. package/dist/adapters/openai-chat.d.cts +9 -0
  12. package/dist/adapters/openai-chat.d.ts +9 -0
  13. package/dist/adapters/openai-chat.js +497 -0
  14. package/dist/adapters/openai-chat.js.map +1 -0
  15. package/dist/adapters/openai-compatible.cjs +519 -0
  16. package/dist/adapters/openai-compatible.cjs.map +1 -0
  17. package/dist/adapters/openai-compatible.d.cts +15 -0
  18. package/dist/adapters/openai-compatible.d.ts +15 -0
  19. package/dist/adapters/openai-compatible.js +517 -0
  20. package/dist/adapters/openai-compatible.js.map +1 -0
  21. package/dist/adapters/openai-responses.cjs +444 -0
  22. package/dist/adapters/openai-responses.cjs.map +1 -0
  23. package/dist/adapters/openai-responses.d.cts +8 -0
  24. package/dist/adapters/openai-responses.d.ts +8 -0
  25. package/dist/adapters/openai-responses.js +442 -0
  26. package/dist/adapters/openai-responses.js.map +1 -0
  27. package/dist/core/index.cjs +816 -0
  28. package/dist/core/index.cjs.map +1 -0
  29. package/dist/core/index.d.cts +18 -0
  30. package/dist/core/index.d.ts +18 -0
  31. package/dist/core/index.js +808 -0
  32. package/dist/core/index.js.map +1 -0
  33. package/dist/index.cjs +2238 -0
  34. package/dist/index.cjs.map +1 -0
  35. package/dist/index.d.cts +66 -0
  36. package/dist/index.d.ts +66 -0
  37. package/dist/index.js +2206 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/types-CskRfrmD.d.cts +176 -0
  40. package/dist/types-CskRfrmD.d.ts +176 -0
  41. package/package.json +95 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,2238 @@
1
+ 'use strict';
2
+
3
+ // src/core/utils/bytes.ts
4
+ var Utf8StreamDecoder = class {
5
+ decoder = new TextDecoder();
6
+ decode(chunk) {
7
+ return this.decoder.decode(chunk, { stream: true });
8
+ }
9
+ flush() {
10
+ return this.decoder.decode();
11
+ }
12
+ };
13
+ var encoder = new TextEncoder();
14
+ function utf8ByteLength(value) {
15
+ return encoder.encode(value).byteLength;
16
+ }
17
+
18
+ // src/core/utils/source.ts
19
+ async function* readableStreamToStrings(source) {
20
+ const reader = source.getReader();
21
+ const decoder = new Utf8StreamDecoder();
22
+ let completed = false;
23
+ try {
24
+ while (true) {
25
+ const { done, value } = await reader.read();
26
+ if (done) {
27
+ completed = true;
28
+ break;
29
+ }
30
+ const decoded = decoder.decode(value);
31
+ if (decoded.length > 0) {
32
+ yield decoded;
33
+ }
34
+ }
35
+ const flushed = decoder.flush();
36
+ if (flushed.length > 0) {
37
+ yield flushed;
38
+ }
39
+ } finally {
40
+ if (!completed) {
41
+ await reader.cancel().catch(() => void 0);
42
+ }
43
+ reader.releaseLock();
44
+ }
45
+ }
46
+ function isReadableStream(source) {
47
+ return typeof source.getReader === "function";
48
+ }
49
+ function sourceToStrings(source) {
50
+ return isReadableStream(source) ? readableStreamToStrings(source) : source;
51
+ }
52
+ function errorFromUnknown(error) {
53
+ return error instanceof Error ? error : new Error(String(error));
54
+ }
55
+ function prefixedError(message) {
56
+ return new Error(`llm-stream-assemble: ${message}`);
57
+ }
58
+
59
+ // src/core/assembly/process-payload.ts
60
+ function isDoneMarker(payload) {
61
+ return payload.trim() === "[DONE]";
62
+ }
63
+ function processPayload(payload, assembler, adapter, options) {
64
+ if (isDoneMarker(payload)) {
65
+ return { kind: "done-marker" };
66
+ }
67
+ let chunks;
68
+ try {
69
+ chunks = adapter.parseChunk(payload);
70
+ } catch (error) {
71
+ if (!options.recoverMalformed) {
72
+ throw error;
73
+ }
74
+ return {
75
+ kind: "recoverable-error",
76
+ event: {
77
+ type: "error",
78
+ error: prefixedError(errorFromUnknown(error).message),
79
+ recoverable: true
80
+ }
81
+ };
82
+ }
83
+ const events = [];
84
+ for (const chunk of chunks) {
85
+ events.push(...assembler.push(chunk));
86
+ }
87
+ return { kind: "events", events };
88
+ }
89
+ function resolveTerminalFlush(assembler, state) {
90
+ if (state.aborted) {
91
+ return assembler.flush({ terminalReason: "aborted" });
92
+ }
93
+ if (state.sawTerminalMarker) {
94
+ return assembler.flush({ terminalReason: "stop" });
95
+ }
96
+ if (assembler.hasFinished()) {
97
+ return assembler.flush();
98
+ }
99
+ return assembler.flush({ terminalReason: "incomplete" });
100
+ }
101
+
102
+ // src/core/parse-partial-json.ts
103
+ function parsePartialJSON(input) {
104
+ const trimmed = input.trim();
105
+ if (trimmed.length === 0) {
106
+ return { complete: false };
107
+ }
108
+ const complete = parseComplete(trimmed);
109
+ if (complete.ok) {
110
+ return { complete: true, value: complete.value };
111
+ }
112
+ const end = findFirstCompleteValueEnd(trimmed);
113
+ if (end !== void 0) {
114
+ const parsed = parseComplete(trimmed.slice(0, end));
115
+ if (parsed.ok) {
116
+ return { complete: false, value: parsed.value };
117
+ }
118
+ }
119
+ for (const candidate of repairedCandidates(trimmed)) {
120
+ const parsed = parseComplete(candidate);
121
+ if (parsed.ok) {
122
+ return { complete: false, value: parsed.value };
123
+ }
124
+ }
125
+ return { complete: false };
126
+ }
127
+ function parseComplete(input) {
128
+ try {
129
+ return { ok: true, value: JSON.parse(input) };
130
+ } catch {
131
+ return { ok: false };
132
+ }
133
+ }
134
+ function findFirstCompleteValueEnd(input) {
135
+ let inString = false;
136
+ let escaped = false;
137
+ const stack = [];
138
+ for (let index = 0; index < input.length; index += 1) {
139
+ const char = input[index];
140
+ if (inString) {
141
+ if (escaped) {
142
+ escaped = false;
143
+ } else if (char === "\\") {
144
+ escaped = true;
145
+ } else if (char === '"') {
146
+ inString = false;
147
+ if (stack.length === 0) {
148
+ return index + 1;
149
+ }
150
+ }
151
+ continue;
152
+ }
153
+ if (char === '"') {
154
+ inString = true;
155
+ } else if (char === "{" || char === "[") {
156
+ stack.push(char === "{" ? "}" : "]");
157
+ } else if (char === "}" || char === "]") {
158
+ if (stack.pop() !== char) return void 0;
159
+ if (stack.length === 0) {
160
+ return index + 1;
161
+ }
162
+ } else if (stack.length === 0 && isPrimitiveTerminator(input, index)) {
163
+ return index;
164
+ }
165
+ }
166
+ return void 0;
167
+ }
168
+ function isPrimitiveTerminator(input, index) {
169
+ if (!/[\s,}\]]/.test(input[index] ?? "")) return false;
170
+ const prefix = input.slice(0, index).trim();
171
+ if (prefix.length === 0) return false;
172
+ return parseComplete(prefix).ok;
173
+ }
174
+ function repairedCandidates(input) {
175
+ const candidates = /* @__PURE__ */ new Set();
176
+ const base = closeContainers(closeOpenString(input));
177
+ candidates.add(base);
178
+ for (const trimmed of trimDanglingValues(input)) {
179
+ candidates.add(closeContainers(closeOpenString(trimmed)));
180
+ }
181
+ return [...candidates];
182
+ }
183
+ function closeOpenString(input) {
184
+ let inString = false;
185
+ let escaped = false;
186
+ for (const char of input) {
187
+ if (inString) {
188
+ if (escaped) {
189
+ escaped = false;
190
+ } else if (char === "\\") {
191
+ escaped = true;
192
+ } else if (char === '"') {
193
+ inString = false;
194
+ }
195
+ } else if (char === '"') {
196
+ inString = true;
197
+ }
198
+ }
199
+ if (!inString) return input;
200
+ return escaped ? `${input.slice(0, -1)}"` : `${input}"`;
201
+ }
202
+ function closeContainers(input) {
203
+ const stack = [];
204
+ let inString = false;
205
+ let escaped = false;
206
+ for (const char of input) {
207
+ if (inString) {
208
+ if (escaped) {
209
+ escaped = false;
210
+ } else if (char === "\\") {
211
+ escaped = true;
212
+ } else if (char === '"') {
213
+ inString = false;
214
+ }
215
+ continue;
216
+ }
217
+ if (char === '"') {
218
+ inString = true;
219
+ } else if (char === "{" || char === "[") {
220
+ stack.push(char === "{" ? "}" : "]");
221
+ } else if ((char === "}" || char === "]") && stack.at(-1) === char) {
222
+ stack.pop();
223
+ }
224
+ }
225
+ return `${input}${stack.reverse().join("")}`;
226
+ }
227
+ function trimDanglingValues(input) {
228
+ const variants = [];
229
+ let current = input.trimEnd();
230
+ while (current.length > 0) {
231
+ const last = current.at(-1);
232
+ if (last === "," || last === ":") {
233
+ current = current.slice(0, -1).trimEnd();
234
+ variants.push(current);
235
+ continue;
236
+ }
237
+ const colon = lastTopLevelToken(current, ":");
238
+ const comma = lastTopLevelToken(current, ",");
239
+ const openObject = lastTopLevelToken(current, "{");
240
+ const cutAt = Math.max(colon, comma, openObject);
241
+ if (cutAt === -1) break;
242
+ current = current.slice(0, cutAt + (current[cutAt] === "{" ? 1 : 0)).trimEnd();
243
+ variants.push(current);
244
+ break;
245
+ }
246
+ return variants;
247
+ }
248
+ function lastTopLevelToken(input, token) {
249
+ let inString = false;
250
+ let escaped = false;
251
+ let depth = 0;
252
+ for (let index = input.length - 1; index >= 0; index -= 1) {
253
+ const char = input[index];
254
+ if (inString) {
255
+ if (char === "\\" && !escaped) {
256
+ escaped = true;
257
+ } else if (char === '"' && !escaped) {
258
+ inString = false;
259
+ } else {
260
+ escaped = false;
261
+ }
262
+ continue;
263
+ }
264
+ if (char === '"') {
265
+ inString = true;
266
+ } else if (char === "}" || char === "]") {
267
+ depth += 1;
268
+ } else if (char === "{" || char === "[") {
269
+ if (depth === 0 && char === token) return index;
270
+ depth -= 1;
271
+ } else if (depth === 0 && char === token) {
272
+ return index;
273
+ }
274
+ }
275
+ return -1;
276
+ }
277
+
278
+ // src/core/assembler/event-assembler.ts
279
+ var EventAssembler = class {
280
+ constructor(options = {}) {
281
+ this.options = options;
282
+ }
283
+ options;
284
+ text = /* @__PURE__ */ new Map();
285
+ reasoning = "";
286
+ reasoningVariant;
287
+ refusal = "";
288
+ json = "";
289
+ tools = /* @__PURE__ */ new Map();
290
+ toolByIndex = /* @__PURE__ */ new Map();
291
+ finishEmitted = false;
292
+ push(chunk) {
293
+ if (this.finishEmitted) return [];
294
+ switch (chunk.kind) {
295
+ case "message-start":
296
+ return [
297
+ optionalEvent({ type: "message.start", id: chunk.id, choiceIndex: chunk.choiceIndex })
298
+ ];
299
+ case "text-delta":
300
+ return this.pushText(chunk.text, chunk.choiceIndex);
301
+ case "reasoning-delta":
302
+ return this.pushReasoning(chunk.text, chunk.variant);
303
+ case "refusal-delta":
304
+ return this.pushRefusal(chunk.text);
305
+ case "json-delta":
306
+ return this.pushJson(chunk.delta);
307
+ case "tool-start":
308
+ return this.pushToolStart(chunk);
309
+ case "tool-args-delta":
310
+ return this.pushToolArgs(chunk);
311
+ case "tool-done":
312
+ return this.finishTool(chunk);
313
+ case "metadata": {
314
+ const { kind: _kind, ...metadata } = chunk;
315
+ return [optionalEvent({ type: "metadata", ...metadata })];
316
+ }
317
+ case "usage": {
318
+ const { kind: _kind, ...usage } = chunk;
319
+ return [optionalEvent({ type: "usage", ...usage })];
320
+ }
321
+ case "finish":
322
+ return chunk.choiceIndex === void 0 ? this.flush({ terminalReason: chunk.reason }) : this.flush({ terminalReason: chunk.reason, choiceIndex: chunk.choiceIndex });
323
+ case "provider-error":
324
+ return [this.errorEvent(chunk.error, chunk.recoverable)];
325
+ }
326
+ }
327
+ flush(options = {}) {
328
+ const events = [];
329
+ events.push(...this.flushText());
330
+ events.push(...this.flushReasoning());
331
+ events.push(...this.flushRefusal());
332
+ events.push(...this.flushJson());
333
+ events.push(...this.flushTools());
334
+ const forcedError = events.some(
335
+ (event) => event.type === "error" && event.recoverable === false
336
+ );
337
+ const reason = forcedError ? "error" : options.terminalReason;
338
+ if (reason && !this.finishEmitted) {
339
+ events.push(optionalEvent({ type: "finish", reason, choiceIndex: options.choiceIndex }));
340
+ this.finishEmitted = true;
341
+ }
342
+ return events;
343
+ }
344
+ reset() {
345
+ this.text = /* @__PURE__ */ new Map();
346
+ this.reasoning = "";
347
+ this.reasoningVariant = void 0;
348
+ this.refusal = "";
349
+ this.json = "";
350
+ this.tools.clear();
351
+ this.toolByIndex.clear();
352
+ this.finishEmitted = false;
353
+ }
354
+ hasFinished() {
355
+ return this.finishEmitted;
356
+ }
357
+ pushText(text, choiceIndex = 0) {
358
+ if (text.length === 0) return [];
359
+ const next = `${this.text.get(choiceIndex) ?? ""}${text}`;
360
+ this.assertBuffer(next, "text");
361
+ this.text.set(choiceIndex, next);
362
+ return [
363
+ optionalEvent({ type: "text.delta", text, choiceIndex: normalizeChoiceIndex(choiceIndex) })
364
+ ];
365
+ }
366
+ pushReasoning(text, variant) {
367
+ if (text.length === 0) return [];
368
+ this.reasoning += text;
369
+ this.reasoningVariant = variant ?? this.reasoningVariant;
370
+ this.assertBuffer(this.reasoning, "reasoning");
371
+ return [optionalEvent({ type: "reasoning.delta", text, variant })];
372
+ }
373
+ pushRefusal(text) {
374
+ if (text.length === 0) return [];
375
+ this.refusal += text;
376
+ this.assertBuffer(this.refusal, "refusal");
377
+ return [{ type: "refusal.delta", text }];
378
+ }
379
+ pushJson(delta) {
380
+ if (delta.length === 0) return [];
381
+ this.json += delta;
382
+ this.assertBuffer(this.json, "json");
383
+ const partial = parsePartialJSON(this.json);
384
+ return [withOptional("partial", partial.value, { type: "json.delta", delta })];
385
+ }
386
+ pushToolStart(chunk) {
387
+ const state = this.getOrCreateTool(chunk);
388
+ if (chunk.id && !state.started) {
389
+ state.eventId = chunk.id;
390
+ }
391
+ state.name = chunk.name;
392
+ state.index = chunk.index;
393
+ state.choiceIndex = chunk.choiceIndex;
394
+ if (state.started) return [];
395
+ state.started = true;
396
+ return [
397
+ optionalEvent({
398
+ type: "tool_call.start",
399
+ id: state.eventId,
400
+ name: state.name,
401
+ index: state.index,
402
+ choiceIndex: state.choiceIndex
403
+ })
404
+ ];
405
+ }
406
+ pushToolArgs(chunk) {
407
+ if (chunk.delta.length === 0) return [];
408
+ const state = this.getOrCreateTool(chunk);
409
+ state.args += chunk.delta;
410
+ this.assertBuffer(state.args, "tool args");
411
+ const partial = parsePartialJSON(state.args);
412
+ return [
413
+ withOptional("partial", partial.value, {
414
+ type: "tool_call.args.delta",
415
+ id: state.eventId,
416
+ delta: chunk.delta
417
+ })
418
+ ];
419
+ }
420
+ finishTool(chunk) {
421
+ const state = this.getOrCreateTool(chunk);
422
+ const done = this.toolDoneEvent(state);
423
+ this.deleteTool(state);
424
+ return [done];
425
+ }
426
+ flushText() {
427
+ const events = [];
428
+ for (const [choiceIndex, text] of this.text) {
429
+ if (text.length > 0) {
430
+ events.push(
431
+ optionalEvent({
432
+ type: "text.done",
433
+ text,
434
+ choiceIndex: normalizeChoiceIndex(choiceIndex)
435
+ })
436
+ );
437
+ }
438
+ }
439
+ this.text.clear();
440
+ return events;
441
+ }
442
+ flushReasoning() {
443
+ if (this.reasoning.length === 0) return [];
444
+ const event = optionalEvent({
445
+ type: "reasoning.done",
446
+ text: this.reasoning,
447
+ variant: this.reasoningVariant
448
+ });
449
+ this.reasoning = "";
450
+ this.reasoningVariant = void 0;
451
+ return [event];
452
+ }
453
+ flushRefusal() {
454
+ if (this.refusal.length === 0) return [];
455
+ const event = { type: "refusal.done", text: this.refusal };
456
+ this.refusal = "";
457
+ return [event];
458
+ }
459
+ flushJson() {
460
+ if (this.json.length === 0) return [];
461
+ const parsed = parsePartialJSON(this.json);
462
+ this.json = "";
463
+ if (parsed.complete) {
464
+ return [{ type: "json.done", value: parsed.value }];
465
+ }
466
+ return [this.errorEvent(prefixedError("json stream ended with invalid JSON"), false)];
467
+ }
468
+ flushTools() {
469
+ const events = [];
470
+ for (const state of this.tools.values()) {
471
+ events.push(this.toolDoneEvent(state));
472
+ }
473
+ this.tools.clear();
474
+ this.toolByIndex.clear();
475
+ return events;
476
+ }
477
+ toolDoneEvent(state) {
478
+ const parsed = parsePartialJSON(state.args);
479
+ if (parsed.complete) {
480
+ return { type: "tool_call.done", id: state.eventId, name: state.name, args: parsed.value };
481
+ }
482
+ if (this.options.strictToolArgs) {
483
+ throw prefixedError(`tool args for ${state.name} ended with invalid JSON`);
484
+ }
485
+ return { type: "tool_call.done", id: state.eventId, name: state.name, args: state.args };
486
+ }
487
+ getOrCreateTool(chunk) {
488
+ const choiceIndex = chunk.choiceIndex ?? 0;
489
+ const indexKey = chunk.index === void 0 ? void 0 : `${choiceIndex}:${chunk.index}`;
490
+ let key = (indexKey ? this.toolByIndex.get(indexKey) : void 0) || chunk.id;
491
+ if (!key && indexKey) {
492
+ key = `tool:${indexKey}`;
493
+ this.toolByIndex.set(indexKey, key);
494
+ }
495
+ key ??= chunk.id ?? `tool:${choiceIndex}:${this.tools.size}`;
496
+ let state = this.tools.get(key);
497
+ if (!state) {
498
+ state = {
499
+ eventId: chunk.id || key,
500
+ name: "unknown",
501
+ args: "",
502
+ index: chunk.index,
503
+ choiceIndex: normalizeChoiceIndex(choiceIndex),
504
+ started: false
505
+ };
506
+ this.tools.set(key, state);
507
+ }
508
+ if (chunk.id && !state.started && state.eventId.startsWith("tool:")) {
509
+ this.tools.delete(key);
510
+ state.eventId = chunk.id;
511
+ this.tools.set(chunk.id, state);
512
+ if (indexKey) {
513
+ this.toolByIndex.set(indexKey, chunk.id);
514
+ }
515
+ }
516
+ return state;
517
+ }
518
+ deleteTool(state) {
519
+ this.tools.delete(state.eventId);
520
+ if (state.index !== void 0) {
521
+ this.toolByIndex.delete(`${state.choiceIndex ?? 0}:${state.index}`);
522
+ }
523
+ }
524
+ assertBuffer(value, label) {
525
+ if (this.options.maxBufferBytes === void 0) return;
526
+ if (utf8ByteLength(value) > this.options.maxBufferBytes) {
527
+ throw prefixedError(`${label} buffer exceeded maxBufferBytes`);
528
+ }
529
+ }
530
+ errorEvent(error, recoverable) {
531
+ const source = errorFromUnknown(error);
532
+ if (!this.options.sanitizeErrors) {
533
+ return optionalEvent({ type: "error", error: source, recoverable });
534
+ }
535
+ return optionalEvent({
536
+ type: "error",
537
+ error: new Error("An error occurred while processing the stream."),
538
+ recoverable,
539
+ sanitized: "An error occurred while processing the stream."
540
+ });
541
+ }
542
+ };
543
+ function optionalEvent(event) {
544
+ return Object.fromEntries(
545
+ Object.entries(event).filter(([, value]) => value !== void 0 && value !== "kind")
546
+ );
547
+ }
548
+ function withOptional(key, value, target) {
549
+ if (value === void 0) return target;
550
+ return { ...target, [key]: value };
551
+ }
552
+ function normalizeChoiceIndex(choiceIndex) {
553
+ return choiceIndex === 0 ? void 0 : choiceIndex;
554
+ }
555
+
556
+ // src/core/assemble-payloads.ts
557
+ function assembleFromPayloads(payloads, adapter, options = {}) {
558
+ return assembleFromPayloadsGenerator(payloads, adapter, options);
559
+ }
560
+ async function* assembleFromPayloadsGenerator(payloads, adapter, options) {
561
+ const assembler = new EventAssembler(options);
562
+ const iterator = payloads[Symbol.asyncIterator]();
563
+ let sawTerminalMarker = false;
564
+ try {
565
+ while (true) {
566
+ if (options.signal?.aborted) {
567
+ yield* assembler.flush({ terminalReason: "aborted" });
568
+ return;
569
+ }
570
+ const item = await iterator.next();
571
+ if (item.done) break;
572
+ const result = processPayload(item.value, assembler, adapter, options);
573
+ if (result.kind === "done-marker") {
574
+ sawTerminalMarker = true;
575
+ continue;
576
+ }
577
+ if (result.kind === "recoverable-error") {
578
+ yield result.event;
579
+ continue;
580
+ }
581
+ yield* result.events;
582
+ }
583
+ yield* resolveTerminalFlush(assembler, {
584
+ sawTerminalMarker,
585
+ aborted: options.signal?.aborted === true
586
+ });
587
+ } finally {
588
+ await iterator.return?.();
589
+ }
590
+ }
591
+
592
+ // src/core/utils/sse-parser.ts
593
+ var SSEParser = class {
594
+ lineBuffer = "";
595
+ dataLines = [];
596
+ push(chunk) {
597
+ const payloads = [];
598
+ this.lineBuffer += chunk;
599
+ while (true) {
600
+ const lineEnd = this.findLineEnd();
601
+ if (!lineEnd) break;
602
+ const line = this.lineBuffer.slice(0, lineEnd.index);
603
+ this.lineBuffer = this.lineBuffer.slice(lineEnd.nextIndex);
604
+ const payload = this.processLine(line);
605
+ if (payload !== void 0) {
606
+ payloads.push(payload);
607
+ }
608
+ }
609
+ return payloads;
610
+ }
611
+ flush() {
612
+ const payloads = [];
613
+ if (this.lineBuffer.length > 0) {
614
+ const payload2 = this.processLine(this.lineBuffer);
615
+ this.lineBuffer = "";
616
+ if (payload2 !== void 0) {
617
+ payloads.push(payload2);
618
+ }
619
+ }
620
+ const payload = this.dispatch();
621
+ if (payload !== void 0) {
622
+ payloads.push(payload);
623
+ }
624
+ return payloads;
625
+ }
626
+ findLineEnd() {
627
+ const lf = this.lineBuffer.indexOf("\n");
628
+ const cr = this.lineBuffer.indexOf("\r");
629
+ if (lf === -1 && cr === -1) return void 0;
630
+ if (cr !== -1 && (lf === -1 || cr < lf)) {
631
+ const nextIndex = this.lineBuffer[cr + 1] === "\n" ? cr + 2 : cr + 1;
632
+ return { index: cr, nextIndex };
633
+ }
634
+ return { index: lf, nextIndex: lf + 1 };
635
+ }
636
+ processLine(line) {
637
+ if (line === "") {
638
+ return this.dispatch();
639
+ }
640
+ if (line.startsWith(":")) {
641
+ return void 0;
642
+ }
643
+ const colon = line.indexOf(":");
644
+ const field = colon === -1 ? line : line.slice(0, colon);
645
+ let value = colon === -1 ? "" : line.slice(colon + 1);
646
+ if (value.startsWith(" ")) {
647
+ value = value.slice(1);
648
+ }
649
+ if (field === "data") {
650
+ this.dataLines.push(value);
651
+ }
652
+ return void 0;
653
+ }
654
+ dispatch() {
655
+ if (this.dataLines.length === 0) {
656
+ return void 0;
657
+ }
658
+ const payload = this.dataLines.join("\n");
659
+ this.dataLines = [];
660
+ return payload.length > 0 ? payload : void 0;
661
+ }
662
+ };
663
+
664
+ // src/core/parse-sse.ts
665
+ function parseSSE(source) {
666
+ return parseSSEGenerator(source);
667
+ }
668
+ async function* parseSSEGenerator(source) {
669
+ const parser = new SSEParser();
670
+ for await (const chunk of sourceToStrings(source)) {
671
+ for (const payload of parser.push(chunk)) {
672
+ yield payload;
673
+ }
674
+ }
675
+ for (const payload of parser.flush()) {
676
+ yield payload;
677
+ }
678
+ }
679
+
680
+ // src/core/assemble-stream.ts
681
+ function assembleStream(source, adapter, options) {
682
+ return assembleFromPayloads(parseSSE(source), adapter, options);
683
+ }
684
+
685
+ // src/core/assemble-response.ts
686
+ function assembleResponse(body, adapter, options = {}) {
687
+ if (!adapter.parseResponse) {
688
+ throw prefixedError("adapter.parseResponse is required for assembleResponse");
689
+ }
690
+ const assembler = new EventAssembler(options);
691
+ const events = [];
692
+ for (const chunk of adapter.parseResponse(body)) {
693
+ events.push(...assembler.push(chunk));
694
+ }
695
+ events.push(...assembler.flush(assembler.hasFinished() ? void 0 : { terminalReason: "stop" }));
696
+ return events;
697
+ }
698
+
699
+ // src/core/assemble-from-file.ts
700
+ function assembleFromFile(path, adapter, options = {}) {
701
+ return assembleFromFileGenerator(path, adapter, options);
702
+ }
703
+ async function* assembleFromFileGenerator(path, adapter, options) {
704
+ const format = options.format ?? inferFormat(path);
705
+ const content = await readFixture(path);
706
+ if (format === "sse") {
707
+ yield* assembleStream(stringIterable(content), adapter, options);
708
+ return;
709
+ }
710
+ let body;
711
+ try {
712
+ body = JSON.parse(content);
713
+ } catch (error) {
714
+ const message = error instanceof Error ? error.message : String(error);
715
+ throw new Error(
716
+ `llm-stream-assemble: assembleFromFile failed to parse JSON ${path}: ${message}`
717
+ );
718
+ }
719
+ for (const event of assembleResponse(body, adapter, options)) {
720
+ yield event;
721
+ }
722
+ }
723
+ function inferFormat(path) {
724
+ if (path.endsWith(".sse")) return "sse";
725
+ if (path.endsWith(".json")) return "json";
726
+ throw new Error(`llm-stream-assemble: assembleFromFile cannot infer format for ${path}`);
727
+ }
728
+ async function readFixture(path) {
729
+ try {
730
+ const { readFile } = await import('fs/promises');
731
+ return await readFile(path, "utf8");
732
+ } catch (error) {
733
+ const message = error instanceof Error ? error.message : String(error);
734
+ throw new Error(`llm-stream-assemble: assembleFromFile failed to read ${path}: ${message}`);
735
+ }
736
+ }
737
+ async function* stringIterable(value) {
738
+ yield value;
739
+ }
740
+
741
+ // src/core/create-assembly-transform.ts
742
+ function createAssemblyTransform(adapter, options = {}) {
743
+ const decoder = new Utf8StreamDecoder();
744
+ const parser = new SSEParser();
745
+ const assembler = new EventAssembler(options);
746
+ let sawTerminalMarker = false;
747
+ let aborted = false;
748
+ const emit = (controller, events) => {
749
+ for (const event of events) {
750
+ controller.enqueue(event);
751
+ }
752
+ };
753
+ const handlePayload = (payload, controller) => {
754
+ const result = processPayload(payload, assembler, adapter, options);
755
+ if (result.kind === "done-marker") {
756
+ sawTerminalMarker = true;
757
+ return;
758
+ }
759
+ if (result.kind === "recoverable-error") {
760
+ controller.enqueue(result.event);
761
+ return;
762
+ }
763
+ emit(controller, result.events);
764
+ };
765
+ return new TransformStream({
766
+ start(controller) {
767
+ options.signal?.addEventListener(
768
+ "abort",
769
+ () => {
770
+ if (aborted || assembler.hasFinished()) return;
771
+ aborted = true;
772
+ emit(controller, assembler.flush({ terminalReason: "aborted" }));
773
+ controller.terminate();
774
+ },
775
+ { once: true }
776
+ );
777
+ },
778
+ transform(chunk, controller) {
779
+ if (aborted || options.signal?.aborted) {
780
+ aborted = true;
781
+ emit(controller, assembler.flush({ terminalReason: "aborted" }));
782
+ controller.terminate();
783
+ return;
784
+ }
785
+ for (const payload of parser.push(decoder.decode(chunk))) {
786
+ handlePayload(payload, controller);
787
+ }
788
+ },
789
+ flush(controller) {
790
+ if (aborted || options.signal?.aborted) {
791
+ emit(controller, assembler.flush({ terminalReason: "aborted" }));
792
+ return;
793
+ }
794
+ const decoded = decoder.flush();
795
+ if (decoded.length > 0) {
796
+ for (const payload of parser.push(decoded)) {
797
+ handlePayload(payload, controller);
798
+ }
799
+ }
800
+ for (const payload of parser.flush()) {
801
+ handlePayload(payload, controller);
802
+ }
803
+ emit(controller, resolveTerminalFlush(assembler, { sawTerminalMarker, aborted: false }));
804
+ }
805
+ });
806
+ }
807
+
808
+ // src/adapters/errors.ts
809
+ function libraryError(message) {
810
+ return new Error(`llm-stream-assemble: ${message}`);
811
+ }
812
+ function adapterScopedError(scope, message) {
813
+ return new Error(`llm-stream-assemble: ${scope}: ${message}`);
814
+ }
815
+ function providerErrorChunks(error, recoverable = false) {
816
+ return [
817
+ { kind: "provider-error", error, recoverable },
818
+ { kind: "finish", reason: "error" }
819
+ ];
820
+ }
821
+ function providerErrorChunksFromMessage(message, recoverable = false) {
822
+ return providerErrorChunks(libraryError(message), recoverable);
823
+ }
824
+ function providerErrorChunksFromPayload(errorPayload, scope, recoverable, fallbackMessage) {
825
+ const message = asString(errorPayload.message) ?? fallbackMessage;
826
+ const error = adapterScopedError(scope, message);
827
+ Object.defineProperty(error, "raw", {
828
+ value: errorPayload,
829
+ enumerable: false
830
+ });
831
+ return providerErrorChunks(error, recoverable);
832
+ }
833
+
834
+ // src/adapters/utils.ts
835
+ function isRecord(value) {
836
+ return typeof value === "object" && value !== null && !Array.isArray(value);
837
+ }
838
+ function asString(value) {
839
+ return typeof value === "string" ? value : void 0;
840
+ }
841
+ function asNumber(value) {
842
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
843
+ }
844
+ function optionalRawChunk(input) {
845
+ return Object.fromEntries(
846
+ Object.entries(input).filter(([, value]) => value !== void 0)
847
+ );
848
+ }
849
+ function prefixedAdapterError(feature, message) {
850
+ return adapterScopedError(feature, message);
851
+ }
852
+ function createStreamAdapter(config) {
853
+ return {
854
+ parseChunk(raw) {
855
+ return config.parser.parseChunk(raw);
856
+ },
857
+ parseResponse(body) {
858
+ return config.parseResponse(body, config.options);
859
+ }
860
+ };
861
+ }
862
+ function parseAdapterJSON(raw, feature) {
863
+ try {
864
+ return JSON.parse(raw);
865
+ } catch (error) {
866
+ const message = error instanceof Error ? error.message : String(error);
867
+ throw prefixedAdapterError(feature, message);
868
+ }
869
+ }
870
+
871
+ // src/adapters/openai-chat/parser/errors.ts
872
+ function providerErrorPayload(payload, options) {
873
+ if (isRecord(payload.error)) return payload.error;
874
+ if (!options.looseErrorShape) return void 0;
875
+ const errorString = asString(payload.error);
876
+ if (errorString) return { message: errorString };
877
+ const detailString = asString(payload.detail);
878
+ if (detailString) return { message: detailString };
879
+ if (isRecord(payload.detail)) return payload.detail;
880
+ const topLevelMessage = asString(payload.message);
881
+ const topLevelType = asString(payload.type);
882
+ if (topLevelMessage && topLevelType === "error") return { message: topLevelMessage };
883
+ return void 0;
884
+ }
885
+ function openAIProviderErrorChunks(errorPayload, recoverable, options) {
886
+ return providerErrorChunksFromPayload(
887
+ errorPayload,
888
+ options.errorPrefix,
889
+ recoverable,
890
+ "OpenAI-compatible provider error"
891
+ );
892
+ }
893
+ function throwAdapterObjectError(scope, message = "expected a JSON object") {
894
+ throw adapterScopedError(scope, message);
895
+ }
896
+ function throwUnrecognizedChunkError(options) {
897
+ throw adapterScopedError(
898
+ `${options.errorPrefix}.parseChunk`,
899
+ "expected an OpenAI-compatible chat completion chunk"
900
+ );
901
+ }
902
+ function throwUnrecognizedResponseError(options) {
903
+ throw adapterScopedError(
904
+ `${options.errorPrefix}.parseResponse`,
905
+ "expected an OpenAI-compatible chat completion object"
906
+ );
907
+ }
908
+
909
+ // src/adapters/openai-chat/parser/chunks.ts
910
+ function metadataChunks(payload) {
911
+ const chunks = [];
912
+ const id = asString(payload.id);
913
+ if (id) chunks.push({ kind: "message-start", id });
914
+ const metadata = { kind: "metadata", raw: payload };
915
+ const model = asString(payload.model);
916
+ const created = asNumber(payload.created);
917
+ if (model) metadata.model = model;
918
+ if (id) metadata.responseId = id;
919
+ if (created !== void 0) metadata.created = created;
920
+ if (metadata.model || metadata.responseId || metadata.created !== void 0) {
921
+ chunks.push(metadata);
922
+ }
923
+ return chunks;
924
+ }
925
+ function hasMetadata(payload) {
926
+ return asString(payload.id) !== void 0 || asString(payload.model) !== void 0 || asNumber(payload.created) !== void 0;
927
+ }
928
+ function isRecognizableResponse(payload) {
929
+ return hasMetadata(payload) || typeof payload.object === "string" || Array.isArray(payload.choices) || isRecord(payload.usage);
930
+ }
931
+ function reasoningChunks(source, options) {
932
+ const chunks = [];
933
+ const aliases = /* @__PURE__ */ new Set([
934
+ "reasoning",
935
+ "reasoning_content",
936
+ "reasoning_summary",
937
+ ...options.reasoningFieldAliases
938
+ ]);
939
+ for (const field of aliases) {
940
+ const text = asString(source[field]);
941
+ if (!text) continue;
942
+ chunks.push({
943
+ kind: "reasoning-delta",
944
+ text,
945
+ variant: field === "reasoning_summary" ? "summary" : "detail"
946
+ });
947
+ }
948
+ return chunks;
949
+ }
950
+ function finishReasonChunks(value, choiceIndex, options) {
951
+ if (value === null || value === void 0) return [];
952
+ const finishReason2 = normalizeFinishReason(value);
953
+ if (finishReason2) {
954
+ return [withChoiceIndex({ kind: "finish", reason: finishReason2 }, choiceIndex)];
955
+ }
956
+ return [
957
+ {
958
+ kind: "provider-error",
959
+ error: adapterScopedError(
960
+ options.errorPrefix,
961
+ `unknown OpenAI-compatible finish_reason: ${String(value)}`
962
+ ),
963
+ recoverable: true
964
+ },
965
+ withChoiceIndex({ kind: "finish", reason: "error" }, choiceIndex)
966
+ ];
967
+ }
968
+ function usageChunk(value, options) {
969
+ if (!isRecord(value)) return void 0;
970
+ const inputTokens = firstNumber(value, options.usageInputTokenFields);
971
+ const outputTokens = firstNumber(value, options.usageOutputTokenFields);
972
+ const details = isRecord(value.completion_tokens_details) ? value.completion_tokens_details : void 0;
973
+ const reasoningTokens = details ? asNumber(details.reasoning_tokens) : void 0;
974
+ if (inputTokens === void 0 && outputTokens === void 0 && reasoningTokens === void 0) {
975
+ return void 0;
976
+ }
977
+ const chunk = { kind: "usage", raw: value };
978
+ if (inputTokens !== void 0) chunk.inputTokens = inputTokens;
979
+ if (outputTokens !== void 0) chunk.outputTokens = outputTokens;
980
+ if (reasoningTokens !== void 0) chunk.reasoningTokens = reasoningTokens;
981
+ return chunk;
982
+ }
983
+ function choiceIndexFor(choice, position, options) {
984
+ return asNumber(choice.index) ?? (options.useChoicePositionFallback ? position : void 0);
985
+ }
986
+ function toolStartChunk(input) {
987
+ return optionalRawChunk({
988
+ kind: "tool-start",
989
+ id: input.id,
990
+ name: input.name,
991
+ index: input.index,
992
+ choiceIndex: input.choiceIndex
993
+ });
994
+ }
995
+ function toolArgsChunk(input) {
996
+ return optionalRawChunk({
997
+ kind: "tool-args-delta",
998
+ id: input.id,
999
+ delta: input.delta,
1000
+ index: input.index,
1001
+ choiceIndex: input.choiceIndex
1002
+ });
1003
+ }
1004
+ function toolDoneChunk(input) {
1005
+ return optionalRawChunk({
1006
+ kind: "tool-done",
1007
+ id: input.id,
1008
+ index: input.index,
1009
+ choiceIndex: input.choiceIndex
1010
+ });
1011
+ }
1012
+ function withChoiceIndex(chunk, choiceIndex) {
1013
+ if (choiceIndex === void 0) return chunk;
1014
+ return optionalRawChunk({ ...chunk, choiceIndex });
1015
+ }
1016
+ function toolKey(choiceIndex, choicePosition, toolIndex) {
1017
+ return `${choiceKey(choiceIndex, choicePosition)}:${toolIndex}`;
1018
+ }
1019
+ function choiceKey(choiceIndex, choicePosition) {
1020
+ return choiceIndex === void 0 ? `unknown-choice:${choicePosition}` : String(choiceIndex);
1021
+ }
1022
+ function normalizeFinishReason(value) {
1023
+ if (value === "stop" || value === "length" || value === "content_filter" || value === "tool_calls") {
1024
+ return value;
1025
+ }
1026
+ if (value === "function_call") return "tool_calls";
1027
+ return void 0;
1028
+ }
1029
+ function firstNumber(source, fields) {
1030
+ for (const field of fields) {
1031
+ const value = asNumber(source[field]);
1032
+ if (value !== void 0) return value;
1033
+ }
1034
+ return void 0;
1035
+ }
1036
+
1037
+ // src/adapters/openai-chat/parser/stream-parser.ts
1038
+ var OpenAIChatLikeParser = class {
1039
+ constructor(options) {
1040
+ this.options = options;
1041
+ }
1042
+ options;
1043
+ metadataEmitted = false;
1044
+ tools = /* @__PURE__ */ new Map();
1045
+ legacyStarted = /* @__PURE__ */ new Set();
1046
+ parseChunk(raw) {
1047
+ if (raw.trim() === "[DONE]") return [];
1048
+ const payload = parseAdapterJSON(raw, `${this.options.errorPrefix}.parseChunk`);
1049
+ if (!isRecord(payload)) {
1050
+ throwAdapterObjectError(`${this.options.errorPrefix}.parseChunk`);
1051
+ }
1052
+ const looseError = providerErrorPayload(payload, this.options);
1053
+ if (looseError) return openAIProviderErrorChunks(looseError, false, this.options);
1054
+ if (this.options.rejectUnrecognizedPayloads && !this.isRecognizableChunk(payload)) {
1055
+ throwUnrecognizedChunkError(this.options);
1056
+ }
1057
+ const chunks = [];
1058
+ if (!this.metadataEmitted && hasMetadata(payload)) {
1059
+ chunks.push(...metadataChunks(payload));
1060
+ this.metadataEmitted = true;
1061
+ }
1062
+ const usage = usageChunk(payload.usage, this.options);
1063
+ if (usage) chunks.push(usage);
1064
+ const choices = Array.isArray(payload.choices) ? payload.choices : [];
1065
+ for (let position = 0; position < choices.length; position += 1) {
1066
+ const choice = choices[position];
1067
+ if (!isRecord(choice)) continue;
1068
+ chunks.push(...this.choiceChunks(choice, position));
1069
+ }
1070
+ return chunks;
1071
+ }
1072
+ isRecognizableChunk(payload) {
1073
+ return hasMetadata(payload) || typeof payload.object === "string" || Array.isArray(payload.choices) || isRecord(payload.usage);
1074
+ }
1075
+ choiceChunks(choice, position) {
1076
+ const choiceIndex = choiceIndexFor(choice, position, this.options);
1077
+ const chunks = [];
1078
+ const delta = isRecord(choice.delta) ? choice.delta : void 0;
1079
+ if (delta) {
1080
+ chunks.push(...this.deltaChunks(delta, choiceIndex, position));
1081
+ }
1082
+ chunks.push(...finishReasonChunks(choice.finish_reason, choiceIndex, this.options));
1083
+ return chunks;
1084
+ }
1085
+ deltaChunks(delta, choiceIndex, choicePosition) {
1086
+ const chunks = [];
1087
+ const content = asString(delta.content);
1088
+ if (content && content.length > 0) {
1089
+ chunks.push(
1090
+ this.options.jsonMode ? { kind: "json-delta", delta: content } : withChoiceIndex({ kind: "text-delta", text: content }, choiceIndex)
1091
+ );
1092
+ }
1093
+ const refusal = asString(delta.refusal);
1094
+ if (refusal && refusal.length > 0) {
1095
+ chunks.push({ kind: "refusal-delta", text: refusal });
1096
+ }
1097
+ chunks.push(...reasoningChunks(delta, this.options));
1098
+ chunks.push(...this.toolCallChunks(delta.tool_calls, choiceIndex, choicePosition));
1099
+ chunks.push(...this.legacyFunctionChunks(delta.function_call, choiceIndex, choicePosition));
1100
+ return chunks;
1101
+ }
1102
+ toolCallChunks(value, choiceIndex, choicePosition) {
1103
+ if (!Array.isArray(value)) return [];
1104
+ const chunks = [];
1105
+ for (let position = 0; position < value.length; position += 1) {
1106
+ const toolCall = value[position];
1107
+ if (!isRecord(toolCall)) continue;
1108
+ const toolIndex = asNumber(toolCall.index) ?? position;
1109
+ const key = toolKey(choiceIndex, choicePosition, toolIndex);
1110
+ const state = this.toolState(key);
1111
+ const id = asString(toolCall.id);
1112
+ const fn = isRecord(toolCall.function) ? toolCall.function : void 0;
1113
+ const name = asString(fn?.name);
1114
+ const args = asString(fn?.arguments);
1115
+ if (id) state.id = id;
1116
+ if (name) state.name = name;
1117
+ if (!state.startEmitted && (id || name || args && args.length > 0)) {
1118
+ chunks.push(
1119
+ toolStartChunk({
1120
+ id: state.id,
1121
+ name: state.name,
1122
+ index: toolIndex,
1123
+ choiceIndex
1124
+ })
1125
+ );
1126
+ state.startEmitted = true;
1127
+ }
1128
+ if (args && args.length > 0) {
1129
+ state.sawArguments = true;
1130
+ chunks.push(
1131
+ toolArgsChunk({
1132
+ id: state.id,
1133
+ delta: args,
1134
+ index: toolIndex,
1135
+ choiceIndex
1136
+ })
1137
+ );
1138
+ }
1139
+ }
1140
+ return chunks;
1141
+ }
1142
+ legacyFunctionChunks(value, choiceIndex, choicePosition) {
1143
+ if (!isRecord(value)) return [];
1144
+ const chunks = [];
1145
+ const name = asString(value.name);
1146
+ const args = asString(value.arguments);
1147
+ const legacyKey = choiceKey(choiceIndex, choicePosition);
1148
+ const id = `${this.options.legacyFunctionIdPrefix}:${choiceIndex ?? choicePosition}`;
1149
+ if (name && !this.legacyStarted.has(legacyKey)) {
1150
+ chunks.push(withChoiceIndex({ kind: "tool-start", id, name, index: 0 }, choiceIndex));
1151
+ this.legacyStarted.add(legacyKey);
1152
+ }
1153
+ if (args && args.length > 0) {
1154
+ if (!this.legacyStarted.has(legacyKey)) {
1155
+ chunks.push(
1156
+ withChoiceIndex(
1157
+ { kind: "tool-start", id, name: name ?? "unknown", index: 0 },
1158
+ choiceIndex
1159
+ )
1160
+ );
1161
+ this.legacyStarted.add(legacyKey);
1162
+ }
1163
+ chunks.push(
1164
+ withChoiceIndex({ kind: "tool-args-delta", id, delta: args, index: 0 }, choiceIndex)
1165
+ );
1166
+ }
1167
+ return chunks;
1168
+ }
1169
+ toolState(key) {
1170
+ let state = this.tools.get(key);
1171
+ if (!state) {
1172
+ state = { name: "unknown", startEmitted: false, sawArguments: false };
1173
+ this.tools.set(key, state);
1174
+ }
1175
+ return state;
1176
+ }
1177
+ };
1178
+
1179
+ // src/adapters/openai-chat/parser/response.ts
1180
+ function parseResponse(body, options) {
1181
+ if (!isRecord(body)) {
1182
+ throwAdapterObjectError(
1183
+ `${options.errorPrefix}.parseResponse`,
1184
+ "expected an OpenAI-compatible chat completion object"
1185
+ );
1186
+ }
1187
+ const looseError = providerErrorPayload(body, options);
1188
+ if (looseError) return openAIProviderErrorChunks(looseError, false, options);
1189
+ if (options.rejectUnrecognizedPayloads && !isRecognizableResponse(body)) {
1190
+ throwUnrecognizedResponseError(options);
1191
+ }
1192
+ const chunks = [];
1193
+ const finishChunks = [];
1194
+ chunks.push(...metadataChunks(body));
1195
+ const choices = Array.isArray(body.choices) ? body.choices : [];
1196
+ for (let position = 0; position < choices.length; position += 1) {
1197
+ const choice = choices[position];
1198
+ if (!isRecord(choice)) continue;
1199
+ chunks.push(...responseChoiceChunks(choice, position, options));
1200
+ finishChunks.push(...responseChoiceFinishChunks(choice, position, options));
1201
+ }
1202
+ const usage = usageChunk(body.usage, options);
1203
+ if (usage) chunks.push(usage);
1204
+ chunks.push(...finishChunks);
1205
+ return chunks;
1206
+ }
1207
+ function responseChoiceChunks(choice, position, options) {
1208
+ const choiceIndex = choiceIndexFor(choice, position, options);
1209
+ const message = isRecord(choice.message) ? choice.message : void 0;
1210
+ const chunks = [];
1211
+ if (message) {
1212
+ const content = asString(message.content);
1213
+ if (content && content.length > 0) {
1214
+ chunks.push(
1215
+ options.jsonMode ? { kind: "json-delta", delta: content } : withChoiceIndex({ kind: "text-delta", text: content }, choiceIndex)
1216
+ );
1217
+ }
1218
+ const refusal = asString(message.refusal);
1219
+ if (refusal && refusal.length > 0) {
1220
+ chunks.push({ kind: "refusal-delta", text: refusal });
1221
+ }
1222
+ chunks.push(...reasoningChunks(message, options));
1223
+ chunks.push(...responseToolCallChunks(message.tool_calls, choiceIndex));
1224
+ chunks.push(
1225
+ ...responseLegacyFunctionChunks(message.function_call, choiceIndex, position, options)
1226
+ );
1227
+ }
1228
+ return chunks;
1229
+ }
1230
+ function responseChoiceFinishChunks(choice, position, options) {
1231
+ const choiceIndex = choiceIndexFor(choice, position, options);
1232
+ return finishReasonChunks(choice.finish_reason, choiceIndex, options);
1233
+ }
1234
+ function responseToolCallChunks(value, choiceIndex) {
1235
+ if (!Array.isArray(value)) return [];
1236
+ const chunks = [];
1237
+ for (let position = 0; position < value.length; position += 1) {
1238
+ const toolCall = value[position];
1239
+ if (!isRecord(toolCall)) continue;
1240
+ const fn = isRecord(toolCall.function) ? toolCall.function : void 0;
1241
+ const id = asString(toolCall.id);
1242
+ const name = asString(fn?.name) ?? "unknown";
1243
+ const args = asString(fn?.arguments) ?? "";
1244
+ const index = asNumber(toolCall.index) ?? position;
1245
+ chunks.push(toolStartChunk({ id, name, index, choiceIndex }));
1246
+ if (args.length > 0) chunks.push(toolArgsChunk({ id, delta: args, index, choiceIndex }));
1247
+ chunks.push(toolDoneChunk({ id, index, choiceIndex }));
1248
+ }
1249
+ return chunks;
1250
+ }
1251
+ function responseLegacyFunctionChunks(value, choiceIndex, choicePosition, options) {
1252
+ if (!isRecord(value)) return [];
1253
+ const name = asString(value.name) ?? "unknown";
1254
+ const args = asString(value.arguments) ?? "";
1255
+ const id = `${options.legacyFunctionIdPrefix}:${choiceIndex ?? choicePosition}`;
1256
+ const chunks = [
1257
+ withChoiceIndex({ kind: "tool-start", id, name, index: 0 }, choiceIndex)
1258
+ ];
1259
+ if (args.length > 0) {
1260
+ chunks.push(
1261
+ withChoiceIndex({ kind: "tool-args-delta", id, delta: args, index: 0 }, choiceIndex)
1262
+ );
1263
+ }
1264
+ chunks.push(withChoiceIndex({ kind: "tool-done", id, index: 0 }, choiceIndex));
1265
+ return chunks;
1266
+ }
1267
+
1268
+ // src/adapters/openai-chat/parser/types.ts
1269
+ function normalizeOptions(options) {
1270
+ return {
1271
+ jsonMode: options.jsonMode ?? false,
1272
+ legacyFunctionIdPrefix: options.legacyFunctionIdPrefix ?? "legacy_function",
1273
+ errorPrefix: options.errorPrefix,
1274
+ looseErrorShape: options.looseErrorShape ?? false,
1275
+ allowMissingMetadata: options.allowMissingMetadata ?? false,
1276
+ useChoicePositionFallback: options.useChoicePositionFallback ?? true,
1277
+ reasoningFieldAliases: options.reasoningFieldAliases ?? [],
1278
+ usageInputTokenFields: options.usageInputTokenFields ?? ["prompt_tokens"],
1279
+ usageOutputTokenFields: options.usageOutputTokenFields ?? ["completion_tokens"],
1280
+ rejectUnrecognizedPayloads: options.rejectUnrecognizedPayloads ?? false
1281
+ };
1282
+ }
1283
+
1284
+ // src/adapters/openai-chat/parser/index.ts
1285
+ function createOpenAIChatLikeAdapter(options) {
1286
+ const normalized = normalizeOptions(options);
1287
+ const parser = new OpenAIChatLikeParser(normalized);
1288
+ return createStreamAdapter({
1289
+ parser,
1290
+ parseResponse,
1291
+ options: normalized
1292
+ });
1293
+ }
1294
+
1295
+ // src/adapters/openai-chat.ts
1296
+ function openaiChatAdapter(options = {}) {
1297
+ return createOpenAIChatLikeAdapter({
1298
+ ...options,
1299
+ errorPrefix: "openaiChatAdapter",
1300
+ looseErrorShape: false,
1301
+ allowMissingMetadata: false,
1302
+ useChoicePositionFallback: true,
1303
+ usageInputTokenFields: ["prompt_tokens"],
1304
+ usageOutputTokenFields: ["completion_tokens"]
1305
+ });
1306
+ }
1307
+
1308
+ // src/adapters/openai-compatible.ts
1309
+ var DEFAULT_PRESET = {
1310
+ looseErrorShape: true,
1311
+ allowMissingMetadata: true,
1312
+ useChoicePositionFallback: true,
1313
+ reasoningFieldAliases: ["thinking", "thinking_content"]
1314
+ };
1315
+ var PRESET_OVERRIDES = {
1316
+ openrouter: { reasoningFieldAliases: ["reasoning"] },
1317
+ together: { reasoningFieldAliases: ["reasoning", "reasoning_delta"] }
1318
+ };
1319
+ function openaiCompatibleAdapter(options = {}) {
1320
+ const preset = providerPreset(options.provider ?? "generic");
1321
+ return createOpenAIChatLikeAdapter({
1322
+ ...preset,
1323
+ ...options,
1324
+ errorPrefix: "openaiCompatibleAdapter",
1325
+ usageInputTokenFields: ["prompt_tokens", "input_tokens"],
1326
+ usageOutputTokenFields: ["completion_tokens", "output_tokens"],
1327
+ rejectUnrecognizedPayloads: options.allowMissingMetadata === false,
1328
+ reasoningFieldAliases: [
1329
+ ...preset.reasoningFieldAliases ?? [],
1330
+ ...options.reasoningFieldAliases ?? []
1331
+ ]
1332
+ });
1333
+ }
1334
+ function providerPreset(provider) {
1335
+ return {
1336
+ ...DEFAULT_PRESET,
1337
+ ...PRESET_OVERRIDES[provider]
1338
+ };
1339
+ }
1340
+
1341
+ // src/adapters/anthropic.ts
1342
+ function anthropicAdapter(options = {}) {
1343
+ const parser = new AnthropicStreamParser(options);
1344
+ return createStreamAdapter({
1345
+ parser,
1346
+ parseResponse: parseResponse2,
1347
+ options
1348
+ });
1349
+ }
1350
+ var AnthropicStreamParser = class {
1351
+ constructor(options) {
1352
+ this.options = options;
1353
+ }
1354
+ options;
1355
+ blocks = /* @__PURE__ */ new Map();
1356
+ sawFinish = false;
1357
+ parseChunk(raw) {
1358
+ const payload = parseAdapterJSON(raw, "anthropicAdapter.parseChunk");
1359
+ if (!isRecord(payload)) {
1360
+ throw libraryError("anthropicAdapter.parseChunk expected a JSON object");
1361
+ }
1362
+ const type = asString(payload.type);
1363
+ switch (type) {
1364
+ case "ping":
1365
+ return [];
1366
+ case "message_start":
1367
+ return this.messageStart(payload);
1368
+ case "content_block_start":
1369
+ return this.contentBlockStart(payload);
1370
+ case "content_block_delta":
1371
+ return this.contentBlockDelta(payload);
1372
+ case "content_block_stop":
1373
+ return this.contentBlockStop(payload);
1374
+ case "message_delta":
1375
+ return this.messageDelta(payload);
1376
+ case "message_stop":
1377
+ return this.messageStop();
1378
+ case "error":
1379
+ return providerErrorChunks2(payload.error);
1380
+ default:
1381
+ throw libraryError(`anthropicAdapter.parseChunk unknown event type: ${String(type)}`);
1382
+ }
1383
+ }
1384
+ messageStart(payload) {
1385
+ const message = isRecord(payload.message) ? payload.message : void 0;
1386
+ if (!message) return [];
1387
+ const chunks = [];
1388
+ const id = asString(message.id);
1389
+ const model = asString(message.model);
1390
+ if (id) chunks.push({ kind: "message-start", id });
1391
+ if (id || model) {
1392
+ chunks.push(optionalRawChunk({ kind: "metadata", responseId: id, model, raw: message }));
1393
+ }
1394
+ const usage = usageChunk2(message.usage);
1395
+ if (usage) chunks.push(usage);
1396
+ return chunks;
1397
+ }
1398
+ contentBlockStart(payload) {
1399
+ const index = asNumber(payload.index) ?? 0;
1400
+ const block = isRecord(payload.content_block) ? payload.content_block : void 0;
1401
+ if (!block) return [];
1402
+ const blockType = asString(block.type) ?? "unknown";
1403
+ const state = { type: blockType };
1404
+ this.blocks.set(index, state);
1405
+ switch (blockType) {
1406
+ case "text": {
1407
+ const text = asString(block.text);
1408
+ return text ? [{ kind: "text-delta", text }] : [];
1409
+ }
1410
+ case "thinking": {
1411
+ const text = asString(block.thinking);
1412
+ return text ? [{ kind: "reasoning-delta", text, variant: "detail" }] : [];
1413
+ }
1414
+ case "redacted_thinking":
1415
+ return [];
1416
+ case "tool_use": {
1417
+ const id = asString(block.id);
1418
+ const name = asString(block.name) ?? "unknown";
1419
+ if (id) state.id = id;
1420
+ state.name = name;
1421
+ const chunks = [optionalRawChunk({ kind: "tool-start", id, name, index })];
1422
+ const input = block.input;
1423
+ if (input !== void 0 && !(isRecord(input) && Object.keys(input).length === 0)) {
1424
+ chunks.push(
1425
+ optionalRawChunk({ kind: "tool-args-delta", id, delta: JSON.stringify(input), index })
1426
+ );
1427
+ }
1428
+ return chunks;
1429
+ }
1430
+ case "json": {
1431
+ const text = asString(block.text) ?? asString(block.partial_json);
1432
+ return text ? [{ kind: "json-delta", delta: text }] : [];
1433
+ }
1434
+ case "refusal": {
1435
+ const text = asString(block.refusal) ?? asString(block.text);
1436
+ return text ? [{ kind: "refusal-delta", text }] : [];
1437
+ }
1438
+ default:
1439
+ return [];
1440
+ }
1441
+ }
1442
+ contentBlockDelta(payload) {
1443
+ const index = asNumber(payload.index) ?? 0;
1444
+ const delta = isRecord(payload.delta) ? payload.delta : void 0;
1445
+ if (!delta) return [];
1446
+ const deltaType = asString(delta.type);
1447
+ const state = this.blocks.get(index);
1448
+ switch (deltaType) {
1449
+ case "text_delta": {
1450
+ const text = asString(delta.text);
1451
+ if (!text) return [];
1452
+ if (this.options.jsonMode || state?.type === "json")
1453
+ return [{ kind: "json-delta", delta: text }];
1454
+ if (state?.type === "refusal") return [{ kind: "refusal-delta", text }];
1455
+ return [{ kind: "text-delta", text }];
1456
+ }
1457
+ case "thinking_delta": {
1458
+ const text = asString(delta.thinking);
1459
+ return text ? [{ kind: "reasoning-delta", text, variant: "detail" }] : [];
1460
+ }
1461
+ case "input_json_delta": {
1462
+ const partial = asString(delta.partial_json);
1463
+ if (!partial) return [];
1464
+ return [
1465
+ optionalRawChunk({ kind: "tool-args-delta", id: state?.id, delta: partial, index })
1466
+ ];
1467
+ }
1468
+ case "signature_delta":
1469
+ return [];
1470
+ default:
1471
+ return [];
1472
+ }
1473
+ }
1474
+ contentBlockStop(payload) {
1475
+ const index = asNumber(payload.index) ?? 0;
1476
+ const state = this.blocks.get(index);
1477
+ this.blocks.delete(index);
1478
+ if (state?.type === "tool_use") {
1479
+ return [optionalRawChunk({ kind: "tool-done", id: state.id, index })];
1480
+ }
1481
+ return [];
1482
+ }
1483
+ messageDelta(payload) {
1484
+ const chunks = [];
1485
+ const usage = usageChunk2(payload.usage);
1486
+ if (usage) chunks.push(usage);
1487
+ const delta = isRecord(payload.delta) ? payload.delta : void 0;
1488
+ const stopReason = delta ? asString(delta.stop_reason) : void 0;
1489
+ if (stopReason) {
1490
+ const reason = finishReason(stopReason);
1491
+ if (reason) chunks.push({ kind: "finish", reason });
1492
+ this.sawFinish = true;
1493
+ }
1494
+ return chunks;
1495
+ }
1496
+ messageStop() {
1497
+ if (this.sawFinish) return [];
1498
+ this.sawFinish = true;
1499
+ return [{ kind: "finish", reason: "stop" }];
1500
+ }
1501
+ };
1502
+ function parseResponse2(body, options) {
1503
+ if (!isRecord(body)) {
1504
+ throw libraryError("anthropicAdapter.parseResponse expected an Anthropic message object");
1505
+ }
1506
+ if (asString(body.type) === "error" || isRecord(body.error)) {
1507
+ return providerErrorChunks2(body.error);
1508
+ }
1509
+ const chunks = [];
1510
+ const id = asString(body.id);
1511
+ const model = asString(body.model);
1512
+ if (id) chunks.push({ kind: "message-start", id });
1513
+ if (id || model)
1514
+ chunks.push(optionalRawChunk({ kind: "metadata", responseId: id, model, raw: body }));
1515
+ const inputUsage = usageChunk2(body.usage);
1516
+ if (inputUsage) chunks.push(inputUsage);
1517
+ const content = Array.isArray(body.content) ? body.content : [];
1518
+ for (let index = 0; index < content.length; index += 1) {
1519
+ const block = content[index];
1520
+ if (!isRecord(block)) continue;
1521
+ chunks.push(...responseBlockChunks(block, index, options));
1522
+ }
1523
+ const reason = finishReason(asString(body.stop_reason));
1524
+ if (reason) chunks.push({ kind: "finish", reason });
1525
+ return chunks;
1526
+ }
1527
+ function responseBlockChunks(block, index, options) {
1528
+ const type = asString(block.type);
1529
+ switch (type) {
1530
+ case "text": {
1531
+ const text = asString(block.text);
1532
+ if (!text) return [];
1533
+ return options.jsonMode ? [{ kind: "json-delta", delta: text }] : [{ kind: "text-delta", text }];
1534
+ }
1535
+ case "thinking": {
1536
+ const text = asString(block.thinking);
1537
+ return text ? [{ kind: "reasoning-delta", text, variant: "detail" }] : [];
1538
+ }
1539
+ case "tool_use": {
1540
+ const id = asString(block.id);
1541
+ const name = asString(block.name) ?? "unknown";
1542
+ const chunks = [optionalRawChunk({ kind: "tool-start", id, name, index })];
1543
+ if (block.input !== void 0) {
1544
+ chunks.push(
1545
+ optionalRawChunk({
1546
+ kind: "tool-args-delta",
1547
+ id,
1548
+ delta: JSON.stringify(block.input),
1549
+ index
1550
+ })
1551
+ );
1552
+ }
1553
+ chunks.push(optionalRawChunk({ kind: "tool-done", id, index }));
1554
+ return chunks;
1555
+ }
1556
+ case "refusal": {
1557
+ const text = asString(block.refusal) ?? asString(block.text);
1558
+ return text ? [{ kind: "refusal-delta", text }] : [];
1559
+ }
1560
+ default:
1561
+ return [];
1562
+ }
1563
+ }
1564
+ function finishReason(value) {
1565
+ switch (value) {
1566
+ case "end_turn":
1567
+ case "stop_sequence":
1568
+ return "stop";
1569
+ case "max_tokens":
1570
+ return "length";
1571
+ case "tool_use":
1572
+ return "tool_calls";
1573
+ case "refusal":
1574
+ return "content_filter";
1575
+ case void 0:
1576
+ case null:
1577
+ return void 0;
1578
+ default:
1579
+ return "stop";
1580
+ }
1581
+ }
1582
+ function usageChunk2(value) {
1583
+ if (!isRecord(value)) return void 0;
1584
+ const inputTokens = asNumber(value.input_tokens);
1585
+ const outputTokens = asNumber(value.output_tokens);
1586
+ if (inputTokens === void 0 && outputTokens === void 0) return void 0;
1587
+ return optionalRawChunk({ kind: "usage", inputTokens, outputTokens, raw: value });
1588
+ }
1589
+ function providerErrorChunks2(value) {
1590
+ const message = isRecord(value) ? asString(value.message) : void 0;
1591
+ return providerErrorChunksFromMessage(message ?? "Anthropic provider error", false);
1592
+ }
1593
+
1594
+ // src/adapters/openai-responses.ts
1595
+ function openaiResponsesAdapter(options = {}) {
1596
+ const parser = new ResponsesParser(options);
1597
+ return createStreamAdapter({
1598
+ parser,
1599
+ parseResponse: parseResponse3,
1600
+ options
1601
+ });
1602
+ }
1603
+ var ResponsesParser = class {
1604
+ constructor(options) {
1605
+ this.options = options;
1606
+ }
1607
+ options;
1608
+ metadataEmitted = false;
1609
+ textSeen = false;
1610
+ tools = /* @__PURE__ */ new Map();
1611
+ aliases = /* @__PURE__ */ new Map();
1612
+ parseChunk(raw) {
1613
+ if (raw.trim() === "[DONE]") return [];
1614
+ const payload = parseAdapterJSON(raw, "openaiResponsesAdapter.parseChunk");
1615
+ if (!isRecord(payload)) {
1616
+ throw libraryError("openaiResponsesAdapter.parseChunk expected a JSON object");
1617
+ }
1618
+ if (isErrorPayload(payload)) return providerErrorChunks3(errorMessage(payload));
1619
+ const chunks = [];
1620
+ const response = isRecord(payload.response) ? payload.response : payload;
1621
+ if (!this.metadataEmitted && isRecord(response) && hasResponseMetadata(response)) {
1622
+ chunks.push(...metadataChunks2(response));
1623
+ this.metadataEmitted = true;
1624
+ }
1625
+ const type = asString(payload.type);
1626
+ switch (type) {
1627
+ case "response.created":
1628
+ case "response.in_progress":
1629
+ break;
1630
+ case "response.output_text.delta":
1631
+ chunks.push(...this.textDelta(payload));
1632
+ break;
1633
+ case "response.output_text.done":
1634
+ chunks.push(...this.textDone(payload));
1635
+ break;
1636
+ case "response.refusal.delta":
1637
+ chunks.push(...refusalDelta(payload));
1638
+ break;
1639
+ case "response.refusal.done":
1640
+ break;
1641
+ case "response.content_part.added":
1642
+ case "response.content_part.done":
1643
+ chunks.push(...contentPartChunks(payload, this.options));
1644
+ break;
1645
+ case "response.output_item.added":
1646
+ chunks.push(...this.outputItemAdded(payload));
1647
+ break;
1648
+ case "response.output_item.delta":
1649
+ chunks.push(...this.outputItemDelta(payload));
1650
+ break;
1651
+ case "response.output_item.done":
1652
+ chunks.push(...this.outputItemDone(payload));
1653
+ break;
1654
+ case "response.function_call_arguments.delta":
1655
+ chunks.push(...this.functionArgsDelta(payload));
1656
+ break;
1657
+ case "response.function_call_arguments.done":
1658
+ chunks.push(...this.functionArgsDone(payload));
1659
+ break;
1660
+ case "response.completed":
1661
+ chunks.push(...usageFromResponse(response));
1662
+ chunks.push({ kind: "finish", reason: "stop" });
1663
+ break;
1664
+ case "response.failed":
1665
+ chunks.push(...providerErrorChunks3(errorMessage(response)));
1666
+ break;
1667
+ case "response.incomplete":
1668
+ chunks.push(...usageFromResponse(response));
1669
+ chunks.push({ kind: "finish", reason: "incomplete" });
1670
+ break;
1671
+ case "error":
1672
+ chunks.push(...providerErrorChunks3(errorMessage(payload)));
1673
+ break;
1674
+ default:
1675
+ chunks.push(...reasoningChunks2(payload));
1676
+ break;
1677
+ }
1678
+ return chunks;
1679
+ }
1680
+ textDelta(payload) {
1681
+ const text = asString(payload.delta) ?? asString(payload.text);
1682
+ if (!text) return [];
1683
+ this.textSeen = true;
1684
+ return [
1685
+ this.options.jsonMode ? { kind: "json-delta", delta: text } : { kind: "text-delta", text }
1686
+ ];
1687
+ }
1688
+ textDone(payload) {
1689
+ if (this.textSeen) return [];
1690
+ const text = asString(payload.text) ?? asString(payload.delta);
1691
+ if (!text) return [];
1692
+ this.textSeen = true;
1693
+ return [
1694
+ this.options.jsonMode ? { kind: "json-delta", delta: text } : { kind: "text-delta", text }
1695
+ ];
1696
+ }
1697
+ outputItemAdded(payload) {
1698
+ const item = isRecord(payload.item) ? payload.item : void 0;
1699
+ if (!item) return [];
1700
+ if (asString(item.type) === "function_call") {
1701
+ const state = this.toolState(payload, item);
1702
+ const chunks = [];
1703
+ if (!state.started) {
1704
+ chunks.push(
1705
+ optionalRawChunk({
1706
+ kind: "tool-start",
1707
+ id: state.id,
1708
+ name: state.name,
1709
+ index: state.index
1710
+ })
1711
+ );
1712
+ state.started = true;
1713
+ }
1714
+ const args = asString(item.arguments);
1715
+ if (args && state.args.length === 0) {
1716
+ state.args += args;
1717
+ chunks.push(
1718
+ optionalRawChunk({
1719
+ kind: "tool-args-delta",
1720
+ id: state.id,
1721
+ delta: args,
1722
+ index: state.index
1723
+ })
1724
+ );
1725
+ }
1726
+ return chunks;
1727
+ }
1728
+ return messageItemChunks(item, this.options);
1729
+ }
1730
+ outputItemDelta(payload) {
1731
+ const delta = isRecord(payload.delta) ? payload.delta : payload;
1732
+ const args = asString(delta.arguments) ?? asString(delta.delta);
1733
+ if (!args) return [];
1734
+ const state = this.toolState(payload, delta);
1735
+ const chunks = [];
1736
+ if (!state.started) {
1737
+ chunks.push(
1738
+ optionalRawChunk({
1739
+ kind: "tool-start",
1740
+ id: state.id,
1741
+ name: state.name,
1742
+ index: state.index
1743
+ })
1744
+ );
1745
+ state.started = true;
1746
+ }
1747
+ state.args += args;
1748
+ chunks.push(
1749
+ optionalRawChunk({ kind: "tool-args-delta", id: state.id, delta: args, index: state.index })
1750
+ );
1751
+ return chunks;
1752
+ }
1753
+ outputItemDone(payload) {
1754
+ const item = isRecord(payload.item) ? payload.item : payload;
1755
+ if (asString(item.type) !== "function_call") return messageItemChunks(item, this.options);
1756
+ const state = this.toolState(payload, item);
1757
+ if (state.done) return [];
1758
+ state.done = true;
1759
+ return [optionalRawChunk({ kind: "tool-done", id: state.id, index: state.index })];
1760
+ }
1761
+ functionArgsDelta(payload) {
1762
+ const delta = asString(payload.delta);
1763
+ if (!delta) return [];
1764
+ const state = this.toolState(payload);
1765
+ const chunks = [];
1766
+ if (!state.started) {
1767
+ chunks.push(
1768
+ optionalRawChunk({
1769
+ kind: "tool-start",
1770
+ id: state.id,
1771
+ name: state.name,
1772
+ index: state.index
1773
+ })
1774
+ );
1775
+ state.started = true;
1776
+ }
1777
+ state.args += delta;
1778
+ chunks.push(
1779
+ optionalRawChunk({ kind: "tool-args-delta", id: state.id, delta, index: state.index })
1780
+ );
1781
+ return chunks;
1782
+ }
1783
+ functionArgsDone(payload) {
1784
+ const state = this.toolState(payload);
1785
+ const chunks = [];
1786
+ const finalArgs = asString(payload.arguments);
1787
+ if (finalArgs && finalArgs !== state.args && !finalArgs.startsWith(state.args)) {
1788
+ chunks.push(
1789
+ optionalRawChunk({
1790
+ kind: "tool-args-delta",
1791
+ id: state.id,
1792
+ delta: finalArgs,
1793
+ index: state.index
1794
+ })
1795
+ );
1796
+ state.args += finalArgs;
1797
+ } else if (finalArgs && finalArgs.startsWith(state.args) && finalArgs.length > state.args.length) {
1798
+ const missing = finalArgs.slice(state.args.length);
1799
+ chunks.push(
1800
+ optionalRawChunk({
1801
+ kind: "tool-args-delta",
1802
+ id: state.id,
1803
+ delta: missing,
1804
+ index: state.index
1805
+ })
1806
+ );
1807
+ state.args = finalArgs;
1808
+ }
1809
+ if (!state.started) {
1810
+ chunks.unshift(
1811
+ optionalRawChunk({
1812
+ kind: "tool-start",
1813
+ id: state.id,
1814
+ name: state.name,
1815
+ index: state.index
1816
+ })
1817
+ );
1818
+ state.started = true;
1819
+ }
1820
+ if (!state.done) {
1821
+ chunks.push(optionalRawChunk({ kind: "tool-done", id: state.id, index: state.index }));
1822
+ state.done = true;
1823
+ }
1824
+ return chunks;
1825
+ }
1826
+ toolState(payload, item) {
1827
+ const id = toolId(payload, item);
1828
+ const index = asNumber(payload.output_index);
1829
+ const existing = this.tools.get(id);
1830
+ if (existing) {
1831
+ const callId2 = asString(item?.call_id) ?? asString(payload.call_id);
1832
+ const itemId2 = asString(item?.id) ?? asString(payload.item_id);
1833
+ if (callId2) this.aliases.set(callId2, id);
1834
+ if (itemId2) this.aliases.set(itemId2, id);
1835
+ return existing;
1836
+ }
1837
+ const state = {
1838
+ id,
1839
+ name: asString(item?.name) ?? "unknown",
1840
+ index,
1841
+ args: "",
1842
+ started: false,
1843
+ done: false
1844
+ };
1845
+ this.tools.set(id, state);
1846
+ const callId = asString(item?.call_id) ?? asString(payload.call_id);
1847
+ const itemId = asString(item?.id) ?? asString(payload.item_id);
1848
+ if (callId) this.aliases.set(callId, id);
1849
+ if (itemId) this.aliases.set(itemId, id);
1850
+ return state;
1851
+ }
1852
+ };
1853
+ function parseResponse3(body, options) {
1854
+ if (!isRecord(body)) {
1855
+ throw libraryError("openaiResponsesAdapter.parseResponse expected an OpenAI Responses object");
1856
+ }
1857
+ if (isErrorPayload(body) || asString(body.status) === "failed") {
1858
+ return providerErrorChunks3(errorMessage(body));
1859
+ }
1860
+ const chunks = [];
1861
+ chunks.push(...metadataChunks2(body));
1862
+ const output = Array.isArray(body.output) ? body.output : [];
1863
+ for (let index = 0; index < output.length; index += 1) {
1864
+ const item = output[index];
1865
+ if (!isRecord(item)) continue;
1866
+ if (asString(item.type) === "function_call") {
1867
+ const id = asString(item.call_id) ?? asString(item.id) ?? `response_tool:${index}`;
1868
+ const name = asString(item.name) ?? "unknown";
1869
+ chunks.push({ kind: "tool-start", id, name, index });
1870
+ const args = asString(item.arguments);
1871
+ if (args) chunks.push({ kind: "tool-args-delta", id, delta: args, index });
1872
+ chunks.push({ kind: "tool-done", id, index });
1873
+ } else {
1874
+ chunks.push(...messageItemChunks(item, options));
1875
+ }
1876
+ }
1877
+ chunks.push(...usageFromResponse(body));
1878
+ const status = asString(body.status);
1879
+ if (status === "incomplete") chunks.push({ kind: "finish", reason: "incomplete" });
1880
+ else chunks.push({ kind: "finish", reason: "stop" });
1881
+ return chunks;
1882
+ }
1883
+ function metadataChunks2(response) {
1884
+ const id = asString(response.id);
1885
+ const chunks = [];
1886
+ if (id) chunks.push({ kind: "message-start", id });
1887
+ const metadata = optionalRawChunk({
1888
+ kind: "metadata",
1889
+ responseId: id,
1890
+ model: asString(response.model),
1891
+ created: asNumber(response.created_at),
1892
+ raw: response
1893
+ });
1894
+ if (metadata.kind === "metadata" && (metadata.responseId || metadata.model || metadata.created)) {
1895
+ chunks.push(metadata);
1896
+ }
1897
+ return chunks;
1898
+ }
1899
+ function hasResponseMetadata(response) {
1900
+ return asString(response.id) !== void 0 || asString(response.model) !== void 0 || asNumber(response.created_at) !== void 0;
1901
+ }
1902
+ function messageItemChunks(item, options) {
1903
+ const chunks = [];
1904
+ const content = Array.isArray(item.content) ? item.content : [];
1905
+ for (const part of content) {
1906
+ if (!isRecord(part)) continue;
1907
+ const type = asString(part.type);
1908
+ const text = asString(part.text) ?? asString(part.delta);
1909
+ const refusal = asString(part.refusal);
1910
+ if (type === "output_text" && text) chunks.push(textChunk(text, options));
1911
+ if (type === "refusal" && (refusal || text))
1912
+ chunks.push({ kind: "refusal-delta", text: refusal ?? text ?? "" });
1913
+ }
1914
+ const directText = asString(item.text);
1915
+ if (directText) chunks.push(textChunk(directText, options));
1916
+ chunks.push(...reasoningChunks2(item));
1917
+ return chunks;
1918
+ }
1919
+ function contentPartChunks(payload, options) {
1920
+ const part = isRecord(payload.part) ? payload.part : isRecord(payload.content_part) ? payload.content_part : payload;
1921
+ return messageItemChunks({ content: [part] }, options);
1922
+ }
1923
+ function refusalDelta(payload) {
1924
+ const text = asString(payload.delta) ?? asString(payload.refusal) ?? asString(payload.text);
1925
+ return text ? [{ kind: "refusal-delta", text }] : [];
1926
+ }
1927
+ function reasoningChunks2(payload) {
1928
+ const chunks = [];
1929
+ for (const field of ["reasoning", "reasoning_text", "summary"]) {
1930
+ const text = asString(payload[field]);
1931
+ if (text)
1932
+ chunks.push({
1933
+ kind: "reasoning-delta",
1934
+ text,
1935
+ variant: field === "summary" ? "summary" : "detail"
1936
+ });
1937
+ }
1938
+ return chunks;
1939
+ }
1940
+ function usageFromResponse(response) {
1941
+ const usage = isRecord(response.usage) ? response.usage : void 0;
1942
+ if (!usage) return [];
1943
+ const inputTokens = asNumber(usage.input_tokens);
1944
+ const outputTokens = asNumber(usage.output_tokens);
1945
+ const details = isRecord(usage.output_tokens_details) ? usage.output_tokens_details : void 0;
1946
+ const reasoningTokens = details ? asNumber(details.reasoning_tokens) : void 0;
1947
+ if (inputTokens === void 0 && outputTokens === void 0 && reasoningTokens === void 0)
1948
+ return [];
1949
+ return [
1950
+ optionalRawChunk({
1951
+ kind: "usage",
1952
+ inputTokens,
1953
+ outputTokens,
1954
+ reasoningTokens,
1955
+ raw: usage
1956
+ })
1957
+ ];
1958
+ }
1959
+ function textChunk(text, options) {
1960
+ return options.jsonMode ? { kind: "json-delta", delta: text } : { kind: "text-delta", text };
1961
+ }
1962
+ function providerErrorChunks3(message) {
1963
+ return providerErrorChunksFromMessage(message, false);
1964
+ }
1965
+ function errorMessage(payload) {
1966
+ const error = isRecord(payload.error) ? payload.error : void 0;
1967
+ return asString(error?.message) ?? asString(payload.message) ?? asString(payload.error) ?? "OpenAI Responses provider error";
1968
+ }
1969
+ function isErrorPayload(payload) {
1970
+ return asString(payload.type) === "error" || payload.error !== void 0;
1971
+ }
1972
+ function toolId(payload, item) {
1973
+ const callId = asString(item?.call_id) ?? asString(payload.call_id);
1974
+ const itemId = asString(item?.id) ?? asString(payload.item_id);
1975
+ const index = asNumber(payload.output_index);
1976
+ return callId ?? itemId ?? `response_tool:${index ?? 0}`;
1977
+ }
1978
+
1979
+ // src/transforms/collect-stream.ts
1980
+ async function collectStream(events) {
1981
+ const result = {
1982
+ text: "",
1983
+ reasoning: "",
1984
+ refusals: "",
1985
+ json: void 0,
1986
+ toolCalls: []
1987
+ };
1988
+ const iterator = events[Symbol.asyncIterator]();
1989
+ try {
1990
+ while (true) {
1991
+ const item = await iterator.next();
1992
+ if (item.done) break;
1993
+ collectEvent(result, item.value);
1994
+ }
1995
+ return result;
1996
+ } catch (error) {
1997
+ await iterator.return?.();
1998
+ throw error;
1999
+ }
2000
+ }
2001
+ function collectEvent(result, event) {
2002
+ switch (event.type) {
2003
+ case "text.delta":
2004
+ result.text += event.text;
2005
+ break;
2006
+ case "text.done":
2007
+ result.text = preferDone(result.text, event.text);
2008
+ break;
2009
+ case "reasoning.delta":
2010
+ result.reasoning += event.text;
2011
+ break;
2012
+ case "reasoning.done":
2013
+ result.reasoning = preferDone(result.reasoning, event.text);
2014
+ break;
2015
+ case "refusal.delta":
2016
+ result.refusals += event.text;
2017
+ break;
2018
+ case "refusal.done":
2019
+ result.refusals = preferDone(result.refusals, event.text);
2020
+ break;
2021
+ case "json.done":
2022
+ result.json = event.value;
2023
+ break;
2024
+ case "tool_call.done":
2025
+ result.toolCalls.push({ id: event.id, name: event.name, args: event.args });
2026
+ break;
2027
+ case "usage":
2028
+ result.usage = event;
2029
+ break;
2030
+ case "finish":
2031
+ result.finishReason = event;
2032
+ break;
2033
+ case "error":
2034
+ if (event.recoverable !== true) throw event.error;
2035
+ break;
2036
+ }
2037
+ }
2038
+ function preferDone(current, done) {
2039
+ if (current === "" || current === done || done.startsWith(current)) return done;
2040
+ if (current.endsWith(done)) return current;
2041
+ return done;
2042
+ }
2043
+
2044
+ // src/transforms/to-sse.ts
2045
+ function toSSE(events, options = {}) {
2046
+ const iterator = events[Symbol.asyncIterator]();
2047
+ const encoder2 = new TextEncoder();
2048
+ let closed = false;
2049
+ return new ReadableStream({
2050
+ async pull(controller) {
2051
+ if (closed) return;
2052
+ try {
2053
+ const item = await iterator.next();
2054
+ if (item.done) {
2055
+ closed = true;
2056
+ controller.close();
2057
+ return;
2058
+ }
2059
+ const event = item.value;
2060
+ controller.enqueue(
2061
+ encoder2.encode(`data: ${JSON.stringify(serializeEvent(event, options))}
2062
+
2063
+ `)
2064
+ );
2065
+ if (event.type === "finish") {
2066
+ closed = true;
2067
+ await iterator.return?.();
2068
+ controller.close();
2069
+ }
2070
+ } catch (error) {
2071
+ closed = true;
2072
+ await iterator.return?.();
2073
+ controller.error(error);
2074
+ }
2075
+ },
2076
+ async cancel() {
2077
+ closed = true;
2078
+ await iterator.return?.();
2079
+ }
2080
+ });
2081
+ }
2082
+ function serializeEvent(event, options) {
2083
+ if (event.type !== "error") return event;
2084
+ const message = options.sanitizeErrors ? event.sanitized ?? "An error occurred while processing the stream." : event.error.message;
2085
+ return {
2086
+ type: "error",
2087
+ error: {
2088
+ name: event.error.name,
2089
+ message
2090
+ },
2091
+ ...event.recoverable === void 0 ? {} : { recoverable: event.recoverable },
2092
+ ...event.sanitized === void 0 ? {} : { sanitized: event.sanitized }
2093
+ };
2094
+ }
2095
+
2096
+ // src/transforms/tap-events.ts
2097
+ function tapEvents(events, onEvent) {
2098
+ return tapEventsGenerator(events, onEvent);
2099
+ }
2100
+ async function* tapEventsGenerator(events, onEvent) {
2101
+ const iterator = events[Symbol.asyncIterator]();
2102
+ try {
2103
+ while (true) {
2104
+ const item = await iterator.next();
2105
+ if (item.done) break;
2106
+ onEvent(item.value);
2107
+ yield item.value;
2108
+ }
2109
+ } finally {
2110
+ await iterator.return?.();
2111
+ }
2112
+ }
2113
+
2114
+ // src/helpers/match-event.ts
2115
+ function matchEvent(event, handlers) {
2116
+ switch (event.type) {
2117
+ case "message.start":
2118
+ return handlers["message.start"]?.(event);
2119
+ case "metadata":
2120
+ return handlers.metadata?.(event);
2121
+ case "text.delta":
2122
+ return handlers["text.delta"]?.(event);
2123
+ case "text.done":
2124
+ return handlers["text.done"]?.(event);
2125
+ case "reasoning.delta":
2126
+ return handlers["reasoning.delta"]?.(event);
2127
+ case "reasoning.done":
2128
+ return handlers["reasoning.done"]?.(event);
2129
+ case "refusal.delta":
2130
+ return handlers["refusal.delta"]?.(event);
2131
+ case "refusal.done":
2132
+ return handlers["refusal.done"]?.(event);
2133
+ case "json.delta":
2134
+ return handlers["json.delta"]?.(event);
2135
+ case "json.done":
2136
+ return handlers["json.done"]?.(event);
2137
+ case "tool_call.start":
2138
+ return handlers["tool_call.start"]?.(event);
2139
+ case "tool_call.args.delta":
2140
+ return handlers["tool_call.args.delta"]?.(event);
2141
+ case "tool_call.done":
2142
+ return handlers["tool_call.done"]?.(event);
2143
+ case "usage":
2144
+ return handlers.usage?.(event);
2145
+ case "finish":
2146
+ return handlers.finish?.(event);
2147
+ case "error":
2148
+ return handlers.error?.(event);
2149
+ default: {
2150
+ const _exhaustive = event;
2151
+ return _exhaustive;
2152
+ }
2153
+ }
2154
+ }
2155
+
2156
+ // src/helpers/type-guards.ts
2157
+ function isMessageStart(event) {
2158
+ return event.type === "message.start";
2159
+ }
2160
+ function isMetadata(event) {
2161
+ return event.type === "metadata";
2162
+ }
2163
+ function isTextDelta(event) {
2164
+ return event.type === "text.delta";
2165
+ }
2166
+ function isTextDone(event) {
2167
+ return event.type === "text.done";
2168
+ }
2169
+ function isReasoningDelta(event) {
2170
+ return event.type === "reasoning.delta";
2171
+ }
2172
+ function isReasoningDone(event) {
2173
+ return event.type === "reasoning.done";
2174
+ }
2175
+ function isRefusalDelta(event) {
2176
+ return event.type === "refusal.delta";
2177
+ }
2178
+ function isRefusalDone(event) {
2179
+ return event.type === "refusal.done";
2180
+ }
2181
+ function isJsonDelta(event) {
2182
+ return event.type === "json.delta";
2183
+ }
2184
+ function isJsonDone(event) {
2185
+ return event.type === "json.done";
2186
+ }
2187
+ function isToolCallStart(event) {
2188
+ return event.type === "tool_call.start";
2189
+ }
2190
+ function isToolCallArgsDelta(event) {
2191
+ return event.type === "tool_call.args.delta";
2192
+ }
2193
+ function isToolCallDone(event) {
2194
+ return event.type === "tool_call.done";
2195
+ }
2196
+ function isUsage(event) {
2197
+ return event.type === "usage";
2198
+ }
2199
+ function isFinish(event) {
2200
+ return event.type === "finish";
2201
+ }
2202
+ function isError(event) {
2203
+ return event.type === "error";
2204
+ }
2205
+
2206
+ exports.anthropicAdapter = anthropicAdapter;
2207
+ exports.assembleFromFile = assembleFromFile;
2208
+ exports.assembleFromPayloads = assembleFromPayloads;
2209
+ exports.assembleResponse = assembleResponse;
2210
+ exports.assembleStream = assembleStream;
2211
+ exports.collectStream = collectStream;
2212
+ exports.createAssemblyTransform = createAssemblyTransform;
2213
+ exports.isError = isError;
2214
+ exports.isFinish = isFinish;
2215
+ exports.isJsonDelta = isJsonDelta;
2216
+ exports.isJsonDone = isJsonDone;
2217
+ exports.isMessageStart = isMessageStart;
2218
+ exports.isMetadata = isMetadata;
2219
+ exports.isReasoningDelta = isReasoningDelta;
2220
+ exports.isReasoningDone = isReasoningDone;
2221
+ exports.isRefusalDelta = isRefusalDelta;
2222
+ exports.isRefusalDone = isRefusalDone;
2223
+ exports.isTextDelta = isTextDelta;
2224
+ exports.isTextDone = isTextDone;
2225
+ exports.isToolCallArgsDelta = isToolCallArgsDelta;
2226
+ exports.isToolCallDone = isToolCallDone;
2227
+ exports.isToolCallStart = isToolCallStart;
2228
+ exports.isUsage = isUsage;
2229
+ exports.matchEvent = matchEvent;
2230
+ exports.openaiChatAdapter = openaiChatAdapter;
2231
+ exports.openaiCompatibleAdapter = openaiCompatibleAdapter;
2232
+ exports.openaiResponsesAdapter = openaiResponsesAdapter;
2233
+ exports.parsePartialJSON = parsePartialJSON;
2234
+ exports.parseSSE = parseSSE;
2235
+ exports.tapEvents = tapEvents;
2236
+ exports.toSSE = toSSE;
2237
+ //# sourceMappingURL=index.cjs.map
2238
+ //# sourceMappingURL=index.cjs.map