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