@ai-sdk-tool/parser 3.0.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1644 +1,1644 @@
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;
237
+ }
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("");
269
+ }
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;
276
+ }
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;
311
+ }
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;
313
334
  }
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
- };
335
+ function extractSchemaProperties(schema) {
336
+ const unwrapped = unwrapJsonSchema(schema);
337
+ if (!unwrapped || typeof unwrapped !== "object") {
338
+ return void 0;
339
+ }
340
+ return unwrapped.properties;
322
341
  }
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
- };
342
+ function shouldDeduplicateStringTags(schema) {
343
+ const props = extractSchemaProperties(schema);
344
+ if (!props) {
345
+ return false;
346
+ }
347
+ const commandRaw = props.command;
348
+ if (!commandRaw) {
349
+ return false;
350
+ }
351
+ const command = unwrapJsonSchema(commandRaw);
352
+ return (command == null ? void 0 : command.type) === "array";
335
353
  }
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
- };
354
+ function getStringPropertyNames(schema) {
355
+ const props = extractSchemaProperties(schema);
356
+ if (!props) {
357
+ return [];
358
+ }
359
+ const names = [];
360
+ for (const key of Object.keys(props)) {
361
+ const prop = unwrapJsonSchema(props[key]);
362
+ if ((prop == null ? void 0 : prop.type) === "string") {
363
+ names.push(key);
364
+ }
365
+ }
366
+ return names;
349
367
  }
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
- };
368
+ function escapeRegExp(s) {
369
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
358
370
  }
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]}`);
371
+ function dedupeSingleTag(xml, key) {
372
+ var _a, _b;
373
+ const escaped = escapeRegExp(key);
374
+ const re = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
375
+ const matches = Array.from(xml.matchAll(re));
376
+ if (matches.length <= 1) {
377
+ return xml;
373
378
  }
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
- };
379
+ const last = matches.at(-1);
380
+ let result = "";
381
+ let cursor = 0;
382
+ for (const m of matches) {
383
+ const idx = (_a = m.index) != null ? _a : 0;
384
+ result += xml.slice(cursor, idx);
385
+ if (last && idx === ((_b = last.index) != null ? _b : -1)) {
386
+ result += m[0];
387
+ }
388
+ cursor = idx + m[0].length;
389
+ }
390
+ result += xml.slice(cursor);
391
+ return result;
382
392
  }
383
- function makeTokenSpecs(relaxed) {
384
- function f(type) {
385
- return (m) => {
386
- return { type, match: m[0], value: void 0 };
387
- };
393
+ function repairParsedAgainstSchema(input, schema) {
394
+ if (!input || typeof input !== "object") {
395
+ return input;
388
396
  }
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
- ]);
397
+ const properties = extractSchemaProperties(schema);
398
+ if (!properties) {
399
+ return input;
427
400
  }
428
- return tokenSpecs;
401
+ applySchemaProps(input, properties);
402
+ return input;
429
403
  }
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;
404
+ function applySchemaProps(obj, properties) {
405
+ for (const key of Object.keys(obj)) {
406
+ const propSchema = properties[key];
407
+ if (!propSchema) {
408
+ continue;
409
+ }
410
+ const prop = unwrapJsonSchema(propSchema);
411
+ if ((prop == null ? void 0 : prop.type) === "array" && prop.items) {
412
+ const itemSchema = unwrapJsonSchema(prop.items);
413
+ obj[key] = coerceArrayItems(obj[key], itemSchema);
414
+ continue;
415
+ }
416
+ if ((prop == null ? void 0 : prop.type) === "object") {
417
+ const val = obj[key];
418
+ if (val && typeof val === "object") {
419
+ obj[key] = repairParsedAgainstSchema(val, prop);
420
+ }
437
421
  }
438
422
  }
439
- return;
440
423
  }
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
- }
459
- }
424
+ function coerceArrayItems(val, itemSchema) {
425
+ if (!Array.isArray(val)) {
426
+ return val;
427
+ }
428
+ return val.map((v) => coerceArrayItem(v, itemSchema));
429
+ }
430
+ function coerceArrayItem(v, itemSchema) {
431
+ const itemType = itemSchema == null ? void 0 : itemSchema.type;
432
+ if (typeof v === "string" && itemType === "object") {
433
+ const parsed = tryParseStringToSchemaObject(v, itemSchema);
434
+ if (parsed !== null) {
435
+ return parsed;
460
436
  }
461
- res.push(token);
462
- });
463
- return res;
437
+ const fallback = extractStepStatusFromString(
438
+ v.replace(MALFORMED_CLOSE_RE_G, "</$1>")
439
+ );
440
+ if (fallback) {
441
+ return fallback;
442
+ }
443
+ return v;
444
+ }
445
+ if (v && typeof v === "object" && itemType === "object") {
446
+ return repairParsedAgainstSchema(v, itemSchema);
447
+ }
448
+ return v;
464
449
  }
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 };
450
+ function tryParseStringToSchemaObject(xml, itemSchema) {
451
+ try {
452
+ const normalized = xml.replace(MALFORMED_CLOSE_RE_G, "</$1>");
453
+ const fixed = parse(normalized, itemSchema, { noChildNodes: [] });
454
+ return typeof fixed === "string" ? null : fixed;
455
+ } catch (e) {
456
+ return null;
472
457
  }
473
- return token;
474
458
  }
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}'`;
459
+ function extractStepStatusFromString(normXml) {
460
+ const stepMatch = normXml.match(STEP_TAG_RE);
461
+ const statusMatch = normXml.match(STATUS_TAG_RE);
462
+ if (stepMatch && statusMatch) {
463
+ return { step: stepMatch[1], status: statusMatch[1] };
485
464
  }
465
+ return null;
486
466
  }
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
- }
467
+
468
+ // src/core/utils/debug.ts
469
+ var LINE_SPLIT_REGEX = /\r?\n/;
470
+ function normalizeBooleanString(value) {
471
+ const normalized = value.trim().toLowerCase();
472
+ if (normalized === "1" || normalized === "true" || normalized === "yes") {
473
+ return true;
502
474
  }
503
- }
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
- }
475
+ if (normalized === "0" || normalized === "false" || normalized === "no") {
476
+ return false;
532
477
  }
478
+ return;
533
479
  }
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;
480
+ function getDebugLevel() {
481
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW || "off";
482
+ const envLower = String(envVal).toLowerCase();
483
+ if (envLower === "stream" || envLower === "parse" || envLower === "off") {
484
+ return envLower;
485
+ }
486
+ const boolEnv = normalizeBooleanString(envLower);
487
+ if (boolEnv === true) {
488
+ return "stream";
489
+ }
490
+ if (envLower === "2") {
491
+ return "parse";
544
492
  }
493
+ return "off";
545
494
  }
