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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -20,11 +20,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
- RJSON: () => robust_json_exports,
23
+ applyHeuristicPipeline: () => applyHeuristicPipeline,
24
+ balanceTagsHeuristic: () => balanceTagsHeuristic,
24
25
  createDynamicIfThenElseSchema: () => createDynamicIfThenElseSchema,
26
+ createIntermediateCall: () => createIntermediateCall,
25
27
  createToolMiddleware: () => createToolMiddleware,
26
28
  decodeOriginalTools: () => decodeOriginalTools,
29
+ dedupeShellStringTagsHeuristic: () => dedupeShellStringTagsHeuristic,
30
+ defaultPipelineConfig: () => defaultPipelineConfig,
27
31
  encodeOriginalTools: () => encodeOriginalTools,
32
+ escapeInvalidLtHeuristic: () => escapeInvalidLtHeuristic,
28
33
  escapeRegExp: () => escapeRegExp,
29
34
  extractOnErrorOption: () => extractOnErrorOption,
30
35
  extractToolNamesFromOriginalTools: () => extractToolNamesFromOriginalTools,
@@ -37,23 +42,24 @@ __export(src_exports, {
37
42
  isToolChoiceActive: () => isToolChoiceActive,
38
43
  isToolResultPart: () => isToolResultPart,
39
44
  jsonMixProtocol: () => jsonMixProtocol,
45
+ logParseFailure: () => logParseFailure,
40
46
  logParsedChunk: () => logParsedChunk,
41
47
  logParsedSummary: () => logParsedSummary,
42
48
  logRawChunk: () => logRawChunk,
49
+ mergePipelineConfigs: () => mergePipelineConfigs,
43
50
  morphXmlProtocol: () => morphXmlProtocol,
44
51
  morphXmlToolMiddleware: () => morphXmlToolMiddleware,
52
+ normalizeCloseTagsHeuristic: () => normalizeCloseTagsHeuristic,
45
53
  originalToolsSchema: () => originalToolsSchema,
46
54
  parseRJSON: () => parse,
55
+ repairAgainstSchemaHeuristic: () => repairAgainstSchemaHeuristic,
47
56
  stringifyRJSON: () => stringify,
48
57
  transformRJSON: () => transform
49
58
  });
50
59
  module.exports = __toCommonJS(src_exports);
51
60
 
52
- // src/protocols/dummy-protocol.ts
53
- var import_provider_utils = require("@ai-sdk/provider-utils");
54
-
55
61
  // src/protocols/json-mix-protocol.ts
56
- var import_provider_utils2 = require("@ai-sdk/provider-utils");
62
+ var import_provider_utils = require("@ai-sdk/provider-utils");
57
63
 
58
64
  // src/utils/debug.ts
59
65
  var LINE_SPLIT_REGEX = /\r?\n/;
@@ -101,6 +107,7 @@ var cBgGreen = color(ANSI_BG_GREEN);
101
107
  var cInverse = color(ANSI_INVERSE);
102
108
  var cUnderline = color(ANSI_UNDERLINE);
103
109
  var cBold = color(ANSI_BOLD);
110
+ var MAX_SNIPPET_LENGTH = 800;
104
111
  function safeStringify(value) {
105
112
  try {
106
113
  return `
@@ -109,6 +116,41 @@ ${typeof value === "string" ? value : JSON.stringify(value, null, 2)}`;
109
116
  return String(value);
110
117
  }
111
118
  }
119
+ function formatError(error) {
120
+ if (error instanceof Error) {
121
+ const stack = error.stack ? `
122
+ ${error.stack}` : "";
123
+ return `
124
+ ${error.name}: ${error.message}${stack}`;
125
+ }
126
+ return safeStringify(error);
127
+ }
128
+ function truncateSnippet(snippet) {
129
+ if (snippet.length <= MAX_SNIPPET_LENGTH) {
130
+ return snippet;
131
+ }
132
+ return `${snippet.slice(0, MAX_SNIPPET_LENGTH)}
133
+ \u2026[truncated ${snippet.length - MAX_SNIPPET_LENGTH} chars]`;
134
+ }
135
+ function logParseFailure({
136
+ phase,
137
+ reason,
138
+ snippet,
139
+ error
140
+ }) {
141
+ if (getDebugLevel() !== "parse") {
142
+ return;
143
+ }
144
+ const label = cBgBlue(`[${phase}]`);
145
+ console.log(cGray("[debug:mw:fail]"), label, cYellow(reason));
146
+ if (snippet) {
147
+ const formatted = truncateSnippet(snippet);
148
+ console.log(cGray("[debug:mw:fail:snippet]"), formatted);
149
+ }
150
+ if (error) {
151
+ console.log(cGray("[debug:mw:fail:error]"), cCyan(formatError(error)));
152
+ }
153
+ }
112
154
  function logRawChunk(part) {
113
155
  console.log(cGray("[debug:mw:raw]"), cYellow(safeStringify(part)));
114
156
  }
