@ai-sdk-tool/parser 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,9 +4,12 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
- // src/stream-handler.ts
7
+ // src/protocols/dummy-protocol.ts
8
8
  import { generateId } from "@ai-sdk/provider-utils";
9
9
 
10
+ // src/protocols/json-mix-protocol.ts
11
+ import { generateId as generateId2 } from "@ai-sdk/provider-utils";
12
+
10
13
  // src/utils/dynamic-tool-schema.ts
11
14
  function createDynamicIfThenElseSchema(tools) {
12
15
  let currentSchema = {};
@@ -81,6 +84,11 @@ function getPotentialStartIndex(text, searchedText) {
81
84
  return null;
82
85
  }
83
86
 
87
+ // src/utils/regex.ts
88
+ function escapeRegExp(literal) {
89
+ return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
90
+ }
91
+
84
92
  // src/utils/relaxed-json.ts
85
93
  var relaxed_json_exports = {};
86
94
  __export(relaxed_json_exports, {
@@ -714,62 +722,6 @@ function stringify(obj) {
714
722
  return "null";
715
723
  }
716
724
 
717
- // src/utils/regex.ts
718
- function escapeRegExp(literal) {
719
- return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
720
- }
721
-
722
- // src/utils/type-guards.ts
723
- function isToolCallContent(content) {
724
- return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
725
- (typeof content.input === "string" || typeof content.input === "object");
726
- }
727
- function isToolResultPart(content) {
728
- const c = content;
729
- return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
730
- }
731
- function hasInputProperty(obj) {
732
- return typeof obj === "object" && obj !== null && "input" in obj;
733
- }
734
-
735
- // src/utils/tools.ts
736
- function isToolChoiceActive(params) {
737
- var _a, _b, _c;
738
- const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
739
- 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"));
740
- }
741
- function getFunctionTools(params) {
742
- var _a, _b;
743
- const functionTools = ((_a = params.tools) != null ? _a : []).filter(
744
- (t) => t.type === "function"
745
- );
746
- if (functionTools.length > 0) return functionTools;
747
- const rawToolNames = params.providerOptions && typeof params.providerOptions === "object" && ((_b = params.providerOptions.toolCallMiddleware) == null ? void 0 : _b.toolNames) || [];
748
- const toStringArray = (val) => Array.isArray(val) ? val.filter(
749
- (item) => typeof item === "string"
750
- ) : [];
751
- const toolNames = toStringArray(rawToolNames);
752
- if (toolNames.length > 0) {
753
- return toolNames.map((name) => ({
754
- type: "function",
755
- name,
756
- description: "",
757
- inputSchema: { type: "object" }
758
- }));
759
- }
760
- return [];
761
- }
762
-
763
- // src/utils/on-error.ts
764
- function extractOnErrorOption(providerOptions) {
765
- var _a;
766
- if (providerOptions && typeof providerOptions === "object") {
767
- const onError = (_a = providerOptions.toolCallMiddleware) == null ? void 0 : _a.onError;
768
- return onError ? { onError } : void 0;
769
- }
770
- return void 0;
771
- }
772
-
773
725
  // src/utils/coercion.ts
774
726
  function unwrapJsonSchema(schema) {
775
727
  if (!schema || typeof schema !== "object") return schema;
@@ -974,506 +926,218 @@ function coerceToolCallInput(part, tools) {
974
926
  return fixToolCallWithSchema(part, tools);
975
927
  }
976
928
 
977
- // src/utils/protocol.ts
978
- function isProtocolFactory(protocol) {
979
- return typeof protocol === "function";
929
+ // src/utils/debug.ts
930
+ function normalizeBooleanString(value) {
931
+ const normalized = value.trim().toLowerCase();
932
+ if (normalized === "1" || normalized === "true" || normalized === "yes") {
933
+ return true;
934
+ }
935
+ if (normalized === "0" || normalized === "false" || normalized === "no") {
936
+ return false;
937
+ }
938
+ return void 0;
980
939
  }
981
-
982
- // src/stream-handler.ts
983
- async function wrapStream({
984
- protocol,
985
- doStream,
986
- doGenerate,
987
- params
988
- }) {
989
- var _a;
990
- if (isToolChoiceActive(params)) {
991
- return toolChoiceStream({
992
- doGenerate,
993
- options: extractOnErrorOption(params.providerOptions)
994
- });
940
+ function getDebugLevel() {
941
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW || "off";
942
+ const envLower = String(envVal).toLowerCase();
943
+ if (envLower === "stream" || envLower === "parse" || envLower === "off") {
944
+ return envLower;
995
945
  }
996
- const { stream, ...rest } = await doStream();
997
- return {
998
- stream: stream.pipeThrough(
999
- protocol.createStreamParser({
1000
- tools: getFunctionTools(params),
1001
- options: {
1002
- ...extractOnErrorOption(params.providerOptions),
1003
- ...(_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware
1004
- }
1005
- })
1006
- ),
1007
- ...rest
1008
- };
946
+ const boolEnv = normalizeBooleanString(envLower);
947
+ if (boolEnv === true) return "stream";
948
+ if (envLower === "2") return "parse";
949
+ return "off";
1009
950
  }
1010
- async function toolChoiceStream({
1011
- doGenerate,
1012
- options
1013
- }) {
1014
- var _a, _b;
1015
- const result = await doGenerate();
1016
- let toolJson = {};
1017
- if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
1018
- try {
1019
- toolJson = JSON.parse(result.content[0].text);
1020
- } catch (error) {
1021
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1022
- options,
1023
- "Failed to parse toolChoice JSON from streamed model output",
1024
- {
1025
- text: result.content[0].text,
1026
- error: error instanceof Error ? error.message : String(error)
1027
- }
1028
- );
1029
- toolJson = {};
1030
- }
951
+ function color(code) {
952
+ return (text) => `\x1B[${code}m${text}\x1B[0m`;
953
+ }
954
+ var cGray = color(90);
955
+ var cYellow = color(33);
956
+ var cCyan = color(36);
957
+ var cBgBlue = color(44);
958
+ var cBgGreen = color(42);
959
+ var cInverse = color(7);
960
+ var cUnderline = color(4);
961
+ var cBold = color(1);
962
+ function safeStringify(value) {
963
+ try {
964
+ return `
965
+ ${typeof value === "string" ? value : JSON.stringify(value, null, 2)}`;
966
+ } catch (e) {
967
+ return String(value);
1031
968
  }
1032
- const toolCallChunk = {
1033
- type: "tool-call",
1034
- toolCallId: generateId(),
1035
- toolName: toolJson.name || "unknown",
1036
- input: JSON.stringify(toolJson.arguments || {})
1037
- };
1038
- const finishChunk = {
1039
- type: "finish",
1040
- usage: (result == null ? void 0 : result.usage) || // TODO: If possible, try to return a certain amount of LLM usage.
1041
- {
1042
- inputTokens: 0,
1043
- outputTokens: 0,
1044
- totalTokens: 0
1045
- },
1046
- finishReason: "tool-calls"
1047
- };
1048
- const stream = new ReadableStream({
1049
- start(controller) {
1050
- controller.enqueue(toolCallChunk);
1051
- controller.enqueue(finishChunk);
1052
- controller.close();
1053
- }
1054
- });
1055
- return {
1056
- request: (result == null ? void 0 : result.request) || {},
1057
- response: (result == null ? void 0 : result.response) || {},
1058
- stream
1059
- };
1060
969
  }
1061
-
1062
- // src/generate-handler.ts
1063
- import { generateId as generateId2 } from "@ai-sdk/provider-utils";
1064
- async function wrapGenerate({
1065
- protocol,
1066
- doGenerate,
1067
- params
970
+ function logRawChunk(part) {
971
+ console.log(cGray("[debug:mw:raw]"), cYellow(safeStringify(part)));
972
+ }
973
+ function logParsedChunk(part) {
974
+ console.log(cGray("[debug:mw:out]"), cCyan(safeStringify(part)));
975
+ }
976
+ function logParsedSummary({
977
+ toolCalls,
978
+ originalText
1068
979
  }) {
1069
- var _a, _b;
1070
- if (isToolChoiceActive(params)) {
1071
- const result2 = await doGenerate();
1072
- let parsed2 = {};
1073
- const first = (_a = result2.content) == null ? void 0 : _a[0];
1074
- if (first && first.type === "text") {
1075
- try {
1076
- parsed2 = JSON.parse(first.text);
1077
- } catch (error) {
1078
- const options = extractOnErrorOption(params.providerOptions);
1079
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1080
- options,
1081
- "Failed to parse toolChoice JSON from generated model output",
1082
- {
1083
- text: first.text,
1084
- error: error instanceof Error ? error.message : String(error)
1085
- }
1086
- );
1087
- parsed2 = {};
1088
- }
1089
- }
1090
- const toolCall = {
1091
- type: "tool-call",
1092
- toolCallId: generateId2(),
1093
- toolName: parsed2.name || "unknown",
1094
- input: JSON.stringify(parsed2.arguments || {})
1095
- };
1096
- return {
1097
- ...result2,
1098
- content: [toolCall]
1099
- };
980
+ if (originalText) {
981
+ const style = (() => {
982
+ const envVal = typeof process !== "undefined" && process.env && process.env.DEBUG_PARSER_MW_STYLE || "bg";
983
+ const normalized = String(envVal).trim().toLowerCase();
984
+ if (normalized === "inverse" || normalized === "invert")
985
+ return "inverse";
986
+ if (normalized === "underline" || normalized === "ul")
987
+ return "underline";
988
+ if (normalized === "bold") return "bold";
989
+ if (normalized === "bg" || normalized === "background")
990
+ return "bg";
991
+ const asBool = normalizeBooleanString(normalized);
992
+ if (asBool === true) return "bg";
993
+ return "bg";
994
+ })();
995
+ const highlight = style === "inverse" ? cInverse : style === "underline" ? cUnderline : style === "bold" ? cBold : style === "bg" ? cBgGreen : cYellow;
996
+ 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);
997
+ console.log(cGray("[debug:mw:origin]"), `
998
+ ${rendered}`);
1100
999
  }
1101
- const result = await doGenerate();
1102
- if (result.content.length === 0) {
1103
- return result;
1000
+ if (toolCalls.length > 0) {
1001
+ const styledSummary = safeStringify(toolCalls).split(/\r?\n/).map((line) => line.length ? cBgBlue(line) : line).join("\n");
1002
+ console.log(cGray("[debug:mw:summary]"), styledSummary);
1104
1003
  }
1105
- const parsed = result.content.flatMap((contentItem) => {
1106
- var _a2;
1107
- if (contentItem.type !== "text") {
1108
- return [contentItem];
1109
- }
1110
- return protocol.parseGeneratedText({
1111
- text: contentItem.text,
1112
- tools: getFunctionTools(params),
1113
- options: {
1114
- ...extractOnErrorOption(params.providerOptions),
1115
- ...(_a2 = params.providerOptions) == null ? void 0 : _a2.toolCallMiddleware
1116
- }
1117
- });
1118
- });
1119
- const tools = getFunctionTools(params);
1120
- const newContent = parsed.map(
1121
- (part) => coerceToolCallInput(part, tools)
1122
- );
1123
- return {
1124
- ...result,
1125
- content: newContent
1126
- };
1127
1004
  }
1128
1005
 
1129
- // src/transform-handler.ts
1130
- async function transformParams({
1131
- params,
1132
- protocol,
1133
- toolSystemPromptTemplate
1134
- }) {
1135
- var _a, _b, _c, _d, _e, _f, _g, _h;
1136
- const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
1006
+ // src/utils/on-error.ts
1007
+ function extractOnErrorOption(providerOptions) {
1008
+ var _a;
1009
+ if (providerOptions && typeof providerOptions === "object") {
1010
+ const onError = (_a = providerOptions.toolCallMiddleware) == null ? void 0 : _a.onError;
1011
+ return onError ? { onError } : void 0;
1012
+ }
1013
+ return void 0;
1014
+ }
1015
+
1016
+ // src/utils/protocol.ts
1017
+ function isProtocolFactory(protocol) {
1018
+ return typeof protocol === "function";
1019
+ }
1020
+
1021
+ // src/utils/tools.ts
1022
+ function isToolChoiceActive(params) {
1023
+ var _a, _b, _c;
1024
+ const toolChoice = (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.toolChoice;
1025
+ 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"));
1026
+ }
1027
+ function getFunctionTools(params) {
1028
+ var _a, _b;
1137
1029
  const functionTools = ((_a = params.tools) != null ? _a : []).filter(
1138
1030
  (t) => t.type === "function"
1139
1031
  );
1140
- const systemPrompt = resolvedProtocol.formatTools({
1141
- tools: functionTools,
1142
- toolSystemPromptTemplate
1143
- });
1144
- const processedPrompt = convertToolPrompt(
1145
- (_b = params.prompt) != null ? _b : [],
1146
- resolvedProtocol,
1147
- extractOnErrorOption(params.providerOptions)
1148
- );
1149
- const finalPrompt = ((_c = processedPrompt[0]) == null ? void 0 : _c.role) === "system" ? [
1150
- {
1151
- role: "system",
1152
- content: systemPrompt + "\n\n" + processedPrompt[0].content
1153
- },
1154
- ...processedPrompt.slice(1)
1155
- ] : [
1156
- {
1157
- role: "system",
1158
- content: systemPrompt
1159
- },
1160
- ...processedPrompt
1161
- ];
1162
- const baseReturnParams = {
1163
- ...params,
1164
- prompt: finalPrompt,
1165
- tools: [],
1166
- toolChoice: void 0,
1167
- providerOptions: {
1168
- ...params.providerOptions || {},
1169
- toolCallMiddleware: {
1170
- ...params.providerOptions && typeof params.providerOptions === "object" && params.providerOptions.toolCallMiddleware || {},
1171
- toolNames: functionTools.map((t) => t.name)
1172
- }
1173
- }
1174
- };
1175
- if (((_d = params.toolChoice) == null ? void 0 : _d.type) === "none") {
1176
- throw new Error(
1177
- "The 'none' toolChoice type is not supported by this middleware. Please use 'auto', 'required', or specify a tool name."
1178
- );
1032
+ if (functionTools.length > 0) return functionTools;
1033
+ const rawToolNames = params.providerOptions && typeof params.providerOptions === "object" && ((_b = params.providerOptions.toolCallMiddleware) == null ? void 0 : _b.toolNames) || [];
1034
+ const toStringArray = (val) => Array.isArray(val) ? val.filter(
1035
+ (item) => typeof item === "string"
1036
+ ) : [];
1037
+ const toolNames = toStringArray(rawToolNames);
1038
+ if (toolNames.length > 0) {
1039
+ return toolNames.map((name) => ({
1040
+ type: "function",
1041
+ name,
1042
+ description: "",
1043
+ inputSchema: { type: "object" }
1044
+ }));
1179
1045
  }
1180
- if (((_e = params.toolChoice) == null ? void 0 : _e.type) === "tool") {
1181
- const selectedToolName = params.toolChoice.toolName;
1182
- const providerDefinedMatch = ((_f = params.tools) != null ? _f : []).find((t) => {
1183
- if (t.type === "function") return false;
1184
- const anyTool = t;
1185
- return anyTool.id === selectedToolName || anyTool.name === selectedToolName;
1186
- });
1187
- if (providerDefinedMatch) {
1188
- throw new Error(
1189
- "Provider-defined tools are not supported by this middleware. Please use custom tools."
1190
- );
1046
+ return [];
1047
+ }
1048
+
1049
+ // src/utils/type-guards.ts
1050
+ function isToolCallContent(content) {
1051
+ return content.type === "tool-call" && typeof content.toolName === "string" && // input may be a JSON string or an already-parsed object depending on provider/runtime
1052
+ (typeof content.input === "string" || typeof content.input === "object");
1053
+ }
1054
+ function isToolResultPart(content) {
1055
+ const c = content;
1056
+ return !!c && c.type === "tool-result" && typeof c.toolName === "string" && typeof c.toolCallId === "string" && "output" in c;
1057
+ }
1058
+ function hasInputProperty(obj) {
1059
+ return typeof obj === "object" && obj !== null && "input" in obj;
1060
+ }
1061
+
1062
+ // src/protocols/json-mix-protocol.ts
1063
+ var jsonMixProtocol = ({
1064
+ toolCallStart = "<tool_call>",
1065
+ toolCallEnd = "</tool_call>",
1066
+ toolResponseStart = "<tool_response>",
1067
+ toolResponseEnd = "</tool_response>"
1068
+ } = {}) => ({
1069
+ formatTools({ tools, toolSystemPromptTemplate }) {
1070
+ const toolsForPrompt = (tools || []).filter((tool) => tool.type === "function").map((tool) => ({
1071
+ name: tool.name,
1072
+ description: tool.type === "function" && typeof tool.description === "string" ? tool.description : void 0,
1073
+ parameters: tool.inputSchema
1074
+ }));
1075
+ return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1076
+ },
1077
+ formatToolCall(toolCall) {
1078
+ let args = {};
1079
+ try {
1080
+ args = JSON.parse(toolCall.input);
1081
+ } catch (e) {
1082
+ args = toolCall.input;
1191
1083
  }
1192
- const selectedTool = ((_g = params.tools) != null ? _g : []).find(
1193
- (t) => t.type === "function" && t.name === selectedToolName
1084
+ return `${toolCallStart}${JSON.stringify({
1085
+ name: toolCall.toolName,
1086
+ arguments: args
1087
+ })}${toolCallEnd}`;
1088
+ },
1089
+ formatToolResponse(toolResult) {
1090
+ return `${toolResponseStart}${JSON.stringify({
1091
+ toolName: toolResult.toolName,
1092
+ result: toolResult.output
1093
+ })}${toolResponseEnd}`;
1094
+ },
1095
+ parseGeneratedText({ text, options }) {
1096
+ var _a;
1097
+ const startEsc = escapeRegExp(toolCallStart);
1098
+ const endEsc = escapeRegExp(toolCallEnd);
1099
+ const toolCallRegex = new RegExp(
1100
+ `${startEsc}([\0-\uFFFF]*?)${endEsc}`,
1101
+ "gs"
1194
1102
  );
1195
- if (!selectedTool) {
1196
- throw new Error(
1197
- `Tool with name '${selectedToolName}' not found in params.tools.`
1198
- );
1199
- }
1200
- return {
1201
- ...baseReturnParams,
1202
- responseFormat: {
1203
- type: "json",
1204
- schema: {
1205
- type: "object",
1206
- properties: {
1207
- name: {
1208
- const: selectedTool.name
1209
- },
1210
- arguments: selectedTool.inputSchema
1211
- },
1212
- required: ["name", "arguments"]
1213
- },
1214
- name: selectedTool.name,
1215
- description: typeof selectedTool.description === "string" ? selectedTool.description : void 0
1216
- },
1217
- providerOptions: {
1218
- ...baseReturnParams.providerOptions || {},
1219
- toolCallMiddleware: {
1220
- ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
1221
- toolChoice: params.toolChoice
1222
- }
1223
- }
1224
- };
1225
- }
1226
- if (((_h = params.toolChoice) == null ? void 0 : _h.type) === "required") {
1227
- if (!params.tools || params.tools.length === 0) {
1228
- throw new Error(
1229
- "Tool choice type 'required' is set, but no tools are provided in params.tools."
1230
- );
1231
- }
1232
- return {
1233
- ...baseReturnParams,
1234
- responseFormat: {
1235
- type: "json",
1236
- schema: createDynamicIfThenElseSchema(functionTools)
1237
- },
1238
- providerOptions: {
1239
- ...baseReturnParams.providerOptions || {},
1240
- toolCallMiddleware: {
1241
- ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
1242
- toolChoice: { type: "required" }
1103
+ const processedElements = [];
1104
+ let currentIndex = 0;
1105
+ let match;
1106
+ while ((match = toolCallRegex.exec(text)) !== null) {
1107
+ const startIndex = match.index;
1108
+ const toolCallJson = match[1];
1109
+ if (startIndex > currentIndex) {
1110
+ const textSegment = text.substring(currentIndex, startIndex);
1111
+ if (textSegment.trim()) {
1112
+ processedElements.push({ type: "text", text: textSegment });
1243
1113
  }
1244
1114
  }
1245
- };
1246
- }
1247
- return baseReturnParams;
1248
- }
1249
- function convertToolPrompt(prompt, resolvedProtocol, providerOptions) {
1250
- const processedPrompt = prompt.map((message) => {
1251
- var _a;
1252
- if (message.role === "assistant") {
1253
- const newContent = [];
1254
- for (const content of message.content) {
1255
- if (isToolCallContent(content)) {
1256
- newContent.push({
1257
- type: "text",
1258
- text: resolvedProtocol.formatToolCall(content)
1259
- });
1260
- } else if (content.type === "text") {
1261
- newContent.push(content);
1262
- } else if (content.type === "reasoning") {
1263
- newContent.push(content);
1264
- } else {
1265
- const options = extractOnErrorOption(providerOptions);
1266
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
1267
- options,
1268
- "tool-call-middleware: unknown assistant content; stringifying for provider compatibility",
1269
- { content }
1270
- );
1271
- newContent.push({
1272
- type: "text",
1273
- text: JSON.stringify(content)
1115
+ if (toolCallJson) {
1116
+ try {
1117
+ const parsedToolCall = relaxed_json_exports.parse(toolCallJson);
1118
+ processedElements.push({
1119
+ type: "tool-call",
1120
+ toolCallId: generateId2(),
1121
+ toolName: parsedToolCall.name,
1122
+ input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1274
1123
  });
1124
+ } catch (error) {
1125
+ if (options == null ? void 0 : options.onError) {
1126
+ options.onError(
1127
+ "Could not process JSON tool call, keeping original text.",
1128
+ { toolCall: match[0], error }
1129
+ );
1130
+ }
1131
+ processedElements.push({ type: "text", text: match[0] });
1275
1132
  }
1276
1133
  }
1277
- const onlyText = newContent.every((c) => c.type === "text");
1278
- const condensedAssistant = onlyText ? [
1279
- {
1280
- type: "text",
1281
- text: newContent.map((c) => c.text).join("\n")
1282
- }
1283
- ] : newContent;
1284
- return { role: "assistant", content: condensedAssistant };
1134
+ currentIndex = startIndex + match[0].length;
1285
1135
  }
1286
- if (message.role === "tool") {
1287
- return {
1288
- role: "user",
1289
- // Map tool results to text response blocks, then condense into a single text block
1290
- content: [
1291
- {
1292
- type: "text",
1293
- text: message.content.map(
1294
- (toolResult) => isToolResultPart(toolResult) ? resolvedProtocol.formatToolResponse(toolResult) : resolvedProtocol.formatToolResponse(
1295
- toolResult
1296
- )
1297
- ).join("\n")
1298
- }
1299
- ]
1300
- };
1301
- }
1302
- return message;
1303
- });
1304
- for (let i = 0; i < processedPrompt.length; i++) {
1305
- const msg = processedPrompt[i];
1306
- if (Array.isArray(msg.content)) {
1307
- const allText = msg.content.every(
1308
- (c) => (c == null ? void 0 : c.type) === "text"
1309
- );
1310
- if (allText && msg.content.length > 1) {
1311
- const joinedText = msg.content.map((c) => c.text).join("\n");
1312
- if (msg.role === "system") {
1313
- processedPrompt[i] = {
1314
- role: "system",
1315
- content: joinedText
1316
- };
1317
- } else if (msg.role === "assistant") {
1318
- processedPrompt[i] = {
1319
- role: "assistant",
1320
- content: [
1321
- {
1322
- type: "text",
1323
- text: joinedText
1324
- }
1325
- ]
1326
- };
1327
- } else {
1328
- processedPrompt[i] = {
1329
- role: "user",
1330
- content: [
1331
- {
1332
- type: "text",
1333
- text: joinedText
1334
- }
1335
- ]
1336
- };
1337
- }
1338
- }
1339
- }
1340
- }
1341
- for (let i = processedPrompt.length - 1; i > 0; i--) {
1342
- const current = processedPrompt[i];
1343
- const prev = processedPrompt[i - 1];
1344
- if (current.role === "user" && prev.role === "user") {
1345
- const prevContent = prev.content.map((c) => c.type === "text" ? c.text : "").join("\n");
1346
- const currentContent = current.content.map((c) => c.type === "text" ? c.text : "").join("\n");
1347
- processedPrompt[i - 1] = {
1348
- role: "user",
1349
- content: [{ type: "text", text: prevContent + "\n" + currentContent }]
1350
- };
1351
- processedPrompt.splice(i, 1);
1352
- }
1353
- }
1354
- return processedPrompt;
1355
- }
1356
-
1357
- // src/tool-call-middleware.ts
1358
- function createToolMiddleware({
1359
- protocol,
1360
- toolSystemPromptTemplate
1361
- }) {
1362
- const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
1363
- return {
1364
- middlewareVersion: "v2",
1365
- wrapStream: async ({ doStream, doGenerate, params }) => {
1366
- if (isToolChoiceActive(params)) {
1367
- return toolChoiceStream({
1368
- doGenerate,
1369
- options: extractOnErrorOption(params.providerOptions)
1370
- });
1371
- } else {
1372
- return wrapStream({
1373
- protocol: resolvedProtocol,
1374
- doStream,
1375
- doGenerate,
1376
- params
1377
- });
1378
- }
1379
- },
1380
- wrapGenerate: async ({ doGenerate, params }) => wrapGenerate({
1381
- protocol: resolvedProtocol,
1382
- doGenerate,
1383
- params
1384
- }),
1385
- transformParams: async ({
1386
- params
1387
- }) => {
1388
- return transformParams({
1389
- protocol: resolvedProtocol,
1390
- toolSystemPromptTemplate,
1391
- params
1392
- });
1393
- }
1394
- };
1395
- }
1396
-
1397
- // src/protocols/json-mix-protocol.ts
1398
- import { generateId as generateId3 } from "@ai-sdk/provider-utils";
1399
- var jsonMixProtocol = ({
1400
- toolCallStart = "<tool_call>",
1401
- toolCallEnd = "</tool_call>",
1402
- toolResponseStart = "<tool_response>",
1403
- toolResponseEnd = "</tool_response>"
1404
- } = {}) => ({
1405
- formatTools({ tools, toolSystemPromptTemplate }) {
1406
- const toolsForPrompt = (tools || []).filter((tool) => tool.type === "function").map((tool) => ({
1407
- name: tool.name,
1408
- description: tool.type === "function" && typeof tool.description === "string" ? tool.description : void 0,
1409
- parameters: tool.inputSchema
1410
- }));
1411
- return toolSystemPromptTemplate(JSON.stringify(toolsForPrompt));
1412
- },
1413
- formatToolCall(toolCall) {
1414
- let args = {};
1415
- try {
1416
- args = JSON.parse(toolCall.input);
1417
- } catch (e) {
1418
- args = toolCall.input;
1419
- }
1420
- return `${toolCallStart}${JSON.stringify({
1421
- name: toolCall.toolName,
1422
- arguments: args
1423
- })}${toolCallEnd}`;
1424
- },
1425
- formatToolResponse(toolResult) {
1426
- return `${toolResponseStart}${JSON.stringify({
1427
- toolName: toolResult.toolName,
1428
- result: toolResult.output
1429
- })}${toolResponseEnd}`;
1430
- },
1431
- parseGeneratedText({ text, options }) {
1432
- var _a;
1433
- const startEsc = escapeRegExp(toolCallStart);
1434
- const endEsc = escapeRegExp(toolCallEnd);
1435
- const toolCallRegex = new RegExp(
1436
- `${startEsc}([\0-\uFFFF]*?)${endEsc}`,
1437
- "gs"
1438
- );
1439
- const processedElements = [];
1440
- let currentIndex = 0;
1441
- let match;
1442
- while ((match = toolCallRegex.exec(text)) !== null) {
1443
- const startIndex = match.index;
1444
- const toolCallJson = match[1];
1445
- if (startIndex > currentIndex) {
1446
- const textSegment = text.substring(currentIndex, startIndex);
1447
- if (textSegment.trim()) {
1448
- processedElements.push({ type: "text", text: textSegment });
1449
- }
1450
- }
1451
- if (toolCallJson) {
1452
- try {
1453
- const parsedToolCall = relaxed_json_exports.parse(toolCallJson);
1454
- processedElements.push({
1455
- type: "tool-call",
1456
- toolCallId: generateId3(),
1457
- toolName: parsedToolCall.name,
1458
- input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1459
- });
1460
- } catch (error) {
1461
- if (options == null ? void 0 : options.onError) {
1462
- options.onError(
1463
- "Could not process JSON tool call, keeping original text.",
1464
- { toolCall: match[0], error }
1465
- );
1466
- }
1467
- processedElements.push({ type: "text", text: match[0] });
1468
- }
1469
- }
1470
- currentIndex = startIndex + match[0].length;
1471
- }
1472
- if (currentIndex < text.length) {
1473
- const remainingText = text.substring(currentIndex);
1474
- if (remainingText.trim()) {
1475
- processedElements.push({ type: "text", text: remainingText });
1476
- }
1136
+ if (currentIndex < text.length) {
1137
+ const remainingText = text.substring(currentIndex);
1138
+ if (remainingText.trim()) {
1139
+ processedElements.push({ type: "text", text: remainingText });
1140
+ }
1477
1141
  }
1478
1142
  return processedElements;
1479
1143
  },
@@ -1489,7 +1153,7 @@ var jsonMixProtocol = ({
1489
1153
  if (chunk.type === "finish") {
1490
1154
  if (isInsideToolCall && buffer.length > 0) {
1491
1155
  if (!currentTextId) {
1492
- currentTextId = generateId3();
1156
+ currentTextId = generateId2();
1493
1157
  controller.enqueue({ type: "text-start", id: currentTextId });
1494
1158
  hasEmittedTextStart = true;
1495
1159
  }
@@ -1501,7 +1165,7 @@ var jsonMixProtocol = ({
1501
1165
  buffer = "";
1502
1166
  } else if (!isInsideToolCall && buffer.length > 0) {
1503
1167
  if (!currentTextId) {
1504
- currentTextId = generateId3();
1168
+ currentTextId = generateId2();
1505
1169
  controller.enqueue({ type: "text-start", id: currentTextId });
1506
1170
  hasEmittedTextStart = true;
1507
1171
  }
@@ -1518,7 +1182,7 @@ var jsonMixProtocol = ({
1518
1182
  hasEmittedTextStart = false;
1519
1183
  }
1520
1184
  if (currentToolCallJson) {
1521
- const errorId = generateId3();
1185
+ const errorId = generateId2();
1522
1186
  controller.enqueue({ type: "text-start", id: errorId });
1523
1187
  controller.enqueue({
1524
1188
  type: "text-delta",
@@ -1546,7 +1210,7 @@ var jsonMixProtocol = ({
1546
1210
  currentToolCallJson += text;
1547
1211
  } else if (text.length > 0) {
1548
1212
  if (!currentTextId) {
1549
- currentTextId = generateId3();
1213
+ currentTextId = generateId2();
1550
1214
  controller.enqueue({ type: "text-start", id: currentTextId });
1551
1215
  hasEmittedTextStart = true;
1552
1216
  }
@@ -1581,12 +1245,12 @@ var jsonMixProtocol = ({
1581
1245
  }
1582
1246
  controller.enqueue({
1583
1247
  type: "tool-call",
1584
- toolCallId: generateId3(),
1248
+ toolCallId: generateId2(),
1585
1249
  toolName: parsedToolCall.name,
1586
1250
  input: JSON.stringify((_a = parsedToolCall.arguments) != null ? _a : {})
1587
1251
  });
1588
1252
  } catch (e) {
1589
- const errorId = generateId3();
1253
+ const errorId = generateId2();
1590
1254
  controller.enqueue({ type: "text-start", id: errorId });
1591
1255
  controller.enqueue({
1592
1256
  type: "text-delta",
@@ -1619,13 +1283,24 @@ var jsonMixProtocol = ({
1619
1283
  }
1620
1284
  }
1621
1285
  });
1286
+ },
1287
+ extractToolCallSegments({ text }) {
1288
+ const startEsc = escapeRegExp(toolCallStart);
1289
+ const endEsc = escapeRegExp(toolCallEnd);
1290
+ const regex = new RegExp(`${startEsc}([\0-\uFFFF]*?)${endEsc}`, "gs");
1291
+ const segments = [];
1292
+ let m;
1293
+ while ((m = regex.exec(text)) != null) {
1294
+ segments.push(m[0]);
1295
+ }
1296
+ return segments;
1622
1297
  }
1623
1298
  });
1624
1299
 
1625
- // src/protocols/xml-protocol.ts
1626
- import { generateId as generateId4 } from "@ai-sdk/provider-utils";
1627
- import { XMLParser, XMLBuilder } from "fast-xml-parser";
1628
- var xmlProtocol = () => ({
1300
+ // src/protocols/morph-xml-protocol.ts
1301
+ import { generateId as generateId3 } from "@ai-sdk/provider-utils";
1302
+ import { XMLBuilder, XMLParser } from "fast-xml-parser";
1303
+ var morphXmlProtocol = () => ({
1629
1304
  formatTools({ tools, toolSystemPromptTemplate }) {
1630
1305
  const toolsForPrompt = (tools || []).map((tool) => ({
1631
1306
  name: tool.name,
@@ -1776,7 +1451,7 @@ var xmlProtocol = () => ({
1776
1451
  const coercedArgs = coerceBySchema(args, schema);
1777
1452
  processedElements.push({
1778
1453
  type: "tool-call",
1779
- toolCallId: generateId4(),
1454
+ toolCallId: generateId3(),
1780
1455
  toolName,
1781
1456
  input: JSON.stringify(coercedArgs)
1782
1457
  });
@@ -1805,7 +1480,7 @@ var xmlProtocol = () => ({
1805
1480
  const content = text != null ? text : buffer;
1806
1481
  if (content) {
1807
1482
  if (!currentTextId) {
1808
- currentTextId = generateId4();
1483
+ currentTextId = generateId3();
1809
1484
  controller.enqueue({ type: "text-start", id: currentTextId });
1810
1485
  }
1811
1486
  controller.enqueue({
@@ -1930,7 +1605,7 @@ var xmlProtocol = () => ({
1930
1605
  flushText(controller);
1931
1606
  controller.enqueue({
1932
1607
  type: "tool-call",
1933
- toolCallId: generateId4(),
1608
+ toolCallId: generateId3(),
1934
1609
  toolName: currentToolCall.name,
1935
1610
  input: JSON.stringify(coercedArgs)
1936
1611
  });
@@ -1990,11 +1665,578 @@ var xmlProtocol = () => ({
1990
1665
  }
1991
1666
  }
1992
1667
  });
1668
+ },
1669
+ extractToolCallSegments({ text, tools }) {
1670
+ const toolNames = tools.map((t) => t.name).filter(Boolean);
1671
+ if (toolNames.length === 0) return [];
1672
+ const names = toolNames.map((n) => escapeRegExp(String(n))).join("|");
1673
+ if (!names) return [];
1674
+ const regex = new RegExp(`<(${names})>[\\s\\S]*?<\\/\\1>`, "g");
1675
+ const segments = [];
1676
+ let m;
1677
+ while ((m = regex.exec(text)) != null) {
1678
+ segments.push(m[0]);
1679
+ }
1680
+ return segments;
1993
1681
  }
1994
1682
  });
1995
1683
 
1996
- // src/protocols/dummy-protocol.ts
1684
+ // src/generate-handler.ts
1685
+ import { generateId as generateId4 } from "@ai-sdk/provider-utils";
1686
+ async function wrapGenerate({
1687
+ protocol,
1688
+ doGenerate,
1689
+ params
1690
+ }) {
1691
+ var _a, _b;
1692
+ if (isToolChoiceActive(params)) {
1693
+ const result2 = await doGenerate();
1694
+ let parsed2 = {};
1695
+ const first = (_a = result2.content) == null ? void 0 : _a[0];
1696
+ if (first && first.type === "text") {
1697
+ const debugLevel2 = getDebugLevel();
1698
+ if (debugLevel2 === "parse") {
1699
+ logRawChunk(first.text);
1700
+ }
1701
+ try {
1702
+ parsed2 = JSON.parse(first.text);
1703
+ } catch (error) {
1704
+ const options = extractOnErrorOption(params.providerOptions);
1705
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1706
+ options,
1707
+ "Failed to parse toolChoice JSON from generated model output",
1708
+ {
1709
+ text: first.text,
1710
+ error: error instanceof Error ? error.message : String(error)
1711
+ }
1712
+ );
1713
+ parsed2 = {};
1714
+ }
1715
+ }
1716
+ const toolCall = {
1717
+ type: "tool-call",
1718
+ toolCallId: generateId4(),
1719
+ toolName: parsed2.name || "unknown",
1720
+ input: JSON.stringify(parsed2.arguments || {})
1721
+ };
1722
+ const debugLevelToolChoice = getDebugLevel();
1723
+ const originText = first && first.type === "text" ? first.text : "";
1724
+ if (debugLevelToolChoice === "parse") {
1725
+ logParsedSummary({ toolCalls: [toolCall], originalText: originText });
1726
+ }
1727
+ return {
1728
+ ...result2,
1729
+ content: [toolCall]
1730
+ };
1731
+ }
1732
+ const result = await doGenerate();
1733
+ if (result.content.length === 0) {
1734
+ return result;
1735
+ }
1736
+ const parsed = result.content.flatMap((contentItem) => {
1737
+ var _a2;
1738
+ if (contentItem.type !== "text") {
1739
+ return [contentItem];
1740
+ }
1741
+ const debugLevel2 = getDebugLevel();
1742
+ if (debugLevel2 === "stream") {
1743
+ logRawChunk(contentItem.text);
1744
+ }
1745
+ return protocol.parseGeneratedText({
1746
+ text: contentItem.text,
1747
+ tools: getFunctionTools(params),
1748
+ options: {
1749
+ ...extractOnErrorOption(params.providerOptions),
1750
+ ...(_a2 = params.providerOptions) == null ? void 0 : _a2.toolCallMiddleware
1751
+ }
1752
+ });
1753
+ });
1754
+ const tools = getFunctionTools(params);
1755
+ const newContent = parsed.map(
1756
+ (part) => coerceToolCallInput(part, tools)
1757
+ );
1758
+ const debugLevel = getDebugLevel();
1759
+ if (debugLevel === "stream") {
1760
+ newContent.forEach((part) => logParsedChunk(part));
1761
+ }
1762
+ if (debugLevel === "parse") {
1763
+ const allText = result.content.filter(
1764
+ (c) => c.type === "text"
1765
+ ).map((c) => c.text).join("\n\n");
1766
+ const segments = protocol.extractToolCallSegments ? protocol.extractToolCallSegments({ text: allText, tools }) : [];
1767
+ const originalText = segments.join("\n\n");
1768
+ const toolCalls = newContent.filter(
1769
+ (p) => p.type === "tool-call"
1770
+ );
1771
+ logParsedSummary({ toolCalls, originalText });
1772
+ }
1773
+ return {
1774
+ ...result,
1775
+ content: newContent
1776
+ };
1777
+ }
1778
+
1779
+ // src/stream-handler.ts
1997
1780
  import { generateId as generateId5 } from "@ai-sdk/provider-utils";
1781
+ async function wrapStream({
1782
+ protocol,
1783
+ doStream,
1784
+ doGenerate,
1785
+ params
1786
+ }) {
1787
+ var _a;
1788
+ if (isToolChoiceActive(params)) {
1789
+ return toolChoiceStream({
1790
+ doGenerate,
1791
+ options: extractOnErrorOption(params.providerOptions)
1792
+ });
1793
+ }
1794
+ const { stream, ...rest } = await doStream();
1795
+ const debugLevel = getDebugLevel();
1796
+ const tools = getFunctionTools(params);
1797
+ const options = {
1798
+ ...extractOnErrorOption(params.providerOptions),
1799
+ ...(_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware
1800
+ };
1801
+ if (debugLevel === "off") {
1802
+ return {
1803
+ stream: stream.pipeThrough(
1804
+ protocol.createStreamParser({
1805
+ tools,
1806
+ options
1807
+ })
1808
+ ),
1809
+ ...rest
1810
+ };
1811
+ }
1812
+ if (debugLevel === "stream") {
1813
+ const withRawTap2 = stream.pipeThrough(
1814
+ new TransformStream(
1815
+ {
1816
+ transform(part, controller) {
1817
+ logRawChunk(part);
1818
+ controller.enqueue(part);
1819
+ }
1820
+ }
1821
+ )
1822
+ );
1823
+ const parsed2 = withRawTap2.pipeThrough(
1824
+ protocol.createStreamParser({
1825
+ tools,
1826
+ options
1827
+ })
1828
+ );
1829
+ const withParsedTap = parsed2.pipeThrough(
1830
+ new TransformStream(
1831
+ {
1832
+ transform(part, controller) {
1833
+ logParsedChunk(part);
1834
+ controller.enqueue(part);
1835
+ }
1836
+ }
1837
+ )
1838
+ );
1839
+ return {
1840
+ stream: withParsedTap,
1841
+ ...rest
1842
+ };
1843
+ }
1844
+ let fullRawText = "";
1845
+ const withRawTap = stream.pipeThrough(
1846
+ new TransformStream({
1847
+ transform(part, controller) {
1848
+ if (part.type === "text-delta") {
1849
+ const delta = part.delta;
1850
+ if (typeof delta === "string" && delta.length > 0) {
1851
+ fullRawText += delta;
1852
+ }
1853
+ }
1854
+ controller.enqueue(part);
1855
+ }
1856
+ })
1857
+ );
1858
+ const parsed = withRawTap.pipeThrough(
1859
+ protocol.createStreamParser({
1860
+ tools,
1861
+ options
1862
+ })
1863
+ );
1864
+ const withSummary = parsed.pipeThrough(
1865
+ new TransformStream({
1866
+ transform: /* @__PURE__ */ (() => {
1867
+ const parsedToolCalls = [];
1868
+ return (part, controller) => {
1869
+ if (part.type === "tool-call") {
1870
+ parsedToolCalls.push(part);
1871
+ }
1872
+ if (part.type === "finish") {
1873
+ try {
1874
+ const segments = protocol.extractToolCallSegments ? protocol.extractToolCallSegments({
1875
+ text: fullRawText,
1876
+ tools
1877
+ }) : [];
1878
+ const origin = segments.join("\n\n");
1879
+ logParsedSummary({
1880
+ toolCalls: parsedToolCalls,
1881
+ originalText: origin
1882
+ });
1883
+ } catch (e) {
1884
+ }
1885
+ }
1886
+ controller.enqueue(part);
1887
+ };
1888
+ })()
1889
+ })
1890
+ );
1891
+ return {
1892
+ stream: withSummary,
1893
+ ...rest
1894
+ };
1895
+ }
1896
+ async function toolChoiceStream({
1897
+ doGenerate,
1898
+ options
1899
+ }) {
1900
+ var _a, _b;
1901
+ const result = await doGenerate();
1902
+ let toolJson = {};
1903
+ if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
1904
+ try {
1905
+ toolJson = JSON.parse(result.content[0].text);
1906
+ } catch (error) {
1907
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
1908
+ options,
1909
+ "Failed to parse toolChoice JSON from streamed model output",
1910
+ {
1911
+ text: result.content[0].text,
1912
+ error: error instanceof Error ? error.message : String(error)
1913
+ }
1914
+ );
1915
+ toolJson = {};
1916
+ }
1917
+ }
1918
+ const toolCallChunk = {
1919
+ type: "tool-call",
1920
+ toolCallId: generateId5(),
1921
+ toolName: toolJson.name || "unknown",
1922
+ input: JSON.stringify(toolJson.arguments || {})
1923
+ };
1924
+ const finishChunk = {
1925
+ type: "finish",
1926
+ usage: (result == null ? void 0 : result.usage) || // TODO: If possible, try to return a certain amount of LLM usage.
1927
+ {
1928
+ inputTokens: 0,
1929
+ outputTokens: 0,
1930
+ totalTokens: 0
1931
+ },
1932
+ finishReason: "tool-calls"
1933
+ };
1934
+ const stream = new ReadableStream({
1935
+ start(controller) {
1936
+ controller.enqueue(toolCallChunk);
1937
+ controller.enqueue(finishChunk);
1938
+ controller.close();
1939
+ }
1940
+ });
1941
+ const debugLevel = getDebugLevel();
1942
+ const firstText = (result == null ? void 0 : result.content) && result.content[0] && result.content[0].type === "text" && result.content[0].text || "";
1943
+ const streamWithSummary = debugLevel === "parse" ? stream.pipeThrough(
1944
+ new TransformStream({
1945
+ transform(part, controller) {
1946
+ if (part.type === "finish") {
1947
+ try {
1948
+ logParsedSummary({
1949
+ toolCalls: [toolCallChunk],
1950
+ originalText: typeof firstText === "string" ? firstText : ""
1951
+ });
1952
+ } catch (e) {
1953
+ }
1954
+ }
1955
+ controller.enqueue(part);
1956
+ }
1957
+ })
1958
+ ) : stream;
1959
+ return {
1960
+ request: (result == null ? void 0 : result.request) || {},
1961
+ response: (result == null ? void 0 : result.response) || {},
1962
+ stream: streamWithSummary
1963
+ };
1964
+ }
1965
+
1966
+ // src/transform-handler.ts
1967
+ async function transformParams({
1968
+ params,
1969
+ protocol,
1970
+ toolSystemPromptTemplate
1971
+ }) {
1972
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1973
+ const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
1974
+ const functionTools = ((_a = params.tools) != null ? _a : []).filter(
1975
+ (t) => t.type === "function"
1976
+ );
1977
+ const systemPrompt = resolvedProtocol.formatTools({
1978
+ tools: functionTools,
1979
+ toolSystemPromptTemplate
1980
+ });
1981
+ const processedPrompt = convertToolPrompt(
1982
+ (_b = params.prompt) != null ? _b : [],
1983
+ resolvedProtocol,
1984
+ extractOnErrorOption(params.providerOptions)
1985
+ );
1986
+ const finalPrompt = ((_c = processedPrompt[0]) == null ? void 0 : _c.role) === "system" ? [
1987
+ {
1988
+ role: "system",
1989
+ content: systemPrompt + "\n\n" + processedPrompt[0].content
1990
+ },
1991
+ ...processedPrompt.slice(1)
1992
+ ] : [
1993
+ {
1994
+ role: "system",
1995
+ content: systemPrompt
1996
+ },
1997
+ ...processedPrompt
1998
+ ];
1999
+ const baseReturnParams = {
2000
+ ...params,
2001
+ prompt: finalPrompt,
2002
+ tools: [],
2003
+ toolChoice: void 0,
2004
+ providerOptions: {
2005
+ ...params.providerOptions || {},
2006
+ toolCallMiddleware: {
2007
+ ...params.providerOptions && typeof params.providerOptions === "object" && params.providerOptions.toolCallMiddleware || {},
2008
+ // INTERNAL: used by the middleware to propagate the names of custom
2009
+ // function tools into downstream handlers (stream/generate) when
2010
+ // providers strip or ignore `params.tools`. Not a stable public API.
2011
+ toolNames: functionTools.map((t) => t.name)
2012
+ }
2013
+ }
2014
+ };
2015
+ if (((_d = params.toolChoice) == null ? void 0 : _d.type) === "none") {
2016
+ throw new Error(
2017
+ "The 'none' toolChoice type is not supported by this middleware. Please use 'auto', 'required', or specify a tool name."
2018
+ );
2019
+ }
2020
+ if (((_e = params.toolChoice) == null ? void 0 : _e.type) === "tool") {
2021
+ const selectedToolName = params.toolChoice.toolName;
2022
+ const providerDefinedMatch = ((_f = params.tools) != null ? _f : []).find((t) => {
2023
+ if (t.type === "function") return false;
2024
+ const anyTool = t;
2025
+ return anyTool.id === selectedToolName || anyTool.name === selectedToolName;
2026
+ });
2027
+ if (providerDefinedMatch) {
2028
+ throw new Error(
2029
+ "Provider-defined tools are not supported by this middleware. Please use custom tools."
2030
+ );
2031
+ }
2032
+ const selectedTool = ((_g = params.tools) != null ? _g : []).find(
2033
+ (t) => t.type === "function" && t.name === selectedToolName
2034
+ );
2035
+ if (!selectedTool) {
2036
+ throw new Error(
2037
+ `Tool with name '${selectedToolName}' not found in params.tools.`
2038
+ );
2039
+ }
2040
+ return {
2041
+ ...baseReturnParams,
2042
+ responseFormat: {
2043
+ type: "json",
2044
+ schema: {
2045
+ type: "object",
2046
+ properties: {
2047
+ name: {
2048
+ const: selectedTool.name
2049
+ },
2050
+ arguments: selectedTool.inputSchema
2051
+ },
2052
+ required: ["name", "arguments"]
2053
+ },
2054
+ name: selectedTool.name,
2055
+ description: typeof selectedTool.description === "string" ? selectedTool.description : void 0
2056
+ },
2057
+ providerOptions: {
2058
+ ...baseReturnParams.providerOptions || {},
2059
+ toolCallMiddleware: {
2060
+ ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
2061
+ // INTERNAL: used by the middleware to activate the tool-choice
2062
+ // fast-path in handlers. Not a stable public API.
2063
+ toolChoice: params.toolChoice
2064
+ }
2065
+ }
2066
+ };
2067
+ }
2068
+ if (((_h = params.toolChoice) == null ? void 0 : _h.type) === "required") {
2069
+ if (!params.tools || params.tools.length === 0) {
2070
+ throw new Error(
2071
+ "Tool choice type 'required' is set, but no tools are provided in params.tools."
2072
+ );
2073
+ }
2074
+ return {
2075
+ ...baseReturnParams,
2076
+ responseFormat: {
2077
+ type: "json",
2078
+ schema: createDynamicIfThenElseSchema(functionTools)
2079
+ },
2080
+ providerOptions: {
2081
+ ...baseReturnParams.providerOptions || {},
2082
+ toolCallMiddleware: {
2083
+ ...baseReturnParams.providerOptions && typeof baseReturnParams.providerOptions === "object" && baseReturnParams.providerOptions.toolCallMiddleware || {},
2084
+ // INTERNAL: used by the middleware to activate the tool-choice
2085
+ // fast-path in handlers. Not a stable public API.
2086
+ toolChoice: { type: "required" }
2087
+ }
2088
+ }
2089
+ };
2090
+ }
2091
+ return baseReturnParams;
2092
+ }
2093
+ function convertToolPrompt(prompt, resolvedProtocol, providerOptions) {
2094
+ const processedPrompt = prompt.map((message) => {
2095
+ var _a;
2096
+ if (message.role === "assistant") {
2097
+ const newContent = [];
2098
+ for (const content of message.content) {
2099
+ if (isToolCallContent(content)) {
2100
+ newContent.push({
2101
+ type: "text",
2102
+ text: resolvedProtocol.formatToolCall(content)
2103
+ });
2104
+ } else if (content.type === "text") {
2105
+ newContent.push(content);
2106
+ } else if (content.type === "reasoning") {
2107
+ newContent.push(content);
2108
+ } else {
2109
+ const options = extractOnErrorOption(providerOptions);
2110
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
2111
+ options,
2112
+ "tool-call-middleware: unknown assistant content; stringifying for provider compatibility",
2113
+ { content }
2114
+ );
2115
+ newContent.push({
2116
+ type: "text",
2117
+ text: JSON.stringify(content)
2118
+ });
2119
+ }
2120
+ }
2121
+ const onlyText = newContent.every((c) => c.type === "text");
2122
+ const condensedAssistant = onlyText ? [
2123
+ {
2124
+ type: "text",
2125
+ text: newContent.map((c) => c.text).join("\n")
2126
+ }
2127
+ ] : newContent;
2128
+ return { role: "assistant", content: condensedAssistant };
2129
+ }
2130
+ if (message.role === "tool") {
2131
+ return {
2132
+ role: "user",
2133
+ // Map tool results to text response blocks, then condense into a single text block
2134
+ content: [
2135
+ {
2136
+ type: "text",
2137
+ text: message.content.map(
2138
+ (toolResult) => isToolResultPart(toolResult) ? resolvedProtocol.formatToolResponse(toolResult) : resolvedProtocol.formatToolResponse(
2139
+ toolResult
2140
+ )
2141
+ ).join("\n")
2142
+ }
2143
+ ]
2144
+ };
2145
+ }
2146
+ return message;
2147
+ });
2148
+ for (let i = 0; i < processedPrompt.length; i++) {
2149
+ const msg = processedPrompt[i];
2150
+ if (Array.isArray(msg.content)) {
2151
+ const allText = msg.content.every(
2152
+ (c) => (c == null ? void 0 : c.type) === "text"
2153
+ );
2154
+ if (allText && msg.content.length > 1) {
2155
+ const joinedText = msg.content.map((c) => c.text).join("\n");
2156
+ if (msg.role === "system") {
2157
+ processedPrompt[i] = {
2158
+ role: "system",
2159
+ content: joinedText
2160
+ };
2161
+ } else if (msg.role === "assistant") {
2162
+ processedPrompt[i] = {
2163
+ role: "assistant",
2164
+ content: [
2165
+ {
2166
+ type: "text",
2167
+ text: joinedText
2168
+ }
2169
+ ]
2170
+ };
2171
+ } else {
2172
+ processedPrompt[i] = {
2173
+ role: "user",
2174
+ content: [
2175
+ {
2176
+ type: "text",
2177
+ text: joinedText
2178
+ }
2179
+ ]
2180
+ };
2181
+ }
2182
+ }
2183
+ }
2184
+ }
2185
+ for (let i = processedPrompt.length - 1; i > 0; i--) {
2186
+ const current = processedPrompt[i];
2187
+ const prev = processedPrompt[i - 1];
2188
+ if (current.role === "user" && prev.role === "user") {
2189
+ const prevContent = prev.content.map((c) => c.type === "text" ? c.text : "").join("\n");
2190
+ const currentContent = current.content.map((c) => c.type === "text" ? c.text : "").join("\n");
2191
+ processedPrompt[i - 1] = {
2192
+ role: "user",
2193
+ content: [{ type: "text", text: prevContent + "\n" + currentContent }]
2194
+ };
2195
+ processedPrompt.splice(i, 1);
2196
+ }
2197
+ }
2198
+ return processedPrompt;
2199
+ }
2200
+
2201
+ // src/tool-call-middleware.ts
2202
+ function createToolMiddleware({
2203
+ protocol,
2204
+ toolSystemPromptTemplate
2205
+ }) {
2206
+ const resolvedProtocol = isProtocolFactory(protocol) ? protocol() : protocol;
2207
+ return {
2208
+ middlewareVersion: "v2",
2209
+ wrapStream: async ({ doStream, doGenerate, params }) => {
2210
+ if (isToolChoiceActive(params)) {
2211
+ return toolChoiceStream({
2212
+ doGenerate,
2213
+ options: extractOnErrorOption(params.providerOptions)
2214
+ });
2215
+ } else {
2216
+ return wrapStream({
2217
+ protocol: resolvedProtocol,
2218
+ doStream,
2219
+ doGenerate,
2220
+ params
2221
+ });
2222
+ }
2223
+ },
2224
+ wrapGenerate: async ({ doGenerate, params }) => wrapGenerate({
2225
+ protocol: resolvedProtocol,
2226
+ doGenerate,
2227
+ params
2228
+ }),
2229
+ transformParams: async ({
2230
+ params
2231
+ }) => {
2232
+ return transformParams({
2233
+ protocol: resolvedProtocol,
2234
+ toolSystemPromptTemplate,
2235
+ params
2236
+ });
2237
+ }
2238
+ };
2239
+ }
1998
2240
 
1999
2241
  // src/index.ts
2000
2242
  var gemmaToolMiddleware = createToolMiddleware({
@@ -2002,8 +2244,9 @@ var gemmaToolMiddleware = createToolMiddleware({
2002
2244
  // Customize the tool call delimiters to use markdown code fences
2003
2245
  {
2004
2246
  toolCallStart: "```tool_call\n",
2005
- toolCallEnd: "\n``",
2006
- // two backticks are more common in gemma output @
2247
+ // TODO: Support specifying multiple possible tags,
2248
+ // e.g., for gemma, it would be nice to be able to set both `` and ``` at the same time.
2249
+ toolCallEnd: "\n```",
2007
2250
  toolResponseStart: "```tool_response\n",
2008
2251
  toolResponseEnd: "\n```"
2009
2252
  }
@@ -2034,7 +2277,7 @@ For each function call return a json object with function name and arguments wit
2034
2277
  }
2035
2278
  });
2036
2279
  var xmlToolMiddleware = createToolMiddleware({
2037
- protocol: xmlProtocol,
2280
+ protocol: morphXmlProtocol,
2038
2281
  toolSystemPromptTemplate(tools) {
2039
2282
  return `You are a function calling AI model.
2040
2283
  You are provided with function signatures within <tools></tools> XML tags.
@@ -2052,15 +2295,11 @@ San Fransisco
2052
2295
  }
2053
2296
  });
2054
2297
  export {
2055
- coerceBySchema,
2056
2298
  createToolMiddleware,
2057
- fixToolCallWithSchema,
2058
2299
  gemmaToolMiddleware,
2059
- getSchemaType,
2060
2300
  hermesToolMiddleware,
2061
2301
  jsonMixProtocol,
2062
- unwrapJsonSchema,
2063
- xmlProtocol,
2302
+ morphXmlProtocol,
2064
2303
  xmlToolMiddleware
2065
2304
  };
2066
2305
  //# sourceMappingURL=index.js.map