@ai-sdk-tool/parser 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1644 +1,1652 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
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
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/v6/index.ts
31
- var v6_exports = {};
32
- __export(v6_exports, {
33
- createToolMiddleware: () => createToolMiddleware,
34
- gemmaToolMiddleware: () => gemmaToolMiddleware,
35
- hermesToolMiddleware: () => hermesToolMiddleware,
36
- morphXmlToolMiddleware: () => morphXmlToolMiddleware,
37
- orchestratorToolMiddleware: () => orchestratorToolMiddleware
38
- });
39
- module.exports = __toCommonJS(v6_exports);
40
-
41
- // src/core/utils/debug.ts
42
- var LINE_SPLIT_REGEX = /\r?\n/;
43
- function normalizeBooleanString(value) {
44
- const normalized = value.trim().toLowerCase();
45
- if (normalized === "1" || normalized === "true" || normalized === "yes") {
46
- return true;
47
- }
48
- if (normalized === "0" || normalized === "false" || normalized === "no") {
49
- return false;
50
- }
51
- return;
52
- }
53
- function getDebugLevel() {
54
- const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW || "off";
55
- const envLower = String(envVal).toLowerCase();
56
- if (envLower === "stream" || envLower === "parse" || envLower === "off") {
57
- return envLower;
58
- }
59
- const boolEnv = normalizeBooleanString(envLower);
60
- if (boolEnv === true) {
61
- return "stream";
62
- }
63
- if (envLower === "2") {
64
- return "parse";
65
- }
66
- return "off";
67
- }
68
- function color(code) {
69
- return (text) => `\x1B[${code}m${text}\x1B[0m`;
70
- }
71
- var ANSI_GRAY = 90;
72
- var ANSI_YELLOW = 33;
73
- var ANSI_CYAN = 36;
74
- var ANSI_BG_BLUE = 44;
75
- var ANSI_BG_GREEN = 42;
76
- var ANSI_INVERSE = 7;
77
- var ANSI_UNDERLINE = 4;
78
- var ANSI_BOLD = 1;
79
- var cGray = color(ANSI_GRAY);
80
- var cYellow = color(ANSI_YELLOW);
81
- var cCyan = color(ANSI_CYAN);
82
- var cBgBlue = color(ANSI_BG_BLUE);
83
- var cBgGreen = color(ANSI_BG_GREEN);
84
- var cInverse = color(ANSI_INVERSE);
85
- var cUnderline = color(ANSI_UNDERLINE);
86
- var cBold = color(ANSI_BOLD);
87
- var MAX_SNIPPET_LENGTH = 800;
88
- function safeStringify(value) {
89
- try {
90
- return `
91
- ${typeof value === "string" ? value : JSON.stringify(value, null, 2)}`;
92
- } catch (e) {
93
- return String(value);
1
+ // src/core/heuristics/engine.ts
2
+ function applyRawSegmentUpdate(current, result) {
3
+ if (result.rawSegment !== void 0) {
4
+ return { ...current, rawSegment: result.rawSegment };
94
5
  }
6
+ return current;
95
7
  }
96
- function formatError(error) {
97
- if (error instanceof Error) {
98
- const stack = error.stack ? `
99
- ${error.stack}` : "";
100
- return `
101
- ${error.name}: ${error.message}${stack}`;
8
+ function applyParsedUpdate(current, result) {
9
+ if (result.parsed !== void 0) {
10
+ return { ...current, parsed: result.parsed };
102
11
  }
103
- return safeStringify(error);
12
+ return current;
104
13
  }
105
- function truncateSnippet(snippet) {
106
- if (snippet.length <= MAX_SNIPPET_LENGTH) {
107
- return snippet;
14
+ function applyWarningsUpdate(current, result) {
15
+ var _a, _b;
16
+ if (result.warnings && result.warnings.length > 0) {
17
+ const meta = (_a = current.meta) != null ? _a : {};
18
+ const existingWarnings = (_b = meta.warnings) != null ? _b : [];
19
+ return {
20
+ ...current,
21
+ meta: { ...meta, warnings: [...existingWarnings, ...result.warnings] }
22
+ };
108
23
  }
109
- return `${snippet.slice(0, MAX_SNIPPET_LENGTH)}
110
- \u2026[truncated ${snippet.length - MAX_SNIPPET_LENGTH} chars]`;
24
+ return current;
111
25
  }
112
- function logParseFailure({
113
- phase,
114
- reason,
115
- snippet,
116
- error
117
- }) {
118
- if (getDebugLevel() !== "parse") {
119
- return;
120
- }
121
- const label = cBgBlue(`[${phase}]`);
122
- console.log(cGray("[debug:mw:fail]"), label, cYellow(reason));
123
- if (snippet) {
124
- const formatted = truncateSnippet(snippet);
125
- console.log(cGray("[debug:mw:fail:snippet]"), formatted);
26
+ function attemptReparse(current, result, reparseCount, maxReparses, parse4) {
27
+ if (!result.reparse || result.rawSegment === void 0 || reparseCount >= maxReparses) {
28
+ return { state: current, newCount: reparseCount };
126
29
  }
127
- if (error) {
128
- console.log(cGray("[debug:mw:fail:error]"), cCyan(formatError(error)));
30
+ try {
31
+ const reparsed = parse4(result.rawSegment, current.schema);
32
+ return {
33
+ state: { ...current, parsed: reparsed, errors: [] },
34
+ newCount: reparseCount + 1
35
+ };
36
+ } catch (error) {
37
+ return {
38
+ state: { ...current, errors: [...current.errors, error] },
39
+ newCount: reparseCount + 1
40
+ };
129
41
  }
130
42
  }
131
- function logRawChunk(part) {
132
- console.log(cGray("[debug:mw:raw]"), cYellow(safeStringify(part)));
133
- }
134
- function logParsedChunk(part) {
135
- console.log(cGray("[debug:mw:out]"), cCyan(safeStringify(part)));
136
- }
137
- function getHighlightStyle() {
138
- const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW_STYLE || "bg";
139
- const normalized = String(envVal).trim().toLowerCase();
140
- if (normalized === "inverse" || normalized === "invert") {
141
- return "inverse";
142
- }
143
- if (normalized === "underline" || normalized === "ul") {
144
- return "underline";
145
- }
146
- if (normalized === "bold") {
147
- return "bold";
148
- }
149
- if (normalized === "bg" || normalized === "background") {
150
- return "bg";
151
- }
152
- const asBool = normalizeBooleanString(normalized);
153
- if (asBool === true) {
154
- return "bg";
43
+ function executePhase(ctx, heuristics, options) {
44
+ var _a;
45
+ let current = ctx;
46
+ let reparseCount = 0;
47
+ const maxReparses = (_a = options.maxReparses) != null ? _a : 2;
48
+ for (const heuristic of heuristics) {
49
+ if (!heuristic.applies(current)) {
50
+ continue;
51
+ }
52
+ const result = heuristic.run(current);
53
+ current = applyRawSegmentUpdate(current, result);
54
+ current = applyParsedUpdate(current, result);
55
+ current = applyWarningsUpdate(current, result);
56
+ const reparseResult = attemptReparse(
57
+ current,
58
+ result,
59
+ reparseCount,
60
+ maxReparses,
61
+ options.parse
62
+ );
63
+ current = reparseResult.state;
64
+ reparseCount = reparseResult.newCount;
65
+ if (result.stop) {
66
+ break;
67
+ }
155
68
  }
156
- return "bg";
69
+ return current;
157
70
  }
158
- function getHighlightFunction(style) {
159
- if (style === "inverse") {
160
- return cInverse;
161
- }
162
- if (style === "underline") {
163
- return cUnderline;
71
+ function applyHeuristicPipeline(ctx, config, options) {
72
+ let current = ctx;
73
+ if (config.preParse && config.preParse.length > 0) {
74
+ current = executePhase(current, config.preParse, options);
164
75
  }
165
- if (style === "bold") {
166
- return cBold;
76
+ if (current.parsed === null && current.errors.length === 0) {
77
+ try {
78
+ const parsed = options.parse(current.rawSegment, current.schema);
79
+ current = { ...current, parsed, errors: [] };
80
+ } catch (error) {
81
+ current = { ...current, errors: [error] };
82
+ }
167
83
  }
168
- if (style === "bg") {
169
- return cBgGreen;
84
+ if (current.errors.length > 0 && config.fallbackReparse && config.fallbackReparse.length > 0) {
85
+ current = executePhase(current, config.fallbackReparse, options);
170
86
  }
171
- return cYellow;
172
- }
173
- function renderHighlightedText(originalText, style, highlight) {
174
- if (style === "bg" || style === "inverse" || style === "underline" || style === "bold") {
175
- return originalText.split(LINE_SPLIT_REGEX).map((line) => line.length ? highlight(line) : line).join("\n");
87
+ if (current.parsed !== null && config.postParse && config.postParse.length > 0) {
88
+ current = executePhase(current, config.postParse, options);
176
89
  }
177
- return highlight(originalText);
90
+ return current;
178
91
  }
179
- function logParsedSummary({
180
- toolCalls,
181
- originalText
182
- }) {
183
- if (originalText) {
184
- const style = getHighlightStyle();
185
- const highlight = getHighlightFunction(style);
186
- const rendered = renderHighlightedText(originalText, style, highlight);
187
- console.log(cGray("[debug:mw:origin]"), `
188
- ${rendered}`);
189
- }
190
- if (toolCalls.length > 0) {
191
- const styledSummary = safeStringify(toolCalls).split(LINE_SPLIT_REGEX).map((line) => line.length ? cBgBlue(line) : line).join("\n");
192
- console.log(cGray("[debug:mw:summary]"), styledSummary);
193
- }
92
+ function createIntermediateCall(toolName, rawSegment, schema) {
93
+ return {
94
+ toolName,
95
+ schema,
96
+ rawSegment,
97
+ parsed: null,
98
+ errors: [],
99
+ meta: { originalContent: rawSegment }
100
+ };
194
101
  }
195
-
196
- // src/core/utils/get-potential-start-index.ts
197
- function getPotentialStartIndex(text, searchedText) {
198
- if (searchedText.length === 0) {
199
- return null;
200
- }
201
- const directIndex = text.indexOf(searchedText);
202
- if (directIndex !== -1) {
203
- return directIndex;
204
- }
205
- for (let i = text.length - 1; i >= 0; i -= 1) {
206
- const suffix = text.substring(i);
207
- if (searchedText.startsWith(suffix)) {
208
- return i;
102
+ function mergePipelineConfigs(...configs) {
103
+ var _a, _b, _c;
104
+ const result = {
105
+ preParse: [],
106
+ fallbackReparse: [],
107
+ postParse: []
108
+ };
109
+ for (const config of configs) {
110
+ if (config.preParse) {
111
+ result.preParse = [...(_a = result.preParse) != null ? _a : [], ...config.preParse];
112
+ }
113
+ if (config.fallbackReparse) {
114
+ result.fallbackReparse = [
115
+ ...(_b = result.fallbackReparse) != null ? _b : [],
116
+ ...config.fallbackReparse
117
+ ];
118
+ }
119
+ if (config.postParse) {
120
+ result.postParse = [...(_c = result.postParse) != null ? _c : [], ...config.postParse];
209
121
  }
210
122
  }
211
- return null;
212
- }
213
-
214
- // src/core/utils/id.ts
215
- function generateId() {
216
- return Math.random().toString(36).substring(2, 15);
217
- }
218
-
219
- // src/core/utils/regex.ts
220
- function escapeRegExp(literal) {
221
- return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
123
+ return result;
222
124
  }
223
125
 
224
- // src/core/utils/robust-json.ts
225
- var WHITESPACE_TEST_REGEX = /\s/;
226
- var WHITESPACE_REGEX = /^\s+/;
227
- var OBJECT_START_REGEX = /^\{/;
228
- var OBJECT_END_REGEX = /^\}/;
229
- var ARRAY_START_REGEX = /^\[/;
230
- var ARRAY_END_REGEX = /^\]/;
231
- var COMMA_REGEX = /^,/;
232
- var COLON_REGEX = /^:/;
233
- var KEYWORD_REGEX = /^(?:true|false|null)/;
234
- var NUMBER_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/;
235
- var STRING_DOUBLE_REGEX = /^"(?:[^"\\]|\\["bnrtf\\/]|\\u[0-9a-fA-F]{4})*"/;
236
- var STRING_SINGLE_REGEX = /^'((?:[^'\\]|\\['bnrtf\\/]|\\u[0-9a-fA-F]{4})*)'/;
237
- var COMMENT_SINGLE_REGEX = /^\/\/.*?(?:\r\n|\r|\n)/;
238
- var COMMENT_MULTI_REGEX = /^\/\*[\s\S]*?\*\//;
239
- var IDENTIFIER_REGEX = /^[$a-zA-Z0-9_\-+.*?!|&%^/#\\]+/;
240
- function some(array, f) {
241
- let acc = false;
242
- for (let i = 0; i < array.length; i += 1) {
243
- const result = f(array[i], i, array);
244
- acc = result === void 0 ? false : result;
245
- if (acc) {
246
- return acc;
126
+ // src/core/heuristics/xml-defaults.ts
127
+ import { parse, unwrapJsonSchema } from "@ai-sdk-tool/rxml";
128
+ var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
129
+ var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
130
+ var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
131
+ var WHITESPACE_REGEX = /\s/;
132
+ var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
133
+ var NAME_START_CHAR_RE = /[A-Za-z_:]/;
134
+ var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
135
+ var STATUS_TAG_RE = /<status>([\s\S]*?)<\/status>/i;
136
+ var normalizeCloseTagsHeuristic = {
137
+ id: "normalize-close-tags",
138
+ phase: "pre-parse",
139
+ applies: () => true,
140
+ run: (ctx) => {
141
+ const normalized = ctx.rawSegment.replace(MALFORMED_CLOSE_RE_G, "</$1>");
142
+ if (normalized !== ctx.rawSegment) {
143
+ return { rawSegment: normalized };
247
144
  }
145
+ return {};
248
146
  }
249
- return acc;
250
- }
251
- function makeLexer(tokenSpecs) {
252
- return (contents) => {
253
- const tokens = [];
254
- let line = 1;
255
- let remainingContents = contents;
256
- function findToken() {
257
- const result = some(tokenSpecs, (tokenSpec) => {
258
- const m = tokenSpec.re.exec(remainingContents);
259
- if (m) {
260
- const raw = m[0];
261
- remainingContents = remainingContents.slice(raw.length);
262
- return {
263
- raw,
264
- matched: tokenSpec.f(m)
265
- // Process the match using the spec's function
266
- };
267
- }
268
- return;
269
- });
270
- return result === false ? void 0 : result;
147
+ };
148
+ var escapeInvalidLtHeuristic = {
149
+ id: "escape-invalid-lt",
150
+ phase: "pre-parse",
151
+ applies: () => true,
152
+ run: (ctx) => {
153
+ const escaped = escapeInvalidLt(ctx.rawSegment);
154
+ if (escaped !== ctx.rawSegment) {
155
+ return { rawSegment: escaped };
271
156
  }
272
- while (remainingContents !== "") {
273
- const matched = findToken();
274
- if (!matched) {
275
- const err = new SyntaxError(
276
- `Unexpected character: ${remainingContents[0]}; input: ${remainingContents.substr(
277
- 0,
278
- 100
279
- )}`
280
- );
281
- err.line = line;
282
- throw err;
283
- }
284
- const tokenWithLine = matched.matched;
285
- tokenWithLine.line = line;
286
- line += matched.raw.replace(/[^\n]/g, "").length;
287
- tokens.push(tokenWithLine);
157
+ return {};
158
+ }
159
+ };
160
+ var balanceTagsHeuristic = {
161
+ id: "balance-tags",
162
+ phase: "fallback-reparse",
163
+ applies: (ctx) => {
164
+ var _a;
165
+ const original = ((_a = ctx.meta) == null ? void 0 : _a.originalContent) || ctx.rawSegment;
166
+ const normalized = original.replace(MALFORMED_CLOSE_RE_G, "</$1>");
167
+ const balanced = balanceTags(original);
168
+ const hasMalformedClose = MALFORMED_CLOSE_RE.test(original);
169
+ if (!hasMalformedClose && balanced.length > normalized.length) {
170
+ return false;
288
171
  }
289
- return tokens;
290
- };
172
+ return balanced !== normalized;
173
+ },
174
+ run: (ctx) => {
175
+ var _a;
176
+ const original = ((_a = ctx.meta) == null ? void 0 : _a.originalContent) || ctx.rawSegment;
177
+ const balanced = balanceTags(original);
178
+ const escaped = escapeInvalidLt(balanced);
179
+ return { rawSegment: escaped, reparse: true };
180
+ }
181
+ };
182
+ var dedupeShellStringTagsHeuristic = {
183
+ id: "dedupe-shell-string-tags",
184
+ phase: "fallback-reparse",
185
+ applies: (ctx) => shouldDeduplicateStringTags(ctx.schema),
186
+ run: (ctx) => {
187
+ const names = getStringPropertyNames(ctx.schema);
188
+ let deduped = ctx.rawSegment;
189
+ for (const key of names) {
190
+ deduped = dedupeSingleTag(deduped, key);
191
+ }
192
+ if (deduped !== ctx.rawSegment) {
193
+ return { rawSegment: deduped, reparse: true };
194
+ }
195
+ return {};
196
+ }
197
+ };
198
+ var repairAgainstSchemaHeuristic = {
199
+ id: "repair-against-schema",
200
+ phase: "post-parse",
201
+ applies: (ctx) => ctx.parsed !== null && typeof ctx.parsed === "object",
202
+ run: (ctx) => {
203
+ const repaired = repairParsedAgainstSchema(ctx.parsed, ctx.schema);
204
+ if (repaired !== ctx.parsed) {
205
+ return { parsed: repaired };
206
+ }
207
+ return {};
208
+ }
209
+ };
210
+ var defaultPipelineConfig = {
211
+ preParse: [normalizeCloseTagsHeuristic, escapeInvalidLtHeuristic],
212
+ fallbackReparse: [balanceTagsHeuristic, dedupeShellStringTagsHeuristic],
213
+ postParse: [repairAgainstSchemaHeuristic]
214
+ };
215
+ var INDEX_TAG_RE = /^<(\d+)(?:>|\/?>)/;
216
+ function isIndexTagAt(xml, pos) {
217
+ const remaining = xml.slice(pos);
218
+ return INDEX_TAG_RE.test(remaining);
291
219
  }
292
- function fStringSingle(m) {
293
- const content = m[1].replace(
294
- /([^'\\]|\\['bnrtf\\]|\\u[0-9a-fA-F]{4})/g,
295
- (mm) => {
296
- if (mm === '"') {
297
- return '\\"';
298
- }
299
- if (mm === "\\'") {
300
- return "'";
220
+ function escapeInvalidLt(xml) {
221
+ const len = xml.length;
222
+ let out = "";
223
+ for (let i = 0; i < len; i += 1) {
224
+ const ch = xml[i];
225
+ if (ch === "<") {
226
+ const next = i + 1 < len ? xml[i + 1] : "";
227
+ const isValidStart = NAME_START_CHAR_RE.test(next) || next === "/" || next === "!" || next === "?";
228
+ const isIndexTag = !isValidStart && isIndexTagAt(xml, i);
229
+ if (!(isValidStart || isIndexTag)) {
230
+ out += "&lt;";
231
+ continue;
301
232
  }
302
- return mm;
303
233
  }
304
- );
305
- const match = `"${content}"`;
306
- return {
307
- type: "string",
308
- match,
309
- // The transformed, double-quoted string representation
310
- // Use JSON.parse on the transformed string to handle escape sequences correctly
311
- value: JSON.parse(match)
312
- };
234
+ out += ch;
235
+ }
236
+ return out;
313
237
  }
314
- function fStringDouble(m) {
315
- return {
316
- type: "string",
317
- match: m[0],
318
- // The raw matched string (including quotes)
319
- value: JSON.parse(m[0])
320
- // Use JSON.parse to handle escapes and get the value
321
- };
238
+ function balanceTags(xml) {
239
+ const src = xml.replace(MALFORMED_CLOSE_RE_G, "</$1>").replace(STATUS_TO_STEP_BOUNDARY_RE, "</status></step><step>");
240
+ let i = 0;
241
+ const len = src.length;
242
+ const out = [];
243
+ const stack = [];
244
+ while (i < len) {
245
+ const lt = src.indexOf("<", i);
246
+ if (lt === -1) {
247
+ out.push(src.slice(i));
248
+ break;
249
+ }
250
+ out.push(src.slice(i, lt));
251
+ if (lt + 1 >= len) {
252
+ break;
253
+ }
254
+ const next = src[lt + 1];
255
+ if (next === "!" || next === "?") {
256
+ i = handleSpecialTagSegment(src, lt, out);
257
+ continue;
258
+ }
259
+ if (next === "/") {
260
+ i = handleClosingTagSegment(src, lt, out, stack);
261
+ continue;
262
+ }
263
+ i = handleOpeningTagSegment(src, lt, out, stack);
264
+ }
265
+ for (let k = stack.length - 1; k >= 0; k -= 1) {
266
+ out.push(`</${stack[k]}>`);
267
+ }
268
+ return out.join("");
322
269
  }
323
- function fIdentifier(m) {
324
- const value = m[0];
325
- const match = '"' + value.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + // Escape backslashes and quotes
326
- '"';
327
- return {
328
- type: "string",
329
- // Treat identifiers as strings
330
- value,
331
- // The original identifier name
332
- match
333
- // The double-quoted string representation
334
- };
270
+ function skipWs(s, p, len) {
271
+ let idx = p;
272
+ while (idx < len && WHITESPACE_REGEX.test(s[idx])) {
273
+ idx += 1;
274
+ }
275
+ return idx;
335
276
  }
336
- function fComment(m) {
337
- const match = m[0].replace(
338
- /./g,
339
- (c) => WHITESPACE_TEST_REGEX.test(c) ? c : " "
340
- );
341
- return {
342
- type: " ",
343
- // Represent comments as whitespace tokens
344
- match,
345
- // String containing original newlines and spaces for other chars
346
- value: void 0
347
- // Comments don't have a semantic value
348
- };
277
+ function parseTagNameAt(s, p, len) {
278
+ let idx = p;
279
+ const start = idx;
280
+ while (idx < len && NAME_CHAR_RE.test(s[idx])) {
281
+ idx += 1;
282
+ }
283
+ return { name: s.slice(start, idx), pos: idx };
284
+ }
285
+ function handleSpecialTagSegment(src, lt, out) {
286
+ const gt = src.indexOf(">", lt + 1);
287
+ if (gt === -1) {
288
+ out.push(src.slice(lt));
289
+ return src.length;
290
+ }
291
+ out.push(src.slice(lt, gt + 1));
292
+ return gt + 1;
293
+ }
294
+ function handleClosingTagSegment(src, lt, out, stack) {
295
+ const len = src.length;
296
+ let p = skipWs(src, lt + 2, len);
297
+ const { name, pos } = parseTagNameAt(src, p, len);
298
+ p = pos;
299
+ const gt = src.indexOf(">", p);
300
+ const closingText = gt === -1 ? src.slice(lt) : src.slice(lt, gt + 1);
301
+ const idx = stack.lastIndexOf(name);
302
+ if (idx !== -1) {
303
+ for (let k = stack.length - 1; k > idx; k -= 1) {
304
+ out.push(`</${stack[k]}>`);
305
+ stack.pop();
306
+ }
307
+ out.push(closingText);
308
+ stack.pop();
309
+ }
310
+ return gt === -1 ? len : gt + 1;
349
311
  }
350
- function fNumber(m) {
351
- return {
352
- type: "number",
353
- match: m[0],
354
- // The raw matched number string
355
- value: Number.parseFloat(m[0])
356
- // Convert string to number
357
- };
312
+ function handleOpeningTagSegment(src, lt, out, stack) {
313
+ const len = src.length;
314
+ let p = skipWs(src, lt + 1, len);
315
+ const nameStart = p;
316
+ const parsed = parseTagNameAt(src, p, len);
317
+ p = parsed.pos;
318
+ const name = src.slice(nameStart, p);
319
+ const q = src.indexOf(">", p);
320
+ if (q === -1) {
321
+ out.push(src.slice(lt));
322
+ return len;
323
+ }
324
+ let r = q - 1;
325
+ while (r >= nameStart && WHITESPACE_REGEX.test(src[r])) {
326
+ r -= 1;
327
+ }
328
+ const selfClosing = src[r] === "/";
329
+ out.push(src.slice(lt, q + 1));
330
+ if (!selfClosing && name) {
331
+ stack.push(name);
332
+ }
333
+ return q + 1;
358
334
  }
359
- function fKeyword(m) {
360
- let value;
361
- switch (m[0]) {
362
- case "null":
363
- value = null;
364
- break;
365
- case "true":
366
- value = true;
367
- break;
368
- case "false":
369
- value = false;
370
- break;
371
- default:
372
- throw new Error(`Unexpected keyword: ${m[0]}`);
335
+ function shouldDeduplicateStringTags(schema) {
336
+ const unwrapped = unwrapJsonSchema(schema);
337
+ if (!unwrapped || typeof unwrapped !== "object") {
338
+ return false;
373
339
  }
374
- return {
375
- type: "atom",
376
- // Use 'atom' type for these literals
377
- match: m[0],
378
- // The raw matched keyword
379
- value
380
- // The corresponding JavaScript value
381
- };
340
+ const props = unwrapped.properties;
341
+ if (!props) {
342
+ return false;
343
+ }
344
+ const commandRaw = props.command;
345
+ if (!commandRaw) {
346
+ return false;
347
+ }
348
+ const command = unwrapJsonSchema(commandRaw);
349
+ return (command == null ? void 0 : command.type) === "array";
382
350
  }
383
- function makeTokenSpecs(relaxed) {
384
- function f(type) {
385
- return (m) => {
386
- return { type, match: m[0], value: void 0 };
387
- };
351
+ function getStringPropertyNames(schema) {
352
+ const unwrapped = unwrapJsonSchema(schema);
353
+ if (!unwrapped || typeof unwrapped !== "object") {
354
+ return [];
388
355
  }
389
- let tokenSpecs = [
390
- { re: WHITESPACE_REGEX, f: f(" ") },
391
- // Whitespace
392
- { re: OBJECT_START_REGEX, f: f("{") },
393
- // Object start
394
- { re: OBJECT_END_REGEX, f: f("}") },
395
- // Object end
396
- { re: ARRAY_START_REGEX, f: f("[") },
397
- // Array start
398
- { re: ARRAY_END_REGEX, f: f("]") },
399
- // Array end
400
- { re: COMMA_REGEX, f: f(",") },
401
- // Comma separator
402
- { re: COLON_REGEX, f: f(":") },
403
- // Key-value separator
404
- { re: KEYWORD_REGEX, f: fKeyword },
405
- // Keywords
406
- // Number: optional sign, digits, optional decimal part, optional exponent
407
- { re: NUMBER_REGEX, f: fNumber },
408
- // String: double-quoted, handles escapes
409
- { re: STRING_DOUBLE_REGEX, f: fStringDouble }
410
- ];
411
- if (relaxed) {
412
- tokenSpecs = tokenSpecs.concat([
413
- // Single-quoted strings
414
- {
415
- re: STRING_SINGLE_REGEX,
416
- f: fStringSingle
417
- },
418
- // Single-line comments (// ...)
419
- { re: COMMENT_SINGLE_REGEX, f: fComment },
420
- // Multi-line comments (/* ... */)
421
- { re: COMMENT_MULTI_REGEX, f: fComment },
422
- // Unquoted identifiers (treated as strings)
423
- // Allows letters, numbers, _, -, +, ., *, ?, !, |, &, %, ^, /, #, \
424
- { re: IDENTIFIER_REGEX, f: fIdentifier }
425
- // Note: The order matters here. Identifiers are checked after keywords/numbers.
426
- ]);
356
+ const props = unwrapped.properties;
357
+ if (!props) {
358
+ return [];
427
359
  }
428
- return tokenSpecs;
360
+ const names = [];
361
+ for (const key of Object.keys(props)) {
362
+ const prop = unwrapJsonSchema(
363
+ props[key]
364
+ );
365
+ const type = prop.type;
366
+ if (type === "string") {
367
+ names.push(key);
368
+ }
369
+ }
370
+ return names;
429
371
  }
430
- var lexer = makeLexer(makeTokenSpecs(true));
431
- var strictLexer = makeLexer(makeTokenSpecs(false));
432
- function previousNWSToken(tokens, index) {
433
- let currentIndex = index;
434
- for (; currentIndex >= 0; currentIndex -= 1) {
435
- if (tokens[currentIndex].type !== " ") {
436
- return currentIndex;
372
+ function escapeRegExp(s) {
373
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
374
+ }
375
+ function dedupeSingleTag(xml, key) {
376
+ var _a, _b;
377
+ const escaped = escapeRegExp(key);
378
+ const re = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
379
+ const matches = Array.from(xml.matchAll(re));
380
+ if (matches.length <= 1) {
381
+ return xml;
382
+ }
383
+ const last = matches.at(-1);
384
+ let result = "";
385
+ let cursor = 0;
386
+ for (const m of matches) {
387
+ const idx = (_a = m.index) != null ? _a : 0;
388
+ result += xml.slice(cursor, idx);
389
+ if (last && idx === ((_b = last.index) != null ? _b : -1)) {
390
+ result += m[0];
437
391
  }
392
+ cursor = idx + m[0].length;
438
393
  }
439
- return;
394
+ result += xml.slice(cursor);
395
+ return result;
440
396
  }
441
- function stripTrailingComma(tokens) {
442
- const res = [];
443
- tokens.forEach((token, index) => {
444
- if (index > 0 && (token.type === "]" || token.type === "}")) {
445
- const prevNWSTokenIndex = previousNWSToken(res, res.length - 1);
446
- if (prevNWSTokenIndex !== void 0 && res[prevNWSTokenIndex].type === ",") {
447
- const preCommaIndex = previousNWSToken(res, prevNWSTokenIndex - 1);
448
- if (preCommaIndex !== void 0 && res[preCommaIndex].type !== "[" && res[preCommaIndex].type !== "{") {
449
- res[prevNWSTokenIndex] = {
450
- type: " ",
451
- match: " ",
452
- // Represent as a single space
453
- value: void 0,
454
- // Whitespace has no value
455
- line: res[prevNWSTokenIndex].line
456
- // Preserve original line number
457
- };
458
- }
397
+ function repairParsedAgainstSchema(input, schema) {
398
+ if (!input || typeof input !== "object") {
399
+ return input;
400
+ }
401
+ const unwrapped = unwrapJsonSchema(schema);
402
+ if (!unwrapped || typeof unwrapped !== "object") {
403
+ return input;
404
+ }
405
+ const properties = unwrapped.properties;
406
+ if (!properties) {
407
+ return input;
408
+ }
409
+ applySchemaProps(input, properties);
410
+ return input;
411
+ }
412
+ function applySchemaProps(obj, properties) {
413
+ for (const key of Object.keys(obj)) {
414
+ const propSchema = properties[key];
415
+ if (!propSchema) {
416
+ continue;
417
+ }
418
+ const prop = unwrapJsonSchema(propSchema);
419
+ const propType = prop.type;
420
+ if (propType === "array" && prop.items) {
421
+ const itemSchemaRaw = prop.items;
422
+ const itemSchema = unwrapJsonSchema(itemSchemaRaw);
423
+ obj[key] = coerceArrayItems(obj[key], itemSchema);
424
+ continue;
425
+ }
426
+ if (propType === "object") {
427
+ const val = obj[key];
428
+ if (val && typeof val === "object") {
429
+ obj[key] = repairParsedAgainstSchema(val, prop);
459
430
  }
460
431
  }
461
- res.push(token);
462
- });
463
- return res;
432
+ }
464
433
  }
465
- function popToken(tokens, state) {
466
- var _a, _b;
467
- const token = tokens[state.pos];
468
- state.pos += 1;
469
- if (!token) {
470
- const lastLine = tokens.length !== 0 ? (_b = (_a = tokens.at(-1)) == null ? void 0 : _a.line) != null ? _b : 1 : 1;
471
- return { type: "eof", match: "", value: void 0, line: lastLine };
434
+ function coerceArrayItems(val, itemSchema) {
435
+ if (!Array.isArray(val)) {
436
+ return val;
472
437
  }
473
- return token;
438
+ return val.map((v) => coerceArrayItem(v, itemSchema));
474
439
  }
475
- function strToken(token) {
476
- switch (token.type) {
477
- case "atom":
478
- case "string":
479
- case "number":
480
- return `${token.type} ${token.match}`;
481
- case "eof":
482
- return "end-of-file";
483
- default:
484
- return `'${token.type}'`;
440
+ function coerceArrayItem(v, itemSchema) {
441
+ const itemType = itemSchema == null ? void 0 : itemSchema.type;
442
+ if (typeof v === "string" && itemType === "object") {
443
+ const parsed = tryParseStringToSchemaObject(v, itemSchema);
444
+ if (parsed !== null) {
445
+ return parsed;
446
+ }
447
+ const fallback = extractStepStatusFromString(
448
+ v.replace(MALFORMED_CLOSE_RE_G, "</$1>")
449
+ );
450
+ if (fallback) {
451
+ return fallback;
452
+ }
453
+ return v;
454
+ }
455
+ if (v && typeof v === "object" && itemType === "object") {
456
+ return repairParsedAgainstSchema(v, itemSchema);
457
+ }
458
+ return v;
459
+ }
460
+ function tryParseStringToSchemaObject(xml, itemSchema) {
461
+ try {
462
+ const normalized = xml.replace(MALFORMED_CLOSE_RE_G, "</$1>");
463
+ const fixed = parse(normalized, itemSchema, { noChildNodes: [] });
464
+ return typeof fixed === "string" ? null : fixed;
465
+ } catch (e) {
466
+ return null;
485
467
  }
486
468
  }
487
- function skipColon(tokens, state) {
488
- const colon = popToken(tokens, state);
489
- if (colon.type !== ":") {
490
- const message = `Unexpected token: ${strToken(colon)}, expected ':'`;
491
- if (state.tolerant) {
492
- state.warnings.push({
493
- message,
494
- line: colon.line
495
- });
496
- state.pos -= 1;
497
- } else {
498
- const err = new SyntaxError(message);
499
- err.line = colon.line;
500
- throw err;
501
- }
469
+ function extractStepStatusFromString(normXml) {
470
+ const stepMatch = normXml.match(STEP_TAG_RE);
471
+ const statusMatch = normXml.match(STATUS_TAG_RE);
472
+ if (stepMatch && statusMatch) {
473
+ return { step: stepMatch[1], status: statusMatch[1] };
502
474
  }
475
+ return null;
503
476
  }
504
- function skipPunctuation(tokens, state, valid) {
505
- const punctuation = [",", ":", "]", "}"];
506
- let token = popToken(tokens, state);
507
- while (true) {
508
- if (valid == null ? void 0 : valid.includes(token.type)) {
509
- return token;
510
- }
511
- if (token.type === "eof") {
512
- return token;
513
- }
514
- if (punctuation.includes(token.type)) {
515
- const message = `Unexpected token: ${strToken(
516
- token
517
- )}, expected '[', '{', number, string or atom`;
518
- if (state.tolerant) {
519
- state.warnings.push({
520
- message,
521
- line: token.line
522
- });
523
- token = popToken(tokens, state);
524
- } else {
525
- const err = new SyntaxError(message);
526
- err.line = token.line;
527
- throw err;
528
- }
529
- } else {
530
- return token;
531
- }
477
+
478
+ // src/core/utils/debug.ts
479
+ var LINE_SPLIT_REGEX = /\r?\n/;
480
+ function normalizeBooleanString(value) {
481
+ const normalized = value.trim().toLowerCase();
482
+ if (normalized === "1" || normalized === "true" || normalized === "yes") {
483
+ return true;
484
+ }
485
+ if (normalized === "0" || normalized === "false" || normalized === "no") {
486
+ return false;
532
487
  }
488
+ return;
533
489
  }
534
- function raiseError(state, token, message) {
535
- if (state.tolerant) {
536
- state.warnings.push({
537
- message,
538
- line: token.line
539
- });
540
- } else {
541
- const err = new SyntaxError(message);
542
- err.line = token.line;
543
- throw err;
490
+ function getDebugLevel() {
491
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW || "off";
492
+ const envLower = String(envVal).toLowerCase();
493
+ if (envLower === "stream" || envLower === "parse" || envLower === "off") {
494
+ return envLower;
495
+ }
496
+ const boolEnv = normalizeBooleanString(envLower);
497
+ if (boolEnv === true) {
498
+ return "stream";
544
499
  }
500
+ if (envLower === "2") {
501
+ return "parse";
502
+ }
503
+ return "off";
545
504
  }
546
- function raiseUnexpected(state, token, expected) {
547
- raiseError(
548
- state,
549
- token,
550
- `Unexpected token: ${strToken(token)}, expected ${expected}`
551
- );
505
+ function color(code) {
506
+ return (text) => `\x1B[${code}m${text}\x1B[0m`;
552
507
  }
553
- function checkDuplicates(state, obj, token) {
554
- const key = String(token.value);
555
- if (!state.duplicate && Object.hasOwn(obj, key)) {
556
- raiseError(state, token, `Duplicate key: ${key}`);
508
+ var ANSI_GRAY = 90;
509
+ var ANSI_YELLOW = 33;
510
+ var ANSI_CYAN = 36;
511
+ var ANSI_BG_BLUE = 44;
512
+ var ANSI_BG_GREEN = 42;
513
+ var ANSI_INVERSE = 7;
514
+ var ANSI_UNDERLINE = 4;
515
+ var ANSI_BOLD = 1;
516
+ var cGray = color(ANSI_GRAY);
517
+ var cYellow = color(ANSI_YELLOW);
518
+ var cCyan = color(ANSI_CYAN);
519
+ var cBgBlue = color(ANSI_BG_BLUE);
520
+ var cBgGreen = color(ANSI_BG_GREEN);
521
+ var cInverse = color(ANSI_INVERSE);
522
+ var cUnderline = color(ANSI_UNDERLINE);
523
+ var cBold = color(ANSI_BOLD);
524
+ var MAX_SNIPPET_LENGTH = 800;
525
+ function safeStringify(value) {
526
+ try {
527
+ return `
528
+ ${typeof value === "string" ? value : JSON.stringify(value, null, 2)}`;
529
+ } catch (e) {
530
+ return String(value);
557
531
  }
558
532
  }
559
- function appendPair(state, obj, key, value) {
560
- const finalValue = state.reviver ? state.reviver(key, value) : value;
561
- if (finalValue !== void 0) {
562
- obj[key] = finalValue;
533
+ function formatError(error) {
534
+ if (error instanceof Error) {
535
+ const stack = error.stack ? `
536
+ ${error.stack}` : "";
537
+ return `
538
+ ${error.name}: ${error.message}${stack}`;
563
539
  }
540
+ return safeStringify(error);
564
541
  }
565
- function parsePair(tokens, state, obj) {
566
- let token = skipPunctuation(tokens, state, [":", "string", "number", "atom"]);
567
- let value;
568
- if (token.type !== "string") {
569
- raiseUnexpected(state, token, "string key");
570
- if (state.tolerant) {
571
- switch (token.type) {
572
- case ":":
573
- token = {
574
- type: "string",
575
- value: "null",
576
- match: '"null"',
577
- line: token.line
578
- };
579
- state.pos -= 1;
580
- break;
581
- case "number":
582
- // Use number as string key
583
- case "atom":
584
- token = {
585
- type: "string",
586
- value: String(token.value),
587
- match: `"${token.value}"`,
588
- line: token.line
589
- };
590
- break;
591
- case "[":
592
- // Assume missing key before an array
593
- case "{":
594
- state.pos -= 1;
595
- value = parseAny(tokens, state);
596
- checkDuplicates(state, obj, {
597
- type: "string",
598
- value: "null",
599
- match: '"null"',
600
- line: token.line
601
- });
602
- appendPair(state, obj, "null", value);
603
- return;
604
- // Finished parsing this "pair"
605
- case "eof":
606
- return;
607
- // Cannot recover
608
- default:
609
- return;
610
- }
611
- } else {
612
- return;
613
- }
542
+ function truncateSnippet(snippet) {
543
+ if (snippet.length <= MAX_SNIPPET_LENGTH) {
544
+ return snippet;
614
545
  }
615
- checkDuplicates(state, obj, token);
616
- const key = String(token.value);
617
- skipColon(tokens, state);
618
- value = parseAny(tokens, state);
619
- appendPair(state, obj, key, value);
546
+ return `${snippet.slice(0, MAX_SNIPPET_LENGTH)}
547
+ \u2026[truncated ${snippet.length - MAX_SNIPPET_LENGTH} chars]`;
620
548
  }
621
- function parseElement(tokens, state, arr) {
622
- const key = arr.length;
623
- const value = parseAny(tokens, state);
624
- arr[key] = state.reviver ? state.reviver(String(key), value) : value;
549
+ function logParseFailure({
550
+ phase,
551
+ reason,
552
+ snippet,
553
+ error
554
+ }) {
555
+ if (getDebugLevel() !== "parse") {
556
+ return;
557
+ }
558
+ const label = cBgBlue(`[${phase}]`);
559
+ console.log(cGray("[debug:mw:fail]"), label, cYellow(reason));
560
+ if (snippet) {
561
+ const formatted = truncateSnippet(snippet);
562
+ console.log(cGray("[debug:mw:fail:snippet]"), formatted);
563
+ }
564
+ if (error) {
565
+ console.log(cGray("[debug:mw:fail:error]"), cCyan(formatError(error)));
566
+ }
625
567
  }
626
- function parseObject(tokens, state) {
627
- const obj = {};
628
- return parseMany(tokens, state, obj, {
629
- skip: [":", "}"],
630
- // Initially skip over colon or closing brace (for empty/tolerant cases)
631
- elementParser: parsePair,
632
- // Use parsePair to parse each key-value element
633
- elementName: "string key",
634
- // Expected element type for errors
635
- endSymbol: "}"
636
- // The closing token for an object
637
- });
568
+ function logRawChunk(part) {
569
+ console.log(cGray("[debug:mw:raw]"), cYellow(safeStringify(part)));
638
570
  }
639
- function parseArray(tokens, state) {
640
- const arr = [];
641
- return parseMany(tokens, state, arr, {
642
- skip: ["]"],
643
- // Initially skip over closing bracket (for empty/tolerant cases)
644
- elementParser: parseElement,
645
- // Use parseElement to parse each array item
646
- elementName: "json value",
647
- // Expected element type for errors
648
- endSymbol: "]"
649
- // The closing token for an array
650
- });
571
+ function logParsedChunk(part) {
572
+ console.log(cGray("[debug:mw:out]"), cCyan(safeStringify(part)));
651
573
  }
652
- function handleInvalidToken(token, state, opts, result) {
653
- raiseUnexpected(state, token, `',' or '${opts.endSymbol}'`);
654
- if (state.tolerant) {
655
- if (token.type === "eof") {
656
- return result;
657
- }
658
- state.pos -= 1;
659
- return null;
574
+ function getHighlightStyle() {
575
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW_STYLE || "bg";
576
+ const normalized = String(envVal).trim().toLowerCase();
577
+ if (normalized === "inverse" || normalized === "invert") {
578
+ return "inverse";
579
+ }
580
+ if (normalized === "underline" || normalized === "ul") {
581
+ return "underline";
582
+ }
583
+ if (normalized === "bold") {
584
+ return "bold";
660
585
  }
661
- return result;
662
- }
663
- function handleCommaToken(params) {
664
- const { token, tokens, state, opts, result } = params;
665
- const nextToken = tokens[state.pos];
666
- if (state.tolerant && nextToken && nextToken.type === opts.endSymbol) {
667
- raiseError(state, token, `Trailing comma before '${opts.endSymbol}'`);
668
- popToken(tokens, state);
669
- return result;
586
+ if (normalized === "bg" || normalized === "background") {
587
+ return "bg";
670
588
  }
671
- opts.elementParser(tokens, state, result);
672
- return null;
589
+ const asBool = normalizeBooleanString(normalized);
590
+ if (asBool === true) {
591
+ return "bg";
592
+ }
593
+ return "bg";
673
594
  }
674
- function parseManyInitialElement(tokens, state, result, opts) {
675
- const token = skipPunctuation(tokens, state, opts.skip);
676
- if (token.type === "eof") {
677
- raiseUnexpected(state, token, `'${opts.endSymbol}' or ${opts.elementName}`);
678
- return result;
595
+ function getHighlightFunction(style) {
596
+ if (style === "inverse") {
597
+ return cInverse;
679
598
  }
680
- if (token.type === opts.endSymbol) {
681
- return result;
599
+ if (style === "underline") {
600
+ return cUnderline;
682
601
  }
683
- state.pos -= 1;
684
- opts.elementParser(tokens, state, result);
685
- return;
686
- }
687
- function parseManyProcessToken(params) {
688
- const { token, tokens, state, opts, result } = params;
689
- if (token.type !== opts.endSymbol && token.type !== ",") {
690
- const handledResult = handleInvalidToken(token, state, opts, result);
691
- if (handledResult !== null) {
692
- return handledResult;
693
- }
602
+ if (style === "bold") {
603
+ return cBold;
694
604
  }
695
- if (token.type === opts.endSymbol) {
696
- return result;
605
+ if (style === "bg") {
606
+ return cBgGreen;
697
607
  }
698
- if (token.type === ",") {
699
- const handledResult = handleCommaToken({
700
- token,
701
- tokens,
702
- state,
703
- opts,
704
- result
705
- });
706
- if (handledResult !== null) {
707
- return handledResult;
708
- }
709
- return;
608
+ return cYellow;
609
+ }
610
+ function renderHighlightedText(originalText, style, highlight) {
611
+ if (style === "bg" || style === "inverse" || style === "underline" || style === "bold") {
612
+ return originalText.split(LINE_SPLIT_REGEX).map((line) => line.length ? highlight(line) : line).join("\n");
710
613
  }
711
- opts.elementParser(tokens, state, result);
712
- return;
614
+ return highlight(originalText);
713
615
  }
714
- function parseMany(tokens, state, result, opts) {
715
- const initialResult = parseManyInitialElement(tokens, state, result, opts);
716
- if (initialResult !== void 0) {
717
- return initialResult;
616
+ function logParsedSummary({
617
+ toolCalls,
618
+ originalText
619
+ }) {
620
+ if (originalText) {
621
+ const style = getHighlightStyle();
622
+ const highlight = getHighlightFunction(style);
623
+ const rendered = renderHighlightedText(originalText, style, highlight);
624
+ console.log(cGray("[debug:mw:origin]"), `
625
+ ${rendered}`);
718
626
  }
719
- while (true) {
720
- const token = popToken(tokens, state);
721
- const processedResult = parseManyProcessToken({
722
- token,
723
- tokens,
724
- state,
725
- opts,
726
- result
727
- });
728
- if (processedResult !== void 0) {
729
- return processedResult;
730
- }
627
+ if (toolCalls.length > 0) {
628
+ const styledSummary = safeStringify(toolCalls).split(LINE_SPLIT_REGEX).map((line) => line.length ? cBgBlue(line) : line).join("\n");
629
+ console.log(cGray("[debug:mw:summary]"), styledSummary);
731
630
  }
732
631
  }
733
- function endChecks(tokens, state, ret) {
734
- if (state.pos < tokens.length) {
735
- if (state.tolerant) {
736
- skipPunctuation(tokens, state);
737
- }
738
- if (state.pos < tokens.length) {
739
- raiseError(
740
- state,
741
- tokens[state.pos],
742
- `Unexpected token: ${strToken(tokens[state.pos])}, expected end-of-input`
743
- );
744
- }
632
+
633
+ // src/core/utils/get-potential-start-index.ts
634
+ function getPotentialStartIndex(text, searchedText) {
635
+ if (searchedText.length === 0) {
636
+ return null;
745
637
  }
746
- if (state.tolerant && state.warnings.length > 0) {
747
- const message = state.warnings.length === 1 ? state.warnings[0].message : `${state.warnings.length} parse warnings`;
748
- const err = new SyntaxError(message);
749
- err.line = state.warnings[0].line;
750
- err.warnings = state.warnings;
751
- err.obj = ret;
752
- throw err;
638
+ const directIndex = text.indexOf(searchedText);
639
+ if (directIndex !== -1) {
640
+ return directIndex;
641
+ }
642
+ for (let i = text.length - 1; i >= 0; i -= 1) {
643
+ const suffix = text.substring(i);
644
+ if (searchedText.startsWith(suffix)) {
645
+ return i;
646
+ }
753
647
  }
648
+ return null;
754
649
  }
755
- function parseAny(tokens, state, end = false) {
756
- const token = skipPunctuation(tokens, state);
757
- let ret;
758
- if (token.type === "eof") {
759
- if (end) {
760
- raiseUnexpected(state, token, "json value");
650
+
651
+ // src/core/utils/id.ts
652
+ function generateId() {
653
+ return Math.random().toString(36).substring(2, 15);
654
+ }
655
+
656
+ // src/core/utils/regex.ts
657
+ function escapeRegExp2(literal) {
658
+ return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
659
+ }
660
+
661
+ // src/core/utils/robust-json.ts
662
+ var WHITESPACE_TEST_REGEX = /\s/;
663
+ var WHITESPACE_REGEX2 = /^\s+/;
664
+ var OBJECT_START_REGEX = /^\{/;
665
+ var OBJECT_END_REGEX = /^\}/;
666
+ var ARRAY_START_REGEX = /^\[/;
667
+ var ARRAY_END_REGEX = /^\]/;
668
+ var COMMA_REGEX = /^,/;
669
+ var COLON_REGEX = /^:/;
670
+ var KEYWORD_REGEX = /^(?:true|false|null)/;
671
+ var NUMBER_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/;
672
+ var STRING_DOUBLE_REGEX = /^"(?:[^"\\]|\\["bnrtf\\/]|\\u[0-9a-fA-F]{4})*"/;
673
+ var STRING_SINGLE_REGEX = /^'((?:[^'\\]|\\['bnrtf\\/]|\\u[0-9a-fA-F]{4})*)'/;
674
+ var COMMENT_SINGLE_REGEX = /^\/\/.*?(?:\r\n|\r|\n)/;
675
+ var COMMENT_MULTI_REGEX = /^\/\*[\s\S]*?\*\//;
676
+ var IDENTIFIER_REGEX = /^[$a-zA-Z0-9_\-+.*?!|&%^/#\\]+/;
677
+ function some(array, f) {
678
+ let acc = false;
679
+ for (let i = 0; i < array.length; i += 1) {
680
+ const result = f(array[i], i, array);
681
+ acc = result === void 0 ? false : result;
682
+ if (acc) {
683
+ return acc;
761
684
  }
762
- raiseUnexpected(state, token, "json value");
763
- return;
764
685
  }
765
- switch (token.type) {
766
- case "{":
767
- ret = parseObject(tokens, state);
768
- break;
769
- case "[":
770
- ret = parseArray(tokens, state);
771
- break;
772
- case "string":
773
- // String literal
774
- case "number":
775
- // Number literal
776
- case "atom":
777
- ret = token.value;
778
- break;
779
- default:
780
- raiseUnexpected(state, token, "json value");
781
- if (state.tolerant) {
782
- ret = null;
783
- } else {
686
+ return acc;
687
+ }
688
+ function makeLexer(tokenSpecs) {
689
+ return (contents) => {
690
+ const tokens = [];
691
+ let line = 1;
692
+ let remainingContents = contents;
693
+ function findToken() {
694
+ const result = some(tokenSpecs, (tokenSpec) => {
695
+ const m = tokenSpec.re.exec(remainingContents);
696
+ if (m) {
697
+ const raw = m[0];
698
+ remainingContents = remainingContents.slice(raw.length);
699
+ return {
700
+ raw,
701
+ matched: tokenSpec.f(m)
702
+ // Process the match using the spec's function
703
+ };
704
+ }
784
705
  return;
706
+ });
707
+ return result === false ? void 0 : result;
708
+ }
709
+ while (remainingContents !== "") {
710
+ const matched = findToken();
711
+ if (!matched) {
712
+ const err = new SyntaxError(
713
+ `Unexpected character: ${remainingContents[0]}; input: ${remainingContents.substr(
714
+ 0,
715
+ 100
716
+ )}`
717
+ );
718
+ err.line = line;
719
+ throw err;
785
720
  }
786
- }
787
- if (end) {
788
- ret = state.reviver ? state.reviver("", ret) : ret;
789
- endChecks(tokens, state, ret);
790
- }
791
- return ret;
721
+ const tokenWithLine = matched.matched;
722
+ tokenWithLine.line = line;
723
+ line += matched.raw.replace(/[^\n]/g, "").length;
724
+ tokens.push(tokenWithLine);
725
+ }
726
+ return tokens;
727
+ };
792
728
  }
793
- function normalizeParseOptions(optsOrReviver) {
794
- var _a;
795
- let options = {};
796
- if (typeof optsOrReviver === "function") {
797
- options.reviver = optsOrReviver;
798
- } else if (optsOrReviver !== null && typeof optsOrReviver === "object") {
799
- options = { ...optsOrReviver };
800
- } else if (optsOrReviver !== void 0) {
801
- throw new TypeError(
802
- "Second argument must be a reviver function or an options object."
803
- );
804
- }
805
- if (options.relaxed === void 0) {
806
- if (options.warnings === true || options.tolerant === true) {
807
- options.relaxed = true;
808
- } else if (options.warnings === false && options.tolerant === false) {
809
- options.relaxed = false;
810
- } else {
811
- options.relaxed = true;
729
+ function fStringSingle(m) {
730
+ const content = m[1].replace(
731
+ /([^'\\]|\\['bnrtf\\]|\\u[0-9a-fA-F]{4})/g,
732
+ (mm) => {
733
+ if (mm === '"') {
734
+ return '\\"';
735
+ }
736
+ if (mm === "\\'") {
737
+ return "'";
738
+ }
739
+ return mm;
812
740
  }
813
- }
814
- options.tolerant = options.tolerant || options.warnings;
815
- options.duplicate = (_a = options.duplicate) != null ? _a : false;
816
- return options;
741
+ );
742
+ const match = `"${content}"`;
743
+ return {
744
+ type: "string",
745
+ match,
746
+ // The transformed, double-quoted string representation
747
+ // Use JSON.parse on the transformed string to handle escape sequences correctly
748
+ value: JSON.parse(match)
749
+ };
817
750
  }
818
- function createParseState(options) {
819
- var _a, _b;
751
+ function fStringDouble(m) {
820
752
  return {
821
- pos: 0,
822
- reviver: options.reviver,
823
- tolerant: (_a = options.tolerant) != null ? _a : false,
824
- duplicate: (_b = options.duplicate) != null ? _b : false,
825
- warnings: []
753
+ type: "string",
754
+ match: m[0],
755
+ // The raw matched string (including quotes)
756
+ value: JSON.parse(m[0])
757
+ // Use JSON.parse to handle escapes and get the value
826
758
  };
827
759
  }
828
- function parseWithCustomParser(text, options) {
829
- const lexerToUse = options.relaxed ? lexer : strictLexer;
830
- let tokens = lexerToUse(text);
831
- if (options.relaxed) {
832
- tokens = stripTrailingComma(tokens);
833
- }
834
- tokens = tokens.filter((token) => token.type !== " ");
835
- const state = createParseState(options);
836
- return parseAny(tokens, state, true);
760
+ function fIdentifier(m) {
761
+ const value = m[0];
762
+ const match = '"' + value.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + // Escape backslashes and quotes
763
+ '"';
764
+ return {
765
+ type: "string",
766
+ // Treat identifiers as strings
767
+ value,
768
+ // The original identifier name
769
+ match
770
+ // The double-quoted string representation
771
+ };
837
772
  }
838
- function parseWithTransform(text, options) {
839
- let tokens = lexer(text);
840
- tokens = stripTrailingComma(tokens);
841
- const newtext = tokens.reduce((str, token) => str + token.match, "");
842
- return JSON.parse(
843
- newtext,
844
- options.reviver
773
+ function fComment(m) {
774
+ const match = m[0].replace(
775
+ /./g,
776
+ (c) => WHITESPACE_TEST_REGEX.test(c) ? c : " "
845
777
  );
778
+ return {
779
+ type: " ",
780
+ // Represent comments as whitespace tokens
781
+ match,
782
+ // String containing original newlines and spaces for other chars
783
+ value: void 0
784
+ // Comments don't have a semantic value
785
+ };
846
786
  }
847
- function parse(text, optsOrReviver) {
848
- const options = normalizeParseOptions(optsOrReviver);
849
- if (!(options.relaxed || options.warnings || options.tolerant) && options.duplicate) {
850
- return JSON.parse(
851
- text,
852
- options.reviver
853
- );
854
- }
855
- if (options.warnings || options.tolerant || !options.duplicate) {
856
- return parseWithCustomParser(text, options);
857
- }
858
- return parseWithTransform(text, options);
859
- }
860
-
861
- // src/core/protocols/json-mix-protocol.ts
862
- function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
863
- var _a, _b;
864
- try {
865
- const parsedToolCall = parse(toolCallJson);
866
- processedElements.push({
867
- type: "tool-call",
868
- toolCallId: generateId(),
869
- toolName: parsedToolCall.name,
870
- input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
871
- });
872
- } catch (error) {
873
- logParseFailure({
874
- phase: "generated-text",
875
- reason: "Failed to parse tool call JSON segment",
876
- snippet: fullMatch,
877
- error
878
- });
879
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
880
- options,
881
- "Could not process JSON tool call, keeping original text.",
882
- { toolCall: fullMatch, error }
883
- );
884
- processedElements.push({ type: "text", text: fullMatch });
885
- }
886
- }
887
- function addTextSegment(text, processedElements) {
888
- if (text.trim()) {
889
- processedElements.push({ type: "text", text });
890
- }
891
- }
892
- function processMatchedToolCall(context) {
893
- const { match, text, currentIndex, processedElements, options } = context;
894
- const startIndex = match.index;
895
- const toolCallJson = match[1];
896
- if (startIndex > currentIndex) {
897
- const textSegment = text.substring(currentIndex, startIndex);
898
- addTextSegment(textSegment, processedElements);
899
- }
900
- if (toolCallJson) {
901
- processToolCallJson(toolCallJson, match[0], processedElements, options);
902
- }
903
- return startIndex + match[0].length;
904
- }
905
- function flushBuffer(state, controller, toolCallStart) {
906
- if (state.buffer.length === 0) {
907
- return;
908
- }
909
- if (!state.currentTextId) {
910
- state.currentTextId = generateId();
911
- controller.enqueue({
912
- type: "text-start",
913
- id: state.currentTextId
914
- });
915
- state.hasEmittedTextStart = true;
916
- }
917
- const deltaContent = state.isInsideToolCall ? `${toolCallStart}${state.buffer}` : state.buffer;
918
- controller.enqueue({
919
- type: "text-delta",
920
- id: state.currentTextId,
921
- textDelta: deltaContent,
922
- delta: deltaContent
923
- });
924
- state.buffer = "";
787
+ function fNumber(m) {
788
+ return {
789
+ type: "number",
790
+ match: m[0],
791
+ // The raw matched number string
792
+ value: Number.parseFloat(m[0])
793
+ // Convert string to number
794
+ };
925
795
  }
926
- function closeTextBlock(state, controller) {
927
- if (state.currentTextId && state.hasEmittedTextStart) {
928
- controller.enqueue({
929
- type: "text-end",
930
- id: state.currentTextId
931
- });
932
- state.currentTextId = null;
933
- state.hasEmittedTextStart = false;
796
+ function fKeyword(m) {
797
+ let value;
798
+ switch (m[0]) {
799
+ case "null":
800
+ value = null;
801
+ break;
802
+ case "true":
803
+ value = true;
804
+ break;
805
+ case "false":
806
+ value = false;
807
+ break;
808
+ default:
809
+ throw new Error(`Unexpected keyword: ${m[0]}`);
934
810
  }
811
+ return {
812
+ type: "atom",
813
+ // Use 'atom' type for these literals
814
+ match: m[0],
815
+ // The raw matched keyword
816
+ value
817
+ // The corresponding JavaScript value
818
+ };
935
819
  }
936
- function emitIncompleteToolCall(state, controller, toolCallStart) {
937
- if (!state.currentToolCallJson) {
938
- return;
820
+ function makeTokenSpecs(relaxed) {
821
+ function f(type) {
822
+ return (m) => {
823
+ return { type, match: m[0], value: void 0 };
824
+ };
939
825
  }
940
- logParseFailure({
941
- phase: "stream",
942
- reason: "Incomplete streaming tool call segment emitted as text",
943
- snippet: `${toolCallStart}${state.currentToolCallJson}`
944
- });
945
- const errorId = generateId();
946
- const errorContent = `${toolCallStart}${state.currentToolCallJson}`;
947
- controller.enqueue({
948
- type: "text-start",
949
- id: errorId
950
- });
951
- controller.enqueue({
952
- type: "text-delta",
953
- id: errorId,
954
- textDelta: errorContent,
955
- delta: errorContent
956
- });
957
- controller.enqueue({
958
- type: "text-end",
959
- id: errorId
960
- });
961
- state.currentToolCallJson = "";
962
- }
963
- function handleFinishChunk(state, controller, toolCallStart, chunk) {
964
- if (state.buffer.length > 0) {
965
- flushBuffer(state, controller, toolCallStart);
826
+ let tokenSpecs = [
827
+ { re: WHITESPACE_REGEX2, f: f(" ") },
828
+ // Whitespace
829
+ { re: OBJECT_START_REGEX, f: f("{") },
830
+ // Object start
831
+ { re: OBJECT_END_REGEX, f: f("}") },
832
+ // Object end
833
+ { re: ARRAY_START_REGEX, f: f("[") },
834
+ // Array start
835
+ { re: ARRAY_END_REGEX, f: f("]") },
836
+ // Array end
837
+ { re: COMMA_REGEX, f: f(",") },
838
+ // Comma separator
839
+ { re: COLON_REGEX, f: f(":") },
840
+ // Key-value separator
841
+ { re: KEYWORD_REGEX, f: fKeyword },
842
+ // Keywords
843
+ // Number: optional sign, digits, optional decimal part, optional exponent
844
+ { re: NUMBER_REGEX, f: fNumber },
845
+ // String: double-quoted, handles escapes
846
+ { re: STRING_DOUBLE_REGEX, f: fStringDouble }
847
+ ];
848
+ if (relaxed) {
849
+ tokenSpecs = tokenSpecs.concat([
850
+ // Single-quoted strings
851
+ {
852
+ re: STRING_SINGLE_REGEX,
853
+ f: fStringSingle
854
+ },
855
+ // Single-line comments (// ...)
856
+ { re: COMMENT_SINGLE_REGEX, f: fComment },
857
+ // Multi-line comments (/* ... */)
858
+ { re: COMMENT_MULTI_REGEX, f: fComment },
859
+ // Unquoted identifiers (treated as strings)
860
+ // Allows letters, numbers, _, -, +, ., *, ?, !, |, &, %, ^, /, #, \
861
+ { re: IDENTIFIER_REGEX, f: fIdentifier }
862
+ // Note: The order matters here. Identifiers are checked after keywords/numbers.
863
+ ]);
966
864
  }
967
- closeTextBlock(state, controller);
968
- emitIncompleteToolCall(state, controller, toolCallStart);
969
- controller.enqueue(chunk);
865
+ return tokenSpecs;
970
866
  }
971
- function publishText(text, state, controller) {
972
- if (state.isInsideToolCall) {
973
- closeTextBlock(state, controller);
974
- state.currentToolCallJson += text;
975
- } else if (text.length > 0) {
976
- if (!state.currentTextId) {
977
- state.currentTextId = generateId();
978
- controller.enqueue({
979
- type: "text-start",
980
- id: state.currentTextId
981
- });
982
- state.hasEmittedTextStart = true;
867
+ var lexer = makeLexer(makeTokenSpecs(true));
868
+ var strictLexer = makeLexer(makeTokenSpecs(false));
869
+ function previousNWSToken(tokens, index) {
870
+ let currentIndex = index;
871
+ for (; currentIndex >= 0; currentIndex -= 1) {
872
+ if (tokens[currentIndex].type !== " ") {
873
+ return currentIndex;
983
874
  }
984
- controller.enqueue({
985
- type: "text-delta",
986
- id: state.currentTextId,
987
- textDelta: text,
988
- delta: text
989
- });
990
875
  }
876
+ return;
991
877
  }
992
- function emitToolCall(context) {
993
- var _a, _b;
994
- const { state, controller, toolCallStart, toolCallEnd, options } = context;
995
- try {
996
- const parsedToolCall = parse(state.currentToolCallJson);
997
- closeTextBlock(state, controller);
998
- controller.enqueue({
999
- type: "tool-call",
1000
- toolCallId: generateId(),
1001
- toolName: parsedToolCall.name,
1002
- input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1003
- });
1004
- } catch (error) {
1005
- logParseFailure({
1006
- phase: "stream",
1007
- reason: "Failed to parse streaming tool call JSON segment",
1008
- snippet: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`,
1009
- error
1010
- });
1011
- const errorId = generateId();
1012
- const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
1013
- controller.enqueue({
1014
- type: "text-start",
1015
- id: errorId
1016
- });
1017
- controller.enqueue({
1018
- type: "text-delta",
1019
- id: errorId,
1020
- textDelta: errorContent,
1021
- delta: errorContent
1022
- });
1023
- controller.enqueue({
1024
- type: "text-end",
1025
- id: errorId
1026
- });
1027
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1028
- options,
1029
- "Could not process streaming JSON tool call; emitting original text.",
1030
- {
1031
- toolCall: errorContent
878
+ function stripTrailingComma(tokens) {
879
+ const res = [];
880
+ tokens.forEach((token, index) => {
881
+ if (index > 0 && (token.type === "]" || token.type === "}")) {
882
+ const prevNWSTokenIndex = previousNWSToken(res, res.length - 1);
883
+ if (prevNWSTokenIndex !== void 0 && res[prevNWSTokenIndex].type === ",") {
884
+ const preCommaIndex = previousNWSToken(res, prevNWSTokenIndex - 1);
885
+ if (preCommaIndex !== void 0 && res[preCommaIndex].type !== "[" && res[preCommaIndex].type !== "{") {
886
+ res[prevNWSTokenIndex] = {
887
+ type: " ",
888
+ match: " ",
889
+ // Represent as a single space
890
+ value: void 0,
891
+ // Whitespace has no value
892
+ line: res[prevNWSTokenIndex].line
893
+ // Preserve original line number
894
+ };
895
+ }
1032
896
  }
1033
- );
1034
- }
897
+ }
898
+ res.push(token);
899
+ });
900
+ return res;
1035
901
  }
1036
- function processTagMatch(context) {
1037
- const { state } = context;
1038
- if (state.isInsideToolCall) {
1039
- emitToolCall(context);
1040
- state.currentToolCallJson = "";
1041
- state.isInsideToolCall = false;
1042
- } else {
1043
- state.currentToolCallJson = "";
1044
- state.isInsideToolCall = true;
1045
- }
902
+ function transform(text) {
903
+ let tokens = lexer(text);
904
+ tokens = stripTrailingComma(tokens);
905
+ return tokens.reduce((str, token) => str + token.match, "");
1046
906
  }
1047
- function processBufferTags(context) {
1048
- const { state, controller, toolCallStart, toolCallEnd } = context;
1049
- let startIndex = getPotentialStartIndex(
1050
- state.buffer,
1051
- state.isInsideToolCall ? toolCallEnd : toolCallStart
1052
- );
1053
- while (startIndex != null) {
1054
- const tag = state.isInsideToolCall ? toolCallEnd : toolCallStart;
1055
- if (startIndex + tag.length > state.buffer.length) {
1056
- break;
1057
- }
1058
- publishText(state.buffer.slice(0, startIndex), state, controller);
1059
- state.buffer = state.buffer.slice(startIndex + tag.length);
1060
- processTagMatch(context);
1061
- startIndex = getPotentialStartIndex(
1062
- state.buffer,
1063
- state.isInsideToolCall ? toolCallEnd : toolCallStart
1064
- );
907
+ function popToken(tokens, state) {
908
+ var _a, _b;
909
+ const token = tokens[state.pos];
910
+ state.pos += 1;
911
+ if (!token) {
912
+ const lastLine = tokens.length !== 0 ? (_b = (_a = tokens.at(-1)) == null ? void 0 : _a.line) != null ? _b : 1 : 1;
913
+ return { type: "eof", match: "", value: void 0, line: lastLine };
1065
914
  }
915
+ return token;
1066
916
  }
1067
- function handlePartialTag(state, controller, toolCallStart) {
1068
- if (state.isInsideToolCall) {
1069
- return;
1070
- }
1071
- const potentialIndex = getPotentialStartIndex(state.buffer, toolCallStart);
1072
- if (potentialIndex != null && potentialIndex + toolCallStart.length > state.buffer.length) {
1073
- publishText(state.buffer.slice(0, potentialIndex), state, controller);
1074
- state.buffer = state.buffer.slice(potentialIndex);
1075
- } else {
1076
- publishText(state.buffer, state, controller);
1077
- state.buffer = "";
917
+ function strToken(token) {
918
+ switch (token.type) {
919
+ case "atom":
920
+ case "string":
921
+ case "number":
922
+ return `${token.type} ${token.match}`;
923
+ case "eof":
924
+ return "end-of-file";
925
+ default:
926
+ return `'${token.type}'`;
1078
927
  }
1079
928
  }
1080
- var jsonMixProtocol = ({
1081
- toolCallStart = "<tool_call>",
1082
- toolCallEnd = "</tool_call>",
1083
- toolResponseStart = "<tool_response>",
1084
- toolResponseEnd = "</tool_response>"
1085
- } = {}) => ({
1086
- formatTools({ tools, toolSystemPromptTemplate }) {
1087
- const toolsForPrompt = (tools || []).filter((tool) => tool.type === "function").map((tool) => ({
1088
- name: tool.name,
1089
- description: tool.type === "function" && typeof tool.description === "string" ? tool.description : void 0,
1090
- parameters: tool.inputSchema
1091
- }));
1092
- return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1093
- },
1094
- formatToolCall(toolCall) {
1095
- let args = {};
1096
- try {
1097
- args = JSON.parse(toolCall.input);
1098
- } catch (e) {
1099
- args = toolCall.input;
1100
- }
1101
- return `${toolCallStart}${JSON.stringify({
1102
- name: toolCall.toolName,
1103
- arguments: args
1104
- })}${toolCallEnd}`;
1105
- },
1106
- formatToolResponse(toolResult) {
1107
- return `${toolResponseStart}${JSON.stringify({
1108
- toolName: toolResult.toolName,
1109
- result: toolResult.result
1110
- })}${toolResponseEnd}`;
1111
- },
1112
- parseGeneratedText({ text, options }) {
1113
- const startEsc = escapeRegExp(toolCallStart);
1114
- const endEsc = escapeRegExp(toolCallEnd);
1115
- const toolCallRegex = new RegExp(
1116
- `${startEsc}([\0-\uFFFF]*?)${endEsc}`,
1117
- "gs"
1118
- );
1119
- const processedElements = [];
1120
- let currentIndex = 0;
1121
- let match = toolCallRegex.exec(text);
1122
- while (match !== null) {
1123
- currentIndex = processMatchedToolCall({
1124
- match,
1125
- text,
1126
- currentIndex,
1127
- processedElements,
1128
- options
929
+ function skipColon(tokens, state) {
930
+ const colon = popToken(tokens, state);
931
+ if (colon.type !== ":") {
932
+ const message = `Unexpected token: ${strToken(colon)}, expected ':'`;
933
+ if (state.tolerant) {
934
+ state.warnings.push({
935
+ message,
936
+ line: colon.line
1129
937
  });
1130
- match = toolCallRegex.exec(text);
938
+ state.pos -= 1;
939
+ } else {
940
+ const err = new SyntaxError(message);
941
+ err.line = colon.line;
942
+ throw err;
1131
943
  }
1132
- if (currentIndex < text.length) {
1133
- const remainingText = text.substring(currentIndex);
1134
- addTextSegment(remainingText, processedElements);
944
+ }
945
+ }
946
+ function skipPunctuation(tokens, state, valid) {
947
+ const punctuation = [",", ":", "]", "}"];
948
+ let token = popToken(tokens, state);
949
+ while (true) {
950
+ if (valid == null ? void 0 : valid.includes(token.type)) {
951
+ return token;
1135
952
  }
1136
- return processedElements;
1137
- },
1138
- createStreamParser({ options }) {
1139
- const state = {
1140
- isInsideToolCall: false,
1141
- buffer: "",
1142
- currentToolCallJson: "",
1143
- currentTextId: null,
1144
- hasEmittedTextStart: false
1145
- };
1146
- return new TransformStream({
1147
- transform(chunk, controller) {
1148
- var _a, _b;
1149
- if (chunk.type === "finish") {
1150
- handleFinishChunk(state, controller, toolCallStart, chunk);
1151
- return;
1152
- }
1153
- if (chunk.type !== "text-delta") {
1154
- controller.enqueue(chunk);
1155
- return;
1156
- }
1157
- const textContent = (_b = (_a = chunk.textDelta) != null ? _a : chunk.delta) != null ? _b : "";
1158
- state.buffer += textContent;
1159
- processBufferTags({
1160
- state,
1161
- controller,
1162
- toolCallStart,
1163
- toolCallEnd,
1164
- options
1165
- });
1166
- handlePartialTag(state, controller, toolCallStart);
1167
- }
1168
- });
1169
- },
1170
- extractToolCallSegments({ text }) {
1171
- const startEsc = escapeRegExp(toolCallStart);
1172
- const endEsc = escapeRegExp(toolCallEnd);
1173
- const regex = new RegExp(`${startEsc}([\0-\uFFFF]*?)${endEsc}`, "gs");
1174
- const segments = [];
1175
- let m = regex.exec(text);
1176
- while (m != null) {
1177
- segments.push(m[0]);
1178
- m = regex.exec(text);
953
+ if (token.type === "eof") {
954
+ return token;
955
+ }
956
+ if (punctuation.includes(token.type)) {
957
+ const message = `Unexpected token: ${strToken(
958
+ token
959
+ )}, expected '[', '{', number, string or atom`;
960
+ if (state.tolerant) {
961
+ state.warnings.push({
962
+ message,
963
+ line: token.line
964
+ });
965
+ token = popToken(tokens, state);
966
+ } else {
967
+ const err = new SyntaxError(message);
968
+ err.line = token.line;
969
+ throw err;
970
+ }
971
+ } else {
972
+ return token;
1179
973
  }
1180
- return segments;
1181
- }
1182
- });
1183
-
1184
- // src/core/protocols/morph-xml-protocol.ts
1185
- var import_rxml2 = require("@ai-sdk-tool/rxml");
1186
-
1187
- // src/core/heuristics/engine.ts
1188
- function applyRawSegmentUpdate(current, result) {
1189
- if (result.rawSegment !== void 0) {
1190
- return { ...current, rawSegment: result.rawSegment };
1191
974
  }
1192
- return current;
1193
975
  }
1194
- function applyParsedUpdate(current, result) {
1195
- if (result.parsed !== void 0) {
1196
- return { ...current, parsed: result.parsed };
976
+ function raiseError(state, token, message) {
977
+ if (state.tolerant) {
978
+ state.warnings.push({
979
+ message,
980
+ line: token.line
981
+ });
982
+ } else {
983
+ const err = new SyntaxError(message);
984
+ err.line = token.line;
985
+ throw err;
1197
986
  }
1198
- return current;
1199
987
  }
1200
- function applyWarningsUpdate(current, result) {
1201
- var _a, _b;
1202
- if (result.warnings && result.warnings.length > 0) {
1203
- const meta = (_a = current.meta) != null ? _a : {};
1204
- const existingWarnings = (_b = meta.warnings) != null ? _b : [];
1205
- return {
1206
- ...current,
1207
- meta: { ...meta, warnings: [...existingWarnings, ...result.warnings] }
1208
- };
1209
- }
1210
- return current;
988
+ function raiseUnexpected(state, token, expected) {
989
+ raiseError(
990
+ state,
991
+ token,
992
+ `Unexpected token: ${strToken(token)}, expected ${expected}`
993
+ );
1211
994
  }
1212
- function attemptReparse(current, result, reparseCount, maxReparses, parse4) {
1213
- if (!result.reparse || result.rawSegment === void 0 || reparseCount >= maxReparses) {
1214
- return { state: current, newCount: reparseCount };
995
+ function checkDuplicates(state, obj, token) {
996
+ const key = String(token.value);
997
+ if (!state.duplicate && Object.hasOwn(obj, key)) {
998
+ raiseError(state, token, `Duplicate key: ${key}`);
1215
999
  }
1216
- try {
1217
- const reparsed = parse4(result.rawSegment, current.schema);
1218
- return {
1219
- state: { ...current, parsed: reparsed, errors: [] },
1220
- newCount: reparseCount + 1
1221
- };
1222
- } catch (error) {
1223
- return {
1224
- state: { ...current, errors: [...current.errors, error] },
1225
- newCount: reparseCount + 1
1226
- };
1000
+ }
1001
+ function appendPair(state, obj, key, value) {
1002
+ const finalValue = state.reviver ? state.reviver(key, value) : value;
1003
+ if (finalValue !== void 0) {
1004
+ obj[key] = finalValue;
1227
1005
  }
1228
1006
  }
1229
- function executePhase(ctx, heuristics, options) {
1230
- var _a;
1231
- let current = ctx;
1232
- let reparseCount = 0;
1233
- const maxReparses = (_a = options.maxReparses) != null ? _a : 2;
1234
- for (const heuristic of heuristics) {
1235
- if (!heuristic.applies(current)) {
1236
- continue;
1237
- }
1238
- const result = heuristic.run(current);
1239
- current = applyRawSegmentUpdate(current, result);
1240
- current = applyParsedUpdate(current, result);
1241
- current = applyWarningsUpdate(current, result);
1242
- const reparseResult = attemptReparse(
1243
- current,
1244
- result,
1245
- reparseCount,
1246
- maxReparses,
1247
- options.parse
1248
- );
1249
- current = reparseResult.state;
1250
- reparseCount = reparseResult.newCount;
1251
- if (result.stop) {
1252
- break;
1007
+ function parsePair(tokens, state, obj) {
1008
+ let token = skipPunctuation(tokens, state, [":", "string", "number", "atom"]);
1009
+ let value;
1010
+ if (token.type !== "string") {
1011
+ raiseUnexpected(state, token, "string key");
1012
+ if (state.tolerant) {
1013
+ switch (token.type) {
1014
+ case ":":
1015
+ token = {
1016
+ type: "string",
1017
+ value: "null",
1018
+ match: '"null"',
1019
+ line: token.line
1020
+ };
1021
+ state.pos -= 1;
1022
+ break;
1023
+ case "number":
1024
+ // Use number as string key
1025
+ case "atom":
1026
+ token = {
1027
+ type: "string",
1028
+ value: String(token.value),
1029
+ match: `"${token.value}"`,
1030
+ line: token.line
1031
+ };
1032
+ break;
1033
+ case "[":
1034
+ // Assume missing key before an array
1035
+ case "{":
1036
+ state.pos -= 1;
1037
+ value = parseAny(tokens, state);
1038
+ checkDuplicates(state, obj, {
1039
+ type: "string",
1040
+ value: "null",
1041
+ match: '"null"',
1042
+ line: token.line
1043
+ });
1044
+ appendPair(state, obj, "null", value);
1045
+ return;
1046
+ // Finished parsing this "pair"
1047
+ case "eof":
1048
+ return;
1049
+ // Cannot recover
1050
+ default:
1051
+ return;
1052
+ }
1053
+ } else {
1054
+ return;
1253
1055
  }
1254
1056
  }
1255
- return current;
1057
+ checkDuplicates(state, obj, token);
1058
+ const key = String(token.value);
1059
+ skipColon(tokens, state);
1060
+ value = parseAny(tokens, state);
1061
+ appendPair(state, obj, key, value);
1256
1062
  }
1257
- function applyHeuristicPipeline(ctx, config, options) {
1258
- let current = ctx;
1259
- if (config.preParse && config.preParse.length > 0) {
1260
- current = executePhase(current, config.preParse, options);
1261
- }
1262
- if (current.parsed === null && current.errors.length === 0) {
1263
- try {
1264
- const parsed = options.parse(current.rawSegment, current.schema);
1265
- current = { ...current, parsed, errors: [] };
1266
- } catch (error) {
1267
- current = { ...current, errors: [error] };
1063
+ function parseElement(tokens, state, arr) {
1064
+ const key = arr.length;
1065
+ const value = parseAny(tokens, state);
1066
+ arr[key] = state.reviver ? state.reviver(String(key), value) : value;
1067
+ }
1068
+ function parseObject(tokens, state) {
1069
+ const obj = {};
1070
+ return parseMany(tokens, state, obj, {
1071
+ skip: [":", "}"],
1072
+ // Initially skip over colon or closing brace (for empty/tolerant cases)
1073
+ elementParser: parsePair,
1074
+ // Use parsePair to parse each key-value element
1075
+ elementName: "string key",
1076
+ // Expected element type for errors
1077
+ endSymbol: "}"
1078
+ // The closing token for an object
1079
+ });
1080
+ }
1081
+ function parseArray(tokens, state) {
1082
+ const arr = [];
1083
+ return parseMany(tokens, state, arr, {
1084
+ skip: ["]"],
1085
+ // Initially skip over closing bracket (for empty/tolerant cases)
1086
+ elementParser: parseElement,
1087
+ // Use parseElement to parse each array item
1088
+ elementName: "json value",
1089
+ // Expected element type for errors
1090
+ endSymbol: "]"
1091
+ // The closing token for an array
1092
+ });
1093
+ }
1094
+ function handleInvalidToken(token, state, opts, result) {
1095
+ raiseUnexpected(state, token, `',' or '${opts.endSymbol}'`);
1096
+ if (state.tolerant) {
1097
+ if (token.type === "eof") {
1098
+ return result;
1268
1099
  }
1100
+ state.pos -= 1;
1101
+ return null;
1269
1102
  }
1270
- if (current.errors.length > 0 && config.fallbackReparse && config.fallbackReparse.length > 0) {
1271
- current = executePhase(current, config.fallbackReparse, options);
1272
- }
1273
- if (current.parsed !== null && config.postParse && config.postParse.length > 0) {
1274
- current = executePhase(current, config.postParse, options);
1275
- }
1276
- return current;
1103
+ return result;
1277
1104
  }
1278
- function createIntermediateCall(toolName, rawSegment, schema) {
1279
- return {
1280
- toolName,
1281
- schema,
1282
- rawSegment,
1283
- parsed: null,
1284
- errors: [],
1285
- meta: { originalContent: rawSegment }
1286
- };
1105
+ function handleCommaToken(params) {
1106
+ const { token, tokens, state, opts, result } = params;
1107
+ const nextToken = tokens[state.pos];
1108
+ if (state.tolerant && nextToken && nextToken.type === opts.endSymbol) {
1109
+ raiseError(state, token, `Trailing comma before '${opts.endSymbol}'`);
1110
+ popToken(tokens, state);
1111
+ return result;
1112
+ }
1113
+ opts.elementParser(tokens, state, result);
1114
+ return null;
1287
1115
  }
1288
-
1289
- // src/core/heuristics/xml-defaults.ts
1290
- var import_rxml = require("@ai-sdk-tool/rxml");
1291
- var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
1292
- var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
1293
- var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
1294
- var WHITESPACE_REGEX2 = /\s/;
1295
- var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
1296
- var NAME_START_CHAR_RE = /[A-Za-z_:]/;
1297
- var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
1298
- var STATUS_TAG_RE = /<status>([\s\S]*?)<\/status>/i;
1299
- var normalizeCloseTagsHeuristic = {
1300
- id: "normalize-close-tags",
1301
- phase: "pre-parse",
1302
- applies: () => true,
1303
- run: (ctx) => {
1304
- const normalized = ctx.rawSegment.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1305
- if (normalized !== ctx.rawSegment) {
1306
- return { rawSegment: normalized };
1116
+ function parseManyInitialElement(tokens, state, result, opts) {
1117
+ const token = skipPunctuation(tokens, state, opts.skip);
1118
+ if (token.type === "eof") {
1119
+ raiseUnexpected(state, token, `'${opts.endSymbol}' or ${opts.elementName}`);
1120
+ return result;
1121
+ }
1122
+ if (token.type === opts.endSymbol) {
1123
+ return result;
1124
+ }
1125
+ state.pos -= 1;
1126
+ opts.elementParser(tokens, state, result);
1127
+ return;
1128
+ }
1129
+ function parseManyProcessToken(params) {
1130
+ const { token, tokens, state, opts, result } = params;
1131
+ if (token.type !== opts.endSymbol && token.type !== ",") {
1132
+ const handledResult = handleInvalidToken(token, state, opts, result);
1133
+ if (handledResult !== null) {
1134
+ return handledResult;
1307
1135
  }
1308
- return {};
1309
1136
  }
1310
- };
1311
- var escapeInvalidLtHeuristic = {
1312
- id: "escape-invalid-lt",
1313
- phase: "pre-parse",
1314
- applies: () => true,
1315
- run: (ctx) => {
1316
- const escaped = escapeInvalidLt(ctx.rawSegment);
1317
- if (escaped !== ctx.rawSegment) {
1318
- return { rawSegment: escaped };
1137
+ if (token.type === opts.endSymbol) {
1138
+ return result;
1139
+ }
1140
+ if (token.type === ",") {
1141
+ const handledResult = handleCommaToken({
1142
+ token,
1143
+ tokens,
1144
+ state,
1145
+ opts,
1146
+ result
1147
+ });
1148
+ if (handledResult !== null) {
1149
+ return handledResult;
1319
1150
  }
1320
- return {};
1151
+ return;
1321
1152
  }
1322
- };
1323
- var balanceTagsHeuristic = {
1324
- id: "balance-tags",
1325
- phase: "fallback-reparse",
1326
- applies: (ctx) => {
1327
- var _a;
1328
- const original = ((_a = ctx.meta) == null ? void 0 : _a.originalContent) || ctx.rawSegment;
1329
- const normalized = original.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1330
- const balanced = balanceTags(original);
1331
- const hasMalformedClose = MALFORMED_CLOSE_RE.test(original);
1332
- if (!hasMalformedClose && balanced.length > normalized.length) {
1333
- return false;
1153
+ opts.elementParser(tokens, state, result);
1154
+ return;
1155
+ }
1156
+ function parseMany(tokens, state, result, opts) {
1157
+ const initialResult = parseManyInitialElement(tokens, state, result, opts);
1158
+ if (initialResult !== void 0) {
1159
+ return initialResult;
1160
+ }
1161
+ while (true) {
1162
+ const token = popToken(tokens, state);
1163
+ const processedResult = parseManyProcessToken({
1164
+ token,
1165
+ tokens,
1166
+ state,
1167
+ opts,
1168
+ result
1169
+ });
1170
+ if (processedResult !== void 0) {
1171
+ return processedResult;
1334
1172
  }
1335
- return balanced !== normalized;
1336
- },
1337
- run: (ctx) => {
1338
- var _a;
1339
- const original = ((_a = ctx.meta) == null ? void 0 : _a.originalContent) || ctx.rawSegment;
1340
- const balanced = balanceTags(original);
1341
- const escaped = escapeInvalidLt(balanced);
1342
- return { rawSegment: escaped, reparse: true };
1343
1173
  }
1344
- };
1345
- var dedupeShellStringTagsHeuristic = {
1346
- id: "dedupe-shell-string-tags",
1347
- phase: "fallback-reparse",
1348
- applies: (ctx) => shouldDeduplicateStringTags(ctx.schema),
1349
- run: (ctx) => {
1350
- const names = getStringPropertyNames(ctx.schema);
1351
- let deduped = ctx.rawSegment;
1352
- for (const key of names) {
1353
- deduped = dedupeSingleTag(deduped, key);
1174
+ }
1175
+ function endChecks(tokens, state, ret) {
1176
+ if (state.pos < tokens.length) {
1177
+ if (state.tolerant) {
1178
+ skipPunctuation(tokens, state);
1354
1179
  }
1355
- if (deduped !== ctx.rawSegment) {
1356
- return { rawSegment: deduped, reparse: true };
1180
+ if (state.pos < tokens.length) {
1181
+ raiseError(
1182
+ state,
1183
+ tokens[state.pos],
1184
+ `Unexpected token: ${strToken(tokens[state.pos])}, expected end-of-input`
1185
+ );
1357
1186
  }
1358
- return {};
1359
1187
  }
1360
- };
1361
- var repairAgainstSchemaHeuristic = {
1362
- id: "repair-against-schema",
1363
- phase: "post-parse",
1364
- applies: (ctx) => ctx.parsed !== null && typeof ctx.parsed === "object",
1365
- run: (ctx) => {
1366
- const repaired = repairParsedAgainstSchema(ctx.parsed, ctx.schema);
1367
- if (repaired !== ctx.parsed) {
1368
- return { parsed: repaired };
1369
- }
1370
- return {};
1188
+ if (state.tolerant && state.warnings.length > 0) {
1189
+ const message = state.warnings.length === 1 ? state.warnings[0].message : `${state.warnings.length} parse warnings`;
1190
+ const err = new SyntaxError(message);
1191
+ err.line = state.warnings[0].line;
1192
+ err.warnings = state.warnings;
1193
+ err.obj = ret;
1194
+ throw err;
1371
1195
  }
1372
- };
1373
- var defaultPipelineConfig = {
1374
- preParse: [normalizeCloseTagsHeuristic, escapeInvalidLtHeuristic],
1375
- fallbackReparse: [balanceTagsHeuristic, dedupeShellStringTagsHeuristic],
1376
- postParse: [repairAgainstSchemaHeuristic]
1377
- };
1378
- var INDEX_TAG_RE = /^<(\d+)(?:>|\/?>)/;
1379
- function isIndexTagAt(xml, pos) {
1380
- const remaining = xml.slice(pos);
1381
- return INDEX_TAG_RE.test(remaining);
1382
1196
  }
1383
- function escapeInvalidLt(xml) {
1384
- const len = xml.length;
1385
- let out = "";
1386
- for (let i = 0; i < len; i += 1) {
1387
- const ch = xml[i];
1388
- if (ch === "<") {
1389
- const next = i + 1 < len ? xml[i + 1] : "";
1390
- const isValidStart = NAME_START_CHAR_RE.test(next) || next === "/" || next === "!" || next === "?";
1391
- const isIndexTag = !isValidStart && isIndexTagAt(xml, i);
1392
- if (!(isValidStart || isIndexTag)) {
1393
- out += "&lt;";
1394
- continue;
1395
- }
1197
+ function parseAny(tokens, state, end = false) {
1198
+ const token = skipPunctuation(tokens, state);
1199
+ let ret;
1200
+ if (token.type === "eof") {
1201
+ if (end) {
1202
+ raiseUnexpected(state, token, "json value");
1396
1203
  }
1397
- out += ch;
1204
+ raiseUnexpected(state, token, "json value");
1205
+ return;
1398
1206
  }
1399
- return out;
1400
- }
1401
- function balanceTags(xml) {
1402
- const src = xml.replace(MALFORMED_CLOSE_RE_G, "</$1>").replace(STATUS_TO_STEP_BOUNDARY_RE, "</status></step><step>");
1403
- let i = 0;
1404
- const len = src.length;
1405
- const out = [];
1406
- const stack = [];
1407
- while (i < len) {
1408
- const lt = src.indexOf("<", i);
1409
- if (lt === -1) {
1410
- out.push(src.slice(i));
1207
+ switch (token.type) {
1208
+ case "{":
1209
+ ret = parseObject(tokens, state);
1411
1210
  break;
1412
- }
1413
- out.push(src.slice(i, lt));
1414
- if (lt + 1 >= len) {
1211
+ case "[":
1212
+ ret = parseArray(tokens, state);
1415
1213
  break;
1214
+ case "string":
1215
+ // String literal
1216
+ case "number":
1217
+ // Number literal
1218
+ case "atom":
1219
+ ret = token.value;
1220
+ break;
1221
+ default:
1222
+ raiseUnexpected(state, token, "json value");
1223
+ if (state.tolerant) {
1224
+ ret = null;
1225
+ } else {
1226
+ return;
1227
+ }
1228
+ }
1229
+ if (end) {
1230
+ ret = state.reviver ? state.reviver("", ret) : ret;
1231
+ endChecks(tokens, state, ret);
1232
+ }
1233
+ return ret;
1234
+ }
1235
+ function normalizeParseOptions(optsOrReviver) {
1236
+ var _a;
1237
+ let options = {};
1238
+ if (typeof optsOrReviver === "function") {
1239
+ options.reviver = optsOrReviver;
1240
+ } else if (optsOrReviver !== null && typeof optsOrReviver === "object") {
1241
+ options = { ...optsOrReviver };
1242
+ } else if (optsOrReviver !== void 0) {
1243
+ throw new TypeError(
1244
+ "Second argument must be a reviver function or an options object."
1245
+ );
1246
+ }
1247
+ if (options.relaxed === void 0) {
1248
+ if (options.warnings === true || options.tolerant === true) {
1249
+ options.relaxed = true;
1250
+ } else if (options.warnings === false && options.tolerant === false) {
1251
+ options.relaxed = false;
1252
+ } else {
1253
+ options.relaxed = true;
1416
1254
  }
1417
- const next = src[lt + 1];
1418
- if (next === "!" || next === "?") {
1419
- i = handleSpecialTagSegment(src, lt, out);
1420
- continue;
1421
- }
1422
- if (next === "/") {
1423
- i = handleClosingTagSegment(src, lt, out, stack);
1424
- continue;
1425
- }
1426
- i = handleOpeningTagSegment(src, lt, out, stack);
1427
1255
  }
1428
- for (let k = stack.length - 1; k >= 0; k -= 1) {
1429
- out.push(`</${stack[k]}>`);
1256
+ options.tolerant = options.tolerant || options.warnings;
1257
+ options.duplicate = (_a = options.duplicate) != null ? _a : false;
1258
+ return options;
1259
+ }
1260
+ function createParseState(options) {
1261
+ var _a, _b;
1262
+ return {
1263
+ pos: 0,
1264
+ reviver: options.reviver,
1265
+ tolerant: (_a = options.tolerant) != null ? _a : false,
1266
+ duplicate: (_b = options.duplicate) != null ? _b : false,
1267
+ warnings: []
1268
+ };
1269
+ }
1270
+ function parseWithCustomParser(text, options) {
1271
+ const lexerToUse = options.relaxed ? lexer : strictLexer;
1272
+ let tokens = lexerToUse(text);
1273
+ if (options.relaxed) {
1274
+ tokens = stripTrailingComma(tokens);
1275
+ }
1276
+ tokens = tokens.filter((token) => token.type !== " ");
1277
+ const state = createParseState(options);
1278
+ return parseAny(tokens, state, true);
1279
+ }
1280
+ function parseWithTransform(text, options) {
1281
+ let tokens = lexer(text);
1282
+ tokens = stripTrailingComma(tokens);
1283
+ const newtext = tokens.reduce((str, token) => str + token.match, "");
1284
+ return JSON.parse(
1285
+ newtext,
1286
+ options.reviver
1287
+ );
1288
+ }
1289
+ function parse2(text, optsOrReviver) {
1290
+ const options = normalizeParseOptions(optsOrReviver);
1291
+ if (!(options.relaxed || options.warnings || options.tolerant) && options.duplicate) {
1292
+ return JSON.parse(
1293
+ text,
1294
+ options.reviver
1295
+ );
1430
1296
  }
1431
- return out.join("");
1432
- }
1433
- function skipWs(s, p, len) {
1434
- let idx = p;
1435
- while (idx < len && WHITESPACE_REGEX2.test(s[idx])) {
1436
- idx += 1;
1297
+ if (options.warnings || options.tolerant || !options.duplicate) {
1298
+ return parseWithCustomParser(text, options);
1437
1299
  }
1438
- return idx;
1300
+ return parseWithTransform(text, options);
1439
1301
  }
1440
- function parseTagNameAt(s, p, len) {
1441
- let idx = p;
1442
- const start = idx;
1443
- while (idx < len && NAME_CHAR_RE.test(s[idx])) {
1444
- idx += 1;
1445
- }
1446
- return { name: s.slice(start, idx), pos: idx };
1302
+ function stringifyPair(obj, key) {
1303
+ return `${JSON.stringify(key)}:${stringify(obj[key])}`;
1447
1304
  }
1448
- function handleSpecialTagSegment(src, lt, out) {
1449
- const gt = src.indexOf(">", lt + 1);
1450
- if (gt === -1) {
1451
- out.push(src.slice(lt));
1452
- return src.length;
1305
+ function stringify(obj) {
1306
+ const type = typeof obj;
1307
+ if (type === "string" || type === "number" || type === "boolean" || obj === null) {
1308
+ return JSON.stringify(obj);
1453
1309
  }
1454
- out.push(src.slice(lt, gt + 1));
1455
- return gt + 1;
1456
- }
1457
- function handleClosingTagSegment(src, lt, out, stack) {
1458
- const len = src.length;
1459
- let p = skipWs(src, lt + 2, len);
1460
- const { name, pos } = parseTagNameAt(src, p, len);
1461
- p = pos;
1462
- const gt = src.indexOf(">", p);
1463
- const closingText = gt === -1 ? src.slice(lt) : src.slice(lt, gt + 1);
1464
- const idx = stack.lastIndexOf(name);
1465
- if (idx !== -1) {
1466
- for (let k = stack.length - 1; k > idx; k -= 1) {
1467
- out.push(`</${stack[k]}>`);
1468
- stack.pop();
1469
- }
1470
- out.push(closingText);
1471
- stack.pop();
1310
+ if (type === "undefined") {
1311
+ return "null";
1472
1312
  }
1473
- return gt === -1 ? len : gt + 1;
1474
- }
1475
- function handleOpeningTagSegment(src, lt, out, stack) {
1476
- const len = src.length;
1477
- let p = skipWs(src, lt + 1, len);
1478
- const nameStart = p;
1479
- const parsed = parseTagNameAt(src, p, len);
1480
- p = parsed.pos;
1481
- const name = src.slice(nameStart, p);
1482
- const q = src.indexOf(">", p);
1483
- if (q === -1) {
1484
- out.push(src.slice(lt));
1485
- return len;
1313
+ if (Array.isArray(obj)) {
1314
+ const elements = obj.map(stringify).join(",");
1315
+ return `[${elements}]`;
1486
1316
  }
1487
- let r = q - 1;
1488
- while (r >= nameStart && WHITESPACE_REGEX2.test(src[r])) {
1489
- r -= 1;
1317
+ if (type === "object") {
1318
+ const keys = Object.keys(obj);
1319
+ keys.sort();
1320
+ const pairs = keys.map((key) => stringifyPair(obj, key)).join(",");
1321
+ return `{${pairs}}`;
1490
1322
  }
1491
- const selfClosing = src[r] === "/";
1492
- out.push(src.slice(lt, q + 1));
1493
- if (!selfClosing && name) {
1494
- stack.push(name);
1323
+ return "null";
1324
+ }
1325
+
1326
+ // src/core/protocols/json-protocol.ts
1327
+ function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
1328
+ var _a, _b;
1329
+ try {
1330
+ const parsedToolCall = parse2(toolCallJson);
1331
+ processedElements.push({
1332
+ type: "tool-call",
1333
+ toolCallId: generateId(),
1334
+ toolName: parsedToolCall.name,
1335
+ input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1336
+ });
1337
+ } catch (error) {
1338
+ logParseFailure({
1339
+ phase: "generated-text",
1340
+ reason: "Failed to parse tool call JSON segment",
1341
+ snippet: fullMatch,
1342
+ error
1343
+ });
1344
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1345
+ options,
1346
+ "Could not process JSON tool call, keeping original text.",
1347
+ { toolCall: fullMatch, error }
1348
+ );
1349
+ processedElements.push({ type: "text", text: fullMatch });
1495
1350
  }
1496
- return q + 1;
1497
1351
  }
1498
- function shouldDeduplicateStringTags(schema) {
1499
- const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1500
- if (!unwrapped || typeof unwrapped !== "object") {
1501
- return false;
1352
+ function addTextSegment(text, processedElements) {
1353
+ if (text.trim()) {
1354
+ processedElements.push({ type: "text", text });
1502
1355
  }
1503
- const props = unwrapped.properties;
1504
- if (!props) {
1505
- return false;
1356
+ }
1357
+ function processMatchedToolCall(context) {
1358
+ const { match, text, currentIndex, processedElements, options } = context;
1359
+ const startIndex = match.index;
1360
+ const toolCallJson = match[1];
1361
+ if (startIndex > currentIndex) {
1362
+ const textSegment = text.substring(currentIndex, startIndex);
1363
+ addTextSegment(textSegment, processedElements);
1506
1364
  }
1507
- const commandRaw = props.command;
1508
- if (!commandRaw) {
1509
- return false;
1365
+ if (toolCallJson) {
1366
+ processToolCallJson(toolCallJson, match[0], processedElements, options);
1510
1367
  }
1511
- const command = (0, import_rxml.unwrapJsonSchema)(commandRaw);
1512
- return (command == null ? void 0 : command.type) === "array";
1368
+ return startIndex + match[0].length;
1513
1369
  }
1514
- function getStringPropertyNames(schema) {
1515
- const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1516
- if (!unwrapped || typeof unwrapped !== "object") {
1517
- return [];
1370
+ function flushBuffer(state, controller, toolCallStart) {
1371
+ if (state.buffer.length === 0) {
1372
+ return;
1518
1373
  }
1519
- const props = unwrapped.properties;
1520
- if (!props) {
1521
- return [];
1374
+ if (!state.currentTextId) {
1375
+ state.currentTextId = generateId();
1376
+ controller.enqueue({
1377
+ type: "text-start",
1378
+ id: state.currentTextId
1379
+ });
1380
+ state.hasEmittedTextStart = true;
1522
1381
  }
1523
- const names = [];
1524
- for (const key of Object.keys(props)) {
1525
- const prop = (0, import_rxml.unwrapJsonSchema)(
1526
- props[key]
1527
- );
1528
- const type = prop.type;
1529
- if (type === "string") {
1530
- names.push(key);
1531
- }
1382
+ const deltaContent = state.isInsideToolCall ? `${toolCallStart}${state.buffer}` : state.buffer;
1383
+ controller.enqueue({
1384
+ type: "text-delta",
1385
+ id: state.currentTextId,
1386
+ delta: deltaContent
1387
+ });
1388
+ state.buffer = "";
1389
+ }
1390
+ function closeTextBlock(state, controller) {
1391
+ if (state.currentTextId && state.hasEmittedTextStart) {
1392
+ controller.enqueue({
1393
+ type: "text-end",
1394
+ id: state.currentTextId
1395
+ });
1396
+ state.currentTextId = null;
1397
+ state.hasEmittedTextStart = false;
1532
1398
  }
1533
- return names;
1534
1399
  }
1535
- function escapeRegExp2(s) {
1536
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1400
+ function emitIncompleteToolCall(state, controller, toolCallStart) {
1401
+ if (!state.currentToolCallJson) {
1402
+ return;
1403
+ }
1404
+ logParseFailure({
1405
+ phase: "stream",
1406
+ reason: "Incomplete streaming tool call segment emitted as text",
1407
+ snippet: `${toolCallStart}${state.currentToolCallJson}`
1408
+ });
1409
+ const errorId = generateId();
1410
+ const errorContent = `${toolCallStart}${state.currentToolCallJson}`;
1411
+ controller.enqueue({
1412
+ type: "text-start",
1413
+ id: errorId
1414
+ });
1415
+ controller.enqueue({
1416
+ type: "text-delta",
1417
+ id: errorId,
1418
+ delta: errorContent
1419
+ });
1420
+ controller.enqueue({
1421
+ type: "text-end",
1422
+ id: errorId
1423
+ });
1424
+ state.currentToolCallJson = "";
1537
1425
  }
1538
- function dedupeSingleTag(xml, key) {
1539
- var _a, _b;
1540
- const escaped = escapeRegExp2(key);
1541
- const re = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
1542
- const matches = Array.from(xml.matchAll(re));
1543
- if (matches.length <= 1) {
1544
- return xml;
1426
+ function handleFinishChunk(state, controller, toolCallStart, chunk) {
1427
+ if (state.buffer.length > 0) {
1428
+ flushBuffer(state, controller, toolCallStart);
1545
1429
  }
1546
- const last = matches.at(-1);
1547
- let result = "";
1548
- let cursor = 0;
1549
- for (const m of matches) {
1550
- const idx = (_a = m.index) != null ? _a : 0;
1551
- result += xml.slice(cursor, idx);
1552
- if (last && idx === ((_b = last.index) != null ? _b : -1)) {
1553
- result += m[0];
1430
+ closeTextBlock(state, controller);
1431
+ emitIncompleteToolCall(state, controller, toolCallStart);
1432
+ controller.enqueue(chunk);
1433
+ }
1434
+ function publishText(text, state, controller) {
1435
+ if (state.isInsideToolCall) {
1436
+ closeTextBlock(state, controller);
1437
+ state.currentToolCallJson += text;
1438
+ } else if (text.length > 0) {
1439
+ if (!state.currentTextId) {
1440
+ state.currentTextId = generateId();
1441
+ controller.enqueue({
1442
+ type: "text-start",
1443
+ id: state.currentTextId
1444
+ });
1445
+ state.hasEmittedTextStart = true;
1554
1446
  }
1555
- cursor = idx + m[0].length;
1447
+ controller.enqueue({
1448
+ type: "text-delta",
1449
+ id: state.currentTextId,
1450
+ delta: text
1451
+ });
1556
1452
  }
1557
- result += xml.slice(cursor);
1558
- return result;
1559
1453
  }
1560
- function repairParsedAgainstSchema(input, schema) {
1561
- if (!input || typeof input !== "object") {
1562
- return input;
1563
- }
1564
- const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1565
- if (!unwrapped || typeof unwrapped !== "object") {
1566
- return input;
1454
+ function emitToolCall(context) {
1455
+ var _a, _b;
1456
+ const { state, controller, toolCallStart, toolCallEnd, options } = context;
1457
+ try {
1458
+ const parsedToolCall = parse2(state.currentToolCallJson);
1459
+ closeTextBlock(state, controller);
1460
+ controller.enqueue({
1461
+ type: "tool-call",
1462
+ toolCallId: generateId(),
1463
+ toolName: parsedToolCall.name,
1464
+ input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1465
+ });
1466
+ } catch (error) {
1467
+ logParseFailure({
1468
+ phase: "stream",
1469
+ reason: "Failed to parse streaming tool call JSON segment",
1470
+ snippet: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`,
1471
+ error
1472
+ });
1473
+ const errorId = generateId();
1474
+ const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
1475
+ controller.enqueue({
1476
+ type: "text-start",
1477
+ id: errorId
1478
+ });
1479
+ controller.enqueue({
1480
+ type: "text-delta",
1481
+ id: errorId,
1482
+ delta: errorContent
1483
+ });
1484
+ controller.enqueue({
1485
+ type: "text-end",
1486
+ id: errorId
1487
+ });
1488
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1489
+ options,
1490
+ "Could not process streaming JSON tool call; emitting original text.",
1491
+ {
1492
+ toolCall: errorContent
1493
+ }
1494
+ );
1567
1495
  }
1568
- const properties = unwrapped.properties;
1569
- if (!properties) {
1570
- return input;
1496
+ }
1497
+ function processTagMatch(context) {
1498
+ const { state } = context;
1499
+ if (state.isInsideToolCall) {
1500
+ emitToolCall(context);
1501
+ state.currentToolCallJson = "";
1502
+ state.isInsideToolCall = false;
1503
+ } else {
1504
+ state.currentToolCallJson = "";
1505
+ state.isInsideToolCall = true;
1571
1506
  }
1572
- applySchemaProps(input, properties);
1573
- return input;
1574
1507
  }
1575
- function applySchemaProps(obj, properties) {
1576
- for (const key of Object.keys(obj)) {
1577
- const propSchema = properties[key];
1578
- if (!propSchema) {
1579
- continue;
1580
- }
1581
- const prop = (0, import_rxml.unwrapJsonSchema)(propSchema);
1582
- const propType = prop.type;
1583
- if (propType === "array" && prop.items) {
1584
- const itemSchemaRaw = prop.items;
1585
- const itemSchema = (0, import_rxml.unwrapJsonSchema)(itemSchemaRaw);
1586
- obj[key] = coerceArrayItems(obj[key], itemSchema);
1587
- continue;
1588
- }
1589
- if (propType === "object") {
1590
- const val = obj[key];
1591
- if (val && typeof val === "object") {
1592
- obj[key] = repairParsedAgainstSchema(val, prop);
1593
- }
1508
+ function processBufferTags(context) {
1509
+ const { state, controller, toolCallStart, toolCallEnd } = context;
1510
+ let startIndex = getPotentialStartIndex(
1511
+ state.buffer,
1512
+ state.isInsideToolCall ? toolCallEnd : toolCallStart
1513
+ );
1514
+ while (startIndex != null) {
1515
+ const tag = state.isInsideToolCall ? toolCallEnd : toolCallStart;
1516
+ if (startIndex + tag.length > state.buffer.length) {
1517
+ break;
1594
1518
  }
1519
+ publishText(state.buffer.slice(0, startIndex), state, controller);
1520
+ state.buffer = state.buffer.slice(startIndex + tag.length);
1521
+ processTagMatch(context);
1522
+ startIndex = getPotentialStartIndex(
1523
+ state.buffer,
1524
+ state.isInsideToolCall ? toolCallEnd : toolCallStart
1525
+ );
1595
1526
  }
1596
1527
  }
1597
- function coerceArrayItems(val, itemSchema) {
1598
- if (!Array.isArray(val)) {
1599
- return val;
1528
+ function handlePartialTag(state, controller, toolCallStart) {
1529
+ if (state.isInsideToolCall) {
1530
+ return;
1531
+ }
1532
+ const potentialIndex = getPotentialStartIndex(state.buffer, toolCallStart);
1533
+ if (potentialIndex != null && potentialIndex + toolCallStart.length > state.buffer.length) {
1534
+ publishText(state.buffer.slice(0, potentialIndex), state, controller);
1535
+ state.buffer = state.buffer.slice(potentialIndex);
1536
+ } else {
1537
+ publishText(state.buffer, state, controller);
1538
+ state.buffer = "";
1600
1539
  }
1601
- return val.map((v) => coerceArrayItem(v, itemSchema));
1602
1540
  }
1603
- function coerceArrayItem(v, itemSchema) {
1604
- const itemType = itemSchema == null ? void 0 : itemSchema.type;
1605
- if (typeof v === "string" && itemType === "object") {
1606
- const parsed = tryParseStringToSchemaObject(v, itemSchema);
1607
- if (parsed !== null) {
1608
- return parsed;
1541
+ var jsonProtocol = ({
1542
+ toolCallStart = "<tool_call>",
1543
+ toolCallEnd = "</tool_call>"
1544
+ } = {}) => ({
1545
+ formatTools({
1546
+ tools,
1547
+ toolSystemPromptTemplate
1548
+ }) {
1549
+ return toolSystemPromptTemplate(tools || []);
1550
+ },
1551
+ formatToolCall(toolCall) {
1552
+ let args = {};
1553
+ try {
1554
+ args = JSON.parse(toolCall.input);
1555
+ } catch (e) {
1556
+ args = toolCall.input;
1609
1557
  }
1610
- const fallback = extractStepStatusFromString(
1611
- v.replace(MALFORMED_CLOSE_RE_G, "</$1>")
1558
+ return `${toolCallStart}${JSON.stringify({
1559
+ name: toolCall.toolName,
1560
+ arguments: args
1561
+ })}${toolCallEnd}`;
1562
+ },
1563
+ parseGeneratedText({
1564
+ text,
1565
+ options
1566
+ }) {
1567
+ const startEsc = escapeRegExp2(toolCallStart);
1568
+ const endEsc = escapeRegExp2(toolCallEnd);
1569
+ const toolCallRegex = new RegExp(
1570
+ `${startEsc}([\0-\uFFFF]*?)${endEsc}`,
1571
+ "gs"
1612
1572
  );
1613
- if (fallback) {
1614
- return fallback;
1573
+ const processedElements = [];
1574
+ let currentIndex = 0;
1575
+ let match = toolCallRegex.exec(text);
1576
+ while (match !== null) {
1577
+ currentIndex = processMatchedToolCall({
1578
+ match,
1579
+ text,
1580
+ currentIndex,
1581
+ processedElements,
1582
+ options
1583
+ });
1584
+ match = toolCallRegex.exec(text);
1615
1585
  }
1616
- return v;
1617
- }
1618
- if (v && typeof v === "object" && itemType === "object") {
1619
- return repairParsedAgainstSchema(v, itemSchema);
1620
- }
1621
- return v;
1622
- }
1623
- function tryParseStringToSchemaObject(xml, itemSchema) {
1624
- try {
1625
- const normalized = xml.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1626
- const fixed = (0, import_rxml.parse)(normalized, itemSchema, { noChildNodes: [] });
1627
- return typeof fixed === "string" ? null : fixed;
1628
- } catch (e) {
1629
- return null;
1586
+ if (currentIndex < text.length) {
1587
+ const remainingText = text.substring(currentIndex);
1588
+ addTextSegment(remainingText, processedElements);
1589
+ }
1590
+ return processedElements;
1591
+ },
1592
+ createStreamParser({
1593
+ options
1594
+ }) {
1595
+ const state = {
1596
+ isInsideToolCall: false,
1597
+ buffer: "",
1598
+ currentToolCallJson: "",
1599
+ currentTextId: null,
1600
+ hasEmittedTextStart: false
1601
+ };
1602
+ return new TransformStream({
1603
+ transform(chunk, controller) {
1604
+ var _a;
1605
+ if (chunk.type === "finish") {
1606
+ handleFinishChunk(state, controller, toolCallStart, chunk);
1607
+ return;
1608
+ }
1609
+ if (chunk.type !== "text-delta") {
1610
+ controller.enqueue(chunk);
1611
+ return;
1612
+ }
1613
+ const textContent = (_a = chunk.delta) != null ? _a : "";
1614
+ state.buffer += textContent;
1615
+ processBufferTags({
1616
+ state,
1617
+ controller,
1618
+ toolCallStart,
1619
+ toolCallEnd,
1620
+ options
1621
+ });
1622
+ handlePartialTag(state, controller, toolCallStart);
1623
+ }
1624
+ });
1625
+ },
1626
+ extractToolCallSegments({ text }) {
1627
+ const startEsc = escapeRegExp2(toolCallStart);
1628
+ const endEsc = escapeRegExp2(toolCallEnd);
1629
+ const regex = new RegExp(`${startEsc}([\0-\uFFFF]*?)${endEsc}`, "gs");
1630
+ const segments = [];
1631
+ let m = regex.exec(text);
1632
+ while (m != null) {
1633
+ segments.push(m[0]);
1634
+ m = regex.exec(text);
1635
+ }
1636
+ return segments;
1630
1637
  }
1638
+ });
1639
+
1640
+ // src/core/protocols/protocol-interface.ts
1641
+ function isProtocolFactory(protocol) {
1642
+ return typeof protocol === "function";
1631
1643
  }
1632
- function extractStepStatusFromString(normXml) {
1633
- const stepMatch = normXml.match(STEP_TAG_RE);
1634
- const statusMatch = normXml.match(STATUS_TAG_RE);
1635
- if (stepMatch && statusMatch) {
1636
- return { step: stepMatch[1], status: statusMatch[1] };
1637
- }
1638
- return null;
1644
+ function isTCMProtocolFactory(protocol) {
1645
+ return typeof protocol === "function";
1639
1646
  }
1640
1647
 
1641
- // src/core/protocols/morph-xml-protocol.ts
1648
+ // src/core/protocols/xml-protocol.ts
1649
+ import { extractRawInner, parse as parse3, stringify as stringify2 } from "@ai-sdk-tool/rxml";
1642
1650
  var defaultPipelineConfig2 = defaultPipelineConfig;
1643
1651
  var NAME_CHAR_RE2 = /[A-Za-z0-9_:-]/;
1644
1652
  var WHITESPACE_REGEX3 = /\s/;
@@ -1652,7 +1660,7 @@ function normalizeCloseTags(xml) {
1652
1660
  function tryParseSecondaryXml(content, toolSchema, options) {
1653
1661
  const balanced = balanceTags(content);
1654
1662
  try {
1655
- let parsed = (0, import_rxml2.parse)(balanced, toolSchema, {
1663
+ let parsed = parse3(balanced, toolSchema, {
1656
1664
  onError: options == null ? void 0 : options.onError,
1657
1665
  noChildNodes: []
1658
1666
  });
@@ -1667,7 +1675,7 @@ function tryParseSecondaryXml(content, toolSchema, options) {
1667
1675
  }
1668
1676
  if (deduped !== balanced) {
1669
1677
  try {
1670
- let reparsed = (0, import_rxml2.parse)(deduped, toolSchema, {
1678
+ let reparsed = parse3(deduped, toolSchema, {
1671
1679
  onError: options == null ? void 0 : options.onError,
1672
1680
  noChildNodes: []
1673
1681
  });
@@ -1699,7 +1707,7 @@ function processToolCallWithPipeline(params) {
1699
1707
  toolSchema
1700
1708
  );
1701
1709
  const result = applyHeuristicPipeline(ctx, pipelineConfig, {
1702
- parse: (xml, schema) => (0, import_rxml2.parse)(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1710
+ parse: (xml, schema) => parse3(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1703
1711
  onError: options == null ? void 0 : options.onError,
1704
1712
  maxReparses
1705
1713
  });
@@ -1744,7 +1752,7 @@ function handleStreamingToolCallEnd(params) {
1744
1752
  toolSchema
1745
1753
  );
1746
1754
  const result = applyHeuristicPipeline(ctx, pipelineConfig, {
1747
- parse: (xml, schema) => (0, import_rxml2.parse)(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1755
+ parse: (xml, schema) => parse3(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1748
1756
  onError: options == null ? void 0 : options.onError,
1749
1757
  maxReparses
1750
1758
  });
@@ -1752,7 +1760,7 @@ function handleStreamingToolCallEnd(params) {
1752
1760
  } else {
1753
1761
  try {
1754
1762
  const primary = escapeInvalidLt(normalizeCloseTags(toolContent));
1755
- const parsed = (0, import_rxml2.parse)(primary, toolSchema, {
1763
+ const parsed = parse3(primary, toolSchema, {
1756
1764
  onError: options == null ? void 0 : options.onError,
1757
1765
  noChildNodes: []
1758
1766
  });
@@ -1909,7 +1917,7 @@ function findToolCallsForName(text, toolName) {
1909
1917
  const fullTagEnd = findClosingTagEndFlexible(text, contentStart, toolName);
1910
1918
  if (fullTagEnd !== -1 && fullTagEnd > contentStart) {
1911
1919
  const segment = text.substring(tagStart, fullTagEnd);
1912
- const inner = (_a = (0, import_rxml2.extractRawInner)(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
1920
+ const inner = (_a = extractRawInner(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
1913
1921
  toolCalls.push({
1914
1922
  toolName,
1915
1923
  startIndex: tagStart,
@@ -1972,7 +1980,6 @@ function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmitte
1972
1980
  controller.enqueue({
1973
1981
  type: "text-delta",
1974
1982
  id: getCurrentTextId(),
1975
- textDelta: content,
1976
1983
  delta: content
1977
1984
  });
1978
1985
  }
@@ -2134,7 +2141,7 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
2134
2141
  }
2135
2142
  };
2136
2143
  }
2137
- var morphXmlProtocol = (protocolOptions) => {
2144
+ var xmlProtocol = (protocolOptions) => {
2138
2145
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2139
2146
  let pipelineConfig = protocolOptions == null ? void 0 : protocolOptions.pipeline;
2140
2147
  const maxReparses = protocolOptions == null ? void 0 : protocolOptions.maxReparses;
@@ -2174,12 +2181,7 @@ var morphXmlProtocol = (protocolOptions) => {
2174
2181
  }
2175
2182
  return {
2176
2183
  formatTools({ tools, toolSystemPromptTemplate }) {
2177
- const toolsForPrompt = (tools || []).map((tool) => ({
2178
- name: tool.name,
2179
- description: tool.description,
2180
- parameters: (0, import_rxml2.unwrapJsonSchema)(tool.inputSchema)
2181
- }));
2182
- return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
2184
+ return toolSystemPromptTemplate(tools || []);
2183
2185
  },
2184
2186
  formatToolCall(toolCall) {
2185
2187
  let args = {};
@@ -2188,26 +2190,11 @@ var morphXmlProtocol = (protocolOptions) => {
2188
2190
  } catch (e) {
2189
2191
  args = toolCall.input;
2190
2192
  }
2191
- return (0, import_rxml2.stringify)(toolCall.toolName, args, {
2193
+ return stringify2(toolCall.toolName, args, {
2192
2194
  suppressEmptyNode: false,
2193
2195
  format: false
2194
2196
  });
2195
2197
  },
2196
- formatToolResponse(toolResult) {
2197
- let result = toolResult.result;
2198
- if (result && typeof result === "object" && "type" in result && result.type === "json" && "value" in result) {
2199
- result = result.value;
2200
- }
2201
- const xml = (0, import_rxml2.stringify)(
2202
- "tool_response",
2203
- {
2204
- tool_name: toolResult.toolName,
2205
- result
2206
- },
2207
- { declaration: false }
2208
- );
2209
- return xml;
2210
- },
2211
2198
  parseGeneratedText({ text, tools, options }) {
2212
2199
  const toolNames = tools.map((t) => t.name).filter(Boolean);
2213
2200
  if (toolNames.length === 0) {
@@ -2276,7 +2263,7 @@ var morphXmlProtocol = (protocolOptions) => {
2276
2263
  );
2277
2264
  return new TransformStream({
2278
2265
  transform(chunk, controller) {
2279
- var _a2, _b2;
2266
+ var _a2;
2280
2267
  if (chunk.type !== "text-delta") {
2281
2268
  if (buffer) {
2282
2269
  flushText(controller, buffer);
@@ -2285,7 +2272,7 @@ var morphXmlProtocol = (protocolOptions) => {
2285
2272
  controller.enqueue(chunk);
2286
2273
  return;
2287
2274
  }
2288
- const textContent = (_b2 = (_a2 = chunk.textDelta) != null ? _a2 : chunk.delta) != null ? _b2 : "";
2275
+ const textContent = (_a2 = chunk.delta) != null ? _a2 : "";
2289
2276
  buffer += textContent;
2290
2277
  processBuffer(controller);
2291
2278
  },
@@ -2320,9 +2307,8 @@ var morphXmlProtocol = (protocolOptions) => {
2320
2307
  };
2321
2308
  };
2322
2309
 
2323
- // src/core/protocols/yaml-xml-protocol.ts
2324
- var import_rxml3 = require("@ai-sdk-tool/rxml");
2325
- var import_yaml = __toESM(require("yaml"), 1);
2310
+ // src/core/protocols/yaml-protocol.ts
2311
+ import YAML from "yaml";
2326
2312
  var NAME_CHAR_RE3 = /[A-Za-z0-9_:-]/;
2327
2313
  var WHITESPACE_REGEX4 = /\s/;
2328
2314
  var LEADING_WHITESPACE_RE = /^(\s*)/;
@@ -2469,7 +2455,7 @@ function parseYamlContent(yamlContent, options) {
2469
2455
  normalized = lines.map((line) => line.slice(minIndent)).join("\n");
2470
2456
  }
2471
2457
  try {
2472
- const doc = import_yaml.default.parseDocument(normalized);
2458
+ const doc = YAML.parseDocument(normalized);
2473
2459
  if (doc.errors && doc.errors.length > 0) {
2474
2460
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "YAML parse error", {
2475
2461
  errors: doc.errors.map((e) => e.message)
@@ -2542,7 +2528,6 @@ function createFlushTextHandler2(getCurrentTextId, setCurrentTextId, getHasEmitt
2542
2528
  controller.enqueue({
2543
2529
  type: "text-delta",
2544
2530
  id: getCurrentTextId(),
2545
- textDelta: content,
2546
2531
  delta: content
2547
2532
  });
2548
2533
  }
@@ -2590,15 +2575,10 @@ function findEarliestToolTag2(buffer, toolNames) {
2590
2575
  tagLength: bestTagLength
2591
2576
  };
2592
2577
  }
2593
- var yamlXmlProtocol = (_protocolOptions) => {
2578
+ var yamlProtocol = (_protocolOptions) => {
2594
2579
  return {
2595
2580
  formatTools({ tools, toolSystemPromptTemplate }) {
2596
- const toolsForPrompt = (tools || []).map((tool) => ({
2597
- name: tool.name,
2598
- description: tool.description,
2599
- parameters: (0, import_rxml3.unwrapJsonSchema)(tool.inputSchema)
2600
- }));
2601
- return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
2581
+ return toolSystemPromptTemplate(tools || []);
2602
2582
  },
2603
2583
  formatToolCall(toolCall) {
2604
2584
  let args = {};
@@ -2607,25 +2587,10 @@ var yamlXmlProtocol = (_protocolOptions) => {
2607
2587
  } catch (e) {
2608
2588
  args = { value: toolCall.input };
2609
2589
  }
2610
- const yamlContent = import_yaml.default.stringify(args);
2590
+ const yamlContent = YAML.stringify(args);
2611
2591
  return `<${toolCall.toolName}>
2612
2592
  ${yamlContent}</${toolCall.toolName}>`;
2613
2593
  },
2614
- formatToolResponse(toolResult) {
2615
- let result = toolResult.result;
2616
- if (result && typeof result === "object" && "type" in result && result.type === "json" && "value" in result) {
2617
- result = result.value;
2618
- }
2619
- const xml = (0, import_rxml3.stringify)(
2620
- "tool_response",
2621
- {
2622
- tool_name: toolResult.toolName,
2623
- result
2624
- },
2625
- { declaration: false }
2626
- );
2627
- return xml;
2628
- },
2629
2594
  parseGeneratedText({ text, tools, options }) {
2630
2595
  const toolNames = tools.map((t) => t.name).filter(Boolean);
2631
2596
  if (toolNames.length === 0) {
@@ -2739,7 +2704,7 @@ ${yamlContent}</${toolCall.toolName}>`;
2739
2704
  };
2740
2705
  return new TransformStream({
2741
2706
  transform(chunk, controller) {
2742
- var _a, _b;
2707
+ var _a;
2743
2708
  if (chunk.type !== "text-delta") {
2744
2709
  if (buffer) {
2745
2710
  flushText(controller, buffer);
@@ -2748,7 +2713,7 @@ ${yamlContent}</${toolCall.toolName}>`;
2748
2713
  controller.enqueue(chunk);
2749
2714
  return;
2750
2715
  }
2751
- const textContent = (_b = (_a = chunk.textDelta) != null ? _a : chunk.delta) != null ? _b : "";
2716
+ const textContent = (_a = chunk.delta) != null ? _a : "";
2752
2717
  buffer += textContent;
2753
2718
  processBuffer(controller);
2754
2719
  },
@@ -2784,48 +2749,62 @@ ${yamlContent}</${toolCall.toolName}>`;
2784
2749
  }
2785
2750
  };
2786
2751
  };
2787
- function orchestratorSystemPromptTemplate(tools, includeMultilineExample = true) {
2788
- const multilineExample = includeMultilineExample ? `
2789
-
2790
- For multiline values, use YAML's literal block syntax:
2791
- <write_file>
2792
- file_path: /tmp/example.txt
2793
- contents: |
2794
- First line
2795
- Second line
2796
- Third line
2797
- </write_file>` : "";
2798
- return `# Tools
2799
-
2800
- You may call one or more functions to assist with the user query.
2801
-
2802
- You are provided with function signatures within <tools></tools> XML tags:
2803
- <tools>${tools}</tools>
2804
-
2805
- # Format
2806
-
2807
- Use exactly one XML element whose tag name is the function name.
2808
- Inside the XML element, specify parameters using YAML syntax (key: value pairs).
2809
-
2810
- # Example
2811
- <get_weather>
2812
- location: New York
2813
- unit: celsius
2814
- </get_weather>${multilineExample}
2815
-
2816
- # Rules
2817
- - Parameter names and values must follow the schema exactly.
2818
- - Use proper YAML syntax for values (strings, numbers, booleans, arrays, objects).
2819
- - Each required parameter must appear once.
2820
- - Do not add functions or parameters not in the schema.
2821
- - After calling a tool, you will receive a response. Use this result to answer the user.
2822
- - Do NOT ask clarifying questions. Use reasonable defaults for optional parameters.
2823
- - If a task requires multiple function calls, make ALL of them at once.`;
2824
- }
2825
2752
 
2826
- // src/core/protocols/tool-call-protocol.ts
2827
- function isProtocolFactory(protocol) {
2828
- return typeof protocol === "function";
2753
+ // src/core/utils/dynamic-tool-schema.ts
2754
+ function createDynamicIfThenElseSchema(tools) {
2755
+ let currentSchema = {};
2756
+ const toolNames = [];
2757
+ for (let i = tools.length - 1; i >= 0; i -= 1) {
2758
+ const tool = tools[i];
2759
+ if (tool.type === "provider") {
2760
+ throw new Error(
2761
+ "Provider tools are not supported by this middleware. Please use function tools."
2762
+ );
2763
+ }
2764
+ toolNames.unshift(tool.name);
2765
+ const toolCondition = {
2766
+ if: {
2767
+ properties: {
2768
+ name: {
2769
+ const: tool.name
2770
+ }
2771
+ },
2772
+ required: ["name"]
2773
+ },
2774
+ // biome-ignore lint/suspicious/noThenProperty: JSON Schema uses 'then' as a keyword
2775
+ then: {
2776
+ properties: {
2777
+ name: {
2778
+ const: tool.name
2779
+ },
2780
+ arguments: tool.inputSchema
2781
+ },
2782
+ required: ["name", "arguments"]
2783
+ }
2784
+ };
2785
+ if (Object.keys(currentSchema).length > 0) {
2786
+ toolCondition.else = currentSchema;
2787
+ }
2788
+ currentSchema = toolCondition;
2789
+ }
2790
+ return {
2791
+ type: "object",
2792
+ // Explicitly specify type as "object"
2793
+ properties: {
2794
+ name: {
2795
+ type: "string",
2796
+ description: "Name of the tool to call",
2797
+ enum: toolNames
2798
+ },
2799
+ arguments: {
2800
+ type: "object",
2801
+ // By default, arguments is also specified as object type
2802
+ description: "Argument object to be passed to the tool"
2803
+ }
2804
+ },
2805
+ required: ["name", "arguments"],
2806
+ ...currentSchema
2807
+ };
2829
2808
  }
2830
2809
 
2831
2810
  // src/core/utils/on-error.ts
@@ -2861,15 +2840,31 @@ function decodeOriginalTools(originalTools) {
2861
2840
  })
2862
2841
  );
2863
2842
  }
2843
+ function extractToolNamesFromOriginalTools(originalTools) {
2844
+ return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
2845
+ }
2864
2846
  function isToolChoiceActive(params) {
2865
2847
  var _a, _b, _c;
2866
2848
  const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
2867
2849
  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"));
2868
2850
  }
2869
2851
 
2870
- // src/v6/generate-handler.ts
2871
- var import_provider_utils = require("@ai-sdk/provider-utils");
2872
- var import_rxml4 = require("@ai-sdk-tool/rxml");
2852
+ // src/core/utils/type-guards.ts
2853
+ function isToolCallContent(content) {
2854
+ return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
2855
+ (typeof content.input === "string" || typeof content.input === "object");
2856
+ }
2857
+ function isToolResultPart(content) {
2858
+ const c = content;
2859
+ return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
2860
+ }
2861
+ function hasInputProperty(obj) {
2862
+ return typeof obj === "object" && obj !== null && "input" in obj;
2863
+ }
2864
+
2865
+ // src/generate-handler.ts
2866
+ import { generateId as generateId2 } from "@ai-sdk/provider-utils";
2867
+ import { coerceBySchema } from "@ai-sdk-tool/rxml";
2873
2868
  function parseToolChoiceJson(text, providerOptions) {
2874
2869
  var _a;
2875
2870
  try {
@@ -2913,7 +2908,7 @@ async function handleToolChoice(doGenerate, params) {
2913
2908
  }
2914
2909
  const toolCall = {
2915
2910
  type: "tool-call",
2916
- toolCallId: (0, import_provider_utils.generateId)(),
2911
+ toolCallId: generateId2(),
2917
2912
  toolName: parsed.name || "unknown",
2918
2913
  input: JSON.stringify(parsed.arguments || {})
2919
2914
  };
@@ -3032,80 +3027,207 @@ function fixToolCallWithSchema(part, tools) {
3032
3027
  args = tc.input;
3033
3028
  }
3034
3029
  const schema = (_a = tools.find((t) => t.name === tc.toolName)) == null ? void 0 : _a.inputSchema;
3035
- const coerced = (0, import_rxml4.coerceBySchema)(args, schema);
3030
+ const coerced = coerceBySchema(args, schema);
3036
3031
  return {
3037
3032
  ...part,
3038
3033
  input: JSON.stringify(coerced != null ? coerced : {})
3039
3034
  };
3040
3035
  }
3041
3036
 
3042
- // src/v6/stream-handler.ts
3043
- var import_provider_utils2 = require("@ai-sdk/provider-utils");
3044
- function mapCorePartToV3(part) {
3045
- switch (part.type) {
3046
- case "text-delta":
3047
- return {
3048
- type: "text-delta",
3049
- id: part.id || (0, import_provider_utils2.generateId)(),
3050
- delta: part.textDelta
3051
- };
3052
- case "tool-call":
3053
- return {
3054
- type: "tool-call",
3055
- toolCallId: part.toolCallId,
3056
- toolName: part.toolName,
3057
- input: part.input
3058
- };
3059
- case "tool-call-delta":
3060
- return {
3061
- type: "tool-call-delta",
3062
- toolCallId: part.toolCallId,
3063
- toolName: part.toolName,
3064
- argsTextDelta: part.argsTextDelta
3065
- };
3066
- case "finish":
3067
- return {
3068
- type: "finish",
3069
- finishReason: part.finishReason,
3070
- usage: part.usage
3071
- };
3072
- case "error":
3073
- return {
3074
- type: "error",
3075
- error: part.error
3076
- };
3077
- default:
3078
- return part;
3037
+ // src/core/prompts/hermes-system-prompt.ts
3038
+ function hermesSystemPromptTemplate(tools) {
3039
+ const toolsJson = JSON.stringify(tools);
3040
+ return `You are a function calling AI model.
3041
+ You are provided with function signatures within <tools></tools> XML tags.
3042
+ You may call one or more functions to assist with the user query.
3043
+ Don't make assumptions about what values to plug into functions.
3044
+ Here are the available tools: <tools>${toolsJson}</tools>
3045
+ Use the following pydantic model json schema for each tool call you will make: {"title": "FunctionCall", "type": "object", "properties": {"arguments": {"title": "Arguments", "type": "object"}, "name": {"title": "Name", "type": "string"}}, "required": ["arguments", "name"]}
3046
+ For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:
3047
+ <tool_call>
3048
+ {"name": "<function-name>", "arguments": <args-dict>}
3049
+ </tool_call>`;
3050
+ }
3051
+
3052
+ // src/core/prompts/tool-response.ts
3053
+ function unwrapToolResult(result) {
3054
+ var _a, _b;
3055
+ switch (result.type) {
3056
+ case "text":
3057
+ return (_a = result.value) != null ? _a : "";
3058
+ case "json":
3059
+ return result.value;
3060
+ case "execution-denied": {
3061
+ const reason = result.reason;
3062
+ return reason ? `[Execution Denied: ${reason}]` : "[Execution Denied]";
3063
+ }
3064
+ case "error-text":
3065
+ return `[Error: ${(_b = result.value) != null ? _b : ""}]`;
3066
+ case "error-json":
3067
+ return `[Error: ${JSON.stringify(result.value)}]`;
3068
+ case "content": {
3069
+ return result.value.map((part) => {
3070
+ var _a2;
3071
+ const contentPart = part;
3072
+ switch (contentPart.type) {
3073
+ case "text":
3074
+ return (_a2 = contentPart.text) != null ? _a2 : "";
3075
+ case "image-data":
3076
+ return `[Image: ${contentPart.mediaType}]`;
3077
+ case "image-url":
3078
+ return `[Image URL: ${contentPart.url}]`;
3079
+ case "image-file-id": {
3080
+ const fileId = contentPart.fileId;
3081
+ const displayId = typeof fileId === "string" ? fileId : JSON.stringify(fileId);
3082
+ return `[Image ID: ${displayId}]`;
3083
+ }
3084
+ case "file-data": {
3085
+ const filePart = contentPart;
3086
+ if (filePart.filename) {
3087
+ return `[File: ${filePart.filename} (${filePart.mediaType})]`;
3088
+ }
3089
+ return `[File: ${filePart.mediaType}]`;
3090
+ }
3091
+ case "file-url":
3092
+ return `[File URL: ${contentPart.url}]`;
3093
+ case "file-id": {
3094
+ const fileId = contentPart.fileId;
3095
+ const displayId = typeof fileId === "string" ? fileId : JSON.stringify(fileId);
3096
+ return `[File ID: ${displayId}]`;
3097
+ }
3098
+ case "media":
3099
+ return `[Media: ${contentPart.mediaType}]`;
3100
+ case "custom":
3101
+ return "[Custom content]";
3102
+ default:
3103
+ return "[Unknown content]";
3104
+ }
3105
+ }).join("\n");
3106
+ }
3107
+ default: {
3108
+ const _exhaustive = result;
3109
+ return _exhaustive;
3110
+ }
3079
3111
  }
3080
3112
  }
3081
- function mapV3PartToCore(part) {
3082
- const p = part;
3083
- switch (p.type) {
3084
- case "text-delta":
3085
- return {
3086
- type: "text-delta",
3087
- id: p.id,
3088
- textDelta: p.delta || p.textDelta || ""
3089
- };
3090
- case "tool-call":
3091
- return {
3092
- type: "tool-call",
3093
- toolCallId: p.toolCallId,
3094
- toolName: p.toolName,
3095
- input: p.input
3096
- };
3097
- case "finish": {
3098
- const finishReason = p.finishReason;
3099
- return {
3100
- type: "finish",
3101
- finishReason: (typeof finishReason === "object" ? finishReason == null ? void 0 : finishReason.unified : finishReason) || "stop",
3102
- usage: p.usage
3103
- };
3113
+ function formatToolResponseAsJsonInXml(toolResult) {
3114
+ const unwrappedResult = unwrapToolResult(toolResult.output);
3115
+ return `<tool_response>${JSON.stringify({
3116
+ toolName: toolResult.toolName,
3117
+ result: unwrappedResult
3118
+ })}</tool_response>`;
3119
+ }
3120
+ function formatToolResponseAsXml(toolResult) {
3121
+ const unwrappedResult = unwrapToolResult(toolResult.output);
3122
+ const toolNameXml = `<tool_name>${toolResult.toolName}</tool_name>`;
3123
+ const resultLines = formatXmlNode("result", unwrappedResult, 1);
3124
+ return [
3125
+ "<tool_response>",
3126
+ ` ${toolNameXml}`,
3127
+ ...resultLines,
3128
+ "</tool_response>"
3129
+ ].join("\n");
3130
+ }
3131
+ function formatXmlNode(tagName, value, depth) {
3132
+ const indent = " ".repeat(depth);
3133
+ if (value === null || value === void 0) {
3134
+ return [`${indent}<${tagName}></${tagName}>`];
3135
+ }
3136
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3137
+ return [`${indent}<${tagName}>${String(value)}</${tagName}>`];
3138
+ }
3139
+ if (Array.isArray(value)) {
3140
+ if (value.length === 0) {
3141
+ return [`${indent}<${tagName}></${tagName}>`];
3104
3142
  }
3105
- default:
3106
- return p;
3143
+ const lines2 = [`${indent}<${tagName}>`];
3144
+ for (const item of value) {
3145
+ lines2.push(...formatXmlNode("item", item, depth + 1));
3146
+ }
3147
+ lines2.push(`${indent}</${tagName}>`);
3148
+ return lines2;
3149
+ }
3150
+ const entries = Object.entries(value);
3151
+ if (entries.length === 0) {
3152
+ return [`${indent}<${tagName}></${tagName}>`];
3107
3153
  }
3154
+ const lines = [`${indent}<${tagName}>`];
3155
+ for (const [key, entryValue] of entries) {
3156
+ lines.push(...formatXmlNode(key, entryValue, depth + 1));
3157
+ }
3158
+ lines.push(`${indent}</${tagName}>`);
3159
+ return lines;
3160
+ }
3161
+
3162
+ // src/core/prompts/xml-system-prompt.ts
3163
+ function xmlSystemPromptTemplate(tools) {
3164
+ const toolsJson = JSON.stringify(tools);
3165
+ return `# Tools
3166
+
3167
+ You may call one or more functions to assist with the user query.
3168
+
3169
+ You are provided with function signatures within <tools></tools> XML tags:
3170
+ <tools>${toolsJson}</tools>
3171
+
3172
+ # Rules
3173
+ - Use exactly one XML element whose tag name is the function name.
3174
+ - Put each parameter as a child element.
3175
+ - Values must follow the schema exactly (numbers, arrays, objects, enums \u2192 copy as-is).
3176
+ - Do not add or remove functions or parameters.
3177
+ - Each required parameter must appear once.
3178
+ - Output nothing before or after the function call.
3179
+ - After calling a tool, you will receive a response in the format: <tool_response><tool_name>NAME</tool_name><result>RESULT</result></tool_response>. Use this result to answer the user.
3180
+
3181
+ # Example
3182
+ <get_weather>
3183
+ <location>New York</location>
3184
+ <unit>celsius</unit>
3185
+ </get_weather>`;
3186
+ }
3187
+
3188
+ // src/core/prompts/yaml-system-prompt.ts
3189
+ function yamlSystemPromptTemplate(tools, includeMultilineExample = true) {
3190
+ const toolsJson = JSON.stringify(tools);
3191
+ const multilineExample = includeMultilineExample ? `
3192
+
3193
+ For multiline values, use YAML's literal block syntax:
3194
+ <write_file>
3195
+ file_path: /tmp/example.txt
3196
+ contents: |
3197
+ First line
3198
+ Second line
3199
+ Third line
3200
+ </write_file>` : "";
3201
+ return `# Tools
3202
+
3203
+ You may call one or more functions to assist with the user query.
3204
+
3205
+ You are provided with function signatures within <tools></tools> XML tags:
3206
+ <tools>${toolsJson}</tools>
3207
+
3208
+ # Format
3209
+
3210
+ Use exactly one XML element whose tag name is the function name.
3211
+ Inside the XML element, specify parameters using YAML syntax (key: value pairs).
3212
+
3213
+ # Example
3214
+ <get_weather>
3215
+ location: New York
3216
+ unit: celsius
3217
+ </get_weather>${multilineExample}
3218
+
3219
+ # Rules
3220
+ - Parameter names and values must follow the schema exactly.
3221
+ - Use proper YAML syntax for values (strings, numbers, booleans, arrays, objects).
3222
+ - Each required parameter must appear once.
3223
+ - Do not add functions or parameters not in the schema.
3224
+ - After calling a tool, you will receive a response. Use this result to answer the user.
3225
+ - Do NOT ask clarifying questions. Use reasonable defaults for optional parameters.
3226
+ - If a task requires multiple function calls, make ALL of them at once.`;
3108
3227
  }
3228
+
3229
+ // src/stream-handler.ts
3230
+ import { generateId as generateId3 } from "@ai-sdk/provider-utils";
3109
3231
  async function wrapStream({
3110
3232
  protocol,
3111
3233
  doStream,
@@ -3129,23 +3251,24 @@ async function wrapStream({
3129
3251
  ...((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) || {}
3130
3252
  };
3131
3253
  const coreStream = stream.pipeThrough(
3132
- new TransformStream({
3133
- transform(part, controller) {
3134
- if (debugLevel === "stream") {
3135
- logRawChunk(part);
3254
+ new TransformStream(
3255
+ {
3256
+ transform(part, controller) {
3257
+ if (debugLevel === "stream") {
3258
+ logRawChunk(part);
3259
+ }
3260
+ controller.enqueue(part);
3136
3261
  }
3137
- controller.enqueue(mapV3PartToCore(part));
3138
3262
  }
3139
- })
3263
+ )
3140
3264
  ).pipeThrough(protocol.createStreamParser({ tools, options }));
3141
3265
  const v3Stream = coreStream.pipeThrough(
3142
3266
  new TransformStream({
3143
3267
  transform(part, controller) {
3144
- const v3Part = mapCorePartToV3(part);
3145
3268
  if (debugLevel === "stream") {
3146
- logParsedChunk(v3Part);
3269
+ logParsedChunk(part);
3147
3270
  }
3148
- controller.enqueue(v3Part);
3271
+ controller.enqueue(part);
3149
3272
  }
3150
3273
  })
3151
3274
  );
@@ -3180,7 +3303,7 @@ async function toolChoiceStream({
3180
3303
  start(controller) {
3181
3304
  controller.enqueue({
3182
3305
  type: "tool-call",
3183
- toolCallId: (0, import_provider_utils2.generateId)(),
3306
+ toolCallId: generateId3(),
3184
3307
  toolName: toolJson.name || "unknown",
3185
3308
  input: JSON.stringify(toolJson.arguments || {})
3186
3309
  });
@@ -3202,70 +3325,7 @@ async function toolChoiceStream({
3202
3325
  };
3203
3326
  }
3204
3327
 
3205
- // src/core/utils/dynamic-tool-schema.ts
3206
- function createDynamicIfThenElseSchema(tools) {
3207
- let currentSchema = {};
3208
- const toolNames = [];
3209
- for (let i = tools.length - 1; i >= 0; i -= 1) {
3210
- const tool = tools[i];
3211
- if (tool.type === "provider") {
3212
- throw new Error(
3213
- "Provider tools are not supported by this middleware. Please use function tools."
3214
- );
3215
- }
3216
- toolNames.unshift(tool.name);
3217
- const toolCondition = {
3218
- if: {
3219
- properties: {
3220
- name: {
3221
- const: tool.name
3222
- }
3223
- },
3224
- required: ["name"]
3225
- },
3226
- // biome-ignore lint/suspicious/noThenProperty: JSON Schema uses 'then' as a keyword
3227
- then: {
3228
- properties: {
3229
- name: {
3230
- const: tool.name
3231
- },
3232
- arguments: tool.inputSchema
3233
- },
3234
- required: ["name", "arguments"]
3235
- }
3236
- };
3237
- if (Object.keys(currentSchema).length > 0) {
3238
- toolCondition.else = currentSchema;
3239
- }
3240
- currentSchema = toolCondition;
3241
- }
3242
- return {
3243
- type: "object",
3244
- // Explicitly specify type as "object"
3245
- properties: {
3246
- name: {
3247
- type: "string",
3248
- description: "Name of the tool to call",
3249
- enum: toolNames
3250
- },
3251
- arguments: {
3252
- type: "object",
3253
- // By default, arguments is also specified as object type
3254
- description: "Argument object to be passed to the tool"
3255
- }
3256
- },
3257
- required: ["name", "arguments"],
3258
- ...currentSchema
3259
- };
3260
- }
3261
-
3262
- // src/core/utils/type-guards.ts
3263
- function isToolCallContent(content) {
3264
- return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
3265
- (typeof content.input === "string" || typeof content.input === "object");
3266
- }
3267
-
3268
- // src/v6/transform-handler.ts
3328
+ // src/transform-handler.ts
3269
3329
  function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
3270
3330
  const systemIndex = processedPrompt.findIndex((m) => m.role === "system");
3271
3331
  if (systemIndex !== -1) {
@@ -3408,10 +3468,11 @@ function transformParams({
3408
3468
  params,
3409
3469
  protocol,
3410
3470
  toolSystemPromptTemplate,
3471
+ toolResponsePromptTemplate,
3411
3472
  placement = "first"
3412
3473
  }) {
3413
- var _a, _b, _c, _d, _e;
3414
- const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
3474
+ var _a, _b, _c, _d;
3475
+ const resolvedProtocol = isTCMProtocolFactory(protocol) ? protocol() : protocol;
3415
3476
  const functionTools = ((_a = params.tools) != null ? _a : []).filter(
3416
3477
  (t) => t.type === "function"
3417
3478
  );
@@ -3419,9 +3480,18 @@ function transformParams({
3419
3480
  tools: functionTools,
3420
3481
  toolSystemPromptTemplate
3421
3482
  });
3483
+ let normalizedPrompt;
3484
+ if (Array.isArray(params.prompt)) {
3485
+ normalizedPrompt = params.prompt;
3486
+ } else if (params.prompt) {
3487
+ normalizedPrompt = [params.prompt];
3488
+ } else {
3489
+ normalizedPrompt = [];
3490
+ }
3422
3491
  const processedPrompt = convertToolPrompt(
3423
- (_b = params.prompt) != null ? _b : [],
3492
+ normalizedPrompt,
3424
3493
  resolvedProtocol,
3494
+ toolResponsePromptTemplate,
3425
3495
  extractOnErrorOption(params.providerOptions)
3426
3496
  );
3427
3497
  const finalPrompt = buildFinalPrompt(
@@ -3434,15 +3504,15 @@ function transformParams({
3434
3504
  finalPrompt,
3435
3505
  functionTools
3436
3506
  );
3437
- if (((_c = params.toolChoice) == null ? void 0 : _c.type) === "none") {
3507
+ if (((_b = params.toolChoice) == null ? void 0 : _b.type) === "none") {
3438
3508
  throw new Error(
3439
3509
  "The 'none' toolChoice type is not supported by this middleware. Please use 'auto', 'required', or specify a tool name."
3440
3510
  );
3441
3511
  }
3442
- if (((_d = params.toolChoice) == null ? void 0 : _d.type) === "tool") {
3512
+ if (((_c = params.toolChoice) == null ? void 0 : _c.type) === "tool") {
3443
3513
  return handleToolChoiceTool(params, baseReturnParams);
3444
3514
  }
3445
- if (((_e = params.toolChoice) == null ? void 0 : _e.type) === "required") {
3515
+ if (((_d = params.toolChoice) == null ? void 0 : _d.type) === "required") {
3446
3516
  return handleToolChoiceRequired(params, baseReturnParams, functionTools);
3447
3517
  }
3448
3518
  return baseReturnParams;
@@ -3481,25 +3551,28 @@ function processAssistantContent(content, resolvedProtocol, providerOptions) {
3481
3551
  }
3482
3552
  ] : newContent;
3483
3553
  }
3484
- function processToolMessage(content, resolvedProtocol) {
3554
+ function formatApprovalResponse(part) {
3555
+ const status = part.approved ? "Approved" : "Denied";
3556
+ const reason = part.reason ? `: ${part.reason}` : "";
3557
+ return `[Tool Approval ${status}${reason}]`;
3558
+ }
3559
+ function processToolMessage(toolResults, approvalResponses, toolResponsePromptTemplate) {
3560
+ const resultTexts = toolResults.map((toolResult) => {
3561
+ return toolResponsePromptTemplate(toolResult);
3562
+ });
3563
+ const approvalTexts = approvalResponses.map(formatApprovalResponse);
3564
+ const allTexts = [...resultTexts, ...approvalTexts];
3485
3565
  return {
3486
3566
  role: "user",
3487
3567
  content: [
3488
3568
  {
3489
3569
  type: "text",
3490
- text: content.map((toolResult) => {
3491
- var _a, _b;
3492
- const tr = toolResult;
3493
- return resolvedProtocol.formatToolResponse({
3494
- ...toolResult,
3495
- result: (_b = (_a = tr.result) != null ? _a : tr.content) != null ? _b : tr.output
3496
- });
3497
- }).join("\n")
3570
+ text: allTexts.join("\n")
3498
3571
  }
3499
3572
  ]
3500
3573
  };
3501
3574
  }
3502
- function processMessage(message, resolvedProtocol, providerOptions) {
3575
+ function processMessage(message, resolvedProtocol, providerOptions, toolResponsePromptTemplate) {
3503
3576
  if (message.role === "assistant") {
3504
3577
  const condensedContent = processAssistantContent(
3505
3578
  message.content,
@@ -3512,10 +3585,23 @@ function processMessage(message, resolvedProtocol, providerOptions) {
3512
3585
  };
3513
3586
  }
3514
3587
  if (message.role === "tool") {
3515
- const toolResultParts = message.content.filter(
3588
+ const toolContent = message.content;
3589
+ const toolResultParts = toolContent.filter(
3516
3590
  (part) => part.type === "tool-result"
3517
3591
  );
3518
- return processToolMessage(toolResultParts, resolvedProtocol);
3592
+ const approvalResponseParts = toolContent.filter(
3593
+ (part) => part.type === "tool-approval-response"
3594
+ );
3595
+ if (!toolResponsePromptTemplate) {
3596
+ throw new Error(
3597
+ 'toolResponsePromptTemplate is required when processing messages with role "tool". This parameter is optional for other roles but is required here so tool-result content can be converted into a prompt. Ensure your middleware or transform configuration passes a toolResponsePromptTemplate when tool message processing is enabled.'
3598
+ );
3599
+ }
3600
+ return processToolMessage(
3601
+ toolResultParts,
3602
+ approvalResponseParts,
3603
+ toolResponsePromptTemplate
3604
+ );
3519
3605
  }
3520
3606
  return message;
3521
3607
  }
@@ -3578,22 +3664,28 @@ ${currentContent}` }]
3578
3664
  }
3579
3665
  return processedPrompt;
3580
3666
  }
3581
- function convertToolPrompt(prompt, resolvedProtocol, providerOptions) {
3667
+ function convertToolPrompt(prompt, resolvedProtocol, toolResponsePromptTemplate, providerOptions) {
3582
3668
  let processedPrompt = prompt.map(
3583
- (message) => processMessage(message, resolvedProtocol, providerOptions)
3669
+ (message) => processMessage(
3670
+ message,
3671
+ resolvedProtocol,
3672
+ providerOptions,
3673
+ toolResponsePromptTemplate
3674
+ )
3584
3675
  );
3585
3676
  processedPrompt = condenseTextContent(processedPrompt);
3586
3677
  processedPrompt = mergeConsecutiveUserMessages(processedPrompt);
3587
3678
  return processedPrompt;
3588
3679
  }
3589
3680
 
3590
- // src/v6/tool-call-middleware.ts
3681
+ // src/tool-call-middleware.ts
3591
3682
  function createToolMiddleware({
3592
3683
  protocol,
3593
3684
  toolSystemPromptTemplate,
3685
+ toolResponsePromptTemplate,
3594
3686
  placement = "last"
3595
3687
  }) {
3596
- const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
3688
+ const resolvedProtocol = isTCMProtocolFactory(protocol) ? protocol() : protocol;
3597
3689
  return {
3598
3690
  specificationVersion: "v3",
3599
3691
  wrapStream: ({ doStream, doGenerate, params }) => {
@@ -3618,83 +3710,72 @@ function createToolMiddleware({
3618
3710
  transformParams: async ({ params }) => transformParams({
3619
3711
  protocol: resolvedProtocol,
3620
3712
  toolSystemPromptTemplate,
3713
+ toolResponsePromptTemplate,
3621
3714
  placement,
3622
3715
  params
3623
3716
  })
3624
3717
  };
3625
3718
  }
3626
3719
 
3627
- // src/v6/index.ts
3628
- var gemmaToolMiddleware = createToolMiddleware({
3629
- protocol: jsonMixProtocol({
3630
- toolCallStart: "```tool_call\n",
3631
- toolCallEnd: "\n```",
3632
- toolResponseStart: "```tool_response\n",
3633
- toolResponseEnd: "\n```"
3634
- }),
3635
- toolSystemPromptTemplate(tools) {
3636
- return `You have access to functions. If you decide to invoke any of the function(s),
3637
- you MUST put it in the format of markdown code fence block with the language name of tool_call , e.g.
3638
- \`\`\`tool_call
3639
- {'name': <function-name>, 'arguments': <args-dict>}
3640
- \`\`\`
3641
- You SHOULD NOT include any other text in the response if you call a function
3642
- ${tools}`;
3643
- }
3644
- });
3720
+ // src/preconfigured-middleware.ts
3645
3721
  var hermesToolMiddleware = createToolMiddleware({
3646
- protocol: jsonMixProtocol,
3647
- toolSystemPromptTemplate(tools) {
3648
- return `You are a function calling AI model.
3649
- You are provided with function signatures within <tools></tools> XML tags.
3650
- You may call one or more functions to assist with the user query.
3651
- Don't make assumptions about what values to plug into functions.
3652
- Here are the available tools: <tools>${tools}</tools>
3653
- Use the following pydantic model json schema for each tool call you will make: {"title": "FunctionCall", "type": "object", "properties": {"arguments": {"title": "Arguments", "type": "object"}, "name": {"title": "Name", "type": "string"}}, "required": ["arguments", "name"]}
3654
- For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:
3655
- <tool_call>
3656
- {"name": "<function-name>", "arguments": <args-dict>}
3657
- </tool_call>`;
3658
- }
3722
+ protocol: jsonProtocol({}),
3723
+ toolSystemPromptTemplate: hermesSystemPromptTemplate,
3724
+ toolResponsePromptTemplate: formatToolResponseAsJsonInXml
3659
3725
  });
3660
- var morphXmlToolMiddleware = createToolMiddleware({
3661
- protocol: morphXmlProtocol,
3662
- placement: "first",
3663
- toolSystemPromptTemplate(tools) {
3664
- return `# Tools
3665
-
3666
- You may call one or more functions to assist with the user query.
3667
-
3668
- You are provided with function signatures within <tools></tools> XML tags:
3669
- <tools>${tools}</tools>
3670
-
3671
- # Rules
3672
- - Use exactly one XML element whose tag name is the function name.
3673
- - Put each parameter as a child element.
3674
- - Values must follow the schema exactly (numbers, arrays, objects, enums \u2192 copy as-is).
3675
- - Do not add or remove functions or parameters.
3676
- - Each required parameter must appear once.
3677
- - Output nothing before or after the function call.
3678
- - After calling a tool, you will receive a response in the format: <tool_response><tool_name>NAME</tool_name><result>RESULT</result></tool_response>. Use this result to answer the user.
3679
-
3680
- # Example
3681
- <get_weather>
3682
- <location>New York</location>
3683
- <unit>celsius</unit>
3684
- </get_weather>`;
3685
- }
3726
+ var xmlToolMiddleware = createToolMiddleware({
3727
+ protocol: xmlProtocol({}),
3728
+ toolSystemPromptTemplate: xmlSystemPromptTemplate,
3729
+ toolResponsePromptTemplate: formatToolResponseAsXml
3686
3730
  });
3687
- var orchestratorToolMiddleware = createToolMiddleware({
3688
- protocol: yamlXmlProtocol(),
3689
- placement: "first",
3690
- toolSystemPromptTemplate: orchestratorSystemPromptTemplate
3731
+ var yamlToolMiddleware = createToolMiddleware({
3732
+ protocol: yamlProtocol({}),
3733
+ toolSystemPromptTemplate: yamlSystemPromptTemplate,
3734
+ toolResponsePromptTemplate: formatToolResponseAsXml
3691
3735
  });
3692
- // Annotate the CommonJS export names for ESM import in node:
3693
- 0 && (module.exports = {
3736
+
3737
+ export {
3738
+ applyHeuristicPipeline,
3739
+ createIntermediateCall,
3740
+ mergePipelineConfigs,
3741
+ normalizeCloseTagsHeuristic,
3742
+ escapeInvalidLtHeuristic,
3743
+ balanceTagsHeuristic,
3744
+ dedupeShellStringTagsHeuristic,
3745
+ repairAgainstSchemaHeuristic,
3746
+ defaultPipelineConfig,
3747
+ getDebugLevel,
3748
+ logParseFailure,
3749
+ logRawChunk,
3750
+ logParsedChunk,
3751
+ logParsedSummary,
3752
+ getPotentialStartIndex,
3753
+ escapeRegExp2 as escapeRegExp,
3754
+ transform,
3755
+ parse2 as parse,
3756
+ stringify,
3757
+ jsonProtocol,
3758
+ isProtocolFactory,
3759
+ isTCMProtocolFactory,
3760
+ xmlProtocol,
3761
+ yamlProtocol,
3762
+ createDynamicIfThenElseSchema,
3763
+ extractOnErrorOption,
3764
+ originalToolsSchema,
3765
+ encodeOriginalTools,
3766
+ decodeOriginalTools,
3767
+ extractToolNamesFromOriginalTools,
3768
+ isToolChoiceActive,
3769
+ isToolCallContent,
3770
+ isToolResultPart,
3771
+ hasInputProperty,
3772
+ wrapGenerate,
3773
+ wrapStream,
3774
+ toolChoiceStream,
3775
+ transformParams,
3694
3776
  createToolMiddleware,
3695
- gemmaToolMiddleware,
3696
3777
  hermesToolMiddleware,
3697
- morphXmlToolMiddleware,
3698
- orchestratorToolMiddleware
3699
- });
3700
- //# sourceMappingURL=v6.cjs.map
3778
+ xmlToolMiddleware,
3779
+ yamlToolMiddleware
3780
+ };
3781
+ //# sourceMappingURL=chunk-JVQVEA3K.js.map