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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,5 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- // src/protocols/dummy-protocol.ts
8
- import { generateId } from "@ai-sdk/provider-utils";
9
-
10
1
  // src/protocols/json-mix-protocol.ts
11
- import { generateId as generateId2 } from "@ai-sdk/provider-utils";
2
+ import { generateId } from "@ai-sdk/provider-utils";
12
3
 
13
4
  // src/utils/debug.ts
14
5
  var LINE_SPLIT_REGEX = /\r?\n/;
@@ -56,6 +47,7 @@ var cBgGreen = color(ANSI_BG_GREEN);
56
47
  var cInverse = color(ANSI_INVERSE);
57
48
  var cUnderline = color(ANSI_UNDERLINE);
58
49
  var cBold = color(ANSI_BOLD);
50
+ var MAX_SNIPPET_LENGTH = 800;
59
51
  function safeStringify(value) {
60
52
  try {
61
53
  return `
@@ -64,6 +56,41 @@ ${typeof value === "string" ? value : JSON.stringify(value, null, 2)}`;
64
56
  return String(value);
65
57
  }
66
58
  }
59
+ function formatError(error) {
60
+ if (error instanceof Error) {
61
+ const stack = error.stack ? `
62
+ ${error.stack}` : "";
63
+ return `
64
+ ${error.name}: ${error.message}${stack}`;
65
+ }
66
+ return safeStringify(error);
67
+ }
68
+ function truncateSnippet(snippet) {
69
+ if (snippet.length <= MAX_SNIPPET_LENGTH) {
70
+ return snippet;
71
+ }
72
+ return `${snippet.slice(0, MAX_SNIPPET_LENGTH)}
73
+ \u2026[truncated ${snippet.length - MAX_SNIPPET_LENGTH} chars]`;
74
+ }
75
+ function logParseFailure({
76
+ phase,
77
+ reason,
78
+ snippet,
79
+ error
80
+ }) {
81
+ if (getDebugLevel() !== "parse") {
82
+ return;
83
+ }
84
+ const label = cBgBlue(`[${phase}]`);
85
+ console.log(cGray("[debug:mw:fail]"), label, cYellow(reason));
86
+ if (snippet) {
87
+ const formatted = truncateSnippet(snippet);
88
+ console.log(cGray("[debug:mw:fail:snippet]"), formatted);
89
+ }
90
+ if (error) {
91
+ console.log(cGray("[debug:mw:fail:error]"), cCyan(formatError(error)));
92
+ }
93
+ }
67
94
  function logRawChunk(part) {
68
95
  console.log(cGray("[debug:mw:raw]"), cYellow(safeStringify(part)));
69
96
  }
@@ -129,63 +156,6 @@ ${rendered}`);
129
156
  }
130
157
  }
131
158
 
132
- // src/utils/dynamic-tool-schema.ts
133
- function createDynamicIfThenElseSchema(tools) {
134
- let currentSchema = {};
135
- const toolNames = [];
136
- for (let i = tools.length - 1; i >= 0; i -= 1) {
137
- const tool = tools[i];
138
- if (tool.type === "provider-defined") {
139
- throw new Error(
140
- "Provider-defined tools are not supported by this middleware. Please use custom tools."
141
- );
142
- }
143
- toolNames.unshift(tool.name);
144
- const toolCondition = {
145
- if: {
146
- properties: {
147
- name: {
148
- const: tool.name
149
- }
150
- },
151
- required: ["name"]
152
- },
153
- // biome-ignore lint/suspicious/noThenProperty: JSON Schema uses 'then' as a keyword
154
- then: {
155
- properties: {
156
- name: {
157
- const: tool.name
158
- },
159
- arguments: tool.inputSchema
160
- },
161
- required: ["name", "arguments"]
162
- }
163
- };
164
- if (Object.keys(currentSchema).length > 0) {
165
- toolCondition.else = currentSchema;
166
- }
167
- currentSchema = toolCondition;
168
- }
169
- return {
170
- type: "object",
171
- // Explicitly specify type as "object"
172
- properties: {
173
- name: {
174
- type: "string",
175
- description: "Name of the tool to call",
176
- enum: toolNames
177
- },
178
- arguments: {
179
- type: "object",
180
- // By default, arguments is also specified as object type
181
- description: "Argument object to be passed to the tool"
182
- }
183
- },
184
- required: ["name", "arguments"],
185
- ...currentSchema
186
- };
187
- }
188
-
189
159
  // src/utils/get-potential-start-index.ts
190
160
  function getPotentialStartIndex(text, searchedText) {
191
161
  if (searchedText.length === 0) {
@@ -204,60 +174,12 @@ function getPotentialStartIndex(text, searchedText) {
204
174
  return null;
205
175
  }
206
176
 
207
- // src/utils/on-error.ts
208
- function extractOnErrorOption(providerOptions) {
209
- var _a;
210
- if (providerOptions && typeof providerOptions === "object") {
211
- const onError = (_a = providerOptions.toolCallMiddleware) == null ? void 0 : _a.onError;
212
- return onError ? { onError } : void 0;
213
- }
214
- return;
215
- }
216
-
217
- // src/utils/provider-options.ts
218
- var originalToolsSchema = {
219
- encode: encodeOriginalTools,
220
- decode: decodeOriginalTools
221
- };
222
- function encodeOriginalTools(tools) {
223
- return (tools == null ? void 0 : tools.map((t) => ({
224
- name: t.name,
225
- inputSchema: JSON.stringify(t.inputSchema)
226
- }))) || [];
227
- }
228
- function decodeOriginalTools(originalTools) {
229
- if (!originalTools) {
230
- return [];
231
- }
232
- return originalTools.map(
233
- (t) => ({
234
- type: "function",
235
- name: t.name,
236
- inputSchema: JSON.parse(t.inputSchema)
237
- })
238
- );
239
- }
240
- function extractToolNamesFromOriginalTools(originalTools) {
241
- return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
242
- }
243
- function isToolChoiceActive(params) {
244
- var _a, _b, _c;
245
- const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
246
- 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"));
247
- }
248
-
249
177
  // src/utils/regex.ts
250
178
  function escapeRegExp(literal) {
251
179
  return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
252
180
  }
253
181
 
254
182
  // src/utils/robust-json.ts
255
- var robust_json_exports = {};
256
- __export(robust_json_exports, {
257
- parse: () => parse,
258
- stringify: () => stringify,
259
- transform: () => transform
260
- });
261
183
  var WHITESPACE_TEST_REGEX = /\s/;
262
184
  var WHITESPACE_REGEX = /^\s+/;
263
185
  var OBJECT_START_REGEX = /^\{/;
@@ -922,19 +844,6 @@ function stringify(obj) {
922
844
  return "null";
923
845
  }
924
846
 
925
- // src/utils/type-guards.ts
926
- function isToolCallContent(content) {
927
- return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
928
- (typeof content.input === "string" || typeof content.input === "object");
929
- }
930
- function isToolResultPart(content) {
931
- const c = content;
932
- return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
933
- }
934
- function hasInputProperty(obj) {
935
- return typeof obj === "object" && obj !== null && "input" in obj;
936
- }
937
-
938
847
  // src/protocols/json-mix-protocol.ts
939
848
  function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
940
849
  var _a;
@@ -942,11 +851,17 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
942
851
  const parsedToolCall = parse(toolCallJson);
943
852
  processedElements.push({
944
853
  type: "tool-call",
945
- toolCallId: generateId2(),
854
+ toolCallId: generateId(),
946
855
  toolName: parsedToolCall.name,
947
856
  input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
948
857
  });
949
858
  } catch (error) {
859
+ logParseFailure({
860
+ phase: "generated-text",
861
+ reason: "Failed to parse tool call JSON segment",
862
+ snippet: fullMatch,
863
+ error
864
+ });
950
865
  if (options == null ? void 0 : options.onError) {
951
866
  options.onError(
952
867
  "Could not process JSON tool call, keeping original text.",
@@ -979,7 +894,7 @@ function flushBuffer(state, controller, toolCallStart) {
979
894
  return;
980
895
  }
981
896
  if (!state.currentTextId) {
982
- state.currentTextId = generateId2();
897
+ state.currentTextId = generateId();
983
898
  controller.enqueue({ type: "text-start", id: state.currentTextId });
984
899
  state.hasEmittedTextStart = true;
985
900
  }
@@ -1002,7 +917,12 @@ function emitIncompleteToolCall(state, controller, toolCallStart) {
1002
917
  if (!state.currentToolCallJson) {
1003
918
  return;
1004
919
  }
1005
- const errorId = generateId2();
920
+ logParseFailure({
921
+ phase: "stream",
922
+ reason: "Incomplete streaming tool call segment emitted as text",
923
+ snippet: `${toolCallStart}${state.currentToolCallJson}`
924
+ });
925
+ const errorId = generateId();
1006
926
  controller.enqueue({ type: "text-start", id: errorId });
1007
927
  controller.enqueue({
1008
928
  type: "text-delta",
@@ -1026,7 +946,7 @@ function publishText(text, state, controller) {
1026
946
  state.currentToolCallJson += text;
1027
947
  } else if (text.length > 0) {
1028
948
  if (!state.currentTextId) {
1029
- state.currentTextId = generateId2();
949
+ state.currentTextId = generateId();
1030
950
  controller.enqueue({ type: "text-start", id: state.currentTextId });
1031
951
  state.hasEmittedTextStart = true;
1032
952
  }
@@ -1041,16 +961,22 @@ function emitToolCall(context) {
1041
961
  var _a;
1042
962
  const { state, controller, toolCallStart, toolCallEnd, options } = context;
1043
963
  try {
1044
- const parsedToolCall = robust_json_exports.parse(state.currentToolCallJson);
964
+ const parsedToolCall = parse(state.currentToolCallJson);
1045
965
  closeTextBlock(state, controller);
1046
966
  controller.enqueue({
1047
967
  type: "tool-call",
1048
- toolCallId: generateId2(),
968
+ toolCallId: generateId(),
1049
969
  toolName: parsedToolCall.name,
1050
970
  input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1051
971
  });
1052
- } catch (e) {
1053
- const errorId = generateId2();
972
+ } catch (error) {
973
+ logParseFailure({
974
+ phase: "stream",
975
+ reason: "Failed to parse streaming tool call JSON segment",
976
+ snippet: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`,
977
+ error
978
+ });
979
+ const errorId = generateId();
1054
980
  controller.enqueue({ type: "text-start", id: errorId });
