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