@ai-sdk-tool/parser 2.1.3 → 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,8 +1294,14 @@ 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";
1303
- var WARN_ON_DUPLICATE_STRING_TAGS = true;
1297
+ import {
1298
+ findFirstTopLevelRange,
1299
+ parse as parseXml,
1300
+ RXMLCoercionError,
1301
+ RXMLDuplicateStringTagError,
1302
+ RXMLParseError,
1303
+ stringify as stringify2
1304
+ } from "@ai-sdk-tool/rxml";
1304
1305
  function getToolSchema(tools, originalSchemas, toolName) {
1305
1306
  var _a;
1306
1307
  const original = originalSchemas[toolName];
@@ -1308,598 +1309,42 @@ function getToolSchema(tools, originalSchemas, toolName) {
1308
1309
  const fallback = (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
1309
1310
  return fallback;
1310
1311
  }
1311
- function getPropertySchema(toolSchema, key) {
1312
- const unwrapped = unwrapJsonSchema(toolSchema);
1313
- if (!unwrapped || typeof unwrapped !== "object") return void 0;
1314
- const u = unwrapped;
1315
- const props = u.properties;
1316
- if (props && Object.prototype.hasOwnProperty.call(props, key)) {
1317
- return props[key];
1318
- }
1319
- return void 0;
1320
- }
1321
- function extractRawInner(xmlContent, tagName) {
1322
- const isNameStartChar = (ch) => /[A-Za-z_:]/.test(ch);
1323
- const isNameChar = (ch) => /[A-Za-z0-9_.:-]/.test(ch);
1324
- const len = xmlContent.length;
1325
- const target = tagName;
1326
- let bestStart = -1;
1327
- let bestEnd = -1;
1328
- let bestDepth = Number.POSITIVE_INFINITY;
1329
- const skipQuoted = (s, i2) => {
1330
- const quote = s[i2];
1331
- i2++;
1332
- while (i2 < s.length) {
1333
- const ch = s[i2];
1334
- if (ch === "\\") {
1335
- i2 += 2;
1336
- continue;
1337
- }
1338
- if (ch === quote) {
1339
- return i2 + 1;
1340
- }
1341
- i2++;
1342
- }
1343
- return i2;
1344
- };
1345
- let i = 0;
1346
- let depth = 0;
1347
- while (i < len) {
1348
- const lt = xmlContent.indexOf("<", i);
1349
- if (lt === -1) return void 0;
1350
- i = lt + 1;
1351
- if (i >= len) return void 0;
1352
- const ch = xmlContent[i];
1353
- if (ch === "!") {
1354
- if (xmlContent.startsWith("!--", i + 1)) {
1355
- const close = xmlContent.indexOf("-->", i + 4);
1356
- i = close === -1 ? len : close + 3;
1357
- continue;
1358
- }
1359
- if (xmlContent.startsWith("![CDATA[", i + 1)) {
1360
- const close = xmlContent.indexOf("]]>", i + 9);
1361
- i = close === -1 ? len : close + 3;
1362
- continue;
1363
- }
1364
- const gt = xmlContent.indexOf(">", i + 1);
1365
- i = gt === -1 ? len : gt + 1;
1366
- continue;
1367
- } else if (ch === "?") {
1368
- const close = xmlContent.indexOf("?>", i + 1);
1369
- i = close === -1 ? len : close + 2;
1370
- continue;
1371
- } else if (ch === "/") {
1372
- let j = i + 1;
1373
- if (j < len && isNameStartChar(xmlContent[j])) {
1374
- j++;
1375
- while (j < len && isNameChar(xmlContent[j])) j++;
1376
- }
1377
- const gt = xmlContent.indexOf(">", j);
1378
- i = gt === -1 ? len : gt + 1;
1379
- depth = Math.max(0, depth - 1);
1380
- continue;
1381
- } else {
1382
- let j = i;
1383
- if (j < len && isNameStartChar(xmlContent[j])) {
1384
- j++;
1385
- while (j < len && isNameChar(xmlContent[j])) j++;
1386
- }
1387
- const name = xmlContent.slice(i, j);
1388
- let k = j;
1389
- let isSelfClosing = false;
1390
- while (k < len) {
1391
- const c = xmlContent[k];
1392
- if (c === '"' || c === "'") {
1393
- k = skipQuoted(xmlContent, k);
1394
- continue;
1395
- }
1396
- if (c === ">") {
1397
- break;
1398
- }
1399
- if (c === "/" && xmlContent[k + 1] === ">") {
1400
- isSelfClosing = true;
1401
- k++;
1402
- break;
1403
- }
1404
- k++;
1405
- }
1406
- const tagEnd = k;
1407
- if (name === target) {
1408
- const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1409
- if (isSelfClosing) {
1410
- if (depth < bestDepth) {
1411
- bestStart = contentStart;
1412
- bestEnd = contentStart;
1413
- bestDepth = depth;
1414
- if (bestDepth === 0) {
1415
- }
1416
- }
1417
- } else {
1418
- let pos = contentStart;
1419
- let sameDepth = 1;
1420
- while (pos < len) {
1421
- const nextLt = xmlContent.indexOf("<", pos);
1422
- if (nextLt === -1) break;
1423
- const nx = nextLt + 1;
1424
- if (nx >= len) break;
1425
- const h = xmlContent[nx];
1426
- if (h === "!") {
1427
- if (xmlContent.startsWith("!--", nx + 1)) {
1428
- const close = xmlContent.indexOf("-->", nx + 4);
1429
- pos = close === -1 ? len : close + 3;
1430
- continue;
1431
- }
1432
- if (xmlContent.startsWith("![CDATA[", nx + 1)) {
1433
- const close = xmlContent.indexOf("]]>", nx + 9);
1434
- pos = close === -1 ? len : close + 3;
1435
- continue;
1436
- }
1437
- const gt2 = xmlContent.indexOf(">", nx + 1);
1438
- pos = gt2 === -1 ? len : gt2 + 1;
1439
- continue;
1440
- } else if (h === "?") {
1441
- const close = xmlContent.indexOf("?>", nx + 1);
1442
- pos = close === -1 ? len : close + 2;
1443
- continue;
1444
- } else if (h === "/") {
1445
- let t = nx + 1;
1446
- if (t < len && isNameStartChar(xmlContent[t])) {
1447
- t++;
1448
- while (t < len && isNameChar(xmlContent[t])) t++;
1449
- }
1450
- const endName = xmlContent.slice(nx + 1, t);
1451
- const gt2 = xmlContent.indexOf(">", t);
1452
- if (endName === target) {
1453
- sameDepth--;
1454
- if (sameDepth === 0) {
1455
- if (depth < bestDepth) {
1456
- bestStart = contentStart;
1457
- bestEnd = nextLt;
1458
- bestDepth = depth;
1459
- if (bestDepth === 0) {
1460
- }
1461
- }
1462
- break;
1463
- }
1464
- }
1465
- pos = gt2 === -1 ? len : gt2 + 1;
1466
- continue;
1467
- } else {
1468
- let t = nx;
1469
- if (t < len && isNameStartChar(xmlContent[t])) {
1470
- t++;
1471
- while (t < len && isNameChar(xmlContent[t])) t++;
1472
- }
1473
- const startName = xmlContent.slice(nx, t);
1474
- let u = t;
1475
- let selfClose = false;
1476
- while (u < len) {
1477
- const cu = xmlContent[u];
1478
- if (cu === '"' || cu === "'") {
1479
- u = skipQuoted(xmlContent, u);
1480
- continue;
1481
- }
1482
- if (cu === ">") break;
1483
- if (cu === "/" && xmlContent[u + 1] === ">") {
1484
- selfClose = true;
1485
- u++;
1486
- break;
1487
- }
1488
- u++;
1489
- }
1490
- if (startName === target && !selfClose) {
1491
- sameDepth++;
1492
- }
1493
- pos = xmlContent[u] === ">" ? u + 1 : u + 1;
1494
- continue;
1495
- }
1496
- }
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;
1497
1331
  }
1498
- }
1499
- i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1500
- depth += isSelfClosing ? 0 : 1;
1501
- continue;
1502
- }
1503
- }
1504
- if (bestStart !== -1) {
1505
- return xmlContent.slice(bestStart, bestEnd);
1506
- }
1507
- return void 0;
1508
- }
1509
- function findFirstTopLevelRange(xmlContent, tagName) {
1510
- const isNameStartChar = (ch) => /[A-Za-z_:]/.test(ch);
1511
- const isNameChar = (ch) => /[A-Za-z0-9_.:-]/.test(ch);
1512
- const len = xmlContent.length;
1513
- const target = tagName;
1514
- const skipQuoted = (s, i2) => {
1515
- const quote = s[i2];
1516
- i2++;
1517
- while (i2 < s.length) {
1518
- const ch = s[i2];
1519
- if (ch === "\\") {
1520
- i2 += 2;
1521
- continue;
1522
- }
1523
- if (ch === quote) return i2 + 1;
1524
- i2++;
1525
- }
1526
- return i2;
1527
- };
1528
- let i = 0;
1529
- let depth = 0;
1530
- while (i < len) {
1531
- const lt = xmlContent.indexOf("<", i);
1532
- if (lt === -1) return void 0;
1533
- i = lt + 1;
1534
- if (i >= len) return void 0;
1535
- const ch = xmlContent[i];
1536
- if (ch === "!") {
1537
- if (xmlContent.startsWith("!--", i + 1)) {
1538
- const close = xmlContent.indexOf("-->", i + 4);
1539
- i = close === -1 ? len : close + 3;
1540
- continue;
1541
- }
1542
- if (xmlContent.startsWith("![CDATA[", i + 1)) {
1543
- const close = xmlContent.indexOf("]]>", i + 9);
1544
- i = close === -1 ? len : close + 3;
1545
- continue;
1546
- }
1547
- const gt = xmlContent.indexOf(">", i + 1);
1548
- i = gt === -1 ? len : gt + 1;
1549
- continue;
1550
- } else if (ch === "?") {
1551
- const close = xmlContent.indexOf("?>", i + 1);
1552
- i = close === -1 ? len : close + 2;
1553
- continue;
1554
- } else if (ch === "/") {
1555
- const gt = xmlContent.indexOf(">", i + 1);
1556
- i = gt === -1 ? len : gt + 1;
1557
- depth = Math.max(0, depth - 1);
1558
- continue;
1559
- } else {
1560
- let j = i;
1561
- if (j < len && isNameStartChar(xmlContent[j])) {
1562
- j++;
1563
- while (j < len && isNameChar(xmlContent[j])) j++;
1564
- }
1565
- const name = xmlContent.slice(i, j);
1566
- let k = j;
1567
- let isSelfClosing = false;
1568
- while (k < len) {
1569
- const c = xmlContent[k];
1570
- if (c === '"' || c === "'") {
1571
- k = skipQuoted(xmlContent, k);
1572
- continue;
1573
- }
1574
- if (c === ">") break;
1575
- if (c === "/" && xmlContent[k + 1] === ">") {
1576
- isSelfClosing = true;
1577
- k++;
1578
- break;
1579
- }
1580
- k++;
1581
- }
1582
- const tagEnd = k;
1583
- if (depth === 0 && name === target) {
1584
- const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1585
- if (isSelfClosing) return { start: contentStart, end: contentStart };
1586
- let pos = contentStart;
1587
- let sameDepth = 1;
1588
- while (pos < len) {
1589
- const nextLt = xmlContent.indexOf("<", pos);
1590
- if (nextLt === -1) break;
1591
- const nx = nextLt + 1;
1592
- if (nx >= len) break;
1593
- const h = xmlContent[nx];
1594
- if (h === "!") {
1595
- if (xmlContent.startsWith("!--", nx + 1)) {
1596
- const close = xmlContent.indexOf("-->", nx + 4);
1597
- pos = close === -1 ? len : close + 3;
1598
- continue;
1599
- }
1600
- if (xmlContent.startsWith("![CDATA[", nx + 1)) {
1601
- const close = xmlContent.indexOf("]]>", nx + 9);
1602
- pos = close === -1 ? len : close + 3;
1603
- continue;
1604
- }
1605
- const gt2 = xmlContent.indexOf(">", nx + 1);
1606
- pos = gt2 === -1 ? len : gt2 + 1;
1607
- continue;
1608
- } else if (h === "?") {
1609
- const close = xmlContent.indexOf("?>", nx + 1);
1610
- pos = close === -1 ? len : close + 2;
1611
- continue;
1612
- } else if (h === "/") {
1613
- let t = nx + 1;
1614
- if (t < len && isNameStartChar(xmlContent[t])) {
1615
- t++;
1616
- while (t < len && isNameChar(xmlContent[t])) t++;
1617
- }
1618
- const endName = xmlContent.slice(nx + 1, t);
1619
- const gt2 = xmlContent.indexOf(">", t);
1620
- if (endName === target) {
1621
- sameDepth--;
1622
- if (sameDepth === 0) {
1623
- return { start: contentStart, end: nextLt };
1624
- }
1625
- }
1626
- pos = gt2 === -1 ? len : gt2 + 1;
1627
- continue;
1628
- } else {
1629
- let t = nx;
1630
- if (t < len && isNameStartChar(xmlContent[t])) {
1631
- t++;
1632
- while (t < len && isNameChar(xmlContent[t])) t++;
1633
- }
1634
- let u = t;
1635
- let selfClose = false;
1636
- while (u < len) {
1637
- const cu = xmlContent[u];
1638
- if (cu === '"' || cu === "'") {
1639
- u = skipQuoted(xmlContent, u);
1640
- continue;
1641
- }
1642
- if (cu === ">") break;
1643
- if (cu === "/" && xmlContent[u + 1] === ">") {
1644
- selfClose = true;
1645
- u++;
1646
- break;
1647
- }
1648
- u++;
1649
- }
1650
- if (!selfClose) {
1651
- }
1652
- pos = xmlContent[u] === ">" ? u + 1 : u + 1;
1653
- continue;
1654
- }
1655
- }
1656
- return void 0;
1657
- }
1658
- i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1659
- depth += isSelfClosing ? 0 : 1;
1660
- continue;
1661
- }
1662
- }
1663
- return void 0;
1664
- }
1665
- function countTagOccurrences(xmlContent, tagName, excludeRanges, skipFirst = true) {
1666
- const isNameStartChar = (ch) => /[A-Za-z_:]/.test(ch);
1667
- const isNameChar = (ch) => /[A-Za-z0-9_.:-]/.test(ch);
1668
- const len = xmlContent.length;
1669
- const target = tagName;
1670
- const skipQuoted = (s, i2) => {
1671
- const quote = s[i2];
1672
- i2++;
1673
- while (i2 < s.length) {
1674
- const ch = s[i2];
1675
- if (ch === "\\") {
1676
- i2 += 2;
1677
- continue;
1678
- }
1679
- if (ch === quote) return i2 + 1;
1680
- i2++;
1681
- }
1682
- return i2;
1683
- };
1684
- let i = 0;
1685
- let count = 0;
1686
- const isExcluded = (pos) => {
1687
- if (!excludeRanges || excludeRanges.length === 0) return false;
1688
- for (const r of excludeRanges) {
1689
- if (pos >= r.start && pos < r.end) return true;
1690
- }
1691
- return false;
1692
- };
1693
- while (i < len) {
1694
- const lt = xmlContent.indexOf("<", i);
1695
- if (lt === -1) break;
1696
- i = lt + 1;
1697
- if (i >= len) break;
1698
- const ch = xmlContent[i];
1699
- if (ch === "!") {
1700
- if (xmlContent.startsWith("!--", i + 1)) {
1701
- const close = xmlContent.indexOf("-->", i + 4);
1702
- i = close === -1 ? len : close + 3;
1703
- continue;
1704
- }
1705
- if (xmlContent.startsWith("![CDATA[", i + 1)) {
1706
- const close = xmlContent.indexOf("]]>", i + 9);
1707
- i = close === -1 ? len : close + 3;
1708
- continue;
1709
- }
1710
- const gt = xmlContent.indexOf(">", i + 1);
1711
- i = gt === -1 ? len : gt + 1;
1712
- continue;
1713
- } else if (ch === "?") {
1714
- const close = xmlContent.indexOf("?>", i + 1);
1715
- i = close === -1 ? len : close + 2;
1716
- continue;
1717
- } else if (ch === "/") {
1718
- const gt = xmlContent.indexOf(">", i + 1);
1719
- i = gt === -1 ? len : gt + 1;
1720
- continue;
1721
- } else {
1722
- let j = i;
1723
- if (j < len && isNameStartChar(xmlContent[j])) {
1724
- j++;
1725
- while (j < len && isNameChar(xmlContent[j])) j++;
1726
- }
1727
- const name = xmlContent.slice(i, j);
1728
- let k = j;
1729
- while (k < len) {
1730
- const c = xmlContent[k];
1731
- if (c === '"' || c === "'") {
1732
- k = skipQuoted(xmlContent, k);
1733
- continue;
1734
- }
1735
- if (c === ">") break;
1736
- if (c === "/" && xmlContent[k + 1] === ">") {
1737
- k++;
1738
- break;
1739
- }
1740
- k++;
1741
- }
1742
- if (name === target && !isExcluded(lt)) {
1743
- if (skipFirst) {
1744
- skipFirst = false;
1745
- } else {
1746
- count++;
1747
- }
1748
- }
1749
- i = k + 1;
1750
- continue;
1751
- }
1752
- }
1753
- return count;
1754
- }
1755
- function processParsedArgs(parsedArgs, toolSchema, toolContent, toolName, options) {
1756
- var _a, _b, _c;
1757
- const args = {};
1758
- let cancelToolCall = false;
1759
- const stringTypedProps = (() => {
1760
- const set = /* @__PURE__ */ new Set();
1761
- const unwrapped = unwrapJsonSchema(toolSchema);
1762
- if (unwrapped && typeof unwrapped === "object") {
1763
- const u = unwrapped;
1764
- const props = u.properties;
1765
- if (props && typeof props === "object") {
1766
- for (const key of Object.keys(props)) {
1767
- const t = getSchemaType(props[key]);
1768
- if (t === "string") set.add(key);
1769
- }
1770
- }
1771
- }
1772
- return set;
1773
- })();
1774
- for (const k of Object.keys(parsedArgs || {})) {
1775
- const v = parsedArgs[k];
1776
- let val = v;
1777
- const propSchema = getPropertySchema(toolSchema, k);
1778
- const propType = getSchemaType(propSchema);
1779
- if (propType === "string" && !Array.isArray(v)) {
1780
- const excludeRanges = [];
1781
- for (const other of stringTypedProps) {
1782
- if (other === k) continue;
1783
- const range = findFirstTopLevelRange(toolContent, other);
1784
- if (range) excludeRanges.push(range);
1785
- }
1786
- const occurrences = countTagOccurrences(
1787
- toolContent,
1788
- k,
1789
- excludeRanges,
1790
- true
1791
- );
1792
- if (occurrences > 0) {
1793
- if (WARN_ON_DUPLICATE_STRING_TAGS) {
1794
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
1795
- options,
1796
- `Duplicate string tags for <${k}> detected; cancelling tool call`,
1797
- {
1798
- toolName,
1799
- toolCall: `<${toolName}>${toolContent}</${toolName}>`
1800
- }
1801
- );
1802
- }
1803
- cancelToolCall = true;
1804
- break;
1805
- }
1806
- const raw = extractRawInner(toolContent, k);
1807
- if (typeof raw === "string") {
1808
- args[k] = raw;
1809
- continue;
1810
- }
1811
- }
1812
- if (v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, "#text")) {
1813
- val = v == null ? void 0 : v["#text"];
1814
- }
1815
- if (Array.isArray(v)) {
1816
- if (propType === "string") {
1817
- const mapped = v.map((item) => {
1818
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1819
- const textVal = item == null ? void 0 : item["#text"];
1820
- return typeof textVal === "string" ? textVal : String(textVal);
1821
- }
1822
- return typeof item === "string" ? item : String(item);
1823
- });
1824
- if (mapped.length > 1 && WARN_ON_DUPLICATE_STRING_TAGS) {
1825
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1826
- options,
1827
- `Duplicate string tags for <${k}> detected; cancelling tool call`,
1828
- {
1829
- toolName,
1830
- toolCall: `<${toolName}>${toolContent}</${toolName}>`
1831
- }
1832
- );
1833
- }
1834
- if (mapped.length > 1) {
1835
- cancelToolCall = true;
1836
- break;
1837
- } else {
1838
- args[k] = (_c = mapped[0]) != null ? _c : "";
1839
- continue;
1840
- }
1841
- } else {
1842
- val = v.map((item) => {
1843
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1844
- const textVal = item == null ? void 0 : item["#text"];
1845
- return typeof textVal === "string" ? textVal.trim() : textVal;
1846
- }
1847
- return typeof item === "string" ? item.trim() : item;
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
1848
1340
  });
1849
- }
1850
- } else if (v && typeof v === "object" && !Object.prototype.hasOwnProperty.call(v, "#text")) {
1851
- const obj = v;
1852
- const keys = Object.keys(obj);
1853
- if (keys.length === 1 && keys[0] === "item") {
1854
- const itemValue = obj.item;
1855
- if (Array.isArray(itemValue)) {
1856
- val = itemValue.map((item) => {
1857
- let currentVal = item;
1858
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1859
- currentVal = item == null ? void 0 : item["#text"];
1860
- }
1861
- const trimmed = typeof currentVal === "string" ? currentVal.trim() : currentVal;
1862
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1863
- const num = Number(trimmed);
1864
- if (Number.isFinite(num)) return num;
1865
- }
1866
- return trimmed;
1867
- });
1868
- } else {
1869
- const trimmed = typeof itemValue === "string" ? itemValue.trim() : itemValue;
1870
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1871
- const num = Number(trimmed);
1872
- val = Number.isFinite(num) ? num : trimmed;
1873
- } else {
1874
- val = trimmed;
1875
- }
1876
- }
1341
+ searchIndex = fullTagEnd;
1877
1342
  } else {
1878
- let isIndexedTuple = false;
1879
- if (keys.length > 0 && keys.every((key) => /^\d+$/.test(key))) {
1880
- const indices = keys.map((k2) => parseInt(k2, 10)).sort((a, b) => a - b);
1881
- isIndexedTuple = indices[0] === 0 && indices.every((val2, idx) => val2 === idx);
1882
- }
1883
- if (isIndexedTuple) {
1884
- const sortedKeys = keys.sort(
1885
- (a, b) => parseInt(a, 10) - parseInt(b, 10)
1886
- );
1887
- val = sortedKeys.map((key) => {
1888
- const item = obj[key];
1889
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1890
- const textVal = item == null ? void 0 : item["#text"];
1891
- return typeof textVal === "string" ? textVal.trim() : textVal;
1892
- }
1893
- return typeof item === "string" ? item.trim() : item;
1894
- });
1895
- } else {
1896
- val = v;
1897
- }
1343
+ searchIndex = tagStart + startTag.length;
1898
1344
  }
