@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.
@@ -515,10 +515,6 @@ function isTCMProtocolFactory(protocol) {
515
515
  import { parse, stringify } from "@ai-sdk-tool/rxml";
516
516
  var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
517
517
  var WHITESPACE_REGEX = /\s/;
518
- var REGEX_ESCAPE_RE = /[.*+?^${}()|[\]\\]/g;
519
- function escapeRegExp2(value) {
520
- return value.replace(REGEX_ESCAPE_RE, "\\$&");
521
- }
522
518
  function getToolSchema(tools, toolName) {
523
519
  var _a;
524
520
  return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
@@ -683,21 +679,25 @@ function nextTagToken(text, fromPos) {
683
679
  nextPos: open.nextPos
684
680
  };
685
681
  }
686
- function findNextToolTag(text, searchIndex, startTag, selfTag) {
682
+ function findNextToolTag(text, searchIndex, toolName) {
683
+ var _a, _b;
684
+ const startTag = `<${toolName}>`;
687
685
  const openIdx = text.indexOf(startTag, searchIndex);
688
- const selfIdx = text.indexOf(selfTag, searchIndex);
686
+ const selfMatch = findSelfClosingTag(text, toolName, searchIndex);
687
+ const selfIdx = (_a = selfMatch == null ? void 0 : selfMatch.index) != null ? _a : -1;
689
688
  if (openIdx === -1 && selfIdx === -1) {
690
689
  return null;
691
690
  }
692
691
  const isSelfClosing = selfIdx !== -1 && (openIdx === -1 || selfIdx < openIdx);
693
692
  return {
694
693
  tagStart: isSelfClosing ? selfIdx : openIdx,
695
- isSelfClosing
694
+ isSelfClosing,
695
+ tagLength: isSelfClosing ? (_b = selfMatch == null ? void 0 : selfMatch.length) != null ? _b : 0 : startTag.length
696
696
  };
697
697
  }
698
698
  function findLastCloseTagStart(segment, toolName) {
699
699
  const closeTagPattern = new RegExp(
700
- `</\\s*${escapeRegExp2(toolName)}\\s*>`,
700
+ `</\\s*${escapeRegExp(toolName)}\\s*>`,
701
701
  "g"
702
702
  );
703
703
  let closeTagStart = -1;
@@ -711,8 +711,8 @@ function findLastCloseTagStart(segment, toolName) {
711
711
  }
712
712
  return closeTagStart;
713
713
  }
714
- function pushSelfClosingToolCall(toolCalls, toolName, text, tagStart, selfTag) {
715
- const endIndex = tagStart + selfTag.length;
714
+ function pushSelfClosingToolCall(toolCalls, toolName, text, tagStart, tagLength) {
715
+ const endIndex = tagStart + tagLength;
716
716
  toolCalls.push({
717
717
  toolName,
718
718
  startIndex: tagStart,
@@ -722,6 +722,24 @@ function pushSelfClosingToolCall(toolCalls, toolName, text, tagStart, selfTag) {
722
722
  });
723
723
  return endIndex;
724
724
  }
725
+ var selfClosingTagCache = /* @__PURE__ */ new Map();
726
+ function getSelfClosingTagPattern(toolName) {
727
+ let pattern = selfClosingTagCache.get(toolName);
728
+ if (!pattern) {
729
+ pattern = new RegExp(`<\\s*${escapeRegExp(toolName)}\\s*/>`, "g");
730
+ selfClosingTagCache.set(toolName, pattern);
731
+ }
732
+ return pattern;
733
+ }
734
+ function findSelfClosingTag(text, toolName, fromIndex) {
735
+ const pattern = getSelfClosingTagPattern(toolName);
736
+ pattern.lastIndex = fromIndex;
737
+ const match = pattern.exec(text);
738
+ if (!match || match.index === void 0) {
739
+ return null;
740
+ }
741
+ return { index: match.index, length: match[0].length };
742
+ }
725
743
  function appendOpenToolCallIfComplete(toolCalls, text, toolName, tagStart, startTag) {
726
744
  const contentStart = tagStart + startTag.length;
727
745
  const fullTagEnd = findClosingTagEndFlexible(text, contentStart, toolName);
@@ -743,10 +761,9 @@ function appendOpenToolCallIfComplete(toolCalls, text, toolName, tagStart, start
743
761
  function findToolCallsForName(text, toolName) {
744
762
  const toolCalls = [];
745
763
  const startTag = `<${toolName}>`;
746
- const selfTag = `<${toolName}/>`;
747
764
  let searchIndex = 0;
748
765
  while (searchIndex < text.length) {
749
- const match = findNextToolTag(text, searchIndex, startTag, selfTag);
766
+ const match = findNextToolTag(text, searchIndex, toolName);
750
767
  if (match === null) {
751
768
  break;
752
769
  }
@@ -756,7 +773,7 @@ function findToolCallsForName(text, toolName) {
756
773
  toolName,
757
774
  text,
758
775
  match.tagStart,
759
- selfTag
776
+ match.tagLength
760
777
  );
761
778
  continue;
762
779
  }
@@ -779,28 +796,114 @@ function findToolCalls(text, toolNames) {
779
796
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
780
797
  }
781
798
  function findEarliestToolTag(buffer, toolNames) {
799
+ var _a, _b;
782
800
  let bestIndex = -1;
783
801
  let bestName = "";
784
802
  let bestSelfClosing = false;
803
+ let bestTagLength = 0;
785
804
  if (toolNames.length > 0) {
786
805
  for (const name of toolNames) {
787
806
  const openTag = `<${name}>`;
788
- const selfTag = `<${name}/>`;
789
807
  const idxOpen = buffer.indexOf(openTag);
790
- const idxSelf = buffer.indexOf(selfTag);
808
+ const selfMatch = findSelfClosingTag(buffer, name, 0);
809
+ const idxSelf = (_a = selfMatch == null ? void 0 : selfMatch.index) != null ? _a : -1;
791
810
  if (idxOpen !== -1 && (bestIndex === -1 || idxOpen < bestIndex)) {
792
811
  bestIndex = idxOpen;
793
812
  bestName = name;
794
813
  bestSelfClosing = false;
814
+ bestTagLength = openTag.length;
795
815
  }
796
816
  if (idxSelf !== -1 && (bestIndex === -1 || idxSelf < bestIndex)) {
797
817
  bestIndex = idxSelf;
798
818
  bestName = name;
799
819
  bestSelfClosing = true;
820
+ bestTagLength = (_b = selfMatch == null ? void 0 : selfMatch.length) != null ? _b : 0;
800
821
  }
801
822
  }
802
823
  }
803
- return { index: bestIndex, name: bestName, selfClosing: bestSelfClosing };
824
+ return {
825
+ index: bestIndex,
826
+ name: bestName,
827
+ selfClosing: bestSelfClosing,
828
+ tagLength: bestTagLength
829
+ };
830
+ }
831
+ function isOpenTagPrefix(suffix, toolName) {
832
+ return `${toolName}>`.startsWith(suffix);
833
+ }
834
+ function consumeWhitespace(text, index) {
835
+ let i = index;
836
+ while (i < text.length && WHITESPACE_REGEX.test(text.charAt(i))) {
837
+ i += 1;
838
+ }
839
+ return i;
840
+ }
841
+ function consumeToolNamePrefix(text, index, toolName) {
842
+ let i = index;
843
+ let nameIndex = 0;
844
+ while (i < text.length && nameIndex < toolName.length) {
845
+ if (text.charAt(i) !== toolName.charAt(nameIndex)) {
846
+ return { index: i, done: false, valid: false };
847
+ }
848
+ i += 1;
849
+ nameIndex += 1;
850
+ }
851
+ return { index: i, done: nameIndex === toolName.length, valid: true };
852
+ }
853
+ function isSelfClosingSuffixRemainder(text, index) {
854
+ if (text.charAt(index) !== "/") {
855
+ return false;
856
+ }
857
+ if (index + 1 >= text.length) {
858
+ return true;
859
+ }
860
+ return index + 1 === text.length - 1 && text.charAt(index + 1) === ">";
861
+ }
862
+ function isSelfClosingTagPrefix(suffix, toolName) {
863
+ let i = consumeWhitespace(suffix, 0);
864
+ if (i >= suffix.length) {
865
+ return true;
866
+ }
867
+ const nameRemainder = suffix.slice(i);
868
+ if (toolName.startsWith(nameRemainder)) {
869
+ return true;
870
+ }
871
+ const nameResult = consumeToolNamePrefix(suffix, i, toolName);
872
+ if (!nameResult.valid) {
873
+ return false;
874
+ }
875
+ i = nameResult.index;
876
+ if (i >= suffix.length) {
877
+ return true;
878
+ }
879
+ if (!nameResult.done) {
880
+ return false;
881
+ }
882
+ i = consumeWhitespace(suffix, i);
883
+ if (i >= suffix.length) {
884
+ return true;
885
+ }
886
+ return isSelfClosingSuffixRemainder(suffix, i);
887
+ }
888
+ function findPotentialToolTagStart(buffer, toolNames) {
889
+ if (toolNames.length === 0 || buffer.length === 0) {
890
+ return -1;
891
+ }
892
+ const lastGt = buffer.lastIndexOf(">");
893
+ const offset = lastGt === -1 ? 0 : lastGt + 1;
894
+ const trailing = buffer.slice(offset);
895
+ for (let i = trailing.length - 1; i >= 0; i -= 1) {
896
+ if (trailing.charAt(i) !== "<") {
897
+ continue;
898
+ }
899
+ const suffix = trailing.slice(i + 1);
900
+ for (const name of toolNames) {
901
+ if (isOpenTagPrefix(suffix, name) || isSelfClosingTagPrefix(suffix, name)) {
902
+ return offset + i;
903
+ }
904
+ }
905
+ }
906
+ return -1;
804
907
  }
805
908
  function createFlushTextHandler(getCurrentTextId, setCurrentTextId, getHasEmittedTextStart, setHasEmittedTextStart) {
806
909
  return (controller, text) => {
@@ -846,7 +949,7 @@ function processToolCallInBuffer(params) {
846
949
  parseOptions
847
950
  } = params;
848
951
  const endTagPattern = new RegExp(
849
- `</\\s*${escapeRegExp2(currentToolCall.name)}\\s*>`
952
+ `</\\s*${escapeRegExp(currentToolCall.name)}\\s*>`
850
953
  );
851
954
  const endMatch = endTagPattern.exec(buffer);
852
955
  if (!endMatch || endMatch.index === void 0) {
@@ -886,18 +989,22 @@ function processNoToolCallInBuffer(params) {
886
989
  const {
887
990
  index: earliestStartTagIndex,
888
991
  name: earliestToolName,
889
- selfClosing
992
+ selfClosing,
993
+ tagLength
890
994
  } = findEarliestToolTag(buffer, toolNames);
891
995
  if (earliestStartTagIndex === -1) {
892
- const maxTagLen = toolNames.length ? Math.max(...toolNames.map((n) => `<${n}>`.length)) : 0;
893
- const tail = Math.max(0, maxTagLen - 1);
894
- const safeLen = Math.max(0, buffer.length - tail);
996
+ const potentialStart = findPotentialToolTagStart(buffer, toolNames);
997
+ const safeLen = Math.max(
998
+ 0,
999
+ potentialStart === -1 ? buffer.length : potentialStart
1000
+ );
1001
+ const remaining = buffer.slice(safeLen);
895
1002
  if (safeLen > 0) {
896
1003
  flushText(controller, buffer.slice(0, safeLen));
897
- setBuffer(buffer.slice(safeLen));
1004
+ setBuffer(remaining);
898
1005
  }
899
1006
  return {
900
- buffer: buffer.slice(safeLen),
1007
+ buffer: remaining,
901
1008
  currentToolCall: null,
902
1009
  shouldBreak: true,
903
1010
  shouldContinue: false
@@ -905,8 +1012,7 @@ function processNoToolCallInBuffer(params) {
905
1012
  }
906
1013
  flushText(controller, buffer.substring(0, earliestStartTagIndex));
907
1014
  if (selfClosing) {
908
- const selfTag = `<${earliestToolName}/>`;
909
- const newBuffer2 = buffer.substring(earliestStartTagIndex + selfTag.length);
1015
+ const newBuffer2 = buffer.substring(earliestStartTagIndex + tagLength);
910
1016
  setBuffer(newBuffer2);
911
1017
  handleStreamingToolCallEnd({
912
1018
  toolContent: "",
@@ -1967,29 +2073,230 @@ function formatXmlNode(tagName, value, depth) {
1967
2073
  }
1968
2074
 
1969
2075
  // src/core/prompts/xml-system-prompt.ts
2076
+ import dedent from "dedent";
1970
2077
  function xmlSystemPromptTemplate(tools) {
1971
- const toolsJson = JSON.stringify(tools);
1972
- return `# Tools
1973
-
1974
- You may call one or more functions to assist with the user query.
1975
-
1976
- You are provided with function signatures within <tools></tools> XML tags:
1977
- <tools>${toolsJson}</tools>
1978
-
1979
- # Rules
1980
- - Use exactly one XML element whose tag name is the function name.
1981
- - Put each parameter as a child element.
1982
- - Values must follow the schema exactly (numbers, arrays, objects, enums \u2192 copy as-is).
1983
- - Do not add or remove functions or parameters.
1984
- - Each required parameter must appear once.
1985
- - Output nothing before or after the function call.
1986
- - 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.
1987
-
1988
- # Example
1989
- <get_weather>
1990
- <location>New York</location>
1991
- <unit>celsius</unit>
1992
- </get_weather>`;
2078
+ const toolsText = renderToolsForXmlPrompt(tools);
2079
+ const header = dedent`
2080
+ # Tools
2081
+ You may call one or more functions to assist with the user query.
2082
+ `;
2083
+ const definitions = [
2084
+ "You have access to the following functions:",
2085
+ "<tools>",
2086
+ toolsText,
2087
+ "</tools>"
2088
+ ].join("\n");
2089
+ const rules = dedent`
2090
+ <rules>
2091
+ - Use exactly one XML element whose tag name is the function name.
2092
+ - Put each parameter as a child element.
2093
+ - Values must follow the schema exactly (numbers, arrays, objects, enums copy as-is).
2094
+ - Do not add or remove functions or parameters.
2095
+ - Each required parameter must appear once.
2096
+ - Output nothing before or after the function call.
2097
+ - It is also possible to call multiple types of functions in one turn or to call a single function multiple times.
2098
+ </rules>
2099
+ `;
2100
+ const examples = dedent`
2101
+ For each function call, output the function name and parameter in the following format:
2102
+ <example_function_name>
2103
+ <example_parameter_1>value_1</example_parameter_1>
2104
+ <example_parameter_2>This is the value for the second parameter
2105
+ that can span
2106
+ multiple lines</example_parameter_2>
2107
+ </example_function_name>
2108
+ `;
2109
+ return [header, definitions, rules, examples].join("\n\n");
2110
+ }
2111
+ var INDENT = " ";
2112
+ function renderToolsForXmlPrompt(tools) {
2113
+ if (!tools.length) {
2114
+ return "none";
2115
+ }
2116
+ return tools.map(renderToolForXmlPrompt).join("\n\n");
2117
+ }
2118
+ function renderToolForXmlPrompt(tool) {
2119
+ const lines = [`name: ${tool.name}`];
2120
+ if (tool.description) {
2121
+ lines.push(`description: ${tool.description}`);
2122
+ }
2123
+ lines.push("parameters:");
2124
+ const normalizedSchema = normalizeSchema(tool.inputSchema);
2125
+ lines.push(...renderParametersSummary(normalizedSchema, 1));
2126
+ lines.push(`schema: ${stringifySchema(normalizedSchema)}`);
2127
+ return lines.join("\n");
2128
+ }
2129
+ function normalizeSchema(schema) {
2130
+ if (typeof schema === "string") {
2131
+ try {
2132
+ return JSON.parse(schema);
2133
+ } catch (e) {
2134
+ return { type: "string", const: schema };
2135
+ }
2136
+ }
2137
+ return schema;
2138
+ }
2139
+ function renderParametersSummary(schema, indentLevel) {
2140
+ var _a, _b;
2141
+ const indent = INDENT.repeat(indentLevel);
2142
+ if (schema === void 0 || schema === null) {
2143
+ return [`${indent}(none)`];
2144
+ }
2145
+ if (schema === true) {
2146
+ return [`${indent}(any)`];
2147
+ }
2148
+ if (schema === false) {
2149
+ return [`${indent}(no valid parameters)`];
2150
+ }
2151
+ if (typeof schema !== "object") {
2152
+ return [`${indent}- value (${String(schema)})`];
2153
+ }
2154
+ const schemaType = [];
2155
+ if (Array.isArray(schema.type)) {
2156
+ schemaType.push(...schema.type);
2157
+ } else if (schema.type) {
2158
+ schemaType.push(schema.type);
2159
+ }
2160
+ const isObjectLike = schemaType.includes("object") || !!schema.properties;
2161
+ if (isObjectLike) {
2162
+ const properties = (_a = schema.properties) != null ? _a : {};
2163
+ const requiredSet = new Set((_b = schema.required) != null ? _b : []);
2164
+ const propertyNames = Object.keys(properties).sort();
2165
+ if (propertyNames.length === 0) {
2166
+ return [`${indent}(no named parameters)`];
2167
+ }
2168
+ const lines = [];
2169
+ for (const propName of propertyNames) {
2170
+ const propSchema = properties[propName];
2171
+ lines.push(
2172
+ renderPropertySummaryLine({
2173
+ indent,
2174
+ propName,
2175
+ propSchema,
2176
+ required: requiredSet.has(propName)
2177
+ })
2178
+ );
2179
+ }
2180
+ return lines.length ? lines : [`${indent}(no parameters)`];
2181
+ }
2182
+ return [`${indent}- value (${summarizeType(schema)})`];
2183
+ }
2184
+ function renderPropertySummaryLine({
2185
+ indent,
2186
+ propName,
2187
+ propSchema,
2188
+ required
2189
+ }) {
2190
+ const typeLabel = summarizeType(propSchema);
2191
+ const requiredLabel = required ? "required" : "optional";
2192
+ const extras = collectPropertyExtras(propSchema);
2193
+ const extraText = extras.length ? ` - ${extras.join("; ")}` : "";
2194
+ return `${indent}- ${propName} (${typeLabel}, ${requiredLabel})${extraText}`;
2195
+ }
2196
+ function collectPropertyExtras(propSchema) {
2197
+ if (!propSchema || typeof propSchema !== "object") {
2198
+ return [];
2199
+ }
2200
+ const extras = [];
2201
+ if (propSchema.enum) {
2202
+ extras.push(`enum: ${formatEnumForSummary(propSchema.enum)}`);
2203
+ }
2204
+ if (propSchema.default !== void 0) {
2205
+ extras.push(`default: ${formatValue(propSchema.default)}`);
2206
+ }
2207
+ if (propSchema.description) {
2208
+ extras.push(propSchema.description);
2209
+ }
2210
+ return extras;
2211
+ }
2212
+ function summarizeType(schema) {
2213
+ var _a;
2214
+ if (schema === void 0 || schema === null) {
2215
+ return "unknown";
2216
+ }
2217
+ if (schema === true) {
2218
+ return "any";
2219
+ }
2220
+ if (schema === false) {
2221
+ return "never";
2222
+ }
2223
+ if (typeof schema !== "object") {
2224
+ return String(schema);
2225
+ }
2226
+ const schemaType = schema.type;
2227
+ let baseType = "";
2228
+ if (Array.isArray(schemaType) && schemaType.length) {
2229
+ baseType = schemaType.join(" | ");
2230
+ } else if (typeof schemaType === "string") {
2231
+ baseType = schemaType;
2232
+ } else if (schema.enum) {
2233
+ const inferred = Array.from(
2234
+ new Set(schema.enum.map((value) => typeof value))
2235
+ );
2236
+ if (inferred.length === 1) {
2237
+ baseType = (_a = inferred[0]) != null ? _a : "";
2238
+ }
2239
+ } else if (schema.const !== void 0) {
2240
+ baseType = typeof schema.const;
2241
+ }
2242
+ if (!baseType) {
2243
+ baseType = "any";
2244
+ }
2245
+ if (baseType === "array" && schema.items) {
2246
+ const itemType = Array.isArray(schema.items) ? schema.items.map((item) => summarizeType(item)).join(" | ") : summarizeType(schema.items);
2247
+ return `array<${itemType}>`;
2248
+ }
2249
+ if (baseType === "string" && schema.format) {
2250
+ return `string (${schema.format})`;
2251
+ }
2252
+ return baseType;
2253
+ }
2254
+ var ENUM_MAX_INLINE = 6;
2255
+ var ENUM_PREVIEW_LIMIT = 5;
2256
+ function formatEnumForSummary(values) {
2257
+ if (values.length <= ENUM_MAX_INLINE) {
2258
+ return formatValue(values);
2259
+ }
2260
+ const preview = values.slice(0, ENUM_PREVIEW_LIMIT).map((value) => formatValue(value));
2261
+ return `[${preview.join(", ")}, ... (${values.length} total)]`;
2262
+ }
2263
+ function formatValue(value) {
2264
+ if (typeof value === "string") {
2265
+ return JSON.stringify(value);
2266
+ }
2267
+ if (typeof value === "number" || typeof value === "boolean") {
2268
+ return String(value);
2269
+ }
2270
+ if (value === null) {
2271
+ return "null";
2272
+ }
2273
+ if (Array.isArray(value)) {
2274
+ return `[${value.map(formatValue).join(", ")}]`;
2275
+ }
2276
+ return JSON.stringify(value);
2277
+ }
2278
+ function stringifySchema(schema) {
2279
+ if (schema === void 0) {
2280
+ return "null";
2281
+ }
2282
+ return JSON.stringify(stripSchemaKeys(schema));
2283
+ }
2284
+ function stripSchemaKeys(value) {
2285
+ if (Array.isArray(value)) {
2286
+ return value.map((entry) => stripSchemaKeys(entry));
2287
+ }
2288
+ if (value && typeof value === "object") {
2289
+ const record = value;
2290
+ const cleaned = {};
2291
+ for (const [key, entry] of Object.entries(record)) {
2292
+ if (key === "$schema") {
2293
+ continue;
2294
+ }
2295
+ cleaned[key] = stripSchemaKeys(entry);
2296
+ }
2297
+ return cleaned;
2298
+ }
2299
+ return value;
1993
2300
  }
1994
2301
 
1995
2302
  // src/core/prompts/yaml-system-prompt.ts
@@ -2567,4 +2874,4 @@ export {
2567
2874
  xmlToolMiddleware,
2568
2875
  yamlToolMiddleware
2569
2876
  };
2570
- //# sourceMappingURL=chunk-PIUBQRFC.js.map
2877
+ //# sourceMappingURL=chunk-DCK5APVO.js.map