@ai-sdk-tool/parser 3.3.2 → 4.0.0

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
@@ -905,7 +905,25 @@ function getPotentialStartIndex(text, searchedText) {
905
905
 
906
906
  // src/core/utils/id.ts
907
907
  function generateId() {
908
- return Math.random().toString(36).substring(2, 15);
908
+ return crypto.randomUUID().replace(/-/g, "").slice(0, 13);
909
+ }
910
+ var TOOL_CALL_ID_PREFIX = "call_";
911
+ var TOOL_CALL_ID_BODY_LENGTH = 24;
912
+ var TOOL_CALL_ID_ALPHANUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
913
+ function randomAlphaNumeric(length) {
914
+ var _a;
915
+ const bytes = new Uint8Array(length);
916
+ crypto.getRandomValues(bytes);
917
+ let out = "";
918
+ for (let i = 0; i < length; i += 1) {
919
+ const byte = bytes[i];
920
+ const index = (byte != null ? byte : 0) % TOOL_CALL_ID_ALPHANUM.length;
921
+ out += (_a = TOOL_CALL_ID_ALPHANUM[index]) != null ? _a : "0";
922
+ }
923
+ return out;
924
+ }
925
+ function generateToolCallId() {
926
+ return `${TOOL_CALL_ID_PREFIX}${randomAlphaNumeric(TOOL_CALL_ID_BODY_LENGTH)}`;
909
927
  }
910
928
 
911
929
  // src/core/utils/protocol-utils.ts
@@ -914,6 +932,38 @@ function addTextSegment(text, processedElements) {
914
932
  processedElements.push({ type: "text", text });
915
933
  }
916
934
  }
935
+ function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
936
+ return (controller, text) => {
937
+ const content = text;
938
+ if (content) {
939
+ if (!getCurrentTextId()) {
940
+ const newId = generateId();
941
+ setCurrentTextId(newId);
942
+ controller.enqueue({
943
+ type: "text-start",
944
+ id: newId
945
+ });
946
+ setHasEmittedTextStart(true);
947
+ }
948
+ controller.enqueue({
949
+ type: "text-delta",
950
+ id: getCurrentTextId(),
951
+ delta: content
952
+ });
953
+ }
954
+ const currentTextId = getCurrentTextId();
955
+ if (currentTextId && !text) {
956
+ if (getHasEmittedTextStart()) {
957
+ controller.enqueue({
958
+ type: "text-end",
959
+ id: currentTextId
960
+ });
961
+ setHasEmittedTextStart(false);
962
+ }
963
+ setCurrentTextId(null);
964
+ }
965
+ };
966
+ }
917
967
 
918
968
  // src/core/utils/regex.ts
