@ai-sdk-tool/parser 2.1.2 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -89,9 +89,9 @@ function escapeRegExp(literal) {
89
89
  return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
90
90
  }
91
91
 
92
- // src/utils/relaxed-json.ts
93
- var relaxed_json_exports = {};
94
- __export(relaxed_json_exports, {
92
+ // src/utils/robust-json.ts
93
+ var robust_json_exports = {};
94
+ __export(robust_json_exports, {
95
95
  parse: () => parse,
96
96
  stringify: () => stringify,
97
97
  transform: () => transform
@@ -1013,11 +1013,6 @@ function extractOnErrorOption(providerOptions) {
1013
1013
  return void 0;
1014
1014
  }
1015
1015
 
1016
- // src/utils/protocol.ts
1017
- function isProtocolFactory(protocol) {
1018
- return typeof protocol === "function";
1019
- }
1020
-
1021
1016
  // src/utils/tools.ts
1022
1017
  function isToolChoiceActive(params) {
1023
1018
  var _a, _b, _c;
@@ -1114,7 +1109,7 @@ var jsonMixProtocol = ({
1114
1109
  }
1115
1110
  if (toolCallJson) {
1116
1111
  try {
1117
- const parsedToolCall = relaxed_json_exports.parse(toolCallJson);
1112
+ const parsedToolCall = robust_json_exports.parse(toolCallJson);
1118
1113
  processedElements.push({
1119
1114
  type: "tool-call",
1120
1115
  toolCallId: generateId2(),
@@ -1237,7 +1232,7 @@ var jsonMixProtocol = ({
1237
1232
  isInsideToolCall = true;
1238
1233
  } else {
1239
1234
  try {
1240
- const parsedToolCall = relaxed_json_exports.parse(currentToolCallJson);
1235
+ const parsedToolCall = robust_json_exports.parse(currentToolCallJson);
1241
1236
  if (currentTextId && hasEmittedTextStart) {
1242
1237
  controller.enqueue({ type: "text-end", id: currentTextId });
1243
1238
  currentTextId = null;
@@ -1299,7 +1294,58 @@ var jsonMixProtocol = ({
1299
1294
 
1300
1295
  // src/protocols/morph-xml-protocol.ts
1301
1296
  import { generateId as generateId3 } from "@ai-sdk/provider-utils";
1302
- import { XMLBuilder, XMLParser } from "fast-xml-parser";
1297
+ import {
1298
+ findFirstTopLevelRange,
1299
+ parse as parseXml,
1300
+ RXMLCoercionError,
1301
+ RXMLDuplicateStringTagError,
1302
+ RXMLParseError,
1303
+ stringify as stringify2
1304
+ } from "@ai-sdk-tool/rxml";
1305
+ function getToolSchema(tools, originalSchemas, toolName) {
1306
+ var _a;
1307
+ const original = originalSchemas[toolName];
1308
+ if (original) return original;
1309
+ const fallback = (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
1310
+ return fallback;
1311
+ }
1312
+ function findToolCalls(text, toolNames) {
1313
+ const toolCalls = [];
1314
+ for (const toolName of toolNames) {
1315
+ let searchIndex = 0;
1316
+ while (searchIndex < text.length) {
1317
+ const startTag = `<${toolName}>`;
1318
+ const tagStart = text.indexOf(startTag, searchIndex);
1319
+ if (tagStart === -1) break;
1320
+ const remainingText = text.substring(tagStart);
1321
+ const range = findFirstTopLevelRange(remainingText, toolName);
1322
+ if (range) {
1323
+ const contentStart = tagStart + startTag.length;
1324
+ const contentEnd = contentStart + (range.end - range.start);
1325
+ let fullTagEnd = contentEnd + `</${toolName}>`.length;
1326
+ const closeHead = text.indexOf(`</${toolName}`, contentEnd);
1327
+ if (closeHead === contentEnd) {
1328
+ let p = closeHead + 2 + toolName.length;
1329
+ while (p < text.length && /\s/.test(text[p])) p++;
1330
+ if (text[p] === ">") fullTagEnd = p + 1;
1331
+ }
1332
+ const toolContent = text.substring(contentStart, contentEnd);
1333
+ const fullSegment = text.substring(tagStart, fullTagEnd);
1334
+ toolCalls.push({
1335
+ toolName,
1336
+ startIndex: tagStart,
1337
+ endIndex: fullTagEnd,
1338
+ content: toolContent,
1339
+ segment: fullSegment
1340
+ });
1341
+ searchIndex = fullTagEnd;
1342
+ } else {
1343
+ searchIndex = tagStart + startTag.length;
1344
+ }
1345
+ }
1346
+ }
1347
+ return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
1348
+ }
1303
1349
  var morphXmlProtocol = () => ({
1304
1350
  formatTools({ tools, toolSystemPromptTemplate }) {
1305
1351
  const toolsForPrompt = (tools || []).map((tool) => ({
@@ -1310,7 +1356,6 @@ var morphXmlProtocol = () => ({
1310
1356
  return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1311
1357
  },
1312
1358
  formatToolCall(toolCall) {
1313
- const builder = new XMLBuilder({ format: true, suppressEmptyNode: true });
1314
1359
  let args = {};
1315
1360
  const inputValue = hasInputProperty(toolCall) ? toolCall.input : void 0;
1316
1361
  if (typeof inputValue === "string") {
@@ -1322,145 +1367,63 @@ var morphXmlProtocol = () => ({
1322
1367
  } else {
1323
1368
  args = inputValue;
1324
1369
  }
1325
- const xmlContent = builder.build({
1326
- [toolCall.toolName]: args
1370
+ return stringify2(toolCall.toolName, args, {
1371
+ suppressEmptyNode: false,
1372
+ format: false
1327
1373
  });
1328
- return xmlContent;
1329
1374
  },
1330
1375
  formatToolResponse(toolResult) {
1331
- const builder = new XMLBuilder({ format: true });
1332
- const xmlContent = builder.build({
1333
- tool_response: {
1334
- tool_name: toolResult.toolName,
1335
- result: toolResult.output
1336
- }
1376
+ return stringify2("tool_response", {
1377
+ tool_name: toolResult.toolName,
1378
+ result: toolResult.output
1337
1379
  });
1338
- return xmlContent;
1339
1380
  },
1340
1381
  parseGeneratedText({ text, tools, options }) {
1341
- var _a, _b, _c;
1382
+ var _a;
1342
1383
  const originalSchemas = (options == null ? void 0 : options.originalToolSchemas) || {};
1343
1384
  const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1344
1385
  if (toolNames.length === 0) {
1345
1386
  return [{ type: "text", text }];
1346
1387
  }
1347
- const toolNamesPattern = toolNames.map((n) => escapeRegExp(n)).join("|");
1348
- const toolCallRegex = new RegExp(
1349
- String.raw`<(${toolNamesPattern})>([\s\S]*?)<\/\1>`,
1350
- "g"
1351
- );
1352
1388
  const processedElements = [];
1353
1389
  let currentIndex = 0;
1354
- let match;
1355
- while ((match = toolCallRegex.exec(text)) !== null) {
1356
- const startIndex = match.index;
1357
- const toolName = match[1];
1358
- const toolContent = match[2].trim();
1359
- if (startIndex > currentIndex) {
1360
- const textSegment = text.substring(currentIndex, startIndex);
1390
+ const toolCalls = findToolCalls(text, toolNames);
1391
+ for (const toolCall of toolCalls) {
1392
+ if (toolCall.startIndex > currentIndex) {
1393
+ const textSegment = text.substring(currentIndex, toolCall.startIndex);
1361
1394
  if (textSegment.trim()) {
1362
1395
  processedElements.push({ type: "text", text: textSegment });
1363
1396
  }
1364
1397
  }
1365
1398
  try {
1366
- const parser = new XMLParser({
1367
- ignoreAttributes: false,
1368
- parseTagValue: false,
1369
- ignoreDeclaration: true,
1370
- textNodeName: "#text"
1399
+ const toolSchema = getToolSchema(
1400
+ tools,
1401
+ originalSchemas,
1402
+ toolCall.toolName
1403
+ );
1404
+ const parsed = parseXml(toolCall.content, toolSchema, {
1405
+ onError: options == null ? void 0 : options.onError
1371
1406
  });
1372
- const parsedArgs = ((_a = parser.parse(`<root>${toolContent}</root>`)) == null ? void 0 : _a.root) || {};
1373
- const args = {};
1374
- for (const k of Object.keys(parsedArgs || {})) {
1375
- const v = parsedArgs[k];
1376
- let val = v;
1377
- if (v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, "#text")) {
1378
- val = v == null ? void 0 : v["#text"];
1379
- }
1380
- if (Array.isArray(v)) {
1381
- val = v.map((item) => {
1382
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1383
- const textVal = item == null ? void 0 : item["#text"];
1384
- return typeof textVal === "string" ? textVal.trim() : textVal;
1385
- }
1386
- return typeof item === "string" ? item.trim() : item;
1387
- });
1388
- } else if (v && typeof v === "object" && !Object.prototype.hasOwnProperty.call(v, "#text")) {
1389
- const obj = v;
1390
- const keys = Object.keys(obj);
1391
- if (keys.length === 1 && keys[0] === "item") {
1392
- const itemValue = obj.item;
1393
- if (Array.isArray(itemValue)) {
1394
- val = itemValue.map((item) => {
1395
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1396
- const textVal = item == null ? void 0 : item["#text"];
1397
- const trimmed2 = typeof textVal === "string" ? textVal.trim() : textVal;
1398
- if (typeof trimmed2 === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed2)) {
1399
- const num = Number(trimmed2);
1400
- if (Number.isFinite(num)) return num;
1401
- }
1402
- return trimmed2;
1403
- }
1404
- const trimmed = typeof item === "string" ? item.trim() : item;
1405
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1406
- const num = Number(trimmed);
1407
- if (Number.isFinite(num)) return num;
1408
- }
1409
- return trimmed;
1410
- });
1411
- } else {
1412
- const trimmed = typeof itemValue === "string" ? itemValue.trim() : itemValue;
1413
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1414
- const num = Number(trimmed);
1415
- if (Number.isFinite(num)) {
1416
- val = num;
1417
- } else {
1418
- val = trimmed;
1419
- }
1420
- } else {
1421
- val = trimmed;
1422
- }
1423
- }
1424
- } else {
1425
- const isIndexedTuple = keys.length > 0 && keys.every((key) => /^\d+$/.test(key)) && (() => {
1426
- const indices = keys.map((k2) => parseInt(k2)).sort((a, b) => a - b);
1427
- return indices[0] === 0 && indices.every((val2, idx) => val2 === idx);
1428
- })();
1429
- if (isIndexedTuple) {
1430
- const sortedKeys = keys.sort(
1431
- (a, b) => parseInt(a) - parseInt(b)
1432
- );
1433
- val = sortedKeys.map((key) => {
1434
- const item = obj[key];
1435
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1436
- const textVal = item == null ? void 0 : item["#text"];
1437
- return typeof textVal === "string" ? textVal.trim() : textVal;
1438
- }
1439
- return typeof item === "string" ? item.trim() : item;
1440
- });
1441
- } else {
1442
- val = v;
1443
- }
1444
- }
1445
- }
1446
- args[k] = typeof val === "string" ? val.trim() : val;
1447
- }
1448
- const originalSchema = originalSchemas[toolName];
1449
- const fallbackSchema = (_b = tools.find((t) => t.name === toolName)) == null ? void 0 : _b.inputSchema;
1450
- const schema = originalSchema || fallbackSchema;
1451
- const coercedArgs = coerceBySchema(args, schema);
1452
1407
  processedElements.push({
1453
1408
  type: "tool-call",
1454
1409
  toolCallId: generateId3(),
1455
- toolName,
1456
- input: JSON.stringify(coercedArgs)
1410
+ toolName: toolCall.toolName,
1411
+ input: JSON.stringify(parsed)
1457
1412
  });
1458
1413
  } catch (error) {
1459
- const message = `Could not process XML tool call, keeping original text: ${match[0]}`;
1460
- (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(options, message, { toolCall: match[0], toolName, error });
1461
- processedElements.push({ type: "text", text: match[0] });
1414
+ const originalCallText = text.substring(
1415
+ toolCall.startIndex,
1416
+ toolCall.endIndex
1417
+ );
1418
+ const message = `Could not process XML tool call, keeping original text: ${originalCallText}`;
1419
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1420
+ toolCall: originalCallText,
1421
+ toolName: toolCall.toolName,
1422
+ error
1423
+ });
1424
+ processedElements.push({ type: "text", text: originalCallText });
1462
1425
  }
1463
- currentIndex = startIndex + match[0].length;
1426
+ currentIndex = toolCall.endIndex;
1464
1427
  }
1465
1428
  if (currentIndex < text.length) {
1466
1429
  const remainingText = text.substring(currentIndex);
@@ -1499,7 +1462,7 @@ var morphXmlProtocol = () => ({
1499
1462
  };
1500
1463
  return new TransformStream({
1501
1464
  transform(chunk, controller) {
1502
- var _a, _b;
1465
+ var _a;
1503
1466
  if (chunk.type !== "text-delta") {
1504
1467
  if (buffer) flushText(controller);
1505
1468
  controller.enqueue(chunk);
@@ -1514,112 +1477,36 @@ var morphXmlProtocol = () => ({
1514
1477
  const toolContent = buffer.substring(0, endTagIndex);
1515
1478
  buffer = buffer.substring(endTagIndex + endTag.length);
1516
1479
  try {
1517
- const parser = new XMLParser({
1518
- ignoreAttributes: false,
1519
- parseTagValue: false,
1520
- ignoreDeclaration: true,
1521
- textNodeName: "#text"
1480
+ const toolSchema = getToolSchema(
1481
+ tools,
1482
+ originalSchemas,
1483
+ currentToolCall.name
1484
+ );
1485
+ const parsed = parseXml(toolContent, toolSchema, {
1486
+ onError: options == null ? void 0 : options.onError
1522
1487
  });
1523
- const parsedArgs = ((_a = parser.parse(`<root>${toolContent}</root>`)) == null ? void 0 : _a.root) || {};
1524
- const args = {};
1525
- for (const k of Object.keys(parsedArgs || {})) {
1526
- const v = parsedArgs[k];
1527
- let val = v;
1528
- if (v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, "#text")) {
1529
- val = v == null ? void 0 : v["#text"];
1530
- }
1531
- if (Array.isArray(v)) {
1532
- val = v.map((item) => {
1533
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1534
- const textVal = item == null ? void 0 : item["#text"];
1535
- return typeof textVal === "string" ? textVal.trim() : textVal;
1536
- }
1537
- return typeof item === "string" ? item.trim() : item;
1538
- });
1539
- } else if (v && typeof v === "object" && !Object.prototype.hasOwnProperty.call(v, "#text")) {
1540
- const obj = v;
1541
- const keys = Object.keys(obj);
1542
- if (keys.length === 1 && keys[0] === "item") {
1543
- const itemValue = obj.item;
1544
- if (Array.isArray(itemValue)) {
1545
- val = itemValue.map((item) => {
1546
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1547
- const textVal = item == null ? void 0 : item["#text"];
1548
- const trimmed2 = typeof textVal === "string" ? textVal.trim() : textVal;
1549
- if (typeof trimmed2 === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed2)) {
1550
- const num = Number(trimmed2);
1551
- if (Number.isFinite(num)) return num;
1552
- }
1553
- return trimmed2;
1554
- }
1555
- const trimmed = typeof item === "string" ? item.trim() : item;
1556
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1557
- const num = Number(trimmed);
1558
- if (Number.isFinite(num)) return num;
1559
- }
1560
- return trimmed;
1561
- });
1562
- } else {
1563
- const trimmed = typeof itemValue === "string" ? itemValue.trim() : itemValue;
1564
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1565
- const num = Number(trimmed);
1566
- if (Number.isFinite(num)) {
1567
- val = num;
1568
- } else {
1569
- val = trimmed;
1570
- }
1571
- } else {
1572
- val = trimmed;
1573
- }
1574
- }
1575
- } else {
1576
- const isIndexedTuple = keys.length > 0 && keys.every((key) => /^\d+$/.test(key)) && (() => {
1577
- const indices = keys.map((k2) => parseInt(k2)).sort((a, b) => a - b);
1578
- return indices[0] === 0 && indices.every((val2, idx) => val2 === idx);
1579
- })();
1580
- if (isIndexedTuple) {
1581
- const sortedKeys = keys.sort(
1582
- (a, b) => parseInt(a) - parseInt(b)
1583
- );
1584
- val = sortedKeys.map((key) => {
1585
- const item = obj[key];
1586
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1587
- const textVal = item == null ? void 0 : item["#text"];
1588
- return typeof textVal === "string" ? textVal.trim() : textVal;
1589
- }
1590
- return typeof item === "string" ? item.trim() : item;
1591
- });
1592
- } else {
1593
- val = v;
1594
- }
1595
- }
1596
- }
1597
- args[k] = typeof val === "string" ? val.trim() : val;
1598
- }
1599
- const originalSchema = originalSchemas[currentToolCall.name];
1600
- const fallbackSchema = (_b = tools.find(
1601
- (t) => t.name === currentToolCall.name
1602
- )) == null ? void 0 : _b.inputSchema;
1603
- const toolSchema = originalSchema || fallbackSchema;
1604
- const coercedArgs = coerceBySchema(args, toolSchema);
1605
1488
  flushText(controller);
1606
1489
  controller.enqueue({
1607
1490
  type: "tool-call",
1608
1491
  toolCallId: generateId3(),
1609
1492
  toolName: currentToolCall.name,
1610
- input: JSON.stringify(coercedArgs)
1493
+ input: JSON.stringify(parsed)
1611
1494
  });
1612
- } catch (e) {
1495
+ } catch (error) {
1613
1496
  const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
1614
- if (options == null ? void 0 : options.onError) {
1615
- options.onError(
1616
- "Could not process streaming XML tool call; emitting original text.",
1617
- {
1618
- toolCall: originalCallText,
1619
- toolName: currentToolCall.name
1620
- }
1621
- );
1497
+ let message = "Could not process streaming XML tool call; emitting original text.";
1498
+ if (error instanceof RXMLDuplicateStringTagError) {
1499
+ message = `Duplicate string tags detected in streaming tool call '${currentToolCall.name}'; emitting original text.`;
1500
+ } else if (error instanceof RXMLCoercionError) {
1501
+ message = `Failed to coerce arguments for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1502
+ } else if (error instanceof RXMLParseError) {
1503
+ message = `Failed to parse XML for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1622
1504
  }
1505
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1506
+ toolCall: originalCallText,
1507
+ toolName: currentToolCall.name,
1508
+ error
1509
+ });
1623
1510
  flushText(controller, originalCallText);
1624
1511
  }
1625
1512
  currentToolCall = null;
@@ -1669,18 +1556,15 @@ var morphXmlProtocol = () => ({
1669
1556
  extractToolCallSegments({ text, tools }) {
1670
1557
  const toolNames = tools.map((t) => t.name).filter(Boolean);
1671
1558
  if (toolNames.length === 0) return [];
1672
- const names = toolNames.map((n) => escapeRegExp(String(n))).join("|");
1673
- if (!names) return [];
1674
- const regex = new RegExp(`<(${names})>[\\s\\S]*?<\\/\\1>`, "g");
1675
- const segments = [];
1676
- let m;
1677
- while ((m = regex.exec(text)) != null) {
1678
- segments.push(m[0]);
1679
- }
1680
- return segments;
1559
+ return findToolCalls(text, toolNames).map((tc) => tc.segment);
1681
1560
  }
1682
1561
  });
1683
1562
 
1563
+ // src/protocols/tool-call-protocol.ts
1564
+ function isProtocolFactory(protocol) {
1565
+ return typeof protocol === "function";
1566
+ }
1567
+
1684
1568
  // src/generate-handler.ts
1685
1569
  import { generateId as generateId4 } from "@ai-sdk/provider-utils";
1686
1570
  async function wrapGenerate({
@@ -2295,11 +2179,30 @@ San Fransisco
2295
2179
  }
2296
2180
  });
2297
2181
  export {
2182
+ robust_json_exports as RJSON,
2183
+ coerceBySchema,
2184
+ coerceToolCallInput,
2185
+ createDynamicIfThenElseSchema,
2298
2186
  createToolMiddleware,
2187
+ escapeRegExp,
2188
+ extractOnErrorOption,
2189
+ fixToolCallWithSchema,
2299
2190
  gemmaToolMiddleware,
2191
+ getDebugLevel,
2192
+ getFunctionTools,
2193
+ getPotentialStartIndex,
2194
+ getSchemaType,
2195
+ hasInputProperty,
2300
2196
  hermesToolMiddleware,
2197
+ isToolCallContent,
2198
+ isToolChoiceActive,
2199
+ isToolResultPart,
2301
2200
  jsonMixProtocol,
2201
+ logParsedChunk,
2202
+ logParsedSummary,
2203
+ logRawChunk,
2302
2204
  morphXmlProtocol,
2205
+ unwrapJsonSchema,
2303
2206
  xmlToolMiddleware
2304
2207
  };
2305
2208
  //# sourceMappingURL=index.js.map