@ai-sdk-tool/parser 3.2.0 → 3.2.1

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.
@@ -585,10 +585,6 @@ function isTCMProtocolFactory(protocol) {
585
585
  var import_rxml = require("@ai-sdk-tool/rxml");
586
586
  var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
587
587
  var WHITESPACE_REGEX = /\s/;
588
- var REGEX_ESCAPE_RE = /[.*+?^${}()|[\]\\]/g;
589
- function escapeRegExp2(value) {
590
- return value.replace(REGEX_ESCAPE_RE, "\\$&");
591
- }
592
588
  function getToolSchema(tools, toolName) {
593
589
  var _a;
594
590
  return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
@@ -753,21 +749,25 @@ function nextTagToken(text, fromPos) {
753
749
  nextPos: open.nextPos
754
750
  };
755
751
  }
756
- function findNextToolTag(text, searchIndex, startTag, selfTag) {
752
+ function findNextToolTag(text, searchIndex, toolName) {
753
+ var _a, _b;
754
+ const startTag = `<${toolName}>`;
757
755
  const openIdx = text.indexOf(startTag, searchIndex);
758
- const selfIdx = text.indexOf(selfTag, searchIndex);
756
+ const selfMatch = findSelfClosingTag(text, toolName, searchIndex);
757
+ const selfIdx = (_a = selfMatch == null ? void 0 : selfMatch.index) != null ? _a : -1;
759
758
  if (openIdx === -1 && selfIdx === -1) {
760
759
  return null;
761
760
  }
762
761
  const isSelfClosing = selfIdx !== -1 && (openIdx === -1 || selfIdx < openIdx);
763
762
  return {
764
763
  tagStart: isSelfClosing ? selfIdx : openIdx,
765
- isSelfClosing
764
+ isSelfClosing,
765
+ tagLength: isSelfClosing ? (_b = selfMatch == null ? void 0 : selfMatch.length) != null ? _b : 0 : startTag.length
766
766
  };
767
767
  }
768
768
  function findLastCloseTagStart(segment, toolName) {
769
769
  const closeTagPattern = new RegExp(
770
- `</\\s*${escapeRegExp2(toolName)}\\s*>`,
770
+ `</\\s*${escapeRegExp(toolName)}\\s*>`,
771
771
  "g"
772
772
  );
773
773
  let closeTagStart = -1;
@@ -781,8 +781,8 @@ function findLastCloseTagStart(segment, toolName) {
781
781
  }
782
782
  return closeTagStart;
783
783
  }
784
- function pushSelfClosingToolCall(toolCalls, toolName, text, tagStart, selfTag) {
785
- const endIndex = tagStart + selfTag.length;
784
+ function pushSelfClosingToolCall(toolCalls, toolName, text, tagStart, tagLength) {
785
+ const endIndex = tagStart + tagLength;
786
786
  toolCalls.push({
787
787
  toolName,
788
788
  startIndex: tagStart,
@@ -792,6 +792,24 @@ function pushSelfClosingToolCall(toolCalls, toolName, text, tagStart, selfTag) {
792
792
  });
793
793
  return endIndex;
794
794
  }
795
+ var selfClosingTagCache = /* @__PURE__ */ new Map();
796
+ function getSelfClosingTagPattern(toolName) {
797
+ let pattern = selfClosingTagCache.get(toolName);
798
+ if (!pattern) {
799
+ pattern = new RegExp(`<\\s*${escapeRegExp(toolName)}\\s*/>`, "g");
800
+ selfClosingTagCache.set(toolName, pattern);
801
+ }
802
+ return pattern;
803
+ }
804
+ function findSelfClosingTag(text, toolName, fromIndex) {
805
+ const pattern = getSelfClosingTagPattern(toolName);
806
+ pattern.lastIndex = fromIndex;
807
+ const match = pattern.exec(text);
808
+ if (!match || match.index === void 0) {
809
+ return null;
810
+ }
811
+ return { index: match.index, length: match[0].length };
812
+ }
795
813
  function appendOpenToolCallIfComplete(toolCalls, text, toolName, tagStart, startTag) {
796
814
  const contentStart = tagStart + startTag.length;
797
815
  const fullTagEnd = findClosingTagEndFlexible(text, contentStart, toolName);
@@ -813,10 +831,9 @@ function appendOpenToolCallIfComplete(toolCalls, text, toolName, tagStart, start
813
831
  function findToolCallsForName(text, toolName) {
814
832
  const toolCalls = [];
815
833
  const startTag = `<${toolName}>`;
816
- const selfTag = `<${toolName}/>`;
817
834
  let searchIndex = 0;
818
835
  while (searchIndex < text.length) {
819
- const match = findNextToolTag(text, searchIndex, startTag, selfTag);
836
+ const match = findNextToolTag(text, searchIndex, toolName);
820
837
  if (match === null) {
821
838
  break;
822
839
  }
@@ -826,7 +843,7 @@ function findToolCallsForName(text, toolName) {
826
843
  toolName,
827
844
  text,
828
845
  match.tagStart,
829
- selfTag
846
+ match.tagLength
830
847
  );
831
848
  continue;
832
849
  }
@@ -849,28 +866,114 @@ function findToolCalls(text, toolNames) {
849
866
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
850
867
  }
851
868
  function findEarliestToolTag(buffer, toolNames) {
869
+ var _a, _b;
852
870
  let bestIndex = -1;
853
871
  let bestName = "";
854
872
  let bestSelfClosing = false;
873
+ let bestTagLength = 0;
855
874
  if (toolNames.length > 0) {
856
875
  for (const name of toolNames) {
857
876
  const openTag = `<${name}>`;
858
- const selfTag = `<${name}/>`;
859
877
  const idxOpen = buffer.indexOf(openTag);
860
- const idxSelf = buffer.indexOf(selfTag);
878
+ const selfMatch = findSelfClosingTag(buffer, name, 0);
879
+ const idxSelf = (_a = selfMatch == null ? void 0 : selfMatch.index) != null ? _a : -1;
861
880
  if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
862
881
  bestIndex = idxOpen;
863
882
  bestName = name;
864
883
  bestSelfClosing = false;
884
+ bestTagLength = openTag.length;
865
885
  }
866
886
  if (idxSelf !== -1 && (bestIndex === -1 || idxSelf < bestIndex)) {
867
887
  bestIndex = idxSelf;
868
888
  bestName = name;
869
889
  bestSelfClosing = true;
890
+ bestTagLength = (_b = selfMatch == null ? void 0 : selfMatch.length) != null ? _b : 0;
870
891
  }
871
892
  }
872
893
  }
873
- return { index: bestIndex, name: bestName, selfClosing: bestSelfClosing };
894
+ return {
895
+ index: bestIndex,
896
+ name: bestName,
897
+ selfClosing: bestSelfClosing,
898
+ tagLength: bestTagLength
899
+ };
900
+ }
901
+ function isOpenTagPrefix(suffix, toolName) {
902
+ return `${toolName}>`.startsWith(suffix);
903
+ }
904
+ function consumeWhitespace(text, index) {
905
+ let i = index;
906
+ while (i < text.length && WHITESPACE_REGEX.test(text.charAt(i))) {
907
+ i += 1;
908
+ }
909
+ return i;
910
+ }
911
+ function consumeToolNamePrefix(text, index, toolName) {
912
+ let i = index;
913
+ let nameIndex = 0;
914
+ while (i < text.length && nameIndex < toolName.length) {
915
+ if (text.charAt(i) !== toolName.charAt(nameIndex)) {
916
+ return { index: i, done: false, valid: false };
917
+ }
918
+ i += 1;
919
+ nameIndex += 1;
920
+ }
921
+ return { index: i, done: nameIndex === toolName.length, valid: true };
922
+ }
923
+ function isSelfClosingSuffixRemainder(text, index) {
924
+ if (text.charAt(index) !== "/") {
925
+ return false;
926
+ }
927
+ if (index + 1 >= text.length) {
928
+ return true;
929
+ }
930
+ return index + 1 === text.length - 1 && text.charAt(index + 1) === ">";
931
+ }
932
+ function isSelfClosingTagPrefix(suffix, toolName) {
933
+ let i = consumeWhitespace(suffix, 0);
934
+ if (i >= suffix.length) {
935
+ return true;
936
+ }
937
+ const nameRemainder = suffix.slice(i);
938
+ if (toolName.startsWith(nameRemainder)) {
939
+ return true;
940
+ }
941
+ const nameResult = consumeToolNamePrefix(suffix, i, toolName);
942
+ if (!nameResult.valid) {
943
+ return false;
944
+ }
945
+ i = nameResult.index;
946
+ if (i >= suffix.length) {
947
+ return true;
948
+ }
949
+ if (!nameResult.done) {
950
+ return false;
951
+ }
952
+ i = consumeWhitespace(suffix, i);
953
+ if (i >= suffix.length) {
954
+ return true;
955
+ }
956
+ return isSelfClosingSuffixRemainder(suffix, i);
957
+ }
958
+ function findPotentialToolTagStart(buffer, toolNames) {
959
+ if (toolNames.length === 0 || buffer.length === 0) {
960
+ return -1;
961
+ }
962
+ const lastGt = buffer.lastIndexOf(">");
963
+ const offset = lastGt === -1 ? 0 : lastGt + 1;
964
+ const trailing = buffer.slice(offset);
965
+ for (let i = trailing.length - 1; i >= 0; i -= 1) {
966
+ if (trailing.charAt(i) !== "<") {
967
+ continue;
968
+ }
969
+ const suffix = trailing.slice(i + 1);
970
+ for (const name of toolNames) {
971
+ if (isOpenTagPrefix(suffix, name) || isSelfClosingTagPrefix(suffix, name)) {
972
+ return offset + i;
973
+ }
974
+ }
975
+ }
976
+ return -1;
874
977
  }
875
978
  function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
876
979
  return (controller, text) => {
@@ -916,7 +1019,7 @@ function processToolCallInBuffer(params) {
916
1019
  parseOptions
917
1020
  } = params;
918
1021
  const endTagPattern = new RegExp(
919
- `</\\s*${escapeRegExp2(currentToolCall.name)}\\s*>`
1022
+ `</\\s*${escapeRegExp(currentToolCall.name)}\\s*>`
920
1023
  );
921
1024
  const endMatch = endTagPattern.exec(buffer);
922
1025
  if (!endMatch || endMatch.index === void 0) {
@@ -956,18 +1059,22 @@ function processNoToolCallInBuffer(params) {
956
1059
  const {
957
1060
  index: earliestStartTagIndex,
958
1061
  name: earliestToolName,
959
- selfClosing
1062
+ selfClosing,
1063
+ tagLength
960
1064
  } = findEarliestToolTag(buffer, toolNames);
961
1065
  if (earliestStartTagIndex === -1) {
962
- const maxTagLen = toolNames.length ? Math.max(...toolNames.map((n) => `<${n}>`.length)) : 0;
963
- const tail = Math.max(0, maxTagLen - 1);
964
- const safeLen = Math.max(0, buffer.length - tail);
1066
+ const potentialStart = findPotentialToolTagStart(buffer, toolNames);
1067
+ const safeLen = Math.max(
1068
+ 0,
1069
+ potentialStart === -1 ? buffer.length : potentialStart
1070
+ );
1071
+ const remaining = buffer.slice(safeLen);
965
1072
  if (safeLen > 0) {
966
1073
  flushText(controller, buffer.slice(0, safeLen));
967
- setBuffer(buffer.slice(safeLen));
1074
+ setBuffer(remaining);
968
1075
  }
969
1076
  return {
970
- buffer: buffer.slice(safeLen),
1077
+ buffer: remaining,
971
1078
  currentToolCall: null,
972
1079
  shouldBreak: true,
973
1080
  shouldContinue: false
@@ -975,8 +1082,7 @@ function processNoToolCallInBuffer(params) {
975
1082
  }
976
1083
  flushText(controller, buffer.substring(0, earliestStartTagIndex));
977
1084
  if (selfClosing) {
978
- const selfTag = `<${earliestToolName}/>`;
979
- const newBuffer2 = buffer.substring(earliestStartTagIndex + selfTag.length);
1085
+ const newBuffer2 = buffer.substring(earliestStartTagIndex + tagLength);
980
1086
  setBuffer(newBuffer2);
981
1087
  handleStreamingToolCallEnd({
982
1088
  toolContent: "",
@@ -2037,29 +2143,230 @@ function formatXmlNode(tagName, value, depth) {
2037
2143
  }
2038
2144
 
2039
2145
  // src/core/prompts/xml-system-prompt.ts
2146
+ var import_dedent = __toESM(require("dedent"), 1);
2040
2147
  function xmlSystemPromptTemplate(tools) {
2041
- const toolsJson = JSON.stringify(tools);
2042
- return `# Tools
2043
-
2044
- You may call one or more functions to assist with the user query.
2045
-
2046
- You are provided with function signatures within <tools></tools> XML tags:
2047
- <tools>${toolsJson}</tools>
2048
-
2049
- # Rules
2050
- - Use exactly one XML element whose tag name is the function name.
2051
- - Put each parameter as a child element.
2052
- - Values must follow the schema exactly (numbers, arrays, objects, enums \u2192 copy as-is).
2053
- - Do not add or remove functions or parameters.
2054
- - Each required parameter must appear once.
2055
- - Output nothing before or after the function call.
2056
- - After calling a tool, you will receive a response in the format: <tool_response><tool_name>NAME</tool_name><result>RESULT</result></tool_response>. Use this result to answer the user.
2057
-
2058
- # Example
2059
- <get_weather>
2060
- <location>New York</location>
2061
- <unit>celsius</unit>
2062
- </get_weather>`;
2148
+ const toolsText = renderToolsForXmlPrompt(tools);
2149
+ const header = import_dedent.default`
2150
+ # Tools
2151
+ You may call one or more functions to assist with the user query.
2152
+ `;
2153
+ const definitions = [
2154
+ "You have access to the following functions:",
2155
+ "<tools>",
2156
+ toolsText,
2157
+ "</tools>"
2158
+ ].join("\n");
2159
+ const rules = import_dedent.default`
2160
+ <rules>
2161
+ - Use exactly one XML element whose tag name is the function name.
2162
+ - Put each parameter as a child element.
2163
+ - Values must follow the schema exactly (numbers, arrays, objects, enums copy as-is).
2164
+ - Do not add or remove functions or parameters.
2165
+ - Each required parameter must appear once.
2166
+ - Output nothing before or after the function call.
2167
+ - It is also possible to call multiple types of functions in one turn or to call a single function multiple times.
2168
+ </rules>
2169
+ `;
2170
+ const examples = import_dedent.default`
2171
+ For each function call, output the function name and parameter in the following format:
2172
+ <example_function_name>
2173
+ <example_parameter_1>value_1</example_parameter_1>
2174
+ <example_parameter_2>This is the value for the second parameter
2175
+ that can span
2176
+ multiple lines</example_parameter_2>
2177
+ </example_function_name>
2178
+ `;
2179
+ return [header, definitions, rules, examples].join("\n\n");
2180
+ }
2181
+ var INDENT = " ";
2182
+ function renderToolsForXmlPrompt(tools) {
2183
+ if (!tools.length) {
2184
+ return "none";
2185
+ }
2186
+ return tools.map(renderToolForXmlPrompt).join("\n\n");
2187
+ }
2188
+ function renderToolForXmlPrompt(tool) {
2189
+ const lines = [`name: ${tool.name}`];
2190
+ if (tool.description) {
2191
+ lines.push(`description: ${tool.description}`);
2192
+ }
2193
+ lines.push("parameters:");
2194
+ const normalizedSchema = normalizeSchema(tool.inputSchema);
2195
+ lines.push(...renderParametersSummary(normalizedSchema, 1));
2196
+ lines.push(`schema: ${stringifySchema(normalizedSchema)}`);
2197
+ return lines.join("\n");
2198
+ }
2199
+ function normalizeSchema(schema) {
2200
+ if (typeof schema === "string") {
2201
+ try {
2202
+ return JSON.parse(schema);
2203
+ } catch (e) {
2204
+ return { type: "string", const: schema };
2205
+ }
2206
+ }
2207
+ return schema;
2208
+ }
2209
+ function renderParametersSummary(schema, indentLevel) {
2210
+ var _a, _b;
2211
+ const indent = INDENT.repeat(indentLevel);
2212
+ if (schema === void 0 || schema === null) {
2213
+ return [`${indent}(none)`];
2214
+ }
2215
+ if (schema === true) {
2216
+ return [`${indent}(any)`];
2217
+ }
2218
+ if (schema === false) {
2219
+ return [`${indent}(no valid parameters)`];
2220
+ }
2221
+ if (typeof schema !== "object") {
2222
+ return [`${indent}- value (${String(schema)})`];
2223
+ }
2224
+ const schemaType = [];
2225
+ if (Array.isArray(schema.type)) {
2226
+ schemaType.push(...schema.type);
2227
+ } else if (schema.type) {
2228
+ schemaType.push(schema.type);
2229
+ }
2230
+ const isObjectLike = schemaType.includes("object") || !!schema.properties;
2231
+ if (isObjectLike) {
2232
+ const properties = (_a = schema.properties) != null ? _a : {};
2233
+ const requiredSet = new Set((_b = schema.required) != null ? _b : []);
2234
+ const propertyNames = Object.keys(properties).sort();
2235
+ if (propertyNames.length === 0) {
2236
+ return [`${indent}(no named parameters)`];
2237
+ }
2238
+ const lines = [];
2239
+ for (const propName of propertyNames) {
2240
+ const propSchema = properties[propName];
2241
+ lines.push(
2242
+ renderPropertySummaryLine({
2243
+ indent,
2244
+ propName,
2245
+ propSchema,
2246
+ required: requiredSet.has(propName)
2247
+ })
2248
+ );
2249
+ }
2250
+ return lines.length ? lines : [`${indent}(no parameters)`];
2251
+ }
2252
+ return [`${indent}- value (${summarizeType(schema)})`];
2253
+ }
2254
+ function renderPropertySummaryLine({
2255
+ indent,
2256
+ propName,
2257
+ propSchema,
2258
+ required
2259
+ }) {
2260
+ const typeLabel = summarizeType(propSchema);
2261
+ const requiredLabel = required ? "required" : "optional";
2262
+ const extras = collectPropertyExtras(propSchema);
2263
+ const extraText = extras.length ? ` - ${extras.join("; ")}` : "";
2264
+ return `${indent}- ${propName} (${typeLabel}, ${requiredLabel})${extraText}`;
2265
+ }
2266
+ function collectPropertyExtras(propSchema) {
2267
+ if (!propSchema || typeof propSchema !== "object") {
2268
+ return [];
2269
+ }
2270
+ const extras = [];
2271
+ if (propSchema.enum) {
2272
+ extras.push(`enum: ${formatEnumForSummary(propSchema.enum)}`);
2273
+ }
2274
+ if (propSchema.default !== void 0) {
2275
+ extras.push(`default: ${formatValue(propSchema.default)}`);
2276
+ }
2277
+ if (propSchema.description) {
2278
+ extras.push(propSchema.description);
2279
+ }
2280
+ return extras;
2281
+ }
2282
+ function summarizeType(schema) {
2283
+ var _a;
2284
+ if (schema === void 0 || schema === null) {
2285
+ return "unknown";
2286
+ }
2287
+ if (schema === true) {
2288
+ return "any";
2289
+ }
2290
+ if (schema === false) {
2291
+ return "never";
2292
+ }
2293
+ if (typeof schema !== "object") {
2294
+ return String(schema);
2295
+ }
2296
+ const schemaType = schema.type;
2297
+ let baseType = "";
2298
+ if (Array.isArray(schemaType) && schemaType.length) {
2299
+ baseType = schemaType.join(" | ");
2300
+ } else if (typeof schemaType === "string") {
2301
+ baseType = schemaType;
2302
+ } else if (schema.enum) {
2303
+ const inferred = Array.from(
2304
+ new Set(schema.enum.map((value) => typeof value))
2305
+ );
2306
+ if (inferred.length === 1) {
2307
+ baseType = (_a = inferred[0]) != null ? _a : "";
2308
+ }
2309
+ } else if (schema.const !== void 0) {
2310
+ baseType = typeof schema.const;
2311
+ }
2312
+ if (!baseType) {
2313
+ baseType = "any";
2314
+ }
2315
+ if (baseType === "array" && schema.items) {
2316
+ const itemType = Array.isArray(schema.items) ? schema.items.map((item) => summarizeType(item)).join(" | ") : summarizeType(schema.items);
2317
+ return `array<${itemType}>`;
2318
+ }
2319
+ if (baseType === "string" && schema.format) {
2320
+ return `string (${schema.format})`;
2321
+ }
2322
+ return baseType;
2323
+ }
2324
+ var ENUM_MAX_INLINE = 6;
2325
+ var ENUM_PREVIEW_LIMIT = 5;
2326
+ function formatEnumForSummary(values) {
2327
+ if (values.length <= ENUM_MAX_INLINE) {
2328
+ return formatValue(values);
2329
+ }
2330
+ const preview = values.slice(0, ENUM_PREVIEW_LIMIT).map((value) => formatValue(value));
2331
+ return `[${preview.join(", ")}, ... (${values.length} total)]`;
2332
+ }
2333
+ function formatValue(value) {
2334
+ if (typeof value === "string") {
2335
+ return JSON.stringify(value);
2336
+ }
2337
+ if (typeof value === "number" || typeof value === "boolean") {
2338
+ return String(value);
2339
+ }
2340
+ if (value === null) {
2341
+ return "null";
2342
+ }
2343
+ if (Array.isArray(value)) {
2344
+ return `[${value.map(formatValue).join(", ")}]`;
2345
+ }
2346
+ return JSON.stringify(value);
2347
+ }
2348
+ function stringifySchema(schema) {
2349
+ if (schema === void 0) {
2350
+ return "null";
2351
+ }
2352
+ return JSON.stringify(stripSchemaKeys(schema));
2353
+ }
2354
+ function stripSchemaKeys(value) {
2355
+ if (Array.isArray(value)) {
2356
+ return value.map((entry) => stripSchemaKeys(entry));
2357
+ }
2358
+ if (value && typeof value === "object") {
2359
+ const record = value;
2360
+ const cleaned = {};
2361
+ for (const [key, entry] of Object.entries(record)) {
2362
+ if (key === "$schema") {
2363
+ continue;
2364
+ }
2365
+ cleaned[key] = stripSchemaKeys(entry);
2366
+ }
2367
+ return cleaned;
2368
+ }
2369
+ return value;
2063
2370
  }
2064
2371
 
2065
2372
  // src/core/prompts/yaml-system-prompt.ts