1899
1345
  }
1900
- args[k] = typeof val === "string" ? val.trim() : val;
1901
1346
  }
1902
- return { args, cancelToolCall };
1347
+ return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
1903
1348
  }
1904
1349
  var morphXmlProtocol = () => ({
1905
1350
  formatTools({ tools, toolSystemPromptTemplate }) {
@@ -1911,7 +1356,6 @@ var morphXmlProtocol = () => ({
1911
1356
  return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1912
1357
  },
1913
1358
  formatToolCall(toolCall) {
1914
- const builder = new XMLBuilder({ format: true, suppressEmptyNode: true });
1915
1359
  let args = {};
1916
1360
  const inputValue = hasInputProperty(toolCall) ? toolCall.input : void 0;
1917
1361
  if (typeof inputValue === "string") {
@@ -1923,85 +1367,63 @@ var morphXmlProtocol = () => ({
1923
1367
  } else {
1924
1368
  args = inputValue;
1925
1369
  }
1926
- const xmlContent = builder.build({
1927
- [toolCall.toolName]: args
1370
+ return stringify2(toolCall.toolName, args, {
1371
+ suppressEmptyNode: false,
1372
+ format: false
1928
1373
  });
1929
- return xmlContent;
1930
1374
  },
1931
1375
  formatToolResponse(toolResult) {
1932
- const builder = new XMLBuilder({ format: true });
1933
- const xmlContent = builder.build({
1934
- tool_response: {
1935
- tool_name: toolResult.toolName,
1936
- result: toolResult.output
1937
- }
1376
+ return stringify2("tool_response", {
1377
+ tool_name: toolResult.toolName,
1378
+ result: toolResult.output
1938
1379
  });
1939
- return xmlContent;
1940
1380
  },
1941
1381
  parseGeneratedText({ text, tools, options }) {
1942
- var _a, _b, _c;
1382
+ var _a;
1943
1383
  const originalSchemas = (options == null ? void 0 : options.originalToolSchemas) || {};
1944
1384
  const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1945
1385
  if (toolNames.length === 0) {
1946
1386
  return [{ type: "text", text }];
1947
1387
  }
1948
- const toolNamesPattern = toolNames.map((n) => escapeRegExp(n)).join("|");
1949
- const toolCallRegex = new RegExp(
1950
- String.raw`<(${toolNamesPattern})>([\s\S]*?)<\/\1>`,
1951
- "g"
1952
- );
1953
1388
  const processedElements = [];
1954
1389
  let currentIndex = 0;
1955
- let match;
1956
- while ((match = toolCallRegex.exec(text)) !== null) {
1957
- const startIndex = match.index;
1958
- const toolName = match[1];
1959
- const toolContent = match[2].trim();
1960
- if (startIndex > currentIndex) {
1961
- 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);
1962
1394
  if (textSegment.trim()) {
1963
1395
  processedElements.push({ type: "text", text: textSegment });
1964
1396
  }
1965
1397
  }
1966
1398
  try {
1967
- const parser = new XMLParser({
1968
- ignoreAttributes: false,
1969
- parseTagValue: false,
1970
- ignoreDeclaration: true,
1971
- textNodeName: "#text"
1972
- });
1973
- const parsedArgs = ((_a = parser.parse(`<root>${toolContent}</root>`)) == null ? void 0 : _a.root) || {};
1974
- const toolSchema = getToolSchema(tools, originalSchemas, toolName);
1975
- const { args, cancelToolCall } = processParsedArgs(
1976
- parsedArgs,
1977
- toolSchema,
1978
- toolContent,
1979
- toolName,
1980
- options
1399
+ const toolSchema = getToolSchema(
1400
+ tools,
1401
+ originalSchemas,
1402
+ toolCall.toolName
1981
1403
  );
1982
- if (cancelToolCall) {
1983
- const originalCallText = match[0];
1984
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1985
- options,
1986
- `Duplicate string tags detected; cancelling tool call`,
1987
- { toolCall: originalCallText, toolName }
1988
- );
1989
- processedElements.push({ type: "text", text: originalCallText });
1990
- } else {
1991
- const coercedArgs = coerceBySchema(args, toolSchema);
1992
- processedElements.push({
1993
- type: "tool-call",
1994
- toolCallId: generateId3(),
1995
- toolName,
1996
- input: JSON.stringify(coercedArgs)
1997
- });
1998
- }
1404
+ const parsed = parseXml(toolCall.content, toolSchema, {
1405
+ onError: options == null ? void 0 : options.onError
1406
+ });
1407
+ processedElements.push({
1408
+ type: "tool-call",
1409
+ toolCallId: generateId3(),
1410
+ toolName: toolCall.toolName,
1411
+ input: JSON.stringify(parsed)
1412
+ });
1999
1413
  } catch (error) {
2000
- const message = `Could not process XML tool call, keeping original text: ${match[0]}`;
2001
- (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(options, message, { toolCall: match[0], toolName, error });
2002
- 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 });
2003
1425
  }
2004
- currentIndex = startIndex + match[0].length;
1426
+ currentIndex = toolCall.endIndex;
2005
1427
  }
2006
1428
  if (currentIndex < text.length) {
2007
1429
  const remainingText = text.substring(currentIndex);
@@ -2055,61 +1477,36 @@ var morphXmlProtocol = () => ({
2055
1477
  const toolContent = buffer.substring(0, endTagIndex);
2056
1478
  buffer = buffer.substring(endTagIndex + endTag.length);
2057
1479
  try {
2058
- const parser = new XMLParser({
2059
- ignoreAttributes: false,
2060
- parseTagValue: false,
2061
- ignoreDeclaration: true,
2062
- textNodeName: "#text"
2063
- });
2064
- const parsedArgs = ((_a = parser.parse(`<root>${toolContent}</root>`)) == null ? void 0 : _a.root) || {};
2065
1480
  const toolSchema = getToolSchema(
2066
1481
  tools,
2067
1482
  originalSchemas,
2068
1483
  currentToolCall.name
2069
1484
  );
2070
- const { args, cancelToolCall } = processParsedArgs(
2071
- parsedArgs,
2072
- toolSchema,
2073
- toolContent,
2074
- currentToolCall.name,
2075
- options
2076
- );
2077
- if (cancelToolCall) {
2078
- const originalCallText = `<${currentToolCall.name}>${toolContent}</${currentToolCall.name}>`;
2079
- if (options == null ? void 0 : options.onError) {
2080
- options.onError(
2081
- "Duplicate string tags detected; cancelling tool call",
2082
- {
2083
- toolCall: originalCallText,
2084
- toolName: currentToolCall.name
2085
- }
2086
- );
2087
- }
2088
- flushText(controller, originalCallText);
2089
- } else {
2090
- const coercedArgs = coerceBySchema(
2091
- args,
2092
- toolSchema
2093
- );
2094
- flushText(controller);
2095
- controller.enqueue({
2096
- type: "tool-call",
2097
- toolCallId: generateId3(),
2098
- toolName: currentToolCall.name,
2099
- input: JSON.stringify(coercedArgs)
2100
- });
2101
- }
2102
- } catch (e) {
1485
+ const parsed = parseXml(toolContent, toolSchema, {
1486
+ onError: options == null ? void 0 : options.onError
1487
+ });
1488
+ flushText(controller);
1489
+ controller.enqueue({
1490
+ type: "tool-call",
1491
+ toolCallId: generateId3(),
1492
+ toolName: currentToolCall.name,
1493
+ input: JSON.stringify(parsed)
1494
+ });
1495
+ } catch (error) {
2103
1496
  const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
2104
- if (options == null ? void 0 : options.onError) {
2105
- options.onError(
2106
- "Could not process streaming XML tool call; emitting original text.",
2107
- {
2108
- toolCall: originalCallText,
2109
- toolName: currentToolCall.name
2110
- }
2111
- );
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.`;
2112
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
+ });
2113
1510
  flushText(controller, originalCallText);
2114
1511
  }
2115
1512
  currentToolCall = null;
@@ -2159,18 +1556,15 @@ var morphXmlProtocol = () => ({
2159
1556
  extractToolCallSegments({ text, tools }) {
2160
1557
  const toolNames = tools.map((t) => t.name).filter(Boolean);
2161
1558
  if (toolNames.length === 0) return [];
2162
- const names = toolNames.map((n) => escapeRegExp(String(n))).join("|");
2163
- if (!names) return [];
2164
- const regex = new RegExp(`<(${names})>[\\s\\S]*?<\\/\\1>`, "g");
2165
- const segments = [];
2166
- let m;
2167
- while ((m = regex.exec(text)) != null) {
2168
- segments.push(m[0]);
2169
- }
2170
- return segments;
1559
+ return findToolCalls(text, toolNames).map((tc) => tc.segment);
2171
1560
  }
2172
1561
  });
2173
1562
 
1563
+ // src/protocols/tool-call-protocol.ts
1564
+ function isProtocolFactory(protocol) {
1565
+ return typeof protocol === "function";
1566
+ }
1567
+
2174
1568
  // src/generate-handler.ts
2175
1569
  import { generateId as generateId4 } from "@ai-sdk/provider-utils";
2176
1570
  async function wrapGenerate({
@@ -2785,11 +2179,30 @@ San Fransisco
2785
2179
  }
2786
2180
  });
2787
2181
  export {
2182
+ robust_json_exports as RJSON,
2183
+ coerceBySchema,
2184
+ coerceToolCallInput,
2185
+ createDynamicIfThenElseSchema,
2788
2186
  createToolMiddleware,
2187
+ escapeRegExp,
2188
+ extractOnErrorOption,
2189
+ fixToolCallWithSchema,
2789
2190
  gemmaToolMiddleware,
2191
+ getDebugLevel,
2192
+ getFunctionTools,
2193
+ getPotentialStartIndex,
2194
+ getSchemaType,
2195
+ hasInputProperty,
2790
2196
  hermesToolMiddleware,
2197
+ isToolCallContent,
2198
+ isToolChoiceActive,
2199
+ isToolResultPart,
2791
2200
  jsonMixProtocol,
2201
+ logParsedChunk,
2202
+ logParsedSummary,
2203
+ logRawChunk,
2792
2204
  morphXmlProtocol,
2205
+ unwrapJsonSchema,
2793
2206
  xmlToolMiddleware
2794
2207
  };
2795
2208
  //# sourceMappingURL=index.js.map