@ai-sdk-tool/parser 2.1.1 → 2.1.3

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,22 +20,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- coerceBySchema: () => coerceBySchema,
24
23
  createToolMiddleware: () => createToolMiddleware,
25
- fixToolCallWithSchema: () => fixToolCallWithSchema,
26
24
  gemmaToolMiddleware: () => gemmaToolMiddleware,
27
- getSchemaType: () => getSchemaType,
28
25
  hermesToolMiddleware: () => hermesToolMiddleware,
29
26
  jsonMixProtocol: () => jsonMixProtocol,
30
- unwrapJsonSchema: () => unwrapJsonSchema,
31
- xmlProtocol: () => xmlProtocol,
27
+ morphXmlProtocol: () => morphXmlProtocol,
32
28
  xmlToolMiddleware: () => xmlToolMiddleware
33
29
  });
34
30
  module.exports = __toCommonJS(index_exports);
35
31
 
36
- // src/stream-handler.ts
32
+ // src/protocols/dummy-protocol.ts
37
33
  var import_provider_utils = require("@ai-sdk/provider-utils");
38
34
 
35
+ // src/protocols/json-mix-protocol.ts
36
+ var import_provider_utils2 = require("@ai-sdk/provider-utils");
37
+
39
38
  // src/utils/dynamic-tool-schema.ts