546
- function raiseUnexpected(state, token, expected) {
547
- raiseError(
548
- state,
549
- token,
550
- `Unexpected token: ${strToken(token)}, expected ${expected}`
551
- );
495
+ function color(code) {
496
+ return (text) => `\x1B[${code}m${text}\x1B[0m`;
552
497
  }
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}`);
498
+ var ANSI_GRAY = 90;
499
+ var ANSI_YELLOW = 33;
500
+ var ANSI_CYAN = 36;
501
+ var ANSI_BG_BLUE = 44;
502
+ var ANSI_BG_GREEN = 42;
503
+ var ANSI_INVERSE = 7;
504
+ var ANSI_UNDERLINE = 4;
505
+ var ANSI_BOLD = 1;
506
+ var cGray = color(ANSI_GRAY);
507
+ var cYellow = color(ANSI_YELLOW);
508
+ var cCyan = color(ANSI_CYAN);
509
+ var cBgBlue = color(ANSI_BG_BLUE);
510
+ var cBgGreen = color(ANSI_BG_GREEN);
511
+ var cInverse = color(ANSI_INVERSE);
512
+ var cUnderline = color(ANSI_UNDERLINE);
513
+ var cBold = color(ANSI_BOLD);
514
+ var MAX_SNIPPET_LENGTH = 800;
515
+ function safeStringify(value) {
516
+ try {
517
+ return `
518
+ ${typeof value === "string" ? value : JSON.stringify(value, null, 2)}`;
519
+ } catch (e) {
520
+ return String(value);
557
521
  }
558
522
  }
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;
523
+ function formatError(error) {
524
+ if (error instanceof Error) {
525
+ const stack = error.stack ? `
526
+ ${error.stack}` : "";
527
+ return `
528
+ ${error.name}: ${error.message}${stack}`;
563
529
  }
530
+ return safeStringify(error);
564
531
  }
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
- }
532
+ function truncateSnippet(snippet) {
533
+ if (snippet.length <= MAX_SNIPPET_LENGTH) {
534
+ return snippet;
614
535
  }
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);
536
+ return `${snippet.slice(0, MAX_SNIPPET_LENGTH)}
537
+ \u2026[truncated ${snippet.length - MAX_SNIPPET_LENGTH} chars]`;
620
538
  }
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;
539
+ function logParseFailure({
540
+ phase,
541
+ reason,
542
+ snippet,
543
+ error
544
+ }) {
545
+ if (getDebugLevel() !== "parse") {
546
+ return;
547
+ }
548
+ const label = cBgBlue(`[${phase}]`);
549
+ console.log(cGray("[debug:mw:fail]"), label, cYellow(reason));
550
+ if (snippet) {
551
+ const formatted = truncateSnippet(snippet);
552
+ console.log(cGray("[debug:mw:fail:snippet]"), formatted);
553
+ }
554
+ if (error) {
555
+ console.log(cGray("[debug:mw:fail:error]"), cCyan(formatError(error)));
556
+ }
625
557
  }
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
- });
558
+ function logRawChunk(part) {
559
+ console.log(cGray("[debug:mw:raw]"), cYellow(safeStringify(part)));
638
560
  }
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
- });
561
+ function logParsedChunk(part) {
562
+ console.log(cGray("[debug:mw:out]"), cCyan(safeStringify(part)));
651
563
  }
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;
564
+ function getHighlightStyle() {
565
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW_STYLE || "bg";
566
+ const normalized = String(envVal).trim().toLowerCase();
567
+ if (normalized === "inverse" || normalized === "invert") {
568
+ return "inverse";
569
+ }
570
+ if (normalized === "underline" || normalized === "ul") {
571
+ return "underline";
572
+ }
573
+ if (normalized === "bold") {
574
+ return "bold";
575
+ }
576
+ if (normalized === "bg" || normalized === "background") {
577
+ return "bg";
660
578
  }
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;
579
+ const asBool = normalizeBooleanString(normalized);
580
+ if (asBool === true) {
581
+ return "bg";
670
582
  }
671
- opts.elementParser(tokens, state, result);
672
- return null;
583
+ return "bg";
673
584
  }
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;
585
+ function getHighlightFunction(style) {
586
+ if (style === "inverse") {
587
+ return cInverse;
679
588
  }
680
- if (token.type === opts.endSymbol) {
681
- return result;
589
+ if (style === "underline") {
590
+ return cUnderline;
682
591
  }
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
- }
592
+ if (style === "bold") {
593
+ return cBold;
694
594
  }
695
- if (token.type === opts.endSymbol) {
696
- return result;
595
+ if (style === "bg") {
596
+ return cBgGreen;
697
597
  }
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;
598
+ return cYellow;
599
+ }
600
+ function renderHighlightedText(originalText, style, highlight) {
601
+ if (style === "bg" || style === "inverse" || style === "underline" || style === "bold") {
602
+ return originalText.split(LINE_SPLIT_REGEX).map((line) => line.length ? highlight(line) : line).join("\n");
710
603
  }
711
- opts.elementParser(tokens, state, result);
712
- return;
604
+ return highlight(originalText);
713
605
  }
714
- function parseMany(tokens, state, result, opts) {
715
- const initialResult = parseManyInitialElement(tokens, state, result, opts);
716
- if (initialResult !== void 0) {
717
- return initialResult;
606
+ function logParsedSummary({
607
+ toolCalls,
608
+ originalText
609
+ }) {
610
+ if (originalText) {
611
+ const style = getHighlightStyle();
612
+ const highlight = getHighlightFunction(style);
613
+ const rendered = renderHighlightedText(originalText, style, highlight);
614
+ console.log(cGray("[debug:mw:origin]"), `
615
+ ${rendered}`);
718
616
  }
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
- }
617
+ if (toolCalls.length > 0) {
618
+ const styledSummary = safeStringify(toolCalls).split(LINE_SPLIT_REGEX).map((line) => line.length ? cBgBlue(line) : line).join("\n");
619
+ console.log(cGray("[debug:mw:summary]"), styledSummary);
731
620
  }
732
621
  }
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
- }
622
+
623
+ // src/core/utils/get-potential-start-index.ts
624
+ function getPotentialStartIndex(text, searchedText) {
625
+ if (searchedText.length === 0) {
626
+ return null;
745
627
  }
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;
628
+ const directIndex = text.indexOf(searchedText);
629
+ if (directIndex !== -1) {
630
+ return directIndex;
631
+ }
632
+ for (let i = text.length - 1; i >= 0; i -= 1) {
633
+ const suffix = text.substring(i);
634
+ if (searchedText.startsWith(suffix)) {
635
+ return i;
636
+ }
753
637
  }
638
+ return null;
754
639
  }
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");
640
+
641
+ // src/core/utils/id.ts
642
+ function generateId() {
643
+ return Math.random().toString(36).substring(2, 15);
644
+ }
645
+
646
+ // src/core/utils/regex.ts
647
+ function escapeRegExp2(literal) {
648
+ return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
649
+ }
650
+
651
+ // src/core/utils/robust-json.ts
652
+ var WHITESPACE_TEST_REGEX = /\s/;
653
+ var WHITESPACE_REGEX2 = /^\s+/;
654
+ var OBJECT_START_REGEX = /^\{/;
655
+ var OBJECT_END_REGEX = /^\}/;
656
+ var ARRAY_START_REGEX = /^\[/;
657
+ var ARRAY_END_REGEX = /^\]/;
658
+ var COMMA_REGEX = /^,/;
659
+ var COLON_REGEX = /^:/;
660
+ var KEYWORD_REGEX = /^(?:true|false|null)/;
661
+ var NUMBER_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/;
662
+ var STRING_DOUBLE_REGEX = /^"(?:[^"\\]|\\["bnrtf\\/]|\\u[0-9a-fA-F]{4})*"/;
663
+ var STRING_SINGLE_REGEX = /^'((?:[^'\\]|\\['bnrtf\\/]|\\u[0-9a-fA-F]{4})*)'/;
664
+ var COMMENT_SINGLE_REGEX = /^\/\/.*?(?:\r\n|\r|\n)/;
665
+ var COMMENT_MULTI_REGEX = /^\/\*[\s\S]*?\*\//;
666
+ var IDENTIFIER_REGEX = /^[$a-zA-Z0-9_\-+.*?!|&%^/#\\]+/;
667
+ function some(array, f) {
668
+ let acc = false;
669
+ for (let i = 0; i < array.length; i += 1) {
670
+ const result = f(array[i], i, array);
671
+ acc = result === void 0 ? false : result;
672
+ if (acc) {
673
+ return acc;
761
674
  }
762
- raiseUnexpected(state, token, "json value");
763
- return;
764
675
  }
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 {
676
+ return acc;
677
+ }
678
+ function makeLexer(tokenSpecs) {
679
+ return (contents) => {
680
+ const tokens = [];
681
+ let line = 1;
682
+ let remainingContents = contents;
683
+ function findToken() {
684
+ const result = some(tokenSpecs, (tokenSpec) => {
685
+ const m = tokenSpec.re.exec(remainingContents);
686
+ if (m) {
687
+ const raw = m[0];
688
+ remainingContents = remainingContents.slice(raw.length);
689
+ return {
690
+ raw,
691
+ matched: tokenSpec.f(m)
692
+ // Process the match using the spec's function
693
+ };
694
+ }
784
695
  return;
696
+ });
697
+ return result === false ? void 0 : result;
698
+ }
699
+ while (remainingContents !== "") {
700
+ const matched = findToken();
701
+ if (!matched) {
702
+ const err = new SyntaxError(
703
+ `Unexpected character: ${remainingContents[0]}; input: ${remainingContents.substr(
704
+ 0,
705
+ 100
706
+ )}`
707
+ );
708
+ err.line = line;
709
+ throw err;
785
710
  }
786
- }
787
- if (end) {
788
- ret = state.reviver ? state.reviver("", ret) : ret;
789
- endChecks(tokens, state, ret);
790
- }
791
- return ret;
711
+ const tokenWithLine = matched.matched;
712
+ tokenWithLine.line = line;
713
+ line += matched.raw.replace(/[^\n]/g, "").length;
714
+ tokens.push(tokenWithLine);
715
+ }
716
+ return tokens;
717
+ };
792
718
  }
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;
719
+ function fStringSingle(m) {
720
+ const content = m[1].replace(
721
+ /([^'\\]|\\['bnrtf\\]|\\u[0-9a-fA-F]{4})/g,
722
+ (mm) => {
723
+ if (mm === '"') {
724
+ return '\\"';
725
+ }
726
+ if (mm === "\\'") {
727
+ return "'";
728
+ }
729
+ return mm;
812
730
  }
813
- }
814
- options.tolerant = options.tolerant || options.warnings;
815
- options.duplicate = (_a = options.duplicate) != null ? _a : false;
816
- return options;
731
+ );
732
+ const match = `"${content}"`;
733
+ return {
734
+ type: "string",
735
+ match,
736
+ // The transformed, double-quoted string representation
737
+ // Use JSON.parse on the transformed string to handle escape sequences correctly
738
+ value: JSON.parse(match)
739
+ };
817
740
  }
818
- function createParseState(options) {
819
- var _a, _b;
741
+ function fStringDouble(m) {
820
742
  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: []
743
+ type: "string",
744
+ match: m[0],
745
+ // The raw matched string (including quotes)
746
+ value: JSON.parse(m[0])
747
+ // Use JSON.parse to handle escapes and get the value
826
748
  };
827
749
  }
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);
750
+ function fIdentifier(m) {
751
+ const value = m[0];
752
+ const match = '"' + value.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + // Escape backslashes and quotes
753
+ '"';
754
+ return {
755
+ type: "string",
756
+ // Treat identifiers as strings
757
+ value,
758
+ // The original identifier name
759
+ match
760
+ // The double-quoted string representation
761
+ };
837
762
  }
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
763
+ function fComment(m) {
764
+ const match = m[0].replace(
765
+ /./g,
766
+ (c) => WHITESPACE_TEST_REGEX.test(c) ? c : " "
845
767
  );
768
+ return {
769
+ type: " ",
770
+ // Represent comments as whitespace tokens
771
+ match,
772
+ // String containing original newlines and spaces for other chars
773
+ value: void 0
774
+ // Comments don't have a semantic value
775
+ };
846
776
  }
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 = "";
777
+ function fNumber(m) {
778
+ return {
779
+ type: "number",
780
+ match: m[0],
781
+ // The raw matched number string
782
+ value: Number.parseFloat(m[0])
783
+ // Convert string to number
784
+ };
925
785
  }
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;
786
+ function fKeyword(m) {
787
+ let value;
788
+ switch (m[0]) {
789
+ case "null":
790
+ value = null;
791
+ break;
792
+ case "true":
793
+ value = true;
794
+ break;
795
+ case "false":
796
+ value = false;
797
+ break;
798
+ default:
799
+ throw new Error(`Unexpected keyword: ${m[0]}`);
934
800
  }
801
+ return {
802
+ type: "atom",
803
+ // Use 'atom' type for these literals
804
+ match: m[0],
805
+ // The raw matched keyword
806
+ value
807
+ // The corresponding JavaScript value
808
+ };
935
809
  }
936
- function emitIncompleteToolCall(state, controller, toolCallStart) {
937
- if (!state.currentToolCallJson) {
938
- return;
810
+ function makeTokenSpecs(relaxed) {
811
+ function f(type) {
812
+ return (m) => {
813
+ return { type, match: m[0], value: void 0 };
814
+ };
939
815
  }
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);
816
+ let tokenSpecs = [
817
+ { re: WHITESPACE_REGEX2, f: f(" ") },
818
+ // Whitespace
819
+ { re: OBJECT_START_REGEX, f: f("{") },
820
+ // Object start
821
+ { re: OBJECT_END_REGEX, f: f("}") },
822
+ // Object end
823
+ { re: ARRAY_START_REGEX, f: f("[") },
824
+ // Array start
825
+ { re: ARRAY_END_REGEX, f: f("]") },
826
+ // Array end
827
+ { re: COMMA_REGEX, f: f(",") },
828
+ // Comma separator
829
+ { re: COLON_REGEX, f: f(":") },
830
+ // Key-value separator
831
+ { re: KEYWORD_REGEX, f: fKeyword },
832
+ // Keywords
833
+ // Number: optional sign, digits, optional decimal part, optional exponent
834
+ { re: NUMBER_REGEX, f: fNumber },
835
+ // String: double-quoted, handles escapes
836
+ { re: STRING_DOUBLE_REGEX, f: fStringDouble }
837
+ ];
838
+ if (relaxed) {
839
+ tokenSpecs = tokenSpecs.concat([
840
+ // Single-quoted strings
841
+ {
842
+ re: STRING_SINGLE_REGEX,
843
+ f: fStringSingle
844
+ },
845
+ // Single-line comments (// ...)
846
+ { re: COMMENT_SINGLE_REGEX, f: fComment },
847
+ // Multi-line comments (/* ... */)
848
+ { re: COMMENT_MULTI_REGEX, f: fComment },
849
+ // Unquoted identifiers (treated as strings)
850
+ // Allows letters, numbers, _, -, +, ., *, ?, !, |, &, %, ^, /, #, \
851
+ { re: IDENTIFIER_REGEX, f: fIdentifier }
852
+ // Note: The order matters here. Identifiers are checked after keywords/numbers.
853
+ ]);
966
854
  }
967
- closeTextBlock(state, controller);
968
- emitIncompleteToolCall(state, controller, toolCallStart);
969
- controller.enqueue(chunk);
855
+ return tokenSpecs;
970
856
  }
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;
857
+ var lexer = makeLexer(makeTokenSpecs(true));
858
+ var strictLexer = makeLexer(makeTokenSpecs(false));
859
+ function previousNWSToken(tokens, index) {
860
+ let currentIndex = index;
861
+ for (; currentIndex >= 0; currentIndex -= 1) {
862
+ if (tokens[currentIndex].type !== " ") {
863
+ return currentIndex;
983
864
  }
984
- controller.enqueue({
985
- type: "text-delta",
986
- id: state.currentTextId,
987
- textDelta: text,
988
- delta: text
989
- });
990
865
  }
866
+ return;
991
867
  }
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
868
+ function stripTrailingComma(tokens) {
869
+ const res = [];
870
+ tokens.forEach((token, index) => {
871
+ if (index > 0 && (token.type === "]" || token.type === "}")) {
872
+ const prevNWSTokenIndex = previousNWSToken(res, res.length - 1);
873
+ if (prevNWSTokenIndex !== void 0 && res[prevNWSTokenIndex].type === ",") {
874
+ const preCommaIndex = previousNWSToken(res, prevNWSTokenIndex - 1);
875
+ if (preCommaIndex !== void 0 && res[preCommaIndex].type !== "[" && res[preCommaIndex].type !== "{") {
876
+ res[prevNWSTokenIndex] = {
877
+ type: " ",
878
+ match: " ",
879
+ // Represent as a single space
880
+ value: void 0,
881
+ // Whitespace has no value
882
+ line: res[prevNWSTokenIndex].line
883
+ // Preserve original line number
884
+ };
885
+ }
1032
886
  }
1033
- );
1034
- }
887
+ }
888
+ res.push(token);
889
+ });
890
+ return res;
1035
891
  }
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
- }
892
+ function transform(text) {
893
+ let tokens = lexer(text);
894
+ tokens = stripTrailingComma(tokens);
895
+ return tokens.reduce((str, token) => str + token.match, "");
1046
896
  }
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
- );
897
+ function popToken(tokens, state) {
898
+ var _a, _b;
899
+ const token = tokens[state.pos];
900
+ state.pos += 1;
901
+ if (!token) {
902
+ const lastLine = tokens.length !== 0 ? (_b = (_a = tokens.at(-1)) == null ? void 0 : _a.line) != null ? _b : 1 : 1;
903
+ return { type: "eof", match: "", value: void 0, line: lastLine };
1065
904
  }
905
+ return token;
1066
906
  }
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 = "";
907
+ function strToken(token) {
908
+ switch (token.type) {
909
+ case "atom":
910
+ case "string":
911
+ case "number":
912
+ return `${token.type} ${token.match}`;
913
+ case "eof":
914
+ return "end-of-file";
915
+ default:
916
+ return `'${token.type}'`;
1078
917
  }
1079
918
  }
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
919
+ function skipColon(tokens, state) {
920
+ const colon = popToken(tokens, state);
921
+ if (colon.type !== ":") {
922
+ const message = `Unexpected token: ${strToken(colon)}, expected ':'`;
923
+ if (state.tolerant) {
924
+ state.warnings.push({
925
+ message,
926
+ line: colon.line
1129
927
  });
1130
- match = toolCallRegex.exec(text);
928
+ state.pos -= 1;
929
+ } else {
930
+ const err = new SyntaxError(message);
931
+ err.line = colon.line;
932
+ throw err;
1131
933
  }
1132
- if (currentIndex < text.length) {
1133
- const remainingText = text.substring(currentIndex);
1134
- addTextSegment(remainingText, processedElements);
934
+ }
935
+ }
936
+ function skipPunctuation(tokens, state, valid) {
937
+ const punctuation = [",", ":", "]", "}"];
938
+ let token = popToken(tokens, state);
939
+ while (true) {
940
+ if (valid == null ? void 0 : valid.includes(token.type)) {
941
+ return token;
1135
942
  }
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
943
+ if (token.type === "eof") {
944
+ return token;
945
+ }
946
+ if (punctuation.includes(token.type)) {
947
+ const message = `Unexpected token: ${strToken(
948
+ token
949
+ )}, expected '[', '{', number, string or atom`;
950
+ if (state.tolerant) {
951
+ state.warnings.push({
952
+ message,
953
+ line: token.line
1165
954
  });
1166
- handlePartialTag(state, controller, toolCallStart);
955
+ token = popToken(tokens, state);
956
+ } else {
957
+ const err = new SyntaxError(message);
958
+ err.line = token.line;
959
+ throw err;
1167
960
  }
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);
961
+ } else {
962
+ return token;
1179
963
  }
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
964
  }
1192
- return current;
1193
965
  }
1194
- function applyParsedUpdate(current, result) {
1195
- if (result.parsed !== void 0) {
1196
- return { ...current, parsed: result.parsed };
966
+ function raiseError(state, token, message) {
967
+ if (state.tolerant) {
968
+ state.warnings.push({
969
+ message,
970
+ line: token.line
971
+ });
972
+ } else {
973
+ const err = new SyntaxError(message);
974
+ err.line = token.line;
975
+ throw err;
1197
976
  }
1198
- return current;
1199
977
  }
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;
978
+ function raiseUnexpected(state, token, expected) {
979
+ raiseError(
980
+ state,
981
+ token,
982
+ `Unexpected token: ${strToken(token)}, expected ${expected}`
983
+ );
1211
984
  }
1212
- function attemptReparse(current, result, reparseCount, maxReparses, parse4) {
1213
- if (!result.reparse || result.rawSegment === void 0 || reparseCount >= maxReparses) {
1214
- return { state: current, newCount: reparseCount };
985
+ function checkDuplicates(state, obj, token) {
986
+ const key = String(token.value);
987
+ if (!state.duplicate && Object.hasOwn(obj, key)) {
988
+ raiseError(state, token, `Duplicate key: ${key}`);
1215
989
  }
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
- };
990
+ }
991
+ function appendPair(state, obj, key, value) {
992
+ const finalValue = state.reviver ? state.reviver(key, value) : value;
993
+ if (finalValue !== void 0) {
994
+ obj[key] = finalValue;
1227
995
  }
1228
996
  }
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;
997
+ function parsePair(tokens, state, obj) {
998
+ let token = skipPunctuation(tokens, state, [":", "string", "number", "atom"]);
999
+ let value;
1000
+ if (token.type !== "string") {
1001
+ raiseUnexpected(state, token, "string key");
1002
+ if (state.tolerant) {
1003
+ switch (token.type) {
1004
+ case ":":
1005
+ token = {
1006
+ type: "string",
1007
+ value: "null",
1008
+ match: '"null"',
1009
+ line: token.line
1010
+ };
1011
+ state.pos -= 1;
1012
+ break;
1013
+ case "number":
1014
+ // Use number as string key
1015
+ case "atom":
1016
+ token = {
1017
+ type: "string",
1018
+ value: String(token.value),
1019
+ match: `"${token.value}"`,
1020
+ line: token.line
1021
+ };
1022
+ break;
1023
+ case "[":
1024
+ // Assume missing key before an array
1025
+ case "{":
1026
+ state.pos -= 1;
1027
+ value = parseAny(tokens, state);
1028
+ checkDuplicates(state, obj, {
1029
+ type: "string",
1030
+ value: "null",
1031
+ match: '"null"',
1032
+ line: token.line
1033
+ });
1034
+ appendPair(state, obj, "null", value);
1035
+ return;
1036
+ // Finished parsing this "pair"
1037
+ case "eof":
1038
+ return;
1039
+ // Cannot recover
1040
+ default:
1041
+ return;
1042
+ }
1043
+ } else {
1044
+ return;
1253
1045
  }
1254
1046
  }
1255
- return current;
1047
+ checkDuplicates(state, obj, token);
1048
+ const key = String(token.value);
1049
+ skipColon(tokens, state);
1050
+ value = parseAny(tokens, state);
1051
+ appendPair(state, obj, key, value);
1256
1052
  }
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] };
1053
+ function parseElement(tokens, state, arr) {
1054
+ const key = arr.length;
1055
+ const value = parseAny(tokens, state);
1056
+ arr[key] = state.reviver ? state.reviver(String(key), value) : value;
1057
+ }
1058
+ function parseObject(tokens, state) {
1059
+ const obj = {};
1060
+ return parseMany(tokens, state, obj, {
1061
+ skip: [":", "}"],
1062
+ // Initially skip over colon or closing brace (for empty/tolerant cases)
1063
+ elementParser: parsePair,
1064
+ // Use parsePair to parse each key-value element
1065
+ elementName: "string key",
1066
+ // Expected element type for errors
1067
+ endSymbol: "}"
1068
+ // The closing token for an object
1069
+ });
1070
+ }
1071
+ function parseArray(tokens, state) {
1072
+ const arr = [];
1073
+ return parseMany(tokens, state, arr, {
1074
+ skip: ["]"],
1075
+ // Initially skip over closing bracket (for empty/tolerant cases)
1076
+ elementParser: parseElement,
1077
+ // Use parseElement to parse each array item
1078
+ elementName: "json value",
1079
+ // Expected element type for errors
1080
+ endSymbol: "]"
1081
+ // The closing token for an array
1082
+ });
1083
+ }
1084
+ function handleInvalidToken(token, state, opts, result) {
1085
+ raiseUnexpected(state, token, `',' or '${opts.endSymbol}'`);
1086
+ if (state.tolerant) {
1087
+ if (token.type === "eof") {
1088
+ return result;
1268
1089
  }
1090
+ state.pos -= 1;
1091
+ return null;
1269
1092
  }
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);
1093
+ return result;
1094
+ }
1095
+ function handleCommaToken(params) {
1096
+ const { token, tokens, state, opts, result } = params;
1097
+ const nextToken = tokens[state.pos];
1098
+ if (state.tolerant && nextToken && nextToken.type === opts.endSymbol) {
1099
+ raiseError(state, token, `Trailing comma before '${opts.endSymbol}'`);
1100
+ popToken(tokens, state);
1101
+ return result;
1275
1102
  }
1276
- return current;
1103
+ opts.elementParser(tokens, state, result);
1104
+ return null;
1277
1105
  }
1278
- function createIntermediateCall(toolName, rawSegment, schema) {
1279
- return {
1280
- toolName,
1281
- schema,
1282
- rawSegment,
1283
- parsed: null,
1284
- errors: [],
1285
- meta: { originalContent: rawSegment }
1286
- };
1106
+ function parseManyInitialElement(tokens, state, result, opts) {
1107
+ const token = skipPunctuation(tokens, state, opts.skip);
1108
+ if (token.type === "eof") {
1109
+ raiseUnexpected(state, token, `'${opts.endSymbol}' or ${opts.elementName}`);
1110
+ return result;
1111
+ }
1112
+ if (token.type === opts.endSymbol) {
1113
+ return result;
1114
+ }
1115
+ state.pos -= 1;
1116
+ opts.elementParser(tokens, state, result);
1117
+ return;
1287
1118
  }
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 };
1119
+ function parseManyProcessToken(params) {
1120
+ const { token, tokens, state, opts, result } = params;
1121
+ if (token.type !== opts.endSymbol && token.type !== ",") {
1122
+ const handledResult = handleInvalidToken(token, state, opts, result);
1123
+ if (handledResult !== null) {
1124
+ return handledResult;
1307
1125
  }
1308
- return {};
1309
1126
  }
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 };
1127
+ if (token.type === opts.endSymbol) {
1128
+ return result;
1129
+ }
1130
+ if (token.type === ",") {
1131
+ const handledResult = handleCommaToken({
1132
+ token,
1133
+ tokens,
1134
+ state,
1135
+ opts,
1136
+ result
1137
+ });
1138
+ if (handledResult !== null) {
1139
+ return handledResult;
1319
1140
  }
1320
- return {};
1141
+ return;
1321
1142
  }
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;
1143
+ opts.elementParser(tokens, state, result);
1144
+ return;
1145
+ }
1146
+ function parseMany(tokens, state, result, opts) {
1147
+ const initialResult = parseManyInitialElement(tokens, state, result, opts);
1148
+ if (initialResult !== void 0) {
1149
+ return initialResult;
1150
+ }
1151
+ while (true) {
1152
+ const token = popToken(tokens, state);
1153
+ const processedResult = parseManyProcessToken({
1154
+ token,
1155
+ tokens,
1156
+ state,
1157
+ opts,
1158
+ result
1159
+ });
1160
+ if (processedResult !== void 0) {
1161
+ return processedResult;
1334
1162
  }
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
1163
  }
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);
1164
+ }
1165
+ function endChecks(tokens, state, ret) {
1166
+ if (state.pos < tokens.length) {
1167
+ if (state.tolerant) {
1168
+ skipPunctuation(tokens, state);
1354
1169
  }
1355
- if (deduped !== ctx.rawSegment) {
1356
- return { rawSegment: deduped, reparse: true };
1170
+ if (state.pos < tokens.length) {
1171
+ raiseError(
1172
+ state,
1173
+ tokens[state.pos],
1174
+ `Unexpected token: ${strToken(tokens[state.pos])}, expected end-of-input`
1175
+ );
1357
1176
  }
1358
- return {};
1359
1177
  }
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 {};
1178
+ if (state.tolerant && state.warnings.length > 0) {
1179
+ const message = state.warnings.length === 1 ? state.warnings[0].message : `${state.warnings.length} parse warnings`;
1180
+ const err = new SyntaxError(message);
1181
+ err.line = state.warnings[0].line;
1182
+ err.warnings = state.warnings;
1183
+ err.obj = ret;
1184
+ throw err;
1371
1185
  }
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
1186
  }
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
- }
1187
+ function parseAny(tokens, state, end = false) {
1188
+ const token = skipPunctuation(tokens, state);
1189
+ let ret;
1190
+ if (token.type === "eof") {
1191
+ if (end) {
1192
+ raiseUnexpected(state, token, "json value");
1396
1193
  }
1397
- out += ch;
1194
+ raiseUnexpected(state, token, "json value");
1195
+ return;
1398
1196
  }
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));
1197
+ switch (token.type) {
1198
+ case "{":
1199
+ ret = parseObject(tokens, state);
1411
1200
  break;
1412
- }
1413
- out.push(src.slice(i, lt));
1414
- if (lt + 1 >= len) {
1201
+ case "[":
1202
+ ret = parseArray(tokens, state);
1415
1203
  break;
1416
- }
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);
1204
+ case "string":
1205
+ // String literal
1206
+ case "number":
1207
+ // Number literal
1208
+ case "atom":
1209
+ ret = token.value;
1210
+ break;
1211
+ default:
1212
+ raiseUnexpected(state, token, "json value");
1213
+ if (state.tolerant) {
1214
+ ret = null;
1215
+ } else {
1216
+ return;
1217
+ }
1427
1218
  }
1428
- for (let k = stack.length - 1; k >= 0; k -= 1) {
1429
- out.push(`</${stack[k]}>`);
1219
+ if (end) {
1220
+ ret = state.reviver ? state.reviver("", ret) : ret;
1221
+ endChecks(tokens, state, ret);
1430
1222
  }
1431
- return out.join("");
1223
+ return ret;
1432
1224
  }
1433
- function skipWs(s, p, len) {
1434
- let idx = p;
1435
- while (idx < len && WHITESPACE_REGEX2.test(s[idx])) {
1436
- idx += 1;
1225
+ function normalizeParseOptions(optsOrReviver) {
1226
+ var _a;
1227
+ let options = {};
1228
+ if (typeof optsOrReviver === "function") {
1229
+ options.reviver = optsOrReviver;
1230
+ } else if (optsOrReviver !== null && typeof optsOrReviver === "object") {
1231
+ options = { ...optsOrReviver };
1232
+ } else if (optsOrReviver !== void 0) {
1233
+ throw new TypeError(
1234
+ "Second argument must be a reviver function or an options object."
1235
+ );
1437
1236
  }
1438
- return idx;
1237
+ if (options.relaxed === void 0) {
1238
+ if (options.warnings === true || options.tolerant === true) {
1239
+ options.relaxed = true;
1240
+ } else if (options.warnings === false && options.tolerant === false) {
1241
+ options.relaxed = false;
1242
+ } else {
1243
+ options.relaxed = true;
1244
+ }
1245
+ }
1246
+ options.tolerant = options.tolerant || options.warnings;
1247
+ options.duplicate = (_a = options.duplicate) != null ? _a : false;
1248
+ return options;
1439
1249
  }
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;
1250
+ function createParseState(options) {
1251
+ var _a, _b;
1252
+ return {
1253
+ pos: 0,
1254
+ reviver: options.reviver,
1255
+ tolerant: (_a = options.tolerant) != null ? _a : false,
1256
+ duplicate: (_b = options.duplicate) != null ? _b : false,
1257
+ warnings: []
1258
+ };
1259
+ }
1260
+ function parseWithCustomParser(text, options) {
1261
+ const lexerToUse = options.relaxed ? lexer : strictLexer;
1262
+ let tokens = lexerToUse(text);
1263
+ if (options.relaxed) {
1264
+ tokens = stripTrailingComma(tokens);
1265
+ }
1266
+ tokens = tokens.filter((token) => token.type !== " ");
1267
+ const state = createParseState(options);
1268
+ return parseAny(tokens, state, true);
1269
+ }
1270
+ function parseWithTransform(text, options) {
1271
+ let tokens = lexer(text);
1272
+ tokens = stripTrailingComma(tokens);
1273
+ const newtext = tokens.reduce((str, token) => str + token.match, "");
1274
+ return JSON.parse(
1275
+ newtext,
1276
+ options.reviver
1277
+ );
1278
+ }
1279
+ function parse2(text, optsOrReviver) {
1280
+ const options = normalizeParseOptions(optsOrReviver);
1281
+ if (!(options.relaxed || options.warnings || options.tolerant) && options.duplicate) {
1282
+ return JSON.parse(
1283
+ text,
1284
+ options.reviver
1285
+ );
1286
+ }
1287
+ if (options.warnings || options.tolerant || !options.duplicate) {
1288
+ return parseWithCustomParser(text, options);
1445
1289
  }
1446
- return { name: s.slice(start, idx), pos: idx };
1290
+ return parseWithTransform(text, options);
1447
1291
  }
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;
1453
- }
1454
- out.push(src.slice(lt, gt + 1));
1455
- return gt + 1;
1292
+ function stringifyPair(obj, key) {
1293
+ return `${JSON.stringify(key)}:${stringify(obj[key])}`;
1456
1294
  }
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();
1295
+ function stringify(obj) {
1296
+ const type = typeof obj;
1297
+ if (type === "string" || type === "number" || type === "boolean" || obj === null) {
1298
+ return JSON.stringify(obj);
1472
1299
  }
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;
1300
+ if (type === "undefined") {
1301
+ return "null";
1486
1302
  }
1487
- let r = q - 1;
1488
- while (r >= nameStart && WHITESPACE_REGEX2.test(src[r])) {
1489
- r -= 1;
1303
+ if (Array.isArray(obj)) {
1304
+ const elements = obj.map(stringify).join(",");
1305
+ return `[${elements}]`;
1490
1306
  }
1491
- const selfClosing = src[r] === "/";
1492
- out.push(src.slice(lt, q + 1));
1493
- if (!selfClosing && name) {
1494
- stack.push(name);
1307
+ if (type === "object") {
1308
+ const keys = Object.keys(obj);
1309
+ keys.sort();
1310
+ const pairs = keys.map((key) => stringifyPair(obj, key)).join(",");
1311
+ return `{${pairs}}`;
1495
1312
  }
1496
- return q + 1;
1313
+ return "null";
1497
1314
  }
1498
- function shouldDeduplicateStringTags(schema) {
1499
- const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1500
- if (!unwrapped || typeof unwrapped !== "object") {
1501
- return false;
1502
- }
1503
- const props = unwrapped.properties;
1504
- if (!props) {
1505
- return false;
1506
- }
1507
- const commandRaw = props.command;
1508
- if (!commandRaw) {
1509
- return false;
1315
+
1316
+ // src/core/protocols/json-protocol.ts
1317
+ function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
1318
+ var _a, _b;
1319
+ try {
1320
+ const parsedToolCall = parse2(toolCallJson);
1321
+ processedElements.push({
1322
+ type: "tool-call",
1323
+ toolCallId: generateId(),
1324
+ toolName: parsedToolCall.name,
1325
+ input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1326
+ });
1327
+ } catch (error) {
1328
+ logParseFailure({
1329
+ phase: "generated-text",
1330
+ reason: "Failed to parse tool call JSON segment",
1331
+ snippet: fullMatch,
1332
+ error
1333
+ });
1334
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1335
+ options,
1336
+ "Could not process JSON tool call, keeping original text.",
1337
+ { toolCall: fullMatch, error }
1338
+ );
1339
+ processedElements.push({ type: "text", text: fullMatch });
1510
1340
  }
1511
- const command = (0, import_rxml.unwrapJsonSchema)(commandRaw);
1512
- return (command == null ? void 0 : command.type) === "array";
1513
1341
  }
1514
- function getStringPropertyNames(schema) {
1515
- const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1516
- if (!unwrapped || typeof unwrapped !== "object") {
1517
- return [];
1342
+ function addTextSegment(text, processedElements) {
1343
+ if (text.trim()) {
1344
+ processedElements.push({ type: "text", text });
1518
1345
  }
1519
- const props = unwrapped.properties;
1520
- if (!props) {
1521
- return [];
1346
+ }
1347
+ function processMatchedToolCall(context) {
1348
+ const { match, text, currentIndex, processedElements, options } = context;
1349
+ const startIndex = match.index;
1350
+ const toolCallJson = match[1];
1351
+ if (startIndex > currentIndex) {
1352
+ const textSegment = text.substring(currentIndex, startIndex);
1353
+ addTextSegment(textSegment, processedElements);
1522
1354
  }
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
- }
1355
+ if (toolCallJson) {
1356
+ processToolCallJson(toolCallJson, match[0], processedElements, options);
1532
1357
  }
1533
- return names;
1534
- }
1535
- function escapeRegExp2(s) {
1536
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1358
+ return startIndex + match[0].length;
1537
1359
  }
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;
1360
+ function flushBuffer(state, controller, toolCallStart) {
1361
+ if (state.buffer.length === 0) {
1362
+ return;
1545
1363
  }
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];
1554
- }
1555
- cursor = idx + m[0].length;
1364
+ if (!state.currentTextId) {
1365
+ state.currentTextId = generateId();
1366
+ controller.enqueue({
1367
+ type: "text-start",
1368
+ id: state.currentTextId
1369
+ });
1370
+ state.hasEmittedTextStart = true;
1556
1371
  }
1557
- result += xml.slice(cursor);
1558
- return result;
1372
+ const deltaContent = state.isInsideToolCall ? `${toolCallStart}${state.buffer}` : state.buffer;
1373
+ controller.enqueue({
1374
+ type: "text-delta",
1375
+ id: state.currentTextId,
1376
+ delta: deltaContent
1377
+ });
1378
+ state.buffer = "";
1559
1379
  }
1560
- function repairParsedAgainstSchema(input, schema) {
1561
- if (!input || typeof input !== "object") {
1562
- return input;
1380
+ function closeTextBlock(state, controller) {
1381
+ if (state.currentTextId && state.hasEmittedTextStart) {
1382
+ controller.enqueue({
1383
+ type: "text-end",
1384
+ id: state.currentTextId
1385
+ });
1386
+ state.currentTextId = null;
1387
+ state.hasEmittedTextStart = false;
1563
1388
  }
1564
- const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1565
- if (!unwrapped || typeof unwrapped !== "object") {
1566
- return input;
1389
+ }
1390
+ function emitIncompleteToolCall(state, controller, toolCallStart) {
1391
+ if (!state.currentToolCallJson) {
1392
+ return;
1567
1393
  }
1568
- const properties = unwrapped.properties;
1569
- if (!properties) {
1570
- return input;
1394
+ logParseFailure({
1395
+ phase: "stream",
1396
+ reason: "Incomplete streaming tool call segment emitted as text",
1397
+ snippet: `${toolCallStart}${state.currentToolCallJson}`
1398
+ });
1399
+ const errorId = generateId();
1400
+ const errorContent = `${toolCallStart}${state.currentToolCallJson}`;
1401
+ controller.enqueue({
1402
+ type: "text-start",
1403
+ id: errorId
1404
+ });
1405
+ controller.enqueue({
1406
+ type: "text-delta",
1407
+ id: errorId,
1408
+ delta: errorContent
1409
+ });
1410
+ controller.enqueue({
1411
+ type: "text-end",
1412
+ id: errorId
1413
+ });
1414
+ state.currentToolCallJson = "";
1415
+ }
1416
+ function handleFinishChunk(state, controller, toolCallStart, chunk) {
1417
+ if (state.buffer.length > 0) {
1418
+ flushBuffer(state, controller, toolCallStart);
1571
1419
  }
1572
- applySchemaProps(input, properties);
1573
- return input;
1420
+ closeTextBlock(state, controller);
1421
+ emitIncompleteToolCall(state, controller, toolCallStart);
1422
+ controller.enqueue(chunk);
1574
1423
  }
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;
1424
+ function publishText(text, state, controller) {
1425
+ if (state.isInsideToolCall) {
1426
+ closeTextBlock(state, controller);
1427
+ state.currentToolCallJson += text;
1428
+ } else if (text.length > 0) {
1429
+ if (!state.currentTextId) {
1430
+ state.currentTextId = generateId();
1431
+ controller.enqueue({
1432
+ type: "text-start",
1433
+ id: state.currentTextId
1434
+ });
1435
+ state.hasEmittedTextStart = true;
1588
1436
  }
1589
- if (propType === "object") {
1590
- const val = obj[key];
1591
- if (val && typeof val === "object") {
1592
- obj[key] = repairParsedAgainstSchema(val, prop);
1437
+ controller.enqueue({
1438
+ type: "text-delta",
1439
+ id: state.currentTextId,
1440
+ delta: text
1441
+ });
1442
+ }
1443
+ }
1444
+ function emitToolCall(context) {
1445
+ var _a, _b;
1446
+ const { state, controller, toolCallStart, toolCallEnd, options } = context;
1447
+ try {
1448
+ const parsedToolCall = parse2(state.currentToolCallJson);
1449
+ closeTextBlock(state, controller);
1450
+ controller.enqueue({
1451
+ type: "tool-call",
1452
+ toolCallId: generateId(),
1453
+ toolName: parsedToolCall.name,
1454
+ input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1455
+ });
1456
+ } catch (error) {
1457
+ logParseFailure({
1458
+ phase: "stream",
1459
+ reason: "Failed to parse streaming tool call JSON segment",
1460
+ snippet: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`,
1461
+ error
1462
+ });
1463
+ const errorId = generateId();
1464
+ const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
1465
+ controller.enqueue({
1466
+ type: "text-start",
1467
+ id: errorId
1468
+ });
1469
+ controller.enqueue({
1470
+ type: "text-delta",
1471
+ id: errorId,
1472
+ delta: errorContent
1473
+ });
1474
+ controller.enqueue({
1475
+ type: "text-end",
1476
+ id: errorId
1477
+ });
1478
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1479
+ options,
1480
+ "Could not process streaming JSON tool call; emitting original text.",
1481
+ {
1482
+ toolCall: errorContent
1593
1483
  }
