@ai-sdk-tool/parser 2.1.7 → 3.0.0-canary.1

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.
@@ -0,0 +1,3168 @@
1
+ // src/protocols/json-mix-protocol.ts
2
+ import { generateId } from "@ai-sdk/provider-utils";
3
+
4
+ // src/utils/debug.ts
5
+ var LINE_SPLIT_REGEX = /\r?\n/;
6
+ function normalizeBooleanString(value) {
7
+ const normalized = value.trim().toLowerCase();
8
+ if (normalized === "1" || normalized === "true" || normalized === "yes") {
9
+ return true;
10
+ }
11
+ if (normalized === "0" || normalized === "false" || normalized === "no") {
12
+ return false;
13
+ }
14
+ return;
15
+ }
16
+ function getDebugLevel() {
17
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW || "off";
18
+ const envLower = String(envVal).toLowerCase();
19
+ if (envLower === "stream" || envLower === "parse" || envLower === "off") {
20
+ return envLower;
21
+ }
22
+ const boolEnv = normalizeBooleanString(envLower);
23
+ if (boolEnv === true) {
24
+ return "stream";
25
+ }
26
+ if (envLower === "2") {
27
+ return "parse";
28
+ }
29
+ return "off";
30
+ }
31
+ function color(code) {
32
+ return (text) => `\x1B[${code}m${text}\x1B[0m`;
33
+ }
34
+ var ANSI_GRAY = 90;
35
+ var ANSI_YELLOW = 33;
36
+ var ANSI_CYAN = 36;
37
+ var ANSI_BG_BLUE = 44;
38
+ var ANSI_BG_GREEN = 42;
39
+ var ANSI_INVERSE = 7;
40
+ var ANSI_UNDERLINE = 4;
41
+ var ANSI_BOLD = 1;
42
+ var cGray = color(ANSI_GRAY);
43
+ var cYellow = color(ANSI_YELLOW);
44
+ var cCyan = color(ANSI_CYAN);
45
+ var cBgBlue = color(ANSI_BG_BLUE);
46
+ var cBgGreen = color(ANSI_BG_GREEN);
47
+ var cInverse = color(ANSI_INVERSE);
48
+ var cUnderline = color(ANSI_UNDERLINE);
49
+ var cBold = color(ANSI_BOLD);
50
+ var MAX_SNIPPET_LENGTH = 800;
51
+ function safeStringify(value) {
52
+ try {
53
+ return `
54
+ ${typeof value === "string" ? value : JSON.stringify(value, null, 2)}`;
55
+ } catch (e) {
56
+ return String(value);
57
+ }
58
+ }
59
+ function formatError(error) {
60
+ if (error instanceof Error) {
61
+ const stack = error.stack ? `
62
+ ${error.stack}` : "";
63
+ return `
64
+ ${error.name}: ${error.message}${stack}`;
65
+ }
66
+ return safeStringify(error);
67
+ }
68
+ function truncateSnippet(snippet) {
69
+ if (snippet.length <= MAX_SNIPPET_LENGTH) {
70
+ return snippet;
71
+ }
72
+ return `${snippet.slice(0, MAX_SNIPPET_LENGTH)}
73
+ \u2026[truncated ${snippet.length - MAX_SNIPPET_LENGTH} chars]`;
74
+ }
75
+ function logParseFailure({
76
+ phase,
77
+ reason,
78
+ snippet,
79
+ error
80
+ }) {
81
+ if (getDebugLevel() !== "parse") {
82
+ return;
83
+ }
84
+ const label = cBgBlue(`[${phase}]`);
85
+ console.log(cGray("[debug:mw:fail]"), label, cYellow(reason));
86
+ if (snippet) {
87
+ const formatted = truncateSnippet(snippet);
88
+ console.log(cGray("[debug:mw:fail:snippet]"), formatted);
89
+ }
90
+ if (error) {
91
+ console.log(cGray("[debug:mw:fail:error]"), cCyan(formatError(error)));
92
+ }
93
+ }
94
+ function logRawChunk(part) {
95
+ console.log(cGray("[debug:mw:raw]"), cYellow(safeStringify(part)));
96
+ }
97
+ function logParsedChunk(part) {
98
+ console.log(cGray("[debug:mw:out]"), cCyan(safeStringify(part)));
99
+ }
100
+ function getHighlightStyle() {
101
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW_STYLE || "bg";
102
+ const normalized = String(envVal).trim().toLowerCase();
103
+ if (normalized === "inverse" || normalized === "invert") {
104
+ return "inverse";
105
+ }
106
+ if (normalized === "underline" || normalized === "ul") {
107
+ return "underline";
108
+ }
109
+ if (normalized === "bold") {
110
+ return "bold";
111
+ }
112
+ if (normalized === "bg" || normalized === "background") {
113
+ return "bg";
114
+ }
115
+ const asBool = normalizeBooleanString(normalized);
116
+ if (asBool === true) {
117
+ return "bg";
118
+ }
119
+ return "bg";
120
+ }
121
+ function getHighlightFunction(style) {
122
+ if (style === "inverse") {
123
+ return cInverse;
124
+ }
125
+ if (style === "underline") {
126
+ return cUnderline;
127
+ }
128
+ if (style === "bold") {
129
+ return cBold;
130
+ }
131
+ if (style === "bg") {
132
+ return cBgGreen;
133
+ }
134
+ return cYellow;
135
+ }
136
+ function renderHighlightedText(originalText, style, highlight) {
137
+ if (style === "bg" || style === "inverse" || style === "underline" || style === "bold") {
138
+ return originalText.split(LINE_SPLIT_REGEX).map((line) => line.length ? highlight(line) : line).join("\n");
139
+ }
140
+ return highlight(originalText);
141
+ }
142
+ function logParsedSummary({
143
+ toolCalls,
144
+ originalText
145
+ }) {
146
+ if (originalText) {
147
+ const style = getHighlightStyle();
148
+ const highlight = getHighlightFunction(style);
149
+ const rendered = renderHighlightedText(originalText, style, highlight);
150
+ console.log(cGray("[debug:mw:origin]"), `
151
+ ${rendered}`);
152
+ }
153
+ if (toolCalls.length > 0) {
154
+ const styledSummary = safeStringify(toolCalls).split(LINE_SPLIT_REGEX).map((line) => line.length ? cBgBlue(line) : line).join("\n");
155
+ console.log(cGray("[debug:mw:summary]"), styledSummary);
156
+ }
157
+ }
158
+
159
+ // src/utils/get-potential-start-index.ts
160
+ function getPotentialStartIndex(text, searchedText) {
161
+ if (searchedText.length === 0) {
162
+ return null;
163
+ }
164
+ const directIndex = text.indexOf(searchedText);
165
+ if (directIndex !== -1) {
166
+ return directIndex;
167
+ }
168
+ for (let i = text.length - 1; i >= 0; i -= 1) {
169
+ const suffix = text.substring(i);
170
+ if (searchedText.startsWith(suffix)) {
171
+ return i;
172
+ }
173
+ }
174
+ return null;
175
+ }
176
+
177
+ // src/utils/regex.ts
178
+ function escapeRegExp(literal) {
179
+ return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
180
+ }
181
+
182
+ // src/utils/robust-json.ts
183
+ var WHITESPACE_TEST_REGEX = /\s/;
184
+ var WHITESPACE_REGEX = /^\s+/;
185
+ var OBJECT_START_REGEX = /^\{/;
186
+ var OBJECT_END_REGEX = /^\}/;
187
+ var ARRAY_START_REGEX = /^\[/;
188
+ var ARRAY_END_REGEX = /^\]/;
189
+ var COMMA_REGEX = /^,/;
190
+ var COLON_REGEX = /^:/;
191
+ var KEYWORD_REGEX = /^(?:true|false|null)/;
192
+ var NUMBER_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/;
193
+ var STRING_DOUBLE_REGEX = /^"(?:[^"\\]|\\["bnrtf\\/]|\\u[0-9a-fA-F]{4})*"/;
194
+ var STRING_SINGLE_REGEX = /^'((?:[^'\\]|\\['bnrtf\\/]|\\u[0-9a-fA-F]{4})*)'/;
195
+ var COMMENT_SINGLE_REGEX = /^\/\/.*?(?:\r\n|\r|\n)/;
196
+ var COMMENT_MULTI_REGEX = /^\/\*[\s\S]*?\*\//;
197
+ var IDENTIFIER_REGEX = /^[$a-zA-Z0-9_\-+.*?!|&%^/#\\]+/;
198
+ function some(array, f) {
199
+ let acc = false;
200
+ for (let i = 0; i < array.length; i += 1) {
201
+ const result = f(array[i], i, array);
202
+ acc = result === void 0 ? false : result;
203
+ if (acc) {
204
+ return acc;
205
+ }
206
+ }
207
+ return acc;
208
+ }
209
+ function makeLexer(tokenSpecs) {
210
+ return (contents) => {
211
+ const tokens = [];
212
+ let line = 1;
213
+ let remainingContents = contents;
214
+ function findToken() {
215
+ const result = some(tokenSpecs, (tokenSpec) => {
216
+ const m = tokenSpec.re.exec(remainingContents);
217
+ if (m) {
218
+ const raw = m[0];
219
+ remainingContents = remainingContents.slice(raw.length);
220
+ return {
221
+ raw,
222
+ matched: tokenSpec.f(m)
223
+ // Process the match using the spec's function
224
+ };
225
+ }
226
+ return;
227
+ });
228
+ return result === false ? void 0 : result;
229
+ }
230
+ while (remainingContents !== "") {
231
+ const matched = findToken();
232
+ if (!matched) {
233
+ const err = new SyntaxError(
234
+ `Unexpected character: ${remainingContents[0]}; input: ${remainingContents.substr(
235
+ 0,
236
+ 100
237
+ )}`
238
+ );
239
+ err.line = line;
240
+ throw err;
241
+ }
242
+ const tokenWithLine = matched.matched;
243
+ tokenWithLine.line = line;
244
+ line += matched.raw.replace(/[^\n]/g, "").length;
245
+ tokens.push(tokenWithLine);
246
+ }
247
+ return tokens;
248
+ };
249
+ }
250
+ function fStringSingle(m) {
251
+ const content = m[1].replace(
252
+ /([^'\\]|\\['bnrtf\\]|\\u[0-9a-fA-F]{4})/g,
253
+ (mm) => {
254
+ if (mm === '"') {
255
+ return '\\"';
256
+ }
257
+ if (mm === "\\'") {
258
+ return "'";
259
+ }
260
+ return mm;
261
+ }
262
+ );
263
+ const match = `"${content}"`;
264
+ return {
265
+ type: "string",
266
+ match,
267
+ // The transformed, double-quoted string representation
268
+ // Use JSON.parse on the transformed string to handle escape sequences correctly
269
+ value: JSON.parse(match)
270
+ };
271
+ }
272
+ function fStringDouble(m) {
273
+ return {
274
+ type: "string",
275
+ match: m[0],
276
+ // The raw matched string (including quotes)
277
+ value: JSON.parse(m[0])
278
+ // Use JSON.parse to handle escapes and get the value
279
+ };
280
+ }
281
+ function fIdentifier(m) {
282
+ const value = m[0];
283
+ const match = '"' + value.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + // Escape backslashes and quotes
284
+ '"';
285
+ return {
286
+ type: "string",
287
+ // Treat identifiers as strings
288
+ value,
289
+ // The original identifier name
290
+ match
291
+ // The double-quoted string representation
292
+ };
293
+ }
294
+ function fComment(m) {
295
+ const match = m[0].replace(
296
+ /./g,
297
+ (c) => WHITESPACE_TEST_REGEX.test(c) ? c : " "
298
+ );
299
+ return {
300
+ type: " ",
301
+ // Represent comments as whitespace tokens
302
+ match,
303
+ // String containing original newlines and spaces for other chars
304
+ value: void 0
305
+ // Comments don't have a semantic value
306
+ };
307
+ }
308
+ function fNumber(m) {
309
+ return {
310
+ type: "number",
311
+ match: m[0],
312
+ // The raw matched number string
313
+ value: Number.parseFloat(m[0])
314
+ // Convert string to number
315
+ };
316
+ }
317
+ function fKeyword(m) {
318
+ let value;
319
+ switch (m[0]) {
320
+ case "null":
321
+ value = null;
322
+ break;
323
+ case "true":
324
+ value = true;
325
+ break;
326
+ case "false":
327
+ value = false;
328
+ break;
329
+ default:
330
+ throw new Error(`Unexpected keyword: ${m[0]}`);
331
+ }
332
+ return {
333
+ type: "atom",
334
+ // Use 'atom' type for these literals
335
+ match: m[0],
336
+ // The raw matched keyword
337
+ value
338
+ // The corresponding JavaScript value
339
+ };
340
+ }
341
+ function makeTokenSpecs(relaxed) {
342
+ function f(type) {
343
+ return (m) => {
344
+ return { type, match: m[0], value: void 0 };
345
+ };
346
+ }
347
+ let tokenSpecs = [
348
+ { re: WHITESPACE_REGEX, f: f(" ") },
349
+ // Whitespace
350
+ { re: OBJECT_START_REGEX, f: f("{") },
351
+ // Object start
352
+ { re: OBJECT_END_REGEX, f: f("}") },
353
+ // Object end
354
+ { re: ARRAY_START_REGEX, f: f("[") },
355
+ // Array start
356
+ { re: ARRAY_END_REGEX, f: f("]") },
357
+ // Array end
358
+ { re: COMMA_REGEX, f: f(",") },
359
+ // Comma separator
360
+ { re: COLON_REGEX, f: f(":") },
361
+ // Key-value separator
362
+ { re: KEYWORD_REGEX, f: fKeyword },
363
+ // Keywords
364
+ // Number: optional sign, digits, optional decimal part, optional exponent
365
+ { re: NUMBER_REGEX, f: fNumber },
366
+ // String: double-quoted, handles escapes
367
+ { re: STRING_DOUBLE_REGEX, f: fStringDouble }
368
+ ];
369
+ if (relaxed) {
370
+ tokenSpecs = tokenSpecs.concat([
371
+ // Single-quoted strings
372
+ {
373
+ re: STRING_SINGLE_REGEX,
374
+ f: fStringSingle
375
+ },
376
+ // Single-line comments (// ...)
377
+ { re: COMMENT_SINGLE_REGEX, f: fComment },
378
+ // Multi-line comments (/* ... */)
379
+ { re: COMMENT_MULTI_REGEX, f: fComment },
380
+ // Unquoted identifiers (treated as strings)
381
+ // Allows letters, numbers, _, -, +, ., *, ?, !, |, &, %, ^, /, #, \
382
+ { re: IDENTIFIER_REGEX, f: fIdentifier }
383
+ // Note: The order matters here. Identifiers are checked after keywords/numbers.
384
+ ]);
385
+ }
386
+ return tokenSpecs;
387
+ }
388
+ var lexer = makeLexer(makeTokenSpecs(true));
389
+ var strictLexer = makeLexer(makeTokenSpecs(false));
390
+ function previousNWSToken(tokens, index) {
391
+ let currentIndex = index;
392
+ for (; currentIndex >= 0; currentIndex -= 1) {
393
+ if (tokens[currentIndex].type !== " ") {
394
+ return currentIndex;
395
+ }
396
+ }
397
+ return;
398
+ }
399
+ function stripTrailingComma(tokens) {
400
+ const res = [];
401
+ tokens.forEach((token, index) => {
402
+ if (index > 0 && (token.type === "]" || token.type === "}")) {
403
+ const prevNWSTokenIndex = previousNWSToken(res, res.length - 1);
404
+ if (prevNWSTokenIndex !== void 0 && res[prevNWSTokenIndex].type === ",") {
405
+ const preCommaIndex = previousNWSToken(res, prevNWSTokenIndex - 1);
406
+ if (preCommaIndex !== void 0 && res[preCommaIndex].type !== "[" && res[preCommaIndex].type !== "{") {
407
+ res[prevNWSTokenIndex] = {
408
+ type: " ",
409
+ match: " ",
410
+ // Represent as a single space
411
+ value: void 0,
412
+ // Whitespace has no value
413
+ line: res[prevNWSTokenIndex].line
414
+ // Preserve original line number
415
+ };
416
+ }
417
+ }
418
+ }
419
+ res.push(token);
420
+ });
421
+ return res;
422
+ }
423
+ function transform(text) {
424
+ let tokens = lexer(text);
425
+ tokens = stripTrailingComma(tokens);
426
+ return tokens.reduce((str, token) => str + token.match, "");
427
+ }
428
+ function popToken(tokens, state) {
429
+ var _a, _b;
430
+ const token = tokens[state.pos];
431
+ state.pos += 1;
432
+ if (!token) {
433
+ const lastLine = tokens.length !== 0 ? (_b = (_a = tokens.at(-1)) == null ? void 0 : _a.line) != null ? _b : 1 : 1;
434
+ return { type: "eof", match: "", value: void 0, line: lastLine };
435
+ }
436
+ return token;
437
+ }
438
+ function strToken(token) {
439
+ switch (token.type) {
440
+ case "atom":
441
+ case "string":
442
+ case "number":
443
+ return `${token.type} ${token.match}`;
444
+ case "eof":
445
+ return "end-of-file";
446
+ default:
447
+ return `'${token.type}'`;
448
+ }
449
+ }
450
+ function skipColon(tokens, state) {
451
+ const colon = popToken(tokens, state);
452
+ if (colon.type !== ":") {
453
+ const message = `Unexpected token: ${strToken(colon)}, expected ':'`;
454
+ if (state.tolerant) {
455
+ state.warnings.push({
456
+ message,
457
+ line: colon.line
458
+ });
459
+ state.pos -= 1;
460
+ } else {
461
+ const err = new SyntaxError(message);
462
+ err.line = colon.line;
463
+ throw err;
464
+ }
465
+ }
466
+ }
467
+ function skipPunctuation(tokens, state, valid) {
468
+ const punctuation = [",", ":", "]", "}"];
469
+ let token = popToken(tokens, state);
470
+ while (true) {
471
+ if (valid == null ? void 0 : valid.includes(token.type)) {
472
+ return token;
473
+ }
474
+ if (token.type === "eof") {
475
+ return token;
476
+ }
477
+ if (punctuation.includes(token.type)) {
478
+ const message = `Unexpected token: ${strToken(
479
+ token
480
+ )}, expected '[', '{', number, string or atom`;
481
+ if (state.tolerant) {
482
+ state.warnings.push({
483
+ message,
484
+ line: token.line
485
+ });
486
+ token = popToken(tokens, state);
487
+ } else {
488
+ const err = new SyntaxError(message);
489
+ err.line = token.line;
490
+ throw err;
491
+ }
492
+ } else {
493
+ return token;
494
+ }
495
+ }
496
+ }
497
+ function raiseError(state, token, message) {
498
+ if (state.tolerant) {
499
+ state.warnings.push({
500
+ message,
501
+ line: token.line
502
+ });
503
+ } else {
504
+ const err = new SyntaxError(message);
505
+ err.line = token.line;
506
+ throw err;
507
+ }
508
+ }
509
+ function raiseUnexpected(state, token, expected) {
510
+ raiseError(
511
+ state,
512
+ token,
513
+ `Unexpected token: ${strToken(token)}, expected ${expected}`
514
+ );
515
+ }
516
+ function checkDuplicates(state, obj, token) {
517
+ const key = String(token.value);
518
+ if (!state.duplicate && Object.hasOwn(obj, key)) {
519
+ raiseError(state, token, `Duplicate key: ${key}`);
520
+ }
521
+ }
522
+ function appendPair(state, obj, key, value) {
523
+ const finalValue = state.reviver ? state.reviver(key, value) : value;
524
+ if (finalValue !== void 0) {
525
+ obj[key] = finalValue;
526
+ }
527
+ }
528
+ function parsePair(tokens, state, obj) {
529
+ let token = skipPunctuation(tokens, state, [":", "string", "number", "atom"]);
530
+ let value;
531
+ if (token.type !== "string") {
532
+ raiseUnexpected(state, token, "string key");
533
+ if (state.tolerant) {
534
+ switch (token.type) {
535
+ case ":":
536
+ token = {
537
+ type: "string",
538
+ value: "null",
539
+ match: '"null"',
540
+ line: token.line
541
+ };
542
+ state.pos -= 1;
543
+ break;
544
+ case "number":
545
+ // Use number as string key
546
+ case "atom":
547
+ token = {
548
+ type: "string",
549
+ value: String(token.value),
550
+ match: `"${token.value}"`,
551
+ line: token.line
552
+ };
553
+ break;
554
+ case "[":
555
+ // Assume missing key before an array
556
+ case "{":
557
+ state.pos -= 1;
558
+ value = parseAny(tokens, state);
559
+ checkDuplicates(state, obj, {
560
+ type: "string",
561
+ value: "null",
562
+ match: '"null"',
563
+ line: token.line
564
+ });
565
+ appendPair(state, obj, "null", value);
566
+ return;
567
+ // Finished parsing this "pair"
568
+ case "eof":
569
+ return;
570
+ // Cannot recover
571
+ default:
572
+ return;
573
+ }
574
+ } else {
575
+ return;
576
+ }
577
+ }
578
+ checkDuplicates(state, obj, token);
579
+ const key = String(token.value);
580
+ skipColon(tokens, state);
581
+ value = parseAny(tokens, state);
582
+ appendPair(state, obj, key, value);
583
+ }
584
+ function parseElement(tokens, state, arr) {
585
+ const key = arr.length;
586
+ const value = parseAny(tokens, state);
587
+ arr[key] = state.reviver ? state.reviver(String(key), value) : value;
588
+ }
589
+ function parseObject(tokens, state) {
590
+ const obj = {};
591
+ return parseMany(tokens, state, obj, {
592
+ skip: [":", "}"],
593
+ // Initially skip over colon or closing brace (for empty/tolerant cases)
594
+ elementParser: parsePair,
595
+ // Use parsePair to parse each key-value element
596
+ elementName: "string key",
597
+ // Expected element type for errors
598
+ endSymbol: "}"
599
+ // The closing token for an object
600
+ });
601
+ }
602
+ function parseArray(tokens, state) {
603
+ const arr = [];
604
+ return parseMany(tokens, state, arr, {
605
+ skip: ["]"],
606
+ // Initially skip over closing bracket (for empty/tolerant cases)
607
+ elementParser: parseElement,
608
+ // Use parseElement to parse each array item
609
+ elementName: "json value",
610
+ // Expected element type for errors
611
+ endSymbol: "]"
612
+ // The closing token for an array
613
+ });
614
+ }
615
+ function handleInvalidToken(token, state, opts, result) {
616
+ raiseUnexpected(state, token, `',' or '${opts.endSymbol}'`);
617
+ if (state.tolerant) {
618
+ if (token.type === "eof") {
619
+ return result;
620
+ }
621
+ state.pos -= 1;
622
+ return null;
623
+ }
624
+ return result;
625
+ }
626
+ function handleCommaToken(params) {
627
+ const { token, tokens, state, opts, result } = params;
628
+ const nextToken = tokens[state.pos];
629
+ if (state.tolerant && nextToken && nextToken.type === opts.endSymbol) {
630
+ raiseError(state, token, `Trailing comma before '${opts.endSymbol}'`);
631
+ popToken(tokens, state);
632
+ return result;
633
+ }
634
+ opts.elementParser(tokens, state, result);
635
+ return null;
636
+ }
637
+ function parseManyInitialElement(tokens, state, result, opts) {
638
+ const token = skipPunctuation(tokens, state, opts.skip);
639
+ if (token.type === "eof") {
640
+ raiseUnexpected(state, token, `'${opts.endSymbol}' or ${opts.elementName}`);
641
+ return result;
642
+ }
643
+ if (token.type === opts.endSymbol) {
644
+ return result;
645
+ }
646
+ state.pos -= 1;
647
+ opts.elementParser(tokens, state, result);
648
+ return;
649
+ }
650
+ function parseManyProcessToken(params) {
651
+ const { token, tokens, state, opts, result } = params;
652
+ if (token.type !== opts.endSymbol && token.type !== ",") {
653
+ const handledResult = handleInvalidToken(token, state, opts, result);
654
+ if (handledResult !== null) {
655
+ return handledResult;
656
+ }
657
+ }
658
+ if (token.type === opts.endSymbol) {
659
+ return result;
660
+ }
661
+ if (token.type === ",") {
662
+ const handledResult = handleCommaToken({
663
+ token,
664
+ tokens,
665
+ state,
666
+ opts,
667
+ result
668
+ });
669
+ if (handledResult !== null) {
670
+ return handledResult;
671
+ }
672
+ return;
673
+ }
674
+ opts.elementParser(tokens, state, result);
675
+ return;
676
+ }
677
+ function parseMany(tokens, state, result, opts) {
678
+ const initialResult = parseManyInitialElement(tokens, state, result, opts);
679
+ if (initialResult !== void 0) {
680
+ return initialResult;
681
+ }
682
+ while (true) {
683
+ const token = popToken(tokens, state);
684
+ const processedResult = parseManyProcessToken({
685
+ token,
686
+ tokens,
687
+ state,
688
+ opts,
689
+ result
690
+ });
691
+ if (processedResult !== void 0) {
692
+ return processedResult;
693
+ }
694
+ }
695
+ }
696
+ function endChecks(tokens, state, ret) {
697
+ if (state.pos < tokens.length) {
698
+ if (state.tolerant) {
699
+ skipPunctuation(tokens, state);
700
+ }
701
+ if (state.pos < tokens.length) {
702
+ raiseError(
703
+ state,
704
+ tokens[state.pos],
705
+ `Unexpected token: ${strToken(tokens[state.pos])}, expected end-of-input`
706
+ );
707
+ }
708
+ }
709
+ if (state.tolerant && state.warnings.length > 0) {
710
+ const message = state.warnings.length === 1 ? state.warnings[0].message : `${state.warnings.length} parse warnings`;
711
+ const err = new SyntaxError(message);
712
+ err.line = state.warnings[0].line;
713
+ err.warnings = state.warnings;
714
+ err.obj = ret;
715
+ throw err;
716
+ }
717
+ }
718
+ function parseAny(tokens, state, end = false) {
719
+ const token = skipPunctuation(tokens, state);
720
+ let ret;
721
+ if (token.type === "eof") {
722
+ if (end) {
723
+ raiseUnexpected(state, token, "json value");
724
+ }
725
+ raiseUnexpected(state, token, "json value");
726
+ return;
727
+ }
728
+ switch (token.type) {
729
+ case "{":
730
+ ret = parseObject(tokens, state);
731
+ break;
732
+ case "[":
733
+ ret = parseArray(tokens, state);
734
+ break;
735
+ case "string":
736
+ // String literal
737
+ case "number":
738
+ // Number literal
739
+ case "atom":
740
+ ret = token.value;
741
+ break;
742
+ default:
743
+ raiseUnexpected(state, token, "json value");
744
+ if (state.tolerant) {
745
+ ret = null;
746
+ } else {
747
+ return;
748
+ }
749
+ }
750
+ if (end) {
751
+ ret = state.reviver ? state.reviver("", ret) : ret;
752
+ endChecks(tokens, state, ret);
753
+ }
754
+ return ret;
755
+ }
756
+ function normalizeParseOptions(optsOrReviver) {
757
+ var _a;
758
+ let options = {};
759
+ if (typeof optsOrReviver === "function") {
760
+ options.reviver = optsOrReviver;
761
+ } else if (optsOrReviver !== null && typeof optsOrReviver === "object") {
762
+ options = { ...optsOrReviver };
763
+ } else if (optsOrReviver !== void 0) {
764
+ throw new TypeError(
765
+ "Second argument must be a reviver function or an options object."
766
+ );
767
+ }
768
+ if (options.relaxed === void 0) {
769
+ if (options.warnings === true || options.tolerant === true) {
770
+ options.relaxed = true;
771
+ } else if (options.warnings === false && options.tolerant === false) {
772
+ options.relaxed = false;
773
+ } else {
774
+ options.relaxed = true;
775
+ }
776
+ }
777
+ options.tolerant = options.tolerant || options.warnings;
778
+ options.duplicate = (_a = options.duplicate) != null ? _a : false;
779
+ return options;
780
+ }
781
+ function createParseState(options) {
782
+ var _a, _b;
783
+ return {
784
+ pos: 0,
785
+ reviver: options.reviver,
786
+ tolerant: (_a = options.tolerant) != null ? _a : false,
787
+ duplicate: (_b = options.duplicate) != null ? _b : false,
788
+ warnings: []
789
+ };
790
+ }
791
+ function parseWithCustomParser(text, options) {
792
+ const lexerToUse = options.relaxed ? lexer : strictLexer;
793
+ let tokens = lexerToUse(text);
794
+ if (options.relaxed) {
795
+ tokens = stripTrailingComma(tokens);
796
+ }
797
+ tokens = tokens.filter((token) => token.type !== " ");
798
+ const state = createParseState(options);
799
+ return parseAny(tokens, state, true);
800
+ }
801
+ function parseWithTransform(text, options) {
802
+ let tokens = lexer(text);
803
+ tokens = stripTrailingComma(tokens);
804
+ const newtext = tokens.reduce((str, token) => str + token.match, "");
805
+ return JSON.parse(
806
+ newtext,
807
+ options.reviver
808
+ );
809
+ }
810
+ function parse(text, optsOrReviver) {
811
+ const options = normalizeParseOptions(optsOrReviver);
812
+ if (!(options.relaxed || options.warnings || options.tolerant) && options.duplicate) {
813
+ return JSON.parse(
814
+ text,
815
+ options.reviver
816
+ );
817
+ }
818
+ if (options.warnings || options.tolerant || !options.duplicate) {
819
+ return parseWithCustomParser(text, options);
820
+ }
821
+ return parseWithTransform(text, options);
822
+ }
823
+ function stringifyPair(obj, key) {
824
+ return `${JSON.stringify(key)}:${stringify(obj[key])}`;
825
+ }
826
+ function stringify(obj) {
827
+ const type = typeof obj;
828
+ if (type === "string" || type === "number" || type === "boolean" || obj === null) {
829
+ return JSON.stringify(obj);
830
+ }
831
+ if (type === "undefined") {
832
+ return "null";
833
+ }
834
+ if (Array.isArray(obj)) {
835
+ const elements = obj.map(stringify).join(",");
836
+ return `[${elements}]`;
837
+ }
838
+ if (type === "object") {
839
+ const keys = Object.keys(obj);
840
+ keys.sort();
841
+ const pairs = keys.map((key) => stringifyPair(obj, key)).join(",");
842
+ return `{${pairs}}`;
843
+ }
844
+ return "null";
845
+ }
846
+
847
+ // src/protocols/json-mix-protocol.ts
848
+ function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
849
+ var _a;
850
+ try {
851
+ const parsedToolCall = parse(toolCallJson);
852
+ processedElements.push({
853
+ type: "tool-call",
854
+ toolCallId: generateId(),
855
+ toolName: parsedToolCall.name,
856
+ input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
857
+ });
858
+ } catch (error) {
859
+ logParseFailure({
860
+ phase: "generated-text",
861
+ reason: "Failed to parse tool call JSON segment",
862
+ snippet: fullMatch,
863
+ error
864
+ });
865
+ if (options == null ? void 0 : options.onError) {
866
+ options.onError(
867
+ "Could not process JSON tool call, keeping original text.",
868
+ { toolCall: fullMatch, error }
869
+ );
870
+ }
871
+ processedElements.push({ type: "text", text: fullMatch });
872
+ }
873
+ }
874
+ function addTextSegment(text, processedElements) {
875
+ if (text.trim()) {
876
+ processedElements.push({ type: "text", text });
877
+ }
878
+ }
879
+ function processMatchedToolCall(context) {
880
+ const { match, text, currentIndex, processedElements, options } = context;
881
+ const startIndex = match.index;
882
+ const toolCallJson = match[1];
883
+ if (startIndex > currentIndex) {
884
+ const textSegment = text.substring(currentIndex, startIndex);
885
+ addTextSegment(textSegment, processedElements);
886
+ }
887
+ if (toolCallJson) {
888
+ processToolCallJson(toolCallJson, match[0], processedElements, options);
889
+ }
890
+ return startIndex + match[0].length;
891
+ }
892
+ function flushBuffer(state, controller, toolCallStart) {
893
+ if (state.buffer.length === 0) {
894
+ return;
895
+ }
896
+ if (!state.currentTextId) {
897
+ state.currentTextId = generateId();
898
+ controller.enqueue({ type: "text-start", id: state.currentTextId });
899
+ state.hasEmittedTextStart = true;
900
+ }
901
+ const delta = state.isInsideToolCall ? `${toolCallStart}${state.buffer}` : state.buffer;
902
+ controller.enqueue({
903
+ type: "text-delta",
904
+ id: state.currentTextId,
905
+ delta
906
+ });
907
+ state.buffer = "";
908
+ }
909
+ function closeTextBlock(state, controller) {
910
+ if (state.currentTextId && state.hasEmittedTextStart) {
911
+ controller.enqueue({ type: "text-end", id: state.currentTextId });
912
+ state.currentTextId = null;
913
+ state.hasEmittedTextStart = false;
914
+ }
915
+ }
916
+ function emitIncompleteToolCall(state, controller, toolCallStart) {
917
+ if (!state.currentToolCallJson) {
918
+ return;
919
+ }
920
+ logParseFailure({
921
+ phase: "stream",
922
+ reason: "Incomplete streaming tool call segment emitted as text",
923
+ snippet: `${toolCallStart}${state.currentToolCallJson}`
924
+ });
925
+ const errorId = generateId();
926
+ controller.enqueue({ type: "text-start", id: errorId });
927
+ controller.enqueue({
928
+ type: "text-delta",
929
+ id: errorId,
930
+ delta: `${toolCallStart}${state.currentToolCallJson}`
931
+ });
932
+ controller.enqueue({ type: "text-end", id: errorId });
933
+ state.currentToolCallJson = "";
934
+ }
935
+ function handleFinishChunk(state, controller, toolCallStart, chunk) {
936
+ if (state.buffer.length > 0) {
937
+ flushBuffer(state, controller, toolCallStart);
938
+ }
939
+ closeTextBlock(state, controller);
940
+ emitIncompleteToolCall(state, controller, toolCallStart);
941
+ controller.enqueue(chunk);
942
+ }
943
+ function publishText(text, state, controller) {
944
+ if (state.isInsideToolCall) {
945
+ closeTextBlock(state, controller);
946
+ state.currentToolCallJson += text;
947
+ } else if (text.length > 0) {
948
+ if (!state.currentTextId) {
949
+ state.currentTextId = generateId();
950
+ controller.enqueue({ type: "text-start", id: state.currentTextId });
951
+ state.hasEmittedTextStart = true;
952
+ }
953
+ controller.enqueue({
954
+ type: "text-delta",
955
+ id: state.currentTextId,
956
+ delta: text
957
+ });
958
+ }
959
+ }
960
+ function emitToolCall(context) {
961
+ var _a;
962
+ const { state, controller, toolCallStart, toolCallEnd, options } = context;
963
+ try {
964
+ const parsedToolCall = parse(state.currentToolCallJson);
965
+ closeTextBlock(state, controller);
966
+ controller.enqueue({
967
+ type: "tool-call",
968
+ toolCallId: generateId(),
969
+ toolName: parsedToolCall.name,
970
+ input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
971
+ });
972
+ } catch (error) {
973
+ logParseFailure({
974
+ phase: "stream",
975
+ reason: "Failed to parse streaming tool call JSON segment",
976
+ snippet: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`,
977
+ error
978
+ });
979
+ const errorId = generateId();
980
+ controller.enqueue({ type: "text-start", id: errorId });
981
+ controller.enqueue({
982
+ type: "text-delta",
983
+ id: errorId,
984
+ delta: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`
985
+ });
986
+ controller.enqueue({ type: "text-end", id: errorId });
987
+ if (options == null ? void 0 : options.onError) {
988
+ options.onError(
989
+ "Could not process streaming JSON tool call; emitting original text.",
990
+ {
991
+ toolCall: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`
992
+ }
993
+ );
994
+ }
995
+ }
996
+ }
997
+ function processTagMatch(context) {
998
+ const { state } = context;
999
+ if (state.isInsideToolCall) {
1000
+ emitToolCall(context);
1001
+ state.currentToolCallJson = "";
1002
+ state.isInsideToolCall = false;
1003
+ } else {
1004
+ state.currentToolCallJson = "";
1005
+ state.isInsideToolCall = true;
1006
+ }
1007
+ }
1008
+ function processBufferTags(context) {
1009
+ const { state, controller, toolCallStart, toolCallEnd } = context;
1010
+ let startIndex = getPotentialStartIndex(
1011
+ state.buffer,
1012
+ state.isInsideToolCall ? toolCallEnd : toolCallStart
1013
+ );
1014
+ while (startIndex != null) {
1015
+ const tag = state.isInsideToolCall ? toolCallEnd : toolCallStart;
1016
+ if (startIndex + tag.length > state.buffer.length) {
1017
+ break;
1018
+ }
1019
+ publishText(state.buffer.slice(0, startIndex), state, controller);
1020
+ state.buffer = state.buffer.slice(startIndex + tag.length);
1021
+ processTagMatch(context);
1022
+ startIndex = getPotentialStartIndex(
1023
+ state.buffer,
1024
+ state.isInsideToolCall ? toolCallEnd : toolCallStart
1025
+ );
1026
+ }
1027
+ }
1028
+ function handlePartialTag(state, controller, toolCallStart) {
1029
+ if (state.isInsideToolCall) {
1030
+ return;
1031
+ }
1032
+ const potentialIndex = getPotentialStartIndex(state.buffer, toolCallStart);
1033
+ if (potentialIndex != null && potentialIndex + toolCallStart.length > state.buffer.length) {
1034
+ publishText(state.buffer.slice(0, potentialIndex), state, controller);
1035
+ state.buffer = state.buffer.slice(potentialIndex);
1036
+ } else {
1037
+ publishText(state.buffer, state, controller);
1038
+ state.buffer = "";
1039
+ }
1040
+ }
1041
+ var jsonMixProtocol = ({
1042
+ toolCallStart = "<tool_call>",
1043
+ toolCallEnd = "</tool_call>",
1044
+ toolResponseStart = "<tool_response>",
1045
+ toolResponseEnd = "</tool_response>"
1046
+ } = {}) => ({
1047
+ formatTools({ tools, toolSystemPromptTemplate }) {
1048
+ const toolsForPrompt = (tools || []).filter((tool) => tool.type === "function").map((tool) => ({
1049
+ name: tool.name,
1050
+ description: tool.type === "function" && typeof tool.description === "string" ? tool.description : void 0,
1051
+ parameters: tool.inputSchema
1052
+ }));
1053
+ return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1054
+ },
1055
+ formatToolCall(toolCall) {
1056
+ let args = {};
1057
+ try {
1058
+ args = JSON.parse(toolCall.input);
1059
+ } catch (e) {
1060
+ args = toolCall.input;
1061
+ }
1062
+ return `${toolCallStart}${JSON.stringify({
1063
+ name: toolCall.toolName,
1064
+ arguments: args
1065
+ })}${toolCallEnd}`;
1066
+ },
1067
+ formatToolResponse(toolResult) {
1068
+ return `${toolResponseStart}${JSON.stringify({
1069
+ toolName: toolResult.toolName,
1070
+ result: toolResult.output
1071
+ })}${toolResponseEnd}`;
1072
+ },
1073
+ parseGeneratedText({ text, options }) {
1074
+ const startEsc = escapeRegExp(toolCallStart);
1075
+ const endEsc = escapeRegExp(toolCallEnd);
1076
+ const toolCallRegex = new RegExp(
1077
+ `${startEsc}([\0-\uFFFF]*?)${endEsc}`,
1078
+ "gs"
1079
+ );
1080
+ const processedElements = [];
1081
+ let currentIndex = 0;
1082
+ let match = toolCallRegex.exec(text);
1083
+ while (match !== null) {
1084
+ currentIndex = processMatchedToolCall({
1085
+ match,
1086
+ text,
1087
+ currentIndex,
1088
+ processedElements,
1089
+ options
1090
+ });
1091
+ match = toolCallRegex.exec(text);
1092
+ }
1093
+ if (currentIndex < text.length) {
1094
+ const remainingText = text.substring(currentIndex);
1095
+ addTextSegment(remainingText, processedElements);
1096
+ }
1097
+ return processedElements;
1098
+ },
1099
+ createStreamParser({ tools: _tools, options } = { tools: [] }) {
1100
+ const state = {
1101
+ isInsideToolCall: false,
1102
+ buffer: "",
1103
+ currentToolCallJson: "",
1104
+ currentTextId: null,
1105
+ hasEmittedTextStart: false
1106
+ };
1107
+ return new TransformStream({
1108
+ transform(chunk, controller) {
1109
+ if (chunk.type === "finish") {
1110
+ handleFinishChunk(state, controller, toolCallStart, chunk);
1111
+ return;
1112
+ }
1113
+ if (chunk.type !== "text-delta") {
1114
+ controller.enqueue(chunk);
1115
+ return;
1116
+ }
1117
+ state.buffer += chunk.delta;
1118
+ processBufferTags({
1119
+ state,
1120
+ controller,
1121
+ toolCallStart,
1122
+ toolCallEnd,
1123
+ options
1124
+ });
1125
+ handlePartialTag(state, controller, toolCallStart);
1126
+ }
1127
+ });
1128
+ },
1129
+ extractToolCallSegments({ text }) {
1130
+ const startEsc = escapeRegExp(toolCallStart);
1131
+ const endEsc = escapeRegExp(toolCallEnd);
1132
+ const regex = new RegExp(`${startEsc}([\0-\uFFFF]*?)${endEsc}`, "gs");
1133
+ const segments = [];
1134
+ let m = regex.exec(text);
1135
+ while (m != null) {
1136
+ segments.push(m[0]);
1137
+ m = regex.exec(text);
1138
+ }
1139
+ return segments;
1140
+ }
1141
+ });
1142
+
1143
+ // src/protocols/morph-xml-protocol.ts
1144
+ import { generateId as generateId2 } from "@ai-sdk/provider-utils";
1145
+ import {
1146
+ extractRawInner,
1147
+ parse as parse2,
1148
+ RXMLCoercionError,
1149
+ RXMLDuplicateStringTagError,
1150
+ RXMLParseError,
1151
+ stringify as stringify2,
1152
+ unwrapJsonSchema
1153
+ } from "@ai-sdk-tool/rxml";
1154
+
1155
+ // src/utils/type-guards.ts
1156
+ function isToolCallContent(content) {
1157
+ return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
1158
+ (typeof content.input === "string" || typeof content.input === "object");
1159
+ }
1160
+ function isToolResultPart(content) {
1161
+ const c = content;
1162
+ return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
1163
+ }
1164
+ function hasInputProperty(obj) {
1165
+ return typeof obj === "object" && obj !== null && "input" in obj;
1166
+ }
1167
+
1168
+ // src/protocols/morph-xml-protocol.ts
1169
+ var WHITESPACE_REGEX2 = /\s/;
1170
+ var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
1171
+ var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
1172
+ var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
1173
+ var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
1174
+ var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
1175
+ var STATUS_TAG_RE = /<status>([\s\S]*?)<\/status>/i;
1176
+ function normalizeCloseTags(xml) {
1177
+ return xml.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1178
+ }
1179
+ function escapeInvalidLt(xml) {
1180
+ const len = xml.length;
1181
+ let out = "";
1182
+ for (let i = 0; i < len; i += 1) {
1183
+ const ch = xml[i];
1184
+ if (ch === "<") {
1185
+ const next = i + 1 < len ? xml[i + 1] : "";
1186
+ if (!(NAME_CHAR_RE.test(next) || next === "/" || next === "!" || next === "?")) {
1187
+ out += "&lt;";
1188
+ continue;
1189
+ }
1190
+ }
1191
+ out += ch;
1192
+ }
1193
+ return out;
1194
+ }
1195
+ function shouldDeduplicateStringTags(schema) {
1196
+ const unwrapped = unwrapJsonSchema(schema);
1197
+ if (!unwrapped || typeof unwrapped !== "object") {
1198
+ return false;
1199
+ }
1200
+ const props = unwrapped.properties;
1201
+ if (!props) {
1202
+ return false;
1203
+ }
1204
+ const commandRaw = props.command;
1205
+ if (!commandRaw) {
1206
+ return false;
1207
+ }
1208
+ const command = unwrapJsonSchema(commandRaw);
1209
+ return (command == null ? void 0 : command.type) === "array";
1210
+ }
1211
+ function tryParseSecondaryXml(content, toolSchema, options) {
1212
+ const normalized = normalizeCloseTags(content);
1213
+ const balanced = balanceTags(content);
1214
+ const hasMalformedClose = MALFORMED_CLOSE_RE.test(content);
1215
+ if (!hasMalformedClose && balanced.length > normalized.length) {
1216
+ return null;
1217
+ }
1218
+ try {
1219
+ let parsed = parse2(balanced, toolSchema, {
1220
+ onError: options == null ? void 0 : options.onError,
1221
+ noChildNodes: []
1222
+ });
1223
+ parsed = repairParsedAgainstSchema(parsed, toolSchema, options);
1224
+ return parsed;
1225
+ } catch (_e) {
1226
+ if (shouldDeduplicateStringTags(toolSchema)) {
1227
+ const deduped = dedupeStringTagsAgainstSchema(balanced, toolSchema);
1228
+ if (deduped !== balanced) {
1229
+ try {
1230
+ let reparsed = parse2(deduped, toolSchema, {
1231
+ onError: options == null ? void 0 : options.onError,
1232
+ noChildNodes: []
1233
+ });
1234
+ reparsed = repairParsedAgainstSchema(reparsed, toolSchema, options);
1235
+ return reparsed;
1236
+ } catch (_) {
1237
+ return null;
1238
+ }
1239
+ }
1240
+ }
1241
+ return null;
1242
+ }
1243
+ }
1244
+ function balanceTags(xml) {
1245
+ const src = normalizeCloseTags(xml).replace(
1246
+ STATUS_TO_STEP_BOUNDARY_RE,
1247
+ "</status></step><step>"
1248
+ );
1249
+ let i = 0;
1250
+ const len = src.length;
1251
+ const out = [];
1252
+ const stack = [];
1253
+ while (i < len) {
1254
+ const lt = src.indexOf("<", i);
1255
+ if (lt === -1) {
1256
+ out.push(src.slice(i));
1257
+ break;
1258
+ }
1259
+ out.push(src.slice(i, lt));
1260
+ if (lt + 1 >= len) {
1261
+ break;
1262
+ }
1263
+ const next = src[lt + 1];
1264
+ if (next === "!" || next === "?") {
1265
+ i = handleSpecialTagSegment(src, lt, out);
1266
+ continue;
1267
+ }
1268
+ if (next === "/") {
1269
+ i = handleClosingTagSegment(src, lt, out, stack);
1270
+ continue;
1271
+ }
1272
+ i = handleOpeningTagSegment(src, lt, out, stack);
1273
+ }
1274
+ for (let k = stack.length - 1; k >= 0; k -= 1) {
1275
+ out.push(`</${stack[k]}>`);
1276
+ }
1277
+ return out.join("");
1278
+ }
1279
+ function skipWs(s, p, len) {
1280
+ let idx = p;
1281
+ while (idx < len && WHITESPACE_REGEX2.test(s[idx])) {
1282
+ idx += 1;
1283
+ }
1284
+ return idx;
1285
+ }
1286
+ function parseTagNameAt(s, p, len) {
1287
+ let idx = p;
1288
+ const start = idx;
1289
+ while (idx < len && NAME_CHAR_RE.test(s[idx])) {
1290
+ idx += 1;
1291
+ }
1292
+ return { name: s.slice(start, idx), pos: idx };
1293
+ }
1294
+ function handleSpecialTagSegment(src, lt, out) {
1295
+ const gt = src.indexOf(">", lt + 1);
1296
+ if (gt === -1) {
1297
+ out.push(src.slice(lt));
1298
+ return src.length;
1299
+ }
1300
+ out.push(src.slice(lt, gt + 1));
1301
+ return gt + 1;
1302
+ }
1303
+ function handleClosingTagSegment(src, lt, out, stack) {
1304
+ const len = src.length;
1305
+ let p = skipWs(src, lt + 2, len);
1306
+ const { name, pos } = parseTagNameAt(src, p, len);
1307
+ p = pos;
1308
+ const gt = src.indexOf(">", p);
1309
+ const closingText = gt === -1 ? src.slice(lt) : src.slice(lt, gt + 1);
1310
+ const idx = stack.lastIndexOf(name);
1311
+ if (idx !== -1) {
1312
+ for (let k = stack.length - 1; k > idx; k -= 1) {
1313
+ out.push(`</${stack[k]}>`);
1314
+ stack.pop();
1315
+ }
1316
+ out.push(closingText);
1317
+ stack.pop();
1318
+ }
1319
+ return gt === -1 ? len : gt + 1;
1320
+ }
1321
+ function handleOpeningTagSegment(src, lt, out, stack) {
1322
+ const len = src.length;
1323
+ let p = skipWs(src, lt + 1, len);
1324
+ const nameStart = p;
1325
+ const parsed = parseTagNameAt(src, p, len);
1326
+ p = parsed.pos;
1327
+ const name = src.slice(nameStart, p);
1328
+ const q = src.indexOf(">", p);
1329
+ if (q === -1) {
1330
+ out.push(src.slice(lt));
1331
+ return len;
1332
+ }
1333
+ let r = q - 1;
1334
+ while (r >= nameStart && WHITESPACE_REGEX2.test(src[r])) {
1335
+ r -= 1;
1336
+ }
1337
+ const selfClosing = src[r] === "/";
1338
+ out.push(src.slice(lt, q + 1));
1339
+ if (!selfClosing && name) {
1340
+ stack.push(name);
1341
+ }
1342
+ return q + 1;
1343
+ }
1344
+ function repairParsedAgainstSchema(input, schema, options) {
1345
+ if (!input || typeof input !== "object") {
1346
+ return input;
1347
+ }
1348
+ const unwrapped = unwrapJsonSchema(schema);
1349
+ if (!unwrapped || typeof unwrapped !== "object") {
1350
+ return input;
1351
+ }
1352
+ const properties = unwrapped.properties;
1353
+ if (!properties) {
1354
+ return input;
1355
+ }
1356
+ applySchemaProps(input, properties, options);
1357
+ return input;
1358
+ }
1359
+ function applySchemaProps(obj, properties, options) {
1360
+ for (const key of Object.keys(obj)) {
1361
+ const propSchema = properties[key];
1362
+ if (!propSchema) {
1363
+ continue;
1364
+ }
1365
+ const prop = unwrapJsonSchema(propSchema);
1366
+ const propType = prop.type;
1367
+ if (propType === "array" && prop.items) {
1368
+ const itemSchemaRaw = prop.items;
1369
+ const itemSchema = unwrapJsonSchema(itemSchemaRaw);
1370
+ obj[key] = coerceArrayItems(obj[key], itemSchema, options);
1371
+ continue;
1372
+ }
1373
+ if (propType === "object") {
1374
+ const val = obj[key];
1375
+ if (val && typeof val === "object") {
1376
+ obj[key] = repairParsedAgainstSchema(
1377
+ val,
1378
+ prop,
1379
+ options
1380
+ );
1381
+ }
1382
+ }
1383
+ }
1384
+ }
1385
+ function coerceArrayItems(val, itemSchema, options) {
1386
+ if (!Array.isArray(val)) {
1387
+ return val;
1388
+ }
1389
+ return val.map((v) => coerceArrayItem(v, itemSchema, options));
1390
+ }
1391
+ function coerceArrayItem(v, itemSchema, options) {
1392
+ const itemType = itemSchema == null ? void 0 : itemSchema.type;
1393
+ if (typeof v === "string" && itemType === "object") {
1394
+ const parsed = tryParseStringToSchemaObject(v, itemSchema, options);
1395
+ if (parsed !== null) {
1396
+ return parsed;
1397
+ }
1398
+ const fallback = extractStepStatusFromString(normalizeCloseTags(v));
1399
+ if (fallback) {
1400
+ return fallback;
1401
+ }
1402
+ return v;
1403
+ }
1404
+ if (v && typeof v === "object" && itemType === "object") {
1405
+ return repairParsedAgainstSchema(
1406
+ v,
1407
+ itemSchema,
1408
+ options
1409
+ );
1410
+ }
1411
+ return v;
1412
+ }
1413
+ function getStringPropertyNames(schema) {
1414
+ const unwrapped = unwrapJsonSchema(schema);
1415
+ if (!unwrapped || typeof unwrapped !== "object") {
1416
+ return [];
1417
+ }
1418
+ const props = unwrapped.properties;
1419
+ if (!props) {
1420
+ return [];
1421
+ }
1422
+ const names = [];
1423
+ for (const key of Object.keys(props)) {
1424
+ const prop = unwrapJsonSchema(
1425
+ props[key]
1426
+ );
1427
+ const type = prop.type;
1428
+ if (type === "string") {
1429
+ names.push(key);
1430
+ }
1431
+ }
1432
+ return names;
1433
+ }
1434
+ function escapeRegExp2(s) {
1435
+ return s.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&");
1436
+ }
1437
+ function dedupeStringTagsAgainstSchema(xml, schema) {
1438
+ const names = getStringPropertyNames(schema);
1439
+ let out = xml;
1440
+ for (const key of names) {
1441
+ out = dedupeSingleTag(out, key);
1442
+ }
1443
+ return out;
1444
+ }
1445
+ function dedupeSingleTag(xml, key) {
1446
+ var _a, _b;
1447
+ const escaped = escapeRegExp2(key);
1448
+ const re = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
1449
+ const matches = Array.from(xml.matchAll(re));
1450
+ if (matches.length <= 1) {
1451
+ return xml;
1452
+ }
1453
+ const last = matches.at(-1);
1454
+ let result = "";
1455
+ let cursor = 0;
1456
+ for (const m of matches) {
1457
+ const idx = (_a = m.index) != null ? _a : 0;
1458
+ result += xml.slice(cursor, idx);
1459
+ if (last && idx === ((_b = last.index) != null ? _b : -1)) {
1460
+ result += m[0];
1461
+ }
1462
+ cursor = idx + m[0].length;
1463
+ }
1464
+ result += xml.slice(cursor);
1465
+ return result;
1466
+ }
1467
+ function tryParseStringToSchemaObject(xml, itemSchema, options) {
1468
+ try {
1469
+ const fixed = parse2(normalizeCloseTags(xml), itemSchema, {
1470
+ onError: options == null ? void 0 : options.onError,
1471
+ noChildNodes: []
1472
+ });
1473
+ return typeof fixed === "string" ? null : fixed;
1474
+ } catch (e) {
1475
+ return null;
1476
+ }
1477
+ }
1478
+ function extractStepStatusFromString(normXml) {
1479
+ const stepMatch = normXml.match(STEP_TAG_RE);
1480
+ const statusMatch = normXml.match(STATUS_TAG_RE);
1481
+ if (stepMatch && statusMatch) {
1482
+ return { step: stepMatch[1], status: statusMatch[1] };
1483
+ }
1484
+ return null;
1485
+ }
1486
+ function processTextBeforeToolCall(text, currentIndex, toolCallStartIndex, processedElements) {
1487
+ if (toolCallStartIndex > currentIndex) {
1488
+ const textSegment = text.substring(currentIndex, toolCallStartIndex);
1489
+ if (textSegment.trim()) {
1490
+ processedElements.push({ type: "text", text: textSegment });
1491
+ }
1492
+ }
1493
+ return currentIndex;
1494
+ }
1495
+ function processToolCall(params) {
1496
+ var _a;
1497
+ const { toolCall, tools, options, text, processedElements } = params;
1498
+ const toolSchema = getToolSchema(tools, toolCall.toolName);
1499
+ try {
1500
+ const primary = escapeInvalidLt(normalizeCloseTags(toolCall.content));
1501
+ let parsed = parse2(primary, toolSchema, {
1502
+ onError: options == null ? void 0 : options.onError,
1503
+ // Disable HTML self-closing tag behavior to allow base, meta, link etc. as regular tags
1504
+ noChildNodes: []
1505
+ });
1506
+ parsed = repairParsedAgainstSchema(parsed, toolSchema, options);
1507
+ processedElements.push({
1508
+ type: "tool-call",
1509
+ toolCallId: generateId2(),
1510
+ toolName: toolCall.toolName,
1511
+ input: JSON.stringify(parsed)
1512
+ });
1513
+ } catch (error) {
1514
+ const reparsed = tryParseSecondaryXml(
1515
+ toolCall.content,
1516
+ toolSchema,
1517
+ options
1518
+ );
1519
+ if (reparsed !== null) {
1520
+ processedElements.push({
1521
+ type: "tool-call",
1522
+ toolCallId: generateId2(),
1523
+ toolName: toolCall.toolName,
1524
+ input: JSON.stringify(reparsed)
1525
+ });
1526
+ return;
1527
+ }
1528
+ const originalCallText = text.substring(
1529
+ toolCall.startIndex,
1530
+ toolCall.endIndex
1531
+ );
1532
+ const message = `Could not process XML tool call, keeping original text: ${originalCallText}`;
1533
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1534
+ toolCall: originalCallText,
1535
+ toolName: toolCall.toolName,
1536
+ error
1537
+ });
1538
+ processedElements.push({ type: "text", text: originalCallText });
1539
+ }
1540
+ }
1541
+ function addRemainingText(text, currentIndex, processedElements) {
1542
+ if (currentIndex < text.length) {
1543
+ const remainingText = text.substring(currentIndex);
1544
+ if (remainingText.trim()) {
1545
+ processedElements.push({ type: "text", text: remainingText });
1546
+ }
1547
+ }
1548
+ }
1549
+ function handleStreamingToolCallEnd(params) {
1550
+ const { toolContent, currentToolCall, tools, options, ctrl, flushText } = params;
1551
+ const toolSchema = getToolSchema(tools, currentToolCall.name);
1552
+ try {
1553
+ const primary = escapeInvalidLt(normalizeCloseTags(toolContent));
1554
+ let parsed = parse2(primary, toolSchema, {
1555
+ onError: options == null ? void 0 : options.onError,
1556
+ noChildNodes: []
1557
+ });
1558
+ parsed = repairParsedAgainstSchema(parsed, toolSchema, options);
1559
+ flushText(ctrl);
1560
+ ctrl.enqueue({
1561
+ type: "tool-call",
1562
+ toolCallId: generateId2(),
1563
+ toolName: currentToolCall.name,
1564
+ input: JSON.stringify(parsed)
1565
+ });
1566
+ } catch (error) {
1567
+ const parsed = tryParseSecondaryXml(toolContent, toolSchema, options);
1568
+ if (parsed !== null) {
1569
+ flushText(ctrl);
1570
+ ctrl.enqueue({
1571
+ type: "tool-call",
1572
+ toolCallId: generateId2(),
1573
+ toolName: currentToolCall.name,
1574
+ input: JSON.stringify(parsed)
1575
+ });
1576
+ return;
1577
+ }
1578
+ handleStreamingToolCallError({
1579
+ error,
1580
+ currentToolCall,
1581
+ toolContent,
1582
+ options,
1583
+ ctrl,
1584
+ flushText
1585
+ });
1586
+ }
1587
+ }
1588
+ function handleStreamingToolCallError(params) {
1589
+ var _a;
1590
+ const { error, currentToolCall, toolContent, options, ctrl, flushText } = params;
1591
+ const endTag = `</${currentToolCall.name}>`;
1592
+ const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
1593
+ let message = "Could not process streaming XML tool call; emitting original text.";
1594
+ if (error instanceof RXMLDuplicateStringTagError) {
1595
+ message = `Duplicate string tags detected in streaming tool call '${currentToolCall.name}'; emitting original text.`;
1596
+ } else if (error instanceof RXMLCoercionError) {
1597
+ message = `Failed to coerce arguments for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1598
+ } else if (error instanceof RXMLParseError) {
1599
+ message = `Failed to parse XML for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1600
+ }
1601
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1602
+ toolCall: originalCallText,
1603
+ toolName: currentToolCall.name,
1604
+ error
1605
+ });
1606
+ flushText(ctrl, originalCallText);
1607
+ }
1608
+ function findEarliestToolTag(buffer, toolNames) {
1609
+ let bestIndex = -1;
1610
+ let bestName = "";
1611
+ let bestSelfClosing = false;
1612
+ if (toolNames.length > 0) {
1613
+ for (const name of toolNames) {
1614
+ const openTag = `<${name}>`;
1615
+ const selfTag = `<${name}/>`;
1616
+ const idxOpen = buffer.indexOf(openTag);
1617
+ const idxSelf = buffer.indexOf(selfTag);
1618
+ if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
1619
+ bestIndex = idxOpen;
1620
+ bestName = name;
1621
+ bestSelfClosing = false;
1622
+ }
1623
+ if (idxSelf !== -1 && (bestIndex === -1 || idxSelf < bestIndex)) {
1624
+ bestIndex = idxSelf;
1625
+ bestName = name;
1626
+ bestSelfClosing = true;
1627
+ }
1628
+ }
1629
+ }
1630
+ return { index: bestIndex, name: bestName, selfClosing: bestSelfClosing };
1631
+ }
1632
+ function handleNoToolTagInBuffer(buffer, maxStartTagLen, controller, flushText) {
1633
+ const tail = Math.max(0, maxStartTagLen - 1);
1634
+ const safeLen = Math.max(0, buffer.length - tail);
1635
+ if (safeLen > 0) {
1636
+ const textToFlush = buffer.slice(0, safeLen);
1637
+ flushText(controller, textToFlush);
1638
+ return { buffer: buffer.slice(safeLen), shouldContinue: true };
1639
+ }
1640
+ return { buffer, shouldContinue: false };
1641
+ }
1642
+ function processToolCallInBuffer(params) {
1643
+ const {
1644
+ buffer,
1645
+ currentToolCall,
1646
+ tools,
1647
+ options,
1648
+ controller,
1649
+ flushText,
1650
+ setBuffer
1651
+ } = params;
1652
+ const endTag = `</${currentToolCall.name}>`;
1653
+ const normalized = normalizeCloseTags(buffer);
1654
+ const effectiveBuffer = normalized;
1655
+ const endTagIndex = effectiveBuffer.indexOf(endTag);
1656
+ if (endTagIndex !== -1) {
1657
+ const toolContent = effectiveBuffer.substring(0, endTagIndex);
1658
+ const newBuffer = effectiveBuffer.substring(endTagIndex + endTag.length);
1659
+ setBuffer("");
1660
+ handleStreamingToolCallEnd({
1661
+ toolContent,
1662
+ currentToolCall,
1663
+ tools,
1664
+ options,
1665
+ ctrl: controller,
1666
+ flushText
1667
+ });
1668
+ setBuffer(newBuffer);
1669
+ return { buffer: newBuffer, currentToolCall: null, shouldBreak: false };
1670
+ }
1671
+ return { buffer: effectiveBuffer, currentToolCall, shouldBreak: true };
1672
+ }
1673
+ function processNoToolCallInBuffer(params) {
1674
+ const {
1675
+ buffer,
1676
+ toolNames,
1677
+ maxStartTagLen,
1678
+ controller,
1679
+ flushText,
1680
+ tools,
1681
+ options
1682
+ } = params;
1683
+ const {
1684
+ index: earliestStartTagIndex,
1685
+ name: earliestToolName,
1686
+ selfClosing
1687
+ } = findEarliestToolTag(buffer, toolNames);
1688
+ if (earliestStartTagIndex !== -1) {
1689
+ const textBeforeTag = buffer.substring(0, earliestStartTagIndex);
1690
+ flushText(controller, textBeforeTag);
1691
+ if (selfClosing) {
1692
+ const selfTag = `<${earliestToolName}/>`;
1693
+ const newBuffer2 = buffer.substring(
1694
+ earliestStartTagIndex + selfTag.length
1695
+ );
1696
+ handleStreamingToolCallEnd({
1697
+ toolContent: "",
1698
+ currentToolCall: { name: earliestToolName, content: "" },
1699
+ tools,
1700
+ options,
1701
+ ctrl: controller,
1702
+ flushText
1703
+ });
1704
+ return {
1705
+ buffer: newBuffer2,
1706
+ currentToolCall: null,
1707
+ shouldBreak: false,
1708
+ shouldContinue: false
1709
+ };
1710
+ }
1711
+ const startTag = `<${earliestToolName}>`;
1712
+ const newBuffer = buffer.substring(earliestStartTagIndex + startTag.length);
1713
+ return {
1714
+ buffer: newBuffer,
1715
+ currentToolCall: { name: earliestToolName, content: "" },
1716
+ shouldBreak: false,
1717
+ shouldContinue: false
1718
+ };
1719
+ }
1720
+ const result = handleNoToolTagInBuffer(
1721
+ buffer,
1722
+ maxStartTagLen,
1723
+ controller,
1724
+ flushText
1725
+ );
1726
+ return {
1727
+ buffer: result.buffer,
1728
+ currentToolCall: null,
1729
+ shouldBreak: !result.shouldContinue,
1730
+ shouldContinue: result.shouldContinue
1731
+ };
1732
+ }
1733
+ function createFlushTextHandler(getBuffer, setBuffer, getCurrentTextId, setCurrentTextId) {
1734
+ return (controller, text) => {
1735
+ const content = text != null ? text : getBuffer();
1736
+ if (content) {
1737
+ const currentTextId2 = getCurrentTextId();
1738
+ if (!currentTextId2) {
1739
+ const newId = generateId2();
1740
+ setCurrentTextId(newId);
1741
+ controller.enqueue({ type: "text-start", id: newId });
1742
+ }
1743
+ controller.enqueue({
1744
+ type: "text-delta",
1745
+ id: getCurrentTextId(),
1746
+ delta: content
1747
+ });
1748
+ if (text === void 0) {
1749
+ setBuffer("");
1750
+ }
1751
+ }
1752
+ const currentTextId = getCurrentTextId();
1753
+ if (currentTextId && !text) {
1754
+ controller.enqueue({ type: "text-end", id: currentTextId });
1755
+ setCurrentTextId(null);
1756
+ }
1757
+ };
1758
+ }
1759
+ function processBufferWithToolCall(params, controller) {
1760
+ const {
1761
+ getBuffer,
1762
+ setBuffer,
1763
+ getCurrentToolCall,
1764
+ setCurrentToolCall,
1765
+ tools,
1766
+ options,
1767
+ flushText
1768
+ } = params;
1769
+ const currentToolCall = getCurrentToolCall();
1770
+ if (!currentToolCall) {
1771
+ return true;
1772
+ }
1773
+ const result = processToolCallInBuffer({
1774
+ buffer: getBuffer(),
1775
+ currentToolCall,
1776
+ tools,
1777
+ options,
1778
+ controller,
1779
+ flushText,
1780
+ setBuffer
1781
+ });
1782
+ setBuffer(result.buffer);
1783
+ setCurrentToolCall(result.currentToolCall);
1784
+ return result.shouldBreak;
1785
+ }
1786
+ function processBufferWithoutToolCall(params, controller) {
1787
+ const {
1788
+ getBuffer,
1789
+ setBuffer,
1790
+ setCurrentToolCall,
1791
+ tools,
1792
+ options,
1793
+ toolNames,
1794
+ maxStartTagLen,
1795
+ flushText
1796
+ } = params;
1797
+ const result = processNoToolCallInBuffer({
1798
+ buffer: getBuffer(),
1799
+ toolNames,
1800
+ maxStartTagLen,
1801
+ controller,
1802
+ flushText,
1803
+ tools,
1804
+ options
1805
+ });
1806
+ setBuffer(result.buffer);
1807
+ setCurrentToolCall(result.currentToolCall);
1808
+ return {
1809
+ shouldBreak: result.shouldBreak,
1810
+ shouldContinue: result.shouldContinue
1811
+ };
1812
+ }
1813
+ function processBufferLoop(params, controller) {
1814
+ while (true) {
1815
+ const currentToolCall = params.getCurrentToolCall();
1816
+ if (currentToolCall) {
1817
+ const shouldBreak = processBufferWithToolCall(params, controller);
1818
+ if (shouldBreak) {
1819
+ break;
1820
+ }
1821
+ } else {
1822
+ const { shouldBreak, shouldContinue } = processBufferWithoutToolCall(
1823
+ params,
1824
+ controller
1825
+ );
1826
+ if (shouldContinue) {
1827
+ continue;
1828
+ }
1829
+ if (shouldBreak) {
1830
+ break;
1831
+ }
1832
+ }
1833
+ }
1834
+ }
1835
+ function createProcessBufferHandler(params) {
1836
+ return (controller) => {
1837
+ processBufferLoop(params, controller);
1838
+ };
1839
+ }
1840
+ var morphXmlProtocol = () => ({
1841
+ formatTools({ tools, toolSystemPromptTemplate }) {
1842
+ const toolsForPrompt = (tools || []).map((tool) => ({
1843
+ name: tool.name,
1844
+ description: tool.description,
1845
+ parameters: unwrapJsonSchema(tool.inputSchema)
1846
+ }));
1847
+ return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1848
+ },
1849
+ formatToolCall(toolCall) {
1850
+ let args = {};
1851
+ const inputValue = hasInputProperty(toolCall) ? toolCall.input : void 0;
1852
+ if (typeof inputValue === "string") {
1853
+ try {
1854
+ args = JSON.parse(inputValue);
1855
+ } catch (e) {
1856
+ args = inputValue;
1857
+ }
1858
+ } else {
1859
+ args = inputValue;
1860
+ }
1861
+ return stringify2(toolCall.toolName, args, {
1862
+ suppressEmptyNode: false,
1863
+ format: false
1864
+ });
1865
+ },
1866
+ formatToolResponse(toolResult) {
1867
+ return stringify2("tool_response", {
1868
+ tool_name: toolResult.toolName,
1869
+ result: toolResult.output
1870
+ });
1871
+ },
1872
+ parseGeneratedText({ text, tools, options }) {
1873
+ const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1874
+ if (toolNames.length === 0) {
1875
+ return [{ type: "text", text }];
1876
+ }
1877
+ const processedElements = [];
1878
+ let currentIndex = 0;
1879
+ const toolCallsRaw = findToolCalls(text, toolNames);
1880
+ const toolCallsNorm = collectToolCallsFromNormalizedText(text, toolNames);
1881
+ const seen = /* @__PURE__ */ new Set();
1882
+ const toolCalls = [...toolCallsRaw, ...toolCallsNorm].filter((tc) => {
1883
+ const key = `${tc.toolName}:${tc.startIndex}:${tc.endIndex}`;
1884
+ if (seen.has(key)) {
1885
+ return false;
1886
+ }
1887
+ seen.add(key);
1888
+ return true;
1889
+ }).sort((a, b) => a.startIndex - b.startIndex);
1890
+ for (const toolCall of toolCalls) {
1891
+ currentIndex = processTextBeforeToolCall(
1892
+ text,
1893
+ currentIndex,
1894
+ toolCall.startIndex,
1895
+ processedElements
1896
+ );
1897
+ processToolCall({ toolCall, tools, options, text, processedElements });
1898
+ currentIndex = toolCall.endIndex;
1899
+ }
1900
+ addRemainingText(text, currentIndex, processedElements);
1901
+ return processedElements;
1902
+ },
1903
+ createStreamParser({ tools, options }) {
1904
+ const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1905
+ const maxStartTagLen = toolNames.length ? Math.max(...toolNames.map((n) => `<${n}>`.length)) : 0;
1906
+ let buffer = "";
1907
+ let currentToolCall = null;
1908
+ let currentTextId = null;
1909
+ const flushText = createFlushTextHandler(
1910
+ () => buffer,
1911
+ (newBuffer) => {
1912
+ buffer = newBuffer;
1913
+ },
1914
+ () => currentTextId,
1915
+ (newId) => {
1916
+ currentTextId = newId;
1917
+ }
1918
+ );
1919
+ const processChunk = (chunk, controller) => {
1920
+ if (chunk.type !== "text-delta") {
1921
+ if (buffer) {
1922
+ flushText(controller);
1923
+ }
1924
+ controller.enqueue(chunk);
1925
+ return;
1926
+ }
1927
+ buffer += chunk.delta;
1928
+ processBuffer(controller);
1929
+ };
1930
+ const processBuffer = createProcessBufferHandler({
1931
+ getBuffer: () => buffer,
1932
+ setBuffer: (newBuffer) => {
1933
+ buffer = newBuffer;
1934
+ },
1935
+ getCurrentToolCall: () => currentToolCall,
1936
+ setCurrentToolCall: (newToolCall) => {
1937
+ currentToolCall = newToolCall;
1938
+ },
1939
+ tools,
1940
+ options,
1941
+ toolNames,
1942
+ maxStartTagLen,
1943
+ flushText
1944
+ });
1945
+ const flushBuffer2 = (controller) => {
1946
+ if (currentToolCall) {
1947
+ const unfinishedCall = `<${currentToolCall.name}>${buffer}`;
1948
+ flushText(controller, unfinishedCall);
1949
+ } else if (buffer) {
1950
+ flushText(controller);
1951
+ }
1952
+ if (currentTextId) {
1953
+ controller.enqueue({ type: "text-end", id: currentTextId });
1954
+ }
1955
+ };
1956
+ return new TransformStream({
1957
+ transform(chunk, controller) {
1958
+ processChunk(chunk, controller);
1959
+ },
1960
+ flush(controller) {
1961
+ flushBuffer2(controller);
1962
+ }
1963
+ });
1964
+ },
1965
+ extractToolCallSegments({ text, tools }) {
1966
+ const toolNames = tools.map((t) => t.name).filter(Boolean);
1967
+ if (toolNames.length === 0) {
1968
+ return [];
1969
+ }
1970
+ return findToolCalls(text, toolNames).map((tc) => tc.segment);
1971
+ }
1972
+ });
1973
+ function getToolSchema(tools, toolName) {
1974
+ var _a;
1975
+ return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
1976
+ }
1977
+ function findClosingTagEndFlexible(text, contentStart, toolName) {
1978
+ let pos = contentStart;
1979
+ let depth = 1;
1980
+ while (pos < text.length) {
1981
+ const tok = nextTagToken(text, pos);
1982
+ if (tok.kind === "eof") {
1983
+ break;
1984
+ }
1985
+ const result = updateDepthWithToken(tok, toolName, depth);
1986
+ depth = result.depth;
1987
+ if (result.closedAt !== void 0) {
1988
+ return result.closedAt;
1989
+ }
1990
+ pos = tok.nextPos;
1991
+ }
1992
+ return -1;
1993
+ }
1994
+ function skipSpecialSegment(text, lt) {
1995
+ const next = text[lt + 1];
1996
+ if (next !== "!" && next !== "?") {
1997
+ return null;
1998
+ }
1999
+ const gt = text.indexOf(">", lt + 1);
2000
+ if (gt === -1) {
2001
+ return null;
2002
+ }
2003
+ return gt + 1;
2004
+ }
2005
+ function consumeClosingTag(text, lt, toolName) {
2006
+ let p = lt + 2;
2007
+ while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2008
+ p += 1;
2009
+ }
2010
+ if (text.slice(p, p + toolName.length) === toolName) {
2011
+ p += toolName.length;
2012
+ while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2013
+ p += 1;
2014
+ }
2015
+ if (text[p] === ">") {
2016
+ const endPos2 = p + 1;
2017
+ return { matched: true, endPos: endPos2 };
2018
+ }
2019
+ }
2020
+ const gt = text.indexOf(">", lt + 1);
2021
+ const endPos = gt === -1 ? text.length : gt + 1;
2022
+ return { matched: false, endPos };
2023
+ }
2024
+ function consumeOpenTag(text, lt) {
2025
+ let p = lt + 1;
2026
+ while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2027
+ p += 1;
2028
+ }
2029
+ const nameStart = p;
2030
+ while (p < text.length && NAME_CHAR_RE.test(text.charAt(p))) {
2031
+ p += 1;
2032
+ }
2033
+ const name = text.slice(nameStart, p);
2034
+ const q = text.indexOf(">", p);
2035
+ if (q === -1) {
2036
+ return null;
2037
+ }
2038
+ let r = q - 1;
2039
+ while (r >= nameStart && WHITESPACE_REGEX2.test(text[r])) {
2040
+ r -= 1;
2041
+ }
2042
+ const selfClosing = text[r] === "/";
2043
+ return { name, selfClosing, nextPos: q + 1 };
2044
+ }
2045
+ function updateDepthWithToken(tok, toolName, depth) {
2046
+ if (tok.kind === "close" && tok.name === toolName) {
2047
+ const newDepth = depth - 1;
2048
+ return newDepth === 0 ? { depth: newDepth, closedAt: tok.nextPos } : { depth: newDepth };
2049
+ }
2050
+ if (tok.kind === "open" && tok.name === toolName && !tok.selfClosing) {
2051
+ return { depth: depth + 1 };
2052
+ }
2053
+ return { depth };
2054
+ }
2055
+ function nextTagToken(text, fromPos) {
2056
+ const lt = text.indexOf("<", fromPos);
2057
+ if (lt === -1 || lt + 1 >= text.length) {
2058
+ return { kind: "eof", nextPos: text.length };
2059
+ }
2060
+ const next = text[lt + 1];
2061
+ const specialEnd = skipSpecialSegment(text, lt);
2062
+ if (specialEnd !== null) {
2063
+ return { kind: "special", nextPos: specialEnd };
2064
+ }
2065
+ if (next === "/") {
2066
+ const closing = consumeClosingTag(text, lt, "");
2067
+ let p = lt + 2;
2068
+ while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2069
+ p += 1;
2070
+ }
2071
+ const nameStart = p;
2072
+ while (p < text.length && NAME_CHAR_RE.test(text.charAt(p))) {
2073
+ p += 1;
2074
+ }
2075
+ const name = text.slice(nameStart, p);
2076
+ return { kind: "close", name, nextPos: closing.endPos };
2077
+ }
2078
+ const open = consumeOpenTag(text, lt);
2079
+ if (open === null) {
2080
+ return { kind: "eof", nextPos: text.length };
2081
+ }
2082
+ return {
2083
+ kind: "open",
2084
+ name: open.name,
2085
+ selfClosing: open.selfClosing,
2086
+ nextPos: open.nextPos
2087
+ };
2088
+ }
2089
+ function collectToolCallsFromNormalizedText(text, toolNames) {
2090
+ var _a;
2091
+ const normalizedText = normalizeCloseTags(text);
2092
+ const collected = [];
2093
+ for (const toolName of toolNames) {
2094
+ const startTag = `<${toolName}>`;
2095
+ let idx = 0;
2096
+ let lastOrigIdx = 0;
2097
+ while (idx < normalizedText.length) {
2098
+ const tagStartNorm = normalizedText.indexOf(startTag, idx);
2099
+ if (tagStartNorm === -1) {
2100
+ break;
2101
+ }
2102
+ const contentStartNorm = tagStartNorm + startTag.length;
2103
+ const endNorm = findClosingTagEndFlexible(
2104
+ normalizedText,
2105
+ contentStartNorm,
2106
+ toolName
2107
+ );
2108
+ if (endNorm > contentStartNorm) {
2109
+ const tagStartOrig = text.indexOf(startTag, lastOrigIdx);
2110
+ const contentStartOrig = tagStartOrig + startTag.length;
2111
+ let endOrig = findClosingTagEndFlexible(
2112
+ text,
2113
+ contentStartOrig,
2114
+ toolName
2115
+ );
2116
+ if (endOrig === -1) {
2117
+ const approxLen = endNorm - tagStartNorm;
2118
+ endOrig = Math.min(text.length, tagStartOrig + approxLen);
2119
+ }
2120
+ const segment = text.substring(tagStartOrig, endOrig);
2121
+ const inner = (_a = extractRawInner(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2122
+ collected.push({
2123
+ toolName,
2124
+ startIndex: tagStartOrig,
2125
+ endIndex: endOrig,
2126
+ content: inner,
2127
+ segment
2128
+ });
2129
+ lastOrigIdx = endOrig;
2130
+ idx = endNorm;
2131
+ } else {
2132
+ idx = contentStartNorm;
2133
+ }
2134
+ }
2135
+ }
2136
+ return collected.sort((a, b) => a.startIndex - b.startIndex);
2137
+ }
2138
+ function getNextTagInfo(text, toolName, fromIndex) {
2139
+ const startTag = `<${toolName}>`;
2140
+ const selfTag = `<${toolName}/>`;
2141
+ const openIdx = text.indexOf(startTag, fromIndex);
2142
+ const selfIdx = text.indexOf(selfTag, fromIndex);
2143
+ const hasOpen = openIdx !== -1;
2144
+ const hasSelf = selfIdx !== -1;
2145
+ if (!(hasOpen || hasSelf)) {
2146
+ return {
2147
+ found: false,
2148
+ tagStart: -1,
2149
+ selfClosing: false,
2150
+ startTag,
2151
+ selfTag
2152
+ };
2153
+ }
2154
+ const pickSelf = hasSelf && (!hasOpen || selfIdx < openIdx);
2155
+ const tagStart = pickSelf ? selfIdx : openIdx;
2156
+ return { found: true, tagStart, selfClosing: pickSelf, startTag, selfTag };
2157
+ }
2158
+ function findToolCallsForName(text, toolName) {
2159
+ var _a;
2160
+ const toolCalls = [];
2161
+ let searchIndex = 0;
2162
+ while (searchIndex < text.length) {
2163
+ const info = getNextTagInfo(text, toolName, searchIndex);
2164
+ if (!info.found) {
2165
+ break;
2166
+ }
2167
+ const { tagStart, selfClosing, startTag, selfTag } = info;
2168
+ if (selfClosing) {
2169
+ const endIndex = tagStart + selfTag.length;
2170
+ const segment = text.substring(tagStart, endIndex);
2171
+ toolCalls.push({
2172
+ toolName,
2173
+ startIndex: tagStart,
2174
+ endIndex,
2175
+ content: "",
2176
+ segment
2177
+ });
2178
+ searchIndex = endIndex;
2179
+ continue;
2180
+ }
2181
+ const contentStart = tagStart + startTag.length;
2182
+ const fullTagEnd = findClosingTagEndFlexible(text, contentStart, toolName);
2183
+ if (fullTagEnd !== -1 && fullTagEnd > contentStart) {
2184
+ const segment = text.substring(tagStart, fullTagEnd);
2185
+ const inner = (_a = extractRawInner(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2186
+ toolCalls.push({
2187
+ toolName,
2188
+ startIndex: tagStart,
2189
+ endIndex: fullTagEnd,
2190
+ content: inner,
2191
+ segment
2192
+ });
2193
+ searchIndex = fullTagEnd;
2194
+ } else {
2195
+ searchIndex = contentStart;
2196
+ }
2197
+ }
2198
+ return toolCalls;
2199
+ }
2200
+ function findToolCalls(text, toolNames) {
2201
+ const toolCalls = [];
2202
+ for (const toolName of toolNames) {
2203
+ const calls = findToolCallsForName(text, toolName);
2204
+ toolCalls.push(...calls);
2205
+ }
2206
+ return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
2207
+ }
2208
+
2209
+ // src/generate-handler.ts
2210
+ import { generateId as generateId3 } from "@ai-sdk/provider-utils";
2211
+ import { coerceBySchema } from "@ai-sdk-tool/rxml";
2212
+
2213
+ // src/utils/on-error.ts
2214
+ function extractOnErrorOption(providerOptions) {
2215
+ var _a;
2216
+ if (providerOptions && typeof providerOptions === "object") {
2217
+ const onError = (_a = providerOptions.toolCallMiddleware) == null ? void 0 : _a.onError;
2218
+ return onError ? { onError } : void 0;
2219
+ }
2220
+ return;
2221
+ }
2222
+
2223
+ // src/utils/provider-options.ts
2224
+ var originalToolsSchema = {
2225
+ encode: encodeOriginalTools,
2226
+ decode: decodeOriginalTools
2227
+ };
2228
+ function encodeOriginalTools(tools) {
2229
+ return (tools == null ? void 0 : tools.map((t) => ({
2230
+ name: t.name,
2231
+ inputSchema: JSON.stringify(t.inputSchema)
2232
+ }))) || [];
2233
+ }
2234
+ function decodeOriginalTools(originalTools) {
2235
+ if (!originalTools) {
2236
+ return [];
2237
+ }
2238
+ return originalTools.map(
2239
+ (t) => ({
2240
+ type: "function",
2241
+ name: t.name,
2242
+ inputSchema: JSON.parse(t.inputSchema)
2243
+ })
2244
+ );
2245
+ }
2246
+ function extractToolNamesFromOriginalTools(originalTools) {
2247
+ return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
2248
+ }
2249
+ function isToolChoiceActive(params) {
2250
+ var _a, _b, _c;
2251
+ const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
2252
+ return !!(typeof params.providerOptions === "object" && params.providerOptions !== null && typeof ((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) === "object" && toolChoice && typeof toolChoice === "object" && (toolChoice.type === "tool" || toolChoice.type === "required"));
2253
+ }
2254
+
2255
+ // src/generate-handler.ts
2256
+ function parseToolChoiceJson(text, providerOptions) {
2257
+ var _a;
2258
+ try {
2259
+ return JSON.parse(text);
2260
+ } catch (error) {
2261
+ const options = extractOnErrorOption(providerOptions);
2262
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
2263
+ options,
2264
+ "Failed to parse toolChoice JSON from generated model output",
2265
+ {
2266
+ text,
2267
+ error: error instanceof Error ? error.message : String(error)
2268
+ }
2269
+ );
2270
+ return {};
2271
+ }
2272
+ }
2273
+ function logDebugSummary(debugSummary, toolCall, originText) {
2274
+ if (debugSummary) {
2275
+ debugSummary.originalText = originText;
2276
+ try {
2277
+ debugSummary.toolCalls = JSON.stringify([
2278
+ { toolName: toolCall.toolName, input: toolCall.input }
2279
+ ]);
2280
+ } catch (e) {
2281
+ }
2282
+ } else if (getDebugLevel() === "parse") {
2283
+ logParsedSummary({ toolCalls: [toolCall], originalText: originText });
2284
+ }
2285
+ }
2286
+ async function handleToolChoice(doGenerate, params) {
2287
+ var _a, _b, _c;
2288
+ const result = await doGenerate();
2289
+ const first = (_a = result.content) == null ? void 0 : _a[0];
2290
+ let parsed = {};
2291
+ if (first && first.type === "text") {
2292
+ if (getDebugLevel() === "parse") {
2293
+ logRawChunk(first.text);
2294
+ }
2295
+ parsed = parseToolChoiceJson(first.text, params.providerOptions);
2296
+ }
2297
+ const toolCall = {
2298
+ type: "tool-call",
2299
+ toolCallId: generateId3(),
2300
+ toolName: parsed.name || "unknown",
2301
+ input: JSON.stringify(parsed.arguments || {})
2302
+ };
2303
+ const originText = first && first.type === "text" ? first.text : "";
2304
+ const debugSummary = (_c = (_b = params.providerOptions) == null ? void 0 : _b.toolCallMiddleware) == null ? void 0 : _c.debugSummary;
2305
+ logDebugSummary(debugSummary, toolCall, originText);
2306
+ return {
2307
+ ...result,
2308
+ content: [toolCall]
2309
+ };
2310
+ }
2311
+ function parseContent(content, protocol, tools, providerOptions) {
2312
+ const parsed = content.flatMap((contentItem) => {
2313
+ if (contentItem.type !== "text") {
2314
+ return [contentItem];
2315
+ }
2316
+ if (getDebugLevel() === "stream") {
2317
+ logRawChunk(contentItem.text);
2318
+ }
2319
+ return protocol.parseGeneratedText({
2320
+ text: contentItem.text,
2321
+ tools,
2322
+ options: {
2323
+ ...extractOnErrorOption(providerOptions),
2324
+ ...providerOptions == null ? void 0 : providerOptions.toolCallMiddleware
2325
+ }
2326
+ });
2327
+ });
2328
+ return parsed.map(
2329
+ (part) => fixToolCallWithSchema(part, tools)
2330
+ );
2331
+ }
2332
+ function logParsedContent(content) {
2333
+ if (getDebugLevel() === "stream") {
2334
+ for (const part of content) {
2335
+ logParsedChunk(part);
2336
+ }
2337
+ }
2338
+ }
2339
+ function computeDebugSummary(options) {
2340
+ var _a;
2341
+ const { result, newContent, protocol, tools, providerOptions } = options;
2342
+ const allText = result.content.filter(
2343
+ (c) => c.type === "text"
2344
+ ).map((c) => c.text).join("\n\n");
2345
+ const segments = protocol.extractToolCallSegments ? protocol.extractToolCallSegments({ text: allText, tools }) : [];
2346
+ const originalText = segments.join("\n\n");
2347
+ const toolCalls = newContent.filter(
2348
+ (p) => p.type === "tool-call"
2349
+ );
2350
+ const dbg = (_a = providerOptions == null ? void 0 : providerOptions.toolCallMiddleware) == null ? void 0 : _a.debugSummary;
2351
+ if (dbg) {
2352
+ dbg.originalText = originalText;
2353
+ try {
2354
+ dbg.toolCalls = JSON.stringify(
2355
+ toolCalls.map((tc) => ({
2356
+ toolName: tc.toolName,
2357
+ input: tc.input
2358
+ }))
2359
+ );
2360
+ } catch (e) {
2361
+ }
2362
+ } else if (getDebugLevel() === "parse") {
2363
+ logParsedSummary({ toolCalls, originalText });
2364
+ }
2365
+ }
2366
+ async function wrapGenerate({
2367
+ protocol,
2368
+ doGenerate,
2369
+ params
2370
+ }) {
2371
+ var _a, _b;
2372
+ if (isToolChoiceActive(params)) {
2373
+ return handleToolChoice(doGenerate, params);
2374
+ }
2375
+ const tools = originalToolsSchema.decode(
2376
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
2377
+ );
2378
+ const result = await doGenerate();
2379
+ if (result.content.length === 0) {
2380
+ return result;
2381
+ }
2382
+ const newContent = parseContent(
2383
+ result.content,
2384
+ protocol,
2385
+ tools,
2386
+ params.providerOptions
2387
+ );
2388
+ logParsedContent(newContent);
2389
+ computeDebugSummary({
2390
+ result,
2391
+ newContent,
2392
+ protocol,
2393
+ tools,
2394
+ providerOptions: params.providerOptions
2395
+ });
2396
+ return {
2397
+ ...result,
2398
+ content: newContent
2399
+ };
2400
+ }
2401
+ function fixToolCallWithSchema(part, tools) {
2402
+ var _a;
2403
+ if (part.type !== "tool-call") {
2404
+ return part;
2405
+ }
2406
+ const tc = part;
2407
+ let args = {};
2408
+ if (typeof tc.input === "string") {
2409
+ try {
2410
+ args = JSON.parse(tc.input);
2411
+ } catch (e) {
2412
+ return part;
2413
+ }
2414
+ } else if (tc.input && typeof tc.input === "object") {
2415
+ args = tc.input;
2416
+ }
2417
+ const schema = (_a = tools.find((t) => t.name === tc.toolName)) == null ? void 0 : _a.inputSchema;
2418
+ const coerced = coerceBySchema(args, schema);
2419
+ return {
2420
+ ...part,
2421
+ input: JSON.stringify(coerced != null ? coerced : {})
2422
+ };
2423
+ }
2424
+
2425
+ // src/protocols/tool-call-protocol.ts
2426
+ function isProtocolFactory(protocol) {
2427
+ return typeof protocol === "function";
2428
+ }
2429
+
2430
+ // src/stream-handler.ts
2431
+ import { generateId as generateId4 } from "@ai-sdk/provider-utils";
2432
+ function extractToolCallSegments(protocol, fullRawText, tools) {
2433
+ const segments = protocol.extractToolCallSegments ? protocol.extractToolCallSegments({
2434
+ text: fullRawText,
2435
+ tools
2436
+ }) : [];
2437
+ return segments.join("\n\n");
2438
+ }
2439
+ function serializeToolCalls(parsedToolCalls) {
2440
+ const toolCallParts = parsedToolCalls.filter(
2441
+ (p) => p.type === "tool-call"
2442
+ );
2443
+ return JSON.stringify(
2444
+ toolCallParts.map((tc) => ({
2445
+ toolName: tc.toolName,
2446
+ input: tc.input
2447
+ }))
2448
+ );
2449
+ }
2450
+ function handleDebugSummary(parsedToolCalls, origin, params) {
2451
+ var _a, _b;
2452
+ const dbg = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.debugSummary;
2453
+ if (dbg) {
2454
+ dbg.originalText = origin;
2455
+ try {
2456
+ dbg.toolCalls = serializeToolCalls(parsedToolCalls);
2457
+ } catch (e) {
2458
+ }
2459
+ } else {
2460
+ logParsedSummary({
2461
+ toolCalls: parsedToolCalls,
2462
+ originalText: origin
2463
+ });
2464
+ }
2465
+ }
2466
+ function createDebugSummaryTransform({
2467
+ protocol,
2468
+ getFullRawText,
2469
+ tools,
2470
+ params
2471
+ }) {
2472
+ return new TransformStream({
2473
+ transform: /* @__PURE__ */ (() => {
2474
+ const parsedToolCalls = [];
2475
+ return (part, controller) => {
2476
+ if (part.type === "tool-call") {
2477
+ parsedToolCalls.push(part);
2478
+ }
2479
+ if (part.type === "finish") {
2480
+ try {
2481
+ const raw = getFullRawText();
2482
+ logRawChunk(raw);
2483
+ const origin = extractToolCallSegments(protocol, raw, tools);
2484
+ handleDebugSummary(parsedToolCalls, origin, params);
2485
+ } catch (e) {
2486
+ }
2487
+ }
2488
+ controller.enqueue(part);
2489
+ };
2490
+ })()
2491
+ });
2492
+ }
2493
+ async function wrapStream({
2494
+ protocol,
2495
+ doStream,
2496
+ doGenerate,
2497
+ params
2498
+ }) {
2499
+ var _a, _b, _c;
2500
+ if (isToolChoiceActive(params)) {
2501
+ return toolChoiceStream({
2502
+ doGenerate,
2503
+ options: extractOnErrorOption(params.providerOptions)
2504
+ });
2505
+ }
2506
+ const { stream, ...rest } = await doStream();
2507
+ const debugLevel = getDebugLevel();
2508
+ const tools = originalToolsSchema.decode(
2509
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
2510
+ );
2511
+ const options = {
2512
+ ...extractOnErrorOption(params.providerOptions),
2513
+ ...(_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware
2514
+ };
2515
+ if (debugLevel === "off") {
2516
+ return {
2517
+ stream: stream.pipeThrough(
2518
+ protocol.createStreamParser({
2519
+ tools,
2520
+ options
2521
+ })
2522
+ ),
2523
+ ...rest
2524
+ };
2525
+ }
2526
+ if (debugLevel === "stream") {
2527
+ const withRawTap2 = stream.pipeThrough(
2528
+ new TransformStream(
2529
+ {
2530
+ transform(part, controller) {
2531
+ logRawChunk(part);
2532
+ controller.enqueue(part);
2533
+ }
2534
+ }
2535
+ )
2536
+ );
2537
+ const parsed2 = withRawTap2.pipeThrough(
2538
+ protocol.createStreamParser({
2539
+ tools,
2540
+ options
2541
+ })
2542
+ );
2543
+ const withParsedTap = parsed2.pipeThrough(
2544
+ new TransformStream(
2545
+ {
2546
+ transform(part, controller) {
2547
+ logParsedChunk(part);
2548
+ controller.enqueue(part);
2549
+ }
2550
+ }
2551
+ )
2552
+ );
2553
+ return {
2554
+ stream: withParsedTap,
2555
+ ...rest
2556
+ };
2557
+ }
2558
+ let fullRawText = "";
2559
+ const withRawTap = stream.pipeThrough(
2560
+ new TransformStream({
2561
+ transform(part, controller) {
2562
+ if (part.type === "text-delta") {
2563
+ const delta = part.delta;
2564
+ if (typeof delta === "string" && delta.length > 0) {
2565
+ fullRawText += delta;
2566
+ }
2567
+ }
2568
+ controller.enqueue(part);
2569
+ }
2570
+ })
2571
+ );
2572
+ const parsed = withRawTap.pipeThrough(
2573
+ protocol.createStreamParser({
2574
+ tools,
2575
+ options
2576
+ })
2577
+ );
2578
+ const withSummary = parsed.pipeThrough(
2579
+ createDebugSummaryTransform({
2580
+ protocol,
2581
+ getFullRawText: () => fullRawText,
2582
+ tools,
2583
+ params
2584
+ })
2585
+ );
2586
+ return {
2587
+ stream: withSummary,
2588
+ ...rest
2589
+ };
2590
+ }
2591
+ async function toolChoiceStream({
2592
+ doGenerate,
2593
+ options
2594
+ }) {
2595
+ var _a, _b, _c;
2596
+ const result = await doGenerate();
2597
+ let toolJson = {};
2598
+ if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
2599
+ try {
2600
+ toolJson = JSON.parse(result.content[0].text);
2601
+ } catch (error) {
2602
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
2603
+ options,
2604
+ "Failed to parse toolChoice JSON from streamed model output",
2605
+ {
2606
+ text: result.content[0].text,
2607
+ error: error instanceof Error ? error.message : String(error)
2608
+ }
2609
+ );
2610
+ toolJson = {};
2611
+ }
2612
+ }
2613
+ const toolCallChunk = {
2614
+ type: "tool-call",
2615
+ toolCallId: generateId4(),
2616
+ toolName: toolJson.name || "unknown",
2617
+ input: JSON.stringify(toolJson.arguments || {})
2618
+ };
2619
+ const finishChunk = {
2620
+ type: "finish",
2621
+ usage: (result == null ? void 0 : result.usage) || {
2622
+ inputTokens: {
2623
+ total: 0,
2624
+ noCache: void 0,
2625
+ cacheRead: void 0,
2626
+ cacheWrite: void 0
2627
+ },
2628
+ outputTokens: {
2629
+ total: 0,
2630
+ text: void 0,
2631
+ reasoning: void 0
2632
+ }
2633
+ },
2634
+ finishReason: { unified: "tool-calls", raw: void 0 }
2635
+ };
2636
+ const stream = new ReadableStream({
2637
+ start(controller) {
2638
+ controller.enqueue(toolCallChunk);
2639
+ controller.enqueue(finishChunk);
2640
+ controller.close();
2641
+ }
2642
+ });
2643
+ const debugLevel = getDebugLevel();
2644
+ const firstText = ((_c = result == null ? void 0 : result.content) == null ? void 0 : _c[0]) && result.content[0].type === "text" && result.content[0].text || "";
2645
+ const streamWithSummary = debugLevel === "parse" ? stream.pipeThrough(
2646
+ new TransformStream({
2647
+ transform(part, controller) {
2648
+ if (part.type === "finish") {
2649
+ try {
2650
+ logParsedSummary({
2651
+ toolCalls: [toolCallChunk],
2652
+ originalText: typeof firstText === "string" ? firstText : ""
2653
+ });
2654
+ } catch (e) {
2655
+ }
2656
+ }
2657
+ controller.enqueue(part);
2658
+ }
2659
+ })
2660
+ ) : stream;
2661
+ return {
2662
+ request: (result == null ? void 0 : result.request) || {},
2663
+ response: (result == null ? void 0 : result.response) || {},
2664
+ stream: streamWithSummary
2665
+ };
2666
+ }
2667
+
2668
+ // src/utils/dynamic-tool-schema.ts
2669
+ function createDynamicIfThenElseSchema(tools) {
2670
+ let currentSchema = {};
2671
+ const toolNames = [];
2672
+ for (let i = tools.length - 1; i >= 0; i -= 1) {
2673
+ const tool = tools[i];
2674
+ if (tool.type === "provider") {
2675
+ throw new Error(
2676
+ "Provider tools are not supported by this middleware. Please use function tools."
2677
+ );
2678
+ }
2679
+ toolNames.unshift(tool.name);
2680
+ const toolCondition = {
2681
+ if: {
2682
+ properties: {
2683
+ name: {
2684
+ const: tool.name
2685
+ }
2686
+ },
2687
+ required: ["name"]
2688
+ },
2689
+ // biome-ignore lint/suspicious/noThenProperty: JSON Schema uses 'then' as a keyword
2690
+ then: {
2691
+ properties: {
2692
+ name: {
2693
+ const: tool.name
2694
+ },
2695
+ arguments: tool.inputSchema
2696
+ },
2697
+ required: ["name", "arguments"]
2698
+ }
2699
+ };
2700
+ if (Object.keys(currentSchema).length > 0) {
2701
+ toolCondition.else = currentSchema;
2702
+ }
2703
+ currentSchema = toolCondition;
2704
+ }
2705
+ return {
2706
+ type: "object",
2707
+ // Explicitly specify type as "object"
2708
+ properties: {
2709
+ name: {
2710
+ type: "string",
2711
+ description: "Name of the tool to call",
2712
+ enum: toolNames
2713
+ },
2714
+ arguments: {
2715
+ type: "object",
2716
+ // By default, arguments is also specified as object type
2717
+ description: "Argument object to be passed to the tool"
2718
+ }
2719
+ },
2720
+ required: ["name", "arguments"],
2721
+ ...currentSchema
2722
+ };
2723
+ }
2724
+
2725
+ // src/transform-handler.ts
2726
+ function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
2727
+ const systemIndex = processedPrompt.findIndex((m) => m.role === "system");
2728
+ if (systemIndex !== -1) {
2729
+ const existing = processedPrompt[systemIndex].content;
2730
+ let existingText = "";
2731
+ if (typeof existing === "string") {
2732
+ existingText = existing;
2733
+ } else if (Array.isArray(existing)) {
2734
+ existingText = existing.map((p) => {
2735
+ var _a;
2736
+ return (p == null ? void 0 : p.type) === "text" ? (_a = p.text) != null ? _a : "" : "";
2737
+ }).filter(Boolean).join("\n");
2738
+ } else {
2739
+ existingText = String(existing != null ? existing : "");
2740
+ }
2741
+ const mergedContent = placement === "first" ? `${systemPrompt}
2742
+
2743
+ ${existingText}` : `${existingText}
2744
+
2745
+ ${systemPrompt}`;
2746
+ return processedPrompt.map(
2747
+ (m, idx) => idx === systemIndex ? {
2748
+ ...m,
2749
+ content: mergedContent
2750
+ } : m
2751
+ );
2752
+ }
2753
+ if (placement === "first") {
2754
+ return [
2755
+ {
2756
+ role: "system",
2757
+ content: systemPrompt
2758
+ },
2759
+ ...processedPrompt
2760
+ ];
2761
+ }
2762
+ return [
2763
+ ...processedPrompt,
2764
+ {
2765
+ role: "system",
2766
+ content: systemPrompt
2767
+ }
2768
+ ];
2769
+ }
2770
+ function buildBaseReturnParams(params, finalPrompt, functionTools) {
2771
+ return {
2772
+ ...params,
2773
+ prompt: finalPrompt,
2774
+ tools: [],
2775
+ toolChoice: void 0,
2776
+ providerOptions: {
2777
+ ...params.providerOptions || {},
2778
+ toolCallMiddleware: {
2779
+ ...params.providerOptions && typeof params.providerOptions === "object" && params.providerOptions.toolCallMiddleware || {},
2780
+ originalTools: originalToolsSchema.encode(functionTools)
2781
+ }
2782
+ }
2783
+ };
2784
+ }
2785
+ function findProviderDefinedTool(tools, selectedToolName) {
2786
+ return tools.find((t) => {
2787
+ if (t.type === "function") {
2788
+ return false;
2789
+ }
2790
+ const anyTool = t;
2791
+ return anyTool.id === selectedToolName || anyTool.name === selectedToolName;
2792
+ });
2793
+ }
2794
+ function handleToolChoiceTool(params, baseReturnParams) {
2795
+ var _a, _b, _c;
2796
+ const selectedToolName = (_a = params.toolChoice) == null ? void 0 : _a.toolName;
2797
+ if (!selectedToolName) {
2798
+ throw new Error("Tool name is required for 'tool' toolChoice type.");
2799
+ }
2800
+ const providerDefinedMatch = findProviderDefinedTool(
2801
+ (_b = params.tools) != null ? _b : [],
2802
+ selectedToolName
2803
+ );
2804
+ if (providerDefinedMatch) {
2805
+ throw new Error(
2806
+ "Provider-defined tools are not supported by this middleware. Please use custom tools."
2807
+ );
2808
+ }
2809
+ const selectedTool = ((_c = params.tools) != null ? _c : []).find(
2810
+ (t) => t.type === "function" && t.name === selectedToolName
2811
+ );
2812
+ if (!selectedTool) {
2813
+ throw new Error(
2814
+ `Tool with name '${selectedToolName}' not found in params.tools.`
2815
+ );
2816
+ }
2817
+ return {
2818
+ ...baseReturnParams,
2819
+ responseFormat: {
2820
+ type: "json",
2821
+ schema: {
2822
+ type: "object",
2823
+ properties: {
2824
+ name: {
2825
+ const: selectedTool.name
2826
+ },
2827
+ arguments: selectedTool.inputSchema
2828
+ },
2829
+ required: ["name", "arguments"]
2830
+ },
2831
+ name: selectedTool.name,
2832
+ description: typeof selectedTool.description === "string" ? selectedTool.description : void 0
2833
+ },
2834
+ providerOptions: {
2835
+ ...baseReturnParams.providerOptions || {},
2836
+ toolCallMiddleware: {
2837
+ ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
2838
+ ...params.toolChoice ? { toolChoice: params.toolChoice } : {}
2839
+ }
2840
+ }
2841
+ };
2842
+ }
2843
+ function handleToolChoiceRequired(params, baseReturnParams, functionTools) {
2844
+ if (!params.tools || params.tools.length === 0) {
2845
+ throw new Error(
2846
+ "Tool choice type 'required' is set, but no tools are provided in params.tools."
2847
+ );
2848
+ }
2849
+ return {
2850
+ ...baseReturnParams,
2851
+ responseFormat: {
2852
+ type: "json",
2853
+ schema: createDynamicIfThenElseSchema(functionTools)
2854
+ },
2855
+ providerOptions: {
2856
+ ...baseReturnParams.providerOptions || {},
2857
+ toolCallMiddleware: {
2858
+ ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
2859
+ toolChoice: { type: "required" }
2860
+ }
2861
+ }
2862
+ };
2863
+ }
2864
+ function transformParams({
2865
+ params,
2866
+ protocol,
2867
+ toolSystemPromptTemplate,
2868
+ placement = "first"
2869
+ }) {
2870
+ var _a, _b, _c, _d, _e;
2871
+ const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
2872
+ const functionTools = ((_a = params.tools) != null ? _a : []).filter(
2873
+ (t) => t.type === "function"
2874
+ );
2875
+ const systemPrompt = resolvedProtocol.formatTools({
2876
+ tools: functionTools,
2877
+ toolSystemPromptTemplate
2878
+ });
2879
+ const processedPrompt = convertToolPrompt(
2880
+ (_b = params.prompt) != null ? _b : [],
2881
+ resolvedProtocol,
2882
+ extractOnErrorOption(params.providerOptions)
2883
+ );
2884
+ const finalPrompt = buildFinalPrompt(
2885
+ systemPrompt,
2886
+ processedPrompt,
2887
+ placement
2888
+ );
2889
+ const baseReturnParams = buildBaseReturnParams(
2890
+ params,
2891
+ finalPrompt,
2892
+ functionTools
2893
+ );
2894
+ if (((_c = params.toolChoice) == null ? void 0 : _c.type) === "none") {
2895
+ throw new Error(
2896
+ "The 'none' toolChoice type is not supported by this middleware. Please use 'auto', 'required', or specify a tool name."
2897
+ );
2898
+ }
2899
+ if (((_d = params.toolChoice) == null ? void 0 : _d.type) === "tool") {
2900
+ return handleToolChoiceTool(params, baseReturnParams);
2901
+ }
2902
+ if (((_e = params.toolChoice) == null ? void 0 : _e.type) === "required") {
2903
+ return handleToolChoiceRequired(params, baseReturnParams, functionTools);
2904
+ }
2905
+ return baseReturnParams;
2906
+ }
2907
+ function processAssistantContent(content, resolvedProtocol, providerOptions) {
2908
+ var _a;
2909
+ const newContent = [];
2910
+ for (const item of content) {
2911
+ if (isToolCallContent(item)) {
2912
+ newContent.push({
2913
+ type: "text",
2914
+ text: resolvedProtocol.formatToolCall(item)
2915
+ });
2916
+ } else if (item.type === "text") {
2917
+ newContent.push(item);
2918
+ } else if (item.type === "reasoning") {
2919
+ newContent.push(item);
2920
+ } else {
2921
+ const options = extractOnErrorOption(providerOptions);
2922
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
2923
+ options,
2924
+ "tool-call-middleware: unknown assistant content; stringifying for provider compatibility",
2925
+ { content: item }
2926
+ );
2927
+ newContent.push({
2928
+ type: "text",
2929
+ text: JSON.stringify(item)
2930
+ });
2931
+ }
2932
+ }
2933
+ const onlyText = newContent.every((c) => c.type === "text");
2934
+ return onlyText ? [
2935
+ {
2936
+ type: "text",
2937
+ text: newContent.map((c) => c.text).join("\n")
2938
+ }
2939
+ ] : newContent;
2940
+ }
2941
+ function processToolMessage(content, resolvedProtocol) {
2942
+ return {
2943
+ role: "user",
2944
+ content: [
2945
+ {
2946
+ type: "text",
2947
+ text: content.map((toolResult) => resolvedProtocol.formatToolResponse(toolResult)).join("\n")
2948
+ }
2949
+ ]
2950
+ };
2951
+ }
2952
+ function processMessage(message, resolvedProtocol, providerOptions) {
2953
+ if (message.role === "assistant") {
2954
+ const condensedContent = processAssistantContent(
2955
+ message.content,
2956
+ resolvedProtocol,
2957
+ providerOptions
2958
+ );
2959
+ return {
2960
+ role: "assistant",
2961
+ content: condensedContent
2962
+ };
2963
+ }
2964
+ if (message.role === "tool") {
2965
+ const toolResultParts = message.content.filter(
2966
+ (part) => part.type === "tool-result"
2967
+ );
2968
+ return processToolMessage(toolResultParts, resolvedProtocol);
2969
+ }
2970
+ return message;
2971
+ }
2972
+ function isAllTextContent(content) {
2973
+ if (!Array.isArray(content)) {
2974
+ return false;
2975
+ }
2976
+ return content.every(
2977
+ (c) => (c == null ? void 0 : c.type) === "text"
2978
+ );
2979
+ }
2980
+ function joinTextContent(content) {
2981
+ return content.map((c) => c.text).join("\n");
2982
+ }
2983
+ function createCondensedMessage(role, joinedText) {
2984
+ if (role === "system") {
2985
+ return {
2986
+ role: "system",
2987
+ content: joinedText
2988
+ };
2989
+ }
2990
+ return {
2991
+ role,
2992
+ content: [
2993
+ {
2994
+ type: "text",
2995
+ text: joinedText
2996
+ }
2997
+ ]
2998
+ };
2999
+ }
3000
+ function condenseTextContent(processedPrompt) {
3001
+ for (let i = 0; i < processedPrompt.length; i += 1) {
3002
+ const msg = processedPrompt[i];
3003
+ if (!Array.isArray(msg.content)) {
3004
+ continue;
3005
+ }
3006
+ const shouldCondense = isAllTextContent(msg.content) && msg.content.length > 1;
3007
+ if (shouldCondense) {
3008
+ const joinedText = joinTextContent(msg.content);
3009
+ processedPrompt[i] = createCondensedMessage(msg.role, joinedText);
3010
+ }
3011
+ }
3012
+ return processedPrompt;
3013
+ }
3014
+ function mergeConsecutiveUserMessages(processedPrompt) {
3015
+ for (let i = processedPrompt.length - 1; i > 0; i -= 1) {
3016
+ const current = processedPrompt[i];
3017
+ const prev = processedPrompt[i - 1];
3018
+ if (current.role === "user" && prev.role === "user") {
3019
+ const prevContent = prev.content.map((c) => c.type === "text" ? c.text : "").join("\n");
3020
+ const currentContent = current.content.map((c) => c.type === "text" ? c.text : "").join("\n");
3021
+ processedPrompt[i - 1] = {
3022
+ role: "user",
3023
+ content: [{ type: "text", text: `${prevContent}
3024
+ ${currentContent}` }]
3025
+ };
3026
+ processedPrompt.splice(i, 1);
3027
+ }
3028
+ }
3029
+ return processedPrompt;
3030
+ }
3031
+ function convertToolPrompt(prompt, resolvedProtocol, providerOptions) {
3032
+ let processedPrompt = prompt.map(
3033
+ (message) => processMessage(message, resolvedProtocol, providerOptions)
3034
+ );
3035
+ processedPrompt = condenseTextContent(processedPrompt);
3036
+ processedPrompt = mergeConsecutiveUserMessages(processedPrompt);
3037
+ return processedPrompt;
3038
+ }
3039
+
3040
+ // src/tool-call-middleware.ts
3041
+ function createToolMiddleware({
3042
+ protocol,
3043
+ toolSystemPromptTemplate,
3044
+ placement = "last"
3045
+ }) {
3046
+ const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
3047
+ return {
3048
+ specificationVersion: "v3",
3049
+ wrapStream: ({ doStream, doGenerate, params }) => {
3050
+ if (isToolChoiceActive(params)) {
3051
+ return toolChoiceStream({
3052
+ doGenerate,
3053
+ options: extractOnErrorOption(params.providerOptions)
3054
+ });
3055
+ }
3056
+ return wrapStream({
3057
+ protocol: resolvedProtocol,
3058
+ doStream,
3059
+ doGenerate,
3060
+ params
3061
+ });
3062
+ },
3063
+ wrapGenerate: async ({ doGenerate, params }) => wrapGenerate({
3064
+ protocol: resolvedProtocol,
3065
+ doGenerate,
3066
+ params
3067
+ }),
3068
+ transformParams: async ({ params }) => transformParams({
3069
+ protocol: resolvedProtocol,
3070
+ toolSystemPromptTemplate,
3071
+ placement,
3072
+ params
3073
+ })
3074
+ };
3075
+ }
3076
+
3077
+ // src/index.ts
3078
+ var gemmaToolMiddleware = createToolMiddleware({
3079
+ protocol: jsonMixProtocol(
3080
+ // Customize the tool call delimiters to use markdown code fences
3081
+ {
3082
+ toolCallStart: "```tool_call\n",
3083
+ // TODO: Support specifying multiple possible tags,
3084
+ // e.g., for gemma, it would be nice to be able to set both `` and ``` at the same time.
3085
+ toolCallEnd: "\n```",
3086
+ toolResponseStart: "```tool_response\n",
3087
+ toolResponseEnd: "\n```"
3088
+ }
3089
+ ),
3090
+ toolSystemPromptTemplate(tools) {
3091
+ return `You have access to functions. If you decide to invoke any of the function(s),
3092
+ you MUST put it in the format of markdown code fence block with the language name of tool_call , e.g.
3093
+ \`\`\`tool_call
3094
+ {'name': <function-name>, 'arguments': <args-dict>}
3095
+ \`\`\`
3096
+ You SHOULD NOT include any other text in the response if you call a function
3097
+ ${tools}`;
3098
+ }
3099
+ });
3100
+ var hermesToolMiddleware = createToolMiddleware({
3101
+ protocol: jsonMixProtocol,
3102
+ toolSystemPromptTemplate(tools) {
3103
+ return `You are a function calling AI model.
3104
+ You are provided with function signatures within <tools></tools> XML tags.
3105
+ You may call one or more functions to assist with the user query.
3106
+ Don't make assumptions about what values to plug into functions.
3107
+ Here are the available tools: <tools>${tools}</tools>
3108
+ Use the following pydantic model json schema for each tool call you will make: {"title": "FunctionCall", "type": "object", "properties": {"arguments": {"title": "Arguments", "type": "object"}, "name": {"title": "Name", "type": "string"}}, "required": ["arguments", "name"]}
3109
+ For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:
3110
+ <tool_call>
3111
+ {"name": "<function-name>", "arguments": <args-dict>}
3112
+ </tool_call>`;
3113
+ }
3114
+ });
3115
+ var morphXmlToolMiddleware = createToolMiddleware({
3116
+ protocol: morphXmlProtocol,
3117
+ placement: "last",
3118
+ toolSystemPromptTemplate(tools) {
3119
+ return `You are a function calling AI model.
3120
+
3121
+ Available functions are listed inside <tools></tools>.
3122
+ <tools>${tools}</tools>
3123
+
3124
+ # Rules
3125
+ - Use exactly one XML element whose tag name is the function name.
3126
+ - Put each parameter as a child element.
3127
+ - Values must follow the schema exactly (numbers, arrays, objects, enums \u2192 copy as-is).
3128
+ - Do not add or remove functions or parameters.
3129
+ - Each required parameter must appear once.
3130
+ - Output nothing before or after the function call.
3131
+
3132
+ # Example
3133
+ <get_weather>
3134
+ <location>New York</location>
3135
+ <unit>celsius</unit>
3136
+ </get_weather>`;
3137
+ }
3138
+ });
3139
+
3140
+ export {
3141
+ getDebugLevel,
3142
+ logParseFailure,
3143
+ logRawChunk,
3144
+ logParsedChunk,
3145
+ logParsedSummary,
3146
+ getPotentialStartIndex,
3147
+ escapeRegExp,
3148
+ transform,
3149
+ parse,
3150
+ stringify,
3151
+ jsonMixProtocol,
3152
+ isToolCallContent,
3153
+ isToolResultPart,
3154
+ hasInputProperty,
3155
+ morphXmlProtocol,
3156
+ extractOnErrorOption,
3157
+ originalToolsSchema,
3158
+ encodeOriginalTools,
3159
+ decodeOriginalTools,
3160
+ extractToolNamesFromOriginalTools,
3161
+ isToolChoiceActive,
3162
+ createDynamicIfThenElseSchema,
3163
+ createToolMiddleware,
3164
+ gemmaToolMiddleware,
3165
+ hermesToolMiddleware,
3166
+ morphXmlToolMiddleware
3167
+ };
3168
+ //# sourceMappingURL=chunk-L4X363EL.js.map