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

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.cjs CHANGED
@@ -20,10 +20,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ applyHeuristicPipeline: () => applyHeuristicPipeline,
24
+ balanceTagsHeuristic: () => balanceTagsHeuristic,
23
25
  createDynamicIfThenElseSchema: () => createDynamicIfThenElseSchema,
26
+ createIntermediateCall: () => createIntermediateCall,
24
27
  createToolMiddleware: () => createToolMiddleware,
25
28
  decodeOriginalTools: () => decodeOriginalTools,
29
+ dedupeShellStringTagsHeuristic: () => dedupeShellStringTagsHeuristic,
30
+ defaultPipelineConfig: () => defaultPipelineConfig,
26
31
  encodeOriginalTools: () => encodeOriginalTools,
32
+ escapeInvalidLtHeuristic: () => escapeInvalidLtHeuristic,
27
33
  escapeRegExp: () => escapeRegExp,
28
34
  extractOnErrorOption: () => extractOnErrorOption,
29
35
  extractToolNamesFromOriginalTools: () => extractToolNamesFromOriginalTools,
@@ -40,10 +46,13 @@ __export(src_exports, {
40
46
  logParsedChunk: () => logParsedChunk,
41
47
  logParsedSummary: () => logParsedSummary,
42
48
  logRawChunk: () => logRawChunk,
49
+ mergePipelineConfigs: () => mergePipelineConfigs,
43
50
  morphXmlProtocol: () => morphXmlProtocol,
44
51
  morphXmlToolMiddleware: () => morphXmlToolMiddleware,
52
+ normalizeCloseTagsHeuristic: () => normalizeCloseTagsHeuristic,
45
53
  originalToolsSchema: () => originalToolsSchema,
46
54
  parseRJSON: () => parse,
55
+ repairAgainstSchemaHeuristic: () => repairAgainstSchemaHeuristic,
47
56
  stringifyRJSON: () => stringify,
48
57
  transformRJSON: () => transform
49
58
  });