1594
- }
1484
+ );
1595
1485
  }
1596
1486
  }
1597
- function coerceArrayItems(val, itemSchema) {
1598
- if (!Array.isArray(val)) {
1599
- return val;
1487
+ function processTagMatch(context) {
1488
+ const { state } = context;
1489
+ if (state.isInsideToolCall) {
1490
+ emitToolCall(context);
1491
+ state.currentToolCallJson = "";
1492
+ state.isInsideToolCall = false;
1493
+ } else {
1494
+ state.currentToolCallJson = "";
1495
+ state.isInsideToolCall = true;
1600
1496
  }
1601
- return val.map((v) => coerceArrayItem(v, itemSchema));
1602
1497
  }
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;
1498
+ function processBufferTags(context) {
1499
+ const { state, controller, toolCallStart, toolCallEnd } = context;
1500
+ let startIndex = getPotentialStartIndex(
1501
+ state.buffer,
1502
+ state.isInsideToolCall ? toolCallEnd : toolCallStart
1503
+ );
1504
+ while (startIndex != null) {
1505
+ const tag = state.isInsideToolCall ? toolCallEnd : toolCallStart;
1506
+ if (startIndex + tag.length > state.buffer.length) {
1507
+ break;
1609
1508
  }
1610
- const fallback = extractStepStatusFromString(
1611
- v.replace(MALFORMED_CLOSE_RE_G, "</$1>")
1509
+ publishText(state.buffer.slice(0, startIndex), state, controller);
1510
+ state.buffer = state.buffer.slice(startIndex + tag.length);
1511
+ processTagMatch(context);
1512
+ startIndex = getPotentialStartIndex(
1513
+ state.buffer,
1514
+ state.isInsideToolCall ? toolCallEnd : toolCallStart
1612
1515
  );
1613
- if (fallback) {
1614
- return fallback;
1615
- }
1616
- return v;
1617
- }
1618
- if (v && typeof v === "object" && itemType === "object") {
1619
- return repairParsedAgainstSchema(v, itemSchema);
1620
1516
  }
1621
- return v;
1622
1517
  }
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;
1518
+ function handlePartialTag(state, controller, toolCallStart) {
1519
+ if (state.isInsideToolCall) {
1520
+ return;
1521
+ }
1522
+ const potentialIndex = getPotentialStartIndex(state.buffer, toolCallStart);
1523
+ if (potentialIndex != null && potentialIndex + toolCallStart.length > state.buffer.length) {
1524
+ publishText(state.buffer.slice(0, potentialIndex), state, controller);
1525
+ state.buffer = state.buffer.slice(potentialIndex);
1526
+ } else {
1527
+ publishText(state.buffer, state, controller);
1528
+ state.buffer = "";
1630
1529
  }
1631
1530
  }
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] };
1531
+ var jsonProtocol = ({
1532
+ toolCallStart = "<tool_call>",
1533
+ toolCallEnd = "</tool_call>"
1534
+ } = {}) => ({
1535
+ formatTools({
1536
+ tools,
1537
+ toolSystemPromptTemplate
1538
+ }) {
1539
+ return toolSystemPromptTemplate(tools || []);
1540
+ },
1541
+ formatToolCall(toolCall) {
1542
+ let args = {};
1543
+ if (toolCall.input != null) {
1544
+ try {
1545
+ args = JSON.parse(toolCall.input);
1546
+ } catch (e) {
1547
+ args = toolCall.input;
1548
+ }
1549
+ }
1550
+ return `${toolCallStart}${JSON.stringify({
1551
+ name: toolCall.toolName,
1552
+ arguments: args
1553
+ })}${toolCallEnd}`;
1554
+ },
1555
+ parseGeneratedText({
1556
+ text,
1557
+ options
1558
+ }) {
1559
+ const startEsc = escapeRegExp2(toolCallStart);
1560
+ const endEsc = escapeRegExp2(toolCallEnd);
1561
+ const toolCallRegex = new RegExp(
1562
+ `${startEsc}([\0-\uFFFF]*?)${endEsc}`,
1563
+ "gs"
1564
+ );
1565
+ const processedElements = [];
1566
+ let currentIndex = 0;
1567
+ let match = toolCallRegex.exec(text);
1568
+ while (match !== null) {
1569
+ currentIndex = processMatchedToolCall({
1570
+ match,
1571
+ text,
1572
+ currentIndex,
1573
+ processedElements,
1574
+ options
1575
+ });
1576
+ match = toolCallRegex.exec(text);
1577
+ }
1578
+ if (currentIndex < text.length) {
1579
+ const remainingText = text.substring(currentIndex);
1580
+ addTextSegment(remainingText, processedElements);
1581
+ }
1582
+ return processedElements;
1583
+ },
1584
+ createStreamParser({
1585
+ options
1586
+ }) {
1587
+ const state = {
1588
+ isInsideToolCall: false,
1589
+ buffer: "",
1590
+ currentToolCallJson: "",
1591
+ currentTextId: null,
1592
+ hasEmittedTextStart: false
1593
+ };
1594
+ return new TransformStream({
1595
+ transform(chunk, controller) {
1596
+ var _a;
1597
+ if (chunk.type === "finish") {
1598
+ handleFinishChunk(state, controller, toolCallStart, chunk);
1599
+ return;
1600
+ }
1601
+ if (chunk.type !== "text-delta") {
1602
+ controller.enqueue(chunk);
1603
+ return;
1604
+ }
1605
+ const textContent = (_a = chunk.delta) != null ? _a : "";
1606
+ state.buffer += textContent;
1607
+ processBufferTags({
1608
+ state,
1609
+ controller,
1610
+ toolCallStart,
1611
+ toolCallEnd,
1612
+ options
1613
+ });
1614
+ handlePartialTag(state, controller, toolCallStart);
1615
+ }
1616
+ });
1617
+ },
1618
+ extractToolCallSegments({ text }) {
1619
+ const startEsc = escapeRegExp2(toolCallStart);
1620
+ const endEsc = escapeRegExp2(toolCallEnd);
1621
+ const regex = new RegExp(`${startEsc}([\0-\uFFFF]*?)${endEsc}`, "gs");
1622
+ const segments = [];
1623
+ let m = regex.exec(text);
1624
+ while (m != null) {
1625
+ segments.push(m[0]);
1626
+ m = regex.exec(text);
1627
+ }
1628
+ return segments;
1637
1629
  }
1638
- return null;
1630
+ });
1631
+
1632
+ // src/core/protocols/protocol-interface.ts
1633
+ function isProtocolFactory(protocol) {
1634
+ return typeof protocol === "function";
1635
+ }
1636
+ function isTCMProtocolFactory(protocol) {
1637
+ return typeof protocol === "function";
1639
1638
  }
1640
1639
 
1641
- // src/core/protocols/morph-xml-protocol.ts
1640
+ // src/core/protocols/xml-protocol.ts
1641
+ import { extractRawInner, parse as parse3, stringify as stringify2 } from "@ai-sdk-tool/rxml";
1642
1642
  var defaultPipelineConfig2 = defaultPipelineConfig;
1643
1643
  var NAME_CHAR_RE2 = /[A-Za-z0-9_:-]/;
1644
1644
  var WHITESPACE_REGEX3 = /\s/;
@@ -1652,7 +1652,7 @@ function normalizeCloseTags(xml) {
1652
1652
  function tryParseSecondaryXml(content, toolSchema, options) {
1653
1653
  const balanced = balanceTags(content);
1654
1654
  try {
1655
- let parsed = (0, import_rxml2.parse)(balanced, toolSchema, {
1655
+ let parsed = parse3(balanced, toolSchema, {
1656
1656
  onError: options == null ? void 0 : options.onError,
1657
1657
  noChildNodes: []
1658
1658
  });
@@ -1667,7 +1667,7 @@ function tryParseSecondaryXml(content, toolSchema, options) {
1667
1667
  }
1668
1668
  if (deduped !== balanced) {
1669
1669
  try {
1670
- let reparsed = (0, import_rxml2.parse)(deduped, toolSchema, {
1670
+ let reparsed = parse3(deduped, toolSchema, {
1671
1671
  onError: options == null ? void 0 : options.onError,
1672
1672
  noChildNodes: []
1673
1673
  });
@@ -1699,7 +1699,7 @@ function processToolCallWithPipeline(params) {
1699
1699
  toolSchema
1700
1700
  );
1701
1701
  const result = applyHeuristicPipeline(ctx, pipelineConfig, {
1702
- parse: (xml, schema) => (0, import_rxml2.parse)(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1702
+ parse: (xml, schema) => parse3(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1703
1703
  onError: options == null ? void 0 : options.onError,
1704
1704
  maxReparses
1705
1705
  });
@@ -1744,7 +1744,7 @@ function handleStreamingToolCallEnd(params) {
1744
1744
  toolSchema
1745
1745
  );
1746
1746
  const result = applyHeuristicPipeline(ctx, pipelineConfig, {
1747
- parse: (xml, schema) => (0, import_rxml2.parse)(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1747
+ parse: (xml, schema) => parse3(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1748
1748
  onError: options == null ? void 0 : options.onError,
1749
1749
  maxReparses
1750
1750
  });
@@ -1752,7 +1752,7 @@ function handleStreamingToolCallEnd(params) {
1752
1752
  } else {
1753
1753
  try {
1754
1754
  const primary = escapeInvalidLt(normalizeCloseTags(toolContent));
1755
- const parsed = (0, import_rxml2.parse)(primary, toolSchema, {
1755
+ const parsed = parse3(primary, toolSchema, {
1756
1756
  onError: options == null ? void 0 : options.onError,
1757
1757
  noChildNodes: []
1758
1758
  });
@@ -1909,7 +1909,7 @@ function findToolCallsForName(text, toolName) {
1909
1909
  const fullTagEnd = findClosingTagEndFlexible(text, contentStart, toolName);
1910
1910
  if (fullTagEnd !== -1 && fullTagEnd > contentStart) {
1911
1911
  const segment = text.substring(tagStart, fullTagEnd);
1912
- const inner = (_a = (0, import_rxml2.extractRawInner)(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
1912
+ const inner = (_a = extractRawInner(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
1913
1913
  toolCalls.push({
1914
1914
  toolName,
1915
1915
  startIndex: tagStart,
@@ -1972,7 +1972,6 @@ function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmitte
1972
1972
  controller.enqueue({
1973
1973
  type: "text-delta",
1974
1974
  id: getCurrentTextId(),
1975
- textDelta: content,
1976
1975
  delta: content
1977
1976
  });
1978
1977
  }
@@ -2134,7 +2133,7 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
2134
2133
  }
2135
2134
  };
2136
2135
  }
2137
- var morphXmlProtocol = (protocolOptions) => {
2136
+ var xmlProtocol = (protocolOptions) => {
2138
2137
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2139
2138
  let pipelineConfig = protocolOptions == null ? void 0 : protocolOptions.pipeline;
2140
2139
  const maxReparses = protocolOptions == null ? void 0 : protocolOptions.maxReparses;
@@ -2174,40 +2173,22 @@ var morphXmlProtocol = (protocolOptions) => {
2174
2173
  }
2175
2174
  return {
2176
2175
  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));
2176
+ return toolSystemPromptTemplate(tools || []);
2183
2177
  },
2184
2178
  formatToolCall(toolCall) {
2185
2179
  let args = {};
2186
- try {
2187
- args = JSON.parse(toolCall.input);
2188
- } catch (e) {
2189
- args = toolCall.input;
2180
+ if (toolCall.input != null) {
2181
+ try {
2182
+ args = JSON.parse(toolCall.input);
2183
+ } catch (e) {
2184
+ args = toolCall.input;
2185
+ }
2190
2186
  }
2191
- return (0, import_rxml2.stringify)(toolCall.toolName, args, {
2187
+ return stringify2(toolCall.toolName, args, {
2192
2188
  suppressEmptyNode: false,
2193
2189
  format: false
2194
2190
  });
2195
2191
  },
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
2192
  parseGeneratedText({ text, tools, options }) {
2212
2193
  const toolNames = tools.map((t) => t.name).filter(Boolean);
2213
2194
  if (toolNames.length === 0) {
@@ -2276,7 +2257,7 @@ var morphXmlProtocol = (protocolOptions) => {
2276
2257
  );
2277
2258
  return new TransformStream({
2278
2259
  transform(chunk, controller) {
2279
- var _a2, _b2;
2260
+ var _a2;
2280
2261
  if (chunk.type !== "text-delta") {
2281
2262
  if (buffer) {
2282
2263
  flushText(controller, buffer);
@@ -2285,7 +2266,7 @@ var morphXmlProtocol = (protocolOptions) => {
2285
2266
  controller.enqueue(chunk);
2286
2267
  return;
2287
2268
  }
2288
- const textContent = (_b2 = (_a2 = chunk.textDelta) != null ? _a2 : chunk.delta) != null ? _b2 : "";
2269
+ const textContent = (_a2 = chunk.delta) != null ? _a2 : "";
2289
2270
  buffer += textContent;
2290
2271
  processBuffer(controller);
2291
2272
  },
@@ -2320,9 +2301,8 @@ var morphXmlProtocol = (protocolOptions) => {
2320
2301
  };
2321
2302
  };
2322
2303
 
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);
2304
+ // src/core/protocols/yaml-protocol.ts
2305
+ import YAML from "yaml";
2326
2306
  var NAME_CHAR_RE3 = /[A-Za-z0-9_:-]/;
2327
2307
  var WHITESPACE_REGEX4 = /\s/;
2328
2308
  var LEADING_WHITESPACE_RE = /^(\s*)/;
@@ -2469,7 +2449,7 @@ function parseYamlContent(yamlContent, options) {
2469
2449
  normalized = lines.map((line) => line.slice(minIndent)).join("\n");
2470
2450
  }
2471
2451
  try {
2472
- const doc = import_yaml.default.parseDocument(normalized);
2452
+ const doc = YAML.parseDocument(normalized);
2473
2453
  if (doc.errors && doc.errors.length > 0) {
2474
2454
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "YAML parse error", {
2475
2455
  errors: doc.errors.map((e) => e.message)
@@ -2542,7 +2522,6 @@ function createFlushTextHandler2(getCurrentTextId, setCurrentTextId, getHasEmitt
2542
2522
  controller.enqueue({
2543
2523
  type: "text-delta",
2544
2524
  id: getCurrentTextId(),
2545
- textDelta: content,
2546
2525
  delta: content
2547
2526
  });
2548
2527
  }
@@ -2590,42 +2569,24 @@ function findEarliestToolTag2(buffer, toolNames) {
2590
2569
  tagLength: bestTagLength
2591
2570
  };
2592
2571
  }
2593
- var yamlXmlProtocol = (_protocolOptions) => {
2572
+ var yamlProtocol = (_protocolOptions) => {
2594
2573
  return {
2595
2574
  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));
2575
+ return toolSystemPromptTemplate(tools || []);
2602
2576
  },
2603
2577
  formatToolCall(toolCall) {
2604
2578
  let args = {};
2605
- try {
2606
- args = JSON.parse(toolCall.input);
2607
- } catch (e) {
2608
- args = { value: toolCall.input };
2579
+ if (toolCall.input != null) {
2580
+ try {
2581
+ args = JSON.parse(toolCall.input);
2582
+ } catch (e) {
2583
+ args = { value: toolCall.input };
2584
+ }
2609
2585
  }
2610
- const yamlContent = import_yaml.default.stringify(args);
2586
+ const yamlContent = YAML.stringify(args);
2611
2587
  return `<${toolCall.toolName}>
2612
2588
  ${yamlContent}</${toolCall.toolName}>`;
2613
2589
  },
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
2590
  parseGeneratedText({ text, tools, options }) {
2630
2591
  const toolNames = tools.map((t) => t.name).filter(Boolean);
2631
2592
  if (toolNames.length === 0) {
@@ -2739,7 +2700,7 @@ ${yamlContent}</${toolCall.toolName}>`;
2739
2700
  };
2740
2701
  return new TransformStream({
2741
2702
  transform(chunk, controller) {
2742
- var _a, _b;
2703
+ var _a;
2743
2704
  if (chunk.type !== "text-delta") {
2744
2705
  if (buffer) {
2745
2706
  flushText(controller, buffer);
@@ -2748,7 +2709,7 @@ ${yamlContent}</${toolCall.toolName}>`;
2748
2709
  controller.enqueue(chunk);
2749
2710
  return;
2750
2711
  }
2751
- const textContent = (_b = (_a = chunk.textDelta) != null ? _a : chunk.delta) != null ? _b : "";
2712
+ const textContent = (_a = chunk.delta) != null ? _a : "";
2752
2713
  buffer += textContent;
2753
2714
  processBuffer(controller);
2754
2715
  },
@@ -2784,48 +2745,62 @@ ${yamlContent}</${toolCall.toolName}>`;
2784
2745
  }
2785
2746
  };
2786
2747
  };
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
2748
 
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
-
2826
- // src/core/protocols/tool-call-protocol.ts
2827
- function isProtocolFactory(protocol) {
2828
- return typeof protocol === "function";
2749
+ // src/core/utils/dynamic-tool-schema.ts
2750
+ function createDynamicIfThenElseSchema(tools) {
2751
+ let currentSchema = {};
2752
+ const toolNames = [];
2753
+ for (let i = tools.length - 1; i >= 0; i -= 1) {
2754
+ const tool = tools[i];
2755
+ if (tool.type === "provider") {
2756
+ throw new Error(
2757
+ "Provider tools are not supported by this middleware. Please use function tools."
2758
+ );
2759
+ }
2760
+ toolNames.unshift(tool.name);
2761
+ const toolCondition = {
2762
+ if: {
2763
+ properties: {
2764
+ name: {
2765
+ const: tool.name
2766
+ }
2767
+ },
2768
+ required: ["name"]
2769
+ },
2770
+ // biome-ignore lint/suspicious/noThenProperty: JSON Schema uses 'then' as a keyword
2771
+ then: {
2772
+ properties: {
2773
+ name: {
2774
+ const: tool.name
2775
+ },
2776
+ arguments: tool.inputSchema
2777
+ },
2778
+ required: ["name", "arguments"]
2779
+ }
2780
+ };
2781
+ if (Object.keys(currentSchema).length > 0) {
2782
+ toolCondition.else = currentSchema;
2783
+ }
2784
+ currentSchema = toolCondition;
2785
+ }
2786
+ return {
2787
+ type: "object",
2788
+ // Explicitly specify type as "object"
2789
+ properties: {
2790
+ name: {
2791
+ type: "string",
2792
+ description: "Name of the tool to call",
2793
+ enum: toolNames
2794
+ },
2795
+ arguments: {
2796
+ type: "object",
2797
+ // By default, arguments is also specified as object type
2798
+ description: "Argument object to be passed to the tool"
2799
+ }
2800
+ },
2801
+ required: ["name", "arguments"],
2802
+ ...currentSchema
2803
+ };
2829
2804
  }
2830
2805
 
2831
2806
  // src/core/utils/on-error.ts
@@ -2861,15 +2836,30 @@ function decodeOriginalTools(originalTools) {
2861
2836
  })
2862
2837
  );
2863
2838
  }
2839
+ function extractToolNamesFromOriginalTools(originalTools) {
2840
+ return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
2841
+ }
2864
2842
  function isToolChoiceActive(params) {
2865
2843
  var _a, _b, _c;
2866
2844
  const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
2867
2845
  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
2846
  }
2869
2847
 
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");
2848
+ // src/core/utils/type-guards.ts
2849
+ function isToolResultPart(content) {
2850
+ if (!content || typeof content !== "object") {
2851
+ return false;
2852
+ }
2853
+ const c = content;
2854
+ return c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
2855
+ }
2856
+ function hasInputProperty(obj) {
2857
+ return typeof obj === "object" && obj !== null && "input" in obj;
2858
+ }
2859
+
2860
+ // src/generate-handler.ts
2861
+ import { generateId as generateId2 } from "@ai-sdk/provider-utils";
2862
+ import { coerceBySchema } from "@ai-sdk-tool/rxml";
2873
2863
  function parseToolChoiceJson(text, providerOptions) {
2874
2864
  var _a;
2875
2865
  try {
@@ -2913,7 +2903,7 @@ async function handleToolChoice(doGenerate, params) {
2913
2903
  }
2914
2904
  const toolCall = {
2915
2905
  type: "tool-call",
2916
- toolCallId: (0, import_provider_utils.generateId)(),
2906
+ toolCallId: generateId2(),
2917
2907
  toolName: parsed.name || "unknown",
2918
2908
  input: JSON.stringify(parsed.arguments || {})
2919
2909
  };
@@ -3020,92 +3010,218 @@ function fixToolCallWithSchema(part, tools) {
3020
3010
  if (part.type !== "tool-call") {
3021
3011
  return part;
3022
3012
  }
3023
- const tc = part;
3024
3013
  let args = {};
3025
- if (typeof tc.input === "string") {
3014
+ if (typeof part.input === "string") {
3026
3015
  try {
3027
- args = JSON.parse(tc.input);
3016
+ args = JSON.parse(part.input);
3028
3017
  } catch (e) {
3029
3018
  return part;
3030
3019
  }
3031
- } else if (tc.input && typeof tc.input === "object") {
3032
- args = tc.input;
3020
+ } else if (part.input && typeof part.input === "object") {
3021
+ args = part.input;
3033
3022
  }
3034
- const schema = (_a = tools.find((t) => t.name === tc.toolName)) == null ? void 0 : _a.inputSchema;
3035
- const coerced = (0, import_rxml4.coerceBySchema)(args, schema);
3023
+ const schema = (_a = tools.find((t) => t.name === part.toolName)) == null ? void 0 : _a.inputSchema;
3024
+ const coerced = coerceBySchema(args, schema);
3036
3025
  return {
3037
3026
  ...part,
3038
3027
  input: JSON.stringify(coerced != null ? coerced : {})
3039
3028
  };
3040
3029
  }
3041
3030
 
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;
3031
+ // src/core/prompts/hermes-system-prompt.ts
3032
+ function hermesSystemPromptTemplate(tools) {
3033
+ const toolsJson = JSON.stringify(tools);
3034
+ return `You are a function calling AI model.
3035
+ You are provided with function signatures within <tools></tools> XML tags.
3036
+ You may call one or more functions to assist with the user query.
3037
+ Don't make assumptions about what values to plug into functions.
3038
+ Here are the available tools: <tools>${toolsJson}</tools>
3039
+ 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"]}
3040
+ For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:
3041
+ <tool_call>
3042
+ {"name": "<function-name>", "arguments": <args-dict>}
3043
+ </tool_call>`;
3044
+ }
3045
+
3046
+ // src/core/prompts/tool-response.ts
3047
+ function unwrapToolResult(result) {
3048
+ var _a, _b;
3049
+ switch (result.type) {
3050
+ case "text":
3051
+ return (_a = result.value) != null ? _a : "";
3052
+ case "json":
3053
+ return result.value;
3054
+ case "execution-denied": {
3055
+ const reason = result.reason;
3056
+ return reason ? `[Execution Denied: ${reason}]` : "[Execution Denied]";
3057
+ }
3058
+ case "error-text":
3059
+ return `[Error: ${(_b = result.value) != null ? _b : ""}]`;
3060
+ case "error-json":
3061
+ return `[Error: ${JSON.stringify(result.value)}]`;
3062
+ case "content": {
3063
+ return result.value.map((part) => {
3064
+ var _a2;
3065
+ const contentPart = part;
3066
+ switch (contentPart.type) {
3067
+ case "text":
3068
+ return (_a2 = contentPart.text) != null ? _a2 : "";
3069
+ case "image-data":
3070
+ return `[Image: ${contentPart.mediaType}]`;
3071
+ case "image-url":
3072
+ return `[Image URL: ${contentPart.url}]`;
3073
+ case "image-file-id": {
3074
+ const fileId = contentPart.fileId;
3075
+ const displayId = typeof fileId === "string" ? fileId : JSON.stringify(fileId);
3076
+ return `[Image ID: ${displayId}]`;
3077
+ }
3078
+ case "file-data": {
3079
+ const filePart = contentPart;
3080
+ if (filePart.filename) {
3081
+ return `[File: ${filePart.filename} (${filePart.mediaType})]`;
3082
+ }
3083
+ return `[File: ${filePart.mediaType}]`;
3084
+ }
3085
+ case "file-url":
3086
+ return `[File URL: ${contentPart.url}]`;
3087
+ case "file-id": {
3088
+ const fileId = contentPart.fileId;
3089
+ const displayId = typeof fileId === "string" ? fileId : JSON.stringify(fileId);
3090
+ return `[File ID: ${displayId}]`;
3091
+ }
3092
+ case "media":
3093
+ return `[Media: ${contentPart.mediaType}]`;
3094
+ case "custom":
3095
+ return "[Custom content]";
3096
+ default:
3097
+ return "[Unknown content]";
3098
+ }
3099
+ }).join("\n");
3100
+ }
3101
+ default: {
3102
+ const _exhaustive = result;
3103
+ return _exhaustive;
3104
+ }
3079
3105
  }
3080
3106
  }
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
- };
3107
+ function formatToolResponseAsJsonInXml(toolResult) {
3108
+ const unwrappedResult = unwrapToolResult(toolResult.output);
3109
+ return `<tool_response>${JSON.stringify({
3110
+ toolName: toolResult.toolName,
3111
+ result: unwrappedResult
3112
+ })}</tool_response>`;
3113
+ }
3114
+ function formatToolResponseAsXml(toolResult) {
3115
+ const unwrappedResult = unwrapToolResult(toolResult.output);
3116
+ const toolNameXml = `<tool_name>${toolResult.toolName}</tool_name>`;
3117
+ const resultLines = formatXmlNode("result", unwrappedResult, 1);
3118
+ return [
3119
+ "<tool_response>",
3120
+ ` ${toolNameXml}`,
3121
+ ...resultLines,
3122
+ "</tool_response>"
3123
+ ].join("\n");
3124
+ }
3125
+ function formatXmlNode(tagName, value, depth) {
3126
+ const indent = " ".repeat(depth);
3127
+ if (value === null || value === void 0) {
3128
+ return [`${indent}<${tagName}></${tagName}>`];
3129
+ }
3130
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3131
+ return [`${indent}<${tagName}>${String(value)}</${tagName}>`];
3132
+ }
3133
+ if (Array.isArray(value)) {
3134
+ if (value.length === 0) {
3135
+ return [`${indent}<${tagName}></${tagName}>`];
3104
3136
  }
3105
- default:
3106
- return p;
3137
+ const lines2 = [`${indent}<${tagName}>`];
3138
+ for (const item of value) {
3139
+ lines2.push(...formatXmlNode("item", item, depth + 1));
3140
+ }
3141
+ lines2.push(`${indent}</${tagName}>`);
3142
+ return lines2;
3143
+ }
3144
+ const entries = Object.entries(value);
3145
+ if (entries.length === 0) {
3146
+ return [`${indent}<${tagName}></${tagName}>`];
3147
+ }
3148
+ const lines = [`${indent}<${tagName}>`];
3149
+ for (const [key, entryValue] of entries) {
3150
+ lines.push(...formatXmlNode(key, entryValue, depth + 1));
3107
3151
  }
3152
+ lines.push(`${indent}</${tagName}>`);
3153
+ return lines;
3154
+ }
3155
+
3156
+ // src/core/prompts/xml-system-prompt.ts
3157
+ function xmlSystemPromptTemplate(tools) {
3158
+ const toolsJson = JSON.stringify(tools);
3159
+ return `# Tools
3160
+
3161
+ You may call one or more functions to assist with the user query.
3162
+
3163
+ You are provided with function signatures within <tools></tools> XML tags:
3164
+ <tools>${toolsJson}</tools>
3165
+
3166
+ # Rules
3167
+ - Use exactly one XML element whose tag name is the function name.
3168
+ - Put each parameter as a child element.
3169
+ - Values must follow the schema exactly (numbers, arrays, objects, enums \u2192 copy as-is).
3170
+ - Do not add or remove functions or parameters.
3171
+ - Each required parameter must appear once.
3172
+ - Output nothing before or after the function call.
3173
+ - 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.
3174
+
3175
+ # Example
3176
+ <get_weather>
3177
+ <location>New York</location>
3178
+ <unit>celsius</unit>
3179
+ </get_weather>`;
3180
+ }
3181
+
3182
+ // src/core/prompts/yaml-system-prompt.ts
3183
+ function yamlSystemPromptTemplate(tools, includeMultilineExample = true) {
3184
+ const toolsJson = JSON.stringify(tools);
3185
+ const multilineExample = includeMultilineExample ? `
3186
+
3187
+ For multiline values, use YAML's literal block syntax:
3188
+ <write_file>
3189
+ file_path: /tmp/example.txt
3190
+ contents: |
3191
+ First line
3192
+ Second line
3193
+ Third line
3194
+ </write_file>` : "";
3195
+ return `# Tools
3196
+
3197
+ You may call one or more functions to assist with the user query.
3198
+
3199
+ You are provided with function signatures within <tools></tools> XML tags:
3200
+ <tools>${toolsJson}</tools>
3201
+
3202
+ # Format
3203
+
3204
+ Use exactly one XML element whose tag name is the function name.
3205
+ Inside the XML element, specify parameters using YAML syntax (key: value pairs).
3206
+
3207
+ # Example
3208
+ <get_weather>
3209
+ location: New York
3210
+ unit: celsius
3211
+ </get_weather>${multilineExample}
3212
+
3213
+ # Rules
3214
+ - Parameter names and values must follow the schema exactly.
3215
+ - Use proper YAML syntax for values (strings, numbers, booleans, arrays, objects).
3216
+ - Each required parameter must appear once.
3217
+ - Do not add functions or parameters not in the schema.
3218
+ - After calling a tool, you will receive a response. Use this result to answer the user.
3219
+ - Do NOT ask clarifying questions. Use reasonable defaults for optional parameters.
3220
+ - If a task requires multiple function calls, make ALL of them at once.`;
3108
3221
  }
3222
+
3223
+ // src/stream-handler.ts
3224
+ import { generateId as generateId3 } from "@ai-sdk/provider-utils";
3109
3225
  async function wrapStream({
3110
3226
  protocol,
3111
3227
  doStream,
@@ -3129,23 +3245,24 @@ async function wrapStream({
3129
3245
  ...((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) || {}
3130
3246
  };
3131
3247
  const coreStream = stream.pipeThrough(
3132
- new TransformStream({
3133
- transform(part, controller) {
3134
- if (debugLevel === "stream") {
3135
- logRawChunk(part);
3248
+ new TransformStream(
3249
+ {
3250
+ transform(part, controller) {
3251
+ if (debugLevel === "stream") {
3252
+ logRawChunk(part);
3253
+ }
3254
+ controller.enqueue(part);
3136
3255
  }
3137
- controller.enqueue(mapV3PartToCore(part));
3138
3256
  }
3139
- })
3257
+ )
3140
3258
  ).pipeThrough(protocol.createStreamParser({ tools, options }));
3141
3259
  const v3Stream = coreStream.pipeThrough(
3142
3260
  new TransformStream({
3143
3261
  transform(part, controller) {
3144
- const v3Part = mapCorePartToV3(part);
3145
3262
  if (debugLevel === "stream") {
3146
- logParsedChunk(v3Part);
3263
+ logParsedChunk(part);
3147
3264
  }
3148
- controller.enqueue(v3Part);
3265
+ controller.enqueue(part);
3149
3266
  }
3150
3267
  })
3151
3268
  );
@@ -3180,7 +3297,7 @@ async function toolChoiceStream({
3180
3297
  start(controller) {
3181
3298
  controller.enqueue({
3182
3299
  type: "tool-call",
3183
- toolCallId: (0, import_provider_utils2.generateId)(),
3300
+ toolCallId: generateId3(),
3184
3301
  toolName: toolJson.name || "unknown",
3185
3302
  input: JSON.stringify(toolJson.arguments || {})
3186
3303
  });
@@ -3202,70 +3319,7 @@ async function toolChoiceStream({
3202
3319
  };
3203
3320
  }
3204
3321
 
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
3322
+ // src/transform-handler.ts
3269
3323
  function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
3270
3324
  const systemIndex = processedPrompt.findIndex((m) => m.role === "system");
3271
3325
  if (systemIndex !== -1) {
@@ -3408,10 +3462,11 @@ function transformParams({
3408
3462
  params,
3409
3463
  protocol,
3410
3464
  toolSystemPromptTemplate,
3465
+ toolResponsePromptTemplate,
3411
3466
  placement = "first"
3412
3467
  }) {
3413
- var _a, _b, _c, _d, _e;
3414
- const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
3468
+ var _a, _b, _c, _d;
3469
+ const resolvedProtocol = isTCMProtocolFactory(protocol) ? protocol() : protocol;
3415
3470
  const functionTools = ((_a = params.tools) != null ? _a : []).filter(
3416
3471
  (t) => t.type === "function"
3417
3472
  );
@@ -3419,9 +3474,18 @@ function transformParams({
3419
3474
  tools: functionTools,
3420
3475
  toolSystemPromptTemplate
3421
3476
  });
3477
+ let normalizedPrompt;
3478
+ if (Array.isArray(params.prompt)) {
3479
+ normalizedPrompt = params.prompt;
3480
+ } else if (params.prompt) {
3481
+ normalizedPrompt = [params.prompt];
3482
+ } else {
3483
+ normalizedPrompt = [];
3484
+ }
3422
3485
  const processedPrompt = convertToolPrompt(
3423
- (_b = params.prompt) != null ? _b : [],
3486
+ normalizedPrompt,
3424
3487
  resolvedProtocol,
3488
+ toolResponsePromptTemplate,
3425
3489
  extractOnErrorOption(params.providerOptions)
3426
3490
  );
3427
3491
  const finalPrompt = buildFinalPrompt(
@@ -3434,15 +3498,15 @@ function transformParams({
3434
3498
  finalPrompt,
3435
3499
  functionTools
3436
3500
  );
3437
- if (((_c = params.toolChoice) == null ? void 0 : _c.type) === "none") {
3501
+ if (((_b = params.toolChoice) == null ? void 0 : _b.type) === "none") {
3438
3502
  throw new Error(
3439
3503
  "The 'none' toolChoice type is not supported by this middleware. Please use 'auto', 'required', or specify a tool name."
3440
3504
  );
3441
3505
  }
3442
- if (((_d = params.toolChoice) == null ? void 0 : _d.type) === "tool") {
3506
+ if (((_c = params.toolChoice) == null ? void 0 : _c.type) === "tool") {
3443
3507
  return handleToolChoiceTool(params, baseReturnParams);
3444
3508
  }
3445
- if (((_e = params.toolChoice) == null ? void 0 : _e.type) === "required") {
3509
+ if (((_d = params.toolChoice) == null ? void 0 : _d.type) === "required") {
3446
3510
  return handleToolChoiceRequired(params, baseReturnParams, functionTools);
3447
3511
  }
3448
3512
  return baseReturnParams;
@@ -3451,26 +3515,29 @@ function processAssistantContent(content, resolvedProtocol, providerOptions) {
3451
3515
  var _a;
3452
3516
  const newContent = [];
3453
3517
  for (const item of content) {
3454
- if (isToolCallContent(item)) {
3455
- newContent.push({
3456
- type: "text",
3457
- text: resolvedProtocol.formatToolCall(item)
3458
- });
3459
- } else if (item.type === "text") {
3460
- newContent.push(item);
3461
- } else if (item.type === "reasoning") {
3462
- newContent.push(item);
3463
- } else {
3464
- const options = extractOnErrorOption(providerOptions);
3465
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
3466
- options,
3467
- "tool-call-middleware: unknown assistant content; stringifying for provider compatibility",
3468
- { content: item }
3469
- );
3470
- newContent.push({
3471
- type: "text",
3472
- text: JSON.stringify(item)
3473
- });
3518
+ switch (item.type) {
3519
+ case "tool-call":
3520
+ newContent.push({
3521
+ type: "text",
3522
+ text: resolvedProtocol.formatToolCall(item)
3523
+ });
3524
+ break;
3525
+ case "text":
3526
+ case "reasoning":
3527
+ newContent.push(item);
3528
+ break;
3529
+ default: {
3530
+ const options = extractOnErrorOption(providerOptions);
3531
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
3532
+ options,
3533
+ "tool-call-middleware: unknown assistant content; stringifying for provider compatibility",
3534
+ { content: item }
3535
+ );
3536
+ newContent.push({
3537
+ type: "text",
3538
+ text: JSON.stringify(item)
3539
+ });
3540
+ }
3474
3541
  }
3475
3542
  }
3476
3543
  const onlyText = newContent.every((c) => c.type === "text");
@@ -3481,25 +3548,28 @@ function processAssistantContent(content, resolvedProtocol, providerOptions) {
3481
3548
  }
3482
3549
  ] : newContent;
3483
3550
  }
3484
- function processToolMessage(content, resolvedProtocol) {
3551
+ function formatApprovalResponse(part) {
3552
+ const status = part.approved ? "Approved" : "Denied";
3553
+ const reason = part.reason ? `: ${part.reason}` : "";
3554
+ return `[Tool Approval ${status}${reason}]`;
3555
+ }
3556
+ function processToolMessage(toolResults, approvalResponses, toolResponsePromptTemplate) {
3557
+ const resultTexts = toolResults.map((toolResult) => {
3558
+ return toolResponsePromptTemplate(toolResult);
3559
+ });
3560
+ const approvalTexts = approvalResponses.map(formatApprovalResponse);
3561
+ const allTexts = [...resultTexts, ...approvalTexts];
3485
3562
  return {
3486
3563
  role: "user",
3487
3564
  content: [
3488
3565
  {
3489
3566
  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")
3567
+ text: allTexts.join("\n")
3498
3568
  }
3499
3569
  ]
3500
3570
  };
3501
3571
  }
3502
- function processMessage(message, resolvedProtocol, providerOptions) {
3572
+ function processMessage(message, resolvedProtocol, providerOptions, toolResponsePromptTemplate) {
3503
3573
  if (message.role === "assistant") {
3504
3574
  const condensedContent = processAssistantContent(
3505
3575
  message.content,
@@ -3512,10 +3582,23 @@ function processMessage(message, resolvedProtocol, providerOptions) {
3512
3582
  };
3513
3583
  }
3514
3584
  if (message.role === "tool") {
3515
- const toolResultParts = message.content.filter(
3585
+ const toolContent = message.content;
3586
+ const toolResultParts = toolContent.filter(
3516
3587
  (part) => part.type === "tool-result"
3517
3588
  );
3518
- return processToolMessage(toolResultParts, resolvedProtocol);
3589
+ const approvalResponseParts = toolContent.filter(
3590
+ (part) => part.type === "tool-approval-response"
3591
+ );
3592
+ if (!toolResponsePromptTemplate) {
3593
+ throw new Error(
3594
+ '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.'
3595
+ );
3596
+ }
3597
+ return processToolMessage(
3598
+ toolResultParts,
3599
+ approvalResponseParts,
3600
+ toolResponsePromptTemplate
3601
+ );
3519
3602
  }
3520
3603
  return message;
3521
3604
  }
@@ -3578,22 +3661,28 @@ ${currentContent}` }]
3578
3661
  }
3579
3662
  return processedPrompt;
3580
3663
  }
3581
- function convertToolPrompt(prompt, resolvedProtocol, providerOptions) {
3664
+ function convertToolPrompt(prompt, resolvedProtocol, toolResponsePromptTemplate, providerOptions) {
3582
3665
  let processedPrompt = prompt.map(
3583
- (message) => processMessage(message, resolvedProtocol, providerOptions)
3666
+ (message) => processMessage(
3667
+ message,
3668
+ resolvedProtocol,
3669
+ providerOptions,
3670
+ toolResponsePromptTemplate
3671
+ )
3584
3672
  );
3585
3673
  processedPrompt = condenseTextContent(processedPrompt);
3586
3674
  processedPrompt = mergeConsecutiveUserMessages(processedPrompt);
3587
3675
  return processedPrompt;
3588
3676
  }
3589
3677
 
3590
- // src/v6/tool-call-middleware.ts
3678
+ // src/tool-call-middleware.ts
3591
3679
  function createToolMiddleware({
3592
3680
  protocol,
3593
3681
  toolSystemPromptTemplate,
3682
+ toolResponsePromptTemplate,
3594
3683
  placement = "last"
3595
3684
  }) {
3596
- const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
3685
+ const resolvedProtocol = isTCMProtocolFactory(protocol) ? protocol() : protocol;
3597
3686
  return {
3598
3687
  specificationVersion: "v3",
3599
3688
  wrapStream: ({ doStream, doGenerate, params }) => {
@@ -3618,83 +3707,71 @@ function createToolMiddleware({
3618
3707
  transformParams: async ({ params }) => transformParams({
3619
3708
  protocol: resolvedProtocol,
3620
3709
  toolSystemPromptTemplate,
3710
+ toolResponsePromptTemplate,
3621
3711
  placement,
3622
3712
  params
3623
3713
  })
3624
3714
  };
3625
3715
  }
3626
3716
 
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
- });
3717
+ // src/preconfigured-middleware.ts
3645
3718
  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
- }
3719
+ protocol: jsonProtocol({}),
3720
+ toolSystemPromptTemplate: hermesSystemPromptTemplate,
3721
+ toolResponsePromptTemplate: formatToolResponseAsJsonInXml
3659
3722
  });
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
- }
3723
+ var xmlToolMiddleware = createToolMiddleware({
3724
+ protocol: xmlProtocol({}),
3725
+ toolSystemPromptTemplate: xmlSystemPromptTemplate,
3726
+ toolResponsePromptTemplate: formatToolResponseAsXml
3686
3727
  });
3687
- var orchestratorToolMiddleware = createToolMiddleware({
3688
- protocol: yamlXmlProtocol(),
3689
- placement: "first",
3690
- toolSystemPromptTemplate: orchestratorSystemPromptTemplate
3728
+ var yamlToolMiddleware = createToolMiddleware({
3729
+ protocol: yamlProtocol({}),
3730
+ toolSystemPromptTemplate: yamlSystemPromptTemplate,
3731
+ toolResponsePromptTemplate: formatToolResponseAsXml
3691
3732
  });
3692
- // Annotate the CommonJS export names for ESM import in node:
3693
- 0 && (module.exports = {
3733
+
3734
+ export {
3735
+ applyHeuristicPipeline,
3736
+ createIntermediateCall,
3737
+ mergePipelineConfigs,
3738
+ normalizeCloseTagsHeuristic,
3739
+ escapeInvalidLtHeuristic,
3740
+ balanceTagsHeuristic,
3741
+ dedupeShellStringTagsHeuristic,
3742
+ repairAgainstSchemaHeuristic,
3743
+ defaultPipelineConfig,
3744
+ getDebugLevel,
3745
+ logParseFailure,
3746
+ logRawChunk,
3747
+ logParsedChunk,
3748
+ logParsedSummary,
3749
+ getPotentialStartIndex,
3750
+ escapeRegExp2 as escapeRegExp,
3751
+ transform,
3752
+ parse2 as parse,
3753
+ stringify,
3754
+ jsonProtocol,
3755
+ isProtocolFactory,
3756
+ isTCMProtocolFactory,
3757
+ xmlProtocol,
3758
+ yamlProtocol,
3759
+ createDynamicIfThenElseSchema,
3760
+ extractOnErrorOption,
3761
+ originalToolsSchema,
3762
+ encodeOriginalTools,
3763
+ decodeOriginalTools,
3764
+ extractToolNamesFromOriginalTools,
3765
+ isToolChoiceActive,
3766
+ isToolResultPart,
3767
+ hasInputProperty,
3768
+ wrapGenerate,
3769
+ wrapStream,
3770
+ toolChoiceStream,
3771
+ transformParams,
3694
3772
  createToolMiddleware,
3695
- gemmaToolMiddleware,
3696
3773
  hermesToolMiddleware,
3697
- morphXmlToolMiddleware,
3698
- orchestratorToolMiddleware
3699
- });
3700
- //# sourceMappingURL=v6.cjs.map
3774
+ xmlToolMiddleware,
3775
+ yamlToolMiddleware
3776
+ };
3777
+ //# sourceMappingURL=chunk-WX5U7G6L.js.map