@@ -174,63 +216,6 @@ ${rendered}`);
174
216
  }
175
217
  }
176
218
 
177
- // src/utils/dynamic-tool-schema.ts
178
- function createDynamicIfThenElseSchema(tools) {
179
- let currentSchema = {};
180
- const toolNames = [];
181
- for (let i = tools.length - 1; i >= 0; i -= 1) {
182
- const tool = tools[i];
183
- if (tool.type === "provider-defined") {
184
- throw new Error(
185
- "Provider-defined tools are not supported by this middleware. Please use custom tools."
186
- );
187
- }
188
- toolNames.unshift(tool.name);
189
- const toolCondition = {
190
- if: {
191
- properties: {
192
- name: {
193
- const: tool.name
194
- }
195
- },
196
- required: ["name"]
197
- },
198
- // biome-ignore lint/suspicious/noThenProperty: JSON Schema uses 'then' as a keyword
199
- then: {
200
- properties: {
201
- name: {
202
- const: tool.name
203
- },
204
- arguments: tool.inputSchema
205
- },
206
- required: ["name", "arguments"]
207
- }
208
- };
209
- if (Object.keys(currentSchema).length > 0) {
210
- toolCondition.else = currentSchema;
211
- }
212
- currentSchema = toolCondition;
213
- }
214
- return {
215
- type: "object",
216
- // Explicitly specify type as "object"
217
- properties: {
218
- name: {
219
- type: "string",
220
- description: "Name of the tool to call",
221
- enum: toolNames
222
- },
223
- arguments: {
224
- type: "object",
225
- // By default, arguments is also specified as object type
226
- description: "Argument object to be passed to the tool"
227
- }
228
- },
229
- required: ["name", "arguments"],
230
- ...currentSchema
231
- };
232
- }
233
-
234
219
  // src/utils/get-potential-start-index.ts
235
220
  function getPotentialStartIndex(text, searchedText) {
236
221
  if (searchedText.length === 0) {
@@ -249,60 +234,12 @@ function getPotentialStartIndex(text, searchedText) {
249
234
  return null;
250
235
  }
251
236
 
252
- // src/utils/on-error.ts
253
- function extractOnErrorOption(providerOptions) {
254
- var _a;
255
- if (providerOptions && typeof providerOptions === "object") {
256
- const onError = (_a = providerOptions.toolCallMiddleware) == null ? void 0 : _a.onError;
257
- return onError ? { onError } : void 0;
258
- }
259
- return;
260
- }
261
-
262
- // src/utils/provider-options.ts
263
- var originalToolsSchema = {
264
- encode: encodeOriginalTools,
265
- decode: decodeOriginalTools
266
- };
267
- function encodeOriginalTools(tools) {
268
- return (tools == null ? void 0 : tools.map((t) => ({
269
- name: t.name,
270
- inputSchema: JSON.stringify(t.inputSchema)
271
- }))) || [];
272
- }
273
- function decodeOriginalTools(originalTools) {
274
- if (!originalTools) {
275
- return [];
276
- }
277
- return originalTools.map(
278
- (t) => ({
279
- type: "function",
280
- name: t.name,
281
- inputSchema: JSON.parse(t.inputSchema)
282
- })
283
- );
284
- }
285
- function extractToolNamesFromOriginalTools(originalTools) {
286
- return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
287
- }
288
- function isToolChoiceActive(params) {
289
- var _a, _b, _c;
290
- const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
291
- 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"));
292
- }
293
-
294
237
  // src/utils/regex.ts
295
238
  function escapeRegExp(literal) {
296
239
  return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
297
240
  }
298
241
 
299
242
  // src/utils/robust-json.ts
300
- var robust_json_exports = {};
301
- __export(robust_json_exports, {
302
- parse: () => parse,
303
- stringify: () => stringify,
304
- transform: () => transform
305
- });
306
243
  var WHITESPACE_TEST_REGEX = /\s/;
307
244
  var WHITESPACE_REGEX = /^\s+/;
308
245
  var OBJECT_START_REGEX = /^\{/;
@@ -967,19 +904,6 @@ function stringify(obj) {
967
904
  return "null";
968
905
  }
969
906
 
970
- // src/utils/type-guards.ts
971
- function isToolCallContent(content) {
972
- return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
973
- (typeof content.input === "string" || typeof content.input === "object");
974
- }
975
- function isToolResultPart(content) {
976
- const c = content;
977
- return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
978
- }
979
- function hasInputProperty(obj) {
980
- return typeof obj === "object" && obj !== null && "input" in obj;
981
- }
982
-
983
907
  // src/protocols/json-mix-protocol.ts
984
908
  function processToolCallJson(toolCallJson, fullMatch, processedElements, options) {
985
909
  var _a;
@@ -987,11 +911,17 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
987
911
  const parsedToolCall = parse(toolCallJson);
988
912
  processedElements.push({
989
913
  type: "tool-call",
990
- toolCallId: (0, import_provider_utils2.generateId)(),
914
+ toolCallId: (0, import_provider_utils.generateId)(),
991
915
  toolName: parsedToolCall.name,
992
916
  input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
993
917
  });
994
918
  } catch (error) {
919
+ logParseFailure({
920
+ phase: "generated-text",
921
+ reason: "Failed to parse tool call JSON segment",
922
+ snippet: fullMatch,
923
+ error
924
+ });
995
925
  if (options == null ? void 0 : options.onError) {
996
926
  options.onError(
997
927
  "Could not process JSON tool call, keeping original text.",
@@ -1024,7 +954,7 @@ function flushBuffer(state, controller, toolCallStart) {
1024
954
  return;
1025
955
  }
1026
956
  if (!state.currentTextId) {
1027
- state.currentTextId = (0, import_provider_utils2.generateId)();
957
+ state.currentTextId = (0, import_provider_utils.generateId)();
1028
958
  controller.enqueue({ type: "text-start", id: state.currentTextId });
1029
959
  state.hasEmittedTextStart = true;
1030
960
  }
@@ -1047,7 +977,12 @@ function emitIncompleteToolCall(state, controller, toolCallStart) {
1047
977
  if (!state.currentToolCallJson) {
1048
978
  return;
1049
979
  }
1050
- const errorId = (0, import_provider_utils2.generateId)();
980
+ logParseFailure({
981
+ phase: "stream",
982
+ reason: "Incomplete streaming tool call segment emitted as text",
983
+ snippet: `${toolCallStart}${state.currentToolCallJson}`
984
+ });
985
+ const errorId = (0, import_provider_utils.generateId)();
1051
986
  controller.enqueue({ type: "text-start", id: errorId });
1052
987
  controller.enqueue({
1053
988
  type: "text-delta",
@@ -1071,7 +1006,7 @@ function publishText(text, state, controller) {
1071
1006
  state.currentToolCallJson += text;
1072
1007
  } else if (text.length > 0) {
1073
1008
  if (!state.currentTextId) {
1074
- state.currentTextId = (0, import_provider_utils2.generateId)();
1009
+ state.currentTextId = (0, import_provider_utils.generateId)();
1075
1010
  controller.enqueue({ type: "text-start", id: state.currentTextId });
1076
1011
  state.hasEmittedTextStart = true;
1077
1012
  }
@@ -1086,16 +1021,22 @@ function emitToolCall(context) {
1086
1021
  var _a;
1087
1022
  const { state, controller, toolCallStart, toolCallEnd, options } = context;
1088
1023
  try {
1089
- const parsedToolCall = robust_json_exports.parse(state.currentToolCallJson);
1024
+ const parsedToolCall = parse(state.currentToolCallJson);
1090
1025
  closeTextBlock(state, controller);
1091
1026
  controller.enqueue({
1092
1027
  type: "tool-call",
1093
- toolCallId: (0, import_provider_utils2.generateId)(),
1028
+ toolCallId: (0, import_provider_utils.generateId)(),
1094
1029
  toolName: parsedToolCall.name,
1095
1030
  input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1096
1031
  });
1097
- } catch (e) {
1098
- const errorId = (0, import_provider_utils2.generateId)();
1032
+ } catch (error) {
1033
+ logParseFailure({
1034
+ phase: "stream",
1035
+ reason: "Failed to parse streaming tool call JSON segment",
1036
+ snippet: `${toolCallStart}${state.currentToolCallJson}${toolCallEnd}`,
1037
+ error
1038
+ });
1039
+ const errorId = (0, import_provider_utils.generateId)();
1099
1040
  controller.enqueue({ type: "text-start", id: errorId });
1100
1041
  controller.enqueue({
1101
1042
  type: "text-delta",
@@ -1260,162 +1201,900 @@ var jsonMixProtocol = ({
1260
1201
  });
1261
1202
 
1262
1203
  // src/protocols/morph-xml-protocol.ts
1263
- var import_provider_utils3 = require("@ai-sdk/provider-utils");
1264
- var import_rxml = require("@ai-sdk-tool/rxml");
1265
- var WHITESPACE_REGEX2 = /\s/;
1266
- function processTextBeforeToolCall(text, currentIndex, toolCallStartIndex, processedElements) {
1267
- if (toolCallStartIndex > currentIndex) {
1268
- const textSegment = text.substring(currentIndex, toolCallStartIndex);
1269
- if (textSegment.trim()) {
1270
- processedElements.push({ type: "text", text: textSegment });
1271
- }
1204
+ var import_provider_utils2 = require("@ai-sdk/provider-utils");
1205
+ var import_rxml2 = require("@ai-sdk-tool/rxml");
1206
+
1207
+ // src/heuristics/engine.ts
1208
+ function applyRawSegmentUpdate(current, result) {
1209
+ if (result.rawSegment !== void 0) {
1210
+ return { ...current, rawSegment: result.rawSegment };
1272
1211
  }
1273
- return currentIndex;
1212
+ return current;
1274
1213
  }
1275
- function processToolCall(params) {
1276
- var _a;
1277
- const { toolCall, tools, options, text, processedElements } = params;
1278
- try {
1279
- const toolSchema = getToolSchema(tools, toolCall.toolName);
1280
- const parsed = (0, import_rxml.parse)(toolCall.content, toolSchema, {
1281
- onError: options == null ? void 0 : options.onError,
1282
- // Disable HTML self-closing tag behavior to allow base, meta, link etc. as regular tags
1283
- noChildNodes: []
1284
- });
1285
- processedElements.push({
1286
- type: "tool-call",
1287
- toolCallId: (0, import_provider_utils3.generateId)(),
1288
- toolName: toolCall.toolName,
1289
- input: JSON.stringify(parsed)
1290
- });
1291
- } catch (error) {
1292
- const originalCallText = text.substring(
1293
- toolCall.startIndex,
1294
- toolCall.endIndex
1295
- );
1296
- const message = `Could not process XML tool call, keeping original text: ${originalCallText}`;
1297
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1298
- toolCall: originalCallText,
1299
- toolName: toolCall.toolName,
1300
- error
1301
- });
1302
- processedElements.push({ type: "text", text: originalCallText });
1214
+ function applyParsedUpdate(current, result) {
1215
+ if (result.parsed !== void 0) {
1216
+ return { ...current, parsed: result.parsed };
1303
1217
  }
1218
+ return current;
1304
1219
  }
1305
- function addRemainingText(text, currentIndex, processedElements) {
1306
- if (currentIndex < text.length) {
1307
- const remainingText = text.substring(currentIndex);
1308
- if (remainingText.trim()) {
1309
- processedElements.push({ type: "text", text: remainingText });
1310
- }
1220
+ function applyWarningsUpdate(current, result) {
1221
+ var _a, _b;
1222
+ if (result.warnings && result.warnings.length > 0) {
1223
+ const meta = (_a = current.meta) != null ? _a : {};
1224
+ const existingWarnings = (_b = meta.warnings) != null ? _b : [];
1225
+ return {
1226
+ ...current,
1227
+ meta: { ...meta, warnings: [...existingWarnings, ...result.warnings] }
1228
+ };
1311
1229
  }
1230
+ return current;
1312
1231
  }
1313
- function handleStreamingToolCallEnd(params) {
1314
- const { toolContent, currentToolCall, tools, options, ctrl, flushText } = params;
1232
+ function attemptReparse(current, result, reparseCount, maxReparses, parse4) {
1233
+ if (!result.reparse || result.rawSegment === void 0 || reparseCount >= maxReparses) {
1234
+ return { state: current, newCount: reparseCount };
1235
+ }
1315
1236
  try {
1316
- const toolSchema = getToolSchema(tools, currentToolCall.name);
1317
- const parsed = (0, import_rxml.parse)(toolContent, toolSchema, {
1318
- onError: options == null ? void 0 : options.onError,
1319
- noChildNodes: []
1320
- });
1321
- flushText(ctrl);
1322
- ctrl.enqueue({
1323
- type: "tool-call",
1324
- toolCallId: (0, import_provider_utils3.generateId)(),
1325
- toolName: currentToolCall.name,
1326
- input: JSON.stringify(parsed)
1327
- });
1237
+ const reparsed = parse4(result.rawSegment, current.schema);
1238
+ return {
1239
+ state: { ...current, parsed: reparsed, errors: [] },
1240
+ newCount: reparseCount + 1
1241
+ };
1328
1242
  } catch (error) {
1329
- handleStreamingToolCallError({
1330
- error,
1331
- currentToolCall,
1332
- toolContent,
1333
- options,
1334
- ctrl,
1335
- flushText
1336
- });
1243
+ return {
1244
+ state: { ...current, errors: [...current.errors, error] },
1245
+ newCount: reparseCount + 1
1246
+ };
1337
1247
  }
1338
1248
  }
1339
- function handleStreamingToolCallError(params) {
1249
+ function executePhase(ctx, heuristics, options) {
1340
1250
  var _a;
1341
- const { error, currentToolCall, toolContent, options, ctrl, flushText } = params;
1342
- const endTag = `</${currentToolCall.name}>`;
1343
- const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
1344
- let message = "Could not process streaming XML tool call; emitting original text.";
1345
- if (error instanceof import_rxml.RXMLDuplicateStringTagError) {
1346
- message = `Duplicate string tags detected in streaming tool call '${currentToolCall.name}'; emitting original text.`;
1347
- } else if (error instanceof import_rxml.RXMLCoercionError) {
1348
- message = `Failed to coerce arguments for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1349
- } else if (error instanceof import_rxml.RXMLParseError) {
1350
- message = `Failed to parse XML for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1251
+ let current = ctx;
1252
+ let reparseCount = 0;
1253
+ const maxReparses = (_a = options.maxReparses) != null ? _a : 2;
1254
+ for (const heuristic of heuristics) {
1255
+ if (!heuristic.applies(current)) {
1256
+ continue;
1257
+ }
1258
+ const result = heuristic.run(current);
1259
+ current = applyRawSegmentUpdate(current, result);
1260
+ current = applyParsedUpdate(current, result);
1261
+ current = applyWarningsUpdate(current, result);
1262
+ const reparseResult = attemptReparse(
1263
+ current,
1264
+ result,
1265
+ reparseCount,
1266
+ maxReparses,
1267
+ options.parse
1268
+ );
1269
+ current = reparseResult.state;
1270
+ reparseCount = reparseResult.newCount;
1271
+ if (result.stop) {
1272
+ break;
1273
+ }
1351
1274
  }
1352
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1353
- toolCall: originalCallText,
1354
- toolName: currentToolCall.name,
1355
- error
1356
- });
1357
- flushText(ctrl, originalCallText);
1275
+ return current;
1358
1276
  }
1359
- function findEarliestToolTag(buffer, toolNames) {
1360
- let earliestStartTagIndex = -1;
1361
- let earliestToolName = "";
1362
- if (toolNames.length > 0) {
1363
- for (const name of toolNames) {
1364
- const startTag = `<${name}>`;
1365
- const index = buffer.indexOf(startTag);
1366
- if (index !== -1 && (earliestStartTagIndex === -1 || index < earliestStartTagIndex)) {
1367
- earliestStartTagIndex = index;
1368
- earliestToolName = name;
1369
- }
1277
+ function applyHeuristicPipeline(ctx, config, options) {
1278
+ let current = ctx;
1279
+ if (config.preParse && config.preParse.length > 0) {
1280
+ current = executePhase(current, config.preParse, options);
1281
+ }
1282
+ if (current.parsed === null && current.errors.length === 0) {
1283
+ try {
1284
+ const parsed = options.parse(current.rawSegment, current.schema);
1285
+ current = { ...current, parsed, errors: [] };
1286
+ } catch (error) {
1287
+ current = { ...current, errors: [error] };
1370
1288
  }
1371
1289
  }
1372
- return { index: earliestStartTagIndex, name: earliestToolName };
1290
+ if (current.errors.length > 0 && config.fallbackReparse && config.fallbackReparse.length > 0) {
1291
+ current = executePhase(current, config.fallbackReparse, options);
1292
+ }
1293
+ if (current.parsed !== null && config.postParse && config.postParse.length > 0) {
1294
+ current = executePhase(current, config.postParse, options);
1295
+ }
1296
+ return current;
1373
1297
  }
1374
- function handleNoToolTagInBuffer(buffer, maxStartTagLen, controller, flushText) {
1375
- const tail = Math.max(0, maxStartTagLen - 1);
1376
- const safeLen = Math.max(0, buffer.length - tail);
1377
- if (safeLen > 0) {
1378
- const textToFlush = buffer.slice(0, safeLen);
1379
- flushText(controller, textToFlush);
1380
- return { buffer: buffer.slice(safeLen), shouldContinue: true };
1298
+ function createIntermediateCall(toolName, rawSegment, schema) {
1299
+ return {
1300
+ toolName,
1301
+ schema,
1302
+ rawSegment,
1303
+ parsed: null,
1304
+ errors: [],
1305
+ meta: { originalContent: rawSegment }
1306
+ };
1307
+ }
1308
+ function mergePipelineConfigs(...configs) {
1309
+ var _a, _b, _c;
1310
+ const result = {
1311
+ preParse: [],
1312
+ fallbackReparse: [],
1313
+ postParse: []
1314
+ };
1315
+ for (const config of configs) {
1316
+ if (config.preParse) {
1317
+ result.preParse = [...(_a = result.preParse) != null ? _a : [], ...config.preParse];
1318
+ }
1319
+ if (config.fallbackReparse) {
1320
+ result.fallbackReparse = [
1321
+ ...(_b = result.fallbackReparse) != null ? _b : [],
1322
+ ...config.fallbackReparse
1323
+ ];
1324
+ }
1325
+ if (config.postParse) {
1326
+ result.postParse = [...(_c = result.postParse) != null ? _c : [], ...config.postParse];
1327
+ }
1381
1328
  }
1382
- return { buffer, shouldContinue: false };
1329
+ return result;
1383
1330
  }
1384
- function processToolCallInBuffer(params) {
1385
- const {
1386
- buffer,
1387
- currentToolCall,
1388
- tools,
1331
+
1332
+ // src/heuristics/xml-defaults.ts
1333
+ var import_rxml = require("@ai-sdk-tool/rxml");
1334
+ var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
1335
+ var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
1336
+ var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
1337
+ var WHITESPACE_REGEX2 = /\s/;
1338
+ var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
1339
+ var NAME_START_CHAR_RE = /[A-Za-z_:]/;
1340
+ var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
1341
+ var STATUS_TAG_RE = /<status>([\s\S]*?)<\/status>/i;
1342
+ var normalizeCloseTagsHeuristic = {
1343
+ id: "normalize-close-tags",
1344
+ phase: "pre-parse",
1345
+ applies: () => true,
1346
+ run: (ctx) => {
1347
+ const normalized = ctx.rawSegment.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1348
+ if (normalized !== ctx.rawSegment) {
1349
+ return { rawSegment: normalized };
1350
+ }
1351
+ return {};
1352
+ }
1353
+ };
1354
+ var escapeInvalidLtHeuristic = {
1355
+ id: "escape-invalid-lt",
1356
+ phase: "pre-parse",
1357
+ applies: () => true,
1358
+ run: (ctx) => {
1359
+ const escaped = escapeInvalidLt(ctx.rawSegment);
1360
+ if (escaped !== ctx.rawSegment) {
1361
+ return { rawSegment: escaped };
1362
+ }
1363
+ return {};
1364
+ }
1365
+ };
1366
+ var balanceTagsHeuristic = {
1367
+ id: "balance-tags",
1368
+ phase: "fallback-reparse",
1369
+ applies: (ctx) => {
1370
+ var _a;
1371
+ const original = ((_a = ctx.meta) == null ? void 0 : _a.originalContent) || ctx.rawSegment;
1372
+ const normalized = original.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1373
+ const balanced = balanceTags(original);
1374
+ const hasMalformedClose = MALFORMED_CLOSE_RE.test(original);
1375
+ if (!hasMalformedClose && balanced.length > normalized.length) {
1376
+ return false;
1377
+ }
1378
+ return balanced !== normalized;
1379
+ },
1380
+ run: (ctx) => {
1381
+ var _a;
1382
+ const original = ((_a = ctx.meta) == null ? void 0 : _a.originalContent) || ctx.rawSegment;
1383
+ const balanced = balanceTags(original);
1384
+ const escaped = escapeInvalidLt(balanced);
1385
+ return { rawSegment: escaped, reparse: true };
1386
+ }
1387
+ };
1388
+ var dedupeShellStringTagsHeuristic = {
1389
+ id: "dedupe-shell-string-tags",
1390
+ phase: "fallback-reparse",
1391
+ applies: (ctx) => shouldDeduplicateStringTags(ctx.schema),
1392
+ run: (ctx) => {
1393
+ const names = getStringPropertyNames(ctx.schema);
1394
+ let deduped = ctx.rawSegment;
1395
+ for (const key of names) {
1396
+ deduped = dedupeSingleTag(deduped, key);
1397
+ }
1398
+ if (deduped !== ctx.rawSegment) {
1399
+ return { rawSegment: deduped, reparse: true };
1400
+ }
1401
+ return {};
1402
+ }
1403
+ };
1404
+ var repairAgainstSchemaHeuristic = {
1405
+ id: "repair-against-schema",
1406
+ phase: "post-parse",
1407
+ applies: (ctx) => ctx.parsed !== null && typeof ctx.parsed === "object",
1408
+ run: (ctx) => {
1409
+ const repaired = repairParsedAgainstSchema(ctx.parsed, ctx.schema);
1410
+ if (repaired !== ctx.parsed) {
1411
+ return { parsed: repaired };
1412
+ }
1413
+ return {};
1414
+ }
1415
+ };
1416
+ var defaultPipelineConfig = {
1417
+ preParse: [normalizeCloseTagsHeuristic, escapeInvalidLtHeuristic],
1418
+ fallbackReparse: [balanceTagsHeuristic, dedupeShellStringTagsHeuristic],
1419
+ postParse: [repairAgainstSchemaHeuristic]
1420
+ };
1421
+ var INDEX_TAG_RE = /^<(\d+)(?:>|\/?>)/;
1422
+ function isIndexTagAt(xml, pos) {
1423
+ const remaining = xml.slice(pos);
1424
+ return INDEX_TAG_RE.test(remaining);
1425
+ }
1426
+ function escapeInvalidLt(xml) {
1427
+ const len = xml.length;
1428
+ let out = "";
1429
+ for (let i = 0; i < len; i += 1) {
1430
+ const ch = xml[i];
1431
+ if (ch === "<") {
1432
+ const next = i + 1 < len ? xml[i + 1] : "";
1433
+ const isValidStart = NAME_START_CHAR_RE.test(next) || next === "/" || next === "!" || next === "?";
1434
+ const isIndexTag = !isValidStart && isIndexTagAt(xml, i);
1435
+ if (!(isValidStart || isIndexTag)) {
1436
+ out += "&lt;";
1437
+ continue;
1438
+ }
1439
+ }
1440
+ out += ch;
1441
+ }
1442
+ return out;
1443
+ }
1444
+ function balanceTags(xml) {
1445
+ const src = xml.replace(MALFORMED_CLOSE_RE_G, "</$1>").replace(STATUS_TO_STEP_BOUNDARY_RE, "</status></step><step>");
1446
+ let i = 0;
1447
+ const len = src.length;
1448
+ const out = [];
1449
+ const stack = [];
1450
+ while (i < len) {
1451
+ const lt = src.indexOf("<", i);
1452
+ if (lt === -1) {
1453
+ out.push(src.slice(i));
1454
+ break;
1455
+ }
1456
+ out.push(src.slice(i, lt));
1457
+ if (lt + 1 >= len) {
1458
+ break;
1459
+ }
1460
+ const next = src[lt + 1];
1461
+ if (next === "!" || next === "?") {
1462
+ i = handleSpecialTagSegment(src, lt, out);
1463
+ continue;
1464
+ }
1465
+ if (next === "/") {
1466
+ i = handleClosingTagSegment(src, lt, out, stack);
1467
+ continue;
1468
+ }
1469
+ i = handleOpeningTagSegment(src, lt, out, stack);
1470
+ }
1471
+ for (let k = stack.length - 1; k >= 0; k -= 1) {
1472
+ out.push(`</${stack[k]}>`);
1473
+ }
1474
+ return out.join("");
1475
+ }
1476
+ function skipWs(s, p, len) {
1477
+ let idx = p;
1478
+ while (idx < len && WHITESPACE_REGEX2.test(s[idx])) {
1479
+ idx += 1;
1480
+ }
1481
+ return idx;
1482
+ }
1483
+ function parseTagNameAt(s, p, len) {
1484
+ let idx = p;
1485
+ const start = idx;
1486
+ while (idx < len && NAME_CHAR_RE.test(s[idx])) {
1487
+ idx += 1;
1488
+ }
1489
+ return { name: s.slice(start, idx), pos: idx };
1490
+ }
1491
+ function handleSpecialTagSegment(src, lt, out) {
1492
+ const gt = src.indexOf(">", lt + 1);
1493
+ if (gt === -1) {
1494
+ out.push(src.slice(lt));
1495
+ return src.length;
1496
+ }
1497
+ out.push(src.slice(lt, gt + 1));
1498
+ return gt + 1;
1499
+ }
1500
+ function handleClosingTagSegment(src, lt, out, stack) {
1501
+ const len = src.length;
1502
+ let p = skipWs(src, lt + 2, len);
1503
+ const { name, pos } = parseTagNameAt(src, p, len);
1504
+ p = pos;
1505
+ const gt = src.indexOf(">", p);
1506
+ const closingText = gt === -1 ? src.slice(lt) : src.slice(lt, gt + 1);
1507
+ const idx = stack.lastIndexOf(name);
1508
+ if (idx !== -1) {
1509
+ for (let k = stack.length - 1; k > idx; k -= 1) {
1510
+ out.push(`</${stack[k]}>`);
1511
+ stack.pop();
1512
+ }
1513
+ out.push(closingText);
1514
+ stack.pop();
1515
+ }
1516
+ return gt === -1 ? len : gt + 1;
1517
+ }
1518
+ function handleOpeningTagSegment(src, lt, out, stack) {
1519
+ const len = src.length;
1520
+ let p = skipWs(src, lt + 1, len);
1521
+ const nameStart = p;
1522
+ const parsed = parseTagNameAt(src, p, len);
1523
+ p = parsed.pos;
1524
+ const name = src.slice(nameStart, p);
1525
+ const q = src.indexOf(">", p);
1526
+ if (q === -1) {
1527
+ out.push(src.slice(lt));
1528
+ return len;
1529
+ }
1530
+ let r = q - 1;
1531
+ while (r >= nameStart && WHITESPACE_REGEX2.test(src[r])) {
1532
+ r -= 1;
1533
+ }
1534
+ const selfClosing = src[r] === "/";
1535
+ out.push(src.slice(lt, q + 1));
1536
+ if (!selfClosing && name) {
1537
+ stack.push(name);
1538
+ }
1539
+ return q + 1;
1540
+ }
1541
+ function shouldDeduplicateStringTags(schema) {
1542
+ const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1543
+ if (!unwrapped || typeof unwrapped !== "object") {
1544
+ return false;
1545
+ }
1546
+ const props = unwrapped.properties;
1547
+ if (!props) {
1548
+ return false;
1549
+ }
1550
+ const commandRaw = props.command;
1551
+ if (!commandRaw) {
1552
+ return false;
1553
+ }
1554
+ const command = (0, import_rxml.unwrapJsonSchema)(commandRaw);
1555
+ return (command == null ? void 0 : command.type) === "array";
1556
+ }
1557
+ function getStringPropertyNames(schema) {
1558
+ const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1559
+ if (!unwrapped || typeof unwrapped !== "object") {
1560
+ return [];
1561
+ }
1562
+ const props = unwrapped.properties;
1563
+ if (!props) {
1564
+ return [];
1565
+ }
1566
+ const names = [];
1567
+ for (const key of Object.keys(props)) {
1568
+ const prop = (0, import_rxml.unwrapJsonSchema)(
1569
+ props[key]
1570
+ );
1571
+ const type = prop.type;
1572
+ if (type === "string") {
1573
+ names.push(key);
1574
+ }
1575
+ }
1576
+ return names;
1577
+ }
1578
+ function escapeRegExp2(s) {
1579
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1580
+ }
1581
+ function dedupeSingleTag(xml, key) {
1582
+ var _a, _b;
1583
+ const escaped = escapeRegExp2(key);
1584
+ const re = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
1585
+ const matches = Array.from(xml.matchAll(re));
1586
+ if (matches.length <= 1) {
1587
+ return xml;
1588
+ }
1589
+ const last = matches.at(-1);
1590
+ let result = "";
1591
+ let cursor = 0;
1592
+ for (const m of matches) {
1593
+ const idx = (_a = m.index) != null ? _a : 0;
1594
+ result += xml.slice(cursor, idx);
1595
+ if (last && idx === ((_b = last.index) != null ? _b : -1)) {
1596
+ result += m[0];
1597
+ }
1598
+ cursor = idx + m[0].length;
1599
+ }
1600
+ result += xml.slice(cursor);
1601
+ return result;
1602
+ }
1603
+ function repairParsedAgainstSchema(input, schema) {
1604
+ if (!input || typeof input !== "object") {
1605
+ return input;
1606
+ }
1607
+ const unwrapped = (0, import_rxml.unwrapJsonSchema)(schema);
1608
+ if (!unwrapped || typeof unwrapped !== "object") {
1609
+ return input;
1610
+ }
1611
+ const properties = unwrapped.properties;
1612
+ if (!properties) {
1613
+ return input;
1614
+ }
1615
+ applySchemaProps(input, properties);
1616
+ return input;
1617
+ }
1618
+ function applySchemaProps(obj, properties) {
1619
+ for (const key of Object.keys(obj)) {
1620
+ const propSchema = properties[key];
1621
+ if (!propSchema) {
1622
+ continue;
1623
+ }
1624
+ const prop = (0, import_rxml.unwrapJsonSchema)(propSchema);
1625
+ const propType = prop.type;
1626
+ if (propType === "array" && prop.items) {
1627
+ const itemSchemaRaw = prop.items;
1628
+ const itemSchema = (0, import_rxml.unwrapJsonSchema)(itemSchemaRaw);
1629
+ obj[key] = coerceArrayItems(obj[key], itemSchema);
1630
+ continue;
1631
+ }
1632
+ if (propType === "object") {
1633
+ const val = obj[key];
1634
+ if (val && typeof val === "object") {
1635
+ obj[key] = repairParsedAgainstSchema(val, prop);
1636
+ }
1637
+ }
1638
+ }
1639
+ }
1640
+ function coerceArrayItems(val, itemSchema) {
1641
+ if (!Array.isArray(val)) {
1642
+ return val;
1643
+ }
1644
+ return val.map((v) => coerceArrayItem(v, itemSchema));
1645
+ }
1646
+ function coerceArrayItem(v, itemSchema) {
1647
+ const itemType = itemSchema == null ? void 0 : itemSchema.type;
1648
+ if (typeof v === "string" && itemType === "object") {
1649
+ const parsed = tryParseStringToSchemaObject(v, itemSchema);
1650
+ if (parsed !== null) {
1651
+ return parsed;
1652
+ }
1653
+ const fallback = extractStepStatusFromString(
1654
+ v.replace(MALFORMED_CLOSE_RE_G, "</$1>")
1655
+ );
1656
+ if (fallback) {
1657
+ return fallback;
1658
+ }
1659
+ return v;
1660
+ }
1661
+ if (v && typeof v === "object" && itemType === "object") {
1662
+ return repairParsedAgainstSchema(v, itemSchema);
1663
+ }
1664
+ return v;
1665
+ }
1666
+ function tryParseStringToSchemaObject(xml, itemSchema) {
1667
+ try {
1668
+ const normalized = xml.replace(MALFORMED_CLOSE_RE_G, "</$1>");
1669
+ const fixed = (0, import_rxml.parse)(normalized, itemSchema, { noChildNodes: [] });
1670
+ return typeof fixed === "string" ? null : fixed;
1671
+ } catch (e) {
1672
+ return null;
1673
+ }
1674
+ }
1675
+ function extractStepStatusFromString(normXml) {
1676
+ const stepMatch = normXml.match(STEP_TAG_RE);
1677
+ const statusMatch = normXml.match(STATUS_TAG_RE);
1678
+ if (stepMatch && statusMatch) {
1679
+ return { step: stepMatch[1], status: statusMatch[1] };
1680
+ }
1681
+ return null;
1682
+ }
1683
+
1684
+ // src/utils/type-guards.ts
1685
+ function isToolCallContent(content) {
1686
+ return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
1687
+ (typeof content.input === "string" || typeof content.input === "object");
1688
+ }
1689
+ function isToolResultPart(content) {
1690
+ const c = content;
1691
+ return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
1692
+ }
1693
+ function hasInputProperty(obj) {
1694
+ return typeof obj === "object" && obj !== null && "input" in obj;
1695
+ }
1696
+
1697
+ // src/protocols/morph-xml-protocol.ts
1698
+ var defaultPipelineConfig2 = defaultPipelineConfig;
1699
+ var applyHeuristicPipeline2 = applyHeuristicPipeline;
1700
+ var createIntermediateCall2 = createIntermediateCall;
1701
+ var mergePipelineConfigs2 = mergePipelineConfigs;
1702
+ var WHITESPACE_REGEX3 = /\s/;
1703
+ var MALFORMED_CLOSE_RE2 = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
1704
+ var MALFORMED_CLOSE_RE_G2 = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
1705
+ var NAME_CHAR_RE2 = /[A-Za-z0-9_:-]/;
1706
+ function normalizeCloseTags(xml) {
1707
+ return xml.replace(MALFORMED_CLOSE_RE_G2, "</$1>");
1708
+ }
1709
+ function tryParseSecondaryXml(content, toolSchema, options) {
1710
+ const normalized = normalizeCloseTags(content);
1711
+ const balanced = balanceTags(content);
1712
+ const hasMalformedClose = MALFORMED_CLOSE_RE2.test(content);
1713
+ if (!hasMalformedClose && balanced.length > normalized.length) {
1714
+ return null;
1715
+ }
1716
+ try {
1717
+ let parsed = (0, import_rxml2.parse)(balanced, toolSchema, {
1718
+ onError: options == null ? void 0 : options.onError,
1719
+ noChildNodes: []
1720
+ });
1721
+ parsed = repairParsedAgainstSchema(parsed, toolSchema);
1722
+ return parsed;
1723
+ } catch (e) {
1724
+ if (shouldDeduplicateStringTags(toolSchema)) {
1725
+ const deduped = dedupeStringTagsAgainstSchema(balanced, toolSchema);
1726
+ if (deduped !== balanced) {
1727
+ try {
1728
+ let reparsed = (0, import_rxml2.parse)(deduped, toolSchema, {
1729
+ onError: options == null ? void 0 : options.onError,
1730
+ noChildNodes: []
1731
+ });
1732
+ reparsed = repairParsedAgainstSchema(reparsed, toolSchema);
1733
+ return reparsed;
1734
+ } catch (e2) {
1735
+ return null;
1736
+ }
1737
+ }
1738
+ }
1739
+ return null;
1740
+ }
1741
+ }
1742
+ function dedupeStringTagsAgainstSchema(xml, schema) {
1743
+ const names = getStringPropertyNames(schema);
1744
+ let out = xml;
1745
+ for (const key of names) {
1746
+ out = dedupeSingleTag(out, key);
1747
+ }
1748
+ return out;
1749
+ }
1750
+ function processTextBeforeToolCall(text, currentIndex, toolCallStartIndex, processedElements) {
1751
+ if (toolCallStartIndex > currentIndex) {
1752
+ const textSegment = text.substring(currentIndex, toolCallStartIndex);
1753
+ if (textSegment.trim()) {
1754
+ processedElements.push({ type: "text", text: textSegment });
1755
+ }
1756
+ }
1757
+ return currentIndex;
1758
+ }
1759
+ function processToolCallWithPipeline(params) {
1760
+ var _a;
1761
+ const {
1762
+ toolCall,
1763
+ tools,
1389
1764
  options,
1390
- controller,
1765
+ text,
1766
+ processedElements,
1767
+ pipelineConfig = defaultPipelineConfig2,
1768
+ maxReparses
1769
+ } = params;
1770
+ const toolSchema = getToolSchema(tools, toolCall.toolName);
1771
+ const ctx = createIntermediateCall2(
1772
+ toolCall.toolName,
1773
+ toolCall.content,
1774
+ toolSchema
1775
+ );
1776
+ const result = applyHeuristicPipeline2(ctx, pipelineConfig, {
1777
+ parse: (xml, schema) => (0, import_rxml2.parse)(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1778
+ onError: options == null ? void 0 : options.onError,
1779
+ maxReparses
1780
+ });
1781
+ if (result.parsed !== null) {
1782
+ processedElements.push({
1783
+ type: "tool-call",
1784
+ toolCallId: (0, import_provider_utils2.generateId)(),
1785
+ toolName: toolCall.toolName,
1786
+ input: JSON.stringify(result.parsed)
1787
+ });
1788
+ } else {
1789
+ const originalCallText = text.substring(
1790
+ toolCall.startIndex,
1791
+ toolCall.endIndex
1792
+ );
1793
+ const message = `Could not process XML tool call, keeping original text: ${originalCallText}`;
1794
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1795
+ toolCall: originalCallText,
1796
+ toolName: toolCall.toolName,
1797
+ error: result.errors[0]
1798
+ });
1799
+ processedElements.push({ type: "text", text: originalCallText });
1800
+ }
1801
+ }
1802
+ function processToolCall(params) {
1803
+ var _a;
1804
+ const { toolCall, tools, options, text, processedElements } = params;
1805
+ const toolSchema = getToolSchema(tools, toolCall.toolName);
1806
+ try {
1807
+ const primary = escapeInvalidLt(normalizeCloseTags(toolCall.content));
1808
+ let parsed = (0, import_rxml2.parse)(primary, toolSchema, {
1809
+ onError: options == null ? void 0 : options.onError,
1810
+ noChildNodes: []
1811
+ });
1812
+ parsed = repairParsedAgainstSchema(parsed, toolSchema);
1813
+ processedElements.push({
1814
+ type: "tool-call",
1815
+ toolCallId: (0, import_provider_utils2.generateId)(),
1816
+ toolName: toolCall.toolName,
1817
+ input: JSON.stringify(parsed)
1818
+ });
1819
+ } catch (error) {
1820
+ const reparsed = tryParseSecondaryXml(
1821
+ toolCall.content,
1822
+ toolSchema,
1823
+ options
1824
+ );
1825
+ if (reparsed !== null) {
1826
+ processedElements.push({
1827
+ type: "tool-call",
1828
+ toolCallId: (0, import_provider_utils2.generateId)(),
1829
+ toolName: toolCall.toolName,
1830
+ input: JSON.stringify(reparsed)
1831
+ });
1832
+ return;
1833
+ }
1834
+ const originalCallText = text.substring(
1835
+ toolCall.startIndex,
1836
+ toolCall.endIndex
1837
+ );
1838
+ const message = `Could not process XML tool call, keeping original text: ${originalCallText}`;
1839
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1840
+ toolCall: originalCallText,
1841
+ toolName: toolCall.toolName,
1842
+ error
1843
+ });
1844
+ processedElements.push({ type: "text", text: originalCallText });
1845
+ }
1846
+ }
1847
+ function addRemainingText(text, currentIndex, processedElements) {
1848
+ if (currentIndex < text.length) {
1849
+ const remainingText = text.substring(currentIndex);
1850
+ if (remainingText.trim()) {
1851
+ processedElements.push({ type: "text", text: remainingText });
1852
+ }
1853
+ }
1854
+ }
1855
+ function handleStreamingToolCallEndWithPipeline(params) {
1856
+ var _a;
1857
+ const {
1858
+ toolContent,
1859
+ currentToolCall,
1860
+ tools,
1861
+ options,
1862
+ ctrl,
1391
1863
  flushText,
1392
- setBuffer
1864
+ pipelineConfig = defaultPipelineConfig2,
1865
+ maxReparses
1393
1866
  } = params;
1394
- const endTag = `</${currentToolCall.name}>`;
1395
- const endTagIndex = buffer.indexOf(endTag);
1396
- if (endTagIndex !== -1) {
1397
- const toolContent = buffer.substring(0, endTagIndex);
1398
- const newBuffer = buffer.substring(endTagIndex + endTag.length);
1399
- setBuffer("");
1400
- handleStreamingToolCallEnd({
1401
- toolContent,
1867
+ const toolSchema = getToolSchema(tools, currentToolCall.name);
1868
+ const ctx = createIntermediateCall2(
1869
+ currentToolCall.name,
1870
+ toolContent,
1871
+ toolSchema
1872
+ );
1873
+ const result = applyHeuristicPipeline2(ctx, pipelineConfig, {
1874
+ parse: (xml, schema) => (0, import_rxml2.parse)(xml, schema, { onError: options == null ? void 0 : options.onError, noChildNodes: [] }),
1875
+ onError: options == null ? void 0 : options.onError,
1876
+ maxReparses
1877
+ });
1878
+ flushText(ctrl);
1879
+ if (result.parsed !== null) {
1880
+ ctrl.enqueue({
1881
+ type: "tool-call",
1882
+ toolCallId: (0, import_provider_utils2.generateId)(),
1883
+ toolName: currentToolCall.name,
1884
+ input: JSON.stringify(result.parsed)
1885
+ });
1886
+ } else {
1887
+ const endTag = `</${currentToolCall.name}>`;
1888
+ const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
1889
+ const error = result.errors[0];
1890
+ let message = "Could not process streaming XML tool call; emitting original text.";
1891
+ if (error instanceof import_rxml2.RXMLDuplicateStringTagError) {
1892
+ message = `Duplicate string tags detected in streaming tool call '${currentToolCall.name}'; emitting original text.`;
1893
+ } else if (error instanceof import_rxml2.RXMLCoercionError) {
1894
+ message = `Failed to coerce arguments for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1895
+ } else if (error instanceof import_rxml2.RXMLParseError) {
1896
+ message = `Failed to parse XML for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1897
+ }
1898
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1899
+ toolCall: originalCallText,
1900
+ toolName: currentToolCall.name,
1901
+ error
1902
+ });
1903
+ flushText(ctrl, originalCallText);
1904
+ }
1905
+ }
1906
+ function handleStreamingToolCallEnd(params) {
1907
+ const { toolContent, currentToolCall, tools, options, ctrl, flushText } = params;
1908
+ const toolSchema = getToolSchema(tools, currentToolCall.name);
1909
+ try {
1910
+ const primary = escapeInvalidLt(normalizeCloseTags(toolContent));
1911
+ let parsed = (0, import_rxml2.parse)(primary, toolSchema, {
1912
+ onError: options == null ? void 0 : options.onError,
1913
+ noChildNodes: []
1914
+ });
1915
+ parsed = repairParsedAgainstSchema(parsed, toolSchema);
1916
+ flushText(ctrl);
1917
+ ctrl.enqueue({
1918
+ type: "tool-call",
1919
+ toolCallId: (0, import_provider_utils2.generateId)(),
1920
+ toolName: currentToolCall.name,
1921
+ input: JSON.stringify(parsed)
1922
+ });
1923
+ } catch (error) {
1924
+ const parsed = tryParseSecondaryXml(toolContent, toolSchema, options);
1925
+ if (parsed !== null) {
1926
+ flushText(ctrl);
1927
+ ctrl.enqueue({
1928
+ type: "tool-call",
1929
+ toolCallId: (0, import_provider_utils2.generateId)(),
1930
+ toolName: currentToolCall.name,
1931
+ input: JSON.stringify(parsed)
1932
+ });
1933
+ return;
1934
+ }
1935
+ handleStreamingToolCallError({
1936
+ error,
1402
1937
  currentToolCall,
1403
- tools,
1938
+ toolContent,
1404
1939
  options,
1405
- ctrl: controller,
1940
+ ctrl,
1406
1941
  flushText
1407
1942
  });
1943
+ }
1944
+ }
1945
+ function handleStreamingToolCallError(params) {
1946
+ var _a;
1947
+ const { error, currentToolCall, toolContent, options, ctrl, flushText } = params;
1948
+ const endTag = `</${currentToolCall.name}>`;
1949
+ const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
1950
+ let message = "Could not process streaming XML tool call; emitting original text.";
1951
+ if (error instanceof import_rxml2.RXMLDuplicateStringTagError) {
1952
+ message = `Duplicate string tags detected in streaming tool call '${currentToolCall.name}'; emitting original text.`;
1953
+ } else if (error instanceof import_rxml2.RXMLCoercionError) {
1954
+ message = `Failed to coerce arguments for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1955
+ } else if (error instanceof import_rxml2.RXMLParseError) {
1956
+ message = `Failed to parse XML for streaming tool call '${currentToolCall.name}'; emitting original text.`;
1957
+ }
1958
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, message, {
1959
+ toolCall: originalCallText,
1960
+ toolName: currentToolCall.name,
1961
+ error
1962
+ });
1963
+ flushText(ctrl, originalCallText);
1964
+ }
1965
+ function findEarliestToolTag(buffer, toolNames) {
1966
+ let bestIndex = -1;
1967
+ let bestName = "";
1968
+ let bestSelfClosing = false;
1969
+ if (toolNames.length > 0) {
1970
+ for (const name of toolNames) {
1971
+ const openTag = `<${name}>`;
1972
+ const selfTag = `<${name}/>`;
1973
+ const idxOpen = buffer.indexOf(openTag);
1974
+ const idxSelf = buffer.indexOf(selfTag);
1975
+ if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
1976
+ bestIndex = idxOpen;
1977
+ bestName = name;
1978
+ bestSelfClosing = false;
1979
+ }
1980
+ if (idxSelf !== -1 && (bestIndex === -1 || idxSelf < bestIndex)) {
1981
+ bestIndex = idxSelf;
1982
+ bestName = name;
1983
+ bestSelfClosing = true;
1984
+ }
1985
+ }
1986
+ }
1987
+ return { index: bestIndex, name: bestName, selfClosing: bestSelfClosing };
1988
+ }
1989
+ function handleNoToolTagInBuffer(buffer, maxStartTagLen, controller, flushText) {
1990
+ const tail = Math.max(0, maxStartTagLen - 1);
1991
+ const safeLen = Math.max(0, buffer.length - tail);
1992
+ if (safeLen > 0) {
1993
+ const textToFlush = buffer.slice(0, safeLen);
1994
+ flushText(controller, textToFlush);
1995
+ return { buffer: buffer.slice(safeLen), shouldContinue: true };
1996
+ }
1997
+ return { buffer, shouldContinue: false };
1998
+ }
1999
+ function processToolCallInBuffer(params) {
2000
+ const {
2001
+ buffer,
2002
+ currentToolCall,
2003
+ tools,
2004
+ options,
2005
+ controller,
2006
+ flushText,
2007
+ setBuffer,
2008
+ pipelineConfig,
2009
+ maxReparses
2010
+ } = params;
2011
+ const endTag = `</${currentToolCall.name}>`;
2012
+ const normalized = normalizeCloseTags(buffer);
2013
+ const effectiveBuffer = normalized;
2014
+ const endTagIndex = effectiveBuffer.indexOf(endTag);
2015
+ if (endTagIndex !== -1) {
2016
+ const toolContent = effectiveBuffer.substring(0, endTagIndex);
2017
+ const newBuffer = effectiveBuffer.substring(endTagIndex + endTag.length);
2018
+ setBuffer("");
2019
+ if (pipelineConfig) {
2020
+ handleStreamingToolCallEndWithPipeline({
2021
+ toolContent,
2022
+ currentToolCall,
2023
+ tools,
2024
+ options,
2025
+ ctrl: controller,
2026
+ flushText,
2027
+ pipelineConfig,
2028
+ maxReparses
2029
+ });
2030
+ } else {
2031
+ handleStreamingToolCallEnd({
2032
+ toolContent,
2033
+ currentToolCall,
2034
+ tools,
2035
+ options,
2036
+ ctrl: controller,
2037
+ flushText
2038
+ });
2039
+ }
1408
2040
  setBuffer(newBuffer);
1409
2041
  return { buffer: newBuffer, currentToolCall: null, shouldBreak: false };
1410
2042
  }
1411
- return { buffer, currentToolCall, shouldBreak: true };
2043
+ return { buffer: effectiveBuffer, currentToolCall, shouldBreak: true };
1412
2044
  }