@@ -1193,31 +1202,226 @@ var jsonMixProtocol = ({
1193
1202
 
1194
1203
  // src/protocols/morph-xml-protocol.ts
1195
1204
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
1196
- var import_rxml = require("@ai-sdk-tool/rxml");
1205
+ var import_rxml2 = require("@ai-sdk-tool/rxml");
1197
1206
 
1198
- // src/utils/type-guards.ts
1199
- function isToolCallContent(content) {
1200
- return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
1201
- (typeof content.input === "string" || typeof content.input === "object");
1207
+ // src/heuristics/engine.ts
1208
+ function applyRawSegmentUpdate(current, result) {
1209
+ if (result.rawSegment !== void 0) {
1210
+ return { ...current, rawSegment: result.rawSegment };
1211
+ }
1212
+ return current;
1202
1213
  }
1203
- function isToolResultPart(content) {
1204
- const c = content;
1205
- return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
1214
+ function applyParsedUpdate(current, result) {
1215
+ if (result.parsed !== void 0) {
1216
+ return { ...current, parsed: result.parsed };
1217
+ }
1218
+ return current;
1206
1219
  }
1207
- function hasInputProperty(obj) {
1208
- return typeof obj === "object" && obj !== null && "input" in obj;
1220
+ function applyWarningsUpdate(current, result) {
1221
+ var _a, _b;
1222
+ if (result.warnings && result.warnings.length > 0) {
1223
+ const meta = (_a = current.meta) != null ? _a : {};
1224
+ const existingWarnings = (_b = meta.warnings) != null ? _b : [];
1225
+ return {
1226
+ ...current,
1227
+ meta: { ...meta, warnings: [...existingWarnings, ...result.warnings] }
1228
+ };
1229
+ }
1230
+ return current;
1231
+ }
1232
+ function attemptReparse(current, result, reparseCount, maxReparses, parse4) {
1233
+ if (!result.reparse || result.rawSegment === void 0 || reparseCount >= maxReparses) {
1234
+ return { state: current, newCount: reparseCount };
1235
+ }
1236
+ try {
1237
+ const reparsed = parse4(result.rawSegment, current.schema);
1238
+ return {
1239
+ state: { ...current, parsed: reparsed, errors: [] },
1240
+ newCount: reparseCount + 1
1241
+ };
1242
+ } catch (error) {
1243
+ return {
1244
+ state: { ...current, errors: [...current.errors, error] },
1245
+ newCount: reparseCount + 1
1246
+ };
1247
+ }
1248
+ }
1249
+ function executePhase(ctx, heuristics, options) {
1250
+ var _a;
1251
+ let current = ctx;
1252
+ let reparseCount = 0;
1253
+ const maxReparses = (_a = options.maxReparses) != null ? _a : 2;
1254
+ for (const heuristic of heuristics) {
1255
+ if (!heuristic.applies(current)) {
1256
+ continue;
1257
+ }
1258
+ const result = heuristic.run(current);
1259
+ current = applyRawSegmentUpdate(current, result);
1260
+ current = applyParsedUpdate(current, result);
1261
+ current = applyWarningsUpdate(current, result);
1262
+ const reparseResult = attemptReparse(
1263
+ current,
1264
+ result,
1265
+ reparseCount,
1266
+ maxReparses,
1267
+ options.parse
1268
+ );
1269
+ current = reparseResult.state;
1270
+ reparseCount = reparseResult.newCount;
1271
+ if (result.stop) {
1272
+ break;
1273
+ }
1274
+ }
1275
+ return current;
1276
+ }
1277
+ function applyHeuristicPipeline(ctx, config, options) {
1278
+ let current = ctx;
1279
+ if (config.preParse && config.preParse.length > 0) {
1280
+ current = executePhase(current, config.preParse, options);
1281
+ }
1282
+ if (current.parsed === null && current.errors.length === 0) {
1283
+ try {
1284
+ const parsed = options.parse(current.rawSegment, current.schema);
1285
+ current = { ...current, parsed, errors: [] };
1286
+ } catch (error) {
1287
+ current = { ...current, errors: [error] };
1288
+ }
1289
+ }
1290
+ if (current.errors.length > 0 && config.fallbackReparse && config.fallbackReparse.length > 0) {
1291
+ current = executePhase(current, config.fallbackReparse, options);
1292
+ }
1293
+ if (current.parsed !== null && config.postParse && config.postParse.length > 0) {
1294
+ current = executePhase(current, config.postParse, options);
1295
+ }
1296
+ return current;
1297
+ }
1298
+ function createIntermediateCall(toolName, rawSegment, schema) {
1299
+ return {
1300
+ toolName,
1301
+ schema,
1302
+ rawSegment,
1303
+ parsed: null,
1304
+ errors: [],
1305
+ meta: { originalContent: rawSegment }
1306
+ };
1307
+ }
1308
+ function mergePipelineConfigs(...configs) {
1309
+ var _a, _b, _c;
1310
+ const result = {
1311
+ preParse: [],
1312
+ fallbackReparse: [],
1313
+ postParse: []
1314
+ };
1315
+ for (const config of configs) {
1316
+ if (config.preParse) {
1317
+ result.preParse = [...(_a = result.preParse) != null ? _a : [], ...config.preParse];
1318
+ }
1319
+ if (config.fallbackReparse) {
1320
+ result.fallbackReparse = [
1321
+ ...(_b = result.fallbackReparse) != null ? _b : [],
1322
+ ...config.fallbackReparse
1323
+ ];
1324
+ }
1325
+ if (config.postParse) {
1326
+ result.postParse = [...(_c = result.postParse) != null ? _c : [], ...config.postParse];
1327
+ }
1328
+ }
1329
+ return result;
1209
1330
  }
1210
1331
 
1211
- // src/protocols/morph-xml-protocol.ts
1212
- var WHITESPACE_REGEX2 = /\s/;
1213
- var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
1332
+ // src/heuristics/xml-defaults.ts
1333
+ var import_rxml = require("@ai-sdk-tool/rxml");
1214
1334
  var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
1215
- var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
1335
+ var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
1216
1336
  var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
1337
+ var WHITESPACE_REGEX2 = /\s/;
1338
+ var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
1339
+ var NAME_START_CHAR_RE = /[A-Za-z_:]/;
1217
1340
  var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
1218
1341
  var STATUS_TAG_RE = /<status>([\s\S]*?)<\/status>/i;
1219
- function normalizeCloseTags(xml) {
1220
- return xml.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1342
+ var normalizeCloseTagsHeuristic = {
1343
+ id: "normalize-close-tags",
1344
+ phase: "pre-parse",
1345
+ applies: () => true,
1346
+ run: (ctx) => {
1347
+ const normalized = ctx.rawSegment.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1348
+ if (normalized !== ctx.rawSegment) {
1349
+ return { rawSegment: normalized };
1350
+ }
1351
+ return {};
1352
+ }
1353
+ };
1354
+ var escapeInvalidLtHeuristic = {
1355
+ id: "escape-invalid-lt",
1356
+ phase: "pre-parse",
1357
+ applies: () => true,
1358
+ run: (ctx) => {
1359
+ const escaped = escapeInvalidLt(ctx.rawSegment);
1360
+ if (escaped !== ctx.rawSegment) {
1361
+ return { rawSegment: escaped };
1362
+ }
1363
+ return {};
1364
+ }
1365
+ };
1366
+ var balanceTagsHeuristic = {
1367
+ id: "balance-tags",
1368
+ phase: "fallback-reparse",
1369
+ applies: (ctx) => {
1370
+ var _a;
1371
+ const original = ((_a = ctx.meta) == null ? void 0 : _a.originalContent) || ctx.rawSegment;
1372
+ const normalized = original.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1373
+ const balanced = balanceTags(original);
1374
+ const hasMalformedClose = MALFORMED_CLOSE_RE.test(original);
1375
+ if (!hasMalformedClose && balanced.length > normalized.length) {
1376
+ return false;
1377
+ }
1378
+ return balanced !== normalized;
1379
+ },
1380
+ run: (ctx) => {
1381
+ var _a;
1382
+ const original = ((_a = ctx.meta) == null ? void 0 : _a.originalContent) || ctx.rawSegment;
1383
+ const balanced = balanceTags(original);
1384
+ const escaped = escapeInvalidLt(balanced);
1385
+ return { rawSegment: escaped, reparse: true };
1386
+ }
1387
+ };
1388
+ var dedupeShellStringTagsHeuristic = {
1389
+ id: "dedupe-shell-string-tags",
1390
+ phase: "fallback-reparse",
1391
+ applies: (ctx) => shouldDeduplicateStringTags(ctx.schema),
1392
+ run: (ctx) => {
1393
+ const names = getStringPropertyNames(ctx.schema);
1394
+ let deduped = ctx.rawSegment;
1395
+ for (const key of names) {
1396
+ deduped = dedupeSingleTag(deduped, key);
1397
+ }
1398
+ if (deduped !== ctx.rawSegment) {
1399
+ return { rawSegment: deduped, reparse: true };
1400
+ }
1401
+ return {};
1402
+ }
1403
+ };
1404
+ var repairAgainstSchemaHeuristic = {
1405
+ id: "repair-against-schema",
1406
+ phase: "post-parse",
1407
+ applies: (ctx) => ctx.parsed !== null && typeof ctx.parsed === "object",
1408
+ run: (ctx) => {
1409
+ const repaired = repairParsedAgainstSchema(ctx.parsed, ctx.schema);
1410
+ if (repaired !== ctx.parsed) {
1411
+ return { parsed: repaired };
1412
+ }
1413
+ return {};
1414
+ }
1415
+ };
1416
+ var defaultPipelineConfig = {
1417
+ preParse: [normalizeCloseTagsHeuristic, escapeInvalidLtHeuristic],
1418
+ fallbackReparse: [balanceTagsHeuristic, dedupeShellStringTagsHeuristic],
1419
+ postParse: [repairAgainstSchemaHeuristic]
1420
+ };
1421
+ var INDEX_TAG_RE = /^<(\d+)(?:>|\/?>)/;
1422
+ function isIndexTagAt(xml, pos) {
1423
+ const remaining = xml.slice(pos);
1424
+ return INDEX_TAG_RE.test(remaining);
1221
1425
  }
1222
1426
  function escapeInvalidLt(xml) {
1223
1427
  const len = xml.length;
@@ -1226,7 +1430,9 @@ function escapeInvalidLt(xml) {
1226
1430
  const ch = xml[i];
1227
1431
  if (ch === "<") {
1228
1432
  const next = i + 1 < len ? xml[i + 1] : "";
1229
- if (!(NAME_CHAR_RE.test(next) || next === "/" || next === "!" || next === "?")) {
1433
+ const isValidStart = NAME_START_CHAR_RE.test(next) || next === "/" || next === "!" || next === "?";
1434
+ const isIndexTag = !isValidStart && isIndexTagAt(xml, i);
1435
+ if (!(isValidStart || isIndexTag)) {
1230
1436
  out += "&lt;";
1231
1437
  continue;
1232
1438
  }
@@ -1235,60 +1441,8 @@ function escapeInvalidLt(xml) {
1235
1441
  }
1236
1442
  return out;
1237
1443
  }
1238
- function shouldDeduplicateStringTags(schema) {
1239
- const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1240
- if (!unwrapped || typeof unwrapped !== "object") {
1241
- return false;
1242
- }
1243
- const props = unwrapped.properties;
1244
- if (!props) {
1245
- return false;
1246
- }
1247
- const commandRaw = props.command;
1248
- if (!commandRaw) {
1249
- return false;
1250
- }
1251
- const command = (0, import_rxml.unwrapJsonSchema)(commandRaw);
1252
- return (command == null ? void 0 : command.type) === "array";
1253
- }
1254
- function tryParseSecondaryXml(content, toolSchema, options) {
1255
- const normalized = normalizeCloseTags(content);
1256
- const balanced = balanceTags(content);
1257
- const hasMalformedClose = MALFORMED_CLOSE_RE.test(content);
1258
- if (!hasMalformedClose && balanced.length > normalized.length) {
1259
- return null;
1260
- }
1261
- try {
1262
- let parsed = (0, import_rxml.parse)(balanced, toolSchema, {
1263
- onError: options == null ? void 0 : options.onError,
1264
- noChildNodes: []
1265
- });
1266
- parsed = repairParsedAgainstSchema(parsed, toolSchema, options);
1267
- return parsed;
1268
- } catch (_e) {
1269
- if (shouldDeduplicateStringTags(toolSchema)) {
1270
- const deduped = dedupeStringTagsAgainstSchema(balanced, toolSchema);
1271
- if (deduped !== balanced) {
1272
- try {
1273
- let reparsed = (0, import_rxml.parse)(deduped, toolSchema, {
1274
- onError: options == null ? void 0 : options.onError,
1275
- noChildNodes: []
1276
- });
1277
- reparsed = repairParsedAgainstSchema(reparsed, toolSchema, options);
1278
- return reparsed;
1279
- } catch (_) {
1280
- return null;
1281
- }
1282
- }
1283
- }
1284
- return null;
1285
- }
1286
- }
1287
1444
  function balanceTags(xml) {
1288
- const src = normalizeCloseTags(xml).replace(
1289
- STATUS_TO_STEP_BOUNDARY_RE,
1290
- "</status></step><step>"
1291
- );
1445
+ const src = xml.replace(MALFORMED_CLOSE_RE_G, "</$1>").replace(STATUS_TO_STEP_BOUNDARY_RE, "</status></step><step>");
1292
1446
  let i = 0;
1293
1447
  const len = src.length;
1294
1448
  const out = [];
@@ -1384,7 +1538,69 @@ function handleOpeningTagSegment(src, lt, out, stack) {
1384
1538
  }
1385
1539
  return q + 1;
1386
1540
  }
1387
- function repairParsedAgainstSchema(input, schema, options) {
1541
+ function shouldDeduplicateStringTags(schema) {
1542
+ const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1543
+ if (!unwrapped || typeof unwrapped !== "object") {
1544
+ return false;
1545
+ }
1546
+ const props = unwrapped.properties;
1547
+ if (!props) {
1548
+ return false;
1549
+ }
1550
+ const commandRaw = props.command;
1551
+ if (!commandRaw) {
1552
+ return false;
1553
+ }
1554
+ const command = (0, import_rxml.unwrapJsonSchema)(commandRaw);
1555
+ return (command == null ? void 0 : command.type) === "array";
1556
+ }
1557
+ function getStringPropertyNames(schema) {
1558
+ const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1559
+ if (!unwrapped || typeof unwrapped !== "object") {
1560
+ return [];
1561
+ }
1562
+ const props = unwrapped.properties;
1563
+ if (!props) {
1564
+ return [];
1565
+ }
1566
+ const names = [];
1567
+ for (const key of Object.keys(props)) {
1568
+ const prop = (0, import_rxml.unwrapJsonSchema)(
1569
+ props[key]
1570
+ );
1571
+ const type = prop.type;
1572
+ if (type === "string") {
1573
+ names.push(key);
1574
+ }
1575
+ }
1576
+ return names;
1577
+ }
1578
+ function escapeRegExp2(s) {
1579
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1580
+ }
1581
+ function dedupeSingleTag(xml, key) {
1582
+ var _a, _b;
1583
+ const escaped = escapeRegExp2(key);
1584
+ const re = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
1585
+ const matches = Array.from(xml.matchAll(re));
1586
+ if (matches.length <= 1) {
1587
+ return xml;
1588
+ }
1589
+ const last = matches.at(-1);
1590
+ let result = "";
1591
+ let cursor = 0;
1592
+ for (const m of matches) {
1593
+ const idx = (_a = m.index) != null ? _a : 0;
1594
+ result += xml.slice(cursor, idx);
1595
+ if (last && idx === ((_b = last.index) != null ? _b : -1)) {
1596
+ result += m[0];
1597
+ }
1598
+ cursor = idx + m[0].length;
1599
+ }
1600
+ result += xml.slice(cursor);
1601
+ return result;
1602
+ }
1603
+ function repairParsedAgainstSchema(input, schema) {
1388
1604
  if (!input || typeof input !== "object") {
1389
1605
  return input;
1390
1606
  }
@@ -1396,10 +1612,10 @@ function repairParsedAgainstSchema(input, schema, options) {
1396
1612
  if (!properties) {
1397
1613
  return input;
1398
1614
  }
1399
- applySchemaProps(input, properties, options);
1615
+ applySchemaProps(input, properties);
1400
1616
  return input;
1401
1617
  }
1402
- function applySchemaProps(obj, properties, options) {
1618
+ function applySchemaProps(obj, properties) {
1403
1619
  for (const key of Object.keys(obj)) {
1404
1620
  const propSchema = properties[key];
1405
1621
  if (!propSchema) {
@@ -1410,121 +1626,126 @@ function applySchemaProps(obj, properties, options) {
1410
1626
  if (propType === "array" && prop.items) {
1411
1627
  const itemSchemaRaw = prop.items;
1412
1628
  const itemSchema = (0, import_rxml.unwrapJsonSchema)(itemSchemaRaw);
1413
- obj[key] = coerceArrayItems(obj[key], itemSchema, options);
1629
+ obj[key] = coerceArrayItems(obj[key], itemSchema);
1414
1630
  continue;
1415
1631
  }
1416
1632
  if (propType === "object") {
1417
1633
  const val = obj[key];
1418
1634
  if (val && typeof val === "object") {
1419
- obj[key] = repairParsedAgainstSchema(
1420
- val,
1421
- prop,
1422
- options
1423
- );
1635
+ obj[key] = repairParsedAgainstSchema(val, prop);
1424
1636
  }
1425
1637
  }
1426
1638
  }
1427
1639
  }
1428
- function coerceArrayItems(val, itemSchema, options) {
1640
+ function coerceArrayItems(val, itemSchema) {
1429
1641
  if (!Array.isArray(val)) {
1430
1642
  return val;
1431
1643
  }
1432
- return val.map((v) => coerceArrayItem(v, itemSchema, options));
1644
+ return val.map((v) => coerceArrayItem(v, itemSchema));
1433
1645
  }
1434
- function coerceArrayItem(v, itemSchema, options) {
1646
+ function coerceArrayItem(v, itemSchema) {
1435
1647
  const itemType = itemSchema == null ? void 0 : itemSchema.type;
1436
1648
  if (typeof v === "string" && itemType === "object") {
1437
- const parsed = tryParseStringToSchemaObject(v, itemSchema, options);
1649
+ const parsed = tryParseStringToSchemaObject(v, itemSchema);
1438
1650
  if (parsed !== null) {
1439
1651
  return parsed;
1440
1652
  }
1441
- const fallback = extractStepStatusFromString(normalizeCloseTags(v));
1653
+ const fallback = extractStepStatusFromString(
1654
+ v.replace(MALFORMED_CLOSE_RE_G, "</$1>")
1655
+ );
1442
1656
  if (fallback) {
1443
1657
  return fallback;
1444
1658
  }
1445
1659
  return v;
1446
1660
  }
1447
1661
  if (v && typeof v === "object" && itemType === "object") {
1448
- return repairParsedAgainstSchema(
1449
- v,
1450
- itemSchema,
1451
- options
1452
- );
1662
+ return repairParsedAgainstSchema(v, itemSchema);
1453
1663
  }
1454
1664
  return v;
1455
1665
  }
1456
- function getStringPropertyNames(schema) {
1457
- const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1458
- if (!unwrapped || typeof unwrapped !== "object") {
1459
- return [];
1460
- }
1461
- const props = unwrapped.properties;
1462
- if (!props) {
1463
- return [];
1666
+ function tryParseStringToSchemaObject(xml, itemSchema) {
1667
+ try {
1668
+ const normalized = xml.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1669
+ const fixed = (0, import_rxml.parse)(normalized, itemSchema, { noChildNodes: [] });
1670
+ return typeof fixed === "string" ? null : fixed;
1671
+ } catch (e) {
1672
+ return null;
1464
1673
  }
1465
- const names = [];
1466
- for (const key of Object.keys(props)) {
1467
- const prop = (0, import_rxml.unwrapJsonSchema)(
1468
- props[key]
1469
- );
1470
- const type = prop.type;
1471
- if (type === "string") {
1472
- names.push(key);
1473
- }
1674
+ }
1675
+ function extractStepStatusFromString(normXml) {
1676
+ const stepMatch = normXml.match(STEP_TAG_RE);
1677
+ const statusMatch = normXml.match(STATUS_TAG_RE);
1678
+ if (stepMatch && statusMatch) {
1679
+ return { step: stepMatch[1], status: statusMatch[1] };
1474
1680
  }
1475
- return names;
1681
+ return null;
1476
1682
  }
1477
- function escapeRegExp2(s) {
1478
- return s.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&");
1683
+
1684
+ // src/utils/type-guards.ts
1685
+ function isToolCallContent(content) {
1686
+ return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
1687
+ (typeof content.input === "string" || typeof content.input === "object");
1479
1688
  }
1480
- function dedupeStringTagsAgainstSchema(xml, schema) {
1481
- const names = getStringPropertyNames(schema);
1482
- let out = xml;
1483
- for (const key of names) {
1484
- out = dedupeSingleTag(out, key);
1485
- }
1486
- return out;
1689
+ function isToolResultPart(content) {
1690
+ const c = content;
1691
+ return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
1487
1692
  }
1488
- function dedupeSingleTag(xml, key) {
1489
- var _a, _b;
1490
- const escaped = escapeRegExp2(key);
1491
- const re = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
1492
- const matches = Array.from(xml.matchAll(re));
1493
- if (matches.length <= 1) {
1494
- return xml;
1495
- }
1496
- const last = matches.at(-1);
1497
- let result = "";
1498
- let cursor = 0;
1499
- for (const m of matches) {
1500
- const idx = (_a = m.index) != null ? _a : 0;
1501
- result += xml.slice(cursor, idx);
1502
- if (last && idx === ((_b = last.index) != null ? _b : -1)) {
1503
- result += m[0];
1504
- }
1505
- cursor = idx + m[0].length;
1506
- }
1507
- result += xml.slice(cursor);
1508
- return result;
1693
+ function hasInputProperty(obj) {
1694
+ return typeof obj === "object" && obj !== null && "input" in obj;
1695
+ }
1696
+
1697
+ // src/protocols/morph-xml-protocol.ts
1698
+ var defaultPipelineConfig2 = defaultPipelineConfig;
1699
+ var applyHeuristicPipeline2 = applyHeuristicPipeline;
1700
+ var createIntermediateCall2 = createIntermediateCall;
1701
+ var mergePipelineConfigs2 = mergePipelineConfigs;
1702
+ var WHITESPACE_REGEX3 = /\s/;
1703
+ var MALFORMED_CLOSE_RE2 = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
1704
+ var MALFORMED_CLOSE_RE_G2 = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
1705
+ var NAME_CHAR_RE2 = /[A-Za-z0-9_:-]/;
1706
+ function normalizeCloseTags(xml) {
1707
+ return xml.replace(MALFORMED_CLOSE_RE_G2, "</$1>");
1509
1708
  }
1510
- function tryParseStringToSchemaObject(xml, itemSchema, options) {
1709
+ function tryParseSecondaryXml(content, toolSchema, options) {
1710
+ const normalized = normalizeCloseTags(content);
1711
+ const balanced = balanceTags(content);
1712
+ const hasMalformedClose = MALFORMED_CLOSE_RE2.test(content);
1713
+ if (!hasMalformedClose && balanced.length > normalized.length) {
1714
+ return null;
1715
+ }
1511
1716
  try {
1512
- const fixed = (0, import_rxml.parse)(normalizeCloseTags(xml), itemSchema, {
1717
+ let parsed = (0, import_rxml2.parse)(balanced, toolSchema, {
1513
1718
  onError: options == null ? void 0 : options.onError,
1514
1719
  noChildNodes: []
1515
1720
  });
1516
- return typeof fixed === "string" ? null : fixed;
1721
+ parsed = repairParsedAgainstSchema(parsed, toolSchema);
1722
+ return parsed;
1517
1723
  } catch (e) {
1724
+ if (shouldDeduplicateStringTags(toolSchema)) {
1725
+ const deduped = dedupeStringTagsAgainstSchema(balanced, toolSchema);
1726
+ if (deduped !== balanced) {
1727
+ try {
1728
+ let reparsed = (0, import_rxml2.parse)(deduped, toolSchema, {
1729
+ onError: options == null ? void 0 : options.onError,
1730
+ noChildNodes: []
1731
+ });
1732
+ reparsed = repairParsedAgainstSchema(reparsed, toolSchema);
1733
+ return reparsed;
1734
+ } catch (e2) {
1735
+ return null;
1736
+ }
1737
+ }
1738
+ }
1518
1739
  return null;
1519
1740
  }
1520
1741
  }
1521
- function extractStepStatusFromString(normXml) {
1522
- const stepMatch = normXml.match(STEP_TAG_RE);
1523
- const statusMatch = normXml.match(STATUS_TAG_RE);
1524
- if (stepMatch && statusMatch) {
1525
- return { step: stepMatch[1], status: statusMatch[1] };
1742
+ function dedupeStringTagsAgainstSchema(xml, schema) {
1743
+ const names = getStringPropertyNames(schema);
1744
+ let out = xml;
1745
+ for (const key of names) {
1746
+ out = dedupeSingleTag(out, key);
1526
1747
  }
1527
- return null;
1748
+ return out;
1528
1749
  }
1529
1750
  function processTextBeforeToolCall(text, currentIndex, toolCallStartIndex, processedElements) {
1530
1751
  if (toolCallStartIndex > currentIndex) {
@@ -1535,18 +1756,60 @@ function processTextBeforeToolCall(text, currentIndex, toolCallStartIndex, proce
1535
1756
  }
1536
1757
  return currentIndex;
1537
1758
  }
1759
+ function processToolCallWithPipeline(params) {
1760
+ var _a;
1761
+ const {
1762
+ toolCall,
1763
+ tools,
1764
+ options,
1765
+ text,
1766
+ processedElements,
1767
+ pipelineConfig = defaultPipelineConfig2,
1768
+ maxReparses
1769
+ } = params;
1770
+ const toolSchema = getToolSchema(tools, toolCall.toolName);
1771
+ const ctx = createIntermediateCall2(
1772
+ toolCall.toolName,
1773
+ toolCall.content,
1774
+ toolSchema
1775
+ );
1776
+ const result = applyHeuristicPipeline2(ctx, pipelineConfig, {
1777
+ parse: (xml, schema) => (0, import_rxml2.parse)(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1778
+ onError: options == null ? void 0 : options.onError,
1779
+ maxReparses
1780
+ });
1781
+ if (result.parsed !== null) {
1782
+ processedElements.push({
1783
+ type: "tool-call",
1784
+ toolCallId: (0, import_provider_utils2.generateId)(),
1785
+ toolName: toolCall.toolName,
1786
+ input: JSON.stringify(result.parsed)
1787
+ });
1788
+ } else {
1789
+ const originalCallText = text.substring(
1790
+ toolCall.startIndex,
1791
+ toolCall.endIndex
1792
+ );
1793
+ const message = `Could not process XML tool call, keeping original text: ${originalCallText}`;
1794
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1795
+ toolCall: originalCallText,
1796
+ toolName: toolCall.toolName,
1797
+ error: result.errors[0]
1798
+ });
1799
+ processedElements.push({ type: "text", text: originalCallText });
1800
+ }
1801
+ }
1538
1802
  function processToolCall(params) {
1539
1803
  var _a;
1540
1804
  const { toolCall, tools, options, text, processedElements } = params;
1541
1805
  const toolSchema = getToolSchema(tools, toolCall.toolName);
1542
1806
  try {
1543
1807
  const primary = escapeInvalidLt(normalizeCloseTags(toolCall.content));
1544
- let parsed = (0, import_rxml.parse)(primary, toolSchema, {
1808
+ let parsed = (0, import_rxml2.parse)(primary, toolSchema, {
1545
1809
  onError: options == null ? void 0 : options.onError,
1546
- // Disable HTML self-closing tag behavior to allow base, meta, link etc. as regular tags
1547
1810
  noChildNodes: []
1548
1811
  });
1549
- parsed = repairParsedAgainstSchema(parsed, toolSchema, options);
1812
+ parsed = repairParsedAgainstSchema(parsed, toolSchema);
1550
1813
  processedElements.push({
1551
1814
  type: "tool-call",
1552
1815
  toolCallId: (0, import_provider_utils2.generateId)(),
@@ -1589,16 +1852,67 @@ function addRemainingText(text, currentIndex, processedElements) {
1589
1852
  }
1590
1853
  }
1591
1854
  }
1855
+ function handleStreamingToolCallEndWithPipeline(params) {
1856
+ var _a;
1857
+ const {
1858
+ toolContent,
1859
+ currentToolCall,
1860
+ tools,
1861
+ options,
1862
+ ctrl,
1863
+ flushText,
1864
+ pipelineConfig = defaultPipelineConfig2,
1865
+ maxReparses
1866
+ } = params;
1867
+ const toolSchema = getToolSchema(tools, currentToolCall.name);
1868
+ const ctx = createIntermediateCall2(
1869
+ currentToolCall.name,
1870
+ toolContent,
1871
+ toolSchema
1872
+ );
1873
+ const result = applyHeuristicPipeline2(ctx, pipelineConfig, {
1874
+ parse: (xml, schema) => (0, import_rxml2.parse)(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1875
+ onError: options == null ? void 0 : options.onError,
1876
+ maxReparses
1877
+ });
1878
+ flushText(ctrl);
1879
+ if (result.parsed !== null) {
1880
+ ctrl.enqueue({
1881
+ type: "tool-call",
1882
+ toolCallId: (0, import_provider_utils2.generateId)(),
1883
+ toolName: currentToolCall.name,
1884
+ input: JSON.stringify(result.parsed)
1885
+ });
1886
+ } else {
1887
+ const endTag = `</${currentToolCall.name}>`;
1888
+ const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
1889
+ const error = result.errors[0];
1890
+ let message = "Could not process streaming XML tool call; emitting original text.";
1891
+ if (error instanceof import_rxml2.RXMLDuplicateStringTagError) {
1892
+ message = `Duplicate string tags detected in streaming tool call '${currentToolCall.name}'; emitting original text.`;
1893
+ } else if (error instanceof import_rxml2.RXMLCoercionError) {
1894
+ message = `Failed to coerce arguments for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1895
+ } else if (error instanceof import_rxml2.RXMLParseError) {
1896
+ message = `Failed to parse XML for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1897
+ }
1898
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1899
+ toolCall: originalCallText,
1900
+ toolName: currentToolCall.name,
1901
+ error
1902
+ });
1903
+ flushText(ctrl, originalCallText);
1904
+ }
1905
+ }
1592
1906
  function handleStreamingToolCallEnd(params) {
1593
1907
  const { toolContent, currentToolCall, tools, options, ctrl, flushText } = params;
1594
1908
  const toolSchema = getToolSchema(tools, currentToolCall.name);
1595
1909
  try {
1596
1910
  const primary = escapeInvalidLt(normalizeCloseTags(toolContent));
1597
- let parsed = (0, import_rxml.parse)(primary, toolSchema, {
1911
+ let parsed = (0, import_rxml2.parse)(primary, toolSchema, {
1598
1912
  onError: options == null ? void 0 : options.onError,
1599
1913
  noChildNodes: []
1600
1914
  });
1601
- parsed = repairParsedAgainstSchema(parsed, toolSchema, options);
1915
+ parsed = repairParsedAgainstSchema(parsed, toolSchema);
1602
1916
  flushText(ctrl);
1603
1917
  ctrl.enqueue({
1604
1918
  type: "tool-call",
@@ -1634,11 +1948,11 @@ function handleStreamingToolCallError(params) {
1634
1948
  const endTag = `</${currentToolCall.name}>`;
1635
1949
  const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
1636
1950
  let message = "Could not process streaming XML tool call; emitting original text.";
1637
- if (error instanceof import_rxml.RXMLDuplicateStringTagError) {
1951
+ if (error instanceof import_rxml2.RXMLDuplicateStringTagError) {
1638
1952
  message = `Duplicate string tags detected in streaming tool call '${currentToolCall.name}'; emitting original text.`;
1639
- } else if (error instanceof import_rxml.RXMLCoercionError) {
1953
+ } else if (error instanceof import_rxml2.RXMLCoercionError) {
1640
1954
  message = `Failed to coerce arguments for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1641
- } else if (error instanceof import_rxml.RXMLParseError) {
1955
+ } else if (error instanceof import_rxml2.RXMLParseError) {
1642
1956
  message = `Failed to parse XML for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1643
1957
  }
1644
1958
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
@@ -1690,7 +2004,9 @@ function processToolCallInBuffer(params) {
1690
2004
  options,
1691
2005
  controller,
1692
2006
  flushText,
1693
- setBuffer
2007
+ setBuffer,
2008
+ pipelineConfig,
2009
+ maxReparses
1694
2010
  } = params;
1695
2011
  const endTag = `</${currentToolCall.name}>`;
1696
2012
  const normalized = normalizeCloseTags(buffer);
@@ -1700,14 +2016,27 @@ function processToolCallInBuffer(params) {
1700
2016
  const toolContent = effectiveBuffer.substring(0, endTagIndex);
1701
2017
  const newBuffer = effectiveBuffer.substring(endTagIndex + endTag.length);
1702
2018
  setBuffer("");
1703
- handleStreamingToolCallEnd({
1704
- toolContent,
1705
- currentToolCall,
1706
- tools,
1707
- options,
1708
- ctrl: controller,
1709
- flushText
1710
- });
2019
+ if (pipelineConfig) {
2020
+ handleStreamingToolCallEndWithPipeline({
2021
+ toolContent,
2022
+ currentToolCall,
2023
+ tools,
2024
+ options,
2025
+ ctrl: controller,
2026
+ flushText,
2027
+ pipelineConfig,
2028
+ maxReparses
2029
+ });
2030
+ } else {
2031
+ handleStreamingToolCallEnd({
2032
+ toolContent,
2033
+ currentToolCall,
2034
+ tools,
2035
+ options,
2036
+ ctrl: controller,
2037
+ flushText
2038
+ });
2039
+ }
1711
2040
  setBuffer(newBuffer);
1712
2041
  return { buffer: newBuffer, currentToolCall: null, shouldBreak: false };
1713
2042
  }
@@ -1721,7 +2050,9 @@ function processNoToolCallInBuffer(params) {
1721
2050
  controller,
1722
2051
  flushText,
1723
2052
  tools,
1724
- options
2053
+ options,
2054
+ pipelineConfig,
2055
+ maxReparses
1725
2056
  } = params;
1726
2057
  const {
1727
2058
  index: earliestStartTagIndex,
@@ -1736,14 +2067,27 @@ function processNoToolCallInBuffer(params) {
1736
2067
  const newBuffer2 = buffer.substring(
1737
2068
  earliestStartTagIndex + selfTag.length
1738
2069
  );
1739
- handleStreamingToolCallEnd({
1740
- toolContent: "",
1741
- currentToolCall: { name: earliestToolName, content: "" },
1742
- tools,
1743
- options,
1744
- ctrl: controller,
1745
- flushText
1746
- });
2070
+ if (pipelineConfig) {
2071
+ handleStreamingToolCallEndWithPipeline({
2072
+ toolContent: "",
2073
+ currentToolCall: { name: earliestToolName, content: "" },
2074
+ tools,
2075
+ options,
2076
+ ctrl: controller,
2077
+ flushText,
2078
+ pipelineConfig,
2079
+ maxReparses
2080
+ });
2081
+ } else {
2082
+ handleStreamingToolCallEnd({
2083
+ toolContent: "",
2084
+ currentToolCall: { name: earliestToolName, content: "" },
2085
+ tools,
2086
+ options,
2087
+ ctrl: controller,
2088
+ flushText
2089
+ });
2090
+ }
1747
2091
  return {
1748
2092
  buffer: newBuffer2,
1749
2093
  currentToolCall: null,
@@ -1807,7 +2151,9 @@ function processBufferWithToolCall(params, controller) {
1807
2151
  setCurrentToolCall,
1808
2152
  tools,
1809
2153
  options,
1810
- flushText
2154
+ flushText,
2155
+ pipelineConfig,
2156
+ maxReparses
1811
2157
  } = params;
1812
2158
  const currentToolCall = getCurrentToolCall();
1813
2159
  if (!currentToolCall) {
@@ -1820,7 +2166,9 @@ function processBufferWithToolCall(params, controller) {
1820
2166
  options,
1821
2167
  controller,
1822
2168
  flushText,
1823
- setBuffer
2169
+ setBuffer,
2170
+ pipelineConfig,
2171
+ maxReparses
1824
2172
  });
1825
2173
  setBuffer(result.buffer);
1826
2174
  setCurrentToolCall(result.currentToolCall);
@@ -1835,7 +2183,9 @@ function processBufferWithoutToolCall(params, controller) {
1835
2183
  options,
1836
2184
  toolNames,
1837
2185
  maxStartTagLen,
1838
- flushText
2186
+ flushText,
2187
+ pipelineConfig,
2188
+ maxReparses
1839
2189
  } = params;
1840
2190
  const result = processNoToolCallInBuffer({
1841
2191
  buffer: getBuffer(),
@@ -1844,7 +2194,9 @@ function processBufferWithoutToolCall(params, controller) {
1844
2194
  controller,
1845
2195
  flushText,
1846
2196
  tools,
1847
- options
2197
+ options,
2198
+ pipelineConfig,
2199
+ maxReparses
1848
2200
  });
1849
2201
  setBuffer(result.buffer);
1850
2202
  setCurrentToolCall(result.currentToolCall);
@@ -1880,139 +2232,198 @@ function createProcessBufferHandler(params) {
1880
2232
  processBufferLoop(params, controller);
1881
2233
  };
1882
2234
  }
1883
- var morphXmlProtocol = () => ({
1884
- formatTools({ tools, toolSystemPromptTemplate }) {
1885
- const toolsForPrompt = (tools || []).map((tool) => ({
1886
- name: tool.name,
1887
- description: tool.description,
1888
- parameters: (0, import_rxml.unwrapJsonSchema)(tool.inputSchema)
1889
- }));
1890
- return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1891
- },
1892
- formatToolCall(toolCall) {
1893
- let args = {};
1894
- const inputValue = hasInputProperty(toolCall) ? toolCall.input : void 0;
1895
- if (typeof inputValue === "string") {
1896
- try {
1897
- args = JSON.parse(inputValue);
1898
- } catch (e) {
2235
+ function buildPipelineOptions(protocolOptions) {
2236
+ var _a, _b, _c;
2237
+ const maxReparses = protocolOptions == null ? void 0 : protocolOptions.maxReparses;
2238
+ if (protocolOptions == null ? void 0 : protocolOptions.pipeline) {
2239
+ return {
2240
+ pipelineConfig: mergePipelineConfigs2(
2241
+ defaultPipelineConfig2,
2242
+ protocolOptions.pipeline
2243
+ ),
2244
+ maxReparses
2245
+ };
2246
+ }
2247
+ if (protocolOptions == null ? void 0 : protocolOptions.heuristics) {
2248
+ return {
2249
+ pipelineConfig: {
2250
+ ...defaultPipelineConfig2,
2251
+ preParse: [
2252
+ ...(_a = defaultPipelineConfig2.preParse) != null ? _a : [],
2253
+ ...protocolOptions.heuristics.filter((h) => h.phase === "pre-parse")
2254
+ ],
2255
+ fallbackReparse: [
2256
+ ...(_b = defaultPipelineConfig2.fallbackReparse) != null ? _b : [],
2257
+ ...protocolOptions.heuristics.filter(
2258
+ (h) => h.phase === "fallback-reparse"
2259
+ )
2260
+ ],
2261
+ postParse: [
2262
+ ...(_c = defaultPipelineConfig2.postParse) != null ? _c : [],
2263
+ ...protocolOptions.heuristics.filter((h) => h.phase === "post-parse")
2264
+ ]
2265
+ },
2266
+ maxReparses
2267
+ };
2268
+ }
2269
+ return { pipelineConfig: void 0, maxReparses };
2270
+ }
2271
+ var morphXmlProtocol = (protocolOptions) => {
2272
+ const { pipelineConfig, maxReparses } = buildPipelineOptions(protocolOptions);
2273
+ return {
2274
+ formatTools({ tools, toolSystemPromptTemplate }) {
2275
+ const toolsForPrompt = (tools || []).map((tool) => ({
2276
+ name: tool.name,
2277
+ description: tool.description,
2278
+ parameters: (0, import_rxml2.unwrapJsonSchema)(tool.inputSchema)
2279
+ }));
2280
+ return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
2281
+ },
2282
+ formatToolCall(toolCall) {
2283
+ let args = {};
2284
+ const inputValue = hasInputProperty(toolCall) ? toolCall.input : void 0;
2285
+ if (typeof inputValue === "string") {
2286
+ try {
2287
+ args = JSON.parse(inputValue);
2288
+ } catch (e) {
2289
+ args = inputValue;
2290
+ }
2291
+ } else {
1899
2292
  args = inputValue;
1900
2293
  }
1901
- } else {
1902
- args = inputValue;
1903
- }
1904
- return (0, import_rxml.stringify)(toolCall.toolName, args, {
1905
- suppressEmptyNode: false,
1906
- format: false
1907
- });
1908
- },
1909
- formatToolResponse(toolResult) {
1910
- return (0, import_rxml.stringify)("tool_response", {
1911
- tool_name: toolResult.toolName,
1912
- result: toolResult.output
1913
- });
1914
- },
1915
- parseGeneratedText({ text, tools, options }) {
1916
- const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1917
- if (toolNames.length === 0) {
1918
- return [{ type: "text", text }];
1919
- }
1920
- const processedElements = [];
1921
- let currentIndex = 0;
1922
- const toolCallsRaw = findToolCalls(text, toolNames);
1923
- const toolCallsNorm = collectToolCallsFromNormalizedText(text, toolNames);
1924
- const seen = /* @__PURE__ */ new Set();
1925
- const toolCalls = [...toolCallsRaw, ...toolCallsNorm].filter((tc) => {
1926
- const key = `${tc.toolName}:${tc.startIndex}:${tc.endIndex}`;
1927
- if (seen.has(key)) {
1928
- return false;
2294
+ return (0, import_rxml2.stringify)(toolCall.toolName, args, {
2295
+ suppressEmptyNode: false,
2296
+ format: false
2297
+ });
2298
+ },
2299
+ formatToolResponse(toolResult) {
2300
+ return (0, import_rxml2.stringify)("tool_response", {
2301
+ tool_name: toolResult.toolName,
2302
+ result: toolResult.output
2303
+ });
2304
+ },
2305
+ parseGeneratedText({ text, tools, options }) {
2306
+ const toolNames = tools.map((t) => t.name).filter((name) => name != null);
2307
+ if (toolNames.length === 0) {
2308
+ return [{ type: "text", text }];
1929
2309
  }
1930
- seen.add(key);
1931
- return true;
1932
- }).sort((a, b) => a.startIndex - b.startIndex);
1933
- for (const toolCall of toolCalls) {
1934
- currentIndex = processTextBeforeToolCall(
1935
- text,
1936
- currentIndex,
1937
- toolCall.startIndex,
1938
- processedElements
1939
- );
1940
- processToolCall({ toolCall, tools, options, text, processedElements });
1941
- currentIndex = toolCall.endIndex;
1942
- }
1943
- addRemainingText(text, currentIndex, processedElements);
1944
- return processedElements;
1945
- },
1946
- createStreamParser({ tools, options }) {
1947
- const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1948
- const maxStartTagLen = toolNames.length ? Math.max(...toolNames.map((n) => `<${n}>`.length)) : 0;
1949
- let buffer = "";
1950
- let currentToolCall = null;
1951
- let currentTextId = null;
1952
- const flushText = createFlushTextHandler(
1953
- () => buffer,
1954
- (newBuffer) => {
1955
- buffer = newBuffer;
1956
- },
1957
- () => currentTextId,
1958
- (newId) => {
1959
- currentTextId = newId;
2310
+ const processedElements = [];
2311
+ let currentIndex = 0;
2312
+ const toolCallsRaw = findToolCalls(text, toolNames);
2313
+ const toolCallsNorm = collectToolCallsFromNormalizedText(text, toolNames);
2314
+ const seen = /* @__PURE__ */ new Set();
2315
+ const toolCalls = [...toolCallsRaw, ...toolCallsNorm].filter((tc) => {
2316
+ const key = `${tc.toolName}:${tc.startIndex}:${tc.endIndex}`;
2317
+ if (seen.has(key)) {
2318
+ return false;
2319
+ }
2320
+ seen.add(key);
2321
+ return true;
2322
+ }).sort((a, b) => a.startIndex - b.startIndex);
2323
+ for (const toolCall of toolCalls) {
2324
+ currentIndex = processTextBeforeToolCall(
2325
+ text,
2326
+ currentIndex,
2327
+ toolCall.startIndex,
2328
+ processedElements
2329
+ );
2330
+ if (pipelineConfig) {
2331
+ processToolCallWithPipeline({
2332
+ toolCall,
2333
+ tools,
2334
+ options,
2335
+ text,
2336
+ processedElements,
2337
+ pipelineConfig,
2338
+ maxReparses
2339
+ });
2340
+ } else {
2341
+ processToolCall({
2342
+ toolCall,
2343
+ tools,
2344
+ options,
2345
+ text,
2346
+ processedElements
2347
+ });
2348
+ }
2349
+ currentIndex = toolCall.endIndex;
1960
2350
  }
1961
- );
1962
- const processChunk = (chunk, controller) => {
1963
- if (chunk.type !== "text-delta") {
1964
- if (buffer) {
2351
+ addRemainingText(text, currentIndex, processedElements);
2352
+ return processedElements;
2353
+ },
2354
+ createStreamParser({ tools, options }) {
2355
+ const toolNames = tools.map((t) => t.name).filter((name) => name != null);
2356
+ const maxStartTagLen = toolNames.length ? Math.max(...toolNames.map((n) => `<${n}>`.length)) : 0;
2357
+ let buffer = "";
2358
+ let currentToolCall = null;
2359
+ let currentTextId = null;
2360
+ const flushText = createFlushTextHandler(
2361
+ () => buffer,
2362
+ (newBuffer) => {
2363
+ buffer = newBuffer;
2364
+ },
2365
+ () => currentTextId,
2366
+ (newId) => {
2367
+ currentTextId = newId;
2368
+ }
2369
+ );
2370
+ const processChunk = (chunk, controller) => {
2371
+ if (chunk.type !== "text-delta") {
2372
+ if (buffer) {
2373
+ flushText(controller);
2374
+ }
2375
+ controller.enqueue(chunk);
2376
+ return;
2377
+ }
2378
+ buffer += chunk.delta;
2379
+ processBuffer(controller);
2380
+ };
2381
+ const processBuffer = createProcessBufferHandler({
2382
+ getBuffer: () => buffer,
2383
+ setBuffer: (newBuffer) => {
2384
+ buffer = newBuffer;
2385
+ },
2386
+ getCurrentToolCall: () => currentToolCall,
2387
+ setCurrentToolCall: (newToolCall) => {
2388
+ currentToolCall = newToolCall;
2389
+ },
2390
+ tools,
2391
+ options,
2392
+ toolNames,
2393
+ maxStartTagLen,
2394
+ flushText,
2395
+ pipelineConfig,
2396
+ maxReparses
2397
+ });
2398
+ const flushBuffer2 = (controller) => {
2399
+ if (currentToolCall) {
2400
+ const unfinishedCall = `<${currentToolCall.name}>${buffer}`;
2401
+ flushText(controller, unfinishedCall);
2402
+ } else if (buffer) {
1965
2403
  flushText(controller);
1966
2404
  }
1967
- controller.enqueue(chunk);
1968
- return;
1969
- }
1970
- buffer += chunk.delta;
1971
- processBuffer(controller);
1972
- };
1973
- const processBuffer = createProcessBufferHandler({
1974
- getBuffer: () => buffer,
1975
- setBuffer: (newBuffer) => {
1976
- buffer = newBuffer;
1977
- },
1978
- getCurrentToolCall: () => currentToolCall,
1979
- setCurrentToolCall: (newToolCall) => {
1980
- currentToolCall = newToolCall;
1981
- },
1982
- tools,
1983
- options,
1984
- toolNames,
1985
- maxStartTagLen,
1986
- flushText
1987
- });
1988
- const flushBuffer2 = (controller) => {
1989
- if (currentToolCall) {
1990
- const unfinishedCall = `<${currentToolCall.name}>${buffer}`;
1991
- flushText(controller, unfinishedCall);
1992
- } else if (buffer) {
1993
- flushText(controller);
1994
- }
1995
- if (currentTextId) {
1996
- controller.enqueue({ type: "text-end", id: currentTextId });
1997
- }
1998
- };
1999
- return new TransformStream({
2000
- transform(chunk, controller) {
2001
- processChunk(chunk, controller);
2002
- },
2003
- flush(controller) {
2004
- flushBuffer2(controller);
2405
+ if (currentTextId) {
2406
+ controller.enqueue({ type: "text-end", id: currentTextId });
2407
+ }
2408
+ };
2409
+ return new TransformStream({
2410
+ transform(chunk, controller) {
2411
+ processChunk(chunk, controller);
2412
+ },
2413
+ flush(controller) {
2414
+ flushBuffer2(controller);
2415
+ }
2416
+ });
2417
+ },
2418
+ extractToolCallSegments({ text, tools }) {
2419
+ const toolNames = tools.map((t) => t.name).filter(Boolean);
2420
+ if (toolNames.length === 0) {
2421
+ return [];
2005
2422
  }
2006
- });
2007
- },
2008
- extractToolCallSegments({ text, tools }) {
2009
- const toolNames = tools.map((t) => t.name).filter(Boolean);
2010
- if (toolNames.length === 0) {
2011
- return [];
2423
+ return findToolCalls(text, toolNames).map((tc) => tc.segment);
2012
2424
  }
2013
- return findToolCalls(text, toolNames).map((tc) => tc.segment);
2014
- }
2015
- });
2425
+ };
2426
+ };
2016
2427
  function getToolSchema(tools, toolName) {
2017
2428
  var _a;
2018
2429
  return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
@@ -2045,32 +2456,22 @@ function skipSpecialSegment(text, lt) {
2045
2456
  }
2046
2457
  return gt + 1;
2047
2458
  }
2048
- function consumeClosingTag(text, lt, toolName) {
2459
+ function consumeClosingTag(text, lt, _toolName) {
2049
2460
  let p = lt + 2;
2050
- while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2461
+ while (p < text.length && WHITESPACE_REGEX3.test(text[p])) {
2051
2462
  p += 1;
2052
2463
  }
2053
- if (text.slice(p, p + toolName.length) === toolName) {
2054
- p += toolName.length;
2055
- while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2056
- p += 1;
2057
- }
2058
- if (text[p] === ">") {
2059
- const endPos2 = p + 1;
2060
- return { matched: true, endPos: endPos2 };
2061
- }
2062
- }
2063
2464
  const gt = text.indexOf(">", lt + 1);
2064
2465
  const endPos = gt === -1 ? text.length : gt + 1;
2065
2466
  return { matched: false, endPos };
2066
2467
  }
2067
2468
  function consumeOpenTag(text, lt) {
2068
2469
  let p = lt + 1;
2069
- while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2470
+ while (p < text.length && WHITESPACE_REGEX3.test(text[p])) {
2070
2471
  p += 1;
2071
2472
  }
2072
2473
  const nameStart = p;
2073
- while (p < text.length && NAME_CHAR_RE.test(text.charAt(p))) {
2474
+ while (p < text.length && NAME_CHAR_RE2.test(text.charAt(p))) {
2074
2475
  p += 1;
2075
2476
  }
2076
2477
  const name = text.slice(nameStart, p);
@@ -2079,7 +2480,7 @@ function consumeOpenTag(text, lt) {
2079
2480
  return null;
2080
2481
  }
2081
2482
  let r = q - 1;
2082
- while (r >= nameStart && WHITESPACE_REGEX2.test(text[r])) {
2483
+ while (r >= nameStart && WHITESPACE_REGEX3.test(text[r])) {
2083
2484
  r -= 1;
2084
2485
  }
2085
2486
  const selfClosing = text[r] === "/";
@@ -2108,11 +2509,11 @@ function nextTagToken(text, fromPos) {
2108
2509
  if (next === "/") {
2109
2510
  const closing = consumeClosingTag(text, lt, "");
2110
2511
  let p = lt + 2;
2111
- while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2512
+ while (p < text.length && WHITESPACE_REGEX3.test(text[p])) {
2112
2513
  p += 1;
2113
2514
  }
2114
2515
  const nameStart = p;
2115
- while (p < text.length && NAME_CHAR_RE.test(text.charAt(p))) {
2516
+ while (p < text.length && NAME_CHAR_RE2.test(text.charAt(p))) {
2116
2517
  p += 1;
2117
2518
  }
2118
2519
  const name = text.slice(nameStart, p);
@@ -2161,7 +2562,7 @@ function collectToolCallsFromNormalizedText(text, toolNames) {
2161
2562
  endOrig = Math.min(text.length, tagStartOrig + approxLen);
2162
2563
  }
2163
2564
  const segment = text.substring(tagStartOrig, endOrig);
2164
- const inner = (_a = (0, import_rxml.extractRawInner)(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2565
+ const inner = (_a = (0, import_rxml2.extractRawInner)(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2165
2566
  collected.push({
2166
2567
  toolName,
2167
2568
  startIndex: tagStartOrig,
@@ -2225,7 +2626,7 @@ function findToolCallsForName(text, toolName) {
2225
2626
  const fullTagEnd = findClosingTagEndFlexible(text, contentStart, toolName);
2226
2627
  if (fullTagEnd !== -1 && fullTagEnd > contentStart) {
2227
2628
  const segment = text.substring(tagStart, fullTagEnd);
2228
- const inner = (_a = (0, import_rxml.extractRawInner)(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2629
+ const inner = (_a = (0, import_rxml2.extractRawInner)(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2229
2630
  toolCalls.push({
2230
2631
  toolName,
2231
2632
  startIndex: tagStart,
@@ -2251,7 +2652,7 @@ function findToolCalls(text, toolNames) {
2251
2652
 
2252
2653
  // src/generate-handler.ts
2253
2654
  var import_provider_utils3 = require("@ai-sdk/provider-utils");
2254
- var import_rxml2 = require("@ai-sdk-tool/rxml");
2655
+ var import_rxml3 = require("@ai-sdk-tool/rxml");
2255
2656
 
2256
2657
  // src/utils/on-error.ts
2257
2658
  function extractOnErrorOption(providerOptions) {
@@ -2458,7 +2859,7 @@ function fixToolCallWithSchema(part, tools) {
2458
2859
  args = tc.input;
2459
2860
  }
2460
2861
  const schema = (_a = tools.find((t) => t.name === tc.toolName)) == null ? void 0 : _a.inputSchema;
2461
- const coerced = (0, import_rxml2.coerceBySchema)(args, schema);
2862
+ const coerced = (0, import_rxml3.coerceBySchema)(args, schema);
2462
2863
  return {
2463
2864
  ...part,
2464
2865
  input: JSON.stringify(coerced != null ? coerced : {})
@@ -3181,10 +3582,16 @@ Available functions are listed inside <tools></tools>.
3181
3582
  });
3182
3583
  // Annotate the CommonJS export names for ESM import in node:
3183
3584
  0 && (module.exports = {
3585
+ applyHeuristicPipeline,
3586
+ balanceTagsHeuristic,
3184
3587
  createDynamicIfThenElseSchema,
3588
+ createIntermediateCall,
3185
3589
  createToolMiddleware,
3186
3590
  decodeOriginalTools,
3591
+ dedupeShellStringTagsHeuristic,
3592
+ defaultPipelineConfig,
3187
3593
  encodeOriginalTools,
3594
+ escapeInvalidLtHeuristic,
3188
3595
  escapeRegExp,
3189
3596
  extractOnErrorOption,
3190
3597
  extractToolNamesFromOriginalTools,
@@ -3201,10 +3608,13 @@ Available functions are listed inside <tools></tools>.
3201
3608
  logParsedChunk,
3202
3609
  logParsedSummary,
3203
3610
  logRawChunk,
3611
+ mergePipelineConfigs,
3204
3612
  morphXmlProtocol,
3205
3613
  morphXmlToolMiddleware,
3614
+ normalizeCloseTagsHeuristic,
3206
3615
  originalToolsSchema,
3207
3616
  parseRJSON,
3617
+ repairAgainstSchemaHeuristic,
3208
3618
  stringifyRJSON,
3209
3619
  transformRJSON
3210
3620
  });