919
969
  function escapeRegExp(literal) {
@@ -921,15 +971,21 @@ function escapeRegExp(literal) {
921
971
  }
922
972
 
923
973
  // src/core/protocols/json-protocol.ts
974
+ function shouldEmitRawToolCallTextOnError(options) {
975
+ return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
976
+ }
977
+ function canonicalizeToolInput(argumentsValue) {
978
+ return JSON.stringify(argumentsValue != null ? argumentsValue : {});
979
+ }
924
980
  function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
925
- var _a, _b;
981
+ var _a;
926
982
  try {
927
983
  const parsedToolCall = parse(toolCallJson);
928
984
  processedElements.push({
929
985
  type: "tool-call",
930
- toolCallId: generateId(),
986
+ toolCallId: generateToolCallId(),
931
987
  toolName: parsedToolCall.name,
932
- input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
988
+ input: canonicalizeToolInput(parsedToolCall.arguments)
933
989
  });
934
990
  } catch (error) {
935
991
  logParseFailure({
@@ -938,7 +994,7 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
938
994
  snippet: fullMatch,
939
995
  error
940
996
  });
941
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
997
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
942
998
  options,
943
999
  "Could not process JSON tool call, keeping original text.",
944
1000
  { toolCall: fullMatch, error }
@@ -959,6 +1015,293 @@ function processMatchedToolCall(context) {
959
1015
  }
960
1016
  return startIndex + match[0].length;
961
1017
  }
1018
+ var WHITESPACE_JSON_REGEX = /\s/;
1019
+ function skipJsonWhitespace(text, fromIndex) {
1020
+ let index = fromIndex;
1021
+ while (index < text.length && WHITESPACE_JSON_REGEX.test(text[index])) {
1022
+ index += 1;
1023
+ }
1024
+ return index;
1025
+ }
1026
+ function findTopLevelPropertyValueStart(text, property) {
1027
+ const objectStart = skipJsonWhitespace(text, 0);
1028
+ if (objectStart >= text.length || text.charAt(objectStart) !== "{") {
1029
+ return null;
1030
+ }
1031
+ let depth = 0;
1032
+ let inString = false;
1033
+ let escaping = false;
1034
+ for (let index = objectStart; index < text.length; index += 1) {
1035
+ const char = text.charAt(index);
1036
+ if (inString) {
1037
+ if (escaping) {
1038
+ escaping = false;
1039
+ continue;
1040
+ }
1041
+ if (char === "\\") {
1042
+ escaping = true;
1043
+ continue;
1044
+ }
1045
+ if (char === '"') {
1046
+ inString = false;
1047
+ }
1048
+ continue;
1049
+ }
1050
+ if (char === "{") {
1051
+ depth += 1;
1052
+ continue;
1053
+ }
1054
+ if (char === "}") {
1055
+ depth = Math.max(0, depth - 1);
1056
+ continue;
1057
+ }
1058
+ if (char !== '"') {
1059
+ continue;
1060
+ }
1061
+ if (depth !== 1) {
1062
+ inString = true;
1063
+ continue;
1064
+ }
1065
+ const keyStart = index + 1;
1066
+ let keyEnd = keyStart;
1067
+ let keyEscaped = false;
1068
+ while (keyEnd < text.length) {
1069
+ const keyChar = text.charAt(keyEnd);
1070
+ if (keyEscaped) {
1071
+ keyEscaped = false;
1072
+ } else if (keyChar === "\\") {
1073
+ keyEscaped = true;
1074
+ } else if (keyChar === '"') {
1075
+ break;
1076
+ }
1077
+ keyEnd += 1;
1078
+ }
1079
+ if (keyEnd >= text.length || text.charAt(keyEnd) !== '"') {
1080
+ return null;
1081
+ }
1082
+ const key = text.slice(keyStart, keyEnd);
1083
+ let valueCursor = skipJsonWhitespace(text, keyEnd + 1);
1084
+ if (valueCursor >= text.length || text.charAt(valueCursor) !== ":") {
1085
+ index = keyEnd;
1086
+ continue;
1087
+ }
1088
+ valueCursor = skipJsonWhitespace(text, valueCursor + 1);
1089
+ if (key === property) {
1090
+ return valueCursor < text.length ? valueCursor : null;
1091
+ }
1092
+ index = valueCursor - 1;
1093
+ }
1094
+ return null;
1095
+ }
1096
+ function extractTopLevelStringProperty(text, property) {
1097
+ const valueStart = findTopLevelPropertyValueStart(text, property);
1098
+ if (valueStart == null || valueStart >= text.length) {
1099
+ return void 0;
1100
+ }
1101
+ if (text.charAt(valueStart) !== '"') {
1102
+ return void 0;
1103
+ }
1104
+ let valueEnd = valueStart + 1;
1105
+ let escaped = false;
1106
+ while (valueEnd < text.length) {
1107
+ const char = text.charAt(valueEnd);
1108
+ if (escaped) {
1109
+ escaped = false;
1110
+ } else if (char === "\\") {
1111
+ escaped = true;
1112
+ } else if (char === '"') {
1113
+ return text.slice(valueStart + 1, valueEnd);
1114
+ }
1115
+ valueEnd += 1;
1116
+ }
1117
+ return void 0;
1118
+ }
1119
+ function extractJsonValueSlice(text, valueStart) {
1120
+ if (valueStart >= text.length) {
1121
+ return null;
1122
+ }
1123
+ const first = text.charAt(valueStart);
1124
+ if (first === "{" || first === "[") {
1125
+ const stack = [first];
1126
+ let inString = false;
1127
+ let escaped = false;
1128
+ for (let index2 = valueStart + 1; index2 < text.length; index2 += 1) {
1129
+ const char = text.charAt(index2);
1130
+ if (inString) {
1131
+ if (escaped) {
1132
+ escaped = false;
1133
+ } else if (char === "\\") {
1134
+ escaped = true;
1135
+ } else if (char === '"') {
1136
+ inString = false;
1137
+ }
1138
+ continue;
1139
+ }
1140
+ if (char === '"') {
1141
+ inString = true;
1142
+ continue;
1143
+ }
1144
+ if (char === "{" || char === "[") {
1145
+ stack.push(char);
1146
+ continue;
1147
+ }
1148
+ if (char === "}" || char === "]") {
1149
+ const open = stack.at(-1);
1150
+ if (open === "{" && char === "}" || open === "[" && char === "]") {
1151
+ stack.pop();
1152
+ if (stack.length === 0) {
1153
+ return {
1154
+ text: text.slice(valueStart, index2 + 1),
1155
+ complete: true
1156
+ };
1157
+ }
1158
+ }
1159
+ }
1160
+ }
1161
+ return {
1162
+ text: text.slice(valueStart),
1163
+ complete: false
1164
+ };
1165
+ }
1166
+ if (first === '"') {
1167
+ let escaped = false;
1168
+ for (let index2 = valueStart + 1; index2 < text.length; index2 += 1) {
1169
+ const char = text.charAt(index2);
1170
+ if (escaped) {
1171
+ escaped = false;
1172
+ } else if (char === "\\") {
1173
+ escaped = true;
1174
+ } else if (char === '"') {
1175
+ return {
1176
+ text: text.slice(valueStart, index2 + 1),
1177
+ complete: true
1178
+ };
1179
+ }
1180
+ }
1181
+ return {
1182
+ text: text.slice(valueStart),
1183
+ complete: false
1184
+ };
1185
+ }
1186
+ let index = valueStart;
1187
+ while (index < text.length) {
1188
+ const char = text.charAt(index);
1189
+ if (char === "," || char === "}" || WHITESPACE_JSON_REGEX.test(char)) {
1190
+ break;
1191
+ }
1192
+ index += 1;
1193
+ }
1194
+ return {
1195
+ text: text.slice(valueStart, index),
1196
+ complete: index < text.length
1197
+ };
1198
+ }
1199
+ function extractStreamingToolCallProgress(toolCallJson) {
1200
+ var _a;
1201
+ const toolName = extractTopLevelStringProperty(toolCallJson, "name");
1202
+ const argsValueStart = findTopLevelPropertyValueStart(
1203
+ toolCallJson,
1204
+ "arguments"
1205
+ );
1206
+ if (argsValueStart == null) {
1207
+ return {
1208
+ toolName,
1209
+ argumentsText: void 0,
1210
+ argumentsComplete: false
1211
+ };
1212
+ }
1213
+ const argsSlice = extractJsonValueSlice(toolCallJson, argsValueStart);
1214
+ return {
1215
+ toolName,
1216
+ argumentsText: argsSlice == null ? void 0 : argsSlice.text,
1217
+ argumentsComplete: (_a = argsSlice == null ? void 0 : argsSlice.complete) != null ? _a : false
1218
+ };
1219
+ }
1220
+ function ensureToolInputStart(state, controller, toolName) {
1221
+ if (!state.activeToolInput) {
1222
+ const id = generateToolCallId();
1223
+ state.activeToolInput = {
1224
+ id,
1225
+ toolName,
1226
+ emittedInput: ""
1227
+ };
1228
+ controller.enqueue({
1229
+ type: "tool-input-start",
1230
+ id,
1231
+ toolName
1232
+ });
1233
+ }
1234
+ }
1235
+ function emitToolInputDelta(state, controller, fullInput) {
1236
+ const active = state.activeToolInput;
1237
+ if (!active) {
1238
+ return;
1239
+ }
1240
+ if (!fullInput.startsWith(active.emittedInput)) {
1241
+ return;
1242
+ }
1243
+ const delta = fullInput.slice(active.emittedInput.length);
1244
+ if (delta.length === 0) {
1245
+ return;
1246
+ }
1247
+ controller.enqueue({
1248
+ type: "tool-input-delta",
1249
+ id: active.id,
1250
+ delta
1251
+ });
1252
+ active.emittedInput = fullInput;
1253
+ }
1254
+ function closeToolInput(state, controller) {
1255
+ if (!state.activeToolInput) {
1256
+ return;
1257
+ }
1258
+ controller.enqueue({
1259
+ type: "tool-input-end",
1260
+ id: state.activeToolInput.id
1261
+ });
1262
+ state.activeToolInput = null;
1263
+ }
1264
+ function emitToolCallFromParsed(state, controller, parsedToolCall) {
1265
+ var _a, _b, _c, _d;
1266
+ closeTextBlock(state, controller);
1267
+ const toolName = typeof parsedToolCall.name === "string" ? parsedToolCall.name : (_b = (_a = state.activeToolInput) == null ? void 0 : _a.toolName) != null ? _b : "unknown";
1268
+ const input = canonicalizeToolInput(parsedToolCall.arguments);
1269
+ ensureToolInputStart(state, controller, toolName);
1270
+ emitToolInputDelta(state, controller, input);
1271
+ const toolCallId = (_d = (_c = state.activeToolInput) == null ? void 0 : _c.id) != null ? _d : generateToolCallId();
1272
+ closeToolInput(state, controller);
1273
+ controller.enqueue({
1274
+ type: "tool-call",
1275
+ toolCallId,
1276
+ toolName,
1277
+ input
1278
+ });
1279
+ }
1280
+ function canonicalizeArgumentsProgressInput(progress) {
1281
+ if (progress.argumentsText === void 0 || !progress.argumentsComplete) {
1282
+ return void 0;
1283
+ }
1284
+ try {
1285
+ const parsedArguments = parse(progress.argumentsText);
1286
+ return canonicalizeToolInput(parsedArguments);
1287
+ } catch (e) {
1288
+ return void 0;
1289
+ }
1290
+ }
1291
+ function emitToolInputProgress(state, controller) {
1292
+ if (!(state.isInsideToolCall && state.currentToolCallJson)) {
1293
+ return;
1294
+ }
1295
+ const progress = extractStreamingToolCallProgress(state.currentToolCallJson);
1296
+ if (!progress.toolName) {
1297
+ return;
1298
+ }
1299
+ ensureToolInputStart(state, controller, progress.toolName);
1300
+ const canonicalProgressInput = canonicalizeArgumentsProgressInput(progress);
1301
+ if (canonicalProgressInput !== void 0) {
1302
+ emitToolInputDelta(state, controller, canonicalProgressInput);
1303
+ }
1304
+ }
962
1305
  function flushBuffer(state, controller, toolCallStart) {
963
1306
  if (state.buffer.length === 0) {
964
1307
  return;
@@ -989,44 +1332,77 @@ function closeTextBlock(state, controller) {
989
1332
  state.hasEmittedTextStart = false;
990
1333
  }
991
1334
  }
992
- function emitIncompleteToolCall(state, controller, toolCallStart) {
993
- if (!state.currentToolCallJson) {
1335
+ function emitIncompleteToolCall(state, controller, toolCallStart, trailingBuffer, options) {
1336
+ var _a;
1337
+ if (!state.currentToolCallJson && trailingBuffer.length === 0) {
1338
+ state.isInsideToolCall = false;
994
1339
  return;
995
1340
  }
1341
+ if (state.currentToolCallJson) {
1342
+ try {
1343
+ const parsedToolCall = parse(state.currentToolCallJson);
1344
+ emitToolCallFromParsed(state, controller, parsedToolCall);
1345
+ state.currentToolCallJson = "";
1346
+ state.isInsideToolCall = false;
1347
+ return;
1348
+ } catch (e) {
1349
+ }
1350
+ }
1351
+ const rawToolCallContent = `${state.currentToolCallJson}${trailingBuffer}`;
1352
+ const errorContent = `${toolCallStart}${rawToolCallContent}`;
1353
+ const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
996
1354
  logParseFailure({
997
1355
  phase: "stream",
998
- reason: "Incomplete streaming tool call segment emitted as text",
999
- snippet: `${toolCallStart}${state.currentToolCallJson}`
1000
- });
1001
- const errorId = generateId();
1002
- const errorContent = `${toolCallStart}${state.currentToolCallJson}`;
1003
- controller.enqueue({
1004
- type: "text-start",
1005
- id: errorId
1006
- });
1007
- controller.enqueue({
1008
- type: "text-delta",
1009
- id: errorId,
1010
- delta: errorContent
1011
- });
1012
- controller.enqueue({
1013
- type: "text-end",
1014
- id: errorId
1356
+ reason: shouldEmitRawFallback ? "Incomplete streaming tool call segment emitted as text" : "Incomplete streaming tool call segment suppressed without raw text fallback",
1357
+ snippet: errorContent
1015
1358
  });
1359
+ if (shouldEmitRawFallback) {
1360
+ const errorId = generateId();
1361
+ controller.enqueue({
1362
+ type: "text-start",
1363
+ id: errorId
1364
+ });
1365
+ controller.enqueue({
1366
+ type: "text-delta",
1367
+ id: errorId,
1368
+ delta: errorContent
1369
+ });
1370
+ controller.enqueue({
1371
+ type: "text-end",
1372
+ id: errorId
1373
+ });
1374
+ }
1375
+ closeToolInput(state, controller);
1376
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
1377
+ options,
1378
+ shouldEmitRawFallback ? "Could not complete streaming JSON tool call at finish; emitting original text." : "Could not complete streaming JSON tool call at finish.",
1379
+ { toolCall: errorContent }
1380
+ );
1016
1381
  state.currentToolCallJson = "";
1382
+ state.isInsideToolCall = false;
1017
1383
  }
1018
- function handleFinishChunk(state, controller, toolCallStart, chunk) {
1019
- if (state.buffer.length > 0) {
1384
+ function handleFinishChunk(state, controller, toolCallStart, options, chunk) {
1385
+ if (state.isInsideToolCall) {
1386
+ const trailingBuffer = state.buffer;
1387
+ state.buffer = "";
1388
+ emitIncompleteToolCall(
1389
+ state,
1390
+ controller,
1391
+ toolCallStart,
1392
+ trailingBuffer,
1393
+ options
1394
+ );
1395
+ } else if (state.buffer.length > 0) {
1020
1396
  flushBuffer(state, controller, toolCallStart);
1021
1397
  }
1022
1398
  closeTextBlock(state, controller);
1023
- emitIncompleteToolCall(state, controller, toolCallStart);
1024
1399
  controller.enqueue(chunk);
1025
1400
  }
1026
1401
  function publishText(text, state, controller) {
1027
1402
  if (state.isInsideToolCall) {
1028
1403
  closeTextBlock(state, controller);
1029
1404
  state.currentToolCallJson += text;
1405
+ emitToolInputProgress(state, controller);
1030
1406
  } else if (text.length > 0) {
1031
1407
  if (!state.currentTextId) {
1032
1408
  state.currentTextId = generateId();
@@ -1044,42 +1420,40 @@ function publishText(text, state, controller) {
1044
1420
  }
1045
1421
  }
1046
1422
  function emitToolCall(context) {
1047
- var _a, _b;
1423
+ var _a;
1048
1424
  const { state, controller, toolCallStart, toolCallEnd, options } = context;
1049
1425
  try {
1050
1426
  const parsedToolCall = parse(state.currentToolCallJson);
1051
- closeTextBlock(state, controller);
1052
- controller.enqueue({
1053
- type: "tool-call",
1054
- toolCallId: generateId(),
1055
- toolName: parsedToolCall.name,
1056
- input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1057
- });
1427
+ emitToolCallFromParsed(state, controller, parsedToolCall);
1058
1428
  } catch (error) {
1429
+ const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
1430
+ const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
1059
1431
  logParseFailure({
1060
1432
  phase: "stream",
1061
1433
  reason: "Failed to parse streaming tool call JSON segment",
1062
- snippet: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`,
1434
+ snippet: errorContent,
1063
1435
  error
1064
1436
  });
1065
- const errorId = generateId();
1066
- const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
1067
- controller.enqueue({
1068
- type: "text-start",
1069
- id: errorId
1070
- });
1071
- controller.enqueue({
1072
- type: "text-delta",
1073
- id: errorId,
1074
- delta: errorContent
1075
- });
1076
- controller.enqueue({
1077
- type: "text-end",
1078
- id: errorId
1079
- });
1080
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1437
+ if (shouldEmitRawFallback) {
1438
+ const errorId = generateId();
1439
+ controller.enqueue({
1440
+ type: "text-start",
1441
+ id: errorId
1442
+ });
1443
+ controller.enqueue({
1444
+ type: "text-delta",
1445
+ id: errorId,
1446
+ delta: errorContent
1447
+ });
1448
+ controller.enqueue({
1449
+ type: "text-end",
1450
+ id: errorId
1451
+ });
1452
+ }
1453
+ closeToolInput(state, controller);
1454
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
1081
1455
  options,
1082
- "Could not process streaming JSON tool call; emitting original text.",
1456
+ shouldEmitRawFallback ? "Could not process streaming JSON tool call; emitting original text." : "Could not process streaming JSON tool call.",
1083
1457
  {
1084
1458
  toolCall: errorContent
1085
1459
  }
@@ -1095,6 +1469,7 @@ function processTagMatch(context) {
1095
1469
  } else {
1096
1470
  state.currentToolCallJson = "";
1097
1471
  state.isInsideToolCall = true;
1472
+ state.activeToolInput = null;
1098
1473
  }
1099
1474
  }
1100
1475
  function processBufferTags(context) {
@@ -1117,8 +1492,16 @@ function processBufferTags(context) {
1117
1492
  );
1118
1493
  }
1119
1494
  }
1120
- function handlePartialTag(state, controller, toolCallStart) {
1495
+ function handlePartialTag(state, controller, toolCallStart, toolCallEnd) {
1121
1496
  if (state.isInsideToolCall) {
1497
+ const potentialEndIndex = getPotentialStartIndex(state.buffer, toolCallEnd);
1498
+ if (potentialEndIndex != null && potentialEndIndex + toolCallEnd.length > state.buffer.length) {
1499
+ publishText(state.buffer.slice(0, potentialEndIndex), state, controller);
1500
+ state.buffer = state.buffer.slice(potentialEndIndex);
1501
+ } else {
1502
+ publishText(state.buffer, state, controller);
1503
+ state.buffer = "";
1504
+ }
1122
1505
  return;
1123
1506
  }
1124
1507
  const potentialIndex = getPotentialStartIndex(state.buffer, toolCallStart);
@@ -1191,13 +1574,14 @@ var jsonProtocol = ({
1191
1574
  buffer: "",
1192
1575
  currentToolCallJson: "",
1193
1576
  currentTextId: null,
1194
- hasEmittedTextStart: false
1577
+ hasEmittedTextStart: false,
1578
+ activeToolInput: null
1195
1579
  };
1196
1580
  return new TransformStream({
1197
1581
  transform(chunk, controller) {
1198
1582
  var _a;
1199
1583
  if (chunk.type === "finish") {
1200
- handleFinishChunk(state, controller, toolCallStart, chunk);
1584
+ handleFinishChunk(state, controller, toolCallStart, options, chunk);
1201
1585
  return;
1202
1586
  }
1203
1587
  if (chunk.type !== "text-delta") {
@@ -1213,7 +1597,7 @@ var jsonProtocol = ({
1213
1597
  toolCallEnd,
1214
1598
  options
1215
1599
  });
1216
- handlePartialTag(state, controller, toolCallStart);
1600
+ handlePartialTag(state, controller, toolCallStart, toolCallEnd);
1217
1601
  }
1218
1602
  });
1219
1603
  },
@@ -1577,6 +1961,13 @@ var EMPTY_OBJECT_REGEX = /^\{\s*\}$/s;
1577
1961
  var NEWLINE_SPLIT_REGEX = /\n+/;
1578
1962
  var COMMA_SPLIT_REGEX = /,\s*/;
1579
1963
  var DIGIT_KEY_REGEX = /^\d+$/;
1964
+ var WHITESPACE_REGEX2 = /\s+/g;
1965
+ var HAS_WHITESPACE_REGEX = /\s/;
1966
+ var SINGLE_QUOTE = "'";
1967
+ var DOUBLE_QUOTE = '"';
1968
+ var SNAKE_SEGMENT_REGEX = /_([a-zA-Z0-9])/g;
1969
+ var CAMEL_BOUNDARY_REGEX = /([a-z0-9])([A-Z])/g;
1970
+ var LEADING_UNDERSCORES_REGEX = /^_+/;
1580
1971
  function unwrapJsonSchema(schema) {
1581
1972
  if (!schema || typeof schema !== "object") {
1582
1973
  return schema;
@@ -1825,39 +2216,299 @@ function coerceStringToArray(s, unwrapped) {
1825
2216
  }
1826
2217
  return null;
1827
2218
  }
1828
- function coerceObjectToObject(value, unwrapped) {
1829
- const out = {};
1830
- for (const [k, v] of Object.entries(value)) {
1831
- out[k] = coerceValueForKey(v, k, unwrapped);
2219
+ function getStrictObjectSchemaInfo(unwrapped) {
2220
+ if (getSchemaType(unwrapped) !== "object") {
2221
+ return null;
1832
2222
  }
1833
- return out;
2223
+ if (unwrapped.additionalProperties !== false) {
2224
+ return null;
2225
+ }
2226
+ const properties = unwrapped.properties;
2227
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
2228
+ return null;
2229
+ }
2230
+ const propertyMap = properties;
2231
+ const required = Array.isArray(unwrapped.required) ? unwrapped.required.filter(
2232
+ (value) => typeof value === "string" && value.length > 0
2233
+ ) : [];
2234
+ const patternProps = unwrapped.patternProperties;
2235
+ const patternProperties = patternProps && typeof patternProps === "object" && !Array.isArray(patternProps) ? patternProps : void 0;
2236
+ return {
2237
+ properties: propertyMap,
2238
+ required,
2239
+ patternProperties
2240
+ };
1834
2241
  }
1835
- function coerceArrayToArray(value, prefixItems, itemsSchema) {
1836
- if (prefixItems && value.length === prefixItems.length) {
1837
- return value.map((v, i) => coerceBySchema(v, prefixItems[i]));
2242
+ function isSingularPluralPair(left, right) {
2243
+ return left.length > 1 && right.length > 1 && (left === `${right}s` || right === `${left}s`);
2244
+ }
2245
+ function snakeToCamel(value) {
2246
+ const trimmed = value.replace(LEADING_UNDERSCORES_REGEX, "");
2247
+ if (trimmed.length === 0) {
2248
+ return value;
1838
2249
  }
1839
- return value.map((v) => coerceBySchema(v, itemsSchema));
2250
+ const camelized = trimmed.replace(
2251
+ SNAKE_SEGMENT_REGEX,
2252
+ (_, c) => c.toUpperCase()
2253
+ );
2254
+ return camelized.charAt(0).toLowerCase() + camelized.slice(1);
1840
2255
  }
1841
- function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
1842
- if (Object.hasOwn(maybe, "item")) {
1843
- const items = maybe.item;
1844
- const arr = Array.isArray(items) ? items : [items];
1845
- return coerceArrayToArray(arr, prefixItems, itemsSchema);
2256
+ function camelToSnake(value) {
2257
+ return value.replace(CAMEL_BOUNDARY_REGEX, "$1_$2").toLowerCase();
2258
+ }
2259
+ function isCaseStylePair(targetKey, sourceKey) {
2260
+ if (targetKey === sourceKey) {
2261
+ return false;
2262
+ }
2263
+ const sourceLooksSnake = sourceKey.includes("_");
2264
+ const targetLooksSnake = targetKey.includes("_");
2265
+ if (sourceLooksSnake && snakeToCamel(sourceKey) === targetKey) {
2266
+ return true;
2267
+ }
2268
+ if (!sourceLooksSnake && targetLooksSnake && camelToSnake(sourceKey) === targetKey) {
2269
+ return true;
2270
+ }
2271
+ return false;
2272
+ }
2273
+ function isUnexpectedKey(key, schemaInfo) {
2274
+ if (Object.hasOwn(schemaInfo.properties, key)) {
2275
+ return false;
2276
+ }
2277
+ const patternSchemas = getPatternSchemasForKey(
2278
+ schemaInfo.patternProperties,
2279
+ key
2280
+ );
2281
+ if (patternSchemas.length > 0) {
2282
+ return patternSchemas.every((schema) => schema === false);
2283
+ }
2284
+ return true;
2285
+ }
2286
+ function computeMissingAndUnexpectedKeys(input, schemaInfo) {
2287
+ const missingRequired = schemaInfo.required.filter(
2288
+ (key) => !Object.hasOwn(input, key)
2289
+ );
2290
+ const unexpectedKeys = Object.keys(input).filter(
2291
+ (key) => isUnexpectedKey(key, schemaInfo)
2292
+ );
2293
+ return { missingRequired, unexpectedKeys };
2294
+ }
2295
+ function applySingularPluralRequiredKeyRename(input, schemaInfo) {
2296
+ const { missingRequired, unexpectedKeys } = computeMissingAndUnexpectedKeys(
2297
+ input,
2298
+ schemaInfo
2299
+ );
2300
+ if (missingRequired.length !== 1 || unexpectedKeys.length !== 1) {
2301
+ return null;
2302
+ }
2303
+ const targetKey = missingRequired[0];
2304
+ const sourceKey = unexpectedKeys[0];
2305
+ if (!Object.hasOwn(schemaInfo.properties, targetKey)) {
2306
+ return null;
2307
+ }
2308
+ if (!isSingularPluralPair(targetKey, sourceKey)) {
2309
+ return null;
2310
+ }
2311
+ if (getSchemaType(schemaInfo.properties[targetKey]) !== "array") {
2312
+ return null;
2313
+ }
2314
+ if (!Array.isArray(input[sourceKey])) {
2315
+ return null;
2316
+ }
2317
+ if (!Object.hasOwn(input, sourceKey) || Object.hasOwn(input, targetKey)) {
2318
+ return null;
2319
+ }
2320
+ const output = { ...input };
2321
+ output[targetKey] = output[sourceKey];
2322
+ delete output[sourceKey];
2323
+ return output;
2324
+ }
2325
+ function applyCaseStyleRequiredKeyRename(input, schemaInfo) {
2326
+ const { missingRequired, unexpectedKeys } = computeMissingAndUnexpectedKeys(
2327
+ input,
2328
+ schemaInfo
2329
+ );
2330
+ if (missingRequired.length !== 1 || unexpectedKeys.length !== 1) {
2331
+ return null;
2332
+ }
2333
+ const targetKey = missingRequired[0];
2334
+ const sourceKey = unexpectedKeys[0];
2335
+ if (!Object.hasOwn(schemaInfo.properties, targetKey)) {
2336
+ return null;
2337
+ }
2338
+ if (!isCaseStylePair(targetKey, sourceKey)) {
2339
+ return null;
2340
+ }
2341
+ if (!Object.hasOwn(input, sourceKey) || Object.hasOwn(input, targetKey)) {
2342
+ return null;
2343
+ }
2344
+ const output = { ...input };
2345
+ output[targetKey] = output[sourceKey];
2346
+ delete output[sourceKey];
2347
+ return output;
2348
+ }
2349
+ function applyStrictRequiredKeyRename(input, unwrapped) {
2350
+ const schemaInfo = getStrictObjectSchemaInfo(unwrapped);
2351
+ if (!schemaInfo) {
2352
+ return input;
2353
+ }
2354
+ const singularPlural = applySingularPluralRequiredKeyRename(
2355
+ input,
2356
+ schemaInfo
2357
+ );
2358
+ if (singularPlural) {
2359
+ return singularPlural;
2360
+ }
2361
+ const caseStyle = applyCaseStyleRequiredKeyRename(input, schemaInfo);
2362
+ if (caseStyle) {
2363
+ return caseStyle;
2364
+ }
2365
+ return input;
2366
+ }
2367
+ function coerceObjectToObject(value, unwrapped) {
2368
+ const normalizedInput = applyStrictRequiredKeyRename(value, unwrapped);
2369
+ const out = {};
2370
+ for (const [k, v] of Object.entries(normalizedInput)) {
2371
+ out[k] = coerceValueForKey(v, k, unwrapped);
2372
+ }
2373
+ return out;
2374
+ }
2375
+ function coerceArrayToArray(value, prefixItems, itemsSchema) {
2376
+ if (prefixItems && value.length === prefixItems.length) {
2377
+ return value.map((v, i) => coerceBySchema(v, prefixItems[i]));
2378
+ }
2379
+ return value.map((v) => coerceBySchema(v, itemsSchema));
2380
+ }
2381
+ function isPrimitiveSchemaType(schemaType) {
2382
+ return schemaType === "string" || schemaType === "number" || schemaType === "integer" || schemaType === "boolean";
2383
+ }
2384
+ function isPrimitiveMatchForSchemaType(value, schemaType) {
2385
+ if (schemaType === "string") {
2386
+ return typeof value === "string";
2387
+ }
2388
+ if (schemaType === "number") {
2389
+ return typeof value === "number" && Number.isFinite(value);
2390
+ }
2391
+ if (schemaType === "integer") {
2392
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value);
2393
+ }
2394
+ return typeof value === "boolean";
2395
+ }
2396
+ function coercePrimitiveWrappedObject(value, itemsSchema) {
2397
+ const schemaType = getSchemaType(itemsSchema);
2398
+ if (!isPrimitiveSchemaType(schemaType)) {
2399
+ return null;
2400
+ }
2401
+ const keys = Object.keys(value);
2402
+ if (keys.length !== 1) {
2403
+ return null;
2404
+ }
2405
+ const singleValue = value[keys[0]];
2406
+ if (singleValue && typeof singleValue === "object") {
2407
+ return null;
2408
+ }
2409
+ const coerced = coerceBySchema(singleValue, itemsSchema);
2410
+ return isPrimitiveMatchForSchemaType(coerced, schemaType) ? coerced : null;
2411
+ }
2412
+ function coerceParallelArraysObjectToArray(maybe, prefixItems, itemsSchema) {
2413
+ if (prefixItems && prefixItems.length > 0) {
2414
+ return null;
2415
+ }
2416
+ const unwrappedItems = unwrapJsonSchema(itemsSchema);
2417
+ if (!unwrappedItems || typeof unwrappedItems !== "object" || Array.isArray(unwrappedItems)) {
2418
+ return null;
2419
+ }
2420
+ const itemSchema = unwrappedItems;
2421
+ if (getSchemaType(itemSchema) !== "object") {
2422
+ return null;
2423
+ }
2424
+ if (itemSchema.additionalProperties !== false) {
2425
+ return null;
2426
+ }
2427
+ const properties = itemSchema.properties;
2428
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
2429
+ return null;
2430
+ }
2431
+ const propertyMap = properties;
2432
+ const entries = Object.entries(maybe);
2433
+ if (entries.length < 2) {
2434
+ return null;
2435
+ }
2436
+ if (!entries.every(([, value]) => Array.isArray(value))) {
2437
+ return null;
2438
+ }
2439
+ if (!entries.every(([key]) => Object.hasOwn(propertyMap, key))) {
2440
+ return null;
2441
+ }
2442
+ if (!entries.every(([key]) => {
2443
+ const schemaType = getSchemaType(propertyMap[key]);
2444
+ return schemaType !== "array" && schemaType !== "object";
2445
+ })) {
2446
+ return null;
2447
+ }
2448
+ const lengths = [
2449
+ ...new Set(entries.map(([, value]) => value.length))
2450
+ ];
2451
+ if (lengths.length !== 1) {
2452
+ return null;
2453
+ }
2454
+ const length = lengths[0];
2455
+ if (length < 2) {
2456
+ return null;
2457
+ }
2458
+ const zipped = [];
2459
+ for (let index = 0; index < length; index += 1) {
2460
+ const item = {};
2461
+ for (const [key, value] of entries) {
2462
+ item[key] = value[index];
2463
+ }
2464
+ zipped.push(item);
2465
+ }
2466
+ return coerceArrayToArray(zipped, prefixItems, itemsSchema);
2467
+ }
2468
+ function coerceSingleKeyObjectToArray(singleValue, itemsSchema) {
2469
+ if (Array.isArray(singleValue)) {
2470
+ return singleValue.map((v) => coerceBySchema(v, itemsSchema));
2471
+ }
2472
+ if (singleValue && typeof singleValue === "object") {
2473
+ const primitiveWrapped = coercePrimitiveWrappedObject(
2474
+ singleValue,
2475
+ itemsSchema
2476
+ );
2477
+ if (primitiveWrapped !== null) {
2478
+ return [primitiveWrapped];
2479
+ }
2480
+ return [coerceBySchema(singleValue, itemsSchema)];
2481
+ }
2482
+ return null;
2483
+ }
2484
+ function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
2485
+ if (Object.hasOwn(maybe, "item")) {
2486
+ const items = maybe.item;
2487
+ const arr = Array.isArray(items) ? items : [items];
2488
+ return coerceArrayToArray(arr, prefixItems, itemsSchema);
1846
2489
  }
1847
2490
  const keys = Object.keys(maybe);
1848
2491
  if (keys.length > 0 && keys.every((k) => DIGIT_KEY_REGEX.test(k))) {
1849
2492
  const arr = keys.sort((a, b) => Number(a) - Number(b)).map((k) => maybe[k]);
1850
2493
  return coerceArrayToArray(arr, prefixItems, itemsSchema);
1851
2494
  }
2495
+ const parallelArrays = coerceParallelArraysObjectToArray(
2496
+ maybe,
2497
+ prefixItems,
2498
+ itemsSchema
2499
+ );
2500
+ if (parallelArrays !== null) {
2501
+ return parallelArrays;
2502
+ }
1852
2503
  if (keys.length === 1) {
1853
2504
  const singleKey = keys[0];
1854
2505
  if (!(schemaIsUnconstrained(itemsSchema) || schemaHasProperty(itemsSchema, singleKey))) {
1855
- const singleValue = maybe[singleKey];
1856
- if (Array.isArray(singleValue)) {
1857
- return singleValue.map((v) => coerceBySchema(v, itemsSchema));
1858
- }
1859
- if (singleValue && typeof singleValue === "object") {
1860
- return [coerceBySchema(singleValue, itemsSchema)];
2506
+ const result = coerceSingleKeyObjectToArray(
2507
+ maybe[singleKey],
2508
+ itemsSchema
2509
+ );
2510
+ if (result !== null) {
2511
+ return result;
1861
2512
  }
1862
2513
  }
1863
2514
  }
@@ -1887,6 +2538,86 @@ function coerceStringToPrimitive(s, schemaType) {
1887
2538
  }
1888
2539
  return null;
1889
2540
  }
2541
+ function coercePrimitiveToString(value, schemaType) {
2542
+ if (schemaType !== "string") {
2543
+ return null;
2544
+ }
2545
+ if (typeof value === "boolean") {
2546
+ return value ? "true" : "false";
2547
+ }
2548
+ if (typeof value === "number" && Number.isFinite(value)) {
2549
+ return String(value);
2550
+ }
2551
+ return null;
2552
+ }
2553
+ function coerceStringByEnumWhitespace(rawValue, unwrapped) {
2554
+ const enumValues = unwrapped.enum;
2555
+ if (!Array.isArray(enumValues) || enumValues.length === 0) {
2556
+ return null;
2557
+ }
2558
+ if (!enumValues.every((item) => typeof item === "string")) {
2559
+ return null;
2560
+ }
2561
+ const normalizedEnumValues = enumValues;
2562
+ if (normalizedEnumValues.includes(rawValue)) {
2563
+ return null;
2564
+ }
2565
+ const unquoted = unwrapMatchingQuotes(rawValue);
2566
+ if (unquoted !== null) {
2567
+ const exactMatches = normalizedEnumValues.filter(
2568
+ (item) => item === unquoted
2569
+ );
2570
+ if (exactMatches.length === 1) {
2571
+ return exactMatches[0];
2572
+ }
2573
+ }
2574
+ const candidates = [rawValue, unquoted].filter(
2575
+ (item) => item !== null
2576
+ );
2577
+ for (const candidate of candidates) {
2578
+ if (!HAS_WHITESPACE_REGEX.test(candidate)) {
2579
+ continue;
2580
+ }
2581
+ const normalizedInput = candidate.replace(WHITESPACE_REGEX2, "");
2582
+ const matches = normalizedEnumValues.filter(
2583
+ (item) => item.replace(WHITESPACE_REGEX2, "") === normalizedInput
2584
+ );
2585
+ if (matches.length === 1) {
2586
+ return matches[0];
2587
+ }
2588
+ }
2589
+ return null;
2590
+ }
2591
+ function unwrapMatchingQuotes(value) {
2592
+ if (value.length < 2) {
2593
+ return null;
2594
+ }
2595
+ const first = value[0];
2596
+ const last = value.at(-1);
2597
+ const isQuote = (first === SINGLE_QUOTE || first === DOUBLE_QUOTE) && first === last;
2598
+ if (!isQuote) {
2599
+ return null;
2600
+ }
2601
+ return value.slice(1, -1);
2602
+ }
2603
+ function coerceObjectToPrimitive(value, schemaType, fullSchema) {
2604
+ if (!isPrimitiveSchemaType(schemaType)) {
2605
+ return null;
2606
+ }
2607
+ const keys = Object.keys(value);
2608
+ if (keys.length !== 1) {
2609
+ return null;
2610
+ }
2611
+ const singleValue = value[keys[0]];
2612
+ if (singleValue && typeof singleValue === "object") {
2613
+ return null;
2614
+ }
2615
+ const coerced = coerceBySchema(
2616
+ singleValue,
2617
+ fullSchema != null ? fullSchema : { type: schemaType }
2618
+ );
2619
+ return isPrimitiveMatchForSchemaType(coerced, schemaType) ? coerced : null;
2620
+ }
1890
2621
  function coerceStringValue(value, schemaType, u) {
1891
2622
  const s = value.trim();
1892
2623
  if (schemaType === "object") {
@@ -1905,6 +2636,10 @@ function coerceStringValue(value, schemaType, u) {
1905
2636
  if (primitiveResult !== null) {
1906
2637
  return primitiveResult;
1907
2638
  }
2639
+ const enumWhitespaceCanonical = coerceStringByEnumWhitespace(s, u);
2640
+ if (enumWhitespaceCanonical !== null) {
2641
+ return enumWhitespaceCanonical;
2642
+ }
1908
2643
  return value;
1909
2644
  }
1910
2645
  function coerceArrayValue(value, prefixItems, itemsSchema) {
@@ -1943,9 +2678,23 @@ function coerceBySchema(value, schema) {
1943
2678
  if (typeof value === "string") {
1944
2679
  return coerceStringValue(value, schemaType, u);
1945
2680
  }
2681
+ const primitiveString = coercePrimitiveToString(value, schemaType);
2682
+ if (primitiveString !== null) {
2683
+ return primitiveString;
2684
+ }
1946
2685
  if (schemaType === "object" && value && typeof value === "object" && !Array.isArray(value)) {
1947
2686
  return coerceObjectToObject(value, u);
1948
2687
  }
2688
+ if (value && typeof value === "object" && !Array.isArray(value) && isPrimitiveSchemaType(schemaType)) {
2689
+ const primitiveResult = coerceObjectToPrimitive(
2690
+ value,
2691
+ schemaType,
2692
+ u
2693
+ );
2694
+ if (primitiveResult !== null) {
2695
+ return primitiveResult;
2696
+ }
2697
+ }
1949
2698
  if (schemaType === "array") {
1950
2699
  const prefixItems = Array.isArray(u.prefixItems) ? u.prefixItems : void 0;
1951
2700
  const itemsSchema = u.items;
@@ -2960,7 +3709,7 @@ var XMLTokenizer = class {
2960
3709
  };
2961
3710
 
2962
3711
  // src/rxml/core/parser.ts
2963
- var WHITESPACE_REGEX2 = /\s/;
3712
+ var WHITESPACE_REGEX3 = /\s/;
2964
3713
  var NUMERIC_STRING_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
2965
3714
  var DIGIT_KEY_REGEX2 = /^\d+$/;
2966
3715
  function getTopLevelStringProps(s) {
@@ -3130,7 +3879,7 @@ function parse2(xmlInner, schema, options = {}) {
3130
3879
  const closeHead = s.indexOf(`</${rootName}`, range.end);
3131
3880
  if (closeHead === range.end) {
3132
3881
  let p = closeHead + 2 + rootName.length;
3133
- while (p < s.length && WHITESPACE_REGEX2.test(s[p])) {
3882
+ while (p < s.length && WHITESPACE_REGEX3.test(s[p])) {
3134
3883
  p += 1;
3135
3884
  }
3136
3885
  if (s[p] === ">") {
@@ -3468,7 +4217,7 @@ function createIntermediateCall(toolName, rawSegment, schema) {
3468
4217
  var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
3469
4218
  var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
3470
4219
  var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
3471
- var WHITESPACE_REGEX3 = /\s/;
4220
+ var WHITESPACE_REGEX4 = /\s/;
3472
4221
  var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
3473
4222
  var NAME_START_CHAR_RE = /[A-Za-z_:]/;
3474
4223
  var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
@@ -3609,7 +4358,7 @@ function balanceTags(xml) {
3609
4358
  }
3610
4359
  function skipWs(s, p, len) {
3611
4360
  let idx = p;
3612
- while (idx < len && WHITESPACE_REGEX3.test(s[idx])) {
4361
+ while (idx < len && WHITESPACE_REGEX4.test(s[idx])) {
3613
4362
  idx += 1;
3614
4363
  }
3615
4364
  return idx;
@@ -3662,7 +4411,7 @@ function handleOpeningTagSegment(src, lt, out, stack) {
3662
4411
  return len;
3663
4412
  }
3664
4413
  let r = q - 1;
3665
- while (r >= nameStart && WHITESPACE_REGEX3.test(src[r])) {
4414
+ while (r >= nameStart && WHITESPACE_REGEX4.test(src[r])) {
3666
4415
  r -= 1;
3667
4416
  }
3668
4417
  const selfClosing = src[r] === "/";
@@ -3826,13 +4575,114 @@ function parse3(xml, schema, options = {}) {
3826
4575
 
3827
4576
  // src/core/utils/regex-constants.ts
3828
4577
  var NAME_CHAR_RE2 = /[A-Za-z0-9_:-]/;
3829
- var WHITESPACE_REGEX4 = /\s/;
4578
+ var WHITESPACE_REGEX5 = /\s/;
4579
+
4580
+ // src/core/utils/streamed-tool-input-delta.ts
4581
+ function emitDelta({
4582
+ controller,
4583
+ id,
4584
+ state,
4585
+ nextInput
4586
+ }) {
4587
+ if (!nextInput.startsWith(state.emittedInput)) {
4588
+ return false;
4589
+ }
4590
+ const delta = nextInput.slice(state.emittedInput.length);
4591
+ if (delta.length === 0) {
4592
+ return false;
4593
+ }
4594
+ controller.enqueue({
4595
+ type: "tool-input-delta",
4596
+ id,
4597
+ delta
4598
+ });
4599
+ state.emittedInput = nextInput;
4600
+ return true;
4601
+ }
4602
+ function toIncompleteJsonPrefix(fullJson) {
4603
+ const trimmed = fullJson.trim();
4604
+ let prefix = trimmed;
4605
+ while (prefix.endsWith("}") || prefix.endsWith("]")) {
4606
+ prefix = prefix.slice(0, -1);
4607
+ }
4608
+ prefix = prefix.trimEnd();
4609
+ if (prefix.endsWith('"')) {
4610
+ prefix = prefix.slice(0, -1);
4611
+ }
4612
+ if (prefix.length === 0) {
4613
+ if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
4614
+ return trimmed.startsWith("{") ? "{" : "[";
4615
+ }
4616
+ if (trimmed.startsWith("]")) {
4617
+ return "[";
4618
+ }
4619
+ if (trimmed.startsWith("}")) {
4620
+ return "{";
4621
+ }
4622
+ if (trimmed.startsWith('"')) {
4623
+ return '"';
4624
+ }
4625
+ return "{";
4626
+ }
4627
+ return prefix;
4628
+ }
4629
+ function emitPrefixDelta(params) {
4630
+ return emitDelta({
4631
+ ...params,
4632
+ nextInput: params.candidate
4633
+ });
4634
+ }
4635
+ function emitFinalRemainder(params) {
4636
+ var _a;
4637
+ const result = emitDelta({
4638
+ ...params,
4639
+ nextInput: params.finalFullJson
4640
+ });
4641
+ if (!result && params.state.emittedInput.length > 0) {
4642
+ (_a = params.onMismatch) == null ? void 0 : _a.call(
4643
+ params,
4644
+ "Final JSON does not extend emitted tool-input prefix",
4645
+ {
4646
+ emittedLength: params.state.emittedInput.length,
4647
+ finalLength: params.finalFullJson.length
4648
+ }
4649
+ );
4650
+ }
4651
+ return result;
4652
+ }
4653
+
4654
+ // src/core/utils/xml-root-repair.ts
4655
+ var XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX = /^<([A-Za-z_][A-Za-z0-9_-]*)\s*\r?\n([\s\S]+?)\r?\n\s*\/>\s*$/;
4656
+ function tryRepairXmlSelfClosingRootWithBody(rawText, toolNames) {
4657
+ const trimmed = rawText.trim();
4658
+ if (trimmed.length === 0) {
4659
+ return null;
4660
+ }
4661
+ const match = trimmed.match(XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX);
4662
+ if (!match) {
4663
+ return null;
4664
+ }
4665
+ const rootTag = match[1];
4666
+ if (!toolNames.includes(rootTag)) {
4667
+ return null;
4668
+ }
4669
+ const body = match[2].trimEnd();
4670
+ if (body.trim().length === 0 || body.includes(`</${rootTag}>`)) {
4671
+ return null;
4672
+ }
4673
+ return `<${rootTag}>
4674
+ ${body}
4675
+ </${rootTag}>`;
4676
+ }
3830
4677
 
3831
4678
  // src/core/protocols/xml-protocol.ts
3832
4679
  function getToolSchema(tools, toolName) {
3833
4680
  var _a;
3834
4681
  return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
3835
4682
  }
4683
+ function shouldEmitRawToolCallTextOnError2(options) {
4684
+ return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
4685
+ }
3836
4686
  function processToolCall(params) {
3837
4687
  var _a, _b;
3838
4688
  const { toolCall, tools, options, text, processedElements, parseOptions } = params;
@@ -3845,7 +4695,7 @@ function processToolCall(params) {
3845
4695
  const parsed = parse3(toolCall.content, toolSchema, parseConfig);
3846
4696
  processedElements.push({
3847
4697
  type: "tool-call",
3848
- toolCallId: generateId(),
4698
+ toolCallId: generateToolCallId(),
3849
4699
  toolName: toolCall.toolName,
3850
4700
  input: JSON.stringify(parsed)
3851
4701
  });
@@ -3862,60 +4712,371 @@ function processToolCall(params) {
3862
4712
  processedElements.push({ type: "text", text: originalCallText });
3863
4713
  }
3864
4714
  }
3865
- function handleStreamingToolCallEnd(params) {
3866
- var _a, _b;
3867
- const {
3868
- toolContent,
3869
- currentToolCall,
3870
- tools,
3871
- options,
3872
- ctrl,
3873
- flushText,
3874
- parseOptions
3875
- } = params;
3876
- const toolSchema = getToolSchema(tools, currentToolCall.name);
3877
- const parseConfig = {
3878
- ...parseOptions != null ? parseOptions : {},
3879
- onError: (_a = options == null ? void 0 : options.onError) != null ? _a : parseOptions == null ? void 0 : parseOptions.onError
3880
- };
3881
- flushText(ctrl);
3882
- try {
3883
- const parsedResult = parse3(toolContent, toolSchema, parseConfig);
3884
- ctrl.enqueue({
3885
- type: "tool-call",
3886
- toolCallId: generateId(),
3887
- toolName: currentToolCall.name,
3888
- input: JSON.stringify(parsedResult)
3889
- });
3890
- } catch (error) {
3891
- const original = `<${currentToolCall.name}>${toolContent}</${currentToolCall.name}>`;
3892
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "Could not process streaming XML tool call", {
3893
- toolCall: original,
3894
- error
3895
- });
3896
- flushText(ctrl, original);
4715
+ function parseXmlTagName(rawTagBody) {
4716
+ let index = 0;
4717
+ while (index < rawTagBody.length && WHITESPACE_REGEX5.test(rawTagBody[index])) {
4718
+ index += 1;
3897
4719
  }
4720
+ const nameStart = index;
4721
+ while (index < rawTagBody.length && NAME_CHAR_RE2.test(rawTagBody.charAt(index))) {
4722
+ index += 1;
4723
+ }
4724
+ return rawTagBody.slice(nameStart, index);
3898
4725
  }
3899
- function findClosingTagEndFlexible(text, contentStart, toolName) {
3900
- let pos = contentStart;
3901
- let depth = 1;
3902
- while (pos < text.length) {
3903
- const tok = nextTagToken(text, pos);
3904
- if (tok.kind === "eof") {
3905
- break;
3906
- }
3907
- const result = updateDepthWithToken(tok, toolName, depth);
3908
- depth = result.depth;
3909
- if (result.closedAt !== void 0) {
3910
- return result.closedAt;
3911
- }
3912
- pos = tok.nextPos;
4726
+ function consumeXmlSpecialSection(fragment, ltIndex) {
4727
+ if (fragment.startsWith("<!--", ltIndex)) {
4728
+ const commentEnd = fragment.indexOf("-->", ltIndex + 4);
4729
+ return commentEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: commentEnd + 3 };
3913
4730
  }
3914
- return -1;
4731
+ if (fragment.startsWith("<![CDATA[", ltIndex)) {
4732
+ const cdataEnd = fragment.indexOf("]]>", ltIndex + 9);
4733
+ return cdataEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: cdataEnd + 3 };
4734
+ }
4735
+ if (fragment.startsWith("<?", ltIndex)) {
4736
+ const processingEnd = fragment.indexOf("?>", ltIndex + 2);
4737
+ return processingEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: processingEnd + 2 };
4738
+ }
4739
+ if (fragment.startsWith("<!", ltIndex)) {
4740
+ const declarationEnd = fragment.indexOf(">", ltIndex + 2);
4741
+ return declarationEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: declarationEnd + 1 };
4742
+ }
4743
+ return { kind: "none" };
3915
4744
  }
3916
- function skipSpecialSegment(text, lt) {
3917
- const next = text[lt + 1];
3918
- if (next === "!" || next === "?") {
4745
+ function parseXmlTagToken(fragment, ltIndex) {
4746
+ const gtIndex = fragment.indexOf(">", ltIndex + 1);
4747
+ if (gtIndex === -1) {
4748
+ return null;
4749
+ }
4750
+ const tagBody = fragment.slice(ltIndex + 1, gtIndex).trim();
4751
+ if (tagBody.length === 0) {
4752
+ return null;
4753
+ }
4754
+ if (tagBody.startsWith("/")) {
4755
+ const closeName = parseXmlTagName(tagBody.slice(1));
4756
+ if (closeName.length === 0) {
4757
+ return null;
4758
+ }
4759
+ return { kind: "close", name: closeName, nextPos: gtIndex + 1 };
4760
+ }
4761
+ const selfClosing = tagBody.endsWith("/");
4762
+ const openBody = selfClosing ? tagBody.slice(0, -1).trimEnd() : tagBody;
4763
+ const openName = parseXmlTagName(openBody);
4764
+ if (openName.length === 0) {
4765
+ return null;
4766
+ }
4767
+ return {
4768
+ kind: "open",
4769
+ name: openName,
4770
+ selfClosing,
4771
+ nextPos: gtIndex + 1
4772
+ };
4773
+ }
4774
+ function analyzeXmlFragmentForProgress(fragment) {
4775
+ const stack = [];
4776
+ const topLevelTagNames = [];
4777
+ let position = 0;
4778
+ while (position < fragment.length) {
4779
+ const ltIndex = fragment.indexOf("<", position);
4780
+ if (ltIndex === -1) {
4781
+ break;
4782
+ }
4783
+ const special = consumeXmlSpecialSection(fragment, ltIndex);
4784
+ if (special.kind === "incomplete") {
4785
+ return null;
4786
+ }
4787
+ if (special.kind === "consumed") {
4788
+ position = special.nextPos;
4789
+ continue;
4790
+ }
4791
+ const token = parseXmlTagToken(fragment, ltIndex);
4792
+ if (token === null) {
4793
+ return null;
4794
+ }
4795
+ if (token.kind === "close") {
4796
+ const openName = stack.pop();
4797
+ if (!openName || openName !== token.name) {
4798
+ return null;
4799
+ }
4800
+ position = token.nextPos;
4801
+ continue;
4802
+ }
4803
+ if (stack.length === 0) {
4804
+ topLevelTagNames.push(token.name);
4805
+ }
4806
+ if (!token.selfClosing) {
4807
+ stack.push(token.name);
4808
+ }
4809
+ position = token.nextPos;
4810
+ }
4811
+ if (stack.length > 0) {
4812
+ return null;
4813
+ }
4814
+ return { topLevelTagNames };
4815
+ }
4816
+ function scanXmlFragmentTopLevelTextStep(options) {
4817
+ const { fragment, position, stack } = options;
4818
+ const ltIndex = fragment.indexOf("<", position);
4819
+ if (ltIndex === -1) {
4820
+ const trailingText = fragment.slice(position);
4821
+ return {
4822
+ kind: "done",
4823
+ value: stack.length === 0 && trailingText.trim().length > 0
4824
+ };
4825
+ }
4826
+ const textBetweenTags = fragment.slice(position, ltIndex);
4827
+ if (stack.length === 0 && textBetweenTags.trim().length > 0) {
4828
+ return { kind: "found" };
4829
+ }
4830
+ const special = consumeXmlSpecialSection(fragment, ltIndex);
4831
+ if (special.kind === "incomplete") {
4832
+ return { kind: "invalid" };
4833
+ }
4834
+ if (special.kind === "consumed") {
4835
+ return { kind: "next", nextPos: special.nextPos };
4836
+ }
4837
+ const token = parseXmlTagToken(fragment, ltIndex);
4838
+ if (token === null) {
4839
+ return { kind: "invalid" };
4840
+ }
4841
+ if (token.kind === "close") {
4842
+ const openName = stack.pop();
4843
+ if (!openName || openName !== token.name) {
4844
+ return { kind: "invalid" };
4845
+ }
4846
+ } else if (!token.selfClosing) {
4847
+ stack.push(token.name);
4848
+ }
4849
+ return { kind: "next", nextPos: token.nextPos };
4850
+ }
4851
+ function hasNonWhitespaceTopLevelText(fragment) {
4852
+ if (!fragment.includes("<")) {
4853
+ return fragment.trim().length > 0;
4854
+ }
4855
+ const stack = [];
4856
+ let position = 0;
4857
+ while (position < fragment.length) {
4858
+ const step = scanXmlFragmentTopLevelTextStep({ fragment, position, stack });
4859
+ if (step.kind === "found") {
4860
+ return true;
4861
+ }
4862
+ if (step.kind === "invalid") {
4863
+ return false;
4864
+ }
4865
+ if (step.kind === "done") {
4866
+ return step.value;
4867
+ }
4868
+ position = step.nextPos;
4869
+ }
4870
+ return false;
4871
+ }
4872
+ function getObjectSchemaPropertyNames(schema) {
4873
+ if (!schema || typeof schema !== "object") {
4874
+ return null;
4875
+ }
4876
+ const schemaObject = schema;
4877
+ const typeValue = schemaObject.type;
4878
+ if (typeValue != null) {
4879
+ const isObjectType = typeValue === "object" || Array.isArray(typeValue) && typeValue.includes("object");
4880
+ if (!isObjectType) {
4881
+ return null;
4882
+ }
4883
+ }
4884
+ if (!schemaObject.properties || typeof schemaObject.properties !== "object") {
4885
+ return /* @__PURE__ */ new Set();
4886
+ }
4887
+ return new Set(
4888
+ Object.keys(schemaObject.properties)
4889
+ );
4890
+ }
4891
+ function schemaAllowsArrayType(schema) {
4892
+ if (!schema || typeof schema !== "object") {
4893
+ return false;
4894
+ }
4895
+ const schemaRecord = schema;
4896
+ const typeValue = schemaRecord.type;
4897
+ if (typeValue === "array") {
4898
+ return true;
4899
+ }
4900
+ if (Array.isArray(typeValue) && typeValue.includes("array")) {
4901
+ return true;
4902
+ }
4903
+ const unions = [schemaRecord.anyOf, schemaRecord.oneOf, schemaRecord.allOf];
4904
+ for (const union of unions) {
4905
+ if (!Array.isArray(union)) {
4906
+ continue;
4907
+ }
4908
+ if (union.some((entry) => schemaAllowsArrayType(entry))) {
4909
+ return true;
4910
+ }
4911
+ }
4912
+ return false;
4913
+ }
4914
+ function getSchemaObjectProperty(schema, propertyName) {
4915
+ if (!schema || typeof schema !== "object") {
4916
+ return null;
4917
+ }
4918
+ const schemaObject = schema;
4919
+ const properties = schemaObject.properties;
4920
+ if (!properties || typeof properties !== "object") {
4921
+ return null;
4922
+ }
4923
+ const property = properties[propertyName];
4924
+ if (!property) {
4925
+ return null;
4926
+ }
4927
+ return property;
4928
+ }
4929
+ function isStableXmlProgressCandidate(options) {
4930
+ const { candidate, parsed, toolSchema } = options;
4931
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
4932
+ return false;
4933
+ }
4934
+ const structure = analyzeXmlFragmentForProgress(candidate);
4935
+ if (!structure) {
4936
+ return false;
4937
+ }
4938
+ const schemaProperties = getObjectSchemaPropertyNames(toolSchema);
4939
+ if (!schemaProperties || schemaProperties.size === 0) {
4940
+ return false;
4941
+ }
4942
+ const parsedObject = parsed;
4943
+ const uniqueTopLevelTags = new Set(structure.topLevelTagNames);
4944
+ for (const tagName of uniqueTopLevelTags) {
4945
+ if (!schemaProperties.has(tagName)) {
4946
+ continue;
4947
+ }
4948
+ const schemaProperty = getSchemaObjectProperty(toolSchema, tagName);
4949
+ if (schemaProperty && schemaAllowsArrayType(schemaProperty) && !Array.isArray(parsedObject[tagName])) {
4950
+ return false;
4951
+ }
4952
+ }
4953
+ if (structure.topLevelTagNames.length === 1) {
4954
+ const onlyTopLevelTag = structure.topLevelTagNames[0];
4955
+ if (!schemaProperties || schemaProperties.size === 0 || !schemaProperties.has(onlyTopLevelTag)) {
4956
+ return false;
4957
+ }
4958
+ }
4959
+ return true;
4960
+ }
4961
+ function parseXmlContentForStreamProgress({
4962
+ toolContent,
4963
+ toolSchema,
4964
+ parseOptions
4965
+ }) {
4966
+ const tryParse = (content) => {
4967
+ try {
4968
+ return parse3(content, toolSchema, {
4969
+ ...parseOptions != null ? parseOptions : {},
4970
+ repair: false,
4971
+ onError: void 0
4972
+ });
4973
+ } catch (e) {
4974
+ return null;
4975
+ }
4976
+ };
4977
+ const strictFull = tryParse(toolContent);
4978
+ if (strictFull !== null && isStableXmlProgressCandidate({
4979
+ candidate: toolContent,
4980
+ parsed: strictFull,
4981
+ toolSchema
4982
+ })) {
4983
+ return JSON.stringify(strictFull);
4984
+ }
4985
+ let searchEnd = toolContent.length;
4986
+ while (searchEnd > 0) {
4987
+ const gtIndex = toolContent.lastIndexOf(">", searchEnd - 1);
4988
+ if (gtIndex === -1) {
4989
+ break;
4990
+ }
4991
+ const candidate = toolContent.slice(0, gtIndex + 1);
4992
+ if (!analyzeXmlFragmentForProgress(candidate)) {
4993
+ searchEnd = gtIndex;
4994
+ continue;
4995
+ }
4996
+ const parsedCandidate = tryParse(candidate);
4997
+ if (parsedCandidate !== null && isStableXmlProgressCandidate({
4998
+ candidate,
4999
+ parsed: parsedCandidate,
5000
+ toolSchema
5001
+ })) {
5002
+ return JSON.stringify(parsedCandidate);
5003
+ }
5004
+ searchEnd = gtIndex;
5005
+ }
5006
+ return null;
5007
+ }
5008
+ function handleStreamingToolCallEnd(params) {
5009
+ var _a, _b;
5010
+ const {
5011
+ toolContent,
5012
+ currentToolCall,
5013
+ tools,
5014
+ options,
5015
+ ctrl,
5016
+ flushText,
5017
+ parseOptions
5018
+ } = params;
5019
+ const toolSchema = getToolSchema(tools, currentToolCall.name);
5020
+ const parseConfig = {
5021
+ ...parseOptions != null ? parseOptions : {},
5022
+ onError: (_a = options == null ? void 0 : options.onError) != null ? _a : parseOptions == null ? void 0 : parseOptions.onError
5023
+ };
5024
+ flushText(ctrl);
5025
+ try {
5026
+ const parsedResult = parse3(toolContent, toolSchema, parseConfig);
5027
+ const finalInput = JSON.stringify(parsedResult);
5028
+ emitFinalRemainder({
5029
+ controller: ctrl,
5030
+ id: currentToolCall.toolCallId,
5031
+ state: currentToolCall,
5032
+ finalFullJson: finalInput,
5033
+ onMismatch: options == null ? void 0 : options.onError
5034
+ });
5035
+ ctrl.enqueue({
5036
+ type: "tool-input-end",
5037
+ id: currentToolCall.toolCallId
5038
+ });
5039
+ ctrl.enqueue({
5040
+ type: "tool-call",
5041
+ toolCallId: currentToolCall.toolCallId,
5042
+ toolName: currentToolCall.name,
5043
+ input: finalInput
5044
+ });
5045
+ } catch (error) {
5046
+ ctrl.enqueue({
5047
+ type: "tool-input-end",
5048
+ id: currentToolCall.toolCallId
5049
+ });
5050
+ const original = `<${currentToolCall.name}>${toolContent}</${currentToolCall.name}>`;
5051
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "Could not process streaming XML tool call", {
5052
+ toolCall: original,
5053
+ error
5054
+ });
5055
+ if (shouldEmitRawToolCallTextOnError2(options)) {
5056
+ flushText(ctrl, original);
5057
+ }
5058
+ }
5059
+ }
5060
+ function findClosingTagEndFlexible(text, contentStart, toolName) {
5061
+ let pos = contentStart;
5062
+ let depth = 1;
5063
+ while (pos < text.length) {
5064
+ const tok = nextTagToken(text, pos);
5065
+ if (tok.kind === "eof") {
5066
+ break;
5067
+ }
5068
+ const result = updateDepthWithToken(tok, toolName, depth);
5069
+ depth = result.depth;
5070
+ if (result.closedAt !== void 0) {
5071
+ return result.closedAt;
5072
+ }
5073
+ pos = tok.nextPos;
5074
+ }
5075
+ return -1;
5076
+ }
5077
+ function skipSpecialSegment(text, lt) {
5078
+ const next = text[lt + 1];
5079
+ if (next === "!" || next === "?") {
3919
5080
  const gt = text.indexOf(">", lt + 1);
3920
5081
  if (gt !== -1) {
3921
5082
  return gt + 1;
@@ -3930,7 +5091,7 @@ function consumeClosingTag(text, lt) {
3930
5091
  }
3931
5092
  function consumeOpenTag(text, lt) {
3932
5093
  let p = lt + 1;
3933
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
5094
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3934
5095
  p += 1;
3935
5096
  }
3936
5097
  const nameStart = p;
@@ -3943,7 +5104,7 @@ function consumeOpenTag(text, lt) {
3943
5104
  return null;
3944
5105
  }
3945
5106
  let r = q - 1;
3946
- while (r >= nameStart && WHITESPACE_REGEX4.test(text[r])) {
5107
+ while (r >= nameStart && WHITESPACE_REGEX5.test(text[r])) {
3947
5108
  r -= 1;
3948
5109
  }
3949
5110
  const selfClosing = text[r] === "/";
@@ -3972,7 +5133,7 @@ function nextTagToken(text, fromPos) {
3972
5133
  if (next === "/") {
3973
5134
  const closing = consumeClosingTag(text, lt);
3974
5135
  let p = lt + 2;
3975
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
5136
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3976
5137
  p += 1;
3977
5138
  }
3978
5139
  const nameStart = p;
@@ -4109,6 +5270,102 @@ function findToolCalls(text, toolNames) {
4109
5270
  }
4110
5271
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
4111
5272
  }
5273
+ function handleSpecialToken(depth) {
5274
+ return { depth, lastCompleteEnd: -1, shouldBreak: false };
5275
+ }
5276
+ function handleOpenToken(token, depth, lastCompleteEnd) {
5277
+ if (token.selfClosing) {
5278
+ return {
5279
+ depth,
5280
+ lastCompleteEnd: depth === 0 ? token.nextPos : lastCompleteEnd,
5281
+ shouldBreak: false
5282
+ };
5283
+ }
5284
+ return { depth: depth + 1, lastCompleteEnd, shouldBreak: false };
5285
+ }
5286
+ function handleCloseToken(token, depth) {
5287
+ if (depth <= 0) {
5288
+ return { depth, lastCompleteEnd: -1, shouldBreak: true };
5289
+ }
5290
+ const newDepth = depth - 1;
5291
+ return {
5292
+ depth: newDepth,
5293
+ lastCompleteEnd: newDepth === 0 ? token.nextPos : -1,
5294
+ shouldBreak: false
5295
+ };
5296
+ }
5297
+ function findLinePrefixedXmlBodyEnd(text, bodyStartIndex) {
5298
+ let cursor = bodyStartIndex;
5299
+ let depth = 0;
5300
+ let lastCompleteEnd = -1;
5301
+ while (cursor < text.length) {
5302
+ if (depth === 0) {
5303
+ cursor = consumeWhitespace(text, cursor);
5304
+ if (cursor >= text.length || text.charAt(cursor) !== "<") {
5305
+ break;
5306
+ }
5307
+ }
5308
+ const token = nextTagToken(text, cursor);
5309
+ if (token.kind === "eof") {
5310
+ break;
5311
+ }
5312
+ let result;
5313
+ if (token.kind === "special") {
5314
+ result = handleSpecialToken(depth);
5315
+ } else if (token.kind === "open") {
5316
+ result = handleOpenToken(token, depth, lastCompleteEnd);
5317
+ } else {
5318
+ result = handleCloseToken(token, depth);
5319
+ }
5320
+ depth = result.depth;
5321
+ if (result.lastCompleteEnd !== -1) {
5322
+ lastCompleteEnd = result.lastCompleteEnd;
5323
+ }
5324
+ if (result.shouldBreak) {
5325
+ break;
5326
+ }
5327
+ cursor = token.nextPos;
5328
+ }
5329
+ return lastCompleteEnd;
5330
+ }
5331
+ function findLinePrefixedToolCall(text, toolNames) {
5332
+ var _a;
5333
+ let best = null;
5334
+ for (const toolName of toolNames) {
5335
+ const linePattern = new RegExp(
5336
+ `(^|\\n)[\\t ]*${escapeRegExp(toolName)}[\\t ]*:?[\\t ]*(?:\\r?\\n|$)`,
5337
+ "g"
5338
+ );
5339
+ let match = linePattern.exec(text);
5340
+ while (match !== null) {
5341
+ const prefix = (_a = match[1]) != null ? _a : "";
5342
+ const startIndex = match.index + prefix.length;
5343
+ const contentStart = consumeWhitespace(text, linePattern.lastIndex);
5344
+ if (contentStart >= text.length || text.charAt(contentStart) !== "<") {
5345
+ match = linePattern.exec(text);
5346
+ continue;
5347
+ }
5348
+ const contentEnd = findLinePrefixedXmlBodyEnd(text, contentStart);
5349
+ if (contentEnd === -1 || contentEnd <= contentStart) {
5350
+ match = linePattern.exec(text);
5351
+ continue;
5352
+ }
5353
+ const content = text.slice(contentStart, contentEnd);
5354
+ const candidate = {
5355
+ toolName,
5356
+ startIndex,
5357
+ endIndex: contentEnd,
5358
+ content,
5359
+ segment: text.slice(startIndex, contentEnd)
5360
+ };
5361
+ if (best === null || candidate.startIndex < best.startIndex) {
5362
+ best = candidate;
5363
+ }
5364
+ break;
5365
+ }
5366
+ }
5367
+ return best;
5368
+ }
4112
5369
  function findEarliestToolTag(buffer, toolNames) {
4113
5370
  var _a, _b;
4114
5371
  let bestIndex = -1;
@@ -4147,7 +5404,7 @@ function isOpenTagPrefix(suffix, toolName) {
4147
5404
  }
4148
5405
  function consumeWhitespace(text, index) {
4149
5406
  let i = index;
4150
- while (i < text.length && WHITESPACE_REGEX4.test(text.charAt(i))) {
5407
+ while (i < text.length && WHITESPACE_REGEX5.test(text.charAt(i))) {
4151
5408
  i += 1;
4152
5409
  }
4153
5410
  return i;
@@ -4219,38 +5476,6 @@ function findPotentialToolTagStart(buffer, toolNames) {
4219
5476
  }
4220
5477
  return -1;
4221
5478
  }
4222
- function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
4223
- return (controller, text) => {
4224
- const content = text;
4225
- if (content) {
4226
- if (!getCurrentTextId()) {
4227
- const newId = generateId();
4228
- setCurrentTextId(newId);
4229
- controller.enqueue({
4230
- type: "text-start",
4231
- id: newId
4232
- });
4233
- setHasEmittedTextStart(true);
4234
- }
4235
- controller.enqueue({
4236
- type: "text-delta",
4237
- id: getCurrentTextId(),
4238
- delta: content
4239
- });
4240
- }
4241
- const currentTextId = getCurrentTextId();
4242
- if (currentTextId && !text) {
4243
- if (getHasEmittedTextStart()) {
4244
- controller.enqueue({
4245
- type: "text-end",
4246
- id: currentTextId
4247
- });
4248
- setHasEmittedTextStart(false);
4249
- }
4250
- setCurrentTextId(null);
4251
- }
4252
- };
4253
- }
4254
5479
  function processToolCallInBuffer(params) {
4255
5480
  const {
4256
5481
  buffer,
@@ -4260,18 +5485,21 @@ function processToolCallInBuffer(params) {
4260
5485
  controller,
4261
5486
  flushText,
4262
5487
  setBuffer,
4263
- parseOptions
5488
+ parseOptions,
5489
+ emitToolInputProgress: emitToolInputProgress2
4264
5490
  } = params;
4265
5491
  const endTagPattern = new RegExp(
4266
5492
  `</\\s*${escapeRegExp(currentToolCall.name)}\\s*>`
4267
5493
  );
4268
5494
  const endMatch = endTagPattern.exec(buffer);
4269
5495
  if (!endMatch || endMatch.index === void 0) {
5496
+ emitToolInputProgress2(controller, currentToolCall, buffer);
4270
5497
  return { buffer, currentToolCall, shouldBreak: true };
4271
5498
  }
4272
5499
  const endIdx = endMatch.index;
4273
5500
  const endPos = endIdx + endMatch[0].length;
4274
5501
  const content = buffer.substring(0, endIdx);
5502
+ emitToolInputProgress2(controller, currentToolCall, content);
4275
5503
  const remainder = buffer.substring(endPos);
4276
5504
  setBuffer(remainder);
4277
5505
  handleStreamingToolCallEnd({
@@ -4298,7 +5526,8 @@ function processNoToolCallInBuffer(params) {
4298
5526
  tools,
4299
5527
  options,
4300
5528
  parseOptions,
4301
- setBuffer
5529
+ setBuffer,
5530
+ emitToolInputStart
4302
5531
  } = params;
4303
5532
  const {
4304
5533
  index: earliestStartTagIndex,
@@ -4328,9 +5557,10 @@ function processNoToolCallInBuffer(params) {
4328
5557
  if (selfClosing) {
4329
5558
  const newBuffer2 = buffer.substring(earliestStartTagIndex + tagLength);
4330
5559
  setBuffer(newBuffer2);
5560
+ const currentToolCall = emitToolInputStart(controller, earliestToolName);
4331
5561
  handleStreamingToolCallEnd({
4332
5562
  toolContent: "",
4333
- currentToolCall: { name: earliestToolName, content: "" },
5563
+ currentToolCall,
4334
5564
  tools,
4335
5565
  options,
4336
5566
  ctrl: controller,
@@ -4349,12 +5579,12 @@ function processNoToolCallInBuffer(params) {
4349
5579
  setBuffer(newBuffer);
4350
5580
  return {
4351
5581
  buffer: newBuffer,
4352
- currentToolCall: { name: earliestToolName, content: "" },
5582
+ currentToolCall: emitToolInputStart(controller, earliestToolName),
4353
5583
  shouldBreak: false,
4354
5584
  shouldContinue: true
4355
5585
  };
4356
5586
  }
4357
- function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, setCurrentToolCall, tools, options, toolNames, flushText, parseOptions) {
5587
+ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, setCurrentToolCall, tools, options, toolNames, flushText, parseOptions, emitToolInputProgress2, emitToolInputStart) {
4358
5588
  return (controller) => {
4359
5589
  while (true) {
4360
5590
  const currentToolCall = getCurrentToolCall();
@@ -4367,7 +5597,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
4367
5597
  controller,
4368
5598
  flushText,
4369
5599
  setBuffer,
4370
- parseOptions
5600
+ parseOptions,
5601
+ emitToolInputProgress: emitToolInputProgress2
4371
5602
  });
4372
5603
  setBuffer(result.buffer);
4373
5604
  setCurrentToolCall(result.currentToolCall);
@@ -4383,7 +5614,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
4383
5614
  tools,
4384
5615
  options,
4385
5616
  parseOptions,
4386
- setBuffer
5617
+ setBuffer,
5618
+ emitToolInputStart
4387
5619
  });
4388
5620
  setBuffer(result.buffer);
4389
5621
  setCurrentToolCall(result.currentToolCall);
@@ -4398,6 +5630,27 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
4398
5630
  }
4399
5631
  };
4400
5632
  }
5633
+ function findToolCallsWithFallbacks(text, toolNames) {
5634
+ let parseText = text;
5635
+ let toolCalls = findToolCalls(parseText, toolNames);
5636
+ if (toolCalls.length === 0) {
5637
+ const fallbackToolCall = findLinePrefixedToolCall(parseText, toolNames);
5638
+ if (fallbackToolCall !== null) {
5639
+ toolCalls.push(fallbackToolCall);
5640
+ }
5641
+ }
5642
+ if (toolCalls.length === 0) {
5643
+ const repaired = tryRepairXmlSelfClosingRootWithBody(parseText, toolNames);
5644
+ if (repaired) {
5645
+ const repairedCalls = findToolCalls(repaired, toolNames);
5646
+ if (repairedCalls.length > 0) {
5647
+ parseText = repaired;
5648
+ toolCalls = repairedCalls;
5649
+ }
5650
+ }
5651
+ }
5652
+ return { parseText, toolCalls };
5653
+ }
4401
5654
  var xmlProtocol = (protocolOptions) => {
4402
5655
  var _a;
4403
5656
  const parseOptions = {
@@ -4431,28 +5684,31 @@ var xmlProtocol = (protocolOptions) => {
4431
5684
  }
4432
5685
  const processedElements = [];
4433
5686
  let currentIndex = 0;
4434
- const toolCalls = findToolCalls(text, toolNames);
5687
+ const { parseText, toolCalls } = findToolCallsWithFallbacks(
5688
+ text,
5689
+ toolNames
5690
+ );
4435
5691
  for (const tc of toolCalls) {
4436
5692
  if (tc.startIndex > currentIndex) {
4437
5693
  processedElements.push({
4438
5694
  type: "text",
4439
- text: text.substring(currentIndex, tc.startIndex)
5695
+ text: parseText.substring(currentIndex, tc.startIndex)
4440
5696
  });
4441
5697
  }
4442
5698
  processToolCall({
4443
5699
  toolCall: tc,
4444
5700
  tools,
4445
5701
  options,
4446
- text,
5702
+ text: parseText,
4447
5703
  processedElements,
4448
5704
  parseOptions
4449
5705
  });
4450
5706
  currentIndex = tc.endIndex;
4451
5707
  }
4452
- if (currentIndex < text.length) {
5708
+ if (currentIndex < parseText.length) {
4453
5709
  processedElements.push({
4454
5710
  type: "text",
4455
- text: text.substring(currentIndex)
5711
+ text: parseText.substring(currentIndex)
4456
5712
  });
4457
5713
  }
4458
5714
  return processedElements;
@@ -4473,8 +5729,120 @@ var xmlProtocol = (protocolOptions) => {
4473
5729
  hasEmittedTextStart = value;
4474
5730
  }
4475
5731
  );
4476
- const processBuffer = createProcessBufferHandler(
4477
- () => buffer,
5732
+ const emitToolInputStart = (controller, toolName) => {
5733
+ flushText(controller);
5734
+ const next = {
5735
+ name: toolName,
5736
+ toolCallId: generateToolCallId(),
5737
+ emittedInput: "",
5738
+ lastProgressGtIndex: null,
5739
+ lastProgressFullInput: null
5740
+ };
5741
+ controller.enqueue({
5742
+ type: "tool-input-start",
5743
+ id: next.toolCallId,
5744
+ toolName
5745
+ });
5746
+ return next;
5747
+ };
5748
+ const emitToolInputProgress2 = (controller, toolCall, toolContent) => {
5749
+ const progressGtIndex = toolContent.lastIndexOf(">");
5750
+ if (toolCall.lastProgressGtIndex === progressGtIndex) {
5751
+ const cached = toolCall.lastProgressFullInput;
5752
+ if (cached == null) {
5753
+ return;
5754
+ }
5755
+ if (cached === "{}" && toolContent.trim().length === 0) {
5756
+ return;
5757
+ }
5758
+ const prefixCandidate2 = toIncompleteJsonPrefix(cached);
5759
+ emitPrefixDelta({
5760
+ controller,
5761
+ id: toolCall.toolCallId,
5762
+ state: toolCall,
5763
+ candidate: prefixCandidate2
5764
+ });
5765
+ return;
5766
+ }
5767
+ const toolSchema = getToolSchema(tools, toolCall.name);
5768
+ const fullInput = parseXmlContentForStreamProgress({
5769
+ toolContent,
5770
+ toolSchema,
5771
+ parseOptions
5772
+ });
5773
+ toolCall.lastProgressGtIndex = progressGtIndex;
5774
+ toolCall.lastProgressFullInput = fullInput;
5775
+ if (fullInput == null) {
5776
+ return;
5777
+ }
5778
+ if (fullInput === "{}" && toolContent.trim().length === 0) {
5779
+ return;
5780
+ }
5781
+ const prefixCandidate = toIncompleteJsonPrefix(fullInput);
5782
+ emitPrefixDelta({
5783
+ controller,
5784
+ id: toolCall.toolCallId,
5785
+ state: toolCall,
5786
+ candidate: prefixCandidate
5787
+ });
5788
+ };
5789
+ const finalizeUnclosedToolCall = (controller) => {
5790
+ var _a2, _b;
5791
+ if (!currentToolCall) {
5792
+ return;
5793
+ }
5794
+ emitToolInputProgress2(controller, currentToolCall, buffer);
5795
+ const parseConfig = {
5796
+ ...parseOptions,
5797
+ onError: (_a2 = options == null ? void 0 : options.onError) != null ? _a2 : parseOptions == null ? void 0 : parseOptions.onError
5798
+ };
5799
+ const toolSchema = getToolSchema(tools, currentToolCall.name);
5800
+ flushText(controller);
5801
+ try {
5802
+ if (hasNonWhitespaceTopLevelText(buffer)) {
5803
+ throw new Error(
5804
+ "Cannot reconcile unclosed XML tool call with top-level plain text."
5805
+ );
5806
+ }
5807
+ const parsedResult = parse3(buffer, toolSchema, parseConfig);
5808
+ const finalInput = JSON.stringify(parsedResult);
5809
+ emitFinalRemainder({
5810
+ controller,
5811
+ id: currentToolCall.toolCallId,
5812
+ state: currentToolCall,
5813
+ finalFullJson: finalInput,
5814
+ onMismatch: options == null ? void 0 : options.onError
5815
+ });
5816
+ controller.enqueue({
5817
+ type: "tool-input-end",
5818
+ id: currentToolCall.toolCallId
5819
+ });
5820
+ controller.enqueue({
5821
+ type: "tool-call",
5822
+ toolCallId: currentToolCall.toolCallId,
5823
+ toolName: currentToolCall.name,
5824
+ input: finalInput
5825
+ });
5826
+ } catch (error) {
5827
+ controller.enqueue({
5828
+ type: "tool-input-end",
5829
+ id: currentToolCall.toolCallId
5830
+ });
5831
+ const unfinishedContent = `<${currentToolCall.name}>${buffer}`;
5832
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5833
+ options,
5834
+ "Could not complete streaming XML tool call at finish.",
5835
+ { toolCall: unfinishedContent, error }
5836
+ );
5837
+ if (shouldEmitRawToolCallTextOnError2(options)) {
5838
+ flushText(controller, unfinishedContent);
5839
+ }
5840
+ }
5841
+ buffer = "";
5842
+ currentToolCall = null;
5843
+ };
5844
+ const processBuffer = createProcessBufferHandler(
5845
+ () => buffer,
4478
5846
  (newBuffer) => {
4479
5847
  buffer = newBuffer;
4480
5848
  },
@@ -4486,13 +5854,28 @@ var xmlProtocol = (protocolOptions) => {
4486
5854
  options,
4487
5855
  toolNames,
4488
5856
  flushText,
4489
- parseOptions
5857
+ parseOptions,
5858
+ emitToolInputProgress2,
5859
+ emitToolInputStart
4490
5860
  );
4491
5861
  return new TransformStream({
5862
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Stateful stream parsing requires branching over chunk lifecycle and parser states.
4492
5863
  transform(chunk, controller) {
4493
5864
  var _a2;
5865
+ if (chunk.type === "finish") {
5866
+ if (currentToolCall) {
5867
+ finalizeUnclosedToolCall(controller);
5868
+ } else if (buffer) {
5869
+ flushText(controller, buffer);
5870
+ buffer = "";
5871
+ }
5872
+ flushText(controller);
5873
+ controller.enqueue(chunk);
5874
+ return;
5875
+ }
4494
5876
  if (chunk.type !== "text-delta") {
4495
- if (buffer) {
5877
+ if (currentToolCall) {
5878
+ } else if (buffer) {
4496
5879
  flushText(controller, buffer);
4497
5880
  buffer = "";
4498
5881
  }
@@ -4505,10 +5888,7 @@ var xmlProtocol = (protocolOptions) => {
4505
5888
  },
4506
5889
  flush(controller) {
4507
5890
  if (currentToolCall) {
4508
- const unfinishedContent = `<${currentToolCall.name}>${currentToolCall.content || ""}${buffer}`;
4509
- flushText(controller, unfinishedContent);
4510
- buffer = "";
4511
- currentToolCall = null;
5891
+ finalizeUnclosedToolCall(controller);
4512
5892
  } else if (buffer) {
4513
5893
  flushText(controller, buffer);
4514
5894
  buffer = "";
@@ -4536,7 +5916,205 @@ var xmlProtocol = (protocolOptions) => {
4536
5916
 
4537
5917
  // src/core/protocols/yaml-protocol.ts
4538
5918
  var import_yaml = __toESM(require("yaml"), 1);
5919
+ function shouldEmitRawToolCallTextOnError3(options) {
5920
+ return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
5921
+ }
5922
+ var selfClosingTagCache2 = /* @__PURE__ */ new Map();
5923
+ function getSelfClosingTagPattern2(toolName) {
5924
+ let pattern = selfClosingTagCache2.get(toolName);
5925
+ if (!pattern) {
5926
+ pattern = new RegExp(`<\\s*${escapeRegExp(toolName)}\\s*/>`, "g");
5927
+ selfClosingTagCache2.set(toolName, pattern);
5928
+ }
5929
+ return pattern;
5930
+ }
4539
5931
  var LEADING_WHITESPACE_RE = /^(\s*)/;
5932
+ var INCOMPLETE_MAPPING_TAIL_RE = /^[^:[\]{}-][^:]*:\s*$/;
5933
+ var INCOMPLETE_SEQUENCE_TAIL_RE = /^-\s*$/;
5934
+ var BLOCK_SCALAR_KEY_RE = /:\s*[|>][-+0-9]*\s*$/;
5935
+ var PLAIN_MAPPING_VALUE_RE = /^[^:[\]{}-][^:]*:\s*(.+)$/;
5936
+ var PLAIN_SEQUENCE_VALUE_RE = /^-\s+(.+)$/;
5937
+ function normalizeYamlContent(yamlContent) {
5938
+ let normalized = yamlContent;
5939
+ if (normalized.startsWith("\n")) {
5940
+ normalized = normalized.slice(1);
5941
+ }
5942
+ const lines = normalized.split("\n");
5943
+ const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
5944
+ if (nonEmptyLines.length === 0) {
5945
+ return { normalized: "", nonEmptyLines };
5946
+ }
5947
+ const minIndent = Math.min(
5948
+ ...nonEmptyLines.map((line) => {
5949
+ const match = line.match(LEADING_WHITESPACE_RE);
5950
+ return match ? match[1].length : 0;
5951
+ })
5952
+ );
5953
+ if (minIndent > 0) {
5954
+ normalized = lines.map((line) => line.slice(minIndent)).join("\n");
5955
+ }
5956
+ return { normalized, nonEmptyLines };
5957
+ }
5958
+ function parseYamlDocumentAsMapping(normalized) {
5959
+ try {
5960
+ const doc = import_yaml.default.parseDocument(normalized);
5961
+ const errors = doc.errors.map((e) => e.message);
5962
+ const result = doc.toJSON();
5963
+ if (result === null) {
5964
+ return { value: {}, errors };
5965
+ }
5966
+ if (typeof result !== "object" || Array.isArray(result)) {
5967
+ return { value: null, errors };
5968
+ }
5969
+ return { value: result, errors };
5970
+ } catch (error) {
5971
+ return {
5972
+ value: null,
5973
+ errors: [
5974
+ error instanceof Error ? error.message : "Unknown YAML parsing error"
5975
+ ]
5976
+ };
5977
+ }
5978
+ }
5979
+ function getLastMeaningfulLineInfo(input) {
5980
+ var _a;
5981
+ const lines = input.split("\n");
5982
+ let index = lines.length - 1;
5983
+ while (index >= 0) {
5984
+ const raw = (_a = lines[index]) != null ? _a : "";
5985
+ const trimmed = raw.trim();
5986
+ if (trimmed.length > 0 && !trimmed.startsWith("#")) {
5987
+ return {
5988
+ index,
5989
+ raw,
5990
+ trimmed,
5991
+ indent: raw.length - raw.trimStart().length
5992
+ };
5993
+ }
5994
+ index -= 1;
5995
+ }
5996
+ return null;
5997
+ }
5998
+ function dropLastMeaningfulLine(input) {
5999
+ const lineInfo = getLastMeaningfulLineInfo(input);
6000
+ if (!lineInfo) {
6001
+ return null;
6002
+ }
6003
+ return input.split("\n").slice(0, lineInfo.index).join("\n").trimEnd();
6004
+ }
6005
+ function hasIncompleteMappingTail(normalized) {
6006
+ const lineInfo = getLastMeaningfulLineInfo(normalized);
6007
+ if (!lineInfo) {
6008
+ return false;
6009
+ }
6010
+ return INCOMPLETE_MAPPING_TAIL_RE.test(lineInfo.trimmed);
6011
+ }
6012
+ function hasIncompleteSequenceTail(normalized) {
6013
+ const lineInfo = getLastMeaningfulLineInfo(normalized);
6014
+ if (!lineInfo) {
6015
+ return false;
6016
+ }
6017
+ return INCOMPLETE_SEQUENCE_TAIL_RE.test(lineInfo.trimmed);
6018
+ }
6019
+ function hasSplitNestedKeyTail(normalized) {
6020
+ var _a;
6021
+ const lineInfo = getLastMeaningfulLineInfo(normalized);
6022
+ if (!lineInfo) {
6023
+ return false;
6024
+ }
6025
+ const { trimmed, indent, index } = lineInfo;
6026
+ if (indent === 0) {
6027
+ return false;
6028
+ }
6029
+ if (trimmed.startsWith("#") || trimmed.startsWith("-") || trimmed.includes(":")) {
6030
+ return false;
6031
+ }
6032
+ const lines = normalized.split("\n");
6033
+ let parentIndex = index - 1;
6034
+ while (parentIndex >= 0) {
6035
+ const parentRaw = (_a = lines[parentIndex]) != null ? _a : "";
6036
+ const parentTrimmed = parentRaw.trim();
6037
+ if (parentTrimmed.length === 0 || parentTrimmed.startsWith("#")) {
6038
+ parentIndex -= 1;
6039
+ continue;
6040
+ }
6041
+ const parentIndent = parentRaw.length - parentRaw.trimStart().length;
6042
+ if (parentIndent >= indent) {
6043
+ parentIndex -= 1;
6044
+ continue;
6045
+ }
6046
+ if (!parentTrimmed.endsWith(":")) {
6047
+ return false;
6048
+ }
6049
+ if (BLOCK_SCALAR_KEY_RE.test(parentTrimmed)) {
6050
+ return false;
6051
+ }
6052
+ return true;
6053
+ }
6054
+ return false;
6055
+ }
6056
+ function extractTrailingPlainScalarValue(line) {
6057
+ var _a;
6058
+ if (BLOCK_SCALAR_KEY_RE.test(line)) {
6059
+ return null;
6060
+ }
6061
+ const mappingMatch = line.match(PLAIN_MAPPING_VALUE_RE);
6062
+ const sequenceMatch = line.match(PLAIN_SEQUENCE_VALUE_RE);
6063
+ const value = (_a = mappingMatch == null ? void 0 : mappingMatch[1]) != null ? _a : sequenceMatch == null ? void 0 : sequenceMatch[1];
6064
+ if (!value) {
6065
+ return null;
6066
+ }
6067
+ const trimmedValue = value.trim();
6068
+ if (trimmedValue.length === 0) {
6069
+ return null;
6070
+ }
6071
+ if (trimmedValue.startsWith('"') || trimmedValue.startsWith("'")) {
6072
+ return null;
6073
+ }
6074
+ if (trimmedValue.startsWith("{") || trimmedValue.startsWith("[") || trimmedValue.startsWith("|") || trimmedValue.startsWith(">")) {
6075
+ return null;
6076
+ }
6077
+ return trimmedValue;
6078
+ }
6079
+ function hasUnterminatedPlainScalarTail(normalized) {
6080
+ if (normalized.endsWith("\n")) {
6081
+ return false;
6082
+ }
6083
+ const lineInfo = getLastMeaningfulLineInfo(normalized);
6084
+ if (!lineInfo) {
6085
+ return false;
6086
+ }
6087
+ return extractTrailingPlainScalarValue(lineInfo.trimmed) != null;
6088
+ }
6089
+ function hasUnstableProgressTail(normalized) {
6090
+ return hasIncompleteMappingTail(normalized) || hasIncompleteSequenceTail(normalized) || hasSplitNestedKeyTail(normalized) || hasUnterminatedPlainScalarTail(normalized);
6091
+ }
6092
+ function trimTrailingNewlineInUnknown(value) {
6093
+ if (typeof value === "string") {
6094
+ if (value.endsWith("\n")) {
6095
+ return value.slice(0, -1);
6096
+ }
6097
+ return value;
6098
+ }
6099
+ if (Array.isArray(value)) {
6100
+ return value.map((item) => trimTrailingNewlineInUnknown(item));
6101
+ }
6102
+ if (value && typeof value === "object") {
6103
+ return Object.fromEntries(
6104
+ Object.entries(value).map(([key, item]) => [
6105
+ key,
6106
+ trimTrailingNewlineInUnknown(item)
6107
+ ])
6108
+ );
6109
+ }
6110
+ return value;
6111
+ }
6112
+ function stabilizeParsedValueForStreamProgress(value, source) {
6113
+ if (source.endsWith("\n")) {
6114
+ return value;
6115
+ }
6116
+ return trimTrailingNewlineInUnknown(value);
6117
+ }
4540
6118
  function findClosingTagEnd(text, contentStart, toolName) {
4541
6119
  let pos = contentStart;
4542
6120
  let depth = 1;
@@ -4552,7 +6130,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4552
6130
  break;
4553
6131
  }
4554
6132
  let p = ltIdx + 2;
4555
- while (p < gtIdx && WHITESPACE_REGEX4.test(text[p])) {
6133
+ while (p < gtIdx && WHITESPACE_REGEX5.test(text[p])) {
4556
6134
  p++;
4557
6135
  }
4558
6136
  const nameStart = p;
@@ -4572,7 +6150,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4572
6150
  pos = gtIdx === -1 ? text.length : gtIdx + 1;
4573
6151
  } else {
4574
6152
  let p = ltIdx + 1;
4575
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
6153
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
4576
6154
  p++;
4577
6155
  }
4578
6156
  const nameStart = p;
@@ -4585,7 +6163,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4585
6163
  break;
4586
6164
  }
4587
6165
  let r = gtIdx - 1;
4588
- while (r >= nameStart && WHITESPACE_REGEX4.test(text[r])) {
6166
+ while (r >= nameStart && WHITESPACE_REGEX5.test(text[r])) {
4589
6167
  r--;
4590
6168
  }
4591
6169
  const selfClosing = text[r] === "/";
@@ -4608,7 +6186,7 @@ function findEarliestTagPosition(openIdx, selfIdx) {
4608
6186
  function collectToolCallsForName(text, toolName) {
4609
6187
  const toolCalls = [];
4610
6188
  let searchIndex = 0;
4611
- const selfTagRegex = new RegExp(`<${toolName}\\s*/>`, "g");
6189
+ const selfTagRegex = getSelfClosingTagPattern2(toolName);
4612
6190
  while (searchIndex < text.length) {
4613
6191
  const startTag = `<${toolName}>`;
4614
6192
  const openIdx = text.indexOf(startTag, searchIndex);
@@ -4660,47 +6238,48 @@ function findToolCalls2(text, toolNames) {
4660
6238
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
4661
6239
  }
4662
6240
  function parseYamlContent(yamlContent, options) {
4663
- var _a, _b, _c;
4664
- let normalized = yamlContent;
4665
- if (normalized.startsWith("\n")) {
4666
- normalized = normalized.slice(1);
4667
- }
4668
- const lines = normalized.split("\n");
4669
- const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
6241
+ var _a, _b;
6242
+ const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
4670
6243
  if (nonEmptyLines.length === 0) {
4671
6244
  return {};
4672
6245
  }
4673
- const minIndent = Math.min(
4674
- ...nonEmptyLines.map((line) => {
4675
- const match = line.match(LEADING_WHITESPACE_RE);
4676
- return match ? match[1].length : 0;
4677
- })
4678
- );
4679
- if (minIndent > 0) {
4680
- normalized = lines.map((line) => line.slice(minIndent)).join("\n");
6246
+ const parsed = parseYamlDocumentAsMapping(normalized);
6247
+ if (parsed.errors.length > 0) {
6248
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "YAML parse error", {
6249
+ errors: parsed.errors
6250
+ });
6251
+ return null;
4681
6252
  }
4682
- try {
4683
- const doc = import_yaml.default.parseDocument(normalized);
4684
- if (doc.errors && doc.errors.length > 0) {
4685
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "YAML parse error", {
4686
- errors: doc.errors.map((e) => e.message)
4687
- });
4688
- return null;
6253
+ if (parsed.value === null) {
6254
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "YAML content must be a key-value mapping", {
6255
+ got: "non-mapping"
6256
+ });
6257
+ return null;
6258
+ }
6259
+ return parsed.value;
6260
+ }
6261
+ function parseYamlContentForStreamProgress(yamlContent) {
6262
+ const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
6263
+ if (nonEmptyLines.length === 0) {
6264
+ return {};
6265
+ }
6266
+ let candidate = normalized;
6267
+ while (true) {
6268
+ const parsed = parseYamlDocumentAsMapping(candidate);
6269
+ if (parsed.errors.length === 0 && !hasUnstableProgressTail(candidate)) {
6270
+ if (candidate.trim().length === 0 && normalized.trim().length > 0) {
6271
+ return null;
6272
+ }
6273
+ return stabilizeParsedValueForStreamProgress(parsed.value, candidate);
4689
6274
  }
4690
- const result = doc.toJSON();
4691
- if (result === null) {
4692
- return {};
6275
+ const truncated = dropLastMeaningfulLine(candidate);
6276
+ if (truncated == null) {
6277
+ return null;
4693
6278
  }
4694
- if (typeof result !== "object" || Array.isArray(result)) {
4695
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "YAML content must be a key-value mapping", {
4696
- got: typeof result
4697
- });
6279
+ if (truncated === candidate) {
4698
6280
  return null;
4699
6281
  }
4700
- return result;
4701
- } catch (error) {
4702
- (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(options, "Failed to parse YAML content", { error });
4703
- return null;
6282
+ candidate = truncated;
4704
6283
  }
4705
6284
  }
4706
6285
  function processToolCallMatch(text, tc, currentIndex, processedElements, options) {
@@ -4716,7 +6295,7 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
4716
6295
  if (parsedArgs !== null) {
4717
6296
  processedElements.push({
4718
6297
  type: "tool-call",
4719
- toolCallId: generateId(),
6298
+ toolCallId: generateToolCallId(),
4720
6299
  toolName: tc.toolName,
4721
6300
  input: JSON.stringify(parsedArgs)
4722
6301
  });
@@ -4729,38 +6308,6 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
4729
6308
  }
4730
6309
  return tc.endIndex;
4731
6310
  }
4732
- function createFlushTextHandler2(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
4733
- return (controller, text) => {
4734
- const content = text;
4735
- if (content) {
4736
- if (!getCurrentTextId()) {
4737
- const newId = generateId();
4738
- setCurrentTextId(newId);
4739
- controller.enqueue({
4740
- type: "text-start",
4741
- id: newId
4742
- });
4743
- setHasEmittedTextStart(true);
4744
- }
4745
- controller.enqueue({
4746
- type: "text-delta",
4747
- id: getCurrentTextId(),
4748
- delta: content
4749
- });
4750
- }
4751
- const currentTextId = getCurrentTextId();
4752
- if (currentTextId && !text) {
4753
- if (getHasEmittedTextStart()) {
4754
- controller.enqueue({
4755
- type: "text-end",
4756
- id: currentTextId
4757
- });
4758
- setHasEmittedTextStart(false);
4759
- }
4760
- setCurrentTextId(null);
4761
- }
4762
- };
4763
- }
4764
6311
  function findEarliestToolTag2(buffer, toolNames) {
4765
6312
  let bestIndex = -1;
4766
6313
  let bestName = "";
@@ -4768,8 +6315,9 @@ function findEarliestToolTag2(buffer, toolNames) {
4768
6315
  let bestTagLength = 0;
4769
6316
  for (const name of toolNames) {
4770
6317
  const openTag = `<${name}>`;
4771
- const selfTagRegex = new RegExp(`<${name}\\s*/>`);
6318
+ const selfTagRegex = getSelfClosingTagPattern2(name);
4772
6319
  const idxOpen = buffer.indexOf(openTag);
6320
+ selfTagRegex.lastIndex = 0;
4773
6321
  const selfMatch = selfTagRegex.exec(buffer);
4774
6322
  const idxSelf = selfMatch ? selfMatch.index : -1;
4775
6323
  if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
@@ -4792,6 +6340,29 @@ function findEarliestToolTag2(buffer, toolNames) {
4792
6340
  tagLength: bestTagLength
4793
6341
  };
4794
6342
  }
6343
+ function stripTrailingPartialCloseTag(content, toolName) {
6344
+ const closeTag = `</${toolName}>`;
6345
+ const lastLineBreakIndex = Math.max(
6346
+ content.lastIndexOf("\n"),
6347
+ content.lastIndexOf("\r")
6348
+ );
6349
+ const lineStartIndex = lastLineBreakIndex === -1 ? 0 : lastLineBreakIndex + 1;
6350
+ const trailingLine = content.slice(lineStartIndex);
6351
+ const trimmedTrailingLine = trailingLine.trim();
6352
+ if (trimmedTrailingLine.length === 0 || !trimmedTrailingLine.startsWith("</") || trimmedTrailingLine === closeTag || !closeTag.startsWith(trimmedTrailingLine)) {
6353
+ return content;
6354
+ }
6355
+ const leadingWhitespaceLength = trailingLine.length - trailingLine.trimStart().length;
6356
+ const preservedLeadingWhitespace = trailingLine.slice(
6357
+ 0,
6358
+ leadingWhitespaceLength
6359
+ );
6360
+ const contentWithoutPartial = `${content.slice(
6361
+ 0,
6362
+ lineStartIndex
6363
+ )}${preservedLeadingWhitespace}`;
6364
+ return contentWithoutPartial.trimEnd();
6365
+ }
4795
6366
  var yamlProtocol = (_protocolOptions) => {
4796
6367
  return {
4797
6368
  formatTools({ tools, toolSystemPromptTemplate }) {
@@ -4817,18 +6388,32 @@ ${yamlContent}</${toolCall.toolName}>`;
4817
6388
  }
4818
6389
  const processedElements = [];
4819
6390
  let currentIndex = 0;
4820
- const toolCalls = findToolCalls2(text, toolNames);
6391
+ let parseText = text;
6392
+ let toolCalls = findToolCalls2(parseText, toolNames);
6393
+ if (toolCalls.length === 0) {
6394
+ const repaired = tryRepairXmlSelfClosingRootWithBody(
6395
+ parseText,
6396
+ toolNames
6397
+ );
6398
+ if (repaired) {
6399
+ const repairedCalls = findToolCalls2(repaired, toolNames);
6400
+ if (repairedCalls.length > 0) {
6401
+ parseText = repaired;
6402
+ toolCalls = repairedCalls;
6403
+ }
6404
+ }
6405
+ }
4821
6406
  for (const tc of toolCalls) {
4822
6407
  currentIndex = processToolCallMatch(
4823
- text,
6408
+ parseText,
4824
6409
  tc,
4825
6410
  currentIndex,
4826
6411
  processedElements,
4827
6412
  options
4828
6413
  );
4829
6414
  }
4830
- if (currentIndex < text.length) {
4831
- addTextSegment(text.substring(currentIndex), processedElements);
6415
+ if (currentIndex < parseText.length) {
6416
+ addTextSegment(parseText.substring(currentIndex), processedElements);
4832
6417
  }
4833
6418
  return processedElements;
4834
6419
  },
@@ -4838,7 +6423,7 @@ ${yamlContent}</${toolCall.toolName}>`;
4838
6423
  let currentToolCall = null;
4839
6424
  let currentTextId = null;
4840
6425
  let hasEmittedTextStart = false;
4841
- const flushText = createFlushTextHandler2(
6426
+ const flushText = createFlushTextHandler(
4842
6427
  () => currentTextId,
4843
6428
  (newId) => {
4844
6429
  currentTextId = newId;
@@ -4848,33 +6433,128 @@ ${yamlContent}</${toolCall.toolName}>`;
4848
6433
  hasEmittedTextStart = value;
4849
6434
  }
4850
6435
  );
4851
- const processToolCallEnd = (controller, toolContent, toolName) => {
6436
+ const emitToolInputProgress2 = (controller, toolContent) => {
6437
+ if (!currentToolCall) {
6438
+ return;
6439
+ }
6440
+ const parsedArgs = parseYamlContentForStreamProgress(toolContent);
6441
+ if (parsedArgs === null) {
6442
+ return;
6443
+ }
6444
+ const fullInput = JSON.stringify(parsedArgs);
6445
+ if (fullInput === "{}" && toolContent.trim().length === 0) {
6446
+ return;
6447
+ }
6448
+ const prefixCandidate = toIncompleteJsonPrefix(fullInput);
6449
+ emitPrefixDelta({
6450
+ controller,
6451
+ id: currentToolCall.toolCallId,
6452
+ state: currentToolCall,
6453
+ candidate: prefixCandidate
6454
+ });
6455
+ };
6456
+ const processToolCallEnd = (controller, toolContent, toolName, toolCallId) => {
4852
6457
  var _a;
4853
6458
  const parsedArgs = parseYamlContent(toolContent, options);
4854
6459
  flushText(controller);
4855
6460
  if (parsedArgs !== null) {
6461
+ const finalInput = JSON.stringify(parsedArgs);
6462
+ if (currentToolCall && currentToolCall.toolCallId === toolCallId) {
6463
+ emitFinalRemainder({
6464
+ controller,
6465
+ id: toolCallId,
6466
+ state: currentToolCall,
6467
+ finalFullJson: finalInput,
6468
+ onMismatch: options == null ? void 0 : options.onError
6469
+ });
6470
+ }
6471
+ controller.enqueue({
6472
+ type: "tool-input-end",
6473
+ id: toolCallId
6474
+ });
4856
6475
  controller.enqueue({
4857
6476
  type: "tool-call",
4858
- toolCallId: generateId(),
6477
+ toolCallId,
4859
6478
  toolName,
4860
- input: JSON.stringify(parsedArgs)
6479
+ input: finalInput
4861
6480
  });
4862
6481
  } else {
6482
+ controller.enqueue({
6483
+ type: "tool-input-end",
6484
+ id: toolCallId
6485
+ });
4863
6486
  const original = `<${toolName}>${toolContent}</${toolName}>`;
4864
6487
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Could not parse streaming YAML tool call", {
4865
6488
  toolCall: original
4866
6489
  });
4867
- flushText(controller, original);
6490
+ if (shouldEmitRawToolCallTextOnError3(options)) {
6491
+ flushText(controller, original);
6492
+ }
6493
+ }
6494
+ };
6495
+ const finalizeUnclosedToolCall = (controller) => {
6496
+ var _a;
6497
+ if (!currentToolCall) {
6498
+ return;
4868
6499
  }
6500
+ emitToolInputProgress2(controller, buffer);
6501
+ const { name: toolName, toolCallId } = currentToolCall;
6502
+ const reconciledBuffer = stripTrailingPartialCloseTag(buffer, toolName);
6503
+ const parsedArgs = parseYamlContent(reconciledBuffer, options);
6504
+ flushText(controller);
6505
+ if (parsedArgs !== null) {
6506
+ const finalInput = JSON.stringify(parsedArgs);
6507
+ emitFinalRemainder({
6508
+ controller,
6509
+ id: toolCallId,
6510
+ state: currentToolCall,
6511
+ finalFullJson: finalInput,
6512
+ onMismatch: options == null ? void 0 : options.onError
6513
+ });
6514
+ controller.enqueue({
6515
+ type: "tool-input-end",
6516
+ id: toolCallId
6517
+ });
6518
+ controller.enqueue({
6519
+ type: "tool-call",
6520
+ toolCallId,
6521
+ toolName,
6522
+ input: finalInput
6523
+ });
6524
+ } else {
6525
+ controller.enqueue({
6526
+ type: "tool-input-end",
6527
+ id: toolCallId
6528
+ });
6529
+ const unfinishedContent = `<${toolName}>${buffer}`;
6530
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
6531
+ options,
6532
+ "Could not complete streaming YAML tool call at finish.",
6533
+ { toolCall: unfinishedContent }
6534
+ );
6535
+ if (shouldEmitRawToolCallTextOnError3(options)) {
6536
+ flushText(controller, unfinishedContent);
6537
+ }
6538
+ }
6539
+ buffer = "";
6540
+ currentToolCall = null;
4869
6541
  };
4870
6542
  const handlePendingToolCall = (controller, endTag, toolName) => {
6543
+ var _a;
4871
6544
  const endIdx = buffer.indexOf(endTag);
4872
6545
  if (endIdx === -1) {
6546
+ emitToolInputProgress2(controller, buffer);
4873
6547
  return false;
4874
6548
  }
4875
6549
  const content = buffer.substring(0, endIdx);
6550
+ emitToolInputProgress2(controller, content);
4876
6551
  buffer = buffer.substring(endIdx + endTag.length);
4877
- processToolCallEnd(controller, content, toolName);
6552
+ processToolCallEnd(
6553
+ controller,
6554
+ content,
6555
+ toolName,
6556
+ (_a = currentToolCall == null ? void 0 : currentToolCall.toolCallId) != null ? _a : generateToolCallId()
6557
+ );
4878
6558
  currentToolCall = null;
4879
6559
  return true;
4880
6560
  };
@@ -4891,13 +6571,35 @@ ${yamlContent}</${toolCall.toolName}>`;
4891
6571
  if (tagIndex > 0) {
4892
6572
  flushText(controller, buffer.substring(0, tagIndex));
4893
6573
  }
6574
+ flushText(controller);
4894
6575
  if (selfClosing) {
4895
6576
  buffer = buffer.substring(tagIndex + tagLength);
4896
- processToolCallEnd(controller, "", tagName);
6577
+ const toolCallId = generateToolCallId();
6578
+ currentToolCall = {
6579
+ name: tagName,
6580
+ toolCallId,
6581
+ emittedInput: ""
6582
+ };
6583
+ controller.enqueue({
6584
+ type: "tool-input-start",
6585
+ id: toolCallId,
6586
+ toolName: tagName
6587
+ });
6588
+ processToolCallEnd(controller, "", tagName, toolCallId);
6589
+ currentToolCall = null;
4897
6590
  } else {
4898
6591
  const startTag = `<${tagName}>`;
4899
6592
  buffer = buffer.substring(tagIndex + startTag.length);
4900
- currentToolCall = { name: tagName, content: "" };
6593
+ currentToolCall = {
6594
+ name: tagName,
6595
+ toolCallId: generateToolCallId(),
6596
+ emittedInput: ""
6597
+ };
6598
+ controller.enqueue({
6599
+ type: "tool-input-start",
6600
+ id: currentToolCall.toolCallId,
6601
+ toolName: tagName
6602
+ });
4901
6603
  }
4902
6604
  };
4903
6605
  const processBuffer = (controller) => {
@@ -4924,8 +6626,19 @@ ${yamlContent}</${toolCall.toolName}>`;
4924
6626
  return new TransformStream({
4925
6627
  transform(chunk, controller) {
4926
6628
  var _a;
6629
+ if (chunk.type === "finish") {
6630
+ if (currentToolCall) {
6631
+ finalizeUnclosedToolCall(controller);
6632
+ } else if (buffer) {
6633
+ flushText(controller, buffer);
6634
+ buffer = "";
6635
+ }
6636
+ flushText(controller);
6637
+ controller.enqueue(chunk);
6638
+ return;
6639
+ }
4927
6640
  if (chunk.type !== "text-delta") {
4928
- if (buffer) {
6641
+ if (!currentToolCall && buffer) {
4929
6642
  flushText(controller, buffer);
4930
6643
  buffer = "";
4931
6644
  }
@@ -4938,10 +6651,7 @@ ${yamlContent}</${toolCall.toolName}>`;
4938
6651
  },
4939
6652
  flush(controller) {
4940
6653
  if (currentToolCall) {
4941
- const unfinishedContent = `<${currentToolCall.name}>${buffer}`;
4942
- flushText(controller, unfinishedContent);
4943
- buffer = "";
4944
- currentToolCall = null;
6654
+ finalizeUnclosedToolCall(controller);
4945
6655
  } else if (buffer) {
4946
6656
  flushText(controller, buffer);
4947
6657
  buffer = "";
@@ -5047,17 +6757,56 @@ function encodeOriginalTools(tools) {
5047
6757
  inputSchema: JSON.stringify(t.inputSchema)
5048
6758
  }))) || [];
5049
6759
  }
5050
- function decodeOriginalTools(originalTools) {
6760
+ function decodeOriginalTools(originalTools, options) {
6761
+ var _a, _b, _c;
5051
6762
  if (!originalTools) {
5052
6763
  return [];
5053
6764
  }
5054
- return originalTools.map(
5055
- (t) => ({
5056
- type: "function",
5057
- name: t.name,
5058
- inputSchema: JSON.parse(t.inputSchema)
5059
- })
5060
- );
6765
+ const decodedTools = [];
6766
+ for (const [index, tool] of originalTools.entries()) {
6767
+ if (!tool || typeof tool.name !== "string") {
6768
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Invalid originalTools entry: missing tool name", {
6769
+ index,
6770
+ tool
6771
+ });
6772
+ continue;
6773
+ }
6774
+ if (typeof tool.inputSchema !== "string") {
6775
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
6776
+ options,
6777
+ "Invalid originalTools entry: inputSchema must be a string",
6778
+ {
6779
+ index,
6780
+ toolName: tool.name
6781
+ }
6782
+ );
6783
+ continue;
6784
+ }
6785
+ try {
6786
+ decodedTools.push({
6787
+ type: "function",
6788
+ name: tool.name,
6789
+ inputSchema: JSON.parse(tool.inputSchema)
6790
+ });
6791
+ } catch (error) {
6792
+ (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(
6793
+ options,
6794
+ "Failed to decode originalTools input schema, using permissive fallback schema",
6795
+ {
6796
+ index,
6797
+ toolName: tool.name,
6798
+ inputSchema: tool.inputSchema,
6799
+ error: error instanceof Error ? error.message : String(error)
6800
+ }
6801
+ );
6802
+ decodedTools.push({
6803
+ type: "function",
6804
+ name: tool.name,
6805
+ inputSchema: { type: "object" }
6806
+ });
6807
+ }
6808
+ }
6809
+ return decodedTools;
5061
6810
  }
5062
6811
  function extractToolNamesFromOriginalTools(originalTools) {
5063
6812
  return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
@@ -5080,25 +6829,336 @@ function hasInputProperty(obj) {
5080
6829
  return typeof obj === "object" && obj !== null && "input" in obj;
5081
6830
  }
5082
6831
 
5083
- // src/generate-handler.ts
5084
- var import_provider_utils = require("@ai-sdk/provider-utils");
5085
- function parseToolChoiceJson(text, providerOptions) {
6832
+ // src/core/utils/generated-text-json-recovery.ts
6833
+ function isRecord(value) {
6834
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6835
+ }
6836
+ function safeStringify2(value) {
6837
+ try {
6838
+ return JSON.stringify(value != null ? value : {});
6839
+ } catch (e) {
6840
+ return "{}";
6841
+ }
6842
+ }
6843
+ function parseJsonCandidate(candidateText) {
6844
+ try {
6845
+ return parse(candidateText);
6846
+ } catch (e) {
6847
+ return void 0;
6848
+ }
6849
+ }
6850
+ function extractCodeBlockCandidates(text) {
6851
+ var _a, _b;
6852
+ const codeBlockRegex = /```(?:json|yaml|xml)?\s*([\s\S]*?)```/gi;
6853
+ const candidates = [];
6854
+ let match;
6855
+ while (true) {
6856
+ match = codeBlockRegex.exec(text);
6857
+ if (!match) {
6858
+ break;
6859
+ }
6860
+ const body = (_a = match[1]) == null ? void 0 : _a.trim();
6861
+ if (body) {
6862
+ const startIndex = (_b = match.index) != null ? _b : 0;
6863
+ const endIndex = startIndex + match[0].length;
6864
+ candidates.push({
6865
+ text: body,
6866
+ startIndex,
6867
+ endIndex
6868
+ });
6869
+ }
6870
+ }
6871
+ return candidates;
6872
+ }
6873
+ function scanJsonChar(state, char) {
6874
+ if (state.inString) {
6875
+ if (state.escaping) {
6876
+ return { ...state, escaping: false };
6877
+ }
6878
+ if (char === "\\") {
6879
+ return { ...state, escaping: true };
6880
+ }
6881
+ if (char === '"') {
6882
+ return { ...state, inString: false };
6883
+ }
6884
+ return state;
6885
+ }
6886
+ if (char === '"') {
6887
+ return { ...state, inString: true };
6888
+ }
6889
+ if (char === "{") {
6890
+ return { ...state, depth: state.depth + 1 };
6891
+ }
6892
+ if (char === "}") {
6893
+ return { ...state, depth: Math.max(0, state.depth - 1) };
6894
+ }
6895
+ return state;
6896
+ }
6897
+ function extractBalancedJsonObjects(text) {
6898
+ const maxCandidateLength = 1e4;
6899
+ const candidates = [];
6900
+ let state = { depth: 0, inString: false, escaping: false };
6901
+ let currentStart = null;
6902
+ let ignoreCurrent = false;
6903
+ for (let index = 0; index < text.length; index += 1) {
6904
+ const char = text[index];
6905
+ if (!state.inString && char === "{" && state.depth === 0) {
6906
+ currentStart = index;
6907
+ ignoreCurrent = false;
6908
+ }
6909
+ state = scanJsonChar(state, char);
6910
+ if (currentStart !== null && !ignoreCurrent && index - currentStart + 1 > maxCandidateLength) {
6911
+ ignoreCurrent = true;
6912
+ }
6913
+ if (!state.inString && char === "}" && state.depth === 0) {
6914
+ if (currentStart !== null && !ignoreCurrent) {
6915
+ const endIndex = index + 1;
6916
+ const candidate = text.slice(currentStart, endIndex);
6917
+ if (candidate.length > 1) {
6918
+ candidates.push({
6919
+ text: candidate,
6920
+ startIndex: currentStart,
6921
+ endIndex
6922
+ });
6923
+ }
6924
+ }
6925
+ currentStart = null;
6926
+ ignoreCurrent = false;
6927
+ }
6928
+ }
6929
+ return candidates;
6930
+ }
6931
+ function extractTaggedToolCallCandidates(rawText) {
6932
+ var _a, _b;
6933
+ const toolCallRegex = /<tool_call>([\s\S]*?)<\/tool_call>/gi;
6934
+ const candidates = [];
6935
+ let match;
6936
+ while (true) {
6937
+ match = toolCallRegex.exec(rawText);
6938
+ if (!match) {
6939
+ break;
6940
+ }
6941
+ const body = (_a = match[1]) == null ? void 0 : _a.trim();
6942
+ if (!body) {
6943
+ continue;
6944
+ }
6945
+ const startIndex = (_b = match.index) != null ? _b : 0;
6946
+ const endIndex = startIndex + match[0].length;
6947
+ candidates.push({
6948
+ text: body,
6949
+ startIndex,
6950
+ endIndex
6951
+ });
6952
+ }
6953
+ return candidates;
6954
+ }
6955
+ function extractJsonLikeCandidates(rawText) {
6956
+ return mergeJsonCandidatesByStart(
6957
+ extractTaggedToolCallCandidates(rawText),
6958
+ extractCodeBlockCandidates(rawText),
6959
+ extractBalancedJsonObjects(rawText)
6960
+ );
6961
+ }
6962
+ function mergeJsonCandidatesByStart(tagged, codeBlocks, balanced) {
6963
+ return [...tagged, ...codeBlocks, ...balanced].sort(
6964
+ (a, b) => a.startIndex !== b.startIndex ? a.startIndex - b.startIndex : b.endIndex - a.endIndex
6965
+ );
6966
+ }
6967
+ function toToolCallPart(candidate) {
6968
+ return {
6969
+ type: "tool-call",
6970
+ toolCallId: generateToolCallId(),
6971
+ toolName: candidate.toolName,
6972
+ input: candidate.input
6973
+ };
6974
+ }
6975
+ function toRecoveredParts(text, candidate, toolCallPart) {
6976
+ const out = [];
6977
+ const prefix = text.slice(0, candidate.startIndex);
6978
+ if (prefix.length > 0) {
6979
+ out.push({ type: "text", text: prefix });
6980
+ }
6981
+ out.push(toolCallPart);
6982
+ const suffix = text.slice(candidate.endIndex);
6983
+ if (suffix.length > 0) {
6984
+ out.push({ type: "text", text: suffix });
6985
+ }
6986
+ return out;
6987
+ }
6988
+ function parseAsToolPayload(payload, tools) {
6989
+ if (!isRecord(payload)) {
6990
+ return null;
6991
+ }
6992
+ const toolName = typeof payload.name === "string" && payload.name.trim().length > 0 ? payload.name.trim() : null;
6993
+ if (!toolName) {
6994
+ return null;
6995
+ }
6996
+ if (!tools.some((tool) => tool.name === toolName)) {
6997
+ return null;
6998
+ }
6999
+ const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
7000
+ if (!isRecord(rawArgs)) {
7001
+ return null;
7002
+ }
7003
+ return {
7004
+ toolName,
7005
+ input: safeStringify2(rawArgs)
7006
+ };
7007
+ }
7008
+ function isLikelyArgumentsShapeForTool(args, tool) {
7009
+ const unwrapped = unwrapJsonSchema(tool.inputSchema);
7010
+ if (!isRecord(unwrapped)) {
7011
+ return false;
7012
+ }
7013
+ if (getSchemaType(unwrapped) !== "object") {
7014
+ return false;
7015
+ }
7016
+ const properties = unwrapped.properties;
7017
+ if (!isRecord(properties)) {
7018
+ return false;
7019
+ }
7020
+ const keys = Object.keys(args);
7021
+ if (keys.length === 0) {
7022
+ return false;
7023
+ }
7024
+ const knownKeys = keys.filter((key) => Object.hasOwn(properties, key));
7025
+ if (knownKeys.length === 0) {
7026
+ return false;
7027
+ }
7028
+ if (unwrapped.additionalProperties === false && knownKeys.length !== keys.length) {
7029
+ return false;
7030
+ }
7031
+ return true;
7032
+ }
7033
+ function parseAsArgumentsOnly(payload, tools) {
7034
+ if (tools.length !== 1) {
7035
+ return null;
7036
+ }
7037
+ if (!isRecord(payload)) {
7038
+ return null;
7039
+ }
7040
+ const hasNameEnvelope = Object.hasOwn(payload, "name") && typeof payload.name === "string" && payload.name.length > 0;
7041
+ const hasArgumentsEnvelope = Object.hasOwn(payload, "arguments") && (typeof payload.arguments === "string" || isRecord(payload.arguments));
7042
+ if (hasNameEnvelope || hasArgumentsEnvelope) {
7043
+ return null;
7044
+ }
7045
+ const tool = tools[0];
7046
+ if (!isLikelyArgumentsShapeForTool(payload, tool)) {
7047
+ return null;
7048
+ }
7049
+ return {
7050
+ toolName: tool.name,
7051
+ input: safeStringify2(payload)
7052
+ };
7053
+ }
7054
+ function recoverToolCallFromJsonCandidates(text, tools) {
7055
+ if (tools.length === 0) {
7056
+ return null;
7057
+ }
7058
+ const jsonCandidates = extractJsonLikeCandidates(text);
7059
+ for (const jsonCandidate of jsonCandidates) {
7060
+ const parsed = parseJsonCandidate(jsonCandidate.text);
7061
+ if (parsed === void 0) {
7062
+ continue;
7063
+ }
7064
+ const toolPayload = parseAsToolPayload(parsed, tools);
7065
+ if (toolPayload) {
7066
+ return toRecoveredParts(text, jsonCandidate, toToolCallPart(toolPayload));
7067
+ }
7068
+ const argsPayload = parseAsArgumentsOnly(parsed, tools);
7069
+ if (argsPayload) {
7070
+ return toRecoveredParts(text, jsonCandidate, toToolCallPart(argsPayload));
7071
+ }
7072
+ }
7073
+ return null;
7074
+ }
7075
+
7076
+ // src/core/utils/tool-call-coercion.ts
7077
+ function coerceToolCallInput(toolName, input, tools) {
5086
7078
  var _a;
7079
+ let args = {};
7080
+ if (typeof input === "string") {
7081
+ try {
7082
+ args = JSON.parse(input);
7083
+ } catch (e) {
7084
+ return;
7085
+ }
7086
+ } else if (input && typeof input === "object") {
7087
+ args = input;
7088
+ } else {
7089
+ return;
7090
+ }
7091
+ const schema = (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
7092
+ const coerced = coerceBySchema(args, schema);
7093
+ return JSON.stringify(coerced != null ? coerced : {});
7094
+ }
7095
+ function coerceToolCallPart(part, tools) {
7096
+ const coercedInput = coerceToolCallInput(part.toolName, part.input, tools);
7097
+ if (coercedInput === void 0) {
7098
+ return part;
7099
+ }
7100
+ return {
7101
+ ...part,
7102
+ input: coercedInput
7103
+ };
7104
+ }
7105
+
7106
+ // src/core/utils/tool-choice.ts
7107
+ function ensureNonEmptyToolName(name) {
7108
+ if (typeof name !== "string") {
7109
+ return "unknown";
7110
+ }
7111
+ const trimmed = name.trim();
7112
+ return trimmed.length > 0 ? trimmed : "unknown";
7113
+ }
7114
+ function safeStringify3(value) {
7115
+ try {
7116
+ return JSON.stringify(value != null ? value : {});
7117
+ } catch (e) {
7118
+ return "{}";
7119
+ }
7120
+ }
7121
+ function parseToolChoicePayload({
7122
+ text,
7123
+ tools,
7124
+ onError,
7125
+ errorMessage
7126
+ }) {
7127
+ let parsed;
5087
7128
  try {
5088
- return JSON.parse(text);
7129
+ parsed = JSON.parse(text);
5089
7130
  } catch (error) {
5090
- const options = extractOnErrorOption(providerOptions);
5091
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
5092
- options,
5093
- "Failed to parse toolChoice JSON from generated model output",
5094
- {
5095
- text,
5096
- error: error instanceof Error ? error.message : String(error)
5097
- }
5098
- );
5099
- return {};
7131
+ onError == null ? void 0 : onError(errorMessage, {
7132
+ text,
7133
+ error: error instanceof Error ? error.message : String(error)
7134
+ });
7135
+ return { toolName: "unknown", input: "{}" };
7136
+ }
7137
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
7138
+ onError == null ? void 0 : onError("toolChoice JSON payload must be an object", {
7139
+ parsedType: typeof parsed,
7140
+ parsed
7141
+ });
7142
+ return { toolName: "unknown", input: "{}" };
7143
+ }
7144
+ const payload = parsed;
7145
+ const toolName = ensureNonEmptyToolName(payload.name);
7146
+ const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
7147
+ if (rawArgs == null || typeof rawArgs !== "object" || Array.isArray(rawArgs)) {
7148
+ onError == null ? void 0 : onError("toolChoice arguments must be a JSON object", {
7149
+ toolName,
7150
+ arguments: rawArgs
7151
+ });
7152
+ return { toolName, input: "{}" };
5100
7153
  }
7154
+ const coercedInput = coerceToolCallInput(toolName, rawArgs, tools);
7155
+ return {
7156
+ toolName,
7157
+ input: coercedInput != null ? coercedInput : safeStringify3(rawArgs)
7158
+ };
5101
7159
  }
7160
+
7161
+ // src/generate-handler.ts
5102
7162
  function logDebugSummary(debugSummary, toolCall, originText) {
5103
7163
  if (debugSummary) {
5104
7164
  debugSummary.originalText = originText;
@@ -5112,25 +7172,34 @@ function logDebugSummary(debugSummary, toolCall, originText) {
5112
7172
  logParsedSummary({ toolCalls: [toolCall], originalText: originText });
5113
7173
  }
5114
7174
  }
5115
- async function handleToolChoice(doGenerate, params) {
5116
- var _a, _b, _c;
7175
+ async function handleToolChoice(doGenerate, params, tools) {
7176
+ var _a, _b, _c, _d;
5117
7177
  const result = await doGenerate();
5118
7178
  const first = (_a = result.content) == null ? void 0 : _a[0];
5119
- let parsed = {};
7179
+ const onError = (_b = extractOnErrorOption(params.providerOptions)) == null ? void 0 : _b.onError;
7180
+ let toolName = "unknown";
7181
+ let input = "{}";
5120
7182
  if (first && first.type === "text") {
5121
7183
  if (getDebugLevel() === "parse") {
5122
7184
  logRawChunk(first.text);
5123
7185
  }
5124
- parsed = parseToolChoiceJson(first.text, params.providerOptions);
7186
+ const parsed = parseToolChoicePayload({
7187
+ text: first.text,
7188
+ tools,
7189
+ onError,
7190
+ errorMessage: "Failed to parse toolChoice JSON from generated model output"
7191
+ });
7192
+ toolName = parsed.toolName;
7193
+ input = parsed.input;
5125
7194
  }
5126
7195
  const toolCall = {
5127
7196
  type: "tool-call",
5128
- toolCallId: (0, import_provider_utils.generateId)(),
5129
- toolName: parsed.name || "unknown",
5130
- input: JSON.stringify(parsed.arguments || {})
7197
+ toolCallId: generateToolCallId(),
7198
+ toolName,
7199
+ input
5131
7200
  };
5132
7201
  const originText = first && first.type === "text" ? first.text : "";
5133
- const debugSummary = (_c = (_b = params.providerOptions) == null ? void 0 : _b.toolCallMiddleware) == null ? void 0 : _c.debugSummary;
7202
+ const debugSummary = (_d = (_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) == null ? void 0 : _d.debugSummary;
5134
7203
  logDebugSummary(debugSummary, toolCall, originText);
5135
7204
  return {
5136
7205
  ...result,
@@ -5145,7 +7214,7 @@ function parseContent(content, protocol, tools, providerOptions) {
5145
7214
  if (getDebugLevel() === "stream") {
5146
7215
  logRawChunk(contentItem.text);
5147
7216
  }
5148
- return protocol.parseGeneratedText({
7217
+ const parsedByProtocol = protocol.parseGeneratedText({
5149
7218
  text: contentItem.text,
5150
7219
  tools,
5151
7220
  options: {
@@ -5153,9 +7222,20 @@ function parseContent(content, protocol, tools, providerOptions) {
5153
7222
  ...providerOptions == null ? void 0 : providerOptions.toolCallMiddleware
5154
7223
  }
5155
7224
  });
7225
+ const hasToolCall = parsedByProtocol.some(
7226
+ (part) => part.type === "tool-call"
7227
+ );
7228
+ if (hasToolCall) {
7229
+ return parsedByProtocol;
7230
+ }
7231
+ const recoveredFromJson = recoverToolCallFromJsonCandidates(
7232
+ contentItem.text,
7233
+ tools
7234
+ );
7235
+ return recoveredFromJson != null ? recoveredFromJson : parsedByProtocol;
5156
7236
  });
5157
7237
  return parsed.map(
5158
- (part) => fixToolCallWithSchema(part, tools)
7238
+ (part) => part.type === "tool-call" ? coerceToolCallPart(part, tools) : part
5159
7239
  );
5160
7240
  }
5161
7241
  function logParsedContent(content) {
@@ -5198,12 +7278,14 @@ async function wrapGenerate({
5198
7278
  params
5199
7279
  }) {
5200
7280
  var _a, _b;
5201
- if (isToolChoiceActive(params)) {
5202
- return handleToolChoice(doGenerate, params);
5203
- }
7281
+ const onError = extractOnErrorOption(params.providerOptions);
5204
7282
  const tools = originalToolsSchema.decode(
5205
- (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
7283
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
7284
+ onError
5206
7285
  );
7286
+ if (isToolChoiceActive(params)) {
7287
+ return handleToolChoice(doGenerate, params, tools);
7288
+ }
5207
7289
  const result = await doGenerate();
5208
7290
  if (result.content.length === 0) {
5209
7291
  return result;
@@ -5227,28 +7309,6 @@ async function wrapGenerate({
5227
7309
  content: newContent
5228
7310
  };
5229
7311
  }
5230
- function fixToolCallWithSchema(part, tools) {
5231
- var _a;
5232
- if (part.type !== "tool-call") {
5233
- return part;
5234
- }
5235
- let args = {};
5236
- if (typeof part.input === "string") {
5237
- try {
5238
- args = JSON.parse(part.input);
5239
- } catch (e) {
5240
- return part;
5241
- }
5242
- } else if (part.input && typeof part.input === "object") {
5243
- args = part.input;
5244
- }
5245
- const schema = (_a = tools.find((t) => t.name === part.toolName)) == null ? void 0 : _a.inputSchema;
5246
- const coerced = coerceBySchema(args, schema);
5247
- return {
5248
- ...part,
5249
- input: JSON.stringify(coerced != null ? coerced : {})
5250
- };
5251
- }
5252
7312
 
5253
7313
  // src/core/prompts/hermes-system-prompt.ts
5254
7314
  function hermesSystemPromptTemplate(tools) {
@@ -5644,7 +7704,6 @@ unit: celsius
5644
7704
  }
5645
7705
 
5646
7706
  // src/stream-handler.ts
5647
- var import_provider_utils2 = require("@ai-sdk/provider-utils");
5648
7707
  async function wrapStream({
5649
7708
  protocol,
5650
7709
  doStream,
@@ -5652,19 +7711,22 @@ async function wrapStream({
5652
7711
  params
5653
7712
  }) {
5654
7713
  var _a, _b, _c;
7714
+ const onErrorOptions = extractOnErrorOption(params.providerOptions);
7715
+ const tools = originalToolsSchema.decode(
7716
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
7717
+ onErrorOptions
7718
+ );
5655
7719
  if (isToolChoiceActive(params)) {
5656
7720
  return toolChoiceStream({
5657
7721
  doGenerate,
5658
- options: extractOnErrorOption(params.providerOptions)
7722
+ tools,
7723
+ options: onErrorOptions
5659
7724
  });
5660
7725
  }
5661
7726
  const { stream, ...rest } = await doStream();
5662
7727
  const debugLevel = getDebugLevel();
5663
- const tools = originalToolsSchema.decode(
5664
- (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
5665
- );
5666
7728
  const options = {
5667
- ...extractOnErrorOption(params.providerOptions),
7729
+ ...onErrorOptions,
5668
7730
  ...((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) || {}
5669
7731
  };
5670
7732
  const coreStream = stream.pipeThrough(
@@ -5679,13 +7741,26 @@ async function wrapStream({
5679
7741
  }
5680
7742
  )
5681
7743
  ).pipeThrough(protocol.createStreamParser({ tools, options }));
7744
+ let seenToolCall = false;
5682
7745
  const v3Stream = coreStream.pipeThrough(
5683
7746
  new TransformStream({
5684
7747
  transform(part, controller) {
7748
+ let normalizedPart = part.type === "tool-call" ? coerceToolCallPart(part, tools) : part;
7749
+ if (normalizedPart.type === "tool-call") {
7750
+ seenToolCall = true;
7751
+ }
7752
+ if (normalizedPart.type === "finish" && seenToolCall && normalizedPart.finishReason.unified === "stop") {
7753
+ normalizedPart = {
7754
+ ...normalizedPart,
7755
+ finishReason: normalizeToolCallsFinishReason(
7756
+ normalizedPart.finishReason
7757
+ )
7758
+ };
7759
+ }
5685
7760
  if (debugLevel === "stream") {
5686
- logParsedChunk(part);
7761
+ logParsedChunk(normalizedPart);
5687
7762
  }
5688
- controller.enqueue(part);
7763
+ controller.enqueue(normalizedPart);
5689
7764
  }
5690
7765
  })
5691
7766
  );
@@ -5696,41 +7771,36 @@ async function wrapStream({
5696
7771
  }
5697
7772
  async function toolChoiceStream({
5698
7773
  doGenerate,
7774
+ tools,
5699
7775
  options
5700
7776
  }) {
5701
- var _a, _b;
7777
+ var _a;
7778
+ const normalizedTools = Array.isArray(tools) ? tools : [];
5702
7779
  const result = await doGenerate();
5703
- let toolJson = {};
7780
+ let toolName = "unknown";
7781
+ let input = "{}";
5704
7782
  if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
5705
- try {
5706
- toolJson = JSON.parse(result.content[0].text);
5707
- } catch (error) {
5708
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5709
- options,
5710
- "Failed to parse toolChoice JSON from streamed model output",
5711
- {
5712
- text: result.content[0].text,
5713
- error: error instanceof Error ? error.message : String(error)
5714
- }
5715
- );
5716
- toolJson = {};
5717
- }
7783
+ const parsed = parseToolChoicePayload({
7784
+ text: result.content[0].text,
7785
+ tools: normalizedTools,
7786
+ onError: options == null ? void 0 : options.onError,
7787
+ errorMessage: "Failed to parse toolChoice JSON from streamed model output"
7788
+ });
7789
+ toolName = parsed.toolName;
7790
+ input = parsed.input;
5718
7791
  }
5719
7792
  const stream = new ReadableStream({
5720
7793
  start(controller) {
5721
7794
  controller.enqueue({
5722
7795
  type: "tool-call",
5723
- toolCallId: (0, import_provider_utils2.generateId)(),
5724
- toolName: toolJson.name || "unknown",
5725
- input: JSON.stringify(toolJson.arguments || {})
7796
+ toolCallId: generateToolCallId(),
7797
+ toolName,
7798
+ input
5726
7799
  });
5727
7800
  controller.enqueue({
5728
7801
  type: "finish",
5729
- usage: (result == null ? void 0 : result.usage) || {
5730
- inputTokens: 0,
5731
- outputTokens: 0
5732
- },
5733
- finishReason: "tool-calls"
7802
+ usage: normalizeUsage(result == null ? void 0 : result.usage),
7803
+ finishReason: normalizeToolCallsFinishReason(result == null ? void 0 : result.finishReason)
5734
7804
  });
5735
7805
  controller.close();
5736
7806
  }
@@ -5741,6 +7811,60 @@ async function toolChoiceStream({
5741
7811
  stream
5742
7812
  };
5743
7813
  }
7814
+ var ZERO_USAGE = {
7815
+ inputTokens: {
7816
+ total: 0,
7817
+ noCache: void 0,
7818
+ cacheRead: void 0,
7819
+ cacheWrite: void 0
7820
+ },
7821
+ outputTokens: {
7822
+ total: 0,
7823
+ text: void 0,
7824
+ reasoning: void 0
7825
+ }
7826
+ };
7827
+ function normalizeToolCallsFinishReason(finishReason) {
7828
+ let raw = "tool-calls";
7829
+ if (typeof finishReason === "string") {
7830
+ raw = finishReason;
7831
+ } else if (finishReason && typeof finishReason === "object" && "raw" in finishReason && typeof finishReason.raw === "string") {
7832
+ raw = finishReason.raw;
7833
+ } else if (finishReason && typeof finishReason === "object" && "unified" in finishReason && typeof finishReason.unified === "string") {
7834
+ raw = finishReason.unified;
7835
+ }
7836
+ return {
7837
+ unified: "tool-calls",
7838
+ raw
7839
+ };
7840
+ }
7841
+ function normalizeUsage(usage) {
7842
+ if (!usage || typeof usage !== "object") {
7843
+ return ZERO_USAGE;
7844
+ }
7845
+ const usageRecord = usage;
7846
+ const input = usageRecord.inputTokens;
7847
+ const output = usageRecord.outputTokens;
7848
+ if (input && typeof input === "object" && output && typeof output === "object") {
7849
+ return usage;
7850
+ }
7851
+ if (typeof input === "number" && typeof output === "number") {
7852
+ return {
7853
+ inputTokens: {
7854
+ total: input,
7855
+ noCache: void 0,
7856
+ cacheRead: void 0,
7857
+ cacheWrite: void 0
7858
+ },
7859
+ outputTokens: {
7860
+ total: output,
7861
+ text: void 0,
7862
+ reasoning: void 0
7863
+ }
7864
+ };
7865
+ }
7866
+ return ZERO_USAGE;
7867
+ }
5744
7868
 
5745
7869
  // src/transform-handler.ts
5746
7870
  function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
@@ -5866,6 +7990,11 @@ function handleToolChoiceRequired(params, baseReturnParams, functionTools) {
5866
7990
  "Tool choice type 'required' is set, but no tools are provided in params.tools."
5867
7991
  );
5868
7992
  }
7993
+ if (functionTools.length === 0) {
7994
+ throw new Error(
7995
+ "Tool choice type 'required' is set, but no function tools are provided. Provider-defined tools are not supported by this middleware."
7996
+ );
7997
+ }
5869
7998
  return {
5870
7999
  ...baseReturnParams,
5871
8000
  responseFormat: {