40
39
  function createDynamicIfThenElseSchema(tools) {
41
40
  let currentSchema = {};
@@ -110,6 +109,11 @@ function getPotentialStartIndex(text, searchedText) {
110
109
  return null;
111
110
  }
112
111
 
112
+ // src/utils/regex.ts
113
+ function escapeRegExp(literal) {
114
+ return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
115
+ }
116
+
113
117
  // src/utils/relaxed-json.ts
114
118
  var relaxed_json_exports = {};
115
119
  __export(relaxed_json_exports, {
@@ -743,62 +747,6 @@ function stringify(obj) {
743
747
  return "null";
744
748
  }
745
749
 
746
- // src/utils/regex.ts
747
- function escapeRegExp(literal) {
748
- return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
749
- }
750
-
751
- // src/utils/type-guards.ts
752
- function isToolCallContent(content) {
753
- return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
754
- (typeof content.input === "string" || typeof content.input === "object");
755
- }
756
- function isToolResultPart(content) {
757
- const c = content;
758
- return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
759
- }
760
- function hasInputProperty(obj) {
761
- return typeof obj === "object" && obj !== null && "input" in obj;
762
- }
763
-
764
- // src/utils/tools.ts
765
- function isToolChoiceActive(params) {
766
- var _a, _b, _c;
767
- const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
768
- 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"));
769
- }
770
- function getFunctionTools(params) {
771
- var _a, _b;
772
- const functionTools = ((_a = params.tools) != null ? _a : []).filter(
773
- (t) => t.type === "function"
774
- );
775
- if (functionTools.length > 0) return functionTools;
776
- const rawToolNames = params.providerOptions && typeof params.providerOptions === "object" && ((_b = params.providerOptions.toolCallMiddleware) == null ? void 0 : _b.toolNames) || [];
777
- const toStringArray = (val) => Array.isArray(val) ? val.filter(
778
- (item) => typeof item === "string"
779
- ) : [];
780
- const toolNames = toStringArray(rawToolNames);
781
- if (toolNames.length > 0) {
782
- return toolNames.map((name) => ({
783
- type: "function",
784
- name,
785
- description: "",
786
- inputSchema: { type: "object" }
787
- }));
788
- }
789
- return [];
790
- }
791
-
792
- // src/utils/on-error.ts
793
- function extractOnErrorOption(providerOptions) {
794
- var _a;
795
- if (providerOptions && typeof providerOptions === "object") {
796
- const onError = (_a = providerOptions.toolCallMiddleware) == null ? void 0 : _a.onError;
797
- return onError ? { onError } : void 0;
798
- }
799
- return void 0;
800
- }
801
-
802
750
  // src/utils/coercion.ts
803
751
  function unwrapJsonSchema(schema) {
804
752
  if (!schema || typeof schema !== "object") return schema;
@@ -1003,498 +951,1080 @@ function coerceToolCallInput(part, tools) {
1003
951
  return fixToolCallWithSchema(part, tools);
1004
952
  }
1005
953
 
1006
- // src/utils/protocol.ts
1007
- function isProtocolFactory(protocol) {
1008
- return typeof protocol === "function";
954
+ // src/utils/debug.ts
955
+ function normalizeBooleanString(value) {
956
+ const normalized = value.trim().toLowerCase();
957
+ if (normalized === "1" || normalized === "true" || normalized === "yes") {
958
+ return true;
959
+ }
960
+ if (normalized === "0" || normalized === "false" || normalized === "no") {
961
+ return false;
962
+ }
963
+ return void 0;
1009
964
  }
1010
-
1011
- // src/stream-handler.ts
1012
- async function wrapStream({
1013
- protocol,
1014
- doStream,
1015
- doGenerate,
1016
- params
1017
- }) {
1018
- var _a;
1019
- if (isToolChoiceActive(params)) {
1020
- return toolChoiceStream({
1021
- doGenerate,
1022
- options: extractOnErrorOption(params.providerOptions)
1023
- });
965
+ function getDebugLevel() {
966
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW || "off";
967
+ const envLower = String(envVal).toLowerCase();
968
+ if (envLower === "stream" || envLower === "parse" || envLower === "off") {
969
+ return envLower;
1024
970
  }
1025
- const { stream, ...rest } = await doStream();
1026
- return {
1027
- stream: stream.pipeThrough(
1028
- protocol.createStreamParser({
1029
- tools: getFunctionTools(params),
1030
- options: {
1031
- ...extractOnErrorOption(params.providerOptions),
1032
- ...(_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware
1033
- }
1034
- })
1035
- ),
1036
- ...rest
1037
- };
971
+ const boolEnv = normalizeBooleanString(envLower);
972
+ if (boolEnv === true) return "stream";
973
+ if (envLower === "2") return "parse";
974
+ return "off";
1038
975
  }
1039
- async function toolChoiceStream({
1040
- doGenerate,
1041
- options
1042
- }) {
1043
- var _a, _b;
1044
- const result = await doGenerate();
1045
- let toolJson = {};
1046
- if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
1047
- try {
1048
- toolJson = JSON.parse(result.content[0].text);
1049
- } catch (error) {
1050
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1051
- options,
1052
- "Failed to parse toolChoice JSON from streamed model output",
1053
- {
1054
- text: result.content[0].text,
1055
- error: error instanceof Error ? error.message : String(error)
1056
- }
1057
- );
1058
- toolJson = {};
1059
- }
976
+ function color(code) {
977
+ return (text) => `\x1B[${code}m${text}\x1B[0m`;
978
+ }
979
+ var cGray = color(90);
980
+ var cYellow = color(33);
981
+ var cCyan = color(36);
982
+ var cBgBlue = color(44);
983
+ var cBgGreen = color(42);
984
+ var cInverse = color(7);
985
+ var cUnderline = color(4);
986
+ var cBold = color(1);
987
+ function safeStringify(value) {
988
+ try {
989
+ return `
990
+ ${typeof value === "string" ? value : JSON.stringify(value, null, 2)}`;
991
+ } catch (e) {
992
+ return String(value);
1060
993
  }
1061
- const toolCallChunk = {
1062
- type: "tool-call",
1063
- toolCallId: (0, import_provider_utils.generateId)(),
1064
- toolName: toolJson.name || "unknown",
1065
- input: JSON.stringify(toolJson.arguments || {})
1066
- };
1067
- const finishChunk = {
1068
- type: "finish",
1069
- usage: (result == null ? void 0 : result.usage) || // TODO: If possible, try to return a certain amount of LLM usage.
1070
- {
1071
- inputTokens: 0,
1072
- outputTokens: 0,
1073
- totalTokens: 0
1074
- },
1075
- finishReason: "tool-calls"
1076
- };
1077
- const stream = new ReadableStream({
1078
- start(controller) {
1079
- controller.enqueue(toolCallChunk);
1080
- controller.enqueue(finishChunk);
1081
- controller.close();
1082
- }
1083
- });
1084
- return {
1085
- request: (result == null ? void 0 : result.request) || {},
1086
- response: (result == null ? void 0 : result.response) || {},
1087
- stream
1088
- };
1089
994
  }
1090
-
1091
- // src/generate-handler.ts
1092
- var import_provider_utils2 = require("@ai-sdk/provider-utils");
1093
- async function wrapGenerate({
1094
- protocol,
1095
- doGenerate,
1096
- params
995
+ function logRawChunk(part) {
996
+ console.log(cGray("[debug:mw:raw]"), cYellow(safeStringify(part)));
997
+ }
998
+ function logParsedChunk(part) {
999
+ console.log(cGray("[debug:mw:out]"), cCyan(safeStringify(part)));
1000
+ }
1001
+ function logParsedSummary({
1002
+ toolCalls,
1003
+ originalText
1097
1004
  }) {
1098
- var _a, _b;
1099
- if (isToolChoiceActive(params)) {
1100
- const result2 = await doGenerate();
1101
- let parsed2 = {};
1102
- const first = (_a = result2.content) == null ? void 0 : _a[0];
1103
- if (first && first.type === "text") {
1104
- try {
1105
- parsed2 = JSON.parse(first.text);
1106
- } catch (error) {
1107
- const options = extractOnErrorOption(params.providerOptions);
1108
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1109
- options,
1110
- "Failed to parse toolChoice JSON from generated model output",
1111
- {
1112
- text: first.text,
1113
- error: error instanceof Error ? error.message : String(error)
1114
- }
1115
- );
1116
- parsed2 = {};
1117
- }
1118
- }
1119
- const toolCall = {
1120
- type: "tool-call",
1121
- toolCallId: (0, import_provider_utils2.generateId)(),
1122
- toolName: parsed2.name || "unknown",
1123
- input: JSON.stringify(parsed2.arguments || {})
1124
- };
1125
- return {
1126
- ...result2,
1127
- content: [toolCall]
1128
- };
1005
+ if (originalText) {
1006
+ const style = (() => {
1007
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW_STYLE || "bg";
1008
+ const normalized = String(envVal).trim().toLowerCase();
1009
+ if (normalized === "inverse" || normalized === "invert")
1010
+ return "inverse";
1011
+ if (normalized === "underline" || normalized === "ul")
1012
+ return "underline";
1013
+ if (normalized === "bold") return "bold";
1014
+ if (normalized === "bg" || normalized === "background")
1015
+ return "bg";
1016
+ const asBool = normalizeBooleanString(normalized);
1017
+ if (asBool === true) return "bg";
1018
+ return "bg";
1019
+ })();
1020
+ const highlight = style === "inverse" ? cInverse : style === "underline" ? cUnderline : style === "bold" ? cBold : style === "bg" ? cBgGreen : cYellow;
1021
+ const rendered = style === "bg" || style === "inverse" || style === "underline" || style === "bold" ? originalText.split(/\r?\n/).map((line) => line.length ? highlight(line) : line).join("\n") : highlight(originalText);
1022
+ console.log(cGray("[debug:mw:origin]"), `
1023
+ ${rendered}`);
1129
1024
  }
1130
- const result = await doGenerate();
1131
- if (result.content.length === 0) {
1132
- return result;
1025
+ if (toolCalls.length > 0) {
1026
+ const styledSummary = safeStringify(toolCalls).split(/\r?\n/).map((line) => line.length ? cBgBlue(line) : line).join("\n");
1027
+ console.log(cGray("[debug:mw:summary]"), styledSummary);
1133
1028
  }
1134
- const parsed = result.content.flatMap((contentItem) => {
1135
- var _a2;
1136
- if (contentItem.type !== "text") {
1137
- return [contentItem];
1138
- }
1139
- return protocol.parseGeneratedText({
1140
- text: contentItem.text,
1141
- tools: getFunctionTools(params),
1142
- options: {
1143
- ...extractOnErrorOption(params.providerOptions),
1144
- ...(_a2 = params.providerOptions) == null ? void 0 : _a2.toolCallMiddleware
1145
- }
1146
- });
1147
- });
1148
- const tools = getFunctionTools(params);
1149
- const newContent = parsed.map(
1150
- (part) => coerceToolCallInput(part, tools)
1151
- );
1152
- return {
1153
- ...result,
1154
- content: newContent
1155
- };
1156
1029
  }
1157
1030
 
1158
- // src/transform-handler.ts
1159
- async function transformParams({
1160
- params,
1161
- protocol,
1162
- toolSystemPromptTemplate
1163
- }) {
1164
- var _a, _b, _c, _d, _e, _f, _g, _h;
1165
- const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
1031
+ // src/utils/on-error.ts
1032
+ function extractOnErrorOption(providerOptions) {
1033
+ var _a;
1034
+ if (providerOptions && typeof providerOptions === "object") {
1035
+ const onError = (_a = providerOptions.toolCallMiddleware) == null ? void 0 : _a.onError;
1036
+ return onError ? { onError } : void 0;
1037
+ }
1038
+ return void 0;
1039
+ }
1040
+
1041
+ // src/utils/protocol.ts
1042
+ function isProtocolFactory(protocol) {
1043
+ return typeof protocol === "function";
1044
+ }
1045
+
1046
+ // src/utils/tools.ts
1047
+ function isToolChoiceActive(params) {
1048
+ var _a, _b, _c;
1049
+ const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
1050
+ 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"));
1051
+ }
1052
+ function getFunctionTools(params) {
1053
+ var _a, _b;
1166
1054
  const functionTools = ((_a = params.tools) != null ? _a : []).filter(
1167
1055
  (t) => t.type === "function"
1168
1056
  );
1169
- const systemPrompt = resolvedProtocol.formatTools({
1170
- tools: functionTools,
1171
- toolSystemPromptTemplate
1172
- });
1173
- const processedPrompt = convertToolPrompt(
1174
- (_b = params.prompt) != null ? _b : [],
1175
- resolvedProtocol,
1176
- extractOnErrorOption(params.providerOptions)
1177
- );
1178
- const finalPrompt = ((_c = processedPrompt[0]) == null ? void 0 : _c.role) === "system" ? [
1179
- {
1180
- role: "system",
1181
- content: systemPrompt + "\n\n" + processedPrompt[0].content
1182
- },
1183
- ...processedPrompt.slice(1)
1184
- ] : [
1185
- {
1186
- role: "system",
1187
- content: systemPrompt
1188
- },
1189
- ...processedPrompt
1190
- ];
1191
- const baseReturnParams = {
1192
- ...params,
1193
- prompt: finalPrompt,
1194
- tools: [],
1195
- toolChoice: void 0,
1196
- providerOptions: {
1197
- ...params.providerOptions || {},
1198
- toolCallMiddleware: {
1199
- ...params.providerOptions && typeof params.providerOptions === "object" && params.providerOptions.toolCallMiddleware || {},
1200
- toolNames: functionTools.map((t) => t.name)
1201
- }
1202
- }
1203
- };
1204
- if (((_d = params.toolChoice) == null ? void 0 : _d.type) === "none") {
1205
- throw new Error(
1206
- "The 'none' toolChoice type is not supported by this middleware. Please use 'auto', 'required', or specify a tool name."
1207
- );
1057
+ if (functionTools.length > 0) return functionTools;
1058
+ const rawToolNames = params.providerOptions && typeof params.providerOptions === "object" && ((_b = params.providerOptions.toolCallMiddleware) == null ? void 0 : _b.toolNames) || [];
1059
+ const toStringArray = (val) => Array.isArray(val) ? val.filter(
1060
+ (item) => typeof item === "string"
1061
+ ) : [];
1062
+ const toolNames = toStringArray(rawToolNames);
1063
+ if (toolNames.length > 0) {
1064
+ return toolNames.map((name) => ({
1065
+ type: "function",
1066
+ name,
1067
+ description: "",
1068
+ inputSchema: { type: "object" }
1069
+ }));
1208
1070
  }
1209
- if (((_e = params.toolChoice) == null ? void 0 : _e.type) === "tool") {
1210
- const selectedToolName = params.toolChoice.toolName;
1211
- const providerDefinedMatch = ((_f = params.tools) != null ? _f : []).find((t) => {
1212
- if (t.type === "function") return false;
1213
- const anyTool = t;
1214
- return anyTool.id === selectedToolName || anyTool.name === selectedToolName;
1215
- });
1216
- if (providerDefinedMatch) {
1217
- throw new Error(
1218
- "Provider-defined tools are not supported by this middleware. Please use custom tools."
1219
- );
1071
+ return [];
1072
+ }
1073
+
1074
+ // src/utils/type-guards.ts
1075
+ function isToolCallContent(content) {
1076
+ return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
1077
+ (typeof content.input === "string" || typeof content.input === "object");
1078
+ }
1079
+ function isToolResultPart(content) {
1080
+ const c = content;
1081
+ return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
1082
+ }
1083
+ function hasInputProperty(obj) {
1084
+ return typeof obj === "object" && obj !== null && "input" in obj;
1085
+ }
1086
+
1087
+ // src/protocols/json-mix-protocol.ts
1088
+ var jsonMixProtocol = ({
1089
+ toolCallStart = "<tool_call>",
1090
+ toolCallEnd = "</tool_call>",
1091
+ toolResponseStart = "<tool_response>",
1092
+ toolResponseEnd = "</tool_response>"
1093
+ } = {}) => ({
1094
+ formatTools({ tools, toolSystemPromptTemplate }) {
1095
+ const toolsForPrompt = (tools || []).filter((tool) => tool.type === "function").map((tool) => ({
1096
+ name: tool.name,
1097
+ description: tool.type === "function" && typeof tool.description === "string" ? tool.description : void 0,
1098
+ parameters: tool.inputSchema
1099
+ }));
1100
+ return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1101
+ },
1102
+ formatToolCall(toolCall) {
1103
+ let args = {};
1104
+ try {
1105
+ args = JSON.parse(toolCall.input);
1106
+ } catch (e) {
1107
+ args = toolCall.input;
1220
1108
  }
1221
- const selectedTool = ((_g = params.tools) != null ? _g : []).find(
1222
- (t) => t.type === "function" && t.name === selectedToolName
1109
+ return `${toolCallStart}${JSON.stringify({
1110
+ name: toolCall.toolName,
1111
+ arguments: args
1112
+ })}${toolCallEnd}`;
1113
+ },
1114
+ formatToolResponse(toolResult) {
1115
+ return `${toolResponseStart}${JSON.stringify({
1116
+ toolName: toolResult.toolName,
1117
+ result: toolResult.output
1118
+ })}${toolResponseEnd}`;
1119
+ },
1120
+ parseGeneratedText({ text, options }) {
1121
+ var _a;
1122
+ const startEsc = escapeRegExp(toolCallStart);
1123
+ const endEsc = escapeRegExp(toolCallEnd);
1124
+ const toolCallRegex = new RegExp(
1125
+ `${startEsc}([\0-\uFFFF]*?)${endEsc}`,
1126
+ "gs"
1223
1127
  );
1224
- if (!selectedTool) {
1225
- throw new Error(
1226
- `Tool with name '${selectedToolName}' not found in params.tools.`
1227
- );
1228
- }
1229
- return {
1230
- ...baseReturnParams,
1231
- responseFormat: {
1232
- type: "json",
1233
- schema: {
1234
- type: "object",
1235
- properties: {
1236
- name: {
1237
- const: selectedTool.name
1238
- },
1239
- arguments: selectedTool.inputSchema
1240
- },
1241
- required: ["name", "arguments"]
1242
- },
1243
- name: selectedTool.name,
1244
- description: typeof selectedTool.description === "string" ? selectedTool.description : void 0
1245
- },
1246
- providerOptions: {
1247
- ...baseReturnParams.providerOptions || {},
1248
- toolCallMiddleware: {
1249
- ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
1250
- toolChoice: params.toolChoice
1128
+ const processedElements = [];
1129
+ let currentIndex = 0;
1130
+ let match;
1131
+ while ((match = toolCallRegex.exec(text)) !== null) {
1132
+ const startIndex = match.index;
1133
+ const toolCallJson = match[1];
1134
+ if (startIndex > currentIndex) {
1135
+ const textSegment = text.substring(currentIndex, startIndex);
1136
+ if (textSegment.trim()) {
1137
+ processedElements.push({ type: "text", text: textSegment });
1251
1138
  }
1252
1139
  }
1253
- };
1254
- }
1255
- if (((_h = params.toolChoice) == null ? void 0 : _h.type) === "required") {
1256
- if (!params.tools || params.tools.length === 0) {
1257
- throw new Error(
1258
- "Tool choice type 'required' is set, but no tools are provided in params.tools."
1259
- );
1140
+ if (toolCallJson) {
1141
+ try {
1142
+ const parsedToolCall = relaxed_json_exports.parse(toolCallJson);
1143
+ processedElements.push({
1144
+ type: "tool-call",
1145
+ toolCallId: (0, import_provider_utils2.generateId)(),
1146
+ toolName: parsedToolCall.name,
1147
+ input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1148
+ });
1149
+ } catch (error) {
1150
+ if (options == null ? void 0 : options.onError) {
1151
+ options.onError(
1152
+ "Could not process JSON tool call, keeping original text.",
1153
+ { toolCall: match[0], error }
1154
+ );
1155
+ }
1156
+ processedElements.push({ type: "text", text: match[0] });
1157
+ }
1158
+ }
1159
+ currentIndex = startIndex + match[0].length;
1260
1160
  }
1261
- return {
1262
- ...baseReturnParams,
1263
- responseFormat: {
1264
- type: "json",
1265
- schema: createDynamicIfThenElseSchema(functionTools)
1266
- },
1267
- providerOptions: {
1268
- ...baseReturnParams.providerOptions || {},
1269
- toolCallMiddleware: {
1270
- ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
1271
- toolChoice: { type: "required" }
1161
+ if (currentIndex < text.length) {
1162
+ const remainingText = text.substring(currentIndex);
1163
+ if (remainingText.trim()) {
1164
+ processedElements.push({ type: "text", text: remainingText });
1165
+ }
1166
+ }
1167
+ return processedElements;
1168
+ },
1169
+ createStreamParser({ tools: _tools, options } = { tools: [] }) {
1170
+ let isInsideToolCall = false;
1171
+ let buffer = "";
1172
+ let currentToolCallJson = "";
1173
+ let currentTextId = null;
1174
+ let hasEmittedTextStart = false;
1175
+ return new TransformStream({
1176
+ transform(chunk, controller) {
1177
+ var _a;
1178
+ if (chunk.type === "finish") {
1179
+ if (isInsideToolCall && buffer.length > 0) {
1180
+ if (!currentTextId) {
1181
+ currentTextId = (0, import_provider_utils2.generateId)();
1182
+ controller.enqueue({ type: "text-start", id: currentTextId });
1183
+ hasEmittedTextStart = true;
1184
+ }
1185
+ controller.enqueue({
1186
+ type: "text-delta",
1187
+ id: currentTextId,
1188
+ delta: `${toolCallStart}${buffer}`
1189
+ });
1190
+ buffer = "";
1191
+ } else if (!isInsideToolCall && buffer.length > 0) {
1192
+ if (!currentTextId) {
1193
+ currentTextId = (0, import_provider_utils2.generateId)();
1194
+ controller.enqueue({ type: "text-start", id: currentTextId });
1195
+ hasEmittedTextStart = true;
1196
+ }
1197
+ controller.enqueue({
1198
+ type: "text-delta",
1199
+ id: currentTextId,
1200
+ delta: buffer
1201
+ });
1202
+ buffer = "";
1203
+ }
1204
+ if (currentTextId && hasEmittedTextStart) {
1205
+ controller.enqueue({ type: "text-end", id: currentTextId });
1206
+ currentTextId = null;
1207
+ hasEmittedTextStart = false;
1208
+ }
1209
+ if (currentToolCallJson) {
1210
+ const errorId = (0, import_provider_utils2.generateId)();
1211
+ controller.enqueue({ type: "text-start", id: errorId });
1212
+ controller.enqueue({
1213
+ type: "text-delta",
1214
+ id: errorId,
1215
+ delta: `${toolCallStart}${currentToolCallJson}`
1216
+ });
1217
+ controller.enqueue({ type: "text-end", id: errorId });
1218
+ currentToolCallJson = "";
1219
+ }
1220
+ controller.enqueue(chunk);
1221
+ return;
1222
+ }
1223
+ if (chunk.type !== "text-delta") {
1224
+ controller.enqueue(chunk);
1225
+ return;
1226
+ }
1227
+ buffer += chunk.delta;
1228
+ const publish = (text) => {
1229
+ if (isInsideToolCall) {
1230
+ if (currentTextId && hasEmittedTextStart) {
1231
+ controller.enqueue({ type: "text-end", id: currentTextId });
1232
+ currentTextId = null;
1233
+ hasEmittedTextStart = false;
1234
+ }
1235
+ currentToolCallJson += text;
1236
+ } else if (text.length > 0) {
1237
+ if (!currentTextId) {
1238
+ currentTextId = (0, import_provider_utils2.generateId)();
1239
+ controller.enqueue({ type: "text-start", id: currentTextId });
1240
+ hasEmittedTextStart = true;
1241
+ }
1242
+ controller.enqueue({
1243
+ type: "text-delta",
1244
+ id: currentTextId,
1245
+ delta: text
1246
+ });
1247
+ }
1248
+ };
1249
+ let startIndex;
1250
+ while ((startIndex = getPotentialStartIndex(
1251
+ buffer,
1252
+ isInsideToolCall ? toolCallEnd : toolCallStart
1253
+ )) != null) {
1254
+ const tag = isInsideToolCall ? toolCallEnd : toolCallStart;
1255
+ if (startIndex + tag.length > buffer.length) {
1256
+ break;
1257
+ }
1258
+ publish(buffer.slice(0, startIndex));
1259
+ buffer = buffer.slice(startIndex + tag.length);
1260
+ if (!isInsideToolCall) {
1261
+ currentToolCallJson = "";
1262
+ isInsideToolCall = true;
1263
+ } else {
1264
+ try {
1265
+ const parsedToolCall = relaxed_json_exports.parse(currentToolCallJson);
1266
+ if (currentTextId && hasEmittedTextStart) {
1267
+ controller.enqueue({ type: "text-end", id: currentTextId });
1268
+ currentTextId = null;
1269
+ hasEmittedTextStart = false;
1270
+ }
1271
+ controller.enqueue({
1272
+ type: "tool-call",
1273
+ toolCallId: (0, import_provider_utils2.generateId)(),
1274
+ toolName: parsedToolCall.name,
1275
+ input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1276
+ });
1277
+ } catch (e) {
1278
+ const errorId = (0, import_provider_utils2.generateId)();
1279
+ controller.enqueue({ type: "text-start", id: errorId });
1280
+ controller.enqueue({
1281
+ type: "text-delta",
1282
+ id: errorId,
1283
+ delta: `${toolCallStart}${currentToolCallJson}${toolCallEnd}`
1284
+ });
1285
+ controller.enqueue({ type: "text-end", id: errorId });
1286
+ if (options == null ? void 0 : options.onError) {
1287
+ options.onError(
1288
+ "Could not process streaming JSON tool call; emitting original text.",
1289
+ {
1290
+ toolCall: `${toolCallStart}${currentToolCallJson}${toolCallEnd}`
1291
+ }
1292
+ );
1293
+ }
1294
+ }
1295
+ currentToolCallJson = "";
1296
+ isInsideToolCall = false;
1297
+ }
1298
+ }
1299
+ if (!isInsideToolCall) {
1300
+ const potentialIndex = getPotentialStartIndex(buffer, toolCallStart);
1301
+ if (potentialIndex != null && potentialIndex + toolCallStart.length > buffer.length) {
1302
+ publish(buffer.slice(0, potentialIndex));
1303
+ buffer = buffer.slice(potentialIndex);
1304
+ } else {
1305
+ publish(buffer);
1306
+ buffer = "";
1307
+ }
1272
1308
  }
1273
1309
  }
1274
- };
1310
+ });
1311
+ },
1312
+ extractToolCallSegments({ text }) {
1313
+ const startEsc = escapeRegExp(toolCallStart);
1314
+ const endEsc = escapeRegExp(toolCallEnd);
1315
+ const regex = new RegExp(`${startEsc}([\0-\uFFFF]*?)${endEsc}`, "gs");
1316
+ const segments = [];
1317
+ let m;
1318
+ while ((m = regex.exec(text)) != null) {
1319
+ segments.push(m[0]);
1320
+ }
1321
+ return segments;
1275
1322
  }
1276
- return baseReturnParams;
1323
+ });
1324
+
1325
+ // src/protocols/morph-xml-protocol.ts
1326
+ var import_provider_utils3 = require("@ai-sdk/provider-utils");
1327
+ var import_fast_xml_parser = require("fast-xml-parser");
1328
+ var WARN_ON_DUPLICATE_STRING_TAGS = true;
1329
+ function getToolSchema(tools, originalSchemas, toolName) {
1330
+ var _a;
1331
+ const original = originalSchemas[toolName];
1332
+ if (original) return original;
1333
+ const fallback = (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
1334
+ return fallback;
1277
1335
  }
1278
- function convertToolPrompt(prompt, resolvedProtocol, providerOptions) {
1279
- const processedPrompt = prompt.map((message) => {
1280
- var _a;
1281
- if (message.role === "assistant") {
1282
- const newContent = [];
1283
- for (const content of message.content) {
1284
- if (isToolCallContent(content)) {
1285
- newContent.push({
1286
- type: "text",
1287
- text: resolvedProtocol.formatToolCall(content)
1288
- });
1289
- } else if (content.type === "text") {
1290
- newContent.push(content);
1291
- } else if (content.type === "reasoning") {
1292
- newContent.push(content);
1293
- } else {
1294
- const options = extractOnErrorOption(providerOptions);
1295
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
1296
- options,
1297
- "tool-call-middleware: unknown assistant content; stringifying for provider compatibility",
1298
- { content }
1299
- );
1300
- newContent.push({
1301
- type: "text",
1302
- text: JSON.stringify(content)
1303
- });
1336
+ function getPropertySchema(toolSchema, key) {
1337
+ const unwrapped = unwrapJsonSchema(toolSchema);
1338
+ if (!unwrapped || typeof unwrapped !== "object") return void 0;
1339
+ const u = unwrapped;
1340
+ const props = u.properties;
1341
+ if (props && Object.prototype.hasOwnProperty.call(props, key)) {
1342
+ return props[key];
1343
+ }
1344
+ return void 0;
1345
+ }
1346
+ function extractRawInner(xmlContent, tagName) {
1347
+ const isNameStartChar = (ch) => /[A-Za-z_:]/.test(ch);
1348
+ const isNameChar = (ch) => /[A-Za-z0-9_.:-]/.test(ch);
1349
+ const len = xmlContent.length;
1350
+ const target = tagName;
1351
+ let bestStart = -1;
1352
+ let bestEnd = -1;
1353
+ let bestDepth = Number.POSITIVE_INFINITY;
1354
+ const skipQuoted = (s, i2) => {
1355
+ const quote = s[i2];
1356
+ i2++;
1357
+ while (i2 < s.length) {
1358
+ const ch = s[i2];
1359
+ if (ch === "\\") {
1360
+ i2 += 2;
1361
+ continue;
1362
+ }
1363
+ if (ch === quote) {
1364
+ return i2 + 1;
1365
+ }
1366
+ i2++;
1367
+ }
1368
+ return i2;
1369
+ };
1370
+ let i = 0;
1371
+ let depth = 0;
1372
+ while (i < len) {
1373
+ const lt = xmlContent.indexOf("<", i);
1374
+ if (lt === -1) return void 0;
1375
+ i = lt + 1;
1376
+ if (i >= len) return void 0;
1377
+ const ch = xmlContent[i];
1378
+ if (ch === "!") {
1379
+ if (xmlContent.startsWith("!--", i + 1)) {
1380
+ const close = xmlContent.indexOf("-->", i + 4);
1381
+ i = close === -1 ? len : close + 3;
1382
+ continue;
1383
+ }
1384
+ if (xmlContent.startsWith("![CDATA[", i + 1)) {
1385
+ const close = xmlContent.indexOf("]]>", i + 9);
1386
+ i = close === -1 ? len : close + 3;
1387
+ continue;
1388
+ }
1389
+ const gt = xmlContent.indexOf(">", i + 1);
1390
+ i = gt === -1 ? len : gt + 1;
1391
+ continue;
1392
+ } else if (ch === "?") {
1393
+ const close = xmlContent.indexOf("?>", i + 1);
1394
+ i = close === -1 ? len : close + 2;
1395
+ continue;
1396
+ } else if (ch === "/") {
1397
+ let j = i + 1;
1398
+ if (j < len && isNameStartChar(xmlContent[j])) {
1399
+ j++;
1400
+ while (j < len && isNameChar(xmlContent[j])) j++;
1401
+ }
1402
+ const gt = xmlContent.indexOf(">", j);
1403
+ i = gt === -1 ? len : gt + 1;
1404
+ depth = Math.max(0, depth - 1);
1405
+ continue;
1406
+ } else {
1407
+ let j = i;
1408
+ if (j < len && isNameStartChar(xmlContent[j])) {
1409
+ j++;
1410
+ while (j < len && isNameChar(xmlContent[j])) j++;
1411
+ }
1412
+ const name = xmlContent.slice(i, j);
1413
+ let k = j;
1414
+ let isSelfClosing = false;
1415
+ while (k < len) {
1416
+ const c = xmlContent[k];
1417
+ if (c === '"' || c === "'") {
1418
+ k = skipQuoted(xmlContent, k);
1419
+ continue;
1420
+ }
1421
+ if (c === ">") {
1422
+ break;
1304
1423
  }
1424
+ if (c === "/" && xmlContent[k + 1] === ">") {
1425
+ isSelfClosing = true;
1426
+ k++;
1427
+ break;
1428
+ }
1429
+ k++;
1305
1430
  }
1306
- const onlyText = newContent.every((c) => c.type === "text");
1307
- const condensedAssistant = onlyText ? [
1308
- {
1309
- type: "text",
1310
- text: newContent.map((c) => c.text).join("\n")
1431
+ const tagEnd = k;
1432
+ if (name === target) {
1433
+ const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1434
+ if (isSelfClosing) {
1435
+ if (depth < bestDepth) {
1436
+ bestStart = contentStart;
1437
+ bestEnd = contentStart;
1438
+ bestDepth = depth;
1439
+ if (bestDepth === 0) {
1440
+ }
1441
+ }
1442
+ } else {
1443
+ let pos = contentStart;
1444
+ let sameDepth = 1;
1445
+ while (pos < len) {
1446
+ const nextLt = xmlContent.indexOf("<", pos);
1447
+ if (nextLt === -1) break;
1448
+ const nx = nextLt + 1;
1449
+ if (nx >= len) break;
1450
+ const h = xmlContent[nx];
1451
+ if (h === "!") {
1452
+ if (xmlContent.startsWith("!--", nx + 1)) {
1453
+ const close = xmlContent.indexOf("-->", nx + 4);
1454
+ pos = close === -1 ? len : close + 3;
1455
+ continue;
1456
+ }
1457
+ if (xmlContent.startsWith("![CDATA[", nx + 1)) {
1458
+ const close = xmlContent.indexOf("]]>", nx + 9);
1459
+ pos = close === -1 ? len : close + 3;
1460
+ continue;
1461
+ }
1462
+ const gt2 = xmlContent.indexOf(">", nx + 1);
1463
+ pos = gt2 === -1 ? len : gt2 + 1;
1464
+ continue;
1465
+ } else if (h === "?") {
1466
+ const close = xmlContent.indexOf("?>", nx + 1);
1467
+ pos = close === -1 ? len : close + 2;
1468
+ continue;
1469
+ } else if (h === "/") {
1470
+ let t = nx + 1;
1471
+ if (t < len && isNameStartChar(xmlContent[t])) {
1472
+ t++;
1473
+ while (t < len && isNameChar(xmlContent[t])) t++;
1474
+ }
1475
+ const endName = xmlContent.slice(nx + 1, t);
1476
+ const gt2 = xmlContent.indexOf(">", t);
1477
+ if (endName === target) {
1478
+ sameDepth--;
1479
+ if (sameDepth === 0) {
1480
+ if (depth < bestDepth) {
1481
+ bestStart = contentStart;
1482
+ bestEnd = nextLt;
1483
+ bestDepth = depth;
1484
+ if (bestDepth === 0) {
1485
+ }
1486
+ }
1487
+ break;
1488
+ }
1489
+ }
1490
+ pos = gt2 === -1 ? len : gt2 + 1;
1491
+ continue;
1492
+ } else {
1493
+ let t = nx;
1494
+ if (t < len && isNameStartChar(xmlContent[t])) {
1495
+ t++;
1496
+ while (t < len && isNameChar(xmlContent[t])) t++;
1497
+ }
1498
+ const startName = xmlContent.slice(nx, t);
1499
+ let u = t;
1500
+ let selfClose = false;
1501
+ while (u < len) {
1502
+ const cu = xmlContent[u];
1503
+ if (cu === '"' || cu === "'") {
1504
+ u = skipQuoted(xmlContent, u);
1505
+ continue;
1506
+ }
1507
+ if (cu === ">") break;
1508
+ if (cu === "/" && xmlContent[u + 1] === ">") {
1509
+ selfClose = true;
1510
+ u++;
1511
+ break;
1512
+ }
1513
+ u++;
1514
+ }
1515
+ if (startName === target && !selfClose) {
1516
+ sameDepth++;
1517
+ }
1518
+ pos = xmlContent[u] === ">" ? u + 1 : u + 1;
1519
+ continue;
1520
+ }
1521
+ }
1311
1522
  }
1312
- ] : newContent;
1313
- return { role: "assistant", content: condensedAssistant };
1523
+ }
1524
+ i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1525
+ depth += isSelfClosing ? 0 : 1;
1526
+ continue;
1314
1527
  }
1315
- if (message.role === "tool") {
1316
- return {
1317
- role: "user",
1318
- // Map tool results to text response blocks, then condense into a single text block
1319
- content: [
1320
- {
1321
- type: "text",
1322
- text: message.content.map(
1323
- (toolResult) => isToolResultPart(toolResult) ? resolvedProtocol.formatToolResponse(toolResult) : resolvedProtocol.formatToolResponse(
1324
- toolResult
1325
- )
1326
- ).join("\n")
1327
- }
1328
- ]
1329
- };
1528
+ }
1529
+ if (bestStart !== -1) {
1530
+ return xmlContent.slice(bestStart, bestEnd);
1531
+ }
1532
+ return void 0;
1533
+ }
1534
+ function findFirstTopLevelRange(xmlContent, tagName) {
1535
+ const isNameStartChar = (ch) => /[A-Za-z_:]/.test(ch);
1536
+ const isNameChar = (ch) => /[A-Za-z0-9_.:-]/.test(ch);
1537
+ const len = xmlContent.length;
1538
+ const target = tagName;
1539
+ const skipQuoted = (s, i2) => {
1540
+ const quote = s[i2];
1541
+ i2++;
1542
+ while (i2 < s.length) {
1543
+ const ch = s[i2];
1544
+ if (ch === "\\") {
1545
+ i2 += 2;
1546
+ continue;
1547
+ }
1548
+ if (ch === quote) return i2 + 1;
1549
+ i2++;
1330
1550
  }
1331
- return message;
1332
- });
1333
- for (let i = 0; i < processedPrompt.length; i++) {
1334
- const msg = processedPrompt[i];
1335
- if (Array.isArray(msg.content)) {
1336
- const allText = msg.content.every(
1337
- (c) => (c == null ? void 0 : c.type) === "text"
1338
- );
1339
- if (allText && msg.content.length > 1) {
1340
- const joinedText = msg.content.map((c) => c.text).join("\n");
1341
- if (msg.role === "system") {
1342
- processedPrompt[i] = {
1343
- role: "system",
1344
- content: joinedText
1345
- };
1346
- } else if (msg.role === "assistant") {
1347
- processedPrompt[i] = {
1348
- role: "assistant",
1349
- content: [
1350
- {
1351
- type: "text",
1352
- text: joinedText
1551
+ return i2;
1552
+ };
1553
+ let i = 0;
1554
+ let depth = 0;
1555
+ while (i < len) {
1556
+ const lt = xmlContent.indexOf("<", i);
1557
+ if (lt === -1) return void 0;
1558
+ i = lt + 1;
1559
+ if (i >= len) return void 0;
1560
+ const ch = xmlContent[i];
1561
+ if (ch === "!") {
1562
+ if (xmlContent.startsWith("!--", i + 1)) {
1563
+ const close = xmlContent.indexOf("-->", i + 4);
1564
+ i = close === -1 ? len : close + 3;
1565
+ continue;
1566
+ }
1567
+ if (xmlContent.startsWith("![CDATA[", i + 1)) {
1568
+ const close = xmlContent.indexOf("]]>", i + 9);
1569
+ i = close === -1 ? len : close + 3;
1570
+ continue;
1571
+ }
1572
+ const gt = xmlContent.indexOf(">", i + 1);
1573
+ i = gt === -1 ? len : gt + 1;
1574
+ continue;
1575
+ } else if (ch === "?") {
1576
+ const close = xmlContent.indexOf("?>", i + 1);
1577
+ i = close === -1 ? len : close + 2;
1578
+ continue;
1579
+ } else if (ch === "/") {
1580
+ const gt = xmlContent.indexOf(">", i + 1);
1581
+ i = gt === -1 ? len : gt + 1;
1582
+ depth = Math.max(0, depth - 1);
1583
+ continue;
1584
+ } else {
1585
+ let j = i;
1586
+ if (j < len && isNameStartChar(xmlContent[j])) {
1587
+ j++;
1588
+ while (j < len && isNameChar(xmlContent[j])) j++;
1589
+ }
1590
+ const name = xmlContent.slice(i, j);
1591
+ let k = j;
1592
+ let isSelfClosing = false;
1593
+ while (k < len) {
1594
+ const c = xmlContent[k];
1595
+ if (c === '"' || c === "'") {
1596
+ k = skipQuoted(xmlContent, k);
1597
+ continue;
1598
+ }
1599
+ if (c === ">") break;
1600
+ if (c === "/" && xmlContent[k + 1] === ">") {
1601
+ isSelfClosing = true;
1602
+ k++;
1603
+ break;
1604
+ }
1605
+ k++;
1606
+ }
1607
+ const tagEnd = k;
1608
+ if (depth === 0 && name === target) {
1609
+ const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1610
+ if (isSelfClosing) return { start: contentStart, end: contentStart };
1611
+ let pos = contentStart;
1612
+ let sameDepth = 1;
1613
+ while (pos < len) {
1614
+ const nextLt = xmlContent.indexOf("<", pos);
1615
+ if (nextLt === -1) break;
1616
+ const nx = nextLt + 1;
1617
+ if (nx >= len) break;
1618
+ const h = xmlContent[nx];
1619
+ if (h === "!") {
1620
+ if (xmlContent.startsWith("!--", nx + 1)) {
1621
+ const close = xmlContent.indexOf("-->", nx + 4);
1622
+ pos = close === -1 ? len : close + 3;
1623
+ continue;
1624
+ }
1625
+ if (xmlContent.startsWith("![CDATA[", nx + 1)) {
1626
+ const close = xmlContent.indexOf("]]>", nx + 9);
1627
+ pos = close === -1 ? len : close + 3;
1628
+ continue;
1629
+ }
1630
+ const gt2 = xmlContent.indexOf(">", nx + 1);
1631
+ pos = gt2 === -1 ? len : gt2 + 1;
1632
+ continue;
1633
+ } else if (h === "?") {
1634
+ const close = xmlContent.indexOf("?>", nx + 1);
1635
+ pos = close === -1 ? len : close + 2;
1636
+ continue;
1637
+ } else if (h === "/") {
1638
+ let t = nx + 1;
1639
+ if (t < len && isNameStartChar(xmlContent[t])) {
1640
+ t++;
1641
+ while (t < len && isNameChar(xmlContent[t])) t++;
1642
+ }
1643
+ const endName = xmlContent.slice(nx + 1, t);
1644
+ const gt2 = xmlContent.indexOf(">", t);
1645
+ if (endName === target) {
1646
+ sameDepth--;
1647
+ if (sameDepth === 0) {
1648
+ return { start: contentStart, end: nextLt };
1353
1649
  }
1354
- ]
1355
- };
1356
- } else {
1357
- processedPrompt[i] = {
1358
- role: "user",
1359
- content: [
1360
- {
1361
- type: "text",
1362
- text: joinedText
1650
+ }
1651
+ pos = gt2 === -1 ? len : gt2 + 1;
1652
+ continue;
1653
+ } else {
1654
+ let t = nx;
1655
+ if (t < len && isNameStartChar(xmlContent[t])) {
1656
+ t++;
1657
+ while (t < len && isNameChar(xmlContent[t])) t++;
1658
+ }
1659
+ let u = t;
1660
+ let selfClose = false;
1661
+ while (u < len) {
1662
+ const cu = xmlContent[u];
1663
+ if (cu === '"' || cu === "'") {
1664
+ u = skipQuoted(xmlContent, u);
1665
+ continue;
1363
1666
  }
1364
- ]
1365
- };
1667
+ if (cu === ">") break;
1668
+ if (cu === "/" && xmlContent[u + 1] === ">") {
1669
+ selfClose = true;
1670
+ u++;
1671
+ break;
1672
+ }
1673
+ u++;
1674
+ }
1675
+ if (!selfClose) {
1676
+ }
1677
+ pos = xmlContent[u] === ">" ? u + 1 : u + 1;
1678
+ continue;
1679
+ }
1680
+ }
1681
+ return void 0;
1682
+ }
1683
+ i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1684
+ depth += isSelfClosing ? 0 : 1;
1685
+ continue;
1686
+ }
1687
+ }
1688
+ return void 0;
1689
+ }
1690
+ function countTagOccurrences(xmlContent, tagName, excludeRanges, skipFirst = true) {
1691
+ const isNameStartChar = (ch) => /[A-Za-z_:]/.test(ch);
1692
+ const isNameChar = (ch) => /[A-Za-z0-9_.:-]/.test(ch);
1693
+ const len = xmlContent.length;
1694
+ const target = tagName;
1695
+ const skipQuoted = (s, i2) => {
1696
+ const quote = s[i2];
1697
+ i2++;
1698
+ while (i2 < s.length) {
1699
+ const ch = s[i2];
1700
+ if (ch === "\\") {
1701
+ i2 += 2;
1702
+ continue;
1703
+ }
1704
+ if (ch === quote) return i2 + 1;
1705
+ i2++;
1706
+ }
1707
+ return i2;
1708
+ };
1709
+ let i = 0;
1710
+ let count = 0;
1711
+ const isExcluded = (pos) => {
1712
+ if (!excludeRanges || excludeRanges.length === 0) return false;
1713
+ for (const r of excludeRanges) {
1714
+ if (pos >= r.start && pos < r.end) return true;
1715
+ }
1716
+ return false;
1717
+ };
1718
+ while (i < len) {
1719
+ const lt = xmlContent.indexOf("<", i);
1720
+ if (lt === -1) break;
1721
+ i = lt + 1;
1722
+ if (i >= len) break;
1723
+ const ch = xmlContent[i];
1724
+ if (ch === "!") {
1725
+ if (xmlContent.startsWith("!--", i + 1)) {
1726
+ const close = xmlContent.indexOf("-->", i + 4);
1727
+ i = close === -1 ? len : close + 3;
1728
+ continue;
1729
+ }
1730
+ if (xmlContent.startsWith("![CDATA[", i + 1)) {
1731
+ const close = xmlContent.indexOf("]]>", i + 9);
1732
+ i = close === -1 ? len : close + 3;
1733
+ continue;
1734
+ }
1735
+ const gt = xmlContent.indexOf(">", i + 1);
1736
+ i = gt === -1 ? len : gt + 1;
1737
+ continue;
1738
+ } else if (ch === "?") {
1739
+ const close = xmlContent.indexOf("?>", i + 1);
1740
+ i = close === -1 ? len : close + 2;
1741
+ continue;
1742
+ } else if (ch === "/") {
1743
+ const gt = xmlContent.indexOf(">", i + 1);
1744
+ i = gt === -1 ? len : gt + 1;
1745
+ continue;
1746
+ } else {
1747
+ let j = i;
1748
+ if (j < len && isNameStartChar(xmlContent[j])) {
1749
+ j++;
1750
+ while (j < len && isNameChar(xmlContent[j])) j++;
1751
+ }
1752
+ const name = xmlContent.slice(i, j);
1753
+ let k = j;
1754
+ while (k < len) {
1755
+ const c = xmlContent[k];
1756
+ if (c === '"' || c === "'") {
1757
+ k = skipQuoted(xmlContent, k);
1758
+ continue;
1759
+ }
1760
+ if (c === ">") break;
1761
+ if (c === "/" && xmlContent[k + 1] === ">") {
1762
+ k++;
1763
+ break;
1366
1764
  }
1765
+ k++;
1367
1766
  }
1767
+ if (name === target && !isExcluded(lt)) {
1768
+ if (skipFirst) {
1769
+ skipFirst = false;
1770
+ } else {
1771
+ count++;
1772
+ }
1773
+ }
1774
+ i = k + 1;
1775
+ continue;
1368
1776
  }
1369
1777
  }
1370
- for (let i = processedPrompt.length - 1; i > 0; i--) {
1371
- const current = processedPrompt[i];
1372
- const prev = processedPrompt[i - 1];
1373
- if (current.role === "user" && prev.role === "user") {
1374
- const prevContent = prev.content.map((c) => c.type === "text" ? c.text : "").join("\n");
1375
- const currentContent = current.content.map((c) => c.type === "text" ? c.text : "").join("\n");
1376
- processedPrompt[i - 1] = {
1377
- role: "user",
1378
- content: [{ type: "text", text: prevContent + "\n" + currentContent }]
1379
- };
1380
- processedPrompt.splice(i, 1);
1381
- }
1382
- }
1383
- return processedPrompt;
1778
+ return count;
1384
1779
  }
1385
-
1386
- // src/tool-call-middleware.ts
1387
- function createToolMiddleware({
1388
- protocol,
1389
- toolSystemPromptTemplate
1390
- }) {
1391
- const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
1392
- return {
1393
- middlewareVersion: "v2",
1394
- wrapStream: async ({ doStream, doGenerate, params }) => {
1395
- if (isToolChoiceActive(params)) {
1396
- return toolChoiceStream({
1397
- doGenerate,
1398
- options: extractOnErrorOption(params.providerOptions)
1780
+ function processParsedArgs(parsedArgs, toolSchema, toolContent, toolName, options) {
1781
+ var _a, _b, _c;
1782
+ const args = {};
1783
+ let cancelToolCall = false;
1784
+ const stringTypedProps = (() => {
1785
+ const set = /* @__PURE__ */ new Set();
1786
+ const unwrapped = unwrapJsonSchema(toolSchema);
1787
+ if (unwrapped && typeof unwrapped === "object") {
1788
+ const u = unwrapped;
1789
+ const props = u.properties;
1790
+ if (props && typeof props === "object") {
1791
+ for (const key of Object.keys(props)) {
1792
+ const t = getSchemaType(props[key]);
1793
+ if (t === "string") set.add(key);
1794
+ }
1795
+ }
1796
+ }
1797
+ return set;
1798
+ })();
1799
+ for (const k of Object.keys(parsedArgs || {})) {
1800
+ const v = parsedArgs[k];
1801
+ let val = v;
1802
+ const propSchema = getPropertySchema(toolSchema, k);
1803
+ const propType = getSchemaType(propSchema);
1804
+ if (propType === "string" && !Array.isArray(v)) {
1805
+ const excludeRanges = [];
1806
+ for (const other of stringTypedProps) {
1807
+ if (other === k) continue;
1808
+ const range = findFirstTopLevelRange(toolContent, other);
1809
+ if (range) excludeRanges.push(range);
1810
+ }
1811
+ const occurrences = countTagOccurrences(
1812
+ toolContent,
1813
+ k,
1814
+ excludeRanges,
1815
+ true
1816
+ );
1817
+ if (occurrences > 0) {
1818
+ if (WARN_ON_DUPLICATE_STRING_TAGS) {
1819
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
1820
+ options,
1821
+ `Duplicate string tags for <${k}> detected; cancelling tool call`,
1822
+ {
1823
+ toolName,
1824
+ toolCall: `<${toolName}>${toolContent}</${toolName}>`
1825
+ }
1826
+ );
1827
+ }
1828
+ cancelToolCall = true;
1829
+ break;
1830
+ }
1831
+ const raw = extractRawInner(toolContent, k);
1832
+ if (typeof raw === "string") {
1833
+ args[k] = raw;
1834
+ continue;
1835
+ }
1836
+ }
1837
+ if (v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, "#text")) {
1838
+ val = v == null ? void 0 : v["#text"];
1839
+ }
1840
+ if (Array.isArray(v)) {
1841
+ if (propType === "string") {
1842
+ const mapped = v.map((item) => {
1843
+ if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1844
+ const textVal = item == null ? void 0 : item["#text"];
1845
+ return typeof textVal === "string" ? textVal : String(textVal);
1846
+ }
1847
+ return typeof item === "string" ? item : String(item);
1399
1848
  });
1849
+ if (mapped.length > 1 && WARN_ON_DUPLICATE_STRING_TAGS) {
1850
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1851
+ options,
1852
+ `Duplicate string tags for <${k}> detected; cancelling tool call`,
1853
+ {
1854
+ toolName,
1855
+ toolCall: `<${toolName}>${toolContent}</${toolName}>`
1856
+ }
1857
+ );
1858
+ }
1859
+ if (mapped.length > 1) {
1860
+ cancelToolCall = true;
1861
+ break;
1862
+ } else {
1863
+ args[k] = (_c = mapped[0]) != null ? _c : "";
1864
+ continue;
1865
+ }
1400
1866
  } else {
1401
- return wrapStream({
1402
- protocol: resolvedProtocol,
1403
- doStream,
1404
- doGenerate,
1405
- params
1867
+ val = v.map((item) => {
1868
+ if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1869
+ const textVal = item == null ? void 0 : item["#text"];
1870
+ return typeof textVal === "string" ? textVal.trim() : textVal;
1871
+ }
1872
+ return typeof item === "string" ? item.trim() : item;
1406
1873
  });
1407
1874
  }
1408
- },
1409
- wrapGenerate: async ({ doGenerate, params }) => wrapGenerate({
1410
- protocol: resolvedProtocol,
1411
- doGenerate,
1412
- params
1413
- }),
1414
- transformParams: async ({
1415
- params
1416
- }) => {
1417
- return transformParams({
1418
- protocol: resolvedProtocol,
1419
- toolSystemPromptTemplate,
1420
- params
1421
- });
1875
+ } else if (v && typeof v === "object" && !Object.prototype.hasOwnProperty.call(v, "#text")) {
1876
+ const obj = v;
1877
+ const keys = Object.keys(obj);
1878
+ if (keys.length === 1 && keys[0] === "item") {
1879
+ const itemValue = obj.item;
1880
+ if (Array.isArray(itemValue)) {
1881
+ val = itemValue.map((item) => {
1882
+ let currentVal = item;
1883
+ if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1884
+ currentVal = item == null ? void 0 : item["#text"];
1885
+ }
1886
+ const trimmed = typeof currentVal === "string" ? currentVal.trim() : currentVal;
1887
+ if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1888
+ const num = Number(trimmed);
1889
+ if (Number.isFinite(num)) return num;
1890
+ }
1891
+ return trimmed;
1892
+ });
1893
+ } else {
1894
+ const trimmed = typeof itemValue === "string" ? itemValue.trim() : itemValue;
1895
+ if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1896
+ const num = Number(trimmed);
1897
+ val = Number.isFinite(num) ? num : trimmed;
1898
+ } else {
1899
+ val = trimmed;
1900
+ }
1901
+ }
1902
+ } else {
1903
+ let isIndexedTuple = false;
1904
+ if (keys.length > 0 && keys.every((key) => /^\d+$/.test(key))) {
1905
+ const indices = keys.map((k2) => parseInt(k2, 10)).sort((a, b) => a - b);
1906
+ isIndexedTuple = indices[0] === 0 && indices.every((val2, idx) => val2 === idx);
1907
+ }
1908
+ if (isIndexedTuple) {
1909
+ const sortedKeys = keys.sort(
1910
+ (a, b) => parseInt(a, 10) - parseInt(b, 10)
1911
+ );
1912
+ val = sortedKeys.map((key) => {
1913
+ const item = obj[key];
1914
+ if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1915
+ const textVal = item == null ? void 0 : item["#text"];
1916
+ return typeof textVal === "string" ? textVal.trim() : textVal;
1917
+ }
1918
+ return typeof item === "string" ? item.trim() : item;
1919
+ });
1920
+ } else {
1921
+ val = v;
1922
+ }
1923
+ }
1422
1924
  }
1423
- };
1925
+ args[k] = typeof val === "string" ? val.trim() : val;
1926
+ }
1927
+ return { args, cancelToolCall };
1424
1928
  }
1425
-
1426
- // src/protocols/json-mix-protocol.ts
1427
- var import_provider_utils3 = require("@ai-sdk/provider-utils");
1428
- var jsonMixProtocol = ({
1429
- toolCallStart = "<tool_call>",
1430
- toolCallEnd = "</tool_call>",
1431
- toolResponseStart = "<tool_response>",
1432
- toolResponseEnd = "</tool_response>"
1433
- } = {}) => ({
1929
+ var morphXmlProtocol = () => ({
1434
1930
  formatTools({ tools, toolSystemPromptTemplate }) {
1435
- const toolsForPrompt = (tools || []).filter((tool) => tool.type === "function").map((tool) => ({
1931
+ const toolsForPrompt = (tools || []).map((tool) => ({
1436
1932
  name: tool.name,
1437
- description: tool.type === "function" && typeof tool.description === "string" ? tool.description : void 0,
1438
- parameters: tool.inputSchema
1933
+ description: tool.description,
1934
+ parameters: unwrapJsonSchema(tool.inputSchema)
1439
1935
  }));
1440
1936
  return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1441
1937
  },
1442
1938
  formatToolCall(toolCall) {
1939
+ const builder = new import_fast_xml_parser.XMLBuilder({ format: true, suppressEmptyNode: true });
1443
1940
  let args = {};
1444
- try {
1445
- args = JSON.parse(toolCall.input);
1446
- } catch (e) {
1447
- args = toolCall.input;
1941
+ const inputValue = hasInputProperty(toolCall) ? toolCall.input : void 0;
1942
+ if (typeof inputValue === "string") {
1943
+ try {
1944
+ args = JSON.parse(inputValue);
1945
+ } catch (e) {
1946
+ args = inputValue;
1947
+ }
1948
+ } else {
1949
+ args = inputValue;
1448
1950
  }
1449
- return `${toolCallStart}${JSON.stringify({
1450
- name: toolCall.toolName,
1451
- arguments: args
1452
- })}${toolCallEnd}`;
1951
+ const xmlContent = builder.build({
1952
+ [toolCall.toolName]: args
1953
+ });
1954
+ return xmlContent;
1453
1955
  },
1454
1956
  formatToolResponse(toolResult) {
1455
- return `${toolResponseStart}${JSON.stringify({
1456
- toolName: toolResult.toolName,
1457
- result: toolResult.output
1458
- })}${toolResponseEnd}`;
1957
+ const builder = new import_fast_xml_parser.XMLBuilder({ format: true });
1958
+ const xmlContent = builder.build({
1959
+ tool_response: {
1960
+ tool_name: toolResult.toolName,
1961
+ result: toolResult.output
1962
+ }
1963
+ });
1964
+ return xmlContent;
1459
1965
  },
1460
- parseGeneratedText({ text, options }) {
1461
- var _a;
1462
- const startEsc = escapeRegExp(toolCallStart);
1463
- const endEsc = escapeRegExp(toolCallEnd);
1966
+ parseGeneratedText({ text, tools, options }) {
1967
+ var _a, _b, _c;
1968
+ const originalSchemas = (options == null ? void 0 : options.originalToolSchemas) || {};
1969
+ const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1970
+ if (toolNames.length === 0) {
1971
+ return [{ type: "text", text }];
1972
+ }
1973
+ const toolNamesPattern = toolNames.map((n) => escapeRegExp(n)).join("|");
1464
1974
  const toolCallRegex = new RegExp(
1465
- `${startEsc}([\0-\uFFFF]*?)${endEsc}`,
1466
- "gs"
1975
+ String.raw`<(${toolNamesPattern})>([\s\S]*?)<\/\1>`,
1976
+ "g"
1467
1977
  );
1468
1978
  const processedElements = [];
1469
1979
  let currentIndex = 0;
1470
1980
  let match;
1471
1981
  while ((match = toolCallRegex.exec(text)) !== null) {
1472
1982
  const startIndex = match.index;
1473
- const toolCallJson = match[1];
1983
+ const toolName = match[1];
1984
+ const toolContent = match[2].trim();
1474
1985
  if (startIndex > currentIndex) {
1475
1986
  const textSegment = text.substring(currentIndex, startIndex);
1476
1987
  if (textSegment.trim()) {
1477
1988
  processedElements.push({ type: "text", text: textSegment });
1478
1989
  }
1479
1990
  }
1480
- if (toolCallJson) {
1481
- try {
1482
- const parsedToolCall = relaxed_json_exports.parse(toolCallJson);
1991
+ try {
1992
+ const parser = new import_fast_xml_parser.XMLParser({
1993
+ ignoreAttributes: false,
1994
+ parseTagValue: false,
1995
+ ignoreDeclaration: true,
1996
+ textNodeName: "#text"
1997
+ });
1998
+ const parsedArgs = ((_a = parser.parse(`<root>${toolContent}</root>`)) == null ? void 0 : _a.root) || {};
1999
+ const toolSchema = getToolSchema(tools, originalSchemas, toolName);
2000
+ const { args, cancelToolCall } = processParsedArgs(
2001
+ parsedArgs,
2002
+ toolSchema,
2003
+ toolContent,
2004
+ toolName,
2005
+ options
2006
+ );
2007
+ if (cancelToolCall) {
2008
+ const originalCallText = match[0];
2009
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
2010
+ options,
2011
+ `Duplicate string tags detected; cancelling tool call`,
2012
+ { toolCall: originalCallText, toolName }
2013
+ );
2014
+ processedElements.push({ type: "text", text: originalCallText });
2015
+ } else {
2016
+ const coercedArgs = coerceBySchema(args, toolSchema);
1483
2017
  processedElements.push({
1484
2018
  type: "tool-call",
1485
2019
  toolCallId: (0, import_provider_utils3.generateId)(),
1486
- toolName: parsedToolCall.name,
1487
- input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
2020
+ toolName,
2021
+ input: JSON.stringify(coercedArgs)
1488
2022
  });
1489
- } catch (error) {
1490
- if (options == null ? void 0 : options.onError) {
1491
- options.onError(
1492
- "Could not process JSON tool call, keeping original text.",
1493
- { toolCall: match[0], error }
1494
- );
1495
- }
1496
- processedElements.push({ type: "text", text: match[0] });
1497
2023
  }
2024
+ } catch (error) {
2025
+ const message = `Could not process XML tool call, keeping original text: ${match[0]}`;
2026
+ (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(options, message, { toolCall: match[0], toolName, error });
2027
+ processedElements.push({ type: "text", text: match[0] });
1498
2028
  }
1499
2029
  currentIndex = startIndex + match[0].length;
1500
2030
  }
@@ -1506,524 +2036,722 @@ var jsonMixProtocol = ({
1506
2036
  }
1507
2037
  return processedElements;
1508
2038
  },
1509
- createStreamParser({ tools: _tools, options } = { tools: [] }) {
1510
- let isInsideToolCall = false;
2039
+ createStreamParser({ tools, options }) {
2040
+ const originalSchemas = (options == null ? void 0 : options.originalToolSchemas) || {};
2041
+ const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1511
2042
  let buffer = "";
1512
- let currentToolCallJson = "";
2043
+ let currentToolCall = null;
1513
2044
  let currentTextId = null;
1514
- let hasEmittedTextStart = false;
1515
- return new TransformStream({
1516
- transform(chunk, controller) {
1517
- var _a;
1518
- if (chunk.type === "finish") {
1519
- if (isInsideToolCall && buffer.length > 0) {
1520
- if (!currentTextId) {
1521
- currentTextId = (0, import_provider_utils3.generateId)();
1522
- controller.enqueue({ type: "text-start", id: currentTextId });
1523
- hasEmittedTextStart = true;
1524
- }
1525
- controller.enqueue({
1526
- type: "text-delta",
1527
- id: currentTextId,
1528
- delta: `${toolCallStart}${buffer}`
1529
- });
1530
- buffer = "";
1531
- } else if (!isInsideToolCall && buffer.length > 0) {
1532
- if (!currentTextId) {
1533
- currentTextId = (0, import_provider_utils3.generateId)();
1534
- controller.enqueue({ type: "text-start", id: currentTextId });
1535
- hasEmittedTextStart = true;
1536
- }
1537
- controller.enqueue({
1538
- type: "text-delta",
1539
- id: currentTextId,
1540
- delta: buffer
1541
- });
1542
- buffer = "";
1543
- }
1544
- if (currentTextId && hasEmittedTextStart) {
1545
- controller.enqueue({ type: "text-end", id: currentTextId });
1546
- currentTextId = null;
1547
- hasEmittedTextStart = false;
1548
- }
1549
- if (currentToolCallJson) {
1550
- const errorId = (0, import_provider_utils3.generateId)();
1551
- controller.enqueue({ type: "text-start", id: errorId });
1552
- controller.enqueue({
1553
- type: "text-delta",
1554
- id: errorId,
1555
- delta: `${toolCallStart}${currentToolCallJson}`
1556
- });
1557
- controller.enqueue({ type: "text-end", id: errorId });
1558
- currentToolCallJson = "";
1559
- }
1560
- controller.enqueue(chunk);
1561
- return;
2045
+ const flushText = (controller, text) => {
2046
+ const content = text != null ? text : buffer;
2047
+ if (content) {
2048
+ if (!currentTextId) {
2049
+ currentTextId = (0, import_provider_utils3.generateId)();
2050
+ controller.enqueue({ type: "text-start", id: currentTextId });
2051
+ }
2052
+ controller.enqueue({
2053
+ type: "text-delta",
2054
+ id: currentTextId,
2055
+ delta: content
2056
+ });
2057
+ if (text === void 0) {
2058
+ buffer = "";
1562
2059
  }
2060
+ }
2061
+ if (currentTextId && !text) {
2062
+ controller.enqueue({ type: "text-end", id: currentTextId });
2063
+ currentTextId = null;
2064
+ }
2065
+ };
2066
+ return new TransformStream({
2067
+ transform(chunk, controller) {
2068
+ var _a;
1563
2069
  if (chunk.type !== "text-delta") {
2070
+ if (buffer) flushText(controller);
1564
2071
  controller.enqueue(chunk);
1565
2072
  return;
1566
2073
  }
1567
2074
  buffer += chunk.delta;
1568
- const publish = (text) => {
1569
- if (isInsideToolCall) {
1570
- if (currentTextId && hasEmittedTextStart) {
1571
- controller.enqueue({ type: "text-end", id: currentTextId });
1572
- currentTextId = null;
1573
- hasEmittedTextStart = false;
1574
- }
1575
- currentToolCallJson += text;
1576
- } else if (text.length > 0) {
1577
- if (!currentTextId) {
1578
- currentTextId = (0, import_provider_utils3.generateId)();
1579
- controller.enqueue({ type: "text-start", id: currentTextId });
1580
- hasEmittedTextStart = true;
2075
+ while (true) {
2076
+ if (currentToolCall) {
2077
+ const endTag = `</${currentToolCall.name}>`;
2078
+ const endTagIndex = buffer.indexOf(endTag);
2079
+ if (endTagIndex !== -1) {
2080
+ const toolContent = buffer.substring(0, endTagIndex);
2081
+ buffer = buffer.substring(endTagIndex + endTag.length);
2082
+ try {
2083
+ const parser = new import_fast_xml_parser.XMLParser({
2084
+ ignoreAttributes: false,
2085
+ parseTagValue: false,
2086
+ ignoreDeclaration: true,
2087
+ textNodeName: "#text"
2088
+ });
2089
+ const parsedArgs = ((_a = parser.parse(`<root>${toolContent}</root>`)) == null ? void 0 : _a.root) || {};
2090
+ const toolSchema = getToolSchema(
2091
+ tools,
2092
+ originalSchemas,
2093
+ currentToolCall.name
2094
+ );
2095
+ const { args, cancelToolCall } = processParsedArgs(
2096
+ parsedArgs,
2097
+ toolSchema,
2098
+ toolContent,
2099
+ currentToolCall.name,
2100
+ options
2101
+ );
2102
+ if (cancelToolCall) {
2103
+ const originalCallText = `<${currentToolCall.name}>${toolContent}</${currentToolCall.name}>`;
2104
+ if (options == null ? void 0 : options.onError) {
2105
+ options.onError(
2106
+ "Duplicate string tags detected; cancelling tool call",
2107
+ {
2108
+ toolCall: originalCallText,
2109
+ toolName: currentToolCall.name
2110
+ }
2111
+ );
2112
+ }
2113
+ flushText(controller, originalCallText);
2114
+ } else {
2115
+ const coercedArgs = coerceBySchema(
2116
+ args,
2117
+ toolSchema
2118
+ );
2119
+ flushText(controller);
2120
+ controller.enqueue({
2121
+ type: "tool-call",
2122
+ toolCallId: (0, import_provider_utils3.generateId)(),
2123
+ toolName: currentToolCall.name,
2124
+ input: JSON.stringify(coercedArgs)
2125
+ });
2126
+ }
2127
+ } catch (e) {
2128
+ const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
2129
+ if (options == null ? void 0 : options.onError) {
2130
+ options.onError(
2131
+ "Could not process streaming XML tool call; emitting original text.",
2132
+ {
2133
+ toolCall: originalCallText,
2134
+ toolName: currentToolCall.name
2135
+ }
2136
+ );
2137
+ }
2138
+ flushText(controller, originalCallText);
2139
+ }
2140
+ currentToolCall = null;
2141
+ } else {
2142
+ break;
1581
2143
  }
1582
- controller.enqueue({
1583
- type: "text-delta",
1584
- id: currentTextId,
1585
- delta: text
1586
- });
1587
- }
1588
- };
1589
- let startIndex;
1590
- while ((startIndex = getPotentialStartIndex(
1591
- buffer,
1592
- isInsideToolCall ? toolCallEnd : toolCallStart
1593
- )) != null) {
1594
- const tag = isInsideToolCall ? toolCallEnd : toolCallStart;
1595
- if (startIndex + tag.length > buffer.length) {
1596
- break;
1597
- }
1598
- publish(buffer.slice(0, startIndex));
1599
- buffer = buffer.slice(startIndex + tag.length);
1600
- if (!isInsideToolCall) {
1601
- currentToolCallJson = "";
1602
- isInsideToolCall = true;
1603
2144
  } else {
1604
- try {
1605
- const parsedToolCall = relaxed_json_exports.parse(currentToolCallJson);
1606
- if (currentTextId && hasEmittedTextStart) {
1607
- controller.enqueue({ type: "text-end", id: currentTextId });
1608
- currentTextId = null;
1609
- hasEmittedTextStart = false;
1610
- }
1611
- controller.enqueue({
1612
- type: "tool-call",
1613
- toolCallId: (0, import_provider_utils3.generateId)(),
1614
- toolName: parsedToolCall.name,
1615
- input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1616
- });
1617
- } catch (e) {
1618
- const errorId = (0, import_provider_utils3.generateId)();
1619
- controller.enqueue({ type: "text-start", id: errorId });
1620
- controller.enqueue({
1621
- type: "text-delta",
1622
- id: errorId,
1623
- delta: `${toolCallStart}${currentToolCallJson}${toolCallEnd}`
1624
- });
1625
- controller.enqueue({ type: "text-end", id: errorId });
1626
- if (options == null ? void 0 : options.onError) {
1627
- options.onError(
1628
- "Could not process streaming JSON tool call; emitting original text.",
1629
- {
1630
- toolCall: `${toolCallStart}${currentToolCallJson}${toolCallEnd}`
1631
- }
1632
- );
2145
+ let earliestStartTagIndex = -1;
2146
+ let earliestToolName = "";
2147
+ if (toolNames.length > 0) {
2148
+ for (const name of toolNames) {
2149
+ const startTag = `<${name}>`;
2150
+ const index = buffer.indexOf(startTag);
2151
+ if (index !== -1 && (earliestStartTagIndex === -1 || index < earliestStartTagIndex)) {
2152
+ earliestStartTagIndex = index;
2153
+ earliestToolName = name;
2154
+ }
1633
2155
  }
1634
2156
  }
1635
- currentToolCallJson = "";
1636
- isInsideToolCall = false;
2157
+ if (earliestStartTagIndex !== -1) {
2158
+ const textBeforeTag = buffer.substring(0, earliestStartTagIndex);
2159
+ flushText(controller, textBeforeTag);
2160
+ const startTag = `<${earliestToolName}>`;
2161
+ buffer = buffer.substring(
2162
+ earliestStartTagIndex + startTag.length
2163
+ );
2164
+ currentToolCall = { name: earliestToolName, content: "" };
2165
+ } else {
2166
+ break;
2167
+ }
1637
2168
  }
1638
2169
  }
1639
- if (!isInsideToolCall) {
1640
- const potentialIndex = getPotentialStartIndex(buffer, toolCallStart);
1641
- if (potentialIndex != null && potentialIndex + toolCallStart.length > buffer.length) {
1642
- publish(buffer.slice(0, potentialIndex));
1643
- buffer = buffer.slice(potentialIndex);
1644
- } else {
1645
- publish(buffer);
1646
- buffer = "";
1647
- }
2170
+ },
2171
+ flush(controller) {
2172
+ if (currentToolCall) {
2173
+ const unfinishedCall = `<${currentToolCall.name}>${buffer}`;
2174
+ flushText(controller, unfinishedCall);
2175
+ } else if (buffer) {
2176
+ flushText(controller);
2177
+ }
2178
+ if (currentTextId) {
2179
+ controller.enqueue({ type: "text-end", id: currentTextId });
1648
2180
  }
1649
2181
  }
1650
2182
  });
2183
+ },
2184
+ extractToolCallSegments({ text, tools }) {
2185
+ const toolNames = tools.map((t) => t.name).filter(Boolean);
2186
+ if (toolNames.length === 0) return [];
2187
+ const names = toolNames.map((n) => escapeRegExp(String(n))).join("|");
2188
+ if (!names) return [];
2189
+ const regex = new RegExp(`<(${names})>[\\s\\S]*?<\\/\\1>`, "g");
2190
+ const segments = [];
2191
+ let m;
2192
+ while ((m = regex.exec(text)) != null) {
2193
+ segments.push(m[0]);
2194
+ }
2195
+ return segments;
1651
2196
  }
1652
2197
  });
1653
2198
 
1654
- // src/protocols/xml-protocol.ts
2199
+ // src/generate-handler.ts
1655
2200
  var import_provider_utils4 = require("@ai-sdk/provider-utils");
1656
- var import_fast_xml_parser = require("fast-xml-parser");
1657
- var xmlProtocol = () => ({
1658
- formatTools({ tools, toolSystemPromptTemplate }) {
1659
- const toolsForPrompt = (tools || []).map((tool) => ({
1660
- name: tool.name,
1661
- description: tool.description,
1662
- parameters: unwrapJsonSchema(tool.inputSchema)
1663
- }));
1664
- return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1665
- },
1666
- formatToolCall(toolCall) {
1667
- const builder = new import_fast_xml_parser.XMLBuilder({ format: true, suppressEmptyNode: true });
1668
- let args = {};
1669
- const inputValue = hasInputProperty(toolCall) ? toolCall.input : void 0;
1670
- if (typeof inputValue === "string") {
2201
+ async function wrapGenerate({
2202
+ protocol,
2203
+ doGenerate,
2204
+ params
2205
+ }) {
2206
+ var _a, _b;
2207
+ if (isToolChoiceActive(params)) {
2208
+ const result2 = await doGenerate();
2209
+ let parsed2 = {};
2210
+ const first = (_a = result2.content) == null ? void 0 : _a[0];
2211
+ if (first && first.type === "text") {
2212
+ const debugLevel2 = getDebugLevel();
2213
+ if (debugLevel2 === "parse") {
2214
+ logRawChunk(first.text);
2215
+ }
1671
2216
  try {
1672
- args = JSON.parse(inputValue);
1673
- } catch (e) {
1674
- args = inputValue;
2217
+ parsed2 = JSON.parse(first.text);
2218
+ } catch (error) {
2219
+ const options = extractOnErrorOption(params.providerOptions);
2220
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
2221
+ options,
2222
+ "Failed to parse toolChoice JSON from generated model output",
2223
+ {
2224
+ text: first.text,
2225
+ error: error instanceof Error ? error.message : String(error)
2226
+ }
2227
+ );
2228
+ parsed2 = {};
1675
2229
  }
1676
- } else {
1677
- args = inputValue;
1678
2230
  }
1679
- const xmlContent = builder.build({
1680
- [toolCall.toolName]: args
1681
- });
1682
- return xmlContent;
1683
- },
1684
- formatToolResponse(toolResult) {
1685
- const builder = new import_fast_xml_parser.XMLBuilder({ format: true });
1686
- const xmlContent = builder.build({
1687
- tool_response: {
1688
- tool_name: toolResult.toolName,
1689
- result: toolResult.output
2231
+ const toolCall = {
2232
+ type: "tool-call",
2233
+ toolCallId: (0, import_provider_utils4.generateId)(),
2234
+ toolName: parsed2.name || "unknown",
2235
+ input: JSON.stringify(parsed2.arguments || {})
2236
+ };
2237
+ const debugLevelToolChoice = getDebugLevel();
2238
+ const originText = first && first.type === "text" ? first.text : "";
2239
+ if (debugLevelToolChoice === "parse") {
2240
+ logParsedSummary({ toolCalls: [toolCall], originalText: originText });
2241
+ }
2242
+ return {
2243
+ ...result2,
2244
+ content: [toolCall]
2245
+ };
2246
+ }
2247
+ const result = await doGenerate();
2248
+ if (result.content.length === 0) {
2249
+ return result;
2250
+ }
2251
+ const parsed = result.content.flatMap((contentItem) => {
2252
+ var _a2;
2253
+ if (contentItem.type !== "text") {
2254
+ return [contentItem];
2255
+ }
2256
+ const debugLevel2 = getDebugLevel();
2257
+ if (debugLevel2 === "stream") {
2258
+ logRawChunk(contentItem.text);
2259
+ }
2260
+ return protocol.parseGeneratedText({
2261
+ text: contentItem.text,
2262
+ tools: getFunctionTools(params),
2263
+ options: {
2264
+ ...extractOnErrorOption(params.providerOptions),
2265
+ ...(_a2 = params.providerOptions) == null ? void 0 : _a2.toolCallMiddleware
1690
2266
  }
1691
2267
  });
1692
- return xmlContent;
1693
- },
1694
- parseGeneratedText({ text, tools, options }) {
1695
- var _a, _b, _c;
1696
- const originalSchemas = (options == null ? void 0 : options.originalToolSchemas) || {};
1697
- const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1698
- if (toolNames.length === 0) {
1699
- return [{ type: "text", text }];
1700
- }
1701
- const toolNamesPattern = toolNames.map((n) => escapeRegExp(n)).join("|");
1702
- const toolCallRegex = new RegExp(
1703
- String.raw`<(${toolNamesPattern})>([\s\S]*?)<\/\1>`,
1704
- "g"
2268
+ });
2269
+ const tools = getFunctionTools(params);
2270
+ const newContent = parsed.map(
2271
+ (part) => coerceToolCallInput(part, tools)
2272
+ );
2273
+ const debugLevel = getDebugLevel();
2274
+ if (debugLevel === "stream") {
2275
+ newContent.forEach((part) => logParsedChunk(part));
2276
+ }
2277
+ if (debugLevel === "parse") {
2278
+ const allText = result.content.filter(
2279
+ (c) => c.type === "text"
2280
+ ).map((c) => c.text).join("\n\n");
2281
+ const segments = protocol.extractToolCallSegments ? protocol.extractToolCallSegments({ text: allText, tools }) : [];
2282
+ const originalText = segments.join("\n\n");
2283
+ const toolCalls = newContent.filter(
2284
+ (p) => p.type === "tool-call"
2285
+ );
2286
+ logParsedSummary({ toolCalls, originalText });
2287
+ }
2288
+ return {
2289
+ ...result,
2290
+ content: newContent
2291
+ };
2292
+ }
2293
+
2294
+ // src/stream-handler.ts
2295
+ var import_provider_utils5 = require("@ai-sdk/provider-utils");
2296
+ async function wrapStream({
2297
+ protocol,
2298
+ doStream,
2299
+ doGenerate,
2300
+ params
2301
+ }) {
2302
+ var _a;
2303
+ if (isToolChoiceActive(params)) {
2304
+ return toolChoiceStream({
2305
+ doGenerate,
2306
+ options: extractOnErrorOption(params.providerOptions)
2307
+ });
2308
+ }
2309
+ const { stream, ...rest } = await doStream();
2310
+ const debugLevel = getDebugLevel();
2311
+ const tools = getFunctionTools(params);
2312
+ const options = {
2313
+ ...extractOnErrorOption(params.providerOptions),
2314
+ ...(_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware
2315
+ };
2316
+ if (debugLevel === "off") {
2317
+ return {
2318
+ stream: stream.pipeThrough(
2319
+ protocol.createStreamParser({
2320
+ tools,
2321
+ options
2322
+ })
2323
+ ),
2324
+ ...rest
2325
+ };
2326
+ }
2327
+ if (debugLevel === "stream") {
2328
+ const withRawTap2 = stream.pipeThrough(
2329
+ new TransformStream(
2330
+ {
2331
+ transform(part, controller) {
2332
+ logRawChunk(part);
2333
+ controller.enqueue(part);
2334
+ }
2335
+ }
2336
+ )
1705
2337
  );
1706
- const processedElements = [];
1707
- let currentIndex = 0;
1708
- let match;
1709
- while ((match = toolCallRegex.exec(text)) !== null) {
1710
- const startIndex = match.index;
1711
- const toolName = match[1];
1712
- const toolContent = match[2].trim();
1713
- if (startIndex > currentIndex) {
1714
- const textSegment = text.substring(currentIndex, startIndex);
1715
- if (textSegment.trim()) {
1716
- processedElements.push({ type: "text", text: textSegment });
2338
+ const parsed2 = withRawTap2.pipeThrough(
2339
+ protocol.createStreamParser({
2340
+ tools,
2341
+ options
2342
+ })
2343
+ );
2344
+ const withParsedTap = parsed2.pipeThrough(
2345
+ new TransformStream(
2346
+ {
2347
+ transform(part, controller) {
2348
+ logParsedChunk(part);
2349
+ controller.enqueue(part);
2350
+ }
2351
+ }
2352
+ )
2353
+ );
2354
+ return {
2355
+ stream: withParsedTap,
2356
+ ...rest
2357
+ };
2358
+ }
2359
+ let fullRawText = "";
2360
+ const withRawTap = stream.pipeThrough(
2361
+ new TransformStream({
2362
+ transform(part, controller) {
2363
+ if (part.type === "text-delta") {
2364
+ const delta = part.delta;
2365
+ if (typeof delta === "string" && delta.length > 0) {
2366
+ fullRawText += delta;
2367
+ }
1717
2368
  }
2369
+ controller.enqueue(part);
1718
2370
  }
1719
- try {
1720
- const parser = new import_fast_xml_parser.XMLParser({
1721
- ignoreAttributes: false,
1722
- parseTagValue: false,
1723
- ignoreDeclaration: true,
1724
- textNodeName: "#text"
1725
- });
1726
- const parsedArgs = ((_a = parser.parse(`<root>${toolContent}</root>`)) == null ? void 0 : _a.root) || {};
1727
- const args = {};
1728
- for (const k of Object.keys(parsedArgs || {})) {
1729
- const v = parsedArgs[k];
1730
- let val = v;
1731
- if (v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, "#text")) {
1732
- val = v == null ? void 0 : v["#text"];
2371
+ })
2372
+ );
2373
+ const parsed = withRawTap.pipeThrough(
2374
+ protocol.createStreamParser({
2375
+ tools,
2376
+ options
2377
+ })
2378
+ );
2379
+ const withSummary = parsed.pipeThrough(
2380
+ new TransformStream({
2381
+ transform: /* @__PURE__ */ (() => {
2382
+ const parsedToolCalls = [];
2383
+ return (part, controller) => {
2384
+ if (part.type === "tool-call") {
2385
+ parsedToolCalls.push(part);
1733
2386
  }
1734
- if (Array.isArray(v)) {
1735
- val = v.map((item) => {
1736
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1737
- const textVal = item == null ? void 0 : item["#text"];
1738
- return typeof textVal === "string" ? textVal.trim() : textVal;
1739
- }
1740
- return typeof item === "string" ? item.trim() : item;
1741
- });
1742
- } else if (v && typeof v === "object" && !Object.prototype.hasOwnProperty.call(v, "#text")) {
1743
- const obj = v;
1744
- const keys = Object.keys(obj);
1745
- if (keys.length === 1 && keys[0] === "item") {
1746
- const itemValue = obj.item;
1747
- if (Array.isArray(itemValue)) {
1748
- val = itemValue.map((item) => {
1749
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1750
- const textVal = item == null ? void 0 : item["#text"];
1751
- const trimmed2 = typeof textVal === "string" ? textVal.trim() : textVal;
1752
- if (typeof trimmed2 === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed2)) {
1753
- const num = Number(trimmed2);
1754
- if (Number.isFinite(num)) return num;
1755
- }
1756
- return trimmed2;
1757
- }
1758
- const trimmed = typeof item === "string" ? item.trim() : item;
1759
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1760
- const num = Number(trimmed);
1761
- if (Number.isFinite(num)) return num;
1762
- }
1763
- return trimmed;
1764
- });
1765
- } else {
1766
- const trimmed = typeof itemValue === "string" ? itemValue.trim() : itemValue;
1767
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1768
- const num = Number(trimmed);
1769
- if (Number.isFinite(num)) {
1770
- val = num;
1771
- } else {
1772
- val = trimmed;
1773
- }
1774
- } else {
1775
- val = trimmed;
1776
- }
1777
- }
1778
- } else {
1779
- const isIndexedTuple = keys.length > 0 && keys.every((key) => /^\d+$/.test(key)) && (() => {
1780
- const indices = keys.map((k2) => parseInt(k2)).sort((a, b) => a - b);
1781
- return indices[0] === 0 && indices.every((val2, idx) => val2 === idx);
1782
- })();
1783
- if (isIndexedTuple) {
1784
- const sortedKeys = keys.sort(
1785
- (a, b) => parseInt(a) - parseInt(b)
1786
- );
1787
- val = sortedKeys.map((key) => {
1788
- const item = obj[key];
1789
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1790
- const textVal = item == null ? void 0 : item["#text"];
1791
- return typeof textVal === "string" ? textVal.trim() : textVal;
1792
- }
1793
- return typeof item === "string" ? item.trim() : item;
1794
- });
1795
- } else {
1796
- val = v;
1797
- }
2387
+ if (part.type === "finish") {
2388
+ try {
2389
+ const segments = protocol.extractToolCallSegments ? protocol.extractToolCallSegments({
2390
+ text: fullRawText,
2391
+ tools
2392
+ }) : [];
2393
+ const origin = segments.join("\n\n");
2394
+ logParsedSummary({
2395
+ toolCalls: parsedToolCalls,
2396
+ originalText: origin
2397
+ });
2398
+ } catch (e) {
1798
2399
  }
1799
2400
  }
1800
- args[k] = typeof val === "string" ? val.trim() : val;
2401
+ controller.enqueue(part);
2402
+ };
2403
+ })()
2404
+ })
2405
+ );
2406
+ return {
2407
+ stream: withSummary,
2408
+ ...rest
2409
+ };
2410
+ }
2411
+ async function toolChoiceStream({
2412
+ doGenerate,
2413
+ options
2414
+ }) {
2415
+ var _a, _b;
2416
+ const result = await doGenerate();
2417
+ let toolJson = {};
2418
+ if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
2419
+ try {
2420
+ toolJson = JSON.parse(result.content[0].text);
2421
+ } catch (error) {
2422
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
2423
+ options,
2424
+ "Failed to parse toolChoice JSON from streamed model output",
2425
+ {
2426
+ text: result.content[0].text,
2427
+ error: error instanceof Error ? error.message : String(error)
1801
2428
  }
1802
- const originalSchema = originalSchemas[toolName];
1803
- const fallbackSchema = (_b = tools.find((t) => t.name === toolName)) == null ? void 0 : _b.inputSchema;
1804
- const schema = originalSchema || fallbackSchema;
1805
- const coercedArgs = coerceBySchema(args, schema);
1806
- processedElements.push({
1807
- type: "tool-call",
1808
- toolCallId: (0, import_provider_utils4.generateId)(),
1809
- toolName,
1810
- input: JSON.stringify(coercedArgs)
1811
- });
1812
- } catch (error) {
1813
- const message = `Could not process XML tool call, keeping original text: ${match[0]}`;
1814
- (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(options, message, { toolCall: match[0], toolName, error });
1815
- processedElements.push({ type: "text", text: match[0] });
1816
- }
1817
- currentIndex = startIndex + match[0].length;
2429
+ );
2430
+ toolJson = {};
1818
2431
  }
1819
- if (currentIndex < text.length) {
1820
- const remainingText = text.substring(currentIndex);
1821
- if (remainingText.trim()) {
1822
- processedElements.push({ type: "text", text: remainingText });
1823
- }
2432
+ }
2433
+ const toolCallChunk = {
2434
+ type: "tool-call",
2435
+ toolCallId: (0, import_provider_utils5.generateId)(),
2436
+ toolName: toolJson.name || "unknown",
2437
+ input: JSON.stringify(toolJson.arguments || {})
2438
+ };
2439
+ const finishChunk = {
2440
+ type: "finish",
2441
+ usage: (result == null ? void 0 : result.usage) || // TODO: If possible, try to return a certain amount of LLM usage.
2442
+ {
2443
+ inputTokens: 0,
2444
+ outputTokens: 0,
2445
+ totalTokens: 0
2446
+ },
2447
+ finishReason: "tool-calls"
2448
+ };
2449
+ const stream = new ReadableStream({
2450
+ start(controller) {
2451
+ controller.enqueue(toolCallChunk);
2452
+ controller.enqueue(finishChunk);
2453
+ controller.close();
1824
2454
  }
1825
- return processedElements;
1826
- },
1827
- createStreamParser({ tools, options }) {
1828
- const originalSchemas = (options == null ? void 0 : options.originalToolSchemas) || {};
1829
- const toolNames = tools.map((t) => t.name).filter((name) => name != null);
1830
- let buffer = "";
1831
- let currentToolCall = null;
1832
- let currentTextId = null;
1833
- const flushText = (controller, text) => {
1834
- const content = text != null ? text : buffer;
1835
- if (content) {
1836
- if (!currentTextId) {
1837
- currentTextId = (0, import_provider_utils4.generateId)();
1838
- controller.enqueue({ type: "text-start", id: currentTextId });
2455
+ });
2456
+ const debugLevel = getDebugLevel();
2457
+ const firstText = (result == null ? void 0 : result.content) && result.content[0] && result.content[0].type === "text" && result.content[0].text || "";
2458
+ const streamWithSummary = debugLevel === "parse" ? stream.pipeThrough(
2459
+ new TransformStream({
2460
+ transform(part, controller) {
2461
+ if (part.type === "finish") {
2462
+ try {
2463
+ logParsedSummary({
2464
+ toolCalls: [toolCallChunk],
2465
+ originalText: typeof firstText === "string" ? firstText : ""
2466
+ });
2467
+ } catch (e) {
2468
+ }
1839
2469
  }
1840
- controller.enqueue({
1841
- type: "text-delta",
1842
- id: currentTextId,
1843
- delta: content
1844
- });
1845
- if (text === void 0) {
1846
- buffer = "";
2470
+ controller.enqueue(part);
2471
+ }
2472
+ })
2473
+ ) : stream;
2474
+ return {
2475
+ request: (result == null ? void 0 : result.request) || {},
2476
+ response: (result == null ? void 0 : result.response) || {},
2477
+ stream: streamWithSummary
2478
+ };
2479
+ }
2480
+
2481
+ // src/transform-handler.ts
2482
+ async function transformParams({
2483
+ params,
2484
+ protocol,
2485
+ toolSystemPromptTemplate
2486
+ }) {
2487
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2488
+ const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
2489
+ const functionTools = ((_a = params.tools) != null ? _a : []).filter(
2490
+ (t) => t.type === "function"
2491
+ );
2492
+ const systemPrompt = resolvedProtocol.formatTools({
2493
+ tools: functionTools,
2494
+ toolSystemPromptTemplate
2495
+ });
2496
+ const processedPrompt = convertToolPrompt(
2497
+ (_b = params.prompt) != null ? _b : [],
2498
+ resolvedProtocol,
2499
+ extractOnErrorOption(params.providerOptions)
2500
+ );
2501
+ const finalPrompt = ((_c = processedPrompt[0]) == null ? void 0 : _c.role) === "system" ? [
2502
+ {
2503
+ role: "system",
2504
+ content: systemPrompt + "\n\n" + processedPrompt[0].content
2505
+ },
2506
+ ...processedPrompt.slice(1)
2507
+ ] : [
2508
+ {
2509
+ role: "system",
2510
+ content: systemPrompt
2511
+ },
2512
+ ...processedPrompt
2513
+ ];
2514
+ const baseReturnParams = {
2515
+ ...params,
2516
+ prompt: finalPrompt,
2517
+ tools: [],
2518
+ toolChoice: void 0,
2519
+ providerOptions: {
2520
+ ...params.providerOptions || {},
2521
+ toolCallMiddleware: {
2522
+ ...params.providerOptions && typeof params.providerOptions === "object" && params.providerOptions.toolCallMiddleware || {},
2523
+ // INTERNAL: used by the middleware to propagate the names of custom
2524
+ // function tools into downstream handlers (stream/generate) when
2525
+ // providers strip or ignore `params.tools`. Not a stable public API.
2526
+ toolNames: functionTools.map((t) => t.name)
2527
+ }
2528
+ }
2529
+ };
2530
+ if (((_d = params.toolChoice) == null ? void 0 : _d.type) === "none") {
2531
+ throw new Error(
2532
+ "The 'none' toolChoice type is not supported by this middleware. Please use 'auto', 'required', or specify a tool name."
2533
+ );
2534
+ }
2535
+ if (((_e = params.toolChoice) == null ? void 0 : _e.type) === "tool") {
2536
+ const selectedToolName = params.toolChoice.toolName;
2537
+ const providerDefinedMatch = ((_f = params.tools) != null ? _f : []).find((t) => {
2538
+ if (t.type === "function") return false;
2539
+ const anyTool = t;
2540
+ return anyTool.id === selectedToolName || anyTool.name === selectedToolName;
2541
+ });
2542
+ if (providerDefinedMatch) {
2543
+ throw new Error(
2544
+ "Provider-defined tools are not supported by this middleware. Please use custom tools."
2545
+ );
2546
+ }
2547
+ const selectedTool = ((_g = params.tools) != null ? _g : []).find(
2548
+ (t) => t.type === "function" && t.name === selectedToolName
2549
+ );
2550
+ if (!selectedTool) {
2551
+ throw new Error(
2552
+ `Tool with name '${selectedToolName}' not found in params.tools.`
2553
+ );
2554
+ }
2555
+ return {
2556
+ ...baseReturnParams,
2557
+ responseFormat: {
2558
+ type: "json",
2559
+ schema: {
2560
+ type: "object",
2561
+ properties: {
2562
+ name: {
2563
+ const: selectedTool.name
2564
+ },
2565
+ arguments: selectedTool.inputSchema
2566
+ },
2567
+ required: ["name", "arguments"]
2568
+ },
2569
+ name: selectedTool.name,
2570
+ description: typeof selectedTool.description === "string" ? selectedTool.description : void 0
2571
+ },
2572
+ providerOptions: {
2573
+ ...baseReturnParams.providerOptions || {},
2574
+ toolCallMiddleware: {
2575
+ ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
2576
+ // INTERNAL: used by the middleware to activate the tool-choice
2577
+ // fast-path in handlers. Not a stable public API.
2578
+ toolChoice: params.toolChoice
1847
2579
  }
1848
2580
  }
1849
- if (currentTextId && !text) {
1850
- controller.enqueue({ type: "text-end", id: currentTextId });
1851
- currentTextId = null;
2581
+ };
2582
+ }
2583
+ if (((_h = params.toolChoice) == null ? void 0 : _h.type) === "required") {
2584
+ if (!params.tools || params.tools.length === 0) {
2585
+ throw new Error(
2586
+ "Tool choice type 'required' is set, but no tools are provided in params.tools."
2587
+ );
2588
+ }
2589
+ return {
2590
+ ...baseReturnParams,
2591
+ responseFormat: {
2592
+ type: "json",
2593
+ schema: createDynamicIfThenElseSchema(functionTools)
2594
+ },
2595
+ providerOptions: {
2596
+ ...baseReturnParams.providerOptions || {},
2597
+ toolCallMiddleware: {
2598
+ ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
2599
+ // INTERNAL: used by the middleware to activate the tool-choice
2600
+ // fast-path in handlers. Not a stable public API.
2601
+ toolChoice: { type: "required" }
2602
+ }
1852
2603
  }
1853
2604
  };
1854
- return new TransformStream({
1855
- transform(chunk, controller) {
1856
- var _a, _b;
1857
- if (chunk.type !== "text-delta") {
1858
- if (buffer) flushText(controller);
1859
- controller.enqueue(chunk);
1860
- return;
2605
+ }
2606
+ return baseReturnParams;
2607
+ }
2608
+ function convertToolPrompt(prompt, resolvedProtocol, providerOptions) {
2609
+ const processedPrompt = prompt.map((message) => {
2610
+ var _a;
2611
+ if (message.role === "assistant") {
2612
+ const newContent = [];
2613
+ for (const content of message.content) {
2614
+ if (isToolCallContent(content)) {
2615
+ newContent.push({
2616
+ type: "text",
2617
+ text: resolvedProtocol.formatToolCall(content)
2618
+ });
2619
+ } else if (content.type === "text") {
2620
+ newContent.push(content);
2621
+ } else if (content.type === "reasoning") {
2622
+ newContent.push(content);
2623
+ } else {
2624
+ const options = extractOnErrorOption(providerOptions);
2625
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
2626
+ options,
2627
+ "tool-call-middleware: unknown assistant content; stringifying for provider compatibility",
2628
+ { content }
2629
+ );
2630
+ newContent.push({
2631
+ type: "text",
2632
+ text: JSON.stringify(content)
2633
+ });
1861
2634
  }
1862
- buffer += chunk.delta;
1863
- while (true) {
1864
- if (currentToolCall) {
1865
- const endTag = `</${currentToolCall.name}>`;
1866
- const endTagIndex = buffer.indexOf(endTag);
1867
- if (endTagIndex !== -1) {
1868
- const toolContent = buffer.substring(0, endTagIndex);
1869
- buffer = buffer.substring(endTagIndex + endTag.length);
1870
- try {
1871
- const parser = new import_fast_xml_parser.XMLParser({
1872
- ignoreAttributes: false,
1873
- parseTagValue: false,
1874
- ignoreDeclaration: true,
1875
- textNodeName: "#text"
1876
- });
1877
- const parsedArgs = ((_a = parser.parse(`<root>${toolContent}</root>`)) == null ? void 0 : _a.root) || {};
1878
- const args = {};
1879
- for (const k of Object.keys(parsedArgs || {})) {
1880
- const v = parsedArgs[k];
1881
- let val = v;
1882
- if (v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, "#text")) {
1883
- val = v == null ? void 0 : v["#text"];
1884
- }
1885
- if (Array.isArray(v)) {
1886
- val = v.map((item) => {
1887
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1888
- const textVal = item == null ? void 0 : item["#text"];
1889
- return typeof textVal === "string" ? textVal.trim() : textVal;
1890
- }
1891
- return typeof item === "string" ? item.trim() : item;
1892
- });
1893
- } else if (v && typeof v === "object" && !Object.prototype.hasOwnProperty.call(v, "#text")) {
1894
- const obj = v;
1895
- const keys = Object.keys(obj);
1896
- if (keys.length === 1 && keys[0] === "item") {
1897
- const itemValue = obj.item;
1898
- if (Array.isArray(itemValue)) {
1899
- val = itemValue.map((item) => {
1900
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1901
- const textVal = item == null ? void 0 : item["#text"];
1902
- const trimmed2 = typeof textVal === "string" ? textVal.trim() : textVal;
1903
- if (typeof trimmed2 === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed2)) {
1904
- const num = Number(trimmed2);
1905
- if (Number.isFinite(num)) return num;
1906
- }
1907
- return trimmed2;
1908
- }
1909
- const trimmed = typeof item === "string" ? item.trim() : item;
1910
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1911
- const num = Number(trimmed);
1912
- if (Number.isFinite(num)) return num;
1913
- }
1914
- return trimmed;
1915
- });
1916
- } else {
1917
- const trimmed = typeof itemValue === "string" ? itemValue.trim() : itemValue;
1918
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1919
- const num = Number(trimmed);
1920
- if (Number.isFinite(num)) {
1921
- val = num;
1922
- } else {
1923
- val = trimmed;
1924
- }
1925
- } else {
1926
- val = trimmed;
1927
- }
1928
- }
1929
- } else {
1930
- const isIndexedTuple = keys.length > 0 && keys.every((key) => /^\d+$/.test(key)) && (() => {
1931
- const indices = keys.map((k2) => parseInt(k2)).sort((a, b) => a - b);
1932
- return indices[0] === 0 && indices.every((val2, idx) => val2 === idx);
1933
- })();
1934
- if (isIndexedTuple) {
1935
- const sortedKeys = keys.sort(
1936
- (a, b) => parseInt(a) - parseInt(b)
1937
- );
1938
- val = sortedKeys.map((key) => {
1939
- const item = obj[key];
1940
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, "#text")) {
1941
- const textVal = item == null ? void 0 : item["#text"];
1942
- return typeof textVal === "string" ? textVal.trim() : textVal;
1943
- }
1944
- return typeof item === "string" ? item.trim() : item;
1945
- });
1946
- } else {
1947
- val = v;
1948
- }
1949
- }
1950
- }
1951
- args[k] = typeof val === "string" ? val.trim() : val;
1952
- }
1953
- const originalSchema = originalSchemas[currentToolCall.name];
1954
- const fallbackSchema = (_b = tools.find(
1955
- (t) => t.name === currentToolCall.name
1956
- )) == null ? void 0 : _b.inputSchema;
1957
- const toolSchema = originalSchema || fallbackSchema;
1958
- const coercedArgs = coerceBySchema(args, toolSchema);
1959
- flushText(controller);
1960
- controller.enqueue({
1961
- type: "tool-call",
1962
- toolCallId: (0, import_provider_utils4.generateId)(),
1963
- toolName: currentToolCall.name,
1964
- input: JSON.stringify(coercedArgs)
1965
- });
1966
- } catch (e) {
1967
- const originalCallText = `<${currentToolCall.name}>${toolContent}${endTag}`;
1968
- if (options == null ? void 0 : options.onError) {
1969
- options.onError(
1970
- "Could not process streaming XML tool call; emitting original text.",
1971
- {
1972
- toolCall: originalCallText,
1973
- toolName: currentToolCall.name
1974
- }
1975
- );
1976
- }
1977
- flushText(controller, originalCallText);
2635
+ }
2636
+ const onlyText = newContent.every((c) => c.type === "text");
2637
+ const condensedAssistant = onlyText ? [
2638
+ {
2639
+ type: "text",
2640
+ text: newContent.map((c) => c.text).join("\n")
2641
+ }
2642
+ ] : newContent;
2643
+ return { role: "assistant", content: condensedAssistant };
2644
+ }
2645
+ if (message.role === "tool") {
2646
+ return {
2647
+ role: "user",
2648
+ // Map tool results to text response blocks, then condense into a single text block
2649
+ content: [
2650
+ {
2651
+ type: "text",
2652
+ text: message.content.map(
2653
+ (toolResult) => isToolResultPart(toolResult) ? resolvedProtocol.formatToolResponse(toolResult) : resolvedProtocol.formatToolResponse(
2654
+ toolResult
2655
+ )
2656
+ ).join("\n")
2657
+ }
2658
+ ]
2659
+ };
2660
+ }
2661
+ return message;
2662
+ });
2663
+ for (let i = 0; i < processedPrompt.length; i++) {
2664
+ const msg = processedPrompt[i];
2665
+ if (Array.isArray(msg.content)) {
2666
+ const allText = msg.content.every(
2667
+ (c) => (c == null ? void 0 : c.type) === "text"
2668
+ );
2669
+ if (allText && msg.content.length > 1) {
2670
+ const joinedText = msg.content.map((c) => c.text).join("\n");
2671
+ if (msg.role === "system") {
2672
+ processedPrompt[i] = {
2673
+ role: "system",
2674
+ content: joinedText
2675
+ };
2676
+ } else if (msg.role === "assistant") {
2677
+ processedPrompt[i] = {
2678
+ role: "assistant",
2679
+ content: [
2680
+ {
2681
+ type: "text",
2682
+ text: joinedText
1978
2683
  }
1979
- currentToolCall = null;
1980
- } else {
1981
- break;
1982
- }
1983
- } else {
1984
- let earliestStartTagIndex = -1;
1985
- let earliestToolName = "";
1986
- if (toolNames.length > 0) {
1987
- for (const name of toolNames) {
1988
- const startTag = `<${name}>`;
1989
- const index = buffer.indexOf(startTag);
1990
- if (index !== -1 && (earliestStartTagIndex === -1 || index < earliestStartTagIndex)) {
1991
- earliestStartTagIndex = index;
1992
- earliestToolName = name;
1993
- }
2684
+ ]
2685
+ };
2686
+ } else {
2687
+ processedPrompt[i] = {
2688
+ role: "user",
2689
+ content: [
2690
+ {
2691
+ type: "text",
2692
+ text: joinedText
1994
2693
  }
1995
- }
1996
- if (earliestStartTagIndex !== -1) {
1997
- const textBeforeTag = buffer.substring(0, earliestStartTagIndex);
1998
- flushText(controller, textBeforeTag);
1999
- const startTag = `<${earliestToolName}>`;
2000
- buffer = buffer.substring(
2001
- earliestStartTagIndex + startTag.length
2002
- );
2003
- currentToolCall = { name: earliestToolName, content: "" };
2004
- } else {
2005
- break;
2006
- }
2007
- }
2008
- }
2009
- },
2010
- flush(controller) {
2011
- if (currentToolCall) {
2012
- const unfinishedCall = `<${currentToolCall.name}>${buffer}`;
2013
- flushText(controller, unfinishedCall);
2014
- } else if (buffer) {
2015
- flushText(controller);
2016
- }
2017
- if (currentTextId) {
2018
- controller.enqueue({ type: "text-end", id: currentTextId });
2694
+ ]
2695
+ };
2019
2696
  }
2020
2697
  }
2021
- });
2698
+ }
2022
2699
  }
2023
- });
2700
+ for (let i = processedPrompt.length - 1; i > 0; i--) {
2701
+ const current = processedPrompt[i];
2702
+ const prev = processedPrompt[i - 1];
2703
+ if (current.role === "user" && prev.role === "user") {
2704
+ const prevContent = prev.content.map((c) => c.type === "text" ? c.text : "").join("\n");
2705
+ const currentContent = current.content.map((c) => c.type === "text" ? c.text : "").join("\n");
2706
+ processedPrompt[i - 1] = {
2707
+ role: "user",
2708
+ content: [{ type: "text", text: prevContent + "\n" + currentContent }]
2709
+ };
2710
+ processedPrompt.splice(i, 1);
2711
+ }
2712
+ }
2713
+ return processedPrompt;
2714
+ }
2024
2715
 
2025
- // src/protocols/dummy-protocol.ts
2026
- var import_provider_utils5 = require("@ai-sdk/provider-utils");
2716
+ // src/tool-call-middleware.ts
2717
+ function createToolMiddleware({
2718
+ protocol,
2719
+ toolSystemPromptTemplate
2720
+ }) {
2721
+ const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
2722
+ return {
2723
+ middlewareVersion: "v2",
2724
+ wrapStream: async ({ doStream, doGenerate, params }) => {
2725
+ if (isToolChoiceActive(params)) {
2726
+ return toolChoiceStream({
2727
+ doGenerate,
2728
+ options: extractOnErrorOption(params.providerOptions)
2729
+ });
2730
+ } else {
2731
+ return wrapStream({
2732
+ protocol: resolvedProtocol,
2733
+ doStream,
2734
+ doGenerate,
2735
+ params
2736
+ });
2737
+ }
2738
+ },
2739
+ wrapGenerate: async ({ doGenerate, params }) => wrapGenerate({
2740
+ protocol: resolvedProtocol,
2741
+ doGenerate,
2742
+ params
2743
+ }),
2744
+ transformParams: async ({
2745
+ params
2746
+ }) => {
2747
+ return transformParams({
2748
+ protocol: resolvedProtocol,
2749
+ toolSystemPromptTemplate,
2750
+ params
2751
+ });
2752
+ }
2753
+ };
2754
+ }
2027
2755
 
2028
2756
  // src/index.ts
2029
2757
  var gemmaToolMiddleware = createToolMiddleware({
@@ -2031,8 +2759,9 @@ var gemmaToolMiddleware = createToolMiddleware({
2031
2759
  // Customize the tool call delimiters to use markdown code fences
2032
2760
  {
2033
2761
  toolCallStart: "```tool_call\n",
2034
- toolCallEnd: "\n``",
2035
- // two backticks are more common in gemma output @
2762
+ // TODO: Support specifying multiple possible tags,
2763
+ // e.g., for gemma, it would be nice to be able to set both `` and ``` at the same time.
2764
+ toolCallEnd: "\n```",
2036
2765
  toolResponseStart: "```tool_response\n",
2037
2766
  toolResponseEnd: "\n```"
2038
2767
  }
@@ -2063,7 +2792,7 @@ For each function call return a json object with function name and arguments wit
2063
2792
  }
2064
2793
  });
2065
2794
  var xmlToolMiddleware = createToolMiddleware({
2066
- protocol: xmlProtocol,
2795
+ protocol: morphXmlProtocol,
2067
2796
  toolSystemPromptTemplate(tools) {
2068
2797
  return `You are a function calling AI model.
2069
2798
  You are provided with function signatures within <tools></tools> XML tags.
@@ -2082,15 +2811,11 @@ San Fransisco
2082
2811
  });
2083
2812
  // Annotate the CommonJS export names for ESM import in node:
2084
2813
  0 && (module.exports = {
2085
- coerceBySchema,
2086
2814
  createToolMiddleware,
2087
- fixToolCallWithSchema,
2088
2815
  gemmaToolMiddleware,
2089
- getSchemaType,
2090
2816
  hermesToolMiddleware,
2091
2817
  jsonMixProtocol,
2092
- unwrapJsonSchema,
2093
- xmlProtocol,
2818
+ morphXmlProtocol,
2094
2819
  xmlToolMiddleware
2095
2820
  });
2096
2821
  //# sourceMappingURL=index.cjs.map