1413
2045
  function processNoToolCallInBuffer(params) {
1414
- const { buffer, toolNames, maxStartTagLen, controller, flushText } = params;
1415
- const { index: earliestStartTagIndex, name: earliestToolName } = findEarliestToolTag(buffer, toolNames);
2046
+ const {
2047
+ buffer,
2048
+ toolNames,
2049
+ maxStartTagLen,
2050
+ controller,
2051
+ flushText,
2052
+ tools,
2053
+ options,
2054
+ pipelineConfig,
2055
+ maxReparses
2056
+ } = params;
2057
+ const {
2058
+ index: earliestStartTagIndex,
2059
+ name: earliestToolName,
2060
+ selfClosing
2061
+ } = findEarliestToolTag(buffer, toolNames);
1416
2062
  if (earliestStartTagIndex !== -1) {
1417
2063
  const textBeforeTag = buffer.substring(0, earliestStartTagIndex);
1418
2064
  flushText(controller, textBeforeTag);
2065
+ if (selfClosing) {
2066
+ const selfTag = `<${earliestToolName}/>`;
2067
+ const newBuffer2 = buffer.substring(
2068
+ earliestStartTagIndex + selfTag.length
2069
+ );
2070
+ if (pipelineConfig) {
2071
+ handleStreamingToolCallEndWithPipeline({
2072
+ toolContent: "",
2073
+ currentToolCall: { name: earliestToolName, content: "" },
2074
+ tools,
2075
+ options,
2076
+ ctrl: controller,
2077
+ flushText,
2078
+ pipelineConfig,
2079
+ maxReparses
2080
+ });
2081
+ } else {
2082
+ handleStreamingToolCallEnd({
2083
+ toolContent: "",
2084
+ currentToolCall: { name: earliestToolName, content: "" },
2085
+ tools,
2086
+ options,
2087
+ ctrl: controller,
2088
+ flushText
2089
+ });
2090
+ }
2091
+ return {
2092
+ buffer: newBuffer2,
2093
+ currentToolCall: null,
2094
+ shouldBreak: false,
2095
+ shouldContinue: false
2096
+ };
2097
+ }
1419
2098
  const startTag = `<${earliestToolName}>`;
1420
2099
  const newBuffer = buffer.substring(earliestStartTagIndex + startTag.length);
1421
2100
  return {
@@ -1444,7 +2123,7 @@ function createFlushTextHandler(getBuffer, setBuffer, getCurrentTextId, setCurre
1444
2123
  if (content) {
1445
2124
  const currentTextId2 = getCurrentTextId();
1446
2125
  if (!currentTextId2) {
1447
- const newId = (0, import_provider_utils3.generateId)();
2126
+ const newId = (0, import_provider_utils2.generateId)();
1448
2127
  setCurrentTextId(newId);
1449
2128
  controller.enqueue({ type: "text-start", id: newId });
1450
2129
  }
@@ -1472,7 +2151,9 @@ function processBufferWithToolCall(params, controller) {
1472
2151
  setCurrentToolCall,
1473
2152
  tools,
1474
2153
  options,
1475
- flushText
2154
+ flushText,
2155
+ pipelineConfig,
2156
+ maxReparses
1476
2157
  } = params;
1477
2158
  const currentToolCall = getCurrentToolCall();
1478
2159
  if (!currentToolCall) {
@@ -1485,7 +2166,9 @@ function processBufferWithToolCall(params, controller) {
1485
2166
  options,
1486
2167
  controller,
1487
2168
  flushText,
1488
- setBuffer
2169
+ setBuffer,
2170
+ pipelineConfig,
2171
+ maxReparses
1489
2172
  });
1490
2173
  setBuffer(result.buffer);
1491
2174
  setCurrentToolCall(result.currentToolCall);
@@ -1496,16 +2179,24 @@ function processBufferWithoutToolCall(params, controller) {
1496
2179
  getBuffer,
1497
2180
  setBuffer,
1498
2181
  setCurrentToolCall,
2182
+ tools,
2183
+ options,
1499
2184
  toolNames,
1500
2185
  maxStartTagLen,
1501
- flushText
2186
+ flushText,
2187
+ pipelineConfig,
2188
+ maxReparses
1502
2189
  } = params;
1503
2190
  const result = processNoToolCallInBuffer({
1504
2191
  buffer: getBuffer(),
1505
2192
  toolNames,
1506
2193
  maxStartTagLen,
1507
2194
  controller,
1508
- flushText
2195
+ flushText,
2196
+ tools,
2197
+ options,
2198
+ pipelineConfig,
2199
+ maxReparses
1509
2200
  });
1510
2201
  setBuffer(result.buffer);
1511
2202
  setCurrentToolCall(result.currentToolCall);
@@ -1525,196 +2216,427 @@ function processBufferLoop(params, controller) {
1525
2216
  } else {
1526
2217
  const { shouldBreak, shouldContinue } = processBufferWithoutToolCall(
1527
2218
  params,
1528
- controller
1529
- );
1530
- if (shouldContinue) {
1531
- continue;
1532
- }
1533
- if (shouldBreak) {
1534
- break;
1535
- }
1536
- }
1537
- }
1538
- }
1539
- function createProcessBufferHandler(params) {
1540
- return (controller) => {
1541
- processBufferLoop(params, controller);
1542
- };
1543
- }
1544
- var morphXmlProtocol = () => ({
1545
- formatTools({ tools, toolSystemPromptTemplate }) {
1546
- const toolsForPrompt = (tools || []).map((tool) => ({
1547
- name: tool.name,
1548
- description: tool.description,
1549
- parameters: (0, import_rxml.unwrapJsonSchema)(tool.inputSchema)
1550
- }));
1551
- return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1552
- },
1553
- formatToolCall(toolCall) {
1554
- let args = {};
1555
- const inputValue = hasInputProperty(toolCall) ? toolCall.input : void 0;
1556
- if (typeof inputValue === "string") {
1557
- try {
1558
- args = JSON.parse(inputValue);
1559
- } catch (e) {
1560
- args = inputValue;
1561
- }
1562
- } else {
1563
- args = inputValue;
1564
- }
1565
- return (0, import_rxml.stringify)(toolCall.toolName, args, {
1566
- suppressEmptyNode: false,
1567
- format: false
1568
- });
1569
- },
1570
- formatToolResponse(toolResult) {
1571
- return (0, import_rxml.stringify)("tool_response", {
1572
- tool_name: toolResult.toolName,
1573
- result: toolResult.output
1574
- });
1575
- },
1576
- parseGeneratedText({ text, tools, options }) {
1577
- const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1578
- if (toolNames.length === 0) {
1579
- return [{ type: "text", text }];
1580
- }
1581
- const processedElements = [];
1582
- let currentIndex = 0;
1583
- const toolCalls = findToolCalls(text, toolNames);
1584
- for (const toolCall of toolCalls) {
1585
- currentIndex = processTextBeforeToolCall(
1586
- text,
1587
- currentIndex,
1588
- toolCall.startIndex,
1589
- processedElements
1590
- );
1591
- processToolCall({ toolCall, tools, options, text, processedElements });
1592
- currentIndex = toolCall.endIndex;
1593
- }
1594
- addRemainingText(text, currentIndex, processedElements);
1595
- return processedElements;
1596
- },
1597
- createStreamParser({ tools, options }) {
1598
- const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1599
- const maxStartTagLen = toolNames.length ? Math.max(...toolNames.map((n) => `<${n}>`.length)) : 0;
1600
- let buffer = "";
1601
- let currentToolCall = null;
1602
- let currentTextId = null;
1603
- const flushText = createFlushTextHandler(
1604
- () => buffer,
1605
- (newBuffer) => {
1606
- buffer = newBuffer;
1607
- },
1608
- () => currentTextId,
1609
- (newId) => {
1610
- currentTextId = newId;
2219
+ controller
2220
+ );
2221
+ if (shouldContinue) {
2222
+ continue;
1611
2223
  }
1612
- );
1613
- const processChunk = (chunk, controller) => {
1614
- if (chunk.type !== "text-delta") {
1615
- if (buffer) {
1616
- flushText(controller);
1617
- }
1618
- controller.enqueue(chunk);
1619
- return;
2224
+ if (shouldBreak) {
2225
+ break;
1620
2226
  }
1621
- buffer += chunk.delta;
1622
- processBuffer(controller);
2227
+ }
2228
+ }
2229
+ }
2230
+ function createProcessBufferHandler(params) {
2231
+ return (controller) => {
2232
+ processBufferLoop(params, controller);
2233
+ };
2234
+ }
2235
+ function buildPipelineOptions(protocolOptions) {
2236
+ var _a, _b, _c;
2237
+ const maxReparses = protocolOptions == null ? void 0 : protocolOptions.maxReparses;
2238
+ if (protocolOptions == null ? void 0 : protocolOptions.pipeline) {
2239
+ return {
2240
+ pipelineConfig: mergePipelineConfigs2(
2241
+ defaultPipelineConfig2,
2242
+ protocolOptions.pipeline
2243
+ ),
2244
+ maxReparses
1623
2245
  };
1624
- const processBuffer = createProcessBufferHandler({
1625
- getBuffer: () => buffer,
1626
- setBuffer: (newBuffer) => {
1627
- buffer = newBuffer;
1628
- },
1629
- getCurrentToolCall: () => currentToolCall,
1630
- setCurrentToolCall: (newToolCall) => {
1631
- currentToolCall = newToolCall;
2246
+ }
2247
+ if (protocolOptions == null ? void 0 : protocolOptions.heuristics) {
2248
+ return {
2249
+ pipelineConfig: {
2250
+ ...defaultPipelineConfig2,
2251
+ preParse: [
2252
+ ...(_a = defaultPipelineConfig2.preParse) != null ? _a : [],
2253
+ ...protocolOptions.heuristics.filter((h) => h.phase === "pre-parse")
2254
+ ],
2255
+ fallbackReparse: [
2256
+ ...(_b = defaultPipelineConfig2.fallbackReparse) != null ? _b : [],
2257
+ ...protocolOptions.heuristics.filter(
2258
+ (h) => h.phase === "fallback-reparse"
2259
+ )
2260
+ ],
2261
+ postParse: [
2262
+ ...(_c = defaultPipelineConfig2.postParse) != null ? _c : [],
2263
+ ...protocolOptions.heuristics.filter((h) => h.phase === "post-parse")
2264
+ ]
1632
2265
  },
1633
- tools,
1634
- options,
1635
- toolNames,
1636
- maxStartTagLen,
1637
- flushText
1638
- });
1639
- const flushBuffer2 = (controller) => {
1640
- if (currentToolCall) {
1641
- const unfinishedCall = `<${currentToolCall.name}>${buffer}`;
1642
- flushText(controller, unfinishedCall);
1643
- } else if (buffer) {
1644
- flushText(controller);
2266
+ maxReparses
2267
+ };
2268
+ }
2269
+ return { pipelineConfig: void 0, maxReparses };
2270
+ }
2271
+ var morphXmlProtocol = (protocolOptions) => {
2272
+ const { pipelineConfig, maxReparses } = buildPipelineOptions(protocolOptions);
2273
+ return {
2274
+ formatTools({ tools, toolSystemPromptTemplate }) {
2275
+ const toolsForPrompt = (tools || []).map((tool) => ({
2276
+ name: tool.name,
2277
+ description: tool.description,
2278
+ parameters: (0, import_rxml2.unwrapJsonSchema)(tool.inputSchema)
2279
+ }));
2280
+ return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
2281
+ },
2282
+ formatToolCall(toolCall) {
2283
+ let args = {};
2284
+ const inputValue = hasInputProperty(toolCall) ? toolCall.input : void 0;
2285
+ if (typeof inputValue === "string") {
2286
+ try {
2287
+ args = JSON.parse(inputValue);
2288
+ } catch (e) {
2289
+ args = inputValue;
2290
+ }
2291
+ } else {
2292
+ args = inputValue;
1645
2293
  }
1646
- if (currentTextId) {
1647
- controller.enqueue({ type: "text-end", id: currentTextId });
2294
+ return (0, import_rxml2.stringify)(toolCall.toolName, args, {
2295
+ suppressEmptyNode: false,
2296
+ format: false
2297
+ });
2298
+ },
2299
+ formatToolResponse(toolResult) {
2300
+ return (0, import_rxml2.stringify)("tool_response", {
2301
+ tool_name: toolResult.toolName,
2302
+ result: toolResult.output
2303
+ });
2304
+ },
2305
+ parseGeneratedText({ text, tools, options }) {
2306
+ const toolNames = tools.map((t) => t.name).filter((name) => name != null);
2307
+ if (toolNames.length === 0) {
2308
+ return [{ type: "text", text }];
1648
2309
  }
1649
- };
1650
- return new TransformStream({
1651
- transform(chunk, controller) {
1652
- processChunk(chunk, controller);
1653
- },
1654
- flush(controller) {
1655
- flushBuffer2(controller);
2310
+ const processedElements = [];
2311
+ let currentIndex = 0;
2312
+ const toolCallsRaw = findToolCalls(text, toolNames);
2313
+ const toolCallsNorm = collectToolCallsFromNormalizedText(text, toolNames);
2314
+ const seen = /* @__PURE__ */ new Set();
2315
+ const toolCalls = [...toolCallsRaw, ...toolCallsNorm].filter((tc) => {
2316
+ const key = `${tc.toolName}:${tc.startIndex}:${tc.endIndex}`;
2317
+ if (seen.has(key)) {
2318
+ return false;
2319
+ }
2320
+ seen.add(key);
2321
+ return true;
2322
+ }).sort((a, b) => a.startIndex - b.startIndex);
2323
+ for (const toolCall of toolCalls) {
2324
+ currentIndex = processTextBeforeToolCall(
2325
+ text,
2326
+ currentIndex,
2327
+ toolCall.startIndex,
2328
+ processedElements
2329
+ );
2330
+ if (pipelineConfig) {
2331
+ processToolCallWithPipeline({
2332
+ toolCall,
2333
+ tools,
2334
+ options,
2335
+ text,
2336
+ processedElements,
2337
+ pipelineConfig,
2338
+ maxReparses
2339
+ });
2340
+ } else {
2341
+ processToolCall({
2342
+ toolCall,
2343
+ tools,
2344
+ options,
2345
+ text,
2346
+ processedElements
2347
+ });
2348
+ }
2349
+ currentIndex = toolCall.endIndex;
1656
2350
  }
1657
- });
1658
- },
1659
- extractToolCallSegments({ text, tools }) {
1660
- const toolNames = tools.map((t) => t.name).filter(Boolean);
1661
- if (toolNames.length === 0) {
1662
- return [];
2351
+ addRemainingText(text, currentIndex, processedElements);
2352
+ return processedElements;
2353
+ },
2354
+ createStreamParser({ tools, options }) {
2355
+ const toolNames = tools.map((t) => t.name).filter((name) => name != null);
2356
+ const maxStartTagLen = toolNames.length ? Math.max(...toolNames.map((n) => `<${n}>`.length)) : 0;
2357
+ let buffer = "";
2358
+ let currentToolCall = null;
2359
+ let currentTextId = null;
2360
+ const flushText = createFlushTextHandler(
2361
+ () => buffer,
2362
+ (newBuffer) => {
2363
+ buffer = newBuffer;
2364
+ },
2365
+ () => currentTextId,
2366
+ (newId) => {
2367
+ currentTextId = newId;
2368
+ }
2369
+ );
2370
+ const processChunk = (chunk, controller) => {
2371
+ if (chunk.type !== "text-delta") {
2372
+ if (buffer) {
2373
+ flushText(controller);
2374
+ }
2375
+ controller.enqueue(chunk);
2376
+ return;
2377
+ }
2378
+ buffer += chunk.delta;
2379
+ processBuffer(controller);
2380
+ };
2381
+ const processBuffer = createProcessBufferHandler({
2382
+ getBuffer: () => buffer,
2383
+ setBuffer: (newBuffer) => {
2384
+ buffer = newBuffer;
2385
+ },
2386
+ getCurrentToolCall: () => currentToolCall,
2387
+ setCurrentToolCall: (newToolCall) => {
2388
+ currentToolCall = newToolCall;
2389
+ },
2390
+ tools,
2391
+ options,
2392
+ toolNames,
2393
+ maxStartTagLen,
2394
+ flushText,
2395
+ pipelineConfig,
2396
+ maxReparses
2397
+ });
2398
+ const flushBuffer2 = (controller) => {
2399
+ if (currentToolCall) {
2400
+ const unfinishedCall = `<${currentToolCall.name}>${buffer}`;
2401
+ flushText(controller, unfinishedCall);
2402
+ } else if (buffer) {
2403
+ flushText(controller);
2404
+ }
2405
+ if (currentTextId) {
2406
+ controller.enqueue({ type: "text-end", id: currentTextId });
2407
+ }
2408
+ };
2409
+ return new TransformStream({
2410
+ transform(chunk, controller) {
2411
+ processChunk(chunk, controller);
2412
+ },
2413
+ flush(controller) {
2414
+ flushBuffer2(controller);
2415
+ }
2416
+ });
2417
+ },
2418
+ extractToolCallSegments({ text, tools }) {
2419
+ const toolNames = tools.map((t) => t.name).filter(Boolean);
2420
+ if (toolNames.length === 0) {
2421
+ return [];
2422
+ }
2423
+ return findToolCalls(text, toolNames).map((tc) => tc.segment);
1663
2424
  }
1664
- return findToolCalls(text, toolNames).map((tc) => tc.segment);
1665
- }
1666
- });
2425
+ };
2426
+ };
1667
2427
  function getToolSchema(tools, toolName) {
1668
2428
  var _a;
1669
2429
  return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
1670
2430
  }
1671
- function computeFullTagEnd(text, contentEnd, toolName) {
1672
- let fullTagEnd = contentEnd + `</${toolName}>`.length;
1673
- const closeHead = text.indexOf(`</${toolName}`, contentEnd);
1674
- if (closeHead === contentEnd) {
1675
- let p = closeHead + 2 + toolName.length;
1676
- while (p < text.length && WHITESPACE_REGEX2.test(text[p])) {
2431
+ function findClosingTagEndFlexible(text, contentStart, toolName) {
2432
+ let pos = contentStart;
2433
+ let depth = 1;
2434
+ while (pos < text.length) {
2435
+ const tok = nextTagToken(text, pos);
2436
+ if (tok.kind === "eof") {
2437
+ break;
2438
+ }
2439
+ const result = updateDepthWithToken(tok, toolName, depth);
2440
+ depth = result.depth;
2441
+ if (result.closedAt !== void 0) {
2442
+ return result.closedAt;
2443
+ }
2444
+ pos = tok.nextPos;
2445
+ }
2446
+ return -1;
2447
+ }
2448
+ function skipSpecialSegment(text, lt) {
2449
+ const next = text[lt + 1];
2450
+ if (next !== "!" && next !== "?") {
2451
+ return null;
2452
+ }
2453
+ const gt = text.indexOf(">", lt + 1);
2454
+ if (gt === -1) {
2455
+ return null;
2456
+ }
2457
+ return gt + 1;
2458
+ }
2459
+ function consumeClosingTag(text, lt, _toolName) {
2460
+ let p = lt + 2;
2461
+ while (p < text.length && WHITESPACE_REGEX3.test(text[p])) {
2462
+ p += 1;
2463
+ }
2464
+ const gt = text.indexOf(">", lt + 1);
2465
+ const endPos = gt === -1 ? text.length : gt + 1;
2466
+ return { matched: false, endPos };
2467
+ }
2468
+ function consumeOpenTag(text, lt) {
2469
+ let p = lt + 1;
2470
+ while (p < text.length && WHITESPACE_REGEX3.test(text[p])) {
2471
+ p += 1;
2472
+ }
2473
+ const nameStart = p;
2474
+ while (p < text.length && NAME_CHAR_RE2.test(text.charAt(p))) {
2475
+ p += 1;
2476
+ }
2477
+ const name = text.slice(nameStart, p);
2478
+ const q = text.indexOf(">", p);
2479
+ if (q === -1) {
2480
+ return null;
2481
+ }
2482
+ let r = q - 1;
2483
+ while (r >= nameStart && WHITESPACE_REGEX3.test(text[r])) {
2484
+ r -= 1;
2485
+ }
2486
+ const selfClosing = text[r] === "/";
2487
+ return { name, selfClosing, nextPos: q + 1 };
2488
+ }
2489
+ function updateDepthWithToken(tok, toolName, depth) {
2490
+ if (tok.kind === "close" && tok.name === toolName) {
2491
+ const newDepth = depth - 1;
2492
+ return newDepth === 0 ? { depth: newDepth, closedAt: tok.nextPos } : { depth: newDepth };
2493
+ }
2494
+ if (tok.kind === "open" && tok.name === toolName && !tok.selfClosing) {
2495
+ return { depth: depth + 1 };
2496
+ }
2497
+ return { depth };
2498
+ }
2499
+ function nextTagToken(text, fromPos) {
2500
+ const lt = text.indexOf("<", fromPos);
2501
+ if (lt === -1 || lt + 1 >= text.length) {
2502
+ return { kind: "eof", nextPos: text.length };
2503
+ }
2504
+ const next = text[lt + 1];
2505
+ const specialEnd = skipSpecialSegment(text, lt);
2506
+ if (specialEnd !== null) {
2507
+ return { kind: "special", nextPos: specialEnd };
2508
+ }
2509
+ if (next === "/") {
2510
+ const closing = consumeClosingTag(text, lt, "");
2511
+ let p = lt + 2;
2512
+ while (p < text.length && WHITESPACE_REGEX3.test(text[p])) {
1677
2513
  p += 1;
1678
2514
  }
1679
- if (text[p] === ">") {
1680
- fullTagEnd = p + 1;
2515
+ const nameStart = p;
2516
+ while (p < text.length && NAME_CHAR_RE2.test(text.charAt(p))) {
2517
+ p += 1;
1681
2518
  }
2519
+ const name = text.slice(nameStart, p);
2520
+ return { kind: "close", name, nextPos: closing.endPos };
2521
+ }
2522
+ const open = consumeOpenTag(text, lt);
2523
+ if (open === null) {
2524
+ return { kind: "eof", nextPos: text.length };
1682
2525
  }
1683
- return fullTagEnd;
2526
+ return {
2527
+ kind: "open",
2528
+ name: open.name,
2529
+ selfClosing: open.selfClosing,
2530
+ nextPos: open.nextPos
2531
+ };
1684
2532
  }
1685
- function extractToolCallInfo(text, tagStart, toolName, range) {
2533
+ function collectToolCallsFromNormalizedText(text, toolNames) {
1686
2534
  var _a;
2535
+ const normalizedText = normalizeCloseTags(text);
2536
+ const collected = [];
2537
+ for (const toolName of toolNames) {
2538
+ const startTag = `<${toolName}>`;
2539
+ let idx = 0;
2540
+ let lastOrigIdx = 0;
2541
+ while (idx < normalizedText.length) {
2542
+ const tagStartNorm = normalizedText.indexOf(startTag, idx);
2543
+ if (tagStartNorm === -1) {
2544
+ break;
2545
+ }
2546
+ const contentStartNorm = tagStartNorm + startTag.length;
2547
+ const endNorm = findClosingTagEndFlexible(
2548
+ normalizedText,
2549
+ contentStartNorm,
2550
+ toolName
2551
+ );
2552
+ if (endNorm > contentStartNorm) {
2553
+ const tagStartOrig = text.indexOf(startTag, lastOrigIdx);
2554
+ const contentStartOrig = tagStartOrig + startTag.length;
2555
+ let endOrig = findClosingTagEndFlexible(
2556
+ text,
2557
+ contentStartOrig,
2558
+ toolName
2559
+ );
2560
+ if (endOrig === -1) {
2561
+ const approxLen = endNorm - tagStartNorm;
2562
+ endOrig = Math.min(text.length, tagStartOrig + approxLen);
2563
+ }
2564
+ const segment = text.substring(tagStartOrig, endOrig);
2565
+ const inner = (_a = (0, import_rxml2.extractRawInner)(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2566
+ collected.push({
2567
+ toolName,
2568
+ startIndex: tagStartOrig,
2569
+ endIndex: endOrig,
2570
+ content: inner,
2571
+ segment
2572
+ });
2573
+ lastOrigIdx = endOrig;
2574
+ idx = endNorm;
2575
+ } else {
2576
+ idx = contentStartNorm;
2577
+ }
2578
+ }
2579
+ }
2580
+ return collected.sort((a, b) => a.startIndex - b.startIndex);
2581
+ }
2582
+ function getNextTagInfo(text, toolName, fromIndex) {
1687
2583
  const startTag = `<${toolName}>`;
1688
- const contentStart = tagStart + startTag.length;
1689
- const contentEnd = contentStart + (range.end - range.start);
1690
- const fullTagEnd = computeFullTagEnd(text, contentEnd, toolName);
1691
- const segment = text.substring(tagStart, fullTagEnd);
1692
- const content = (_a = (0, import_rxml.extractRawInner)(segment, toolName)) != null ? _a : text.substring(contentStart, contentEnd);
1693
- return {
1694
- toolName,
1695
- startIndex: tagStart,
1696
- endIndex: fullTagEnd,
1697
- content,
1698
- segment
1699
- };
2584
+ const selfTag = `<${toolName}/>`;
2585
+ const openIdx = text.indexOf(startTag, fromIndex);
2586
+ const selfIdx = text.indexOf(selfTag, fromIndex);
2587
+ const hasOpen = openIdx !== -1;
2588
+ const hasSelf = selfIdx !== -1;
2589
+ if (!(hasOpen || hasSelf)) {
2590
+ return {
2591
+ found: false,
2592
+ tagStart: -1,
2593
+ selfClosing: false,
2594
+ startTag,
2595
+ selfTag
2596
+ };
2597
+ }
2598
+ const pickSelf = hasSelf && (!hasOpen || selfIdx < openIdx);
2599
+ const tagStart = pickSelf ? selfIdx : openIdx;
2600
+ return { found: true, tagStart, selfClosing: pickSelf, startTag, selfTag };
1700
2601
  }
1701
2602
  function findToolCallsForName(text, toolName) {
2603
+ var _a;
1702
2604
  const toolCalls = [];
1703
- const startTag = `<${toolName}>`;
1704
2605
  let searchIndex = 0;
1705
2606
  while (searchIndex < text.length) {
1706
- const tagStart = text.indexOf(startTag, searchIndex);
1707
- if (tagStart === -1) {
2607
+ const info = getNextTagInfo(text, toolName, searchIndex);
2608
+ if (!info.found) {
1708
2609
  break;
1709
2610
  }
1710
- const remainingText = text.substring(tagStart);
1711
- const range = (0, import_rxml.findFirstTopLevelRange)(remainingText, toolName);
1712
- if (range) {
1713
- const toolCallInfo = extractToolCallInfo(text, tagStart, toolName, range);
1714
- toolCalls.push(toolCallInfo);
1715
- searchIndex = toolCallInfo.endIndex;
2611
+ const { tagStart, selfClosing, startTag, selfTag } = info;
2612
+ if (selfClosing) {
2613
+ const endIndex = tagStart + selfTag.length;
2614
+ const segment = text.substring(tagStart, endIndex);
2615
+ toolCalls.push({
2616
+ toolName,
2617
+ startIndex: tagStart,
2618
+ endIndex,
2619
+ content: "",
2620
+ segment
2621
+ });
2622
+ searchIndex = endIndex;
2623
+ continue;
2624
+ }
2625
+ const contentStart = tagStart + startTag.length;
2626
+ const fullTagEnd = findClosingTagEndFlexible(text, contentStart, toolName);
2627
+ if (fullTagEnd !== -1 && fullTagEnd > contentStart) {
2628
+ const segment = text.substring(tagStart, fullTagEnd);
2629
+ const inner = (_a = (0, import_rxml2.extractRawInner)(segment, toolName)) != null ? _a : segment.substring(startTag.length, segment.lastIndexOf("<"));
2630
+ toolCalls.push({
2631
+ toolName,
2632
+ startIndex: tagStart,
2633
+ endIndex: fullTagEnd,
2634
+ content: inner,
2635
+ segment
2636
+ });
2637
+ searchIndex = fullTagEnd;
1716
2638
  } else {
1717
- searchIndex = tagStart + startTag.length;
2639
+ searchIndex = contentStart;
1718
2640
  }
1719
2641
  }
1720
2642
  return toolCalls;
@@ -1728,14 +2650,53 @@ function findToolCalls(text, toolNames) {
1728
2650
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
1729
2651
  }
1730
2652
 
1731
- // src/protocols/tool-call-protocol.ts
1732
- function isProtocolFactory(protocol) {
1733
- return typeof protocol === "function";
2653
+ // src/generate-handler.ts
2654
+ var import_provider_utils3 = require("@ai-sdk/provider-utils");
2655
+ var import_rxml3 = require("@ai-sdk-tool/rxml");
2656
+
2657
+ // src/utils/on-error.ts
2658
+ function extractOnErrorOption(providerOptions) {
2659
+ var _a;
2660
+ if (providerOptions && typeof providerOptions === "object") {
2661
+ const onError = (_a = providerOptions.toolCallMiddleware) == null ? void 0 : _a.onError;
2662
+ return onError ? { onError } : void 0;
2663
+ }
2664
+ return;
2665
+ }
2666
+
2667
+ // src/utils/provider-options.ts
2668
+ var originalToolsSchema = {
2669
+ encode: encodeOriginalTools,
2670
+ decode: decodeOriginalTools
2671
+ };
2672
+ function encodeOriginalTools(tools) {
2673
+ return (tools == null ? void 0 : tools.map((t) => ({
2674
+ name: t.name,
2675
+ inputSchema: JSON.stringify(t.inputSchema)
2676
+ }))) || [];
2677
+ }
2678
+ function decodeOriginalTools(originalTools) {
2679
+ if (!originalTools) {
2680
+ return [];
2681
+ }
2682
+ return originalTools.map(
2683
+ (t) => ({
2684
+ type: "function",
2685
+ name: t.name,
2686
+ inputSchema: JSON.parse(t.inputSchema)
2687
+ })
2688
+ );
2689
+ }
2690
+ function extractToolNamesFromOriginalTools(originalTools) {
2691
+ return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
2692
+ }
2693
+ function isToolChoiceActive(params) {
2694
+ var _a, _b, _c;
2695
+ const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
2696
+ 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"));
1734
2697
  }
1735
2698
 
1736
2699
  // src/generate-handler.ts
1737
- var import_provider_utils4 = require("@ai-sdk/provider-utils");
1738
- var import_rxml2 = require("@ai-sdk-tool/rxml");
1739
2700
  function parseToolChoiceJson(text, providerOptions) {
1740
2701
  var _a;
1741
2702
  try {
@@ -1779,7 +2740,7 @@ async function handleToolChoice(doGenerate, params) {
1779
2740
  }
1780
2741
  const toolCall = {
1781
2742
  type: "tool-call",
1782
- toolCallId: (0, import_provider_utils4.generateId)(),
2743
+ toolCallId: (0, import_provider_utils3.generateId)(),
1783
2744
  toolName: parsed.name || "unknown",
1784
2745
  input: JSON.stringify(parsed.arguments || {})
1785
2746
  };
@@ -1898,15 +2859,20 @@ function fixToolCallWithSchema(part, tools) {
1898
2859
  args = tc.input;
1899
2860
  }
1900
2861
  const schema = (_a = tools.find((t) => t.name === tc.toolName)) == null ? void 0 : _a.inputSchema;
1901
- const coerced = (0, import_rxml2.coerceBySchema)(args, schema);
2862
+ const coerced = (0, import_rxml3.coerceBySchema)(args, schema);
1902
2863
  return {
1903
2864
  ...part,
1904
2865
  input: JSON.stringify(coerced != null ? coerced : {})
1905
2866
  };
1906
2867
  }
1907
2868
 
2869
+ // src/protocols/tool-call-protocol.ts
2870
+ function isProtocolFactory(protocol) {
2871
+ return typeof protocol === "function";
2872
+ }
2873
+
1908
2874
  // src/stream-handler.ts
1909
- var import_provider_utils5 = require("@ai-sdk/provider-utils");
2875
+ var import_provider_utils4 = require("@ai-sdk/provider-utils");
1910
2876
  function extractToolCallSegments(protocol, fullRawText, tools) {
1911
2877
  const segments = protocol.extractToolCallSegments ? protocol.extractToolCallSegments({
1912
2878
  text: fullRawText,
@@ -1943,7 +2909,7 @@ function handleDebugSummary(parsedToolCalls, origin, params) {
1943
2909
  }
1944
2910
  function createDebugSummaryTransform({
1945
2911
  protocol,
1946
- fullRawText,
2912
+ getFullRawText,
1947
2913
  tools,
1948
2914
  params
1949
2915
  }) {
@@ -1956,11 +2922,9 @@ function createDebugSummaryTransform({
1956
2922
  }
1957
2923
  if (part.type === "finish") {
1958
2924
  try {
1959
- const origin = extractToolCallSegments(
1960
- protocol,
1961
- fullRawText,
1962
- tools
1963
- );
2925
+ const raw = getFullRawText();
2926
+ logRawChunk(raw);
2927
+ const origin = extractToolCallSegments(protocol, raw, tools);
1964
2928
  handleDebugSummary(parsedToolCalls, origin, params);
1965
2929
  } catch (e) {
1966
2930
  }
@@ -2058,7 +3022,7 @@ async function wrapStream({
2058
3022
  const withSummary = parsed.pipeThrough(
2059
3023
  createDebugSummaryTransform({
2060
3024
  protocol,
2061
- fullRawText,
3025
+ getFullRawText: () => fullRawText,
2062
3026
  tools,
2063
3027
  params
2064
3028
  })
@@ -2092,19 +3056,26 @@ async function toolChoiceStream({
2092
3056
  }
2093
3057
  const toolCallChunk = {
2094
3058
  type: "tool-call",
2095
- toolCallId: (0, import_provider_utils5.generateId)(),
3059
+ toolCallId: (0, import_provider_utils4.generateId)(),
2096
3060
  toolName: toolJson.name || "unknown",
2097
3061
  input: JSON.stringify(toolJson.arguments || {})
2098
3062
  };
2099
3063
  const finishChunk = {
2100
3064
  type: "finish",
2101
- usage: (result == null ? void 0 : result.usage) || // TODO: If possible, try to return a certain amount of LLM usage.
2102
- {
2103
- inputTokens: 0,
2104
- outputTokens: 0,
2105
- totalTokens: 0
3065
+ usage: (result == null ? void 0 : result.usage) || {
3066
+ inputTokens: {
3067
+ total: 0,
3068
+ noCache: void 0,
3069
+ cacheRead: void 0,
3070
+ cacheWrite: void 0
3071
+ },
3072
+ outputTokens: {
3073
+ total: 0,
3074
+ text: void 0,
3075
+ reasoning: void 0
3076
+ }
2106
3077
  },
2107
- finishReason: "tool-calls"
3078
+ finishReason: { unified: "tool-calls", raw: void 0 }
2108
3079
  };
2109
3080
  const stream = new ReadableStream({
2110
3081
  start(controller) {
@@ -2138,26 +3109,106 @@ async function toolChoiceStream({
2138
3109
  };
2139
3110
  }
2140
3111
 
3112
+ // src/utils/dynamic-tool-schema.ts
3113
+ function createDynamicIfThenElseSchema(tools) {
3114
+ let currentSchema = {};
3115
+ const toolNames = [];
3116
+ for (let i = tools.length - 1; i >= 0; i -= 1) {
3117
+ const tool = tools[i];
3118
+ if (tool.type === "provider") {
3119
+ throw new Error(
3120
+ "Provider tools are not supported by this middleware. Please use function tools."
3121
+ );
3122
+ }
3123
+ toolNames.unshift(tool.name);
3124
+ const toolCondition = {
3125
+ if: {
3126
+ properties: {
3127
+ name: {
3128
+ const: tool.name
3129
+ }
3130
+ },
3131
+ required: ["name"]
3132
+ },
3133
+ // biome-ignore lint/suspicious/noThenProperty: JSON Schema uses 'then' as a keyword
3134
+ then: {
3135
+ properties: {
3136
+ name: {
3137
+ const: tool.name
3138
+ },
3139
+ arguments: tool.inputSchema
3140
+ },
3141
+ required: ["name", "arguments"]
3142
+ }
3143
+ };
3144
+ if (Object.keys(currentSchema).length > 0) {
3145
+ toolCondition.else = currentSchema;
3146
+ }
3147
+ currentSchema = toolCondition;
3148
+ }
3149
+ return {
3150
+ type: "object",
3151
+ // Explicitly specify type as "object"
3152
+ properties: {
3153
+ name: {
3154
+ type: "string",
3155
+ description: "Name of the tool to call",
3156
+ enum: toolNames
3157
+ },
3158
+ arguments: {
3159
+ type: "object",
3160
+ // By default, arguments is also specified as object type
3161
+ description: "Argument object to be passed to the tool"
3162
+ }
3163
+ },
3164
+ required: ["name", "arguments"],
3165
+ ...currentSchema
3166
+ };
3167
+ }
3168
+
2141
3169
  // src/transform-handler.ts
2142
- function buildFinalPrompt(systemPrompt, processedPrompt) {
2143
- var _a;
2144
- if (((_a = processedPrompt[0]) == null ? void 0 : _a.role) === "system") {
3170
+ function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
3171
+ const systemIndex = processedPrompt.findIndex((m) => m.role === "system");
3172
+ if (systemIndex !== -1) {
3173
+ const existing = processedPrompt[systemIndex].content;
3174
+ let existingText = "";
3175
+ if (typeof existing === "string") {
3176
+ existingText = existing;
3177
+ } else if (Array.isArray(existing)) {
3178
+ existingText = existing.map((p) => {
3179
+ var _a;
3180
+ return (p == null ? void 0 : p.type) === "text" ? (_a = p.text) != null ? _a : "" : "";
3181
+ }).filter(Boolean).join("\n");
3182
+ } else {
3183
+ existingText = String(existing != null ? existing : "");
3184
+ }
3185
+ const mergedContent = placement === "first" ? `${systemPrompt}
3186
+
3187
+ ${existingText}` : `${existingText}
3188
+
3189
+ ${systemPrompt}`;
3190
+ return processedPrompt.map(
3191
+ (m, idx) => idx === systemIndex ? {
3192
+ ...m,
3193
+ content: mergedContent
3194
+ } : m
3195
+ );
3196
+ }
3197
+ if (placement === "first") {
2145
3198
  return [
2146
3199
  {
2147
3200
  role: "system",
2148
- content: `${systemPrompt}
2149
-
2150
- ${processedPrompt[0].content}`
3201
+ content: systemPrompt
2151
3202
  },
2152
- ...processedPrompt.slice(1)
3203
+ ...processedPrompt
2153
3204
  ];
2154
3205
  }
2155
3206
  return [
3207
+ ...processedPrompt,
2156
3208
  {
2157
3209
  role: "system",
2158
3210
  content: systemPrompt
2159
- },
2160
- ...processedPrompt
3211
+ }
2161
3212
  ];
2162
3213
  }
2163
3214
  function buildBaseReturnParams(params, finalPrompt, functionTools) {
@@ -2257,7 +3308,8 @@ function handleToolChoiceRequired(params, baseReturnParams, functionTools) {
2257
3308
  function transformParams({
2258
3309
  params,
2259
3310
  protocol,
2260
- toolSystemPromptTemplate
3311
+ toolSystemPromptTemplate,
3312
+ placement = "first"
2261
3313
  }) {
2262
3314
  var _a, _b, _c, _d, _e;
2263
3315
  const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
@@ -2273,7 +3325,11 @@ function transformParams({
2273
3325
  resolvedProtocol,
2274
3326
  extractOnErrorOption(params.providerOptions)
2275
3327
  );
2276
- const finalPrompt = buildFinalPrompt(systemPrompt, processedPrompt);
3328
+ const finalPrompt = buildFinalPrompt(
3329
+ systemPrompt,
3330
+ processedPrompt,
3331
+ placement
3332
+ );
2277
3333
  const baseReturnParams = buildBaseReturnParams(
2278
3334
  params,
2279
3335
  finalPrompt,
@@ -2350,7 +3406,10 @@ function processMessage(message, resolvedProtocol, providerOptions) {
2350
3406
  };
2351
3407
  }
2352
3408
  if (message.role === "tool") {
2353
- return processToolMessage(message.content, resolvedProtocol);
3409
+ const toolResultParts = message.content.filter(
3410
+ (part) => part.type === "tool-result"
3411
+ );
3412
+ return processToolMessage(toolResultParts, resolvedProtocol);
2354
3413
  }
2355
3414
  return message;
2356
3415
  }
@@ -2425,7 +3484,8 @@ function convertToolPrompt(prompt, resolvedProtocol, providerOptions) {
2425
3484
  // src/tool-call-middleware.ts
2426
3485
  function createToolMiddleware({
2427
3486
  protocol,
2428
- toolSystemPromptTemplate
3487
+ toolSystemPromptTemplate,
3488
+ placement = "last"
2429
3489
  }) {
2430
3490
  const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
2431
3491
  return {
@@ -2452,6 +3512,7 @@ function createToolMiddleware({
2452
3512
  transformParams: async ({ params }) => transformParams({
2453
3513
  protocol: resolvedProtocol,
2454
3514
  toolSystemPromptTemplate,
3515
+ placement,
2455
3516
  params
2456
3517
  })
2457
3518
  };
@@ -2497,6 +3558,7 @@ For each function call return a json object with function name and arguments wit
2497
3558
  });
2498
3559
  var morphXmlToolMiddleware = createToolMiddleware({
2499
3560
  protocol: morphXmlProtocol,
3561
+ placement: "last",
2500
3562
  toolSystemPromptTemplate(tools) {
2501
3563
  return `You are a function calling AI model.
2502
3564
 
@@ -2520,11 +3582,16 @@ Available functions are listed inside <tools></tools>.
2520
3582
  });
2521
3583
  // Annotate the CommonJS export names for ESM import in node:
2522
3584
  0 && (module.exports = {
2523
- RJSON,
3585
+ applyHeuristicPipeline,
3586
+ balanceTagsHeuristic,
2524
3587
  createDynamicIfThenElseSchema,
3588
+ createIntermediateCall,
2525
3589
  createToolMiddleware,
2526
3590
  decodeOriginalTools,
3591
+ dedupeShellStringTagsHeuristic,
3592
+ defaultPipelineConfig,
2527
3593
  encodeOriginalTools,
3594
+ escapeInvalidLtHeuristic,
2528
3595
  escapeRegExp,
2529
3596
  extractOnErrorOption,
2530
3597
  extractToolNamesFromOriginalTools,
@@ -2537,13 +3604,17 @@ Available functions are listed inside <tools></tools>.
2537
3604
  isToolChoiceActive,
2538
3605
  isToolResultPart,
2539
3606
  jsonMixProtocol,
3607
+ logParseFailure,
2540
3608
  logParsedChunk,
2541
3609
  logParsedSummary,
2542
3610
  logRawChunk,
3611
+ mergePipelineConfigs,
2543
3612
  morphXmlProtocol,
2544
3613
  morphXmlToolMiddleware,
3614
+ normalizeCloseTagsHeuristic,
2545
3615
  originalToolsSchema,
2546
3616
  parseRJSON,
3617
+ repairAgainstSchemaHeuristic,
2547
3618
  stringifyRJSON,
2548
3619
  transformRJSON
2549
3620
  });