@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.
@@ -847,7 +847,25 @@ function getPotentialStartIndex(text, searchedText) {
847
847
 
848
848
  // src/core/utils/id.ts
849
849
  function generateId() {
850
- return Math.random().toString(36).substring(2, 15);
850
+ return crypto.randomUUID().replace(/-/g, "").slice(0, 13);
851
+ }
852
+ var TOOL_CALL_ID_PREFIX = "call_";
853
+ var TOOL_CALL_ID_BODY_LENGTH = 24;
854
+ var TOOL_CALL_ID_ALPHANUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
855
+ function randomAlphaNumeric(length) {
856
+ var _a;
857
+ const bytes = new Uint8Array(length);
858
+ crypto.getRandomValues(bytes);
859
+ let out = "";
860
+ for (let i = 0; i < length; i += 1) {
861
+ const byte = bytes[i];
862
+ const index = (byte != null ? byte : 0) % TOOL_CALL_ID_ALPHANUM.length;
863
+ out += (_a = TOOL_CALL_ID_ALPHANUM[index]) != null ? _a : "0";
864
+ }
865
+ return out;
866
+ }
867
+ function generateToolCallId() {
868
+ return `${TOOL_CALL_ID_PREFIX}${randomAlphaNumeric(TOOL_CALL_ID_BODY_LENGTH)}`;
851
869
  }
852
870
 
853
871
  // src/core/utils/protocol-utils.ts
@@ -856,6 +874,38 @@ function addTextSegment(text, processedElements) {
856
874
  processedElements.push({ type: "text", text });
857
875
  }
858
876
  }
877
+ function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
878
+ return (controller, text) => {
879
+ const content = text;
880
+ if (content) {
881
+ if (!getCurrentTextId()) {
882
+ const newId = generateId();
883
+ setCurrentTextId(newId);
884
+ controller.enqueue({
885
+ type: "text-start",
886
+ id: newId
887
+ });
888
+ setHasEmittedTextStart(true);
889
+ }
890
+ controller.enqueue({
891
+ type: "text-delta",
892
+ id: getCurrentTextId(),
893
+ delta: content
894
+ });
895
+ }
896
+ const currentTextId = getCurrentTextId();
897
+ if (currentTextId && !text) {
898
+ if (getHasEmittedTextStart()) {
899
+ controller.enqueue({
900
+ type: "text-end",
901
+ id: currentTextId
902
+ });
903
+ setHasEmittedTextStart(false);
904
+ }
905
+ setCurrentTextId(null);
906
+ }
907
+ };
908
+ }
859
909
 
860
910
  // src/core/utils/regex.ts