1055
981
  controller.enqueue({
1056
982
  type: "text-delta",
@@ -1215,10 +1141,9 @@ var jsonMixProtocol = ({
1215
1141
  });
1216
1142
 
1217
1143
  // src/protocols/morph-xml-protocol.ts
1218
- import { generateId as generateId3 } from "@ai-sdk/provider-utils";
1144
+ import { generateId as generateId2 } from "@ai-sdk/provider-utils";
1219
1145
  import {
1220
1146
  extractRawInner,
1221
- findFirstTopLevelRange,
1222
1147
  parse as parse2,
1223
1148
  RXMLCoercionError,
1224
1149
  RXMLDuplicateStringTagError,
@@ -1226,7 +1151,338 @@ import {
1226
1151
  stringify as stringify2,
1227
1152
  unwrapJsonSchema
1228
1153
  } from "@ai-sdk-tool/rxml";
1154
+
1155
+ // src/utils/type-guards.ts
1156
+ function isToolCallContent(content) {
1157
+ return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
1158
+ (typeof content.input === "string" || typeof content.input === "object");
1159
+ }
1160
+ function isToolResultPart(content) {
1161
+ const c = content;
1162
+ return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
1163
+ }
1164
+ function hasInputProperty(obj) {
1165
+ return typeof obj === "object" && obj !== null && "input" in obj;
1166
+ }
1167
+
1168
+ // src/protocols/morph-xml-protocol.ts
1229
1169
  var WHITESPACE_REGEX2 = /\s/;
1170
+ var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
1171
+ var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
1172
+ var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
1173
+ var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
1174
+ var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
1175
+ var STATUS_TAG_RE = /<status>([\s\S]*?)<\/status>/i;
1176
+ function normalizeCloseTags(xml) {
1177
+ return xml.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1178
+ }
1179
+ function escapeInvalidLt(xml) {
1180
+ const len = xml.length;
1181
+ let out = "";
1182
+ for (let i = 0; i < len; i += 1) {
1183
+ const ch = xml[i];
1184
+ if (ch === "<") {
1185
+ const next = i + 1 < len ? xml[i + 1] : "";
1186
+ if (!(NAME_CHAR_RE.test(next) || next === "/" || next === "!" || next === "?")) {
1187
+ out += "&lt;";
1188
+ continue;
1189
+ }
1190
+ }
1191
+ out += ch;
1192
+ }
1193
+ return out;
1194
+ }
1195
+ function shouldDeduplicateStringTags(schema) {
1196
+ const unwrapped = unwrapJsonSchema(schema);
1197
+ if (!unwrapped || typeof unwrapped !== "object") {
1198
+ return false;
1199
+ }
1200
+ const props = unwrapped.properties;
1201
+ if (!props) {
1202
+ return false;
1203
+ }
1204
+ const commandRaw = props.command;
1205
+ if (!commandRaw) {
1206
+ return false;
1207
+ }
1208
+ const command = unwrapJsonSchema(commandRaw);
1209
+ return (command == null ? void 0 : command.type) === "array";
1210
+ }
1211
+ function tryParseSecondaryXml(content, toolSchema, options) {
1212
+ const normalized = normalizeCloseTags(content);
1213
+ const balanced = balanceTags(content);
1214
+ const hasMalformedClose = MALFORMED_CLOSE_RE.test(content);
1215
+ if (!hasMalformedClose && balanced.length > normalized.length) {
1216
+ return null;
1217
+ }
1218
+ try {
1219
+ let parsed = parse2(balanced, toolSchema, {
1220
+ onError: options == null ? void 0 : options.onError,
1221
+ noChildNodes: []
1222
+ });
1223
+ parsed = repairParsedAgainstSchema(parsed, toolSchema, options);
1224
+ return parsed;
1225
+ } catch (_e) {
1226
+ if (shouldDeduplicateStringTags(toolSchema)) {
1227
+ const deduped = dedupeStringTagsAgainstSchema(balanced, toolSchema);
1228
+ if (deduped !== balanced) {
1229
+ try {
1230
+ let reparsed = parse2(deduped, toolSchema, {
1231
+ onError: options == null ? void 0 : options.onError,
1232
+ noChildNodes: []
1233
+ });
1234
+ reparsed = repairParsedAgainstSchema(reparsed, toolSchema, options);
1235
+ return reparsed;
1236
+ } catch (_) {
1237
+ return null;
1238
+ }
1239
+ }
1240
+ }
1241
+ return null;
1242
+ }
1243
+ }
1244
+ function balanceTags(xml) {
1245
+ const src = normalizeCloseTags(xml).replace(
1246
+ STATUS_TO_STEP_BOUNDARY_RE,
1247
+ "</status></step><step>"
1248
+ );
1249
+ let i = 0;
1250
+ const len = src.length;
1251
+ const out = [];
1252
+ const stack = [];
1253
+ while (i < len) {
1254
+ const lt = src.indexOf("<", i);
1255
+ if (lt === -1) {
1256
+ out.push(src.slice(i));
1257
+ break;
1258
+ }
1259
+ out.push(src.slice(i, lt));
1260
+ if (lt + 1 >= len) {
1261
+ break;
1262
+ }
1263
+ const next = src[lt + 1];
1264
+ if (next === "!" || next === "?") {
1265
+ i = handleSpecialTagSegment(src, lt, out);
1266
+ continue;
1267
+ }
1268
+ if (next === "/") {
1269
+ i = handleClosingTagSegment(src, lt, out, stack);
1270
+ continue;
1271
+ }
1272
+ i = handleOpeningTagSegment(src, lt, out, stack);
1273
+ }
1274
+ for (let k = stack.length - 1; k >= 0; k -= 1) {
1275
+ out.push(`</${stack[k]}>`);
1276
+ }
1277
+ return out.join("");
1278
+ }
1279
+ function skipWs(s, p, len) {
1280
+ let idx = p;
1281
+ while (idx < len && WHITESPACE_REGEX2.test(s[idx])) {
1282
+ idx += 1;
1283
+ }
1284
+ return idx;
1285
+ }
1286
+ function parseTagNameAt(s, p, len) {
1287
+ let idx = p;
1288
+ const start = idx;
1289
+ while (idx < len && NAME_CHAR_RE.test(s[idx])) {
1290
+ idx += 1;
1291
+ }
1292
+ return { name: s.slice(start, idx), pos: idx };
1293
+ }
1294
+ function handleSpecialTagSegment(src, lt, out) {
1295
+ const gt = src.indexOf(">", lt + 1);
1296
+ if (gt === -1) {
1297
+ out.push(src.slice(lt));
1298
+ return src.length;
1299
+ }
1300
+ out.push(src.slice(lt, gt + 1));
1301
+ return gt + 1;
1302
+ }
1303
+ function handleClosingTagSegment(src, lt, out, stack) {
1304
+ const len = src.length;
1305
+ let p = skipWs(src, lt + 2, len);
1306
+ const { name, pos } = parseTagNameAt(src, p, len);
1307
+ p = pos;
1308
+ const gt = src.indexOf(">", p);
1309
+ const closingText = gt === -1 ? src.slice(lt) : src.slice(lt, gt + 1);
1310
+ const idx = stack.lastIndexOf(name);
1311
+ if (idx !== -1) {
1312
+ for (let k = stack.length - 1; k > idx; k -= 1) {
1313
+ out.push(`</${stack[k]}>`);
1314
+ stack.pop();
1315
+ }
1316
+ out.push(closingText);
1317
+ stack.pop();
1318
+ }
1319
+ return gt === -1 ? len : gt + 1;
1320
+ }
1321
+ function handleOpeningTagSegment(src, lt, out, stack) {
1322
+ const len = src.length;
1323
+ let p = skipWs(src, lt + 1, len);
1324
+ const nameStart = p;
1325
+ const parsed = parseTagNameAt(src, p, len);
1326
+ p = parsed.pos;
1327
+ const name = src.slice(nameStart, p);
1328
+ const q = src.indexOf(">", p);
1329
+ if (q === -1) {
1330
+ out.push(src.slice(lt));
1331
+ return len;
1332
+ }
1333
+ let r = q - 1;
1334
+ while (r >= nameStart && WHITESPACE_REGEX2.test(src[r])) {
1335
+ r -= 1;
1336
+ }
1337
+ const selfClosing = src[r] === "/";
1338
+ out.push(src.slice(lt, q + 1));
1339
+ if (!selfClosing && name) {
1340
+ stack.push(name);
1341
+ }
1342
+ return q + 1;
1343
+ }
1344
+ function repairParsedAgainstSchema(input, schema, options) {
1345
+ if (!input || typeof input !== "object") {
1346
+ return input;
1347
+ }
1348
+ const unwrapped = unwrapJsonSchema(schema);
1349
+ if (!unwrapped || typeof unwrapped !== "object") {
1350
+ return input;
1351
+ }
1352
+ const properties = unwrapped.properties;
1353
+ if (!properties) {
1354
+ return input;
1355
+ }
1356
+ applySchemaProps(input, properties, options);
1357
+ return input;
1358
+ }
1359
+ function applySchemaProps(obj, properties, options) {
1360
+ for (const key of Object.keys(obj)) {
1361
+ const propSchema = properties[key];
1362
+ if (!propSchema) {
1363
+ continue;
1364
+ }
1365
+ const prop = unwrapJsonSchema(propSchema);
1366
+ const propType = prop.type;
1367
+ if (propType === "array" && prop.items) {
1368
+ const itemSchemaRaw = prop.items;
1369
+ const itemSchema = unwrapJsonSchema(itemSchemaRaw);
1370
+ obj[key] = coerceArrayItems(obj[key], itemSchema, options);
1371
+ continue;
1372
+ }
1373
+ if (propType === "object") {
1374
+ const val = obj[key];
1375
+ if (val && typeof val === "object") {
1376
+ obj[key] = repairParsedAgainstSchema(
1377
+ val,
1378
+ prop,
1379
+ options
1380
+ );
1381
+ }
1382
+ }
1383
+ }
1384
+ }
1385
+ function coerceArrayItems(val, itemSchema, options) {
1386
+ if (!Array.isArray(val)) {
1387
+ return val;
1388
+ }
1389
+ return val.map((v) => coerceArrayItem(v, itemSchema, options));
1390
+ }
1391
+ function coerceArrayItem(v, itemSchema, options) {
1392
+ const itemType = itemSchema == null ? void 0 : itemSchema.type;
1393
+ if (typeof v === "string" && itemType === "object") {
1394
+ const parsed = tryParseStringToSchemaObject(v, itemSchema, options);
1395
+ if (parsed !== null) {
1396
+ return parsed;
1397
+ }
1398
+ const fallback = extractStepStatusFromString(normalizeCloseTags(v));
1399
+ if (fallback) {
1400
+ return fallback;
1401
+ }
1402
+ return v;
1403
+ }
1404
+ if (v && typeof v === "object" && itemType === "object") {
1405
+ return repairParsedAgainstSchema(
1406
+ v,
1407
+ itemSchema,
1408
+ options
1409
+ );
1410
+ }
1411
+ return v;
1412
+ }
1413
+ function getStringPropertyNames(schema) {
1414
+ const unwrapped = unwrapJsonSchema(schema);
1415
+ if (!unwrapped || typeof unwrapped !== "object") {
1416
+ return [];
1417
+ }
1418
+ const props = unwrapped.properties;
1419
+ if (!props) {
1420
+ return [];
1421
+ }
1422
+ const names = [];
1423
+ for (const key of Object.keys(props)) {
1424
+ const prop = unwrapJsonSchema(
1425
+ props[key]
1426
+ );
1427
+ const type = prop.type;
1428
+ if (type === "string") {
1429
+ names.push(key);
1430
+ }
1431
+ }
1432
+ return names;
1433
+ }
1434
+ function escapeRegExp2(s) {
1435
+ return s.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&");
1436
+ }
1437
+ function dedupeStringTagsAgainstSchema(xml, schema) {
1438
+ const names = getStringPropertyNames(schema);
1439
+ let out = xml;
1440
+ for (const key of names) {
1441
+ out = dedupeSingleTag(out, key);
1442
+ }
1443
+ return out;
1444
+ }
1445
+ function dedupeSingleTag(xml, key) {
1446
+ var _a, _b;
1447
+ const escaped = escapeRegExp2(key);
1448
+ const re = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
1449
+ const matches = Array.from(xml.matchAll(re));
1450
+ if (matches.length <= 1) {
1451
+ return xml;
1452
+ }
1453
+ const last = matches.at(-1);
1454
+ let result = "";
1455
+ let cursor = 0;
1456
+ for (const m of matches) {
1457
+ const idx = (_a = m.index) != null ? _a : 0;
1458
+ result += xml.slice(cursor, idx);
1459
+ if (last && idx === ((_b = last.index) != null ? _b : -1)) {
1460
+ result += m[0];
1461
+ }
1462
+ cursor = idx + m[0].length;
1463
+ }
1464
+ result += xml.slice(cursor);
1465
+ return result;
1466
+ }
1467
+ function tryParseStringToSchemaObject(xml, itemSchema, options) {
1468
+ try {
1469
+ const fixed = parse2(normalizeCloseTags(xml), itemSchema, {
1470
+ onError: options == null ? void 0 : options.onError,
1471
+ noChildNodes: []
1472
+ });
1473
+ return typeof fixed === "string" ? null : fixed;
1474
+ } catch (e) {
1475
+ return null;
1476
+ }
1477
+ }
1478
+ function extractStepStatusFromString(normXml) {
1479
+ const stepMatch = normXml.match(STEP_TAG_RE);
1480
+ const statusMatch = normXml.match(STATUS_TAG_RE);
1481
+ if (stepMatch && statusMatch) {
1482
+ return { step: stepMatch[1], status: statusMatch[1] };
1483
+ }
1484
+ return null;
1485
+ }
1230
1486
  function processTextBeforeToolCall(text, currentIndex, toolCallStartIndex, processedElements) {
1231
1487
  if (toolCallStartIndex > currentIndex) {
1232
1488
  const textSegment = text.substring(currentIndex, toolCallStartIndex);
@@ -1239,20 +1495,36 @@ function processTextBeforeToolCall(text, currentIndex, toolCallStartIndex, proce
1239
1495
  function processToolCall(params) {
1240
1496
  var _a;
1241
1497
  const { toolCall, tools, options, text, processedElements } = params;
1498
+ const toolSchema = getToolSchema(tools, toolCall.toolName);
1242
1499
  try {
1243
- const toolSchema = getToolSchema(tools, toolCall.toolName);
1244
- const parsed = parse2(toolCall.content, toolSchema, {
1500
+ const primary = escapeInvalidLt(normalizeCloseTags(toolCall.content));
1501
+ let parsed = parse2(primary, toolSchema, {
1245
1502
  onError: options == null ? void 0 : options.onError,
1246
1503
  // Disable HTML self-closing tag behavior to allow base, meta, link etc. as regular tags
1247
1504
  noChildNodes: []
1248
1505
  });
1506
+ parsed = repairParsedAgainstSchema(parsed, toolSchema, options);
1249
1507
  processedElements.push({
1250
1508
  type: "tool-call",
1251
- toolCallId: generateId3(),
1509
+ toolCallId: generateId2(),
1252
1510
  toolName: toolCall.toolName,
1253
1511
  input: JSON.stringify(parsed)
1254
1512
  });
1255
1513
  } catch (error) {
1514
+ const reparsed = tryParseSecondaryXml(
1515
+ toolCall.content,
1516
+ toolSchema,
1517
+ options
1518
+ );
1519
+ if (reparsed !== null) {
1520
+ processedElements.push({
1521
+ type: "tool-call",
1522
+ toolCallId: generateId2(),
1523
+ toolName: toolCall.toolName,
1524
+ input: JSON.stringify(reparsed)
1525
+ });
1526
+ return;
1527
+ }
1256
1528
  const originalCallText = text.substring(
1257
1529
  toolCall.startIndex,
1258
1530
  toolCall.endIndex
@@ -1276,20 +1548,33 @@ function addRemainingText(text, currentIndex, processedElements) {
1276
1548
  }
1277
1549
  function handleStreamingToolCallEnd(params) {
1278
1550
  const { toolContent, currentToolCall, tools, options, ctrl, flushText } = params;
1551
+ const toolSchema = getToolSchema(tools, currentToolCall.name);
1279
1552
  try {
1280
- const toolSchema = getToolSchema(tools, currentToolCall.name);
1281
- const parsed = parse2(toolContent, toolSchema, {
1553
+ const primary = escapeInvalidLt(normalizeCloseTags(toolContent));
1554
+ let parsed = parse2(primary, toolSchema, {
1282
1555
  onError: options == null ? void 0 : options.onError,
1283
1556
  noChildNodes: []
1284
1557
  });
1558
+ parsed = repairParsedAgainstSchema(parsed, toolSchema, options);
1285
1559
  flushText(ctrl);
1286
1560
  ctrl.enqueue({
1287
1561
  type: "tool-call",
1288
- toolCallId: generateId3(),
1562
+ toolCallId: generateId2(),
1289
1563
  toolName: currentToolCall.name,
1290
1564
  input: JSON.stringify(parsed)
1291
1565
  });
1292
1566
  } catch (error) {
1567
+ const parsed = tryParseSecondaryXml(toolContent, toolSchema, options);
1568
+ if (parsed !== null) {
1569
+ flushText(ctrl);
1570
+ ctrl.enqueue({
1571
+ type: "tool-call",
1572
+ toolCallId: generateId2(),
1573
+ toolName: currentToolCall.name,
1574
+ input: JSON.stringify(parsed)
1575
+ });
1576
+ return;
1577
+ }
1293
1578
  handleStreamingToolCallError({
1294
1579
  error,
1295
1580
  currentToolCall,
@@ -1321,19 +1606,28 @@ function handleStreamingToolCallError(params) {
1321
1606
  flushText(ctrl, originalCallText);
1322
1607
  }
1323
1608
  function findEarliestToolTag(buffer, toolNames) {
1324
- let earliestStartTagIndex = -1;
1325
- let earliestToolName = "";
1609
+ let bestIndex = -1;
1610
+ let bestName = "";
1611
+ let bestSelfClosing = false;
1326
1612
  if (toolNames.length > 0) {
1327
1613
  for (const name of toolNames) {
1328
- const startTag = `<${name}>`;
1329
- const index = buffer.indexOf(startTag);
1330
- if (index !== -1 && (earliestStartTagIndex === -1 || index < earliestStartTagIndex)) {
1331
- earliestStartTagIndex = index;
1332
- earliestToolName = name;
1614
+ const openTag = `<${name}>`;
1615
+ const selfTag = `<${name}/>`;
1616
+ const idxOpen = buffer.indexOf(openTag);
1617
+ const idxSelf = buffer.indexOf(selfTag);
1618
+ if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
1619
+ bestIndex = idxOpen;
1620
+ bestName = name;
1621
+ bestSelfClosing = false;
1622
+ }
1623
+ if (idxSelf !== -1 && (bestIndex === -1 || idxSelf < bestIndex)) {
1624
+ bestIndex = idxSelf;
1625
+ bestName = name;
1626
+ bestSelfClosing = true;
1333
1627
  }
1334
1628
  }
1335
1629
  }
1336
- return { index: earliestStartTagIndex, name: earliestToolName };
1630
+ return { index: bestIndex, name: bestName, selfClosing: bestSelfClosing };
1337
1631
  }
1338
1632
  function handleNoToolTagInBuffer(buffer, maxStartTagLen, controller, flushText) {
1339
1633
  const tail = Math.max(0, maxStartTagLen - 1);
@@ -1356,10 +1650,12 @@ function processToolCallInBuffer(params) {
1356
1650
  setBuffer
1357
1651
  } = params;
1358
1652
  const endTag = `</${currentToolCall.name}>`;
1359
- const endTagIndex = buffer.indexOf(endTag);
1653
+ const normalized = normalizeCloseTags(buffer);
1654
+ const effectiveBuffer = normalized;
1655
+ const endTagIndex = effectiveBuffer.indexOf(endTag);
1360
1656
  if (endTagIndex !== -1) {
1361
- const toolContent = buffer.substring(0, endTagIndex);
1362
- const newBuffer = buffer.substring(endTagIndex + endTag.length);
1657
+ const toolContent = effectiveBuffer.substring(0, endTagIndex);
1658
+ const newBuffer = effectiveBuffer.substring(endTagIndex + endTag.length);
1363
1659
  setBuffer("");
1364
1660
  handleStreamingToolCallEnd({
1365
1661
  toolContent,
@@ -1372,14 +1668,46 @@ function processToolCallInBuffer(params) {
1372
1668
  setBuffer(newBuffer);
1373
1669
  return { buffer: newBuffer, currentToolCall: null, shouldBreak: false };
1374
1670
  }
1375
- return { buffer, currentToolCall, shouldBreak: true };
1671
+ return { buffer: effectiveBuffer, currentToolCall, shouldBreak: true };
1376
1672
  }
1377
1673
  function processNoToolCallInBuffer(params) {
1378
- const { buffer, toolNames, maxStartTagLen, controller, flushText } = params;
1379
- const { index: earliestStartTagIndex, name: earliestToolName } = findEarliestToolTag(buffer, toolNames);
1674
+ const {
1675
+ buffer,
1676
+ toolNames,
1677
+ maxStartTagLen,
1678
+ controller,
1679
+ flushText,
1680
+ tools,
1681
+ options
1682
+ } = params;
1683
+ const {
1684
+ index: earliestStartTagIndex,
1685
+ name: earliestToolName,
1686
+ selfClosing
1687
+ } = findEarliestToolTag(buffer, toolNames);
1380
1688
  if (earliestStartTagIndex !== -1) {
1381
1689
  const textBeforeTag = buffer.substring(0, earliestStartTagIndex);
1382
1690
  flushText(controller, textBeforeTag);
1691
+ if (selfClosing) {
1692
+ const selfTag = `<${earliestToolName}/>`;
1693
+ const newBuffer2 = buffer.substring(
1694
+ earliestStartTagIndex + selfTag.length
1695
+ );
1696
+ handleStreamingToolCallEnd({
1697
+ toolContent: "",
1698
+ currentToolCall: { name: earliestToolName, content: "" },
1699
+ tools,
1700
+ options,
1701
+ ctrl: controller,
1702
+ flushText
1703
+ });
1704
+ return {
1705
+ buffer: newBuffer2,
1706
+ currentToolCall: null,
1707
+ shouldBreak: false,
1708
+ shouldContinue: false
1709
+ };
1710
+ }
1383
1711
  const startTag = `<${earliestToolName}>`;
1384
1712
  const newBuffer = buffer.substring(earliestStartTagIndex + startTag.length);
1385
1713
  return {
@@ -1408,7 +1736,7 @@ function createFlushTextHandler(getBuffer, setBuffer, getCurrentTextId, setCurre
1408
1736
  if (content) {
1409
1737
  const currentTextId2 = getCurrentTextId();
1410
1738
  if (!currentTextId2) {
1411
- const newId = generateId3();
1739
+ const newId = generateId2();
1412
1740
  setCurrentTextId(newId);
1413
1741
  controller.enqueue({ type: "text-start", id: newId });
1414
1742
  }
@@ -1460,6 +1788,8 @@ function processBufferWithoutToolCall(params, controller) {
1460
1788
  getBuffer,
1461
1789
  setBuffer,
1462
1790
  setCurrentToolCall,
1791
+ tools,
1792
+ options,
1463
1793
  toolNames,
1464
1794
  maxStartTagLen,
1465
1795
  flushText
@@ -1469,7 +1799,9 @@ function processBufferWithoutToolCall(params, controller) {
1469
1799
  toolNames,
1470
1800
  maxStartTagLen,
1471
1801
  controller,
1472
- flushText
1802
+ flushText,
1803
+ tools,
1804
+ options
1473
1805
  });
1474
1806
  setBuffer(result.buffer);
1475
1807
  setCurrentToolCall(result.currentToolCall);
@@ -1544,7 +1876,17 @@ var morphXmlProtocol = () => ({
1544
1876
  }
1545
1877
  const processedElements = [];
1546
1878
  let currentIndex = 0;
1547
- const toolCalls = findToolCalls(text, toolNames);
1879
+ const toolCallsRaw = findToolCalls(text, toolNames);
1880
+ const toolCallsNorm = collectToolCallsFromNormalizedText(text, toolNames);
1881
+ const seen = /* @__PURE__ */ new Set();
1882
+ const toolCalls = [...toolCallsRaw, ...toolCallsNorm].filter((tc) => {
1883
+ const key = `${tc.toolName}:${tc.startIndex}:${tc.endIndex}`;
1884
+ if (seen.has(key)) {
1885
+ return false;
1886
+ }
1887
+ seen.add(key);
1888
+ return true;
1889
+ }).sort((a, b) => a.startIndex - b.startIndex);
1548
1890
  for (const toolCall of toolCalls) {
1549
1891
  currentIndex = processTextBeforeToolCall(
1550
1892
  text,
@@ -1632,53 +1974,225 @@ function getToolSchema(tools, toolName) {
1632
1974
  var _a;
1633
1975
  return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
1634
1976
  }
1635
- function computeFullTagEnd(text, contentEnd, toolName) {
1636
- let fullTagEnd = contentEnd + `</${toolName}>`.length;
1637
- const closeHead = text.indexOf(`</${toolName}`, contentEnd);
1638
- if (closeHead === contentEnd) {
1639
- let p = closeHead + 2 + toolName.length;
1977
+ function findClosingTagEndFlexible(text, contentStart, toolName) {
1978
+ let pos = contentStart;
1979
+ let depth = 1;
1980
+ while (pos < text.length) {
1981
+ const tok = nextTagToken(text, pos);
1982
+ if (tok.kind === "eof") {
1983
+ break;
1984
+ }
1985
+ const result = updateDepthWithToken(tok, toolName, depth);
1986
+ depth = result.depth;
1987
+ if (result.closedAt !== void 0) {
1988
+ return result.closedAt;
1989
+ }
1990
+ pos = tok.nextPos;
1991
+ }
1992
+ return -1;
1993
+ }
1994
+ function skipSpecialSegment(text, lt) {
1995
+ const next = text[lt + 1];
1996
+ if (next !== "!" && next !== "?") {
1997
+ return null;
1998
+ }
1999
+ const gt = text.indexOf(">", lt + 1);
2000
+ if (gt === -1) {
2001
+ return null;
2002
+ }
2003
+ return gt + 1;
2004
+ }
2005
+ function consumeClosingTag(text, lt, toolName) {
2006
+ let p = lt + 2;
2007
+ while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2008
+ p += 1;
2009
+ }
2010
+ if (text.slice(p, p + toolName.length) === toolName) {
2011
+ p += toolName.length;
1640
2012
  while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
1641
2013
  p += 1;
1642
2014
  }
1643
2015
  if (text[p] === ">") {
1644
- fullTagEnd = p + 1;
2016
+ const endPos2 = p + 1;
2017
+ return { matched: true, endPos: endPos2 };
1645
2018
  }
1646
2019
  }
1647
- return fullTagEnd;
2020
+ const gt = text.indexOf(">", lt + 1);
2021
+ const endPos = gt === -1 ? text.length : gt + 1;
2022
+ return { matched: false, endPos };
1648
2023
  }
1649
- function extractToolCallInfo(text, tagStart, toolName, range) {
1650
- var _a;
1651
- const startTag = `<${toolName}>`;
1652
- const contentStart = tagStart + startTag.length;
1653
- const contentEnd = contentStart + (range.end - range.start);
1654
- const fullTagEnd = computeFullTagEnd(text, contentEnd, toolName);
1655
- const segment = text.substring(tagStart, fullTagEnd);
1656
- const content = (_a = extractRawInner(segment, toolName)) != null ? _a : text.substring(contentStart, contentEnd);
2024
+ function consumeOpenTag(text, lt) {
2025
+ let p = lt + 1;
2026
+ while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2027
+ p += 1;
2028
+ }
2029
+ const nameStart = p;
2030
+ while (p < text.length && NAME_CHAR_RE.test(text.charAt(p))) {
2031
+ p += 1;
2032
+ }
2033
+ const name = text.slice(nameStart, p);
2034
+ const q = text.indexOf(">", p);
2035
+ if (q === -1) {
2036
+ return null;
2037
+ }
2038
+ let r = q - 1;
2039
+ while (r >= nameStart && WHITESPACE_REGEX2.test(text[r])) {
2040
+ r -= 1;
2041
+ }
2042
+ const selfClosing = text[r] === "/";
2043
+ return { name, selfClosing, nextPos: q + 1 };
2044
+ }
2045
+ function updateDepthWithToken(tok, toolName, depth) {
2046
+ if (tok.kind === "close" && tok.name === toolName) {
2047
+ const newDepth = depth - 1;
2048
+ return newDepth === 0 ? { depth: newDepth, closedAt: tok.nextPos } : { depth: newDepth };
2049
+ }
2050
+ if (tok.kind === "open" && tok.name === toolName && !tok.selfClosing) {
2051
+ return { depth: depth + 1 };
2052
+ }
2053
+ return { depth };
2054
+ }
2055
+ function nextTagToken(text, fromPos) {
2056
+ const lt = text.indexOf("<", fromPos);
2057
+ if (lt === -1 || lt + 1 >= text.length) {
2058
+ return { kind: "eof", nextPos: text.length };
2059
+ }
2060
+ const next = text[lt + 1];
2061
+ const specialEnd = skipSpecialSegment(text, lt);
2062
+ if (specialEnd !== null) {
2063
+ return { kind: "special", nextPos: specialEnd };
2064
+ }
2065
+ if (next === "/") {
2066
+ const closing = consumeClosingTag(text, lt, "");
2067
+ let p = lt + 2;
2068
+ while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2069
+ p += 1;
2070
+ }
2071
+ const nameStart = p;
2072
+ while (p < text.length && NAME_CHAR_RE.test(text.charAt(p))) {
2073
+ p += 1;
2074
+ }
2075
+ const name = text.slice(nameStart, p);
2076
+ return { kind: "close", name, nextPos: closing.endPos };
2077
+ }
2078
+ const open = consumeOpenTag(text, lt);
2079
+ if (open === null) {
2080
+ return { kind: "eof", nextPos: text.length };
2081
+ }
1657
2082
  return {
1658
- toolName,
1659
- startIndex: tagStart,
1660
- endIndex: fullTagEnd,
1661
- content,
1662
- segment
2083
+ kind: "open",
2084
+ name: open.name,
2085
+ selfClosing: open.selfClosing,
2086
+ nextPos: open.nextPos
1663
2087
  };
1664
2088
  }
2089
+ function collectToolCallsFromNormalizedText(text, toolNames) {
2090
+ var _a;
2091
+ const normalizedText = normalizeCloseTags(text);
2092
+ const collected = [];
2093
+ for (const toolName of toolNames) {
2094
+ const startTag = `<${toolName}>`;
2095
+ let idx = 0;
2096
+ let lastOrigIdx = 0;
2097
+ while (idx < normalizedText.length) {
2098
+ const tagStartNorm = normalizedText.indexOf(startTag, idx);
2099
+ if (tagStartNorm === -1) {
2100
+ break;
2101
+ }
2102
+ const contentStartNorm = tagStartNorm + startTag.length;
2103
+ const endNorm = findClosingTagEndFlexible(
2104
+ normalizedText,
2105
+ contentStartNorm,
2106
+ toolName
2107
+ );
2108
+ if (endNorm > contentStartNorm) {
2109
+ const tagStartOrig = text.indexOf(startTag, lastOrigIdx);
2110
+ const contentStartOrig = tagStartOrig + startTag.length;
2111
+ let endOrig = findClosingTagEndFlexible(
2112
+ text,
2113
+ contentStartOrig,
2114
+ toolName
2115
+ );
2116
+ if (endOrig === -1) {
2117
+ const approxLen = endNorm - tagStartNorm;
2118
+ endOrig = Math.min(text.length, tagStartOrig + approxLen);
2119
+ }
2120
+ const segment = text.substring(tagStartOrig, endOrig);
2121
+ const inner = (_a = extractRawInner(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2122
+ collected.push({
2123
+ toolName,
2124
+ startIndex: tagStartOrig,
2125
+ endIndex: endOrig,
2126
+ content: inner,
2127
+ segment
2128
+ });
2129
+ lastOrigIdx = endOrig;
2130
+ idx = endNorm;
2131
+ } else {
2132
+ idx = contentStartNorm;
2133
+ }
2134
+ }
2135
+ }
2136
+ return collected.sort((a, b) => a.startIndex - b.startIndex);
2137
+ }
2138
+ function getNextTagInfo(text, toolName, fromIndex) {
2139
+ const startTag = `<${toolName}>`;
2140
+ const selfTag = `<${toolName}/>`;
2141
+ const openIdx = text.indexOf(startTag, fromIndex);
2142
+ const selfIdx = text.indexOf(selfTag, fromIndex);
2143
+ const hasOpen = openIdx !== -1;
2144
+ const hasSelf = selfIdx !== -1;
2145
+ if (!(hasOpen || hasSelf)) {
2146
+ return {
2147
+ found: false,
2148
+ tagStart: -1,
2149
+ selfClosing: false,
2150
+ startTag,
2151
+ selfTag
2152
+ };
2153
+ }
2154
+ const pickSelf = hasSelf && (!hasOpen || selfIdx < openIdx);
2155
+ const tagStart = pickSelf ? selfIdx : openIdx;
2156
+ return { found: true, tagStart, selfClosing: pickSelf, startTag, selfTag };
2157
+ }
1665
2158
  function findToolCallsForName(text, toolName) {
2159
+ var _a;
1666
2160
  const toolCalls = [];
1667
- const startTag = `<${toolName}>`;
1668
2161
  let searchIndex = 0;
1669
2162
  while (searchIndex < text.length) {
1670
- const tagStart = text.indexOf(startTag, searchIndex);
1671
- if (tagStart === -1) {
2163
+ const info = getNextTagInfo(text, toolName, searchIndex);
2164
+ if (!info.found) {
1672
2165
  break;
1673
2166
  }
1674
- const remainingText = text.substring(tagStart);
1675
- const range = findFirstTopLevelRange(remainingText, toolName);
1676
- if (range) {
1677
- const toolCallInfo = extractToolCallInfo(text, tagStart, toolName, range);
1678
- toolCalls.push(toolCallInfo);
1679
- searchIndex = toolCallInfo.endIndex;
2167
+ const { tagStart, selfClosing, startTag, selfTag } = info;
2168
+ if (selfClosing) {
2169
+ const endIndex = tagStart + selfTag.length;
2170
+ const segment = text.substring(tagStart, endIndex);
2171
+ toolCalls.push({
2172
+ toolName,
2173
+ startIndex: tagStart,
2174
+ endIndex,
2175
+ content: "",
2176
+ segment
2177
+ });
2178
+ searchIndex = endIndex;
2179
+ continue;
2180
+ }
2181
+ const contentStart = tagStart + startTag.length;
2182
+ const fullTagEnd = findClosingTagEndFlexible(text, contentStart, toolName);
2183
+ if (fullTagEnd !== -1 && fullTagEnd > contentStart) {
2184
+ const segment = text.substring(tagStart, fullTagEnd);
2185
+ const inner = (_a = extractRawInner(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2186
+ toolCalls.push({
2187
+ toolName,
2188
+ startIndex: tagStart,
2189
+ endIndex: fullTagEnd,
2190
+ content: inner,
2191
+ segment
2192
+ });
2193
+ searchIndex = fullTagEnd;
1680
2194
  } else {
1681
- searchIndex = tagStart + startTag.length;
2195
+ searchIndex = contentStart;
1682
2196
  }
1683
2197
  }
1684
2198
  return toolCalls;
@@ -1692,14 +2206,53 @@ function findToolCalls(text, toolNames) {
1692
2206
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
1693
2207
  }
1694
2208
 
1695
- // src/protocols/tool-call-protocol.ts
1696
- function isProtocolFactory(protocol) {
1697
- return typeof protocol === "function";
2209
+ // src/generate-handler.ts
2210
+ import { generateId as generateId3 } from "@ai-sdk/provider-utils";
2211
+ import { coerceBySchema } from "@ai-sdk-tool/rxml";
2212
+
2213
+ // src/utils/on-error.ts
2214
+ function extractOnErrorOption(providerOptions) {
2215
+ var _a;
2216
+ if (providerOptions && typeof providerOptions === "object") {
2217
+ const onError = (_a = providerOptions.toolCallMiddleware) == null ? void 0 : _a.onError;
2218
+ return onError ? { onError } : void 0;
2219
+ }
2220
+ return;
2221
+ }
2222
+
2223
+ // src/utils/provider-options.ts
2224
+ var originalToolsSchema = {
2225
+ encode: encodeOriginalTools,
2226
+ decode: decodeOriginalTools
2227
+ };
2228
+ function encodeOriginalTools(tools) {
2229
+ return (tools == null ? void 0 : tools.map((t) => ({
2230
+ name: t.name,
2231
+ inputSchema: JSON.stringify(t.inputSchema)
2232
+ }))) || [];
2233
+ }
2234
+ function decodeOriginalTools(originalTools) {
2235
+ if (!originalTools) {
2236
+ return [];
2237
+ }
2238
+ return originalTools.map(
2239
+ (t) => ({
2240
+ type: "function",
2241
+ name: t.name,
2242
+ inputSchema: JSON.parse(t.inputSchema)
2243
+ })
2244
+ );
2245
+ }
2246
+ function extractToolNamesFromOriginalTools(originalTools) {
2247
+ return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
2248
+ }
2249
+ function isToolChoiceActive(params) {
2250
+ var _a, _b, _c;
2251
+ const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
2252
+ return !!(typeof params.providerOptions === "object" && params.providerOptions !== null && typeof ((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) === "object" && toolChoice && typeof toolChoice === "object" && (toolChoice.type === "tool" || toolChoice.type === "required"));
1698
2253
  }
1699
2254
 
1700
2255
  // src/generate-handler.ts
1701
- import { generateId as generateId4 } from "@ai-sdk/provider-utils";
1702
- import { coerceBySchema } from "@ai-sdk-tool/rxml";
1703
2256
  function parseToolChoiceJson(text, providerOptions) {
1704
2257
  var _a;
1705
2258
  try {
@@ -1743,7 +2296,7 @@ async function handleToolChoice(doGenerate, params) {
1743
2296
  }
1744
2297
  const toolCall = {
1745
2298
  type: "tool-call",
1746
- toolCallId: generateId4(),
2299
+ toolCallId: generateId3(),
1747
2300
  toolName: parsed.name || "unknown",
1748
2301
  input: JSON.stringify(parsed.arguments || {})
1749
2302
  };
@@ -1869,8 +2422,13 @@ function fixToolCallWithSchema(part, tools) {
1869
2422
  };
1870
2423
  }
1871
2424
 
2425
+ // src/protocols/tool-call-protocol.ts
2426
+ function isProtocolFactory(protocol) {
2427
+ return typeof protocol === "function";
2428
+ }
2429
+
1872
2430
  // src/stream-handler.ts
1873
- import { generateId as generateId5 } from "@ai-sdk/provider-utils";
2431
+ import { generateId as generateId4 } from "@ai-sdk/provider-utils";
1874
2432
  function extractToolCallSegments(protocol, fullRawText, tools) {
1875
2433
  const segments = protocol.extractToolCallSegments ? protocol.extractToolCallSegments({
1876
2434
  text: fullRawText,
@@ -1907,7 +2465,7 @@ function handleDebugSummary(parsedToolCalls, origin, params) {
1907
2465
  }
1908
2466
  function createDebugSummaryTransform({
1909
2467
  protocol,
1910
- fullRawText,
2468
+ getFullRawText,
1911
2469
  tools,
1912
2470
  params
1913
2471
  }) {
@@ -1920,11 +2478,9 @@ function createDebugSummaryTransform({
1920
2478
  }
1921
2479
  if (part.type === "finish") {
1922
2480
  try {
1923
- const origin = extractToolCallSegments(
1924
- protocol,
1925
- fullRawText,
1926
- tools
1927
- );
2481
+ const raw = getFullRawText();
2482
+ logRawChunk(raw);
2483
+ const origin = extractToolCallSegments(protocol, raw, tools);
1928
2484
  handleDebugSummary(parsedToolCalls, origin, params);
1929
2485
  } catch (e) {
1930
2486
  }
@@ -2022,7 +2578,7 @@ async function wrapStream({
2022
2578
  const withSummary = parsed.pipeThrough(
2023
2579
  createDebugSummaryTransform({
2024
2580
  protocol,
2025
- fullRawText,
2581
+ getFullRawText: () => fullRawText,
2026
2582
  tools,
2027
2583
  params
2028
2584
  })
@@ -2056,19 +2612,26 @@ async function toolChoiceStream({
2056
2612
  }
2057
2613
  const toolCallChunk = {
2058
2614
  type: "tool-call",
2059
- toolCallId: generateId5(),
2615
+ toolCallId: generateId4(),
2060
2616
  toolName: toolJson.name || "unknown",
2061
2617
  input: JSON.stringify(toolJson.arguments || {})
2062
2618
  };
2063
2619
  const finishChunk = {
2064
2620
  type: "finish",
2065
- usage: (result == null ? void 0 : result.usage) || // TODO: If possible, try to return a certain amount of LLM usage.
2066
- {
2067
- inputTokens: 0,
2068
- outputTokens: 0,
2069
- totalTokens: 0
2621
+ usage: (result == null ? void 0 : result.usage) || {
2622
+ inputTokens: {
2623
+ total: 0,
2624
+ noCache: void 0,
2625
+ cacheRead: void 0,
2626
+ cacheWrite: void 0
2627
+ },
2628
+ outputTokens: {
2629
+ total: 0,
2630
+ text: void 0,
2631
+ reasoning: void 0
2632
+ }
2070
2633
  },
2071
- finishReason: "tool-calls"
2634
+ finishReason: { unified: "tool-calls", raw: void 0 }
2072
2635
  };
2073
2636
  const stream = new ReadableStream({
2074
2637
  start(controller) {
@@ -2102,26 +2665,106 @@ async function toolChoiceStream({
2102
2665
  };
2103
2666
  }
2104
2667
 
2668
+ // src/utils/dynamic-tool-schema.ts
2669
+ function createDynamicIfThenElseSchema(tools) {
2670
+ let currentSchema = {};
2671
+ const toolNames = [];
2672
+ for (let i = tools.length - 1; i >= 0; i -= 1) {
2673
+ const tool = tools[i];
2674
+ if (tool.type === "provider") {
2675
+ throw new Error(
2676
+ "Provider tools are not supported by this middleware. Please use function tools."
2677
+ );
2678
+ }
2679
+ toolNames.unshift(tool.name);
2680
+ const toolCondition = {
2681
+ if: {
2682
+ properties: {
2683
+ name: {
2684
+ const: tool.name
2685
+ }
2686
+ },
2687
+ required: ["name"]
2688
+ },
2689
+ // biome-ignore lint/suspicious/noThenProperty: JSON Schema uses 'then' as a keyword
2690
+ then: {
2691
+ properties: {
2692
+ name: {
2693
+ const: tool.name
2694
+ },
2695
+ arguments: tool.inputSchema
2696
+ },
2697
+ required: ["name", "arguments"]
2698
+ }
2699
+ };
2700
+ if (Object.keys(currentSchema).length > 0) {
2701
+ toolCondition.else = currentSchema;
2702
+ }
2703
+ currentSchema = toolCondition;
2704
+ }
2705
+ return {
2706
+ type: "object",
2707
+ // Explicitly specify type as "object"
2708
+ properties: {
2709
+ name: {
2710
+ type: "string",
2711
+ description: "Name of the tool to call",
2712
+ enum: toolNames
2713
+ },
2714
+ arguments: {
2715
+ type: "object",
2716
+ // By default, arguments is also specified as object type
2717
+ description: "Argument object to be passed to the tool"
2718
+ }
2719
+ },
2720
+ required: ["name", "arguments"],
2721
+ ...currentSchema
2722
+ };
2723
+ }
2724
+
2105
2725
  // src/transform-handler.ts
2106
- function buildFinalPrompt(systemPrompt, processedPrompt) {
2107
- var _a;
2108
- if (((_a = processedPrompt[0]) == null ? void 0 : _a.role) === "system") {
2726
+ function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
2727
+ const systemIndex = processedPrompt.findIndex((m) => m.role === "system");
2728
+ if (systemIndex !== -1) {
2729
+ const existing = processedPrompt[systemIndex].content;
2730
+ let existingText = "";
2731
+ if (typeof existing === "string") {
2732
+ existingText = existing;
2733
+ } else if (Array.isArray(existing)) {
2734
+ existingText = existing.map((p) => {
2735
+ var _a;
2736
+ return (p == null ? void 0 : p.type) === "text" ? (_a = p.text) != null ? _a : "" : "";
2737
+ }).filter(Boolean).join("\n");
2738
+ } else {
2739
+ existingText = String(existing != null ? existing : "");
2740
+ }
2741
+ const mergedContent = placement === "first" ? `${systemPrompt}
2742
+
2743
+ ${existingText}` : `${existingText}
2744
+
2745
+ ${systemPrompt}`;
2746
+ return processedPrompt.map(
2747
+ (m, idx) => idx === systemIndex ? {
2748
+ ...m,
2749
+ content: mergedContent
2750
+ } : m
2751
+ );
2752
+ }
2753
+ if (placement === "first") {
2109
2754
  return [
2110
2755
  {
2111
2756
  role: "system",
2112
- content: `${systemPrompt}
2113
-
2114
- ${processedPrompt[0].content}`
2757
+ content: systemPrompt
2115
2758
  },
2116
- ...processedPrompt.slice(1)
2759
+ ...processedPrompt
2117
2760
  ];
2118
2761
  }
2119
2762
  return [
2763
+ ...processedPrompt,
2120
2764
  {
2121
2765
  role: "system",
2122
2766
  content: systemPrompt
2123
- },
2124
- ...processedPrompt
2767
+ }
2125
2768
  ];
2126
2769
  }
2127
2770
  function buildBaseReturnParams(params, finalPrompt, functionTools) {
@@ -2221,7 +2864,8 @@ function handleToolChoiceRequired(params, baseReturnParams, functionTools) {
2221
2864
  function transformParams({
2222
2865
  params,
2223
2866
  protocol,
2224
- toolSystemPromptTemplate
2867
+ toolSystemPromptTemplate,
2868
+ placement = "first"
2225
2869
  }) {
2226
2870
  var _a, _b, _c, _d, _e;
2227
2871
  const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
@@ -2237,7 +2881,11 @@ function transformParams({
2237
2881
  resolvedProtocol,
2238
2882
  extractOnErrorOption(params.providerOptions)
2239
2883
  );
2240
- const finalPrompt = buildFinalPrompt(systemPrompt, processedPrompt);
2884
+ const finalPrompt = buildFinalPrompt(
2885
+ systemPrompt,
2886
+ processedPrompt,
2887
+ placement
2888
+ );
2241
2889
  const baseReturnParams = buildBaseReturnParams(
2242
2890
  params,
2243
2891
  finalPrompt,
@@ -2314,7 +2962,10 @@ function processMessage(message, resolvedProtocol, providerOptions) {
2314
2962
  };
2315
2963
  }
2316
2964
  if (message.role === "tool") {
2317
- return processToolMessage(message.content, resolvedProtocol);
2965
+ const toolResultParts = message.content.filter(
2966
+ (part) => part.type === "tool-result"
2967
+ );
2968
+ return processToolMessage(toolResultParts, resolvedProtocol);
2318
2969
  }
2319
2970
  return message;
2320
2971
  }
@@ -2389,7 +3040,8 @@ function convertToolPrompt(prompt, resolvedProtocol, providerOptions) {
2389
3040
  // src/tool-call-middleware.ts
2390
3041
  function createToolMiddleware({
2391
3042
  protocol,
2392
- toolSystemPromptTemplate
3043
+ toolSystemPromptTemplate,
3044
+ placement = "last"
2393
3045
  }) {
2394
3046
  const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
2395
3047
  return {
@@ -2416,6 +3068,7 @@ function createToolMiddleware({
2416
3068
  transformParams: async ({ params }) => transformParams({
2417
3069
  protocol: resolvedProtocol,
2418
3070
  toolSystemPromptTemplate,
3071
+ placement,
2419
3072
  params
2420
3073
  })
2421
3074
  };
@@ -2461,6 +3114,7 @@ For each function call return a json object with function name and arguments wit
2461
3114
  });
2462
3115
  var morphXmlToolMiddleware = createToolMiddleware({
2463
3116
  protocol: morphXmlProtocol,
3117
+ placement: "last",
2464
3118
  toolSystemPromptTemplate(tools) {
2465
3119
  return `You are a function calling AI model.
2466
3120
 
@@ -2485,30 +3139,30 @@ Available functions are listed inside <tools></tools>.
2485
3139
 
2486
3140
  export {
2487
3141
  getDebugLevel,
3142
+ logParseFailure,
2488
3143
  logRawChunk,
2489
3144
  logParsedChunk,
2490
3145
  logParsedSummary,
2491
- createDynamicIfThenElseSchema,
2492
3146
  getPotentialStartIndex,
2493
- extractOnErrorOption,
2494
- originalToolsSchema,
2495
- encodeOriginalTools,
2496
- decodeOriginalTools,
2497
- extractToolNamesFromOriginalTools,
2498
- isToolChoiceActive,
2499
3147
  escapeRegExp,
2500
3148
  transform,
2501
3149
  parse,
2502
3150
  stringify,
2503
- robust_json_exports,
3151
+ jsonMixProtocol,
2504
3152
  isToolCallContent,
2505
3153
  isToolResultPart,
2506
3154
  hasInputProperty,
2507
- jsonMixProtocol,
2508
3155
  morphXmlProtocol,
3156
+ extractOnErrorOption,
3157
+ originalToolsSchema,
3158
+ encodeOriginalTools,
3159
+ decodeOriginalTools,
3160
+ extractToolNamesFromOriginalTools,
3161
+ isToolChoiceActive,
3162
+ createDynamicIfThenElseSchema,
2509
3163
  createToolMiddleware,
2510
3164
  gemmaToolMiddleware,
2511
3165
  hermesToolMiddleware,
2512
3166
  morphXmlToolMiddleware
2513
3167
  };
2514
- //# sourceMappingURL=chunk-FOANBZRH.js.map
3168
+ //# sourceMappingURL=chunk-L4X363EL.js.map