861
911
  function escapeRegExp(literal) {
@@ -863,15 +913,21 @@ function escapeRegExp(literal) {
863
913
  }
864
914
 
865
915
  // src/core/protocols/json-protocol.ts
916
+ function shouldEmitRawToolCallTextOnError(options) {
917
+ return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
918
+ }
919
+ function canonicalizeToolInput(argumentsValue) {
920
+ return JSON.stringify(argumentsValue != null ? argumentsValue : {});
921
+ }
866
922
  function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
867
- var _a, _b;
923
+ var _a;
868
924
  try {
869
925
  const parsedToolCall = parse(toolCallJson);
870
926
  processedElements.push({
871
927
  type: "tool-call",
872
- toolCallId: generateId(),
928
+ toolCallId: generateToolCallId(),
873
929
  toolName: parsedToolCall.name,
874
- input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
930
+ input: canonicalizeToolInput(parsedToolCall.arguments)
875
931
  });
876
932
  } catch (error) {
877
933
  logParseFailure({
@@ -880,7 +936,7 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
880
936
  snippet: fullMatch,
881
937
  error
882
938
  });
883
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
939
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
884
940
  options,
885
941
  "Could not process JSON tool call, keeping original text.",
886
942
  { toolCall: fullMatch, error }
@@ -901,6 +957,293 @@ function processMatchedToolCall(context) {
901
957
  }
902
958
  return startIndex + match[0].length;
903
959
  }
960
+ var WHITESPACE_JSON_REGEX = /\s/;
961
+ function skipJsonWhitespace(text, fromIndex) {
962
+ let index = fromIndex;
963
+ while (index < text.length && WHITESPACE_JSON_REGEX.test(text[index])) {
964
+ index += 1;
965
+ }
966
+ return index;
967
+ }
968
+ function findTopLevelPropertyValueStart(text, property) {
969
+ const objectStart = skipJsonWhitespace(text, 0);
970
+ if (objectStart >= text.length || text.charAt(objectStart) !== "{") {
971
+ return null;
972
+ }
973
+ let depth = 0;
974
+ let inString = false;
975
+ let escaping = false;
976
+ for (let index = objectStart; index < text.length; index += 1) {
977
+ const char = text.charAt(index);
978
+ if (inString) {
979
+ if (escaping) {
980
+ escaping = false;
981
+ continue;
982
+ }
983
+ if (char === "\\") {
984
+ escaping = true;
985
+ continue;
986
+ }
987
+ if (char === '"') {
988
+ inString = false;
989
+ }
990
+ continue;
991
+ }
992
+ if (char === "{") {
993
+ depth += 1;
994
+ continue;
995
+ }
996
+ if (char === "}") {
997
+ depth = Math.max(0, depth - 1);
998
+ continue;
999
+ }
1000
+ if (char !== '"') {
1001
+ continue;
1002
+ }
1003
+ if (depth !== 1) {
1004
+ inString = true;
1005
+ continue;
1006
+ }
1007
+ const keyStart = index + 1;
1008
+ let keyEnd = keyStart;
1009
+ let keyEscaped = false;
1010
+ while (keyEnd < text.length) {
1011
+ const keyChar = text.charAt(keyEnd);
1012
+ if (keyEscaped) {
1013
+ keyEscaped = false;
1014
+ } else if (keyChar === "\\") {
1015
+ keyEscaped = true;
1016
+ } else if (keyChar === '"') {
1017
+ break;
1018
+ }
1019
+ keyEnd += 1;
1020
+ }
1021
+ if (keyEnd >= text.length || text.charAt(keyEnd) !== '"') {
1022
+ return null;
1023
+ }
1024
+ const key = text.slice(keyStart, keyEnd);
1025
+ let valueCursor = skipJsonWhitespace(text, keyEnd + 1);
1026
+ if (valueCursor >= text.length || text.charAt(valueCursor) !== ":") {
1027
+ index = keyEnd;
1028
+ continue;
1029
+ }
1030
+ valueCursor = skipJsonWhitespace(text, valueCursor + 1);
1031
+ if (key === property) {
1032
+ return valueCursor < text.length ? valueCursor : null;
1033
+ }
1034
+ index = valueCursor - 1;
1035
+ }
1036
+ return null;
1037
+ }
1038
+ function extractTopLevelStringProperty(text, property) {
1039
+ const valueStart = findTopLevelPropertyValueStart(text, property);
1040
+ if (valueStart == null || valueStart >= text.length) {
1041
+ return void 0;
1042
+ }
1043
+ if (text.charAt(valueStart) !== '"') {
1044
+ return void 0;
1045
+ }
1046
+ let valueEnd = valueStart + 1;
1047
+ let escaped = false;
1048
+ while (valueEnd < text.length) {
1049
+ const char = text.charAt(valueEnd);
1050
+ if (escaped) {
1051
+ escaped = false;
1052
+ } else if (char === "\\") {
1053
+ escaped = true;
1054
+ } else if (char === '"') {
1055
+ return text.slice(valueStart + 1, valueEnd);
1056
+ }
1057
+ valueEnd += 1;
1058
+ }
1059
+ return void 0;
1060
+ }
1061
+ function extractJsonValueSlice(text, valueStart) {
1062
+ if (valueStart >= text.length) {
1063
+ return null;
1064
+ }
1065
+ const first = text.charAt(valueStart);
1066
+ if (first === "{" || first === "[") {
1067
+ const stack = [first];
1068
+ let inString = false;
1069
+ let escaped = false;
1070
+ for (let index2 = valueStart + 1; index2 < text.length; index2 += 1) {
1071
+ const char = text.charAt(index2);
1072
+ if (inString) {
1073
+ if (escaped) {
1074
+ escaped = false;
1075
+ } else if (char === "\\") {
1076
+ escaped = true;
1077
+ } else if (char === '"') {
1078
+ inString = false;
1079
+ }
1080
+ continue;
1081
+ }
1082
+ if (char === '"') {
1083
+ inString = true;
1084
+ continue;
1085
+ }
1086
+ if (char === "{" || char === "[") {
1087
+ stack.push(char);
1088
+ continue;
1089
+ }
1090
+ if (char === "}" || char === "]") {
1091
+ const open = stack.at(-1);
1092
+ if (open === "{" && char === "}" || open === "[" && char === "]") {
1093
+ stack.pop();
1094
+ if (stack.length === 0) {
1095
+ return {
1096
+ text: text.slice(valueStart, index2 + 1),
1097
+ complete: true
1098
+ };
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ return {
1104
+ text: text.slice(valueStart),
1105
+ complete: false
1106
+ };
1107
+ }
1108
+ if (first === '"') {
1109
+ let escaped = false;
1110
+ for (let index2 = valueStart + 1; index2 < text.length; index2 += 1) {
1111
+ const char = text.charAt(index2);
1112
+ if (escaped) {
1113
+ escaped = false;
1114
+ } else if (char === "\\") {
1115
+ escaped = true;
1116
+ } else if (char === '"') {
1117
+ return {
1118
+ text: text.slice(valueStart, index2 + 1),
1119
+ complete: true
1120
+ };
1121
+ }
1122
+ }
1123
+ return {
1124
+ text: text.slice(valueStart),
1125
+ complete: false
1126
+ };
1127
+ }
1128
+ let index = valueStart;
1129
+ while (index < text.length) {
1130
+ const char = text.charAt(index);
1131
+ if (char === "," || char === "}" || WHITESPACE_JSON_REGEX.test(char)) {
1132
+ break;
1133
+ }
1134
+ index += 1;
1135
+ }
1136
+ return {
1137
+ text: text.slice(valueStart, index),
1138
+ complete: index < text.length
1139
+ };
1140
+ }
1141
+ function extractStreamingToolCallProgress(toolCallJson) {
1142
+ var _a;
1143
+ const toolName = extractTopLevelStringProperty(toolCallJson, "name");
1144
+ const argsValueStart = findTopLevelPropertyValueStart(
1145
+ toolCallJson,
1146
+ "arguments"
1147
+ );
1148
+ if (argsValueStart == null) {
1149
+ return {
1150
+ toolName,
1151
+ argumentsText: void 0,
1152
+ argumentsComplete: false
1153
+ };
1154
+ }
1155
+ const argsSlice = extractJsonValueSlice(toolCallJson, argsValueStart);
1156
+ return {
1157
+ toolName,
1158
+ argumentsText: argsSlice == null ? void 0 : argsSlice.text,
1159
+ argumentsComplete: (_a = argsSlice == null ? void 0 : argsSlice.complete) != null ? _a : false
1160
+ };
1161
+ }
1162
+ function ensureToolInputStart(state, controller, toolName) {
1163
+ if (!state.activeToolInput) {
1164
+ const id = generateToolCallId();
1165
+ state.activeToolInput = {
1166
+ id,
1167
+ toolName,
1168
+ emittedInput: ""
1169
+ };
1170
+ controller.enqueue({
1171
+ type: "tool-input-start",
1172
+ id,
1173
+ toolName
1174
+ });
1175
+ }
1176
+ }
1177
+ function emitToolInputDelta(state, controller, fullInput) {
1178
+ const active = state.activeToolInput;
1179
+ if (!active) {
1180
+ return;
1181
+ }
1182
+ if (!fullInput.startsWith(active.emittedInput)) {
1183
+ return;
1184
+ }
1185
+ const delta = fullInput.slice(active.emittedInput.length);
1186
+ if (delta.length === 0) {
1187
+ return;
1188
+ }
1189
+ controller.enqueue({
1190
+ type: "tool-input-delta",
1191
+ id: active.id,
1192
+ delta
1193
+ });
1194
+ active.emittedInput = fullInput;
1195
+ }
1196
+ function closeToolInput(state, controller) {
1197
+ if (!state.activeToolInput) {
1198
+ return;
1199
+ }
1200
+ controller.enqueue({
1201
+ type: "tool-input-end",
1202
+ id: state.activeToolInput.id
1203
+ });
1204
+ state.activeToolInput = null;
1205
+ }
1206
+ function emitToolCallFromParsed(state, controller, parsedToolCall) {
1207
+ var _a, _b, _c, _d;
1208
+ closeTextBlock(state, controller);
1209
+ const toolName = typeof parsedToolCall.name === "string" ? parsedToolCall.name : (_b = (_a = state.activeToolInput) == null ? void 0 : _a.toolName) != null ? _b : "unknown";
1210
+ const input = canonicalizeToolInput(parsedToolCall.arguments);
1211
+ ensureToolInputStart(state, controller, toolName);
1212
+ emitToolInputDelta(state, controller, input);
1213
+ const toolCallId = (_d = (_c = state.activeToolInput) == null ? void 0 : _c.id) != null ? _d : generateToolCallId();
1214
+ closeToolInput(state, controller);
1215
+ controller.enqueue({
1216
+ type: "tool-call",
1217
+ toolCallId,
1218
+ toolName,
1219
+ input
1220
+ });
1221
+ }
1222
+ function canonicalizeArgumentsProgressInput(progress) {
1223
+ if (progress.argumentsText === void 0 || !progress.argumentsComplete) {
1224
+ return void 0;
1225
+ }
1226
+ try {
1227
+ const parsedArguments = parse(progress.argumentsText);
1228
+ return canonicalizeToolInput(parsedArguments);
1229
+ } catch (e) {
1230
+ return void 0;
1231
+ }
1232
+ }
1233
+ function emitToolInputProgress(state, controller) {
1234
+ if (!(state.isInsideToolCall && state.currentToolCallJson)) {
1235
+ return;
1236
+ }
1237
+ const progress = extractStreamingToolCallProgress(state.currentToolCallJson);
1238
+ if (!progress.toolName) {
1239
+ return;
1240
+ }
1241
+ ensureToolInputStart(state, controller, progress.toolName);
1242
+ const canonicalProgressInput = canonicalizeArgumentsProgressInput(progress);
1243
+ if (canonicalProgressInput !== void 0) {
1244
+ emitToolInputDelta(state, controller, canonicalProgressInput);
1245
+ }
1246
+ }
904
1247
  function flushBuffer(state, controller, toolCallStart) {
905
1248
  if (state.buffer.length === 0) {
906
1249
  return;
@@ -931,44 +1274,77 @@ function closeTextBlock(state, controller) {
931
1274
  state.hasEmittedTextStart = false;
932
1275
  }
933
1276
  }
934
- function emitIncompleteToolCall(state, controller, toolCallStart) {
935
- if (!state.currentToolCallJson) {
1277
+ function emitIncompleteToolCall(state, controller, toolCallStart, trailingBuffer, options) {
1278
+ var _a;
1279
+ if (!state.currentToolCallJson && trailingBuffer.length === 0) {
1280
+ state.isInsideToolCall = false;
936
1281
  return;
937
1282
  }
1283
+ if (state.currentToolCallJson) {
1284
+ try {
1285
+ const parsedToolCall = parse(state.currentToolCallJson);
1286
+ emitToolCallFromParsed(state, controller, parsedToolCall);
1287
+ state.currentToolCallJson = "";
1288
+ state.isInsideToolCall = false;
1289
+ return;
1290
+ } catch (e) {
1291
+ }
1292
+ }
1293
+ const rawToolCallContent = `${state.currentToolCallJson}${trailingBuffer}`;
1294
+ const errorContent = `${toolCallStart}${rawToolCallContent}`;
1295
+ const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
938
1296
  logParseFailure({
939
1297
  phase: "stream",
940
- reason: "Incomplete streaming tool call segment emitted as text",
941
- snippet: `${toolCallStart}${state.currentToolCallJson}`
942
- });
943
- const errorId = generateId();
944
- const errorContent = `${toolCallStart}${state.currentToolCallJson}`;
945
- controller.enqueue({
946
- type: "text-start",
947
- id: errorId
948
- });
949
- controller.enqueue({
950
- type: "text-delta",
951
- id: errorId,
952
- delta: errorContent
953
- });
954
- controller.enqueue({
955
- type: "text-end",
956
- id: errorId
1298
+ reason: shouldEmitRawFallback ? "Incomplete streaming tool call segment emitted as text" : "Incomplete streaming tool call segment suppressed without raw text fallback",
1299
+ snippet: errorContent
957
1300
  });
1301
+ if (shouldEmitRawFallback) {
1302
+ const errorId = generateId();
1303
+ controller.enqueue({
1304
+ type: "text-start",
1305
+ id: errorId
1306
+ });
1307
+ controller.enqueue({
1308
+ type: "text-delta",
1309
+ id: errorId,
1310
+ delta: errorContent
1311
+ });
1312
+ controller.enqueue({
1313
+ type: "text-end",
1314
+ id: errorId
1315
+ });
1316
+ }
1317
+ closeToolInput(state, controller);
1318
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
1319
+ options,
1320
+ shouldEmitRawFallback ? "Could not complete streaming JSON tool call at finish; emitting original text." : "Could not complete streaming JSON tool call at finish.",
1321
+ { toolCall: errorContent }
1322
+ );
958
1323
  state.currentToolCallJson = "";
1324
+ state.isInsideToolCall = false;
959
1325
  }
960
- function handleFinishChunk(state, controller, toolCallStart, chunk) {
961
- if (state.buffer.length > 0) {
1326
+ function handleFinishChunk(state, controller, toolCallStart, options, chunk) {
1327
+ if (state.isInsideToolCall) {
1328
+ const trailingBuffer = state.buffer;
1329
+ state.buffer = "";
1330
+ emitIncompleteToolCall(
1331
+ state,
1332
+ controller,
1333
+ toolCallStart,
1334
+ trailingBuffer,
1335
+ options
1336
+ );
1337
+ } else if (state.buffer.length > 0) {
962
1338
  flushBuffer(state, controller, toolCallStart);
963
1339
  }
964
1340
  closeTextBlock(state, controller);
965
- emitIncompleteToolCall(state, controller, toolCallStart);
966
1341
  controller.enqueue(chunk);
967
1342
  }
968
1343
  function publishText(text, state, controller) {
969
1344
  if (state.isInsideToolCall) {
970
1345
  closeTextBlock(state, controller);
971
1346
  state.currentToolCallJson += text;
1347
+ emitToolInputProgress(state, controller);
972
1348
  } else if (text.length > 0) {
973
1349
  if (!state.currentTextId) {
974
1350
  state.currentTextId = generateId();
@@ -986,42 +1362,40 @@ function publishText(text, state, controller) {
986
1362
  }
987
1363
  }
988
1364
  function emitToolCall(context) {
989
- var _a, _b;
1365
+ var _a;
990
1366
  const { state, controller, toolCallStart, toolCallEnd, options } = context;
991
1367
  try {
992
1368
  const parsedToolCall = parse(state.currentToolCallJson);
993
- closeTextBlock(state, controller);
994
- controller.enqueue({
995
- type: "tool-call",
996
- toolCallId: generateId(),
997
- toolName: parsedToolCall.name,
998
- input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
999
- });
1369
+ emitToolCallFromParsed(state, controller, parsedToolCall);
1000
1370
  } catch (error) {
1371
+ const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
1372
+ const shouldEmitRawFallback = shouldEmitRawToolCallTextOnError(options);
1001
1373
  logParseFailure({
1002
1374
  phase: "stream",
1003
1375
  reason: "Failed to parse streaming tool call JSON segment",
1004
- snippet: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`,
1376
+ snippet: errorContent,
1005
1377
  error
1006
1378
  });
1007
- const errorId = generateId();
1008
- const errorContent = `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`;
1009
- controller.enqueue({
1010
- type: "text-start",
1011
- id: errorId
1012
- });
1013
- controller.enqueue({
1014
- type: "text-delta",
1015
- id: errorId,
1016
- delta: errorContent
1017
- });
1018
- controller.enqueue({
1019
- type: "text-end",
1020
- id: errorId
1021
- });
1022
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1379
+ if (shouldEmitRawFallback) {
1380
+ const errorId = generateId();
1381
+ controller.enqueue({
1382
+ type: "text-start",
1383
+ id: errorId
1384
+ });
1385
+ controller.enqueue({
1386
+ type: "text-delta",
1387
+ id: errorId,
1388
+ delta: errorContent
1389
+ });
1390
+ controller.enqueue({
1391
+ type: "text-end",
1392
+ id: errorId
1393
+ });
1394
+ }
1395
+ closeToolInput(state, controller);
1396
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
1023
1397
  options,
1024
- "Could not process streaming JSON tool call; emitting original text.",
1398
+ shouldEmitRawFallback ? "Could not process streaming JSON tool call; emitting original text." : "Could not process streaming JSON tool call.",
1025
1399
  {
1026
1400
  toolCall: errorContent
1027
1401
  }
@@ -1037,6 +1411,7 @@ function processTagMatch(context) {
1037
1411
  } else {
1038
1412
  state.currentToolCallJson = "";
1039
1413
  state.isInsideToolCall = true;
1414
+ state.activeToolInput = null;
1040
1415
  }
1041
1416
  }
1042
1417
  function processBufferTags(context) {
@@ -1059,8 +1434,16 @@ function processBufferTags(context) {
1059
1434
  );
1060
1435
  }
1061
1436
  }
1062
- function handlePartialTag(state, controller, toolCallStart) {
1437
+ function handlePartialTag(state, controller, toolCallStart, toolCallEnd) {
1063
1438
  if (state.isInsideToolCall) {
1439
+ const potentialEndIndex = getPotentialStartIndex(state.buffer, toolCallEnd);
1440
+ if (potentialEndIndex != null && potentialEndIndex + toolCallEnd.length > state.buffer.length) {
1441
+ publishText(state.buffer.slice(0, potentialEndIndex), state, controller);
1442
+ state.buffer = state.buffer.slice(potentialEndIndex);
1443
+ } else {
1444
+ publishText(state.buffer, state, controller);
1445
+ state.buffer = "";
1446
+ }
1064
1447
  return;
1065
1448
  }
1066
1449
  const potentialIndex = getPotentialStartIndex(state.buffer, toolCallStart);
@@ -1133,13 +1516,14 @@ var jsonProtocol = ({
1133
1516
  buffer: "",
1134
1517
  currentToolCallJson: "",
1135
1518
  currentTextId: null,
1136
- hasEmittedTextStart: false
1519
+ hasEmittedTextStart: false,
1520
+ activeToolInput: null
1137
1521
  };
1138
1522
  return new TransformStream({
1139
1523
  transform(chunk, controller) {
1140
1524
  var _a;
1141
1525
  if (chunk.type === "finish") {
1142
- handleFinishChunk(state, controller, toolCallStart, chunk);
1526
+ handleFinishChunk(state, controller, toolCallStart, options, chunk);
1143
1527
  return;
1144
1528
  }
1145
1529
  if (chunk.type !== "text-delta") {
@@ -1155,7 +1539,7 @@ var jsonProtocol = ({
1155
1539
  toolCallEnd,
1156
1540
  options
1157
1541
  });
1158
- handlePartialTag(state, controller, toolCallStart);
1542
+ handlePartialTag(state, controller, toolCallStart, toolCallEnd);
1159
1543
  }
1160
1544
  });
1161
1545
  },
@@ -1516,6 +1900,13 @@ var EMPTY_OBJECT_REGEX = /^\{\s*\}$/s;
1516
1900
  var NEWLINE_SPLIT_REGEX = /\n+/;
1517
1901
  var COMMA_SPLIT_REGEX = /,\s*/;
1518
1902
  var DIGIT_KEY_REGEX = /^\d+$/;
1903
+ var WHITESPACE_REGEX2 = /\s+/g;
1904
+ var HAS_WHITESPACE_REGEX = /\s/;
1905
+ var SINGLE_QUOTE = "'";
1906
+ var DOUBLE_QUOTE = '"';
1907
+ var SNAKE_SEGMENT_REGEX = /_([a-zA-Z0-9])/g;
1908
+ var CAMEL_BOUNDARY_REGEX = /([a-z0-9])([A-Z])/g;
1909
+ var LEADING_UNDERSCORES_REGEX = /^_+/;
1519
1910
  function unwrapJsonSchema(schema) {
1520
1911
  if (!schema || typeof schema !== "object") {
1521
1912
  return schema;
@@ -1764,39 +2155,299 @@ function coerceStringToArray(s, unwrapped) {
1764
2155
  }
1765
2156
  return null;
1766
2157
  }
1767
- function coerceObjectToObject(value, unwrapped) {
1768
- const out = {};
1769
- for (const [k, v] of Object.entries(value)) {
1770
- out[k] = coerceValueForKey(v, k, unwrapped);
2158
+ function getStrictObjectSchemaInfo(unwrapped) {
2159
+ if (getSchemaType(unwrapped) !== "object") {
2160
+ return null;
1771
2161
  }
1772
- return out;
2162
+ if (unwrapped.additionalProperties !== false) {
2163
+ return null;
2164
+ }
2165
+ const properties = unwrapped.properties;
2166
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
2167
+ return null;
2168
+ }
2169
+ const propertyMap = properties;
2170
+ const required = Array.isArray(unwrapped.required) ? unwrapped.required.filter(
2171
+ (value) => typeof value === "string" && value.length > 0
2172
+ ) : [];
2173
+ const patternProps = unwrapped.patternProperties;
2174
+ const patternProperties = patternProps && typeof patternProps === "object" && !Array.isArray(patternProps) ? patternProps : void 0;
2175
+ return {
2176
+ properties: propertyMap,
2177
+ required,
2178
+ patternProperties
2179
+ };
1773
2180
  }
1774
- function coerceArrayToArray(value, prefixItems, itemsSchema) {
1775
- if (prefixItems && value.length === prefixItems.length) {
1776
- return value.map((v, i) => coerceBySchema(v, prefixItems[i]));
2181
+ function isSingularPluralPair(left, right) {
2182
+ return left.length > 1 && right.length > 1 && (left === `${right}s` || right === `${left}s`);
2183
+ }
2184
+ function snakeToCamel(value) {
2185
+ const trimmed = value.replace(LEADING_UNDERSCORES_REGEX, "");
2186
+ if (trimmed.length === 0) {
2187
+ return value;
1777
2188
  }
1778
- return value.map((v) => coerceBySchema(v, itemsSchema));
2189
+ const camelized = trimmed.replace(
2190
+ SNAKE_SEGMENT_REGEX,
2191
+ (_, c) => c.toUpperCase()
2192
+ );
2193
+ return camelized.charAt(0).toLowerCase() + camelized.slice(1);
1779
2194
  }
1780
- function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
1781
- if (Object.hasOwn(maybe, "item")) {
1782
- const items = maybe.item;
1783
- const arr = Array.isArray(items) ? items : [items];
1784
- return coerceArrayToArray(arr, prefixItems, itemsSchema);
2195
+ function camelToSnake(value) {
2196
+ return value.replace(CAMEL_BOUNDARY_REGEX, "$1_$2").toLowerCase();
2197
+ }
2198
+ function isCaseStylePair(targetKey, sourceKey) {
2199
+ if (targetKey === sourceKey) {
2200
+ return false;
2201
+ }
2202
+ const sourceLooksSnake = sourceKey.includes("_");
2203
+ const targetLooksSnake = targetKey.includes("_");
2204
+ if (sourceLooksSnake && snakeToCamel(sourceKey) === targetKey) {
2205
+ return true;
2206
+ }
2207
+ if (!sourceLooksSnake && targetLooksSnake && camelToSnake(sourceKey) === targetKey) {
2208
+ return true;
2209
+ }
2210
+ return false;
2211
+ }
2212
+ function isUnexpectedKey(key, schemaInfo) {
2213
+ if (Object.hasOwn(schemaInfo.properties, key)) {
2214
+ return false;
2215
+ }
2216
+ const patternSchemas = getPatternSchemasForKey(
2217
+ schemaInfo.patternProperties,
2218
+ key
2219
+ );
2220
+ if (patternSchemas.length > 0) {
2221
+ return patternSchemas.every((schema) => schema === false);
2222
+ }
2223
+ return true;
2224
+ }
2225
+ function computeMissingAndUnexpectedKeys(input, schemaInfo) {
2226
+ const missingRequired = schemaInfo.required.filter(
2227
+ (key) => !Object.hasOwn(input, key)
2228
+ );
2229
+ const unexpectedKeys = Object.keys(input).filter(
2230
+ (key) => isUnexpectedKey(key, schemaInfo)
2231
+ );
2232
+ return { missingRequired, unexpectedKeys };
2233
+ }
2234
+ function applySingularPluralRequiredKeyRename(input, schemaInfo) {
2235
+ const { missingRequired, unexpectedKeys } = computeMissingAndUnexpectedKeys(
2236
+ input,
2237
+ schemaInfo
2238
+ );
2239
+ if (missingRequired.length !== 1 || unexpectedKeys.length !== 1) {
2240
+ return null;
2241
+ }
2242
+ const targetKey = missingRequired[0];
2243
+ const sourceKey = unexpectedKeys[0];
2244
+ if (!Object.hasOwn(schemaInfo.properties, targetKey)) {
2245
+ return null;
2246
+ }
2247
+ if (!isSingularPluralPair(targetKey, sourceKey)) {
2248
+ return null;
2249
+ }
2250
+ if (getSchemaType(schemaInfo.properties[targetKey]) !== "array") {
2251
+ return null;
2252
+ }
2253
+ if (!Array.isArray(input[sourceKey])) {
2254
+ return null;
2255
+ }
2256
+ if (!Object.hasOwn(input, sourceKey) || Object.hasOwn(input, targetKey)) {
2257
+ return null;
2258
+ }
2259
+ const output = { ...input };
2260
+ output[targetKey] = output[sourceKey];
2261
+ delete output[sourceKey];
2262
+ return output;
2263
+ }
2264
+ function applyCaseStyleRequiredKeyRename(input, schemaInfo) {
2265
+ const { missingRequired, unexpectedKeys } = computeMissingAndUnexpectedKeys(
2266
+ input,
2267
+ schemaInfo
2268
+ );
2269
+ if (missingRequired.length !== 1 || unexpectedKeys.length !== 1) {
2270
+ return null;
2271
+ }
2272
+ const targetKey = missingRequired[0];
2273
+ const sourceKey = unexpectedKeys[0];
2274
+ if (!Object.hasOwn(schemaInfo.properties, targetKey)) {
2275
+ return null;
2276
+ }
2277
+ if (!isCaseStylePair(targetKey, sourceKey)) {
2278
+ return null;
2279
+ }
2280
+ if (!Object.hasOwn(input, sourceKey) || Object.hasOwn(input, targetKey)) {
2281
+ return null;
2282
+ }
2283
+ const output = { ...input };
2284
+ output[targetKey] = output[sourceKey];
2285
+ delete output[sourceKey];
2286
+ return output;
2287
+ }
2288
+ function applyStrictRequiredKeyRename(input, unwrapped) {
2289
+ const schemaInfo = getStrictObjectSchemaInfo(unwrapped);
2290
+ if (!schemaInfo) {
2291
+ return input;
2292
+ }
2293
+ const singularPlural = applySingularPluralRequiredKeyRename(
2294
+ input,
2295
+ schemaInfo
2296
+ );
2297
+ if (singularPlural) {
2298
+ return singularPlural;
2299
+ }
2300
+ const caseStyle = applyCaseStyleRequiredKeyRename(input, schemaInfo);
2301
+ if (caseStyle) {
2302
+ return caseStyle;
2303
+ }
2304
+ return input;
2305
+ }
2306
+ function coerceObjectToObject(value, unwrapped) {
2307
+ const normalizedInput = applyStrictRequiredKeyRename(value, unwrapped);
2308
+ const out = {};
2309
+ for (const [k, v] of Object.entries(normalizedInput)) {
2310
+ out[k] = coerceValueForKey(v, k, unwrapped);
2311
+ }
2312
+ return out;
2313
+ }
2314
+ function coerceArrayToArray(value, prefixItems, itemsSchema) {
2315
+ if (prefixItems && value.length === prefixItems.length) {
2316
+ return value.map((v, i) => coerceBySchema(v, prefixItems[i]));
2317
+ }
2318
+ return value.map((v) => coerceBySchema(v, itemsSchema));
2319
+ }
2320
+ function isPrimitiveSchemaType(schemaType) {
2321
+ return schemaType === "string" || schemaType === "number" || schemaType === "integer" || schemaType === "boolean";
2322
+ }
2323
+ function isPrimitiveMatchForSchemaType(value, schemaType) {
2324
+ if (schemaType === "string") {
2325
+ return typeof value === "string";
2326
+ }
2327
+ if (schemaType === "number") {
2328
+ return typeof value === "number" && Number.isFinite(value);
2329
+ }
2330
+ if (schemaType === "integer") {
2331
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value);
2332
+ }
2333
+ return typeof value === "boolean";
2334
+ }
2335
+ function coercePrimitiveWrappedObject(value, itemsSchema) {
2336
+ const schemaType = getSchemaType(itemsSchema);
2337
+ if (!isPrimitiveSchemaType(schemaType)) {
2338
+ return null;
2339
+ }
2340
+ const keys = Object.keys(value);
2341
+ if (keys.length !== 1) {
2342
+ return null;
2343
+ }
2344
+ const singleValue = value[keys[0]];
2345
+ if (singleValue && typeof singleValue === "object") {
2346
+ return null;
2347
+ }
2348
+ const coerced = coerceBySchema(singleValue, itemsSchema);
2349
+ return isPrimitiveMatchForSchemaType(coerced, schemaType) ? coerced : null;
2350
+ }
2351
+ function coerceParallelArraysObjectToArray(maybe, prefixItems, itemsSchema) {
2352
+ if (prefixItems && prefixItems.length > 0) {
2353
+ return null;
2354
+ }
2355
+ const unwrappedItems = unwrapJsonSchema(itemsSchema);
2356
+ if (!unwrappedItems || typeof unwrappedItems !== "object" || Array.isArray(unwrappedItems)) {
2357
+ return null;
2358
+ }
2359
+ const itemSchema = unwrappedItems;
2360
+ if (getSchemaType(itemSchema) !== "object") {
2361
+ return null;
2362
+ }
2363
+ if (itemSchema.additionalProperties !== false) {
2364
+ return null;
2365
+ }
2366
+ const properties = itemSchema.properties;
2367
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
2368
+ return null;
2369
+ }
2370
+ const propertyMap = properties;
2371
+ const entries = Object.entries(maybe);
2372
+ if (entries.length < 2) {
2373
+ return null;
2374
+ }
2375
+ if (!entries.every(([, value]) => Array.isArray(value))) {
2376
+ return null;
2377
+ }
2378
+ if (!entries.every(([key]) => Object.hasOwn(propertyMap, key))) {
2379
+ return null;
2380
+ }
2381
+ if (!entries.every(([key]) => {
2382
+ const schemaType = getSchemaType(propertyMap[key]);
2383
+ return schemaType !== "array" && schemaType !== "object";
2384
+ })) {
2385
+ return null;
2386
+ }
2387
+ const lengths = [
2388
+ ...new Set(entries.map(([, value]) => value.length))
2389
+ ];
2390
+ if (lengths.length !== 1) {
2391
+ return null;
2392
+ }
2393
+ const length = lengths[0];
2394
+ if (length < 2) {
2395
+ return null;
2396
+ }
2397
+ const zipped = [];
2398
+ for (let index = 0; index < length; index += 1) {
2399
+ const item = {};
2400
+ for (const [key, value] of entries) {
2401
+ item[key] = value[index];
2402
+ }
2403
+ zipped.push(item);
2404
+ }
2405
+ return coerceArrayToArray(zipped, prefixItems, itemsSchema);
2406
+ }
2407
+ function coerceSingleKeyObjectToArray(singleValue, itemsSchema) {
2408
+ if (Array.isArray(singleValue)) {
2409
+ return singleValue.map((v) => coerceBySchema(v, itemsSchema));
2410
+ }
2411
+ if (singleValue && typeof singleValue === "object") {
2412
+ const primitiveWrapped = coercePrimitiveWrappedObject(
2413
+ singleValue,
2414
+ itemsSchema
2415
+ );
2416
+ if (primitiveWrapped !== null) {
2417
+ return [primitiveWrapped];
2418
+ }
2419
+ return [coerceBySchema(singleValue, itemsSchema)];
2420
+ }
2421
+ return null;
2422
+ }
2423
+ function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
2424
+ if (Object.hasOwn(maybe, "item")) {
2425
+ const items = maybe.item;
2426
+ const arr = Array.isArray(items) ? items : [items];
2427
+ return coerceArrayToArray(arr, prefixItems, itemsSchema);
1785
2428
  }
1786
2429
  const keys = Object.keys(maybe);
1787
2430
  if (keys.length > 0 && keys.every((k) => DIGIT_KEY_REGEX.test(k))) {
1788
2431
  const arr = keys.sort((a, b) => Number(a) - Number(b)).map((k) => maybe[k]);
1789
2432
  return coerceArrayToArray(arr, prefixItems, itemsSchema);
1790
2433
  }
2434
+ const parallelArrays = coerceParallelArraysObjectToArray(
2435
+ maybe,
2436
+ prefixItems,
2437
+ itemsSchema
2438
+ );
2439
+ if (parallelArrays !== null) {
2440
+ return parallelArrays;
2441
+ }
1791
2442
  if (keys.length === 1) {
1792
2443
  const singleKey = keys[0];
1793
2444
  if (!(schemaIsUnconstrained(itemsSchema) || schemaHasProperty(itemsSchema, singleKey))) {
1794
- const singleValue = maybe[singleKey];
1795
- if (Array.isArray(singleValue)) {
1796
- return singleValue.map((v) => coerceBySchema(v, itemsSchema));
1797
- }
1798
- if (singleValue && typeof singleValue === "object") {
1799
- return [coerceBySchema(singleValue, itemsSchema)];
2445
+ const result = coerceSingleKeyObjectToArray(
2446
+ maybe[singleKey],
2447
+ itemsSchema
2448
+ );
2449
+ if (result !== null) {
2450
+ return result;
1800
2451
  }
1801
2452
  }
1802
2453
  }
@@ -1826,6 +2477,86 @@ function coerceStringToPrimitive(s, schemaType) {
1826
2477
  }
1827
2478
  return null;
1828
2479
  }
2480
+ function coercePrimitiveToString(value, schemaType) {
2481
+ if (schemaType !== "string") {
2482
+ return null;
2483
+ }
2484
+ if (typeof value === "boolean") {
2485
+ return value ? "true" : "false";
2486
+ }
2487
+ if (typeof value === "number" && Number.isFinite(value)) {
2488
+ return String(value);
2489
+ }
2490
+ return null;
2491
+ }
2492
+ function coerceStringByEnumWhitespace(rawValue, unwrapped) {
2493
+ const enumValues = unwrapped.enum;
2494
+ if (!Array.isArray(enumValues) || enumValues.length === 0) {
2495
+ return null;
2496
+ }
2497
+ if (!enumValues.every((item) => typeof item === "string")) {
2498
+ return null;
2499
+ }
2500
+ const normalizedEnumValues = enumValues;
2501
+ if (normalizedEnumValues.includes(rawValue)) {
2502
+ return null;
2503
+ }
2504
+ const unquoted = unwrapMatchingQuotes(rawValue);
2505
+ if (unquoted !== null) {
2506
+ const exactMatches = normalizedEnumValues.filter(
2507
+ (item) => item === unquoted
2508
+ );
2509
+ if (exactMatches.length === 1) {
2510
+ return exactMatches[0];
2511
+ }
2512
+ }
2513
+ const candidates = [rawValue, unquoted].filter(
2514
+ (item) => item !== null
2515
+ );
2516
+ for (const candidate of candidates) {
2517
+ if (!HAS_WHITESPACE_REGEX.test(candidate)) {
2518
+ continue;
2519
+ }
2520
+ const normalizedInput = candidate.replace(WHITESPACE_REGEX2, "");
2521
+ const matches = normalizedEnumValues.filter(
2522
+ (item) => item.replace(WHITESPACE_REGEX2, "") === normalizedInput
2523
+ );
2524
+ if (matches.length === 1) {
2525
+ return matches[0];
2526
+ }
2527
+ }
2528
+ return null;
2529
+ }
2530
+ function unwrapMatchingQuotes(value) {
2531
+ if (value.length < 2) {
2532
+ return null;
2533
+ }
2534
+ const first = value[0];
2535
+ const last = value.at(-1);
2536
+ const isQuote = (first === SINGLE_QUOTE || first === DOUBLE_QUOTE) && first === last;
2537
+ if (!isQuote) {
2538
+ return null;
2539
+ }
2540
+ return value.slice(1, -1);
2541
+ }
2542
+ function coerceObjectToPrimitive(value, schemaType, fullSchema) {
2543
+ if (!isPrimitiveSchemaType(schemaType)) {
2544
+ return null;
2545
+ }
2546
+ const keys = Object.keys(value);
2547
+ if (keys.length !== 1) {
2548
+ return null;
2549
+ }
2550
+ const singleValue = value[keys[0]];
2551
+ if (singleValue && typeof singleValue === "object") {
2552
+ return null;
2553
+ }
2554
+ const coerced = coerceBySchema(
2555
+ singleValue,
2556
+ fullSchema != null ? fullSchema : { type: schemaType }
2557
+ );
2558
+ return isPrimitiveMatchForSchemaType(coerced, schemaType) ? coerced : null;
2559
+ }
1829
2560
  function coerceStringValue(value, schemaType, u) {
1830
2561
  const s = value.trim();
1831
2562
  if (schemaType === "object") {
@@ -1844,6 +2575,10 @@ function coerceStringValue(value, schemaType, u) {
1844
2575
  if (primitiveResult !== null) {
1845
2576
  return primitiveResult;
1846
2577
  }
2578
+ const enumWhitespaceCanonical = coerceStringByEnumWhitespace(s, u);
2579
+ if (enumWhitespaceCanonical !== null) {
2580
+ return enumWhitespaceCanonical;
2581
+ }
1847
2582
  return value;
1848
2583
  }
1849
2584
  function coerceArrayValue(value, prefixItems, itemsSchema) {
@@ -1882,9 +2617,23 @@ function coerceBySchema(value, schema) {
1882
2617
  if (typeof value === "string") {
1883
2618
  return coerceStringValue(value, schemaType, u);
1884
2619
  }
2620
+ const primitiveString = coercePrimitiveToString(value, schemaType);
2621
+ if (primitiveString !== null) {
2622
+ return primitiveString;
2623
+ }
1885
2624
  if (schemaType === "object" && value && typeof value === "object" && !Array.isArray(value)) {
1886
2625
  return coerceObjectToObject(value, u);
1887
2626
  }
2627
+ if (value && typeof value === "object" && !Array.isArray(value) && isPrimitiveSchemaType(schemaType)) {
2628
+ const primitiveResult = coerceObjectToPrimitive(
2629
+ value,
2630
+ schemaType,
2631
+ u
2632
+ );
2633
+ if (primitiveResult !== null) {
2634
+ return primitiveResult;
2635
+ }
2636
+ }
1888
2637
  if (schemaType === "array") {
1889
2638
  const prefixItems = Array.isArray(u.prefixItems) ? u.prefixItems : void 0;
1890
2639
  const itemsSchema = u.items;
@@ -2899,7 +3648,7 @@ var XMLTokenizer = class {
2899
3648
  };
2900
3649
 
2901
3650
  // src/rxml/core/parser.ts
2902
- var WHITESPACE_REGEX2 = /\s/;
3651
+ var WHITESPACE_REGEX3 = /\s/;
2903
3652
  var NUMERIC_STRING_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
2904
3653
  var DIGIT_KEY_REGEX2 = /^\d+$/;
2905
3654
  function getTopLevelStringProps(s) {
@@ -3069,7 +3818,7 @@ function parse2(xmlInner, schema, options = {}) {
3069
3818
  const closeHead = s.indexOf(`</${rootName}`, range.end);
3070
3819
  if (closeHead === range.end) {
3071
3820
  let p = closeHead + 2 + rootName.length;
3072
- while (p < s.length && WHITESPACE_REGEX2.test(s[p])) {
3821
+ while (p < s.length && WHITESPACE_REGEX3.test(s[p])) {
3073
3822
  p += 1;
3074
3823
  }
3075
3824
  if (s[p] === ">") {
@@ -3407,7 +4156,7 @@ function createIntermediateCall(toolName, rawSegment, schema) {
3407
4156
  var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
3408
4157
  var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
3409
4158
  var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
3410
- var WHITESPACE_REGEX3 = /\s/;
4159
+ var WHITESPACE_REGEX4 = /\s/;
3411
4160
  var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
3412
4161
  var NAME_START_CHAR_RE = /[A-Za-z_:]/;
3413
4162
  var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
@@ -3548,7 +4297,7 @@ function balanceTags(xml) {
3548
4297
  }
3549
4298
  function skipWs(s, p, len) {
3550
4299
  let idx = p;
3551
- while (idx < len && WHITESPACE_REGEX3.test(s[idx])) {
4300
+ while (idx < len && WHITESPACE_REGEX4.test(s[idx])) {
3552
4301
  idx += 1;
3553
4302
  }
3554
4303
  return idx;
@@ -3601,7 +4350,7 @@ function handleOpeningTagSegment(src, lt, out, stack) {
3601
4350
  return len;
3602
4351
  }
3603
4352
  let r = q - 1;
3604
- while (r >= nameStart && WHITESPACE_REGEX3.test(src[r])) {
4353
+ while (r >= nameStart && WHITESPACE_REGEX4.test(src[r])) {
3605
4354
  r -= 1;
3606
4355
  }
3607
4356
  const selfClosing = src[r] === "/";
@@ -3765,13 +4514,114 @@ function parse3(xml, schema, options = {}) {
3765
4514
 
3766
4515
  // src/core/utils/regex-constants.ts
3767
4516
  var NAME_CHAR_RE2 = /[A-Za-z0-9_:-]/;
3768
- var WHITESPACE_REGEX4 = /\s/;
4517
+ var WHITESPACE_REGEX5 = /\s/;
4518
+
4519
+ // src/core/utils/streamed-tool-input-delta.ts
4520
+ function emitDelta({
4521
+ controller,
4522
+ id,
4523
+ state,
4524
+ nextInput
4525
+ }) {
4526
+ if (!nextInput.startsWith(state.emittedInput)) {
4527
+ return false;
4528
+ }
4529
+ const delta = nextInput.slice(state.emittedInput.length);
4530
+ if (delta.length === 0) {
4531
+ return false;
4532
+ }
4533
+ controller.enqueue({
4534
+ type: "tool-input-delta",
4535
+ id,
4536
+ delta
4537
+ });
4538
+ state.emittedInput = nextInput;
4539
+ return true;
4540
+ }
4541
+ function toIncompleteJsonPrefix(fullJson) {
4542
+ const trimmed = fullJson.trim();
4543
+ let prefix = trimmed;
4544
+ while (prefix.endsWith("}") || prefix.endsWith("]")) {
4545
+ prefix = prefix.slice(0, -1);
4546
+ }
4547
+ prefix = prefix.trimEnd();
4548
+ if (prefix.endsWith('"')) {
4549
+ prefix = prefix.slice(0, -1);
4550
+ }
4551
+ if (prefix.length === 0) {
4552
+ if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
4553
+ return trimmed.startsWith("{") ? "{" : "[";
4554
+ }
4555
+ if (trimmed.startsWith("]")) {
4556
+ return "[";
4557
+ }
4558
+ if (trimmed.startsWith("}")) {
4559
+ return "{";
4560
+ }
4561
+ if (trimmed.startsWith('"')) {
4562
+ return '"';
4563
+ }
4564
+ return "{";
4565
+ }
4566
+ return prefix;
4567
+ }
4568
+ function emitPrefixDelta(params) {
4569
+ return emitDelta({
4570
+ ...params,
4571
+ nextInput: params.candidate
4572
+ });
4573
+ }
4574
+ function emitFinalRemainder(params) {
4575
+ var _a;
4576
+ const result = emitDelta({
4577
+ ...params,
4578
+ nextInput: params.finalFullJson
4579
+ });
4580
+ if (!result && params.state.emittedInput.length > 0) {
4581
+ (_a = params.onMismatch) == null ? void 0 : _a.call(
4582
+ params,
4583
+ "Final JSON does not extend emitted tool-input prefix",
4584
+ {
4585
+ emittedLength: params.state.emittedInput.length,
4586
+ finalLength: params.finalFullJson.length
4587
+ }
4588
+ );
4589
+ }
4590
+ return result;
4591
+ }
4592
+
4593
+ // src/core/utils/xml-root-repair.ts
4594
+ var XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX = /^<([A-Za-z_][A-Za-z0-9_-]*)\s*\r?\n([\s\S]+?)\r?\n\s*\/>\s*$/;
4595
+ function tryRepairXmlSelfClosingRootWithBody(rawText, toolNames) {
4596
+ const trimmed = rawText.trim();
4597
+ if (trimmed.length === 0) {
4598
+ return null;
4599
+ }
4600
+ const match = trimmed.match(XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX);
4601
+ if (!match) {
4602
+ return null;
4603
+ }
4604
+ const rootTag = match[1];
4605
+ if (!toolNames.includes(rootTag)) {
4606
+ return null;
4607
+ }
4608
+ const body = match[2].trimEnd();
4609
+ if (body.trim().length === 0 || body.includes(`</${rootTag}>`)) {
4610
+ return null;
4611
+ }
4612
+ return `<${rootTag}>
4613
+ ${body}
4614
+ </${rootTag}>`;
4615
+ }
3769
4616
 
3770
4617
  // src/core/protocols/xml-protocol.ts
3771
4618
  function getToolSchema(tools, toolName) {
3772
4619
  var _a;
3773
4620
  return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
3774
4621
  }
4622
+ function shouldEmitRawToolCallTextOnError2(options) {
4623
+ return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
4624
+ }
3775
4625
  function processToolCall(params) {
3776
4626
  var _a, _b;
3777
4627
  const { toolCall, tools, options, text, processedElements, parseOptions } = params;
@@ -3784,7 +4634,7 @@ function processToolCall(params) {
3784
4634
  const parsed = parse3(toolCall.content, toolSchema, parseConfig);
3785
4635
  processedElements.push({
3786
4636
  type: "tool-call",
3787
- toolCallId: generateId(),
4637
+ toolCallId: generateToolCallId(),
3788
4638
  toolName: toolCall.toolName,
3789
4639
  input: JSON.stringify(parsed)
3790
4640
  });
@@ -3801,60 +4651,371 @@ function processToolCall(params) {
3801
4651
  processedElements.push({ type: "text", text: originalCallText });
3802
4652
  }
3803
4653
  }
3804
- function handleStreamingToolCallEnd(params) {
3805
- var _a, _b;
3806
- const {
3807
- toolContent,
3808
- currentToolCall,
3809
- tools,
3810
- options,
3811
- ctrl,
3812
- flushText,
3813
- parseOptions
3814
- } = params;
3815
- const toolSchema = getToolSchema(tools, currentToolCall.name);
3816
- const parseConfig = {
3817
- ...parseOptions != null ? parseOptions : {},
3818
- onError: (_a = options == null ? void 0 : options.onError) != null ? _a : parseOptions == null ? void 0 : parseOptions.onError
3819
- };
3820
- flushText(ctrl);
3821
- try {
3822
- const parsedResult = parse3(toolContent, toolSchema, parseConfig);
3823
- ctrl.enqueue({
3824
- type: "tool-call",
3825
- toolCallId: generateId(),
3826
- toolName: currentToolCall.name,
3827
- input: JSON.stringify(parsedResult)
3828
- });
3829
- } catch (error) {
3830
- const original = `<${currentToolCall.name}>${toolContent}</${currentToolCall.name}>`;
3831
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "Could not process streaming XML tool call", {
3832
- toolCall: original,
3833
- error
3834
- });
3835
- flushText(ctrl, original);
4654
+ function parseXmlTagName(rawTagBody) {
4655
+ let index = 0;
4656
+ while (index < rawTagBody.length && WHITESPACE_REGEX5.test(rawTagBody[index])) {
4657
+ index += 1;
3836
4658
  }
4659
+ const nameStart = index;
4660
+ while (index < rawTagBody.length && NAME_CHAR_RE2.test(rawTagBody.charAt(index))) {
4661
+ index += 1;
4662
+ }
4663
+ return rawTagBody.slice(nameStart, index);
3837
4664
  }
3838
- function findClosingTagEndFlexible(text, contentStart, toolName) {
3839
- let pos = contentStart;
3840
- let depth = 1;
3841
- while (pos < text.length) {
3842
- const tok = nextTagToken(text, pos);
3843
- if (tok.kind === "eof") {
3844
- break;
3845
- }
3846
- const result = updateDepthWithToken(tok, toolName, depth);
3847
- depth = result.depth;
3848
- if (result.closedAt !== void 0) {
3849
- return result.closedAt;
3850
- }
3851
- pos = tok.nextPos;
4665
+ function consumeXmlSpecialSection(fragment, ltIndex) {
4666
+ if (fragment.startsWith("<!--", ltIndex)) {
4667
+ const commentEnd = fragment.indexOf("-->", ltIndex + 4);
4668
+ return commentEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: commentEnd + 3 };
3852
4669
  }
3853
- return -1;
4670
+ if (fragment.startsWith("<![CDATA[", ltIndex)) {
4671
+ const cdataEnd = fragment.indexOf("]]>", ltIndex + 9);
4672
+ return cdataEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: cdataEnd + 3 };
4673
+ }
4674
+ if (fragment.startsWith("<?", ltIndex)) {
4675
+ const processingEnd = fragment.indexOf("?>", ltIndex + 2);
4676
+ return processingEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: processingEnd + 2 };
4677
+ }
4678
+ if (fragment.startsWith("<!", ltIndex)) {
4679
+ const declarationEnd = fragment.indexOf(">", ltIndex + 2);
4680
+ return declarationEnd === -1 ? { kind: "incomplete" } : { kind: "consumed", nextPos: declarationEnd + 1 };
4681
+ }
4682
+ return { kind: "none" };
3854
4683
  }
3855
- function skipSpecialSegment(text, lt) {
3856
- const next = text[lt + 1];
3857
- if (next === "!" || next === "?") {
4684
+ function parseXmlTagToken(fragment, ltIndex) {
4685
+ const gtIndex = fragment.indexOf(">", ltIndex + 1);
4686
+ if (gtIndex === -1) {
4687
+ return null;
4688
+ }
4689
+ const tagBody = fragment.slice(ltIndex + 1, gtIndex).trim();
4690
+ if (tagBody.length === 0) {
4691
+ return null;
4692
+ }
4693
+ if (tagBody.startsWith("/")) {
4694
+ const closeName = parseXmlTagName(tagBody.slice(1));
4695
+ if (closeName.length === 0) {
4696
+ return null;
4697
+ }
4698
+ return { kind: "close", name: closeName, nextPos: gtIndex + 1 };
4699
+ }
4700
+ const selfClosing = tagBody.endsWith("/");
4701
+ const openBody = selfClosing ? tagBody.slice(0, -1).trimEnd() : tagBody;
4702
+ const openName = parseXmlTagName(openBody);
4703
+ if (openName.length === 0) {
4704
+ return null;
4705
+ }
4706
+ return {
4707
+ kind: "open",
4708
+ name: openName,
4709
+ selfClosing,
4710
+ nextPos: gtIndex + 1
4711
+ };
4712
+ }
4713
+ function analyzeXmlFragmentForProgress(fragment) {
4714
+ const stack = [];
4715
+ const topLevelTagNames = [];
4716
+ let position = 0;
4717
+ while (position < fragment.length) {
4718
+ const ltIndex = fragment.indexOf("<", position);
4719
+ if (ltIndex === -1) {
4720
+ break;
4721
+ }
4722
+ const special = consumeXmlSpecialSection(fragment, ltIndex);
4723
+ if (special.kind === "incomplete") {
4724
+ return null;
4725
+ }
4726
+ if (special.kind === "consumed") {
4727
+ position = special.nextPos;
4728
+ continue;
4729
+ }
4730
+ const token = parseXmlTagToken(fragment, ltIndex);
4731
+ if (token === null) {
4732
+ return null;
4733
+ }
4734
+ if (token.kind === "close") {
4735
+ const openName = stack.pop();
4736
+ if (!openName || openName !== token.name) {
4737
+ return null;
4738
+ }
4739
+ position = token.nextPos;
4740
+ continue;
4741
+ }
4742
+ if (stack.length === 0) {
4743
+ topLevelTagNames.push(token.name);
4744
+ }
4745
+ if (!token.selfClosing) {
4746
+ stack.push(token.name);
4747
+ }
4748
+ position = token.nextPos;
4749
+ }
4750
+ if (stack.length > 0) {
4751
+ return null;
4752
+ }
4753
+ return { topLevelTagNames };
4754
+ }
4755
+ function scanXmlFragmentTopLevelTextStep(options) {
4756
+ const { fragment, position, stack } = options;
4757
+ const ltIndex = fragment.indexOf("<", position);
4758
+ if (ltIndex === -1) {
4759
+ const trailingText = fragment.slice(position);
4760
+ return {
4761
+ kind: "done",
4762
+ value: stack.length === 0 && trailingText.trim().length > 0
4763
+ };
4764
+ }
4765
+ const textBetweenTags = fragment.slice(position, ltIndex);
4766
+ if (stack.length === 0 && textBetweenTags.trim().length > 0) {
4767
+ return { kind: "found" };
4768
+ }
4769
+ const special = consumeXmlSpecialSection(fragment, ltIndex);
4770
+ if (special.kind === "incomplete") {
4771
+ return { kind: "invalid" };
4772
+ }
4773
+ if (special.kind === "consumed") {
4774
+ return { kind: "next", nextPos: special.nextPos };
4775
+ }
4776
+ const token = parseXmlTagToken(fragment, ltIndex);
4777
+ if (token === null) {
4778
+ return { kind: "invalid" };
4779
+ }
4780
+ if (token.kind === "close") {
4781
+ const openName = stack.pop();
4782
+ if (!openName || openName !== token.name) {
4783
+ return { kind: "invalid" };
4784
+ }
4785
+ } else if (!token.selfClosing) {
4786
+ stack.push(token.name);
4787
+ }
4788
+ return { kind: "next", nextPos: token.nextPos };
4789
+ }
4790
+ function hasNonWhitespaceTopLevelText(fragment) {
4791
+ if (!fragment.includes("<")) {
4792
+ return fragment.trim().length > 0;
4793
+ }
4794
+ const stack = [];
4795
+ let position = 0;
4796
+ while (position < fragment.length) {
4797
+ const step = scanXmlFragmentTopLevelTextStep({ fragment, position, stack });
4798
+ if (step.kind === "found") {
4799
+ return true;
4800
+ }
4801
+ if (step.kind === "invalid") {
4802
+ return false;
4803
+ }
4804
+ if (step.kind === "done") {
4805
+ return step.value;
4806
+ }
4807
+ position = step.nextPos;
4808
+ }
4809
+ return false;
4810
+ }
4811
+ function getObjectSchemaPropertyNames(schema) {
4812
+ if (!schema || typeof schema !== "object") {
4813
+ return null;
4814
+ }
4815
+ const schemaObject = schema;
4816
+ const typeValue = schemaObject.type;
4817
+ if (typeValue != null) {
4818
+ const isObjectType = typeValue === "object" || Array.isArray(typeValue) && typeValue.includes("object");
4819
+ if (!isObjectType) {
4820
+ return null;
4821
+ }
4822
+ }
4823
+ if (!schemaObject.properties || typeof schemaObject.properties !== "object") {
4824
+ return /* @__PURE__ */ new Set();
4825
+ }
4826
+ return new Set(
4827
+ Object.keys(schemaObject.properties)
4828
+ );
4829
+ }
4830
+ function schemaAllowsArrayType(schema) {
4831
+ if (!schema || typeof schema !== "object") {
4832
+ return false;
4833
+ }
4834
+ const schemaRecord = schema;
4835
+ const typeValue = schemaRecord.type;
4836
+ if (typeValue === "array") {
4837
+ return true;
4838
+ }
4839
+ if (Array.isArray(typeValue) && typeValue.includes("array")) {
4840
+ return true;
4841
+ }
4842
+ const unions = [schemaRecord.anyOf, schemaRecord.oneOf, schemaRecord.allOf];
4843
+ for (const union of unions) {
4844
+ if (!Array.isArray(union)) {
4845
+ continue;
4846
+ }
4847
+ if (union.some((entry) => schemaAllowsArrayType(entry))) {
4848
+ return true;
4849
+ }
4850
+ }
4851
+ return false;
4852
+ }
4853
+ function getSchemaObjectProperty(schema, propertyName) {
4854
+ if (!schema || typeof schema !== "object") {
4855
+ return null;
4856
+ }
4857
+ const schemaObject = schema;
4858
+ const properties = schemaObject.properties;
4859
+ if (!properties || typeof properties !== "object") {
4860
+ return null;
4861
+ }
4862
+ const property = properties[propertyName];
4863
+ if (!property) {
4864
+ return null;
4865
+ }
4866
+ return property;
4867
+ }
4868
+ function isStableXmlProgressCandidate(options) {
4869
+ const { candidate, parsed, toolSchema } = options;
4870
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
4871
+ return false;
4872
+ }
4873
+ const structure = analyzeXmlFragmentForProgress(candidate);
4874
+ if (!structure) {
4875
+ return false;
4876
+ }
4877
+ const schemaProperties = getObjectSchemaPropertyNames(toolSchema);
4878
+ if (!schemaProperties || schemaProperties.size === 0) {
4879
+ return false;
4880
+ }
4881
+ const parsedObject = parsed;
4882
+ const uniqueTopLevelTags = new Set(structure.topLevelTagNames);
4883
+ for (const tagName of uniqueTopLevelTags) {
4884
+ if (!schemaProperties.has(tagName)) {
4885
+ continue;
4886
+ }
4887
+ const schemaProperty = getSchemaObjectProperty(toolSchema, tagName);
4888
+ if (schemaProperty && schemaAllowsArrayType(schemaProperty) && !Array.isArray(parsedObject[tagName])) {
4889
+ return false;
4890
+ }
4891
+ }
4892
+ if (structure.topLevelTagNames.length === 1) {
4893
+ const onlyTopLevelTag = structure.topLevelTagNames[0];
4894
+ if (!schemaProperties || schemaProperties.size === 0 || !schemaProperties.has(onlyTopLevelTag)) {
4895
+ return false;
4896
+ }
4897
+ }
4898
+ return true;
4899
+ }
4900
+ function parseXmlContentForStreamProgress({
4901
+ toolContent,
4902
+ toolSchema,
4903
+ parseOptions
4904
+ }) {
4905
+ const tryParse = (content) => {
4906
+ try {
4907
+ return parse3(content, toolSchema, {
4908
+ ...parseOptions != null ? parseOptions : {},
4909
+ repair: false,
4910
+ onError: void 0
4911
+ });
4912
+ } catch (e) {
4913
+ return null;
4914
+ }
4915
+ };
4916
+ const strictFull = tryParse(toolContent);
4917
+ if (strictFull !== null && isStableXmlProgressCandidate({
4918
+ candidate: toolContent,
4919
+ parsed: strictFull,
4920
+ toolSchema
4921
+ })) {
4922
+ return JSON.stringify(strictFull);
4923
+ }
4924
+ let searchEnd = toolContent.length;
4925
+ while (searchEnd > 0) {
4926
+ const gtIndex = toolContent.lastIndexOf(">", searchEnd - 1);
4927
+ if (gtIndex === -1) {
4928
+ break;
4929
+ }
4930
+ const candidate = toolContent.slice(0, gtIndex + 1);
4931
+ if (!analyzeXmlFragmentForProgress(candidate)) {
4932
+ searchEnd = gtIndex;
4933
+ continue;
4934
+ }
4935
+ const parsedCandidate = tryParse(candidate);
4936
+ if (parsedCandidate !== null && isStableXmlProgressCandidate({
4937
+ candidate,
4938
+ parsed: parsedCandidate,
4939
+ toolSchema
4940
+ })) {
4941
+ return JSON.stringify(parsedCandidate);
4942
+ }
4943
+ searchEnd = gtIndex;
4944
+ }
4945
+ return null;
4946
+ }
4947
+ function handleStreamingToolCallEnd(params) {
4948
+ var _a, _b;
4949
+ const {
4950
+ toolContent,
4951
+ currentToolCall,
4952
+ tools,
4953
+ options,
4954
+ ctrl,
4955
+ flushText,
4956
+ parseOptions
4957
+ } = params;
4958
+ const toolSchema = getToolSchema(tools, currentToolCall.name);
4959
+ const parseConfig = {
4960
+ ...parseOptions != null ? parseOptions : {},
4961
+ onError: (_a = options == null ? void 0 : options.onError) != null ? _a : parseOptions == null ? void 0 : parseOptions.onError
4962
+ };
4963
+ flushText(ctrl);
4964
+ try {
4965
+ const parsedResult = parse3(toolContent, toolSchema, parseConfig);
4966
+ const finalInput = JSON.stringify(parsedResult);
4967
+ emitFinalRemainder({
4968
+ controller: ctrl,
4969
+ id: currentToolCall.toolCallId,
4970
+ state: currentToolCall,
4971
+ finalFullJson: finalInput,
4972
+ onMismatch: options == null ? void 0 : options.onError
4973
+ });
4974
+ ctrl.enqueue({
4975
+ type: "tool-input-end",
4976
+ id: currentToolCall.toolCallId
4977
+ });
4978
+ ctrl.enqueue({
4979
+ type: "tool-call",
4980
+ toolCallId: currentToolCall.toolCallId,
4981
+ toolName: currentToolCall.name,
4982
+ input: finalInput
4983
+ });
4984
+ } catch (error) {
4985
+ ctrl.enqueue({
4986
+ type: "tool-input-end",
4987
+ id: currentToolCall.toolCallId
4988
+ });
4989
+ const original = `<${currentToolCall.name}>${toolContent}</${currentToolCall.name}>`;
4990
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "Could not process streaming XML tool call", {
4991
+ toolCall: original,
4992
+ error
4993
+ });
4994
+ if (shouldEmitRawToolCallTextOnError2(options)) {
4995
+ flushText(ctrl, original);
4996
+ }
4997
+ }
4998
+ }
4999
+ function findClosingTagEndFlexible(text, contentStart, toolName) {
5000
+ let pos = contentStart;
5001
+ let depth = 1;
5002
+ while (pos < text.length) {
5003
+ const tok = nextTagToken(text, pos);
5004
+ if (tok.kind === "eof") {
5005
+ break;
5006
+ }
5007
+ const result = updateDepthWithToken(tok, toolName, depth);
5008
+ depth = result.depth;
5009
+ if (result.closedAt !== void 0) {
5010
+ return result.closedAt;
5011
+ }
5012
+ pos = tok.nextPos;
5013
+ }
5014
+ return -1;
5015
+ }
5016
+ function skipSpecialSegment(text, lt) {
5017
+ const next = text[lt + 1];
5018
+ if (next === "!" || next === "?") {
3858
5019
  const gt = text.indexOf(">", lt + 1);
3859
5020
  if (gt !== -1) {
3860
5021
  return gt + 1;
@@ -3869,7 +5030,7 @@ function consumeClosingTag(text, lt) {
3869
5030
  }
3870
5031
  function consumeOpenTag(text, lt) {
3871
5032
  let p = lt + 1;
3872
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
5033
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3873
5034
  p += 1;
3874
5035
  }
3875
5036
  const nameStart = p;
@@ -3882,7 +5043,7 @@ function consumeOpenTag(text, lt) {
3882
5043
  return null;
3883
5044
  }
3884
5045
  let r = q - 1;
3885
- while (r >= nameStart && WHITESPACE_REGEX4.test(text[r])) {
5046
+ while (r >= nameStart && WHITESPACE_REGEX5.test(text[r])) {
3886
5047
  r -= 1;
3887
5048
  }
3888
5049
  const selfClosing = text[r] === "/";
@@ -3911,7 +5072,7 @@ function nextTagToken(text, fromPos) {
3911
5072
  if (next === "/") {
3912
5073
  const closing = consumeClosingTag(text, lt);
3913
5074
  let p = lt + 2;
3914
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
5075
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3915
5076
  p += 1;
3916
5077
  }
3917
5078
  const nameStart = p;
@@ -4048,6 +5209,102 @@ function findToolCalls(text, toolNames) {
4048
5209
  }
4049
5210
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
4050
5211
  }
5212
+ function handleSpecialToken(depth) {
5213
+ return { depth, lastCompleteEnd: -1, shouldBreak: false };
5214
+ }
5215
+ function handleOpenToken(token, depth, lastCompleteEnd) {
5216
+ if (token.selfClosing) {
5217
+ return {
5218
+ depth,
5219
+ lastCompleteEnd: depth === 0 ? token.nextPos : lastCompleteEnd,
5220
+ shouldBreak: false
5221
+ };
5222
+ }
5223
+ return { depth: depth + 1, lastCompleteEnd, shouldBreak: false };
5224
+ }
5225
+ function handleCloseToken(token, depth) {
5226
+ if (depth <= 0) {
5227
+ return { depth, lastCompleteEnd: -1, shouldBreak: true };
5228
+ }
5229
+ const newDepth = depth - 1;
5230
+ return {
5231
+ depth: newDepth,
5232
+ lastCompleteEnd: newDepth === 0 ? token.nextPos : -1,
5233
+ shouldBreak: false
5234
+ };
5235
+ }
5236
+ function findLinePrefixedXmlBodyEnd(text, bodyStartIndex) {
5237
+ let cursor = bodyStartIndex;
5238
+ let depth = 0;
5239
+ let lastCompleteEnd = -1;
5240
+ while (cursor < text.length) {
5241
+ if (depth === 0) {
5242
+ cursor = consumeWhitespace(text, cursor);
5243
+ if (cursor >= text.length || text.charAt(cursor) !== "<") {
5244
+ break;
5245
+ }
5246
+ }
5247
+ const token = nextTagToken(text, cursor);
5248
+ if (token.kind === "eof") {
5249
+ break;
5250
+ }
5251
+ let result;
5252
+ if (token.kind === "special") {
5253
+ result = handleSpecialToken(depth);
5254
+ } else if (token.kind === "open") {
5255
+ result = handleOpenToken(token, depth, lastCompleteEnd);
5256
+ } else {
5257
+ result = handleCloseToken(token, depth);
5258
+ }
5259
+ depth = result.depth;
5260
+ if (result.lastCompleteEnd !== -1) {
5261
+ lastCompleteEnd = result.lastCompleteEnd;
5262
+ }
5263
+ if (result.shouldBreak) {
5264
+ break;
5265
+ }
5266
+ cursor = token.nextPos;
5267
+ }
5268
+ return lastCompleteEnd;
5269
+ }
5270
+ function findLinePrefixedToolCall(text, toolNames) {
5271
+ var _a;
5272
+ let best = null;
5273
+ for (const toolName of toolNames) {
5274
+ const linePattern = new RegExp(
5275
+ `(^|\\n)[\\t ]*${escapeRegExp(toolName)}[\\t ]*:?[\\t ]*(?:\\r?\\n|$)`,
5276
+ "g"
5277
+ );
5278
+ let match = linePattern.exec(text);
5279
+ while (match !== null) {
5280
+ const prefix = (_a = match[1]) != null ? _a : "";
5281
+ const startIndex = match.index + prefix.length;
5282
+ const contentStart = consumeWhitespace(text, linePattern.lastIndex);
5283
+ if (contentStart >= text.length || text.charAt(contentStart) !== "<") {
5284
+ match = linePattern.exec(text);
5285
+ continue;
5286
+ }
5287
+ const contentEnd = findLinePrefixedXmlBodyEnd(text, contentStart);
5288
+ if (contentEnd === -1 || contentEnd <= contentStart) {
5289
+ match = linePattern.exec(text);
5290
+ continue;
5291
+ }
5292
+ const content = text.slice(contentStart, contentEnd);
5293
+ const candidate = {
5294
+ toolName,
5295
+ startIndex,
5296
+ endIndex: contentEnd,
5297
+ content,
5298
+ segment: text.slice(startIndex, contentEnd)
5299
+ };
5300
+ if (best === null || candidate.startIndex < best.startIndex) {
5301
+ best = candidate;
5302
+ }
5303
+ break;
5304
+ }
5305
+ }
5306
+ return best;
5307
+ }
4051
5308
  function findEarliestToolTag(buffer, toolNames) {
4052
5309
  var _a, _b;
4053
5310
  let bestIndex = -1;
@@ -4086,7 +5343,7 @@ function isOpenTagPrefix(suffix, toolName) {
4086
5343
  }
4087
5344
  function consumeWhitespace(text, index) {
4088
5345
  let i = index;
4089
- while (i < text.length && WHITESPACE_REGEX4.test(text.charAt(i))) {
5346
+ while (i < text.length && WHITESPACE_REGEX5.test(text.charAt(i))) {
4090
5347
  i += 1;
4091
5348
  }
4092
5349
  return i;
@@ -4158,38 +5415,6 @@ function findPotentialToolTagStart(buffer, toolNames) {
4158
5415
  }
4159
5416
  return -1;
4160
5417
  }
4161
- function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
4162
- return (controller, text) => {
4163
- const content = text;
4164
- if (content) {
4165
- if (!getCurrentTextId()) {
4166
- const newId = generateId();
4167
- setCurrentTextId(newId);
4168
- controller.enqueue({
4169
- type: "text-start",
4170
- id: newId
4171
- });
4172
- setHasEmittedTextStart(true);
4173
- }
4174
- controller.enqueue({
4175
- type: "text-delta",
4176
- id: getCurrentTextId(),
4177
- delta: content
4178
- });
4179
- }
4180
- const currentTextId = getCurrentTextId();
4181
- if (currentTextId && !text) {
4182
- if (getHasEmittedTextStart()) {
4183
- controller.enqueue({
4184
- type: "text-end",
4185
- id: currentTextId
4186
- });
4187
- setHasEmittedTextStart(false);
4188
- }
4189
- setCurrentTextId(null);
4190
- }
4191
- };
4192
- }
4193
5418
  function processToolCallInBuffer(params) {
4194
5419
  const {
4195
5420
  buffer,
@@ -4199,18 +5424,21 @@ function processToolCallInBuffer(params) {
4199
5424
  controller,
4200
5425
  flushText,
4201
5426
  setBuffer,
4202
- parseOptions
5427
+ parseOptions,
5428
+ emitToolInputProgress: emitToolInputProgress2
4203
5429
  } = params;
4204
5430
  const endTagPattern = new RegExp(
4205
5431
  `</\\s*${escapeRegExp(currentToolCall.name)}\\s*>`
4206
5432
  );
4207
5433
  const endMatch = endTagPattern.exec(buffer);
4208
5434
  if (!endMatch || endMatch.index === void 0) {
5435
+ emitToolInputProgress2(controller, currentToolCall, buffer);
4209
5436
  return { buffer, currentToolCall, shouldBreak: true };
4210
5437
  }
4211
5438
  const endIdx = endMatch.index;
4212
5439
  const endPos = endIdx + endMatch[0].length;
4213
5440
  const content = buffer.substring(0, endIdx);
5441
+ emitToolInputProgress2(controller, currentToolCall, content);
4214
5442
  const remainder = buffer.substring(endPos);
4215
5443
  setBuffer(remainder);
4216
5444
  handleStreamingToolCallEnd({
@@ -4237,7 +5465,8 @@ function processNoToolCallInBuffer(params) {
4237
5465
  tools,
4238
5466
  options,
4239
5467
  parseOptions,
4240
- setBuffer
5468
+ setBuffer,
5469
+ emitToolInputStart
4241
5470
  } = params;
4242
5471
  const {
4243
5472
  index: earliestStartTagIndex,
@@ -4267,9 +5496,10 @@ function processNoToolCallInBuffer(params) {
4267
5496
  if (selfClosing) {
4268
5497
  const newBuffer2 = buffer.substring(earliestStartTagIndex + tagLength);
4269
5498
  setBuffer(newBuffer2);
5499
+ const currentToolCall = emitToolInputStart(controller, earliestToolName);
4270
5500
  handleStreamingToolCallEnd({
4271
5501
  toolContent: "",
4272
- currentToolCall: { name: earliestToolName, content: "" },
5502
+ currentToolCall,
4273
5503
  tools,
4274
5504
  options,
4275
5505
  ctrl: controller,
@@ -4288,12 +5518,12 @@ function processNoToolCallInBuffer(params) {
4288
5518
  setBuffer(newBuffer);
4289
5519
  return {
4290
5520
  buffer: newBuffer,
4291
- currentToolCall: { name: earliestToolName, content: "" },
5521
+ currentToolCall: emitToolInputStart(controller, earliestToolName),
4292
5522
  shouldBreak: false,
4293
5523
  shouldContinue: true
4294
5524
  };
4295
5525
  }
4296
- function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, setCurrentToolCall, tools, options, toolNames, flushText, parseOptions) {
5526
+ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, setCurrentToolCall, tools, options, toolNames, flushText, parseOptions, emitToolInputProgress2, emitToolInputStart) {
4297
5527
  return (controller) => {
4298
5528
  while (true) {
4299
5529
  const currentToolCall = getCurrentToolCall();
@@ -4306,7 +5536,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
4306
5536
  controller,
4307
5537
  flushText,
4308
5538
  setBuffer,
4309
- parseOptions
5539
+ parseOptions,
5540
+ emitToolInputProgress: emitToolInputProgress2
4310
5541
  });
4311
5542
  setBuffer(result.buffer);
4312
5543
  setCurrentToolCall(result.currentToolCall);
@@ -4322,7 +5553,8 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
4322
5553
  tools,
4323
5554
  options,
4324
5555
  parseOptions,
4325
- setBuffer
5556
+ setBuffer,
5557
+ emitToolInputStart
4326
5558
  });
4327
5559
  setBuffer(result.buffer);
4328
5560
  setCurrentToolCall(result.currentToolCall);
@@ -4337,6 +5569,27 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
4337
5569
  }
4338
5570
  };
4339
5571
  }
5572
+ function findToolCallsWithFallbacks(text, toolNames) {
5573
+ let parseText = text;
5574
+ let toolCalls = findToolCalls(parseText, toolNames);
5575
+ if (toolCalls.length === 0) {
5576
+ const fallbackToolCall = findLinePrefixedToolCall(parseText, toolNames);
5577
+ if (fallbackToolCall !== null) {
5578
+ toolCalls.push(fallbackToolCall);
5579
+ }
5580
+ }
5581
+ if (toolCalls.length === 0) {
5582
+ const repaired = tryRepairXmlSelfClosingRootWithBody(parseText, toolNames);
5583
+ if (repaired) {
5584
+ const repairedCalls = findToolCalls(repaired, toolNames);
5585
+ if (repairedCalls.length > 0) {
5586
+ parseText = repaired;
5587
+ toolCalls = repairedCalls;
5588
+ }
5589
+ }
5590
+ }
5591
+ return { parseText, toolCalls };
5592
+ }
4340
5593
  var xmlProtocol = (protocolOptions) => {
4341
5594
  var _a;
4342
5595
  const parseOptions = {
@@ -4370,28 +5623,31 @@ var xmlProtocol = (protocolOptions) => {
4370
5623
  }
4371
5624
  const processedElements = [];
4372
5625
  let currentIndex = 0;
4373
- const toolCalls = findToolCalls(text, toolNames);
5626
+ const { parseText, toolCalls } = findToolCallsWithFallbacks(
5627
+ text,
5628
+ toolNames
5629
+ );
4374
5630
  for (const tc of toolCalls) {
4375
5631
  if (tc.startIndex > currentIndex) {
4376
5632
  processedElements.push({
4377
5633
  type: "text",
4378
- text: text.substring(currentIndex, tc.startIndex)
5634
+ text: parseText.substring(currentIndex, tc.startIndex)
4379
5635
  });
4380
5636
  }
4381
5637
  processToolCall({
4382
5638
  toolCall: tc,
4383
5639
  tools,
4384
5640
  options,
4385
- text,
5641
+ text: parseText,
4386
5642
  processedElements,
4387
5643
  parseOptions
4388
5644
  });
4389
5645
  currentIndex = tc.endIndex;
4390
5646
  }
4391
- if (currentIndex < text.length) {
5647
+ if (currentIndex < parseText.length) {
4392
5648
  processedElements.push({
4393
5649
  type: "text",
4394
- text: text.substring(currentIndex)
5650
+ text: parseText.substring(currentIndex)
4395
5651
  });
4396
5652
  }
4397
5653
  return processedElements;
@@ -4412,8 +5668,120 @@ var xmlProtocol = (protocolOptions) => {
4412
5668
  hasEmittedTextStart = value;
4413
5669
  }
4414
5670
  );
4415
- const processBuffer = createProcessBufferHandler(
4416
- () => buffer,
5671
+ const emitToolInputStart = (controller, toolName) => {
5672
+ flushText(controller);
5673
+ const next = {
5674
+ name: toolName,
5675
+ toolCallId: generateToolCallId(),
5676
+ emittedInput: "",
5677
+ lastProgressGtIndex: null,
5678
+ lastProgressFullInput: null
5679
+ };
5680
+ controller.enqueue({
5681
+ type: "tool-input-start",
5682
+ id: next.toolCallId,
5683
+ toolName
5684
+ });
5685
+ return next;
5686
+ };
5687
+ const emitToolInputProgress2 = (controller, toolCall, toolContent) => {
5688
+ const progressGtIndex = toolContent.lastIndexOf(">");
5689
+ if (toolCall.lastProgressGtIndex === progressGtIndex) {
5690
+ const cached = toolCall.lastProgressFullInput;
5691
+ if (cached == null) {
5692
+ return;
5693
+ }
5694
+ if (cached === "{}" && toolContent.trim().length === 0) {
5695
+ return;
5696
+ }
5697
+ const prefixCandidate2 = toIncompleteJsonPrefix(cached);
5698
+ emitPrefixDelta({
5699
+ controller,
5700
+ id: toolCall.toolCallId,
5701
+ state: toolCall,
5702
+ candidate: prefixCandidate2
5703
+ });
5704
+ return;
5705
+ }
5706
+ const toolSchema = getToolSchema(tools, toolCall.name);
5707
+ const fullInput = parseXmlContentForStreamProgress({
5708
+ toolContent,
5709
+ toolSchema,
5710
+ parseOptions
5711
+ });
5712
+ toolCall.lastProgressGtIndex = progressGtIndex;
5713
+ toolCall.lastProgressFullInput = fullInput;
5714
+ if (fullInput == null) {
5715
+ return;
5716
+ }
5717
+ if (fullInput === "{}" && toolContent.trim().length === 0) {
5718
+ return;
5719
+ }
5720
+ const prefixCandidate = toIncompleteJsonPrefix(fullInput);
5721
+ emitPrefixDelta({
5722
+ controller,
5723
+ id: toolCall.toolCallId,
5724
+ state: toolCall,
5725
+ candidate: prefixCandidate
5726
+ });
5727
+ };
5728
+ const finalizeUnclosedToolCall = (controller) => {
5729
+ var _a2, _b;
5730
+ if (!currentToolCall) {
5731
+ return;
5732
+ }
5733
+ emitToolInputProgress2(controller, currentToolCall, buffer);
5734
+ const parseConfig = {
5735
+ ...parseOptions,
5736
+ onError: (_a2 = options == null ? void 0 : options.onError) != null ? _a2 : parseOptions == null ? void 0 : parseOptions.onError
5737
+ };
5738
+ const toolSchema = getToolSchema(tools, currentToolCall.name);
5739
+ flushText(controller);
5740
+ try {
5741
+ if (hasNonWhitespaceTopLevelText(buffer)) {
5742
+ throw new Error(
5743
+ "Cannot reconcile unclosed XML tool call with top-level plain text."
5744
+ );
5745
+ }
5746
+ const parsedResult = parse3(buffer, toolSchema, parseConfig);
5747
+ const finalInput = JSON.stringify(parsedResult);
5748
+ emitFinalRemainder({
5749
+ controller,
5750
+ id: currentToolCall.toolCallId,
5751
+ state: currentToolCall,
5752
+ finalFullJson: finalInput,
5753
+ onMismatch: options == null ? void 0 : options.onError
5754
+ });
5755
+ controller.enqueue({
5756
+ type: "tool-input-end",
5757
+ id: currentToolCall.toolCallId
5758
+ });
5759
+ controller.enqueue({
5760
+ type: "tool-call",
5761
+ toolCallId: currentToolCall.toolCallId,
5762
+ toolName: currentToolCall.name,
5763
+ input: finalInput
5764
+ });
5765
+ } catch (error) {
5766
+ controller.enqueue({
5767
+ type: "tool-input-end",
5768
+ id: currentToolCall.toolCallId
5769
+ });
5770
+ const unfinishedContent = `<${currentToolCall.name}>${buffer}`;
5771
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5772
+ options,
5773
+ "Could not complete streaming XML tool call at finish.",
5774
+ { toolCall: unfinishedContent, error }
5775
+ );
5776
+ if (shouldEmitRawToolCallTextOnError2(options)) {
5777
+ flushText(controller, unfinishedContent);
5778
+ }
5779
+ }
5780
+ buffer = "";
5781
+ currentToolCall = null;
5782
+ };
5783
+ const processBuffer = createProcessBufferHandler(
5784
+ () => buffer,
4417
5785
  (newBuffer) => {
4418
5786
  buffer = newBuffer;
4419
5787
  },
@@ -4425,13 +5793,28 @@ var xmlProtocol = (protocolOptions) => {
4425
5793
  options,
4426
5794
  toolNames,
4427
5795
  flushText,
4428
- parseOptions
5796
+ parseOptions,
5797
+ emitToolInputProgress2,
5798
+ emitToolInputStart
4429
5799
  );
4430
5800
  return new TransformStream({
5801
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Stateful stream parsing requires branching over chunk lifecycle and parser states.
4431
5802
  transform(chunk, controller) {
4432
5803
  var _a2;
5804
+ if (chunk.type === "finish") {
5805
+ if (currentToolCall) {
5806
+ finalizeUnclosedToolCall(controller);
5807
+ } else if (buffer) {
5808
+ flushText(controller, buffer);
5809
+ buffer = "";
5810
+ }
5811
+ flushText(controller);
5812
+ controller.enqueue(chunk);
5813
+ return;
5814
+ }
4433
5815
  if (chunk.type !== "text-delta") {
4434
- if (buffer) {
5816
+ if (currentToolCall) {
5817
+ } else if (buffer) {
4435
5818
  flushText(controller, buffer);
4436
5819
  buffer = "";
4437
5820
  }
@@ -4444,10 +5827,7 @@ var xmlProtocol = (protocolOptions) => {
4444
5827
  },
4445
5828
  flush(controller) {
4446
5829
  if (currentToolCall) {
4447
- const unfinishedContent = `<${currentToolCall.name}>${currentToolCall.content || ""}${buffer}`;
4448
- flushText(controller, unfinishedContent);
4449
- buffer = "";
4450
- currentToolCall = null;
5830
+ finalizeUnclosedToolCall(controller);
4451
5831
  } else if (buffer) {
4452
5832
  flushText(controller, buffer);
4453
5833
  buffer = "";
@@ -4475,7 +5855,205 @@ var xmlProtocol = (protocolOptions) => {
4475
5855
 
4476
5856
  // src/core/protocols/yaml-protocol.ts
4477
5857
  var import_yaml = __toESM(require("yaml"), 1);
5858
+ function shouldEmitRawToolCallTextOnError3(options) {
5859
+ return (options == null ? void 0 : options.emitRawToolCallTextOnError) === true;
5860
+ }
5861
+ var selfClosingTagCache2 = /* @__PURE__ */ new Map();
5862
+ function getSelfClosingTagPattern2(toolName) {
5863
+ let pattern = selfClosingTagCache2.get(toolName);
5864
+ if (!pattern) {
5865
+ pattern = new RegExp(`<\\s*${escapeRegExp(toolName)}\\s*/>`, "g");
5866
+ selfClosingTagCache2.set(toolName, pattern);
5867
+ }
5868
+ return pattern;
5869
+ }
4478
5870
  var LEADING_WHITESPACE_RE = /^(\s*)/;
5871
+ var INCOMPLETE_MAPPING_TAIL_RE = /^[^:[\]{}-][^:]*:\s*$/;
5872
+ var INCOMPLETE_SEQUENCE_TAIL_RE = /^-\s*$/;
5873
+ var BLOCK_SCALAR_KEY_RE = /:\s*[|>][-+0-9]*\s*$/;
5874
+ var PLAIN_MAPPING_VALUE_RE = /^[^:[\]{}-][^:]*:\s*(.+)$/;
5875
+ var PLAIN_SEQUENCE_VALUE_RE = /^-\s+(.+)$/;
5876
+ function normalizeYamlContent(yamlContent) {
5877
+ let normalized = yamlContent;
5878
+ if (normalized.startsWith("\n")) {
5879
+ normalized = normalized.slice(1);
5880
+ }
5881
+ const lines = normalized.split("\n");
5882
+ const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
5883
+ if (nonEmptyLines.length === 0) {
5884
+ return { normalized: "", nonEmptyLines };
5885
+ }
5886
+ const minIndent = Math.min(
5887
+ ...nonEmptyLines.map((line) => {
5888
+ const match = line.match(LEADING_WHITESPACE_RE);
5889
+ return match ? match[1].length : 0;
5890
+ })
5891
+ );
5892
+ if (minIndent > 0) {
5893
+ normalized = lines.map((line) => line.slice(minIndent)).join("\n");
5894
+ }
5895
+ return { normalized, nonEmptyLines };
5896
+ }
5897
+ function parseYamlDocumentAsMapping(normalized) {
5898
+ try {
5899
+ const doc = import_yaml.default.parseDocument(normalized);
5900
+ const errors = doc.errors.map((e) => e.message);
5901
+ const result = doc.toJSON();
5902
+ if (result === null) {
5903
+ return { value: {}, errors };
5904
+ }
5905
+ if (typeof result !== "object" || Array.isArray(result)) {
5906
+ return { value: null, errors };
5907
+ }
5908
+ return { value: result, errors };
5909
+ } catch (error) {
5910
+ return {
5911
+ value: null,
5912
+ errors: [
5913
+ error instanceof Error ? error.message : "Unknown YAML parsing error"
5914
+ ]
5915
+ };
5916
+ }
5917
+ }
5918
+ function getLastMeaningfulLineInfo(input) {
5919
+ var _a;
5920
+ const lines = input.split("\n");
5921
+ let index = lines.length - 1;
5922
+ while (index >= 0) {
5923
+ const raw = (_a = lines[index]) != null ? _a : "";
5924
+ const trimmed = raw.trim();
5925
+ if (trimmed.length > 0 && !trimmed.startsWith("#")) {
5926
+ return {
5927
+ index,
5928
+ raw,
5929
+ trimmed,
5930
+ indent: raw.length - raw.trimStart().length
5931
+ };
5932
+ }
5933
+ index -= 1;
5934
+ }
5935
+ return null;
5936
+ }
5937
+ function dropLastMeaningfulLine(input) {
5938
+ const lineInfo = getLastMeaningfulLineInfo(input);
5939
+ if (!lineInfo) {
5940
+ return null;
5941
+ }
5942
+ return input.split("\n").slice(0, lineInfo.index).join("\n").trimEnd();
5943
+ }
5944
+ function hasIncompleteMappingTail(normalized) {
5945
+ const lineInfo = getLastMeaningfulLineInfo(normalized);
5946
+ if (!lineInfo) {
5947
+ return false;
5948
+ }
5949
+ return INCOMPLETE_MAPPING_TAIL_RE.test(lineInfo.trimmed);
5950
+ }
5951
+ function hasIncompleteSequenceTail(normalized) {
5952
+ const lineInfo = getLastMeaningfulLineInfo(normalized);
5953
+ if (!lineInfo) {
5954
+ return false;
5955
+ }
5956
+ return INCOMPLETE_SEQUENCE_TAIL_RE.test(lineInfo.trimmed);
5957
+ }
5958
+ function hasSplitNestedKeyTail(normalized) {
5959
+ var _a;
5960
+ const lineInfo = getLastMeaningfulLineInfo(normalized);
5961
+ if (!lineInfo) {
5962
+ return false;
5963
+ }
5964
+ const { trimmed, indent, index } = lineInfo;
5965
+ if (indent === 0) {
5966
+ return false;
5967
+ }
5968
+ if (trimmed.startsWith("#") || trimmed.startsWith("-") || trimmed.includes(":")) {
5969
+ return false;
5970
+ }
5971
+ const lines = normalized.split("\n");
5972
+ let parentIndex = index - 1;
5973
+ while (parentIndex >= 0) {
5974
+ const parentRaw = (_a = lines[parentIndex]) != null ? _a : "";
5975
+ const parentTrimmed = parentRaw.trim();
5976
+ if (parentTrimmed.length === 0 || parentTrimmed.startsWith("#")) {
5977
+ parentIndex -= 1;
5978
+ continue;
5979
+ }
5980
+ const parentIndent = parentRaw.length - parentRaw.trimStart().length;
5981
+ if (parentIndent >= indent) {
5982
+ parentIndex -= 1;
5983
+ continue;
5984
+ }
5985
+ if (!parentTrimmed.endsWith(":")) {
5986
+ return false;
5987
+ }
5988
+ if (BLOCK_SCALAR_KEY_RE.test(parentTrimmed)) {
5989
+ return false;
5990
+ }
5991
+ return true;
5992
+ }
5993
+ return false;
5994
+ }
5995
+ function extractTrailingPlainScalarValue(line) {
5996
+ var _a;
5997
+ if (BLOCK_SCALAR_KEY_RE.test(line)) {
5998
+ return null;
5999
+ }
6000
+ const mappingMatch = line.match(PLAIN_MAPPING_VALUE_RE);
6001
+ const sequenceMatch = line.match(PLAIN_SEQUENCE_VALUE_RE);
6002
+ const value = (_a = mappingMatch == null ? void 0 : mappingMatch[1]) != null ? _a : sequenceMatch == null ? void 0 : sequenceMatch[1];
6003
+ if (!value) {
6004
+ return null;
6005
+ }
6006
+ const trimmedValue = value.trim();
6007
+ if (trimmedValue.length === 0) {
6008
+ return null;
6009
+ }
6010
+ if (trimmedValue.startsWith('"') || trimmedValue.startsWith("'")) {
6011
+ return null;
6012
+ }
6013
+ if (trimmedValue.startsWith("{") || trimmedValue.startsWith("[") || trimmedValue.startsWith("|") || trimmedValue.startsWith(">")) {
6014
+ return null;
6015
+ }
6016
+ return trimmedValue;
6017
+ }
6018
+ function hasUnterminatedPlainScalarTail(normalized) {
6019
+ if (normalized.endsWith("\n")) {
6020
+ return false;
6021
+ }
6022
+ const lineInfo = getLastMeaningfulLineInfo(normalized);
6023
+ if (!lineInfo) {
6024
+ return false;
6025
+ }
6026
+ return extractTrailingPlainScalarValue(lineInfo.trimmed) != null;
6027
+ }
6028
+ function hasUnstableProgressTail(normalized) {
6029
+ return hasIncompleteMappingTail(normalized) || hasIncompleteSequenceTail(normalized) || hasSplitNestedKeyTail(normalized) || hasUnterminatedPlainScalarTail(normalized);
6030
+ }
6031
+ function trimTrailingNewlineInUnknown(value) {
6032
+ if (typeof value === "string") {
6033
+ if (value.endsWith("\n")) {
6034
+ return value.slice(0, -1);
6035
+ }
6036
+ return value;
6037
+ }
6038
+ if (Array.isArray(value)) {
6039
+ return value.map((item) => trimTrailingNewlineInUnknown(item));
6040
+ }
6041
+ if (value && typeof value === "object") {
6042
+ return Object.fromEntries(
6043
+ Object.entries(value).map(([key, item]) => [
6044
+ key,
6045
+ trimTrailingNewlineInUnknown(item)
6046
+ ])
6047
+ );
6048
+ }
6049
+ return value;
6050
+ }
6051
+ function stabilizeParsedValueForStreamProgress(value, source) {
6052
+ if (source.endsWith("\n")) {
6053
+ return value;
6054
+ }
6055
+ return trimTrailingNewlineInUnknown(value);
6056
+ }
4479
6057
  function findClosingTagEnd(text, contentStart, toolName) {
4480
6058
  let pos = contentStart;
4481
6059
  let depth = 1;
@@ -4491,7 +6069,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4491
6069
  break;
4492
6070
  }
4493
6071
  let p = ltIdx + 2;
4494
- while (p < gtIdx && WHITESPACE_REGEX4.test(text[p])) {
6072
+ while (p < gtIdx && WHITESPACE_REGEX5.test(text[p])) {
4495
6073
  p++;
4496
6074
  }
4497
6075
  const nameStart = p;
@@ -4511,7 +6089,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4511
6089
  pos = gtIdx === -1 ? text.length : gtIdx + 1;
4512
6090
  } else {
4513
6091
  let p = ltIdx + 1;
4514
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
6092
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
4515
6093
  p++;
4516
6094
  }
4517
6095
  const nameStart = p;
@@ -4524,7 +6102,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4524
6102
  break;
4525
6103
  }
4526
6104
  let r = gtIdx - 1;
4527
- while (r >= nameStart && WHITESPACE_REGEX4.test(text[r])) {
6105
+ while (r >= nameStart && WHITESPACE_REGEX5.test(text[r])) {
4528
6106
  r--;
4529
6107
  }
4530
6108
  const selfClosing = text[r] === "/";
@@ -4547,7 +6125,7 @@ function findEarliestTagPosition(openIdx, selfIdx) {
4547
6125
  function collectToolCallsForName(text, toolName) {
4548
6126
  const toolCalls = [];
4549
6127
  let searchIndex = 0;
4550
- const selfTagRegex = new RegExp(`<${toolName}\\s*/>`, "g");
6128
+ const selfTagRegex = getSelfClosingTagPattern2(toolName);
4551
6129
  while (searchIndex < text.length) {
4552
6130
  const startTag = `<${toolName}>`;
4553
6131
  const openIdx = text.indexOf(startTag, searchIndex);
@@ -4599,47 +6177,48 @@ function findToolCalls2(text, toolNames) {
4599
6177
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
4600
6178
  }
4601
6179
  function parseYamlContent(yamlContent, options) {
4602
- var _a, _b, _c;
4603
- let normalized = yamlContent;
4604
- if (normalized.startsWith("\n")) {
4605
- normalized = normalized.slice(1);
4606
- }
4607
- const lines = normalized.split("\n");
4608
- const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
6180
+ var _a, _b;
6181
+ const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
4609
6182
  if (nonEmptyLines.length === 0) {
4610
6183
  return {};
4611
6184
  }
4612
- const minIndent = Math.min(
4613
- ...nonEmptyLines.map((line) => {
4614
- const match = line.match(LEADING_WHITESPACE_RE);
4615
- return match ? match[1].length : 0;
4616
- })
4617
- );
4618
- if (minIndent > 0) {
4619
- normalized = lines.map((line) => line.slice(minIndent)).join("\n");
6185
+ const parsed = parseYamlDocumentAsMapping(normalized);
6186
+ if (parsed.errors.length > 0) {
6187
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "YAML parse error", {
6188
+ errors: parsed.errors
6189
+ });
6190
+ return null;
4620
6191
  }
4621
- try {
4622
- const doc = import_yaml.default.parseDocument(normalized);
4623
- if (doc.errors && doc.errors.length > 0) {
4624
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "YAML parse error", {
4625
- errors: doc.errors.map((e) => e.message)
4626
- });
4627
- return null;
6192
+ if (parsed.value === null) {
6193
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "YAML content must be a key-value mapping", {
6194
+ got: "non-mapping"
6195
+ });
6196
+ return null;
6197
+ }
6198
+ return parsed.value;
6199
+ }
6200
+ function parseYamlContentForStreamProgress(yamlContent) {
6201
+ const { normalized, nonEmptyLines } = normalizeYamlContent(yamlContent);
6202
+ if (nonEmptyLines.length === 0) {
6203
+ return {};
6204
+ }
6205
+ let candidate = normalized;
6206
+ while (true) {
6207
+ const parsed = parseYamlDocumentAsMapping(candidate);
6208
+ if (parsed.errors.length === 0 && !hasUnstableProgressTail(candidate)) {
6209
+ if (candidate.trim().length === 0 && normalized.trim().length > 0) {
6210
+ return null;
6211
+ }
6212
+ return stabilizeParsedValueForStreamProgress(parsed.value, candidate);
4628
6213
  }
4629
- const result = doc.toJSON();
4630
- if (result === null) {
4631
- return {};
6214
+ const truncated = dropLastMeaningfulLine(candidate);
6215
+ if (truncated == null) {
6216
+ return null;
4632
6217
  }
4633
- if (typeof result !== "object" || Array.isArray(result)) {
4634
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(options, "YAML content must be a key-value mapping", {
4635
- got: typeof result
4636
- });
6218
+ if (truncated === candidate) {
4637
6219
  return null;
4638
6220
  }
4639
- return result;
4640
- } catch (error) {
4641
- (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(options, "Failed to parse YAML content", { error });
4642
- return null;
6221
+ candidate = truncated;
4643
6222
  }
4644
6223
  }
4645
6224
  function processToolCallMatch(text, tc, currentIndex, processedElements, options) {
@@ -4655,7 +6234,7 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
4655
6234
  if (parsedArgs !== null) {
4656
6235
  processedElements.push({
4657
6236
  type: "tool-call",
4658
- toolCallId: generateId(),
6237
+ toolCallId: generateToolCallId(),
4659
6238
  toolName: tc.toolName,
4660
6239
  input: JSON.stringify(parsedArgs)
4661
6240
  });
@@ -4668,38 +6247,6 @@ function processToolCallMatch(text, tc, currentIndex, processedElements, options
4668
6247
  }
4669
6248
  return tc.endIndex;
4670
6249
  }
4671
- function createFlushTextHandler2(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
4672
- return (controller, text) => {
4673
- const content = text;
4674
- if (content) {
4675
- if (!getCurrentTextId()) {
4676
- const newId = generateId();
4677
- setCurrentTextId(newId);
4678
- controller.enqueue({
4679
- type: "text-start",
4680
- id: newId
4681
- });
4682
- setHasEmittedTextStart(true);
4683
- }
4684
- controller.enqueue({
4685
- type: "text-delta",
4686
- id: getCurrentTextId(),
4687
- delta: content
4688
- });
4689
- }
4690
- const currentTextId = getCurrentTextId();
4691
- if (currentTextId && !text) {
4692
- if (getHasEmittedTextStart()) {
4693
- controller.enqueue({
4694
- type: "text-end",
4695
- id: currentTextId
4696
- });
4697
- setHasEmittedTextStart(false);
4698
- }
4699
- setCurrentTextId(null);
4700
- }
4701
- };
4702
- }
4703
6250
  function findEarliestToolTag2(buffer, toolNames) {
4704
6251
  let bestIndex = -1;
4705
6252
  let bestName = "";
@@ -4707,8 +6254,9 @@ function findEarliestToolTag2(buffer, toolNames) {
4707
6254
  let bestTagLength = 0;
4708
6255
  for (const name of toolNames) {
4709
6256
  const openTag = `<${name}>`;
4710
- const selfTagRegex = new RegExp(`<${name}\\s*/>`);
6257
+ const selfTagRegex = getSelfClosingTagPattern2(name);
4711
6258
  const idxOpen = buffer.indexOf(openTag);
6259
+ selfTagRegex.lastIndex = 0;
4712
6260
  const selfMatch = selfTagRegex.exec(buffer);
4713
6261
  const idxSelf = selfMatch ? selfMatch.index : -1;
4714
6262
  if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
@@ -4731,6 +6279,29 @@ function findEarliestToolTag2(buffer, toolNames) {
4731
6279
  tagLength: bestTagLength
4732
6280
  };
4733
6281
  }
6282
+ function stripTrailingPartialCloseTag(content, toolName) {
6283
+ const closeTag = `</${toolName}>`;
6284
+ const lastLineBreakIndex = Math.max(
6285
+ content.lastIndexOf("\n"),
6286
+ content.lastIndexOf("\r")
6287
+ );
6288
+ const lineStartIndex = lastLineBreakIndex === -1 ? 0 : lastLineBreakIndex + 1;
6289
+ const trailingLine = content.slice(lineStartIndex);
6290
+ const trimmedTrailingLine = trailingLine.trim();
6291
+ if (trimmedTrailingLine.length === 0 || !trimmedTrailingLine.startsWith("</") || trimmedTrailingLine === closeTag || !closeTag.startsWith(trimmedTrailingLine)) {
6292
+ return content;
6293
+ }
6294
+ const leadingWhitespaceLength = trailingLine.length - trailingLine.trimStart().length;
6295
+ const preservedLeadingWhitespace = trailingLine.slice(
6296
+ 0,
6297
+ leadingWhitespaceLength
6298
+ );
6299
+ const contentWithoutPartial = `${content.slice(
6300
+ 0,
6301
+ lineStartIndex
6302
+ )}${preservedLeadingWhitespace}`;
6303
+ return contentWithoutPartial.trimEnd();
6304
+ }
4734
6305
  var yamlProtocol = (_protocolOptions) => {
4735
6306
  return {
4736
6307
  formatTools({ tools, toolSystemPromptTemplate }) {
@@ -4756,18 +6327,32 @@ ${yamlContent}</${toolCall.toolName}>`;
4756
6327
  }
4757
6328
  const processedElements = [];
4758
6329
  let currentIndex = 0;
4759
- const toolCalls = findToolCalls2(text, toolNames);
6330
+ let parseText = text;
6331
+ let toolCalls = findToolCalls2(parseText, toolNames);
6332
+ if (toolCalls.length === 0) {
6333
+ const repaired = tryRepairXmlSelfClosingRootWithBody(
6334
+ parseText,
6335
+ toolNames
6336
+ );
6337
+ if (repaired) {
6338
+ const repairedCalls = findToolCalls2(repaired, toolNames);
6339
+ if (repairedCalls.length > 0) {
6340
+ parseText = repaired;
6341
+ toolCalls = repairedCalls;
6342
+ }
6343
+ }
6344
+ }
4760
6345
  for (const tc of toolCalls) {
4761
6346
  currentIndex = processToolCallMatch(
4762
- text,
6347
+ parseText,
4763
6348
  tc,
4764
6349
  currentIndex,
4765
6350
  processedElements,
4766
6351
  options
4767
6352
  );
4768
6353
  }
4769
- if (currentIndex < text.length) {
4770
- addTextSegment(text.substring(currentIndex), processedElements);
6354
+ if (currentIndex < parseText.length) {
6355
+ addTextSegment(parseText.substring(currentIndex), processedElements);
4771
6356
  }
4772
6357
  return processedElements;
4773
6358
  },
@@ -4777,7 +6362,7 @@ ${yamlContent}</${toolCall.toolName}>`;
4777
6362
  let currentToolCall = null;
4778
6363
  let currentTextId = null;
4779
6364
  let hasEmittedTextStart = false;
4780
- const flushText = createFlushTextHandler2(
6365
+ const flushText = createFlushTextHandler(
4781
6366
  () => currentTextId,
4782
6367
  (newId) => {
4783
6368
  currentTextId = newId;
@@ -4787,33 +6372,128 @@ ${yamlContent}</${toolCall.toolName}>`;
4787
6372
  hasEmittedTextStart = value;
4788
6373
  }
4789
6374
  );
4790
- const processToolCallEnd = (controller, toolContent, toolName) => {
6375
+ const emitToolInputProgress2 = (controller, toolContent) => {
6376
+ if (!currentToolCall) {
6377
+ return;
6378
+ }
6379
+ const parsedArgs = parseYamlContentForStreamProgress(toolContent);
6380
+ if (parsedArgs === null) {
6381
+ return;
6382
+ }
6383
+ const fullInput = JSON.stringify(parsedArgs);
6384
+ if (fullInput === "{}" && toolContent.trim().length === 0) {
6385
+ return;
6386
+ }
6387
+ const prefixCandidate = toIncompleteJsonPrefix(fullInput);
6388
+ emitPrefixDelta({
6389
+ controller,
6390
+ id: currentToolCall.toolCallId,
6391
+ state: currentToolCall,
6392
+ candidate: prefixCandidate
6393
+ });
6394
+ };
6395
+ const processToolCallEnd = (controller, toolContent, toolName, toolCallId) => {
4791
6396
  var _a;
4792
6397
  const parsedArgs = parseYamlContent(toolContent, options);
4793
6398
  flushText(controller);
4794
6399
  if (parsedArgs !== null) {
6400
+ const finalInput = JSON.stringify(parsedArgs);
6401
+ if (currentToolCall && currentToolCall.toolCallId === toolCallId) {
6402
+ emitFinalRemainder({
6403
+ controller,
6404
+ id: toolCallId,
6405
+ state: currentToolCall,
6406
+ finalFullJson: finalInput,
6407
+ onMismatch: options == null ? void 0 : options.onError
6408
+ });
6409
+ }
6410
+ controller.enqueue({
6411
+ type: "tool-input-end",
6412
+ id: toolCallId
6413
+ });
4795
6414
  controller.enqueue({
4796
6415
  type: "tool-call",
4797
- toolCallId: generateId(),
6416
+ toolCallId,
4798
6417
  toolName,
4799
- input: JSON.stringify(parsedArgs)
6418
+ input: finalInput
4800
6419
  });
4801
6420
  } else {
6421
+ controller.enqueue({
6422
+ type: "tool-input-end",
6423
+ id: toolCallId
6424
+ });
4802
6425
  const original = `<${toolName}>${toolContent}</${toolName}>`;
4803
6426
  (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Could not parse streaming YAML tool call", {
4804
6427
  toolCall: original
4805
6428
  });
4806
- flushText(controller, original);
6429
+ if (shouldEmitRawToolCallTextOnError3(options)) {
6430
+ flushText(controller, original);
6431
+ }
6432
+ }
6433
+ };
6434
+ const finalizeUnclosedToolCall = (controller) => {
6435
+ var _a;
6436
+ if (!currentToolCall) {
6437
+ return;
4807
6438
  }
6439
+ emitToolInputProgress2(controller, buffer);
6440
+ const { name: toolName, toolCallId } = currentToolCall;
6441
+ const reconciledBuffer = stripTrailingPartialCloseTag(buffer, toolName);
6442
+ const parsedArgs = parseYamlContent(reconciledBuffer, options);
6443
+ flushText(controller);
6444
+ if (parsedArgs !== null) {
6445
+ const finalInput = JSON.stringify(parsedArgs);
6446
+ emitFinalRemainder({
6447
+ controller,
6448
+ id: toolCallId,
6449
+ state: currentToolCall,
6450
+ finalFullJson: finalInput,
6451
+ onMismatch: options == null ? void 0 : options.onError
6452
+ });
6453
+ controller.enqueue({
6454
+ type: "tool-input-end",
6455
+ id: toolCallId
6456
+ });
6457
+ controller.enqueue({
6458
+ type: "tool-call",
6459
+ toolCallId,
6460
+ toolName,
6461
+ input: finalInput
6462
+ });
6463
+ } else {
6464
+ controller.enqueue({
6465
+ type: "tool-input-end",
6466
+ id: toolCallId
6467
+ });
6468
+ const unfinishedContent = `<${toolName}>${buffer}`;
6469
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
6470
+ options,
6471
+ "Could not complete streaming YAML tool call at finish.",
6472
+ { toolCall: unfinishedContent }
6473
+ );
6474
+ if (shouldEmitRawToolCallTextOnError3(options)) {
6475
+ flushText(controller, unfinishedContent);
6476
+ }
6477
+ }
6478
+ buffer = "";
6479
+ currentToolCall = null;
4808
6480
  };
4809
6481
  const handlePendingToolCall = (controller, endTag, toolName) => {
6482
+ var _a;
4810
6483
  const endIdx = buffer.indexOf(endTag);
4811
6484
  if (endIdx === -1) {
6485
+ emitToolInputProgress2(controller, buffer);
4812
6486
  return false;
4813
6487
  }
4814
6488
  const content = buffer.substring(0, endIdx);
6489
+ emitToolInputProgress2(controller, content);
4815
6490
  buffer = buffer.substring(endIdx + endTag.length);
4816
- processToolCallEnd(controller, content, toolName);
6491
+ processToolCallEnd(
6492
+ controller,
6493
+ content,
6494
+ toolName,
6495
+ (_a = currentToolCall == null ? void 0 : currentToolCall.toolCallId) != null ? _a : generateToolCallId()
6496
+ );
4817
6497
  currentToolCall = null;
4818
6498
  return true;
4819
6499
  };
@@ -4830,13 +6510,35 @@ ${yamlContent}</${toolCall.toolName}>`;
4830
6510
  if (tagIndex > 0) {
4831
6511
  flushText(controller, buffer.substring(0, tagIndex));
4832
6512
  }
6513
+ flushText(controller);
4833
6514
  if (selfClosing) {
4834
6515
  buffer = buffer.substring(tagIndex + tagLength);
4835
- processToolCallEnd(controller, "", tagName);
6516
+ const toolCallId = generateToolCallId();
6517
+ currentToolCall = {
6518
+ name: tagName,
6519
+ toolCallId,
6520
+ emittedInput: ""
6521
+ };
6522
+ controller.enqueue({
6523
+ type: "tool-input-start",
6524
+ id: toolCallId,
6525
+ toolName: tagName
6526
+ });
6527
+ processToolCallEnd(controller, "", tagName, toolCallId);
6528
+ currentToolCall = null;
4836
6529
  } else {
4837
6530
  const startTag = `<${tagName}>`;
4838
6531
  buffer = buffer.substring(tagIndex + startTag.length);
4839
- currentToolCall = { name: tagName, content: "" };
6532
+ currentToolCall = {
6533
+ name: tagName,
6534
+ toolCallId: generateToolCallId(),
6535
+ emittedInput: ""
6536
+ };
6537
+ controller.enqueue({
6538
+ type: "tool-input-start",
6539
+ id: currentToolCall.toolCallId,
6540
+ toolName: tagName
6541
+ });
4840
6542
  }
4841
6543
  };
4842
6544
  const processBuffer = (controller) => {
@@ -4863,8 +6565,19 @@ ${yamlContent}</${toolCall.toolName}>`;
4863
6565
  return new TransformStream({
4864
6566
  transform(chunk, controller) {
4865
6567
  var _a;
6568
+ if (chunk.type === "finish") {
6569
+ if (currentToolCall) {
6570
+ finalizeUnclosedToolCall(controller);
6571
+ } else if (buffer) {
6572
+ flushText(controller, buffer);
6573
+ buffer = "";
6574
+ }
6575
+ flushText(controller);
6576
+ controller.enqueue(chunk);
6577
+ return;
6578
+ }
4866
6579
  if (chunk.type !== "text-delta") {
4867
- if (buffer) {
6580
+ if (!currentToolCall && buffer) {
4868
6581
  flushText(controller, buffer);
4869
6582
  buffer = "";
4870
6583
  }
@@ -4877,10 +6590,7 @@ ${yamlContent}</${toolCall.toolName}>`;
4877
6590
  },
4878
6591
  flush(controller) {
4879
6592
  if (currentToolCall) {
4880
- const unfinishedContent = `<${currentToolCall.name}>${buffer}`;
4881
- flushText(controller, unfinishedContent);
4882
- buffer = "";
4883
- currentToolCall = null;
6593
+ finalizeUnclosedToolCall(controller);
4884
6594
  } else if (buffer) {
4885
6595
  flushText(controller, buffer);
4886
6596
  buffer = "";
@@ -4986,17 +6696,56 @@ function encodeOriginalTools(tools) {
4986
6696
  inputSchema: JSON.stringify(t.inputSchema)
4987
6697
  }))) || [];
4988
6698
  }
4989
- function decodeOriginalTools(originalTools) {
6699
+ function decodeOriginalTools(originalTools, options) {
6700
+ var _a, _b, _c;
4990
6701
  if (!originalTools) {
4991
6702
  return [];
4992
6703
  }
4993
- return originalTools.map(
4994
- (t) => ({
4995
- type: "function",
4996
- name: t.name,
4997
- inputSchema: JSON.parse(t.inputSchema)
4998
- })
4999
- );
6704
+ const decodedTools = [];
6705
+ for (const [index, tool] of originalTools.entries()) {
6706
+ if (!tool || typeof tool.name !== "string") {
6707
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Invalid originalTools entry: missing tool name", {
6708
+ index,
6709
+ tool
6710
+ });
6711
+ continue;
6712
+ }
6713
+ if (typeof tool.inputSchema !== "string") {
6714
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
6715
+ options,
6716
+ "Invalid originalTools entry: inputSchema must be a string",
6717
+ {
6718
+ index,
6719
+ toolName: tool.name
6720
+ }
6721
+ );
6722
+ continue;
6723
+ }
6724
+ try {
6725
+ decodedTools.push({
6726
+ type: "function",
6727
+ name: tool.name,
6728
+ inputSchema: JSON.parse(tool.inputSchema)
6729
+ });
6730
+ } catch (error) {
6731
+ (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(
6732
+ options,
6733
+ "Failed to decode originalTools input schema, using permissive fallback schema",
6734
+ {
6735
+ index,
6736
+ toolName: tool.name,
6737
+ inputSchema: tool.inputSchema,
6738
+ error: error instanceof Error ? error.message : String(error)
6739
+ }
6740
+ );
6741
+ decodedTools.push({
6742
+ type: "function",
6743
+ name: tool.name,
6744
+ inputSchema: { type: "object" }
6745
+ });
6746
+ }
6747
+ }
6748
+ return decodedTools;
5000
6749
  }
5001
6750
  function isToolChoiceActive(params) {
5002
6751
  var _a, _b, _c;
@@ -5004,25 +6753,336 @@ function isToolChoiceActive(params) {
5004
6753
  return !!(typeof params.providerOptions === "object" && params.providerOptions !== null && typeof ((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) === "object" && toolChoice && typeof toolChoice === "object" && (toolChoice.type === "tool" || toolChoice.type === "required"));
5005
6754
  }
5006
6755
 
5007
- // src/generate-handler.ts
5008
- var import_provider_utils = require("@ai-sdk/provider-utils");
5009
- function parseToolChoiceJson(text, providerOptions) {
6756
+ // src/core/utils/generated-text-json-recovery.ts
6757
+ function isRecord(value) {
6758
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6759
+ }
6760
+ function safeStringify2(value) {
6761
+ try {
6762
+ return JSON.stringify(value != null ? value : {});
6763
+ } catch (e) {
6764
+ return "{}";
6765
+ }
6766
+ }
6767
+ function parseJsonCandidate(candidateText) {
6768
+ try {
6769
+ return parse(candidateText);
6770
+ } catch (e) {
6771
+ return void 0;
6772
+ }
6773
+ }
6774
+ function extractCodeBlockCandidates(text) {
6775
+ var _a, _b;
6776
+ const codeBlockRegex = /```(?:json|yaml|xml)?\s*([\s\S]*?)```/gi;
6777
+ const candidates = [];
6778
+ let match;
6779
+ while (true) {
6780
+ match = codeBlockRegex.exec(text);
6781
+ if (!match) {
6782
+ break;
6783
+ }
6784
+ const body = (_a = match[1]) == null ? void 0 : _a.trim();
6785
+ if (body) {
6786
+ const startIndex = (_b = match.index) != null ? _b : 0;
6787
+ const endIndex = startIndex + match[0].length;
6788
+ candidates.push({
6789
+ text: body,
6790
+ startIndex,
6791
+ endIndex
6792
+ });
6793
+ }
6794
+ }
6795
+ return candidates;
6796
+ }
6797
+ function scanJsonChar(state, char) {
6798
+ if (state.inString) {
6799
+ if (state.escaping) {
6800
+ return { ...state, escaping: false };
6801
+ }
6802
+ if (char === "\\") {
6803
+ return { ...state, escaping: true };
6804
+ }
6805
+ if (char === '"') {
6806
+ return { ...state, inString: false };
6807
+ }
6808
+ return state;
6809
+ }
6810
+ if (char === '"') {
6811
+ return { ...state, inString: true };
6812
+ }
6813
+ if (char === "{") {
6814
+ return { ...state, depth: state.depth + 1 };
6815
+ }
6816
+ if (char === "}") {
6817
+ return { ...state, depth: Math.max(0, state.depth - 1) };
6818
+ }
6819
+ return state;
6820
+ }
6821
+ function extractBalancedJsonObjects(text) {
6822
+ const maxCandidateLength = 1e4;
6823
+ const candidates = [];
6824
+ let state = { depth: 0, inString: false, escaping: false };
6825
+ let currentStart = null;
6826
+ let ignoreCurrent = false;
6827
+ for (let index = 0; index < text.length; index += 1) {
6828
+ const char = text[index];
6829
+ if (!state.inString && char === "{" && state.depth === 0) {
6830
+ currentStart = index;
6831
+ ignoreCurrent = false;
6832
+ }
6833
+ state = scanJsonChar(state, char);
6834
+ if (currentStart !== null && !ignoreCurrent && index - currentStart + 1 > maxCandidateLength) {
6835
+ ignoreCurrent = true;
6836
+ }
6837
+ if (!state.inString && char === "}" && state.depth === 0) {
6838
+ if (currentStart !== null && !ignoreCurrent) {
6839
+ const endIndex = index + 1;
6840
+ const candidate = text.slice(currentStart, endIndex);
6841
+ if (candidate.length > 1) {
6842
+ candidates.push({
6843
+ text: candidate,
6844
+ startIndex: currentStart,
6845
+ endIndex
6846
+ });
6847
+ }
6848
+ }
6849
+ currentStart = null;
6850
+ ignoreCurrent = false;
6851
+ }
6852
+ }
6853
+ return candidates;
6854
+ }
6855
+ function extractTaggedToolCallCandidates(rawText) {
6856
+ var _a, _b;
6857
+ const toolCallRegex = /<tool_call>([\s\S]*?)<\/tool_call>/gi;
6858
+ const candidates = [];
6859
+ let match;
6860
+ while (true) {
6861
+ match = toolCallRegex.exec(rawText);
6862
+ if (!match) {
6863
+ break;
6864
+ }
6865
+ const body = (_a = match[1]) == null ? void 0 : _a.trim();
6866
+ if (!body) {
6867
+ continue;
6868
+ }
6869
+ const startIndex = (_b = match.index) != null ? _b : 0;
6870
+ const endIndex = startIndex + match[0].length;
6871
+ candidates.push({
6872
+ text: body,
6873
+ startIndex,
6874
+ endIndex
6875
+ });
6876
+ }
6877
+ return candidates;
6878
+ }
6879
+ function extractJsonLikeCandidates(rawText) {
6880
+ return mergeJsonCandidatesByStart(
6881
+ extractTaggedToolCallCandidates(rawText),
6882
+ extractCodeBlockCandidates(rawText),
6883
+ extractBalancedJsonObjects(rawText)
6884
+ );
6885
+ }
6886
+ function mergeJsonCandidatesByStart(tagged, codeBlocks, balanced) {
6887
+ return [...tagged, ...codeBlocks, ...balanced].sort(
6888
+ (a, b) => a.startIndex !== b.startIndex ? a.startIndex - b.startIndex : b.endIndex - a.endIndex
6889
+ );
6890
+ }
6891
+ function toToolCallPart(candidate) {
6892
+ return {
6893
+ type: "tool-call",
6894
+ toolCallId: generateToolCallId(),
6895
+ toolName: candidate.toolName,
6896
+ input: candidate.input
6897
+ };
6898
+ }
6899
+ function toRecoveredParts(text, candidate, toolCallPart) {
6900
+ const out = [];
6901
+ const prefix = text.slice(0, candidate.startIndex);
6902
+ if (prefix.length > 0) {
6903
+ out.push({ type: "text", text: prefix });
6904
+ }
6905
+ out.push(toolCallPart);
6906
+ const suffix = text.slice(candidate.endIndex);
6907
+ if (suffix.length > 0) {
6908
+ out.push({ type: "text", text: suffix });
6909
+ }
6910
+ return out;
6911
+ }
6912
+ function parseAsToolPayload(payload, tools) {
6913
+ if (!isRecord(payload)) {
6914
+ return null;
6915
+ }
6916
+ const toolName = typeof payload.name === "string" && payload.name.trim().length > 0 ? payload.name.trim() : null;
6917
+ if (!toolName) {
6918
+ return null;
6919
+ }
6920
+ if (!tools.some((tool) => tool.name === toolName)) {
6921
+ return null;
6922
+ }
6923
+ const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
6924
+ if (!isRecord(rawArgs)) {
6925
+ return null;
6926
+ }
6927
+ return {
6928
+ toolName,
6929
+ input: safeStringify2(rawArgs)
6930
+ };
6931
+ }
6932
+ function isLikelyArgumentsShapeForTool(args, tool) {
6933
+ const unwrapped = unwrapJsonSchema(tool.inputSchema);
6934
+ if (!isRecord(unwrapped)) {
6935
+ return false;
6936
+ }
6937
+ if (getSchemaType(unwrapped) !== "object") {
6938
+ return false;
6939
+ }
6940
+ const properties = unwrapped.properties;
6941
+ if (!isRecord(properties)) {
6942
+ return false;
6943
+ }
6944
+ const keys = Object.keys(args);
6945
+ if (keys.length === 0) {
6946
+ return false;
6947
+ }
6948
+ const knownKeys = keys.filter((key) => Object.hasOwn(properties, key));
6949
+ if (knownKeys.length === 0) {
6950
+ return false;
6951
+ }
6952
+ if (unwrapped.additionalProperties === false && knownKeys.length !== keys.length) {
6953
+ return false;
6954
+ }
6955
+ return true;
6956
+ }
6957
+ function parseAsArgumentsOnly(payload, tools) {
6958
+ if (tools.length !== 1) {
6959
+ return null;
6960
+ }
6961
+ if (!isRecord(payload)) {
6962
+ return null;
6963
+ }
6964
+ const hasNameEnvelope = Object.hasOwn(payload, "name") && typeof payload.name === "string" && payload.name.length > 0;
6965
+ const hasArgumentsEnvelope = Object.hasOwn(payload, "arguments") && (typeof payload.arguments === "string" || isRecord(payload.arguments));
6966
+ if (hasNameEnvelope || hasArgumentsEnvelope) {
6967
+ return null;
6968
+ }
6969
+ const tool = tools[0];
6970
+ if (!isLikelyArgumentsShapeForTool(payload, tool)) {
6971
+ return null;
6972
+ }
6973
+ return {
6974
+ toolName: tool.name,
6975
+ input: safeStringify2(payload)
6976
+ };
6977
+ }
6978
+ function recoverToolCallFromJsonCandidates(text, tools) {
6979
+ if (tools.length === 0) {
6980
+ return null;
6981
+ }
6982
+ const jsonCandidates = extractJsonLikeCandidates(text);
6983
+ for (const jsonCandidate of jsonCandidates) {
6984
+ const parsed = parseJsonCandidate(jsonCandidate.text);
6985
+ if (parsed === void 0) {
6986
+ continue;
6987
+ }
6988
+ const toolPayload = parseAsToolPayload(parsed, tools);
6989
+ if (toolPayload) {
6990
+ return toRecoveredParts(text, jsonCandidate, toToolCallPart(toolPayload));
6991
+ }
6992
+ const argsPayload = parseAsArgumentsOnly(parsed, tools);
6993
+ if (argsPayload) {
6994
+ return toRecoveredParts(text, jsonCandidate, toToolCallPart(argsPayload));
6995
+ }
6996
+ }
6997
+ return null;
6998
+ }
6999
+
7000
+ // src/core/utils/tool-call-coercion.ts
7001
+ function coerceToolCallInput(toolName, input, tools) {
5010
7002
  var _a;
7003
+ let args = {};
7004
+ if (typeof input === "string") {
7005
+ try {
7006
+ args = JSON.parse(input);
7007
+ } catch (e) {
7008
+ return;
7009
+ }
7010
+ } else if (input && typeof input === "object") {
7011
+ args = input;
7012
+ } else {
7013
+ return;
7014
+ }
7015
+ const schema = (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
7016
+ const coerced = coerceBySchema(args, schema);
7017
+ return JSON.stringify(coerced != null ? coerced : {});
7018
+ }
7019
+ function coerceToolCallPart(part, tools) {
7020
+ const coercedInput = coerceToolCallInput(part.toolName, part.input, tools);
7021
+ if (coercedInput === void 0) {
7022
+ return part;
7023
+ }
7024
+ return {
7025
+ ...part,
7026
+ input: coercedInput
7027
+ };
7028
+ }
7029
+
7030
+ // src/core/utils/tool-choice.ts
7031
+ function ensureNonEmptyToolName(name) {
7032
+ if (typeof name !== "string") {
7033
+ return "unknown";
7034
+ }
7035
+ const trimmed = name.trim();
7036
+ return trimmed.length > 0 ? trimmed : "unknown";
7037
+ }
7038
+ function safeStringify3(value) {
7039
+ try {
7040
+ return JSON.stringify(value != null ? value : {});
7041
+ } catch (e) {
7042
+ return "{}";
7043
+ }
7044
+ }
7045
+ function parseToolChoicePayload({
7046
+ text,
7047
+ tools,
7048
+ onError,
7049
+ errorMessage
7050
+ }) {
7051
+ let parsed;
5011
7052
  try {
5012
- return JSON.parse(text);
7053
+ parsed = JSON.parse(text);
5013
7054
  } catch (error) {
5014
- const options = extractOnErrorOption(providerOptions);
5015
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
5016
- options,
5017
- "Failed to parse toolChoice JSON from generated model output",
5018
- {
5019
- text,
5020
- error: error instanceof Error ? error.message : String(error)
5021
- }
5022
- );
5023
- return {};
7055
+ onError == null ? void 0 : onError(errorMessage, {
7056
+ text,
7057
+ error: error instanceof Error ? error.message : String(error)
7058
+ });
7059
+ return { toolName: "unknown", input: "{}" };
7060
+ }
7061
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
7062
+ onError == null ? void 0 : onError("toolChoice JSON payload must be an object", {
7063
+ parsedType: typeof parsed,
7064
+ parsed
7065
+ });
7066
+ return { toolName: "unknown", input: "{}" };
7067
+ }
7068
+ const payload = parsed;
7069
+ const toolName = ensureNonEmptyToolName(payload.name);
7070
+ const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
7071
+ if (rawArgs == null || typeof rawArgs !== "object" || Array.isArray(rawArgs)) {
7072
+ onError == null ? void 0 : onError("toolChoice arguments must be a JSON object", {
7073
+ toolName,
7074
+ arguments: rawArgs
7075
+ });
7076
+ return { toolName, input: "{}" };
5024
7077
  }
7078
+ const coercedInput = coerceToolCallInput(toolName, rawArgs, tools);
7079
+ return {
7080
+ toolName,
7081
+ input: coercedInput != null ? coercedInput : safeStringify3(rawArgs)
7082
+ };
5025
7083
  }
7084
+
7085
+ // src/generate-handler.ts
5026
7086
  function logDebugSummary(debugSummary, toolCall, originText) {
5027
7087
  if (debugSummary) {
5028
7088
  debugSummary.originalText = originText;
@@ -5036,25 +7096,34 @@ function logDebugSummary(debugSummary, toolCall, originText) {
5036
7096
  logParsedSummary({ toolCalls: [toolCall], originalText: originText });
5037
7097
  }
5038
7098
  }
5039
- async function handleToolChoice(doGenerate, params) {
5040
- var _a, _b, _c;
7099
+ async function handleToolChoice(doGenerate, params, tools) {
7100
+ var _a, _b, _c, _d;
5041
7101
  const result = await doGenerate();
5042
7102
  const first = (_a = result.content) == null ? void 0 : _a[0];
5043
- let parsed = {};
7103
+ const onError = (_b = extractOnErrorOption(params.providerOptions)) == null ? void 0 : _b.onError;
7104
+ let toolName = "unknown";
7105
+ let input = "{}";
5044
7106
  if (first && first.type === "text") {
5045
7107
  if (getDebugLevel() === "parse") {
5046
7108
  logRawChunk(first.text);
5047
7109
  }
5048
- parsed = parseToolChoiceJson(first.text, params.providerOptions);
7110
+ const parsed = parseToolChoicePayload({
7111
+ text: first.text,
7112
+ tools,
7113
+ onError,
7114
+ errorMessage: "Failed to parse toolChoice JSON from generated model output"
7115
+ });
7116
+ toolName = parsed.toolName;
7117
+ input = parsed.input;
5049
7118
  }
5050
7119
  const toolCall = {
5051
7120
  type: "tool-call",
5052
- toolCallId: (0, import_provider_utils.generateId)(),
5053
- toolName: parsed.name || "unknown",
5054
- input: JSON.stringify(parsed.arguments || {})
7121
+ toolCallId: generateToolCallId(),
7122
+ toolName,
7123
+ input
5055
7124
  };
5056
7125
  const originText = first && first.type === "text" ? first.text : "";
5057
- const debugSummary = (_c = (_b = params.providerOptions) == null ? void 0 : _b.toolCallMiddleware) == null ? void 0 : _c.debugSummary;
7126
+ const debugSummary = (_d = (_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) == null ? void 0 : _d.debugSummary;
5058
7127
  logDebugSummary(debugSummary, toolCall, originText);
5059
7128
  return {
5060
7129
  ...result,
@@ -5069,7 +7138,7 @@ function parseContent(content, protocol, tools, providerOptions) {
5069
7138
  if (getDebugLevel() === "stream") {
5070
7139
  logRawChunk(contentItem.text);
5071
7140
  }
5072
- return protocol.parseGeneratedText({
7141
+ const parsedByProtocol = protocol.parseGeneratedText({
5073
7142
  text: contentItem.text,
5074
7143
  tools,
5075
7144
  options: {
@@ -5077,9 +7146,20 @@ function parseContent(content, protocol, tools, providerOptions) {
5077
7146
  ...providerOptions == null ? void 0 : providerOptions.toolCallMiddleware
5078
7147
  }
5079
7148
  });
7149
+ const hasToolCall = parsedByProtocol.some(
7150
+ (part) => part.type === "tool-call"
7151
+ );
7152
+ if (hasToolCall) {
7153
+ return parsedByProtocol;
7154
+ }
7155
+ const recoveredFromJson = recoverToolCallFromJsonCandidates(
7156
+ contentItem.text,
7157
+ tools
7158
+ );
7159
+ return recoveredFromJson != null ? recoveredFromJson : parsedByProtocol;
5080
7160
  });
5081
7161
  return parsed.map(
5082
- (part) => fixToolCallWithSchema(part, tools)
7162
+ (part) => part.type === "tool-call" ? coerceToolCallPart(part, tools) : part
5083
7163
  );
5084
7164
  }
5085
7165
  function logParsedContent(content) {
@@ -5122,12 +7202,14 @@ async function wrapGenerate({
5122
7202
  params
5123
7203
  }) {
5124
7204
  var _a, _b;
5125
- if (isToolChoiceActive(params)) {
5126
- return handleToolChoice(doGenerate, params);
5127
- }
7205
+ const onError = extractOnErrorOption(params.providerOptions);
5128
7206
  const tools = originalToolsSchema.decode(
5129
- (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
7207
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
7208
+ onError
5130
7209
  );
7210
+ if (isToolChoiceActive(params)) {
7211
+ return handleToolChoice(doGenerate, params, tools);
7212
+ }
5131
7213
  const result = await doGenerate();
5132
7214
  if (result.content.length === 0) {
5133
7215
  return result;
@@ -5151,28 +7233,6 @@ async function wrapGenerate({
5151
7233
  content: newContent
5152
7234
  };
5153
7235
  }
5154
- function fixToolCallWithSchema(part, tools) {
5155
- var _a;
5156
- if (part.type !== "tool-call") {
5157
- return part;
5158
- }
5159
- let args = {};
5160
- if (typeof part.input === "string") {
5161
- try {
5162
- args = JSON.parse(part.input);
5163
- } catch (e) {
5164
- return part;
5165
- }
5166
- } else if (part.input && typeof part.input === "object") {
5167
- args = part.input;
5168
- }
5169
- const schema = (_a = tools.find((t) => t.name === part.toolName)) == null ? void 0 : _a.inputSchema;
5170
- const coerced = coerceBySchema(args, schema);
5171
- return {
5172
- ...part,
5173
- input: JSON.stringify(coerced != null ? coerced : {})
5174
- };
5175
- }
5176
7236
 
5177
7237
  // src/core/prompts/hermes-system-prompt.ts
5178
7238
  function hermesSystemPromptTemplate(tools) {
@@ -5568,7 +7628,6 @@ unit: celsius
5568
7628
  }
5569
7629
 
5570
7630
  // src/stream-handler.ts
5571
- var import_provider_utils2 = require("@ai-sdk/provider-utils");
5572
7631
  async function wrapStream({
5573
7632
  protocol,
5574
7633
  doStream,
@@ -5576,19 +7635,22 @@ async function wrapStream({
5576
7635
  params
5577
7636
  }) {
5578
7637
  var _a, _b, _c;
7638
+ const onErrorOptions = extractOnErrorOption(params.providerOptions);
7639
+ const tools = originalToolsSchema.decode(
7640
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
7641
+ onErrorOptions
7642
+ );
5579
7643
  if (isToolChoiceActive(params)) {
5580
7644
  return toolChoiceStream({
5581
7645
  doGenerate,
5582
- options: extractOnErrorOption(params.providerOptions)
7646
+ tools,
7647
+ options: onErrorOptions
5583
7648
  });
5584
7649
  }
5585
7650
  const { stream, ...rest } = await doStream();
5586
7651
  const debugLevel = getDebugLevel();
5587
- const tools = originalToolsSchema.decode(
5588
- (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
5589
- );
5590
7652
  const options = {
5591
- ...extractOnErrorOption(params.providerOptions),
7653
+ ...onErrorOptions,
5592
7654
  ...((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) || {}
5593
7655
  };
5594
7656
  const coreStream = stream.pipeThrough(
@@ -5603,13 +7665,26 @@ async function wrapStream({
5603
7665
  }
5604
7666
  )
5605
7667
  ).pipeThrough(protocol.createStreamParser({ tools, options }));
7668
+ let seenToolCall = false;
5606
7669
  const v3Stream = coreStream.pipeThrough(
5607
7670
  new TransformStream({
5608
7671
  transform(part, controller) {
7672
+ let normalizedPart = part.type === "tool-call" ? coerceToolCallPart(part, tools) : part;
7673
+ if (normalizedPart.type === "tool-call") {
7674
+ seenToolCall = true;
7675
+ }
7676
+ if (normalizedPart.type === "finish" && seenToolCall && normalizedPart.finishReason.unified === "stop") {
7677
+ normalizedPart = {
7678
+ ...normalizedPart,
7679
+ finishReason: normalizeToolCallsFinishReason(
7680
+ normalizedPart.finishReason
7681
+ )
7682
+ };
7683
+ }
5609
7684
  if (debugLevel === "stream") {
5610
- logParsedChunk(part);
7685
+ logParsedChunk(normalizedPart);
5611
7686
  }
5612
- controller.enqueue(part);
7687
+ controller.enqueue(normalizedPart);
5613
7688
  }
5614
7689
  })
5615
7690
  );
@@ -5620,41 +7695,36 @@ async function wrapStream({
5620
7695
  }
5621
7696
  async function toolChoiceStream({
5622
7697
  doGenerate,
7698
+ tools,
5623
7699
  options
5624
7700
  }) {
5625
- var _a, _b;
7701
+ var _a;
7702
+ const normalizedTools = Array.isArray(tools) ? tools : [];
5626
7703
  const result = await doGenerate();
5627
- let toolJson = {};
7704
+ let toolName = "unknown";
7705
+ let input = "{}";
5628
7706
  if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
5629
- try {
5630
- toolJson = JSON.parse(result.content[0].text);
5631
- } catch (error) {
5632
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5633
- options,
5634
- "Failed to parse toolChoice JSON from streamed model output",
5635
- {
5636
- text: result.content[0].text,
5637
- error: error instanceof Error ? error.message : String(error)
5638
- }
5639
- );
5640
- toolJson = {};
5641
- }
7707
+ const parsed = parseToolChoicePayload({
7708
+ text: result.content[0].text,
7709
+ tools: normalizedTools,
7710
+ onError: options == null ? void 0 : options.onError,
7711
+ errorMessage: "Failed to parse toolChoice JSON from streamed model output"
7712
+ });
7713
+ toolName = parsed.toolName;
7714
+ input = parsed.input;
5642
7715
  }
5643
7716
  const stream = new ReadableStream({
5644
7717
  start(controller) {
5645
7718
  controller.enqueue({
5646
7719
  type: "tool-call",
5647
- toolCallId: (0, import_provider_utils2.generateId)(),
5648
- toolName: toolJson.name || "unknown",
5649
- input: JSON.stringify(toolJson.arguments || {})
7720
+ toolCallId: generateToolCallId(),
7721
+ toolName,
7722
+ input
5650
7723
  });
5651
7724
  controller.enqueue({
5652
7725
  type: "finish",
5653
- usage: (result == null ? void 0 : result.usage) || {
5654
- inputTokens: 0,
5655
- outputTokens: 0
5656
- },
5657
- finishReason: "tool-calls"
7726
+ usage: normalizeUsage(result == null ? void 0 : result.usage),
7727
+ finishReason: normalizeToolCallsFinishReason(result == null ? void 0 : result.finishReason)
5658
7728
  });
5659
7729
  controller.close();
5660
7730
  }
@@ -5665,6 +7735,60 @@ async function toolChoiceStream({
5665
7735
  stream
5666
7736
  };
5667
7737
  }
7738
+ var ZERO_USAGE = {
7739
+ inputTokens: {
7740
+ total: 0,
7741
+ noCache: void 0,
7742
+ cacheRead: void 0,
7743
+ cacheWrite: void 0
7744
+ },
7745
+ outputTokens: {
7746
+ total: 0,
7747
+ text: void 0,
7748
+ reasoning: void 0
7749
+ }
7750
+ };
7751
+ function normalizeToolCallsFinishReason(finishReason) {
7752
+ let raw = "tool-calls";
7753
+ if (typeof finishReason === "string") {
7754
+ raw = finishReason;
7755
+ } else if (finishReason && typeof finishReason === "object" && "raw" in finishReason && typeof finishReason.raw === "string") {
7756
+ raw = finishReason.raw;
7757
+ } else if (finishReason && typeof finishReason === "object" && "unified" in finishReason && typeof finishReason.unified === "string") {
7758
+ raw = finishReason.unified;
7759
+ }
7760
+ return {
7761
+ unified: "tool-calls",
7762
+ raw
7763
+ };
7764
+ }
7765
+ function normalizeUsage(usage) {
7766
+ if (!usage || typeof usage !== "object") {
7767
+ return ZERO_USAGE;
7768
+ }
7769
+ const usageRecord = usage;
7770
+ const input = usageRecord.inputTokens;
7771
+ const output = usageRecord.outputTokens;
7772
+ if (input && typeof input === "object" && output && typeof output === "object") {
7773
+ return usage;
7774
+ }
7775
+ if (typeof input === "number" && typeof output === "number") {
7776
+ return {
7777
+ inputTokens: {
7778
+ total: input,
7779
+ noCache: void 0,
7780
+ cacheRead: void 0,
7781
+ cacheWrite: void 0
7782
+ },
7783
+ outputTokens: {
7784
+ total: output,
7785
+ text: void 0,
7786
+ reasoning: void 0
7787
+ }
7788
+ };
7789
+ }
7790
+ return ZERO_USAGE;
7791
+ }
5668
7792
 
5669
7793
  // src/transform-handler.ts
5670
7794
  function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
@@ -5790,6 +7914,11 @@ function handleToolChoiceRequired(params, baseReturnParams, functionTools) {
5790
7914
  "Tool choice type 'required' is set, but no tools are provided in params.tools."
5791
7915
  );
5792
7916
  }
7917
+ if (functionTools.length === 0) {
7918
+ throw new Error(
7919
+ "Tool choice type 'required' is set, but no function tools are provided. Provider-defined tools are not supported by this middleware."
7920
+ );
7921
+ }
5793
7922
  return {
5794
7923
  ...baseReturnParams,
5795
7924
  responseFormat: {