@ai-sdk-tool/parser 3.3.1 → 3.3.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.
@@ -850,6 +850,13 @@ function generateId() {
850
850
  return Math.random().toString(36).substring(2, 15);
851
851
  }
852
852
 
853
+ // src/core/utils/protocol-utils.ts
854
+ function addTextSegment(text, processedElements) {
855
+ if (text.trim()) {
856
+ processedElements.push({ type: "text", text });
857
+ }
858
+ }
859
+
853
860
  // src/core/utils/regex.ts
854
861
  function escapeRegExp(literal) {
855
862
  return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -881,11 +888,6 @@ function processToolCallJson(toolCallJson, fullMatch, processedElements, options
881
888
  processedElements.push({ type: "text", text: fullMatch });
882
889
  }
883
890
  }
884
- function addTextSegment(text, processedElements) {
885
- if (text.trim()) {
886
- processedElements.push({ type: "text", text });
887
- }
888
- }
889
891
  function processMatchedToolCall(context) {
890
892
  const { match, text, currentIndex, processedElements, options } = context;
891
893
  const startIndex = match.index;
@@ -1514,6 +1516,13 @@ var EMPTY_OBJECT_REGEX = /^\{\s*\}$/s;
1514
1516
  var NEWLINE_SPLIT_REGEX = /\n+/;
1515
1517
  var COMMA_SPLIT_REGEX = /,\s*/;
1516
1518
  var DIGIT_KEY_REGEX = /^\d+$/;
1519
+ var WHITESPACE_REGEX2 = /\s+/g;
1520
+ var HAS_WHITESPACE_REGEX = /\s/;
1521
+ var SINGLE_QUOTE = "'";
1522
+ var DOUBLE_QUOTE = '"';
1523
+ var SNAKE_SEGMENT_REGEX = /_([a-zA-Z0-9])/g;
1524
+ var CAMEL_BOUNDARY_REGEX = /([a-z0-9])([A-Z])/g;
1525
+ var LEADING_UNDERSCORES_REGEX = /^_+/;
1517
1526
  function unwrapJsonSchema(schema) {
1518
1527
  if (!schema || typeof schema !== "object") {
1519
1528
  return schema;
@@ -1762,9 +1771,158 @@ function coerceStringToArray(s, unwrapped) {
1762
1771
  }
1763
1772
  return null;
1764
1773
  }
1774
+ function getStrictObjectSchemaInfo(unwrapped) {
1775
+ if (getSchemaType(unwrapped) !== "object") {
1776
+ return null;
1777
+ }
1778
+ if (unwrapped.additionalProperties !== false) {
1779
+ return null;
1780
+ }
1781
+ const properties = unwrapped.properties;
1782
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
1783
+ return null;
1784
+ }
1785
+ const propertyMap = properties;
1786
+ const required = Array.isArray(unwrapped.required) ? unwrapped.required.filter(
1787
+ (value) => typeof value === "string" && value.length > 0
1788
+ ) : [];
1789
+ const patternProps = unwrapped.patternProperties;
1790
+ const patternProperties = patternProps && typeof patternProps === "object" && !Array.isArray(patternProps) ? patternProps : void 0;
1791
+ return {
1792
+ properties: propertyMap,
1793
+ required,
1794
+ patternProperties
1795
+ };
1796
+ }
1797
+ function isSingularPluralPair(left, right) {
1798
+ return left.length > 1 && right.length > 1 && (left === `${right}s` || right === `${left}s`);
1799
+ }
1800
+ function snakeToCamel(value) {
1801
+ const trimmed = value.replace(LEADING_UNDERSCORES_REGEX, "");
1802
+ if (trimmed.length === 0) {
1803
+ return value;
1804
+ }
1805
+ const camelized = trimmed.replace(
1806
+ SNAKE_SEGMENT_REGEX,
1807
+ (_, c) => c.toUpperCase()
1808
+ );
1809
+ return camelized.charAt(0).toLowerCase() + camelized.slice(1);
1810
+ }
1811
+ function camelToSnake(value) {
1812
+ return value.replace(CAMEL_BOUNDARY_REGEX, "$1_$2").toLowerCase();
1813
+ }
1814
+ function isCaseStylePair(targetKey, sourceKey) {
1815
+ if (targetKey === sourceKey) {
1816
+ return false;
1817
+ }
1818
+ const sourceLooksSnake = sourceKey.includes("_");
1819
+ const targetLooksSnake = targetKey.includes("_");
1820
+ if (sourceLooksSnake && snakeToCamel(sourceKey) === targetKey) {
1821
+ return true;
1822
+ }
1823
+ if (!sourceLooksSnake && targetLooksSnake && camelToSnake(sourceKey) === targetKey) {
1824
+ return true;
1825
+ }
1826
+ return false;
1827
+ }
1828
+ function isUnexpectedKey(key, schemaInfo) {
1829
+ if (Object.hasOwn(schemaInfo.properties, key)) {
1830
+ return false;
1831
+ }
1832
+ const patternSchemas = getPatternSchemasForKey(
1833
+ schemaInfo.patternProperties,
1834
+ key
1835
+ );
1836
+ if (patternSchemas.length > 0) {
1837
+ return patternSchemas.every((schema) => schema === false);
1838
+ }
1839
+ return true;
1840
+ }
1841
+ function computeMissingAndUnexpectedKeys(input, schemaInfo) {
1842
+ const missingRequired = schemaInfo.required.filter(
1843
+ (key) => !Object.hasOwn(input, key)
1844
+ );
1845
+ const unexpectedKeys = Object.keys(input).filter(
1846
+ (key) => isUnexpectedKey(key, schemaInfo)
1847
+ );
1848
+ return { missingRequired, unexpectedKeys };
1849
+ }
1850
+ function applySingularPluralRequiredKeyRename(input, schemaInfo) {
1851
+ const { missingRequired, unexpectedKeys } = computeMissingAndUnexpectedKeys(
1852
+ input,
1853
+ schemaInfo
1854
+ );
1855
+ if (missingRequired.length !== 1 || unexpectedKeys.length !== 1) {
1856
+ return null;
1857
+ }
1858
+ const targetKey = missingRequired[0];
1859
+ const sourceKey = unexpectedKeys[0];
1860
+ if (!Object.hasOwn(schemaInfo.properties, targetKey)) {
1861
+ return null;
1862
+ }
1863
+ if (!isSingularPluralPair(targetKey, sourceKey)) {
1864
+ return null;
1865
+ }
1866
+ if (getSchemaType(schemaInfo.properties[targetKey]) !== "array") {
1867
+ return null;
1868
+ }
1869
+ if (!Array.isArray(input[sourceKey])) {
1870
+ return null;
1871
+ }
1872
+ if (!Object.hasOwn(input, sourceKey) || Object.hasOwn(input, targetKey)) {
1873
+ return null;
1874
+ }
1875
+ const output = { ...input };
1876
+ output[targetKey] = output[sourceKey];
1877
+ delete output[sourceKey];
1878
+ return output;
1879
+ }
1880
+ function applyCaseStyleRequiredKeyRename(input, schemaInfo) {
1881
+ const { missingRequired, unexpectedKeys } = computeMissingAndUnexpectedKeys(
1882
+ input,
1883
+ schemaInfo
1884
+ );
1885
+ if (missingRequired.length !== 1 || unexpectedKeys.length !== 1) {
1886
+ return null;
1887
+ }
1888
+ const targetKey = missingRequired[0];
1889
+ const sourceKey = unexpectedKeys[0];
1890
+ if (!Object.hasOwn(schemaInfo.properties, targetKey)) {
1891
+ return null;
1892
+ }
1893
+ if (!isCaseStylePair(targetKey, sourceKey)) {
1894
+ return null;
1895
+ }
1896
+ if (!Object.hasOwn(input, sourceKey) || Object.hasOwn(input, targetKey)) {
1897
+ return null;
1898
+ }
1899
+ const output = { ...input };
1900
+ output[targetKey] = output[sourceKey];
1901
+ delete output[sourceKey];
1902
+ return output;
1903
+ }
1904
+ function applyStrictRequiredKeyRename(input, unwrapped) {
1905
+ const schemaInfo = getStrictObjectSchemaInfo(unwrapped);
1906
+ if (!schemaInfo) {
1907
+ return input;
1908
+ }
1909
+ const singularPlural = applySingularPluralRequiredKeyRename(
1910
+ input,
1911
+ schemaInfo
1912
+ );
1913
+ if (singularPlural) {
1914
+ return singularPlural;
1915
+ }
1916
+ const caseStyle = applyCaseStyleRequiredKeyRename(input, schemaInfo);
1917
+ if (caseStyle) {
1918
+ return caseStyle;
1919
+ }
1920
+ return input;
1921
+ }
1765
1922
  function coerceObjectToObject(value, unwrapped) {
1923
+ const normalizedInput = applyStrictRequiredKeyRename(value, unwrapped);
1766
1924
  const out = {};
1767
- for (const [k, v] of Object.entries(value)) {
1925
+ for (const [k, v] of Object.entries(normalizedInput)) {
1768
1926
  out[k] = coerceValueForKey(v, k, unwrapped);
1769
1927
  }
1770
1928
  return out;
@@ -1775,6 +1933,109 @@ function coerceArrayToArray(value, prefixItems, itemsSchema) {
1775
1933
  }
1776
1934
  return value.map((v) => coerceBySchema(v, itemsSchema));
1777
1935
  }
1936
+ function isPrimitiveSchemaType(schemaType) {
1937
+ return schemaType === "string" || schemaType === "number" || schemaType === "integer" || schemaType === "boolean";
1938
+ }
1939
+ function isPrimitiveMatchForSchemaType(value, schemaType) {
1940
+ if (schemaType === "string") {
1941
+ return typeof value === "string";
1942
+ }
1943
+ if (schemaType === "number") {
1944
+ return typeof value === "number" && Number.isFinite(value);
1945
+ }
1946
+ if (schemaType === "integer") {
1947
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value);
1948
+ }
1949
+ return typeof value === "boolean";
1950
+ }
1951
+ function coercePrimitiveWrappedObject(value, itemsSchema) {
1952
+ const schemaType = getSchemaType(itemsSchema);
1953
+ if (!isPrimitiveSchemaType(schemaType)) {
1954
+ return null;
1955
+ }
1956
+ const keys = Object.keys(value);
1957
+ if (keys.length !== 1) {
1958
+ return null;
1959
+ }
1960
+ const singleValue = value[keys[0]];
1961
+ if (singleValue && typeof singleValue === "object") {
1962
+ return null;
1963
+ }
1964
+ const coerced = coerceBySchema(singleValue, itemsSchema);
1965
+ return isPrimitiveMatchForSchemaType(coerced, schemaType) ? coerced : null;
1966
+ }
1967
+ function coerceParallelArraysObjectToArray(maybe, prefixItems, itemsSchema) {
1968
+ if (prefixItems && prefixItems.length > 0) {
1969
+ return null;
1970
+ }
1971
+ const unwrappedItems = unwrapJsonSchema(itemsSchema);
1972
+ if (!unwrappedItems || typeof unwrappedItems !== "object" || Array.isArray(unwrappedItems)) {
1973
+ return null;
1974
+ }
1975
+ const itemSchema = unwrappedItems;
1976
+ if (getSchemaType(itemSchema) !== "object") {
1977
+ return null;
1978
+ }
1979
+ if (itemSchema.additionalProperties !== false) {
1980
+ return null;
1981
+ }
1982
+ const properties = itemSchema.properties;
1983
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
1984
+ return null;
1985
+ }
1986
+ const propertyMap = properties;
1987
+ const entries = Object.entries(maybe);
1988
+ if (entries.length < 2) {
1989
+ return null;
1990
+ }
1991
+ if (!entries.every(([, value]) => Array.isArray(value))) {
1992
+ return null;
1993
+ }
1994
+ if (!entries.every(([key]) => Object.hasOwn(propertyMap, key))) {
1995
+ return null;
1996
+ }
1997
+ if (!entries.every(([key]) => {
1998
+ const schemaType = getSchemaType(propertyMap[key]);
1999
+ return schemaType !== "array" && schemaType !== "object";
2000
+ })) {
2001
+ return null;
2002
+ }
2003
+ const lengths = [
2004
+ ...new Set(entries.map(([, value]) => value.length))
2005
+ ];
2006
+ if (lengths.length !== 1) {
2007
+ return null;
2008
+ }
2009
+ const length = lengths[0];
2010
+ if (length < 2) {
2011
+ return null;
2012
+ }
2013
+ const zipped = [];
2014
+ for (let index = 0; index < length; index += 1) {
2015
+ const item = {};
2016
+ for (const [key, value] of entries) {
2017
+ item[key] = value[index];
2018
+ }
2019
+ zipped.push(item);
2020
+ }
2021
+ return coerceArrayToArray(zipped, prefixItems, itemsSchema);
2022
+ }
2023
+ function coerceSingleKeyObjectToArray(singleValue, itemsSchema) {
2024
+ if (Array.isArray(singleValue)) {
2025
+ return singleValue.map((v) => coerceBySchema(v, itemsSchema));
2026
+ }
2027
+ if (singleValue && typeof singleValue === "object") {
2028
+ const primitiveWrapped = coercePrimitiveWrappedObject(
2029
+ singleValue,
2030
+ itemsSchema
2031
+ );
2032
+ if (primitiveWrapped !== null) {
2033
+ return [primitiveWrapped];
2034
+ }
2035
+ return [coerceBySchema(singleValue, itemsSchema)];
2036
+ }
2037
+ return null;
2038
+ }
1778
2039
  function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
1779
2040
  if (Object.hasOwn(maybe, "item")) {
1780
2041
  const items = maybe.item;
@@ -1786,15 +2047,23 @@ function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
1786
2047
  const arr = keys.sort((a, b) => Number(a) - Number(b)).map((k) => maybe[k]);
1787
2048
  return coerceArrayToArray(arr, prefixItems, itemsSchema);
1788
2049
  }
2050
+ const parallelArrays = coerceParallelArraysObjectToArray(
2051
+ maybe,
2052
+ prefixItems,
2053
+ itemsSchema
2054
+ );
2055
+ if (parallelArrays !== null) {
2056
+ return parallelArrays;
2057
+ }
1789
2058
  if (keys.length === 1) {
1790
2059
  const singleKey = keys[0];
1791
2060
  if (!(schemaIsUnconstrained(itemsSchema) || schemaHasProperty(itemsSchema, singleKey))) {
1792
- const singleValue = maybe[singleKey];
1793
- if (Array.isArray(singleValue)) {
1794
- return singleValue.map((v) => coerceBySchema(v, itemsSchema));
1795
- }
1796
- if (singleValue && typeof singleValue === "object") {
1797
- return [coerceBySchema(singleValue, itemsSchema)];
2061
+ const result = coerceSingleKeyObjectToArray(
2062
+ maybe[singleKey],
2063
+ itemsSchema
2064
+ );
2065
+ if (result !== null) {
2066
+ return result;
1798
2067
  }
1799
2068
  }
1800
2069
  }
@@ -1824,6 +2093,86 @@ function coerceStringToPrimitive(s, schemaType) {
1824
2093
  }
1825
2094
  return null;
1826
2095
  }
2096
+ function coercePrimitiveToString(value, schemaType) {
2097
+ if (schemaType !== "string") {
2098
+ return null;
2099
+ }
2100
+ if (typeof value === "boolean") {
2101
+ return value ? "true" : "false";
2102
+ }
2103
+ if (typeof value === "number" && Number.isFinite(value)) {
2104
+ return String(value);
2105
+ }
2106
+ return null;
2107
+ }
2108
+ function coerceStringByEnumWhitespace(rawValue, unwrapped) {
2109
+ const enumValues = unwrapped.enum;
2110
+ if (!Array.isArray(enumValues) || enumValues.length === 0) {
2111
+ return null;
2112
+ }
2113
+ if (!enumValues.every((item) => typeof item === "string")) {
2114
+ return null;
2115
+ }
2116
+ const normalizedEnumValues = enumValues;
2117
+ if (normalizedEnumValues.includes(rawValue)) {
2118
+ return null;
2119
+ }
2120
+ const unquoted = unwrapMatchingQuotes(rawValue);
2121
+ if (unquoted !== null) {
2122
+ const exactMatches = normalizedEnumValues.filter(
2123
+ (item) => item === unquoted
2124
+ );
2125
+ if (exactMatches.length === 1) {
2126
+ return exactMatches[0];
2127
+ }
2128
+ }
2129
+ const candidates = [rawValue, unquoted].filter(
2130
+ (item) => item !== null
2131
+ );
2132
+ for (const candidate of candidates) {
2133
+ if (!HAS_WHITESPACE_REGEX.test(candidate)) {
2134
+ continue;
2135
+ }
2136
+ const normalizedInput = candidate.replace(WHITESPACE_REGEX2, "");
2137
+ const matches = normalizedEnumValues.filter(
2138
+ (item) => item.replace(WHITESPACE_REGEX2, "") === normalizedInput
2139
+ );
2140
+ if (matches.length === 1) {
2141
+ return matches[0];
2142
+ }
2143
+ }
2144
+ return null;
2145
+ }
2146
+ function unwrapMatchingQuotes(value) {
2147
+ if (value.length < 2) {
2148
+ return null;
2149
+ }
2150
+ const first = value[0];
2151
+ const last = value.at(-1);
2152
+ const isQuote = (first === SINGLE_QUOTE || first === DOUBLE_QUOTE) && first === last;
2153
+ if (!isQuote) {
2154
+ return null;
2155
+ }
2156
+ return value.slice(1, -1);
2157
+ }
2158
+ function coerceObjectToPrimitive(value, schemaType, fullSchema) {
2159
+ if (!isPrimitiveSchemaType(schemaType)) {
2160
+ return null;
2161
+ }
2162
+ const keys = Object.keys(value);
2163
+ if (keys.length !== 1) {
2164
+ return null;
2165
+ }
2166
+ const singleValue = value[keys[0]];
2167
+ if (singleValue && typeof singleValue === "object") {
2168
+ return null;
2169
+ }
2170
+ const coerced = coerceBySchema(
2171
+ singleValue,
2172
+ fullSchema != null ? fullSchema : { type: schemaType }
2173
+ );
2174
+ return isPrimitiveMatchForSchemaType(coerced, schemaType) ? coerced : null;
2175
+ }
1827
2176
  function coerceStringValue(value, schemaType, u) {
1828
2177
  const s = value.trim();
1829
2178
  if (schemaType === "object") {
@@ -1842,6 +2191,10 @@ function coerceStringValue(value, schemaType, u) {
1842
2191
  if (primitiveResult !== null) {
1843
2192
  return primitiveResult;
1844
2193
  }
2194
+ const enumWhitespaceCanonical = coerceStringByEnumWhitespace(s, u);
2195
+ if (enumWhitespaceCanonical !== null) {
2196
+ return enumWhitespaceCanonical;
2197
+ }
1845
2198
  return value;
1846
2199
  }
1847
2200
  function coerceArrayValue(value, prefixItems, itemsSchema) {
@@ -1880,9 +2233,23 @@ function coerceBySchema(value, schema) {
1880
2233
  if (typeof value === "string") {
1881
2234
  return coerceStringValue(value, schemaType, u);
1882
2235
  }
2236
+ const primitiveString = coercePrimitiveToString(value, schemaType);
2237
+ if (primitiveString !== null) {
2238
+ return primitiveString;
2239
+ }
1883
2240
  if (schemaType === "object" && value && typeof value === "object" && !Array.isArray(value)) {
1884
2241
  return coerceObjectToObject(value, u);
1885
2242
  }
2243
+ if (value && typeof value === "object" && !Array.isArray(value) && isPrimitiveSchemaType(schemaType)) {
2244
+ const primitiveResult = coerceObjectToPrimitive(
2245
+ value,
2246
+ schemaType,
2247
+ u
2248
+ );
2249
+ if (primitiveResult !== null) {
2250
+ return primitiveResult;
2251
+ }
2252
+ }
1886
2253
  if (schemaType === "array") {
1887
2254
  const prefixItems = Array.isArray(u.prefixItems) ? u.prefixItems : void 0;
1888
2255
  const itemsSchema = u.items;
@@ -2897,7 +3264,7 @@ var XMLTokenizer = class {
2897
3264
  };
2898
3265
 
2899
3266
  // src/rxml/core/parser.ts
2900
- var WHITESPACE_REGEX2 = /\s/;
3267
+ var WHITESPACE_REGEX3 = /\s/;
2901
3268
  var NUMERIC_STRING_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
2902
3269
  var DIGIT_KEY_REGEX2 = /^\d+$/;
2903
3270
  function getTopLevelStringProps(s) {
@@ -3067,7 +3434,7 @@ function parse2(xmlInner, schema, options = {}) {
3067
3434
  const closeHead = s.indexOf(`</${rootName}`, range.end);
3068
3435
  if (closeHead === range.end) {
3069
3436
  let p = closeHead + 2 + rootName.length;
3070
- while (p < s.length && WHITESPACE_REGEX2.test(s[p])) {
3437
+ while (p < s.length && WHITESPACE_REGEX3.test(s[p])) {
3071
3438
  p += 1;
3072
3439
  }
3073
3440
  if (s[p] === ">") {
@@ -3405,7 +3772,7 @@ function createIntermediateCall(toolName, rawSegment, schema) {
3405
3772
  var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
3406
3773
  var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
3407
3774
  var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
3408
- var WHITESPACE_REGEX3 = /\s/;
3775
+ var WHITESPACE_REGEX4 = /\s/;
3409
3776
  var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
3410
3777
  var NAME_START_CHAR_RE = /[A-Za-z_:]/;
3411
3778
  var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
@@ -3546,7 +3913,7 @@ function balanceTags(xml) {
3546
3913
  }
3547
3914
  function skipWs(s, p, len) {
3548
3915
  let idx = p;
3549
- while (idx < len && WHITESPACE_REGEX3.test(s[idx])) {
3916
+ while (idx < len && WHITESPACE_REGEX4.test(s[idx])) {
3550
3917
  idx += 1;
3551
3918
  }
3552
3919
  return idx;
@@ -3599,7 +3966,7 @@ function handleOpeningTagSegment(src, lt, out, stack) {
3599
3966
  return len;
3600
3967
  }
3601
3968
  let r = q - 1;
3602
- while (r >= nameStart && WHITESPACE_REGEX3.test(src[r])) {
3969
+ while (r >= nameStart && WHITESPACE_REGEX4.test(src[r])) {
3603
3970
  r -= 1;
3604
3971
  }
3605
3972
  const selfClosing = src[r] === "/";
@@ -3642,12 +4009,9 @@ function getStringPropertyNames(schema) {
3642
4009
  }
3643
4010
  return names;
3644
4011
  }
3645
- function escapeRegExp2(s) {
3646
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3647
- }
3648
4012
  function dedupeSingleTag(xml, key) {
3649
4013
  var _a, _b;
3650
- const escaped = escapeRegExp2(key);
4014
+ const escaped = escapeRegExp(key);
3651
4015
  const re = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
3652
4016
  const matches = Array.from(xml.matchAll(re));
3653
4017
  if (matches.length <= 1) {
@@ -3764,9 +4128,35 @@ function parse3(xml, schema, options = {}) {
3764
4128
  throw new RXMLParseError("Failed to parse XML with repair heuristics", error);
3765
4129
  }
3766
4130
 
3767
- // src/core/protocols/xml-protocol.ts
4131
+ // src/core/utils/regex-constants.ts
3768
4132
  var NAME_CHAR_RE2 = /[A-Za-z0-9_:-]/;
3769
- var WHITESPACE_REGEX4 = /\s/;
4133
+ var WHITESPACE_REGEX5 = /\s/;
4134
+
4135
+ // src/core/utils/xml-root-repair.ts
4136
+ var XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX = /^<([A-Za-z_][A-Za-z0-9_-]*)\s*\r?\n([\s\S]+?)\r?\n\s*\/>\s*$/;
4137
+ function tryRepairXmlSelfClosingRootWithBody(rawText, toolNames) {
4138
+ const trimmed = rawText.trim();
4139
+ if (trimmed.length === 0) {
4140
+ return null;
4141
+ }
4142
+ const match = trimmed.match(XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX);
4143
+ if (!match) {
4144
+ return null;
4145
+ }
4146
+ const rootTag = match[1];
4147
+ if (!toolNames.includes(rootTag)) {
4148
+ return null;
4149
+ }
4150
+ const body = match[2].trimEnd();
4151
+ if (body.trim().length === 0 || body.includes(`</${rootTag}>`)) {
4152
+ return null;
4153
+ }
4154
+ return `<${rootTag}>
4155
+ ${body}
4156
+ </${rootTag}>`;
4157
+ }
4158
+
4159
+ // src/core/protocols/xml-protocol.ts
3770
4160
  function getToolSchema(tools, toolName) {
3771
4161
  var _a;
3772
4162
  return (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
@@ -3868,7 +4258,7 @@ function consumeClosingTag(text, lt) {
3868
4258
  }
3869
4259
  function consumeOpenTag(text, lt) {
3870
4260
  let p = lt + 1;
3871
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
4261
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3872
4262
  p += 1;
3873
4263
  }
3874
4264
  const nameStart = p;
@@ -3881,7 +4271,7 @@ function consumeOpenTag(text, lt) {
3881
4271
  return null;
3882
4272
  }
3883
4273
  let r = q - 1;
3884
- while (r >= nameStart && WHITESPACE_REGEX4.test(text[r])) {
4274
+ while (r >= nameStart && WHITESPACE_REGEX5.test(text[r])) {
3885
4275
  r -= 1;
3886
4276
  }
3887
4277
  const selfClosing = text[r] === "/";
@@ -3910,7 +4300,7 @@ function nextTagToken(text, fromPos) {
3910
4300
  if (next === "/") {
3911
4301
  const closing = consumeClosingTag(text, lt);
3912
4302
  let p = lt + 2;
3913
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
4303
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3914
4304
  p += 1;
3915
4305
  }
3916
4306
  const nameStart = p;
@@ -4047,6 +4437,102 @@ function findToolCalls(text, toolNames) {
4047
4437
  }
4048
4438
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
4049
4439
  }
4440
+ function handleSpecialToken(depth) {
4441
+ return { depth, lastCompleteEnd: -1, shouldBreak: false };
4442
+ }
4443
+ function handleOpenToken(token, depth, lastCompleteEnd) {
4444
+ if (token.selfClosing) {
4445
+ return {
4446
+ depth,
4447
+ lastCompleteEnd: depth === 0 ? token.nextPos : lastCompleteEnd,
4448
+ shouldBreak: false
4449
+ };
4450
+ }
4451
+ return { depth: depth + 1, lastCompleteEnd, shouldBreak: false };
4452
+ }
4453
+ function handleCloseToken(token, depth) {
4454
+ if (depth <= 0) {
4455
+ return { depth, lastCompleteEnd: -1, shouldBreak: true };
4456
+ }
4457
+ const newDepth = depth - 1;
4458
+ return {
4459
+ depth: newDepth,
4460
+ lastCompleteEnd: newDepth === 0 ? token.nextPos : -1,
4461
+ shouldBreak: false
4462
+ };
4463
+ }
4464
+ function findLinePrefixedXmlBodyEnd(text, bodyStartIndex) {
4465
+ let cursor = bodyStartIndex;
4466
+ let depth = 0;
4467
+ let lastCompleteEnd = -1;
4468
+ while (cursor < text.length) {
4469
+ if (depth === 0) {
4470
+ cursor = consumeWhitespace(text, cursor);
4471
+ if (cursor >= text.length || text.charAt(cursor) !== "<") {
4472
+ break;
4473
+ }
4474
+ }
4475
+ const token = nextTagToken(text, cursor);
4476
+ if (token.kind === "eof") {
4477
+ break;
4478
+ }
4479
+ let result;
4480
+ if (token.kind === "special") {
4481
+ result = handleSpecialToken(depth);
4482
+ } else if (token.kind === "open") {
4483
+ result = handleOpenToken(token, depth, lastCompleteEnd);
4484
+ } else {
4485
+ result = handleCloseToken(token, depth);
4486
+ }
4487
+ depth = result.depth;
4488
+ if (result.lastCompleteEnd !== -1) {
4489
+ lastCompleteEnd = result.lastCompleteEnd;
4490
+ }
4491
+ if (result.shouldBreak) {
4492
+ break;
4493
+ }
4494
+ cursor = token.nextPos;
4495
+ }
4496
+ return lastCompleteEnd;
4497
+ }
4498
+ function findLinePrefixedToolCall(text, toolNames) {
4499
+ var _a;
4500
+ let best = null;
4501
+ for (const toolName of toolNames) {
4502
+ const linePattern = new RegExp(
4503
+ `(^|\\n)[\\t ]*${escapeRegExp(toolName)}[\\t ]*:?[\\t ]*(?:\\r?\\n|$)`,
4504
+ "g"
4505
+ );
4506
+ let match = linePattern.exec(text);
4507
+ while (match !== null) {
4508
+ const prefix = (_a = match[1]) != null ? _a : "";
4509
+ const startIndex = match.index + prefix.length;
4510
+ const contentStart = consumeWhitespace(text, linePattern.lastIndex);
4511
+ if (contentStart >= text.length || text.charAt(contentStart) !== "<") {
4512
+ match = linePattern.exec(text);
4513
+ continue;
4514
+ }
4515
+ const contentEnd = findLinePrefixedXmlBodyEnd(text, contentStart);
4516
+ if (contentEnd === -1 || contentEnd <= contentStart) {
4517
+ match = linePattern.exec(text);
4518
+ continue;
4519
+ }
4520
+ const content = text.slice(contentStart, contentEnd);
4521
+ const candidate = {
4522
+ toolName,
4523
+ startIndex,
4524
+ endIndex: contentEnd,
4525
+ content,
4526
+ segment: text.slice(startIndex, contentEnd)
4527
+ };
4528
+ if (best === null || candidate.startIndex < best.startIndex) {
4529
+ best = candidate;
4530
+ }
4531
+ break;
4532
+ }
4533
+ }
4534
+ return best;
4535
+ }
4050
4536
  function findEarliestToolTag(buffer, toolNames) {
4051
4537
  var _a, _b;
4052
4538
  let bestIndex = -1;
@@ -4085,7 +4571,7 @@ function isOpenTagPrefix(suffix, toolName) {
4085
4571
  }
4086
4572
  function consumeWhitespace(text, index) {
4087
4573
  let i = index;
4088
- while (i < text.length && WHITESPACE_REGEX4.test(text.charAt(i))) {
4574
+ while (i < text.length && WHITESPACE_REGEX5.test(text.charAt(i))) {
4089
4575
  i += 1;
4090
4576
  }
4091
4577
  return i;
@@ -4336,6 +4822,27 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
4336
4822
  }
4337
4823
  };
4338
4824
  }
4825
+ function findToolCallsWithFallbacks(text, toolNames) {
4826
+ let parseText = text;
4827
+ let toolCalls = findToolCalls(parseText, toolNames);
4828
+ if (toolCalls.length === 0) {
4829
+ const fallbackToolCall = findLinePrefixedToolCall(parseText, toolNames);
4830
+ if (fallbackToolCall !== null) {
4831
+ toolCalls.push(fallbackToolCall);
4832
+ }
4833
+ }
4834
+ if (toolCalls.length === 0) {
4835
+ const repaired = tryRepairXmlSelfClosingRootWithBody(parseText, toolNames);
4836
+ if (repaired) {
4837
+ const repairedCalls = findToolCalls(repaired, toolNames);
4838
+ if (repairedCalls.length > 0) {
4839
+ parseText = repaired;
4840
+ toolCalls = repairedCalls;
4841
+ }
4842
+ }
4843
+ }
4844
+ return { parseText, toolCalls };
4845
+ }
4339
4846
  var xmlProtocol = (protocolOptions) => {
4340
4847
  var _a;
4341
4848
  const parseOptions = {
@@ -4369,28 +4876,31 @@ var xmlProtocol = (protocolOptions) => {
4369
4876
  }
4370
4877
  const processedElements = [];
4371
4878
  let currentIndex = 0;
4372
- const toolCalls = findToolCalls(text, toolNames);
4879
+ const { parseText, toolCalls } = findToolCallsWithFallbacks(
4880
+ text,
4881
+ toolNames
4882
+ );
4373
4883
  for (const tc of toolCalls) {
4374
4884
  if (tc.startIndex > currentIndex) {
4375
4885
  processedElements.push({
4376
4886
  type: "text",
4377
- text: text.substring(currentIndex, tc.startIndex)
4887
+ text: parseText.substring(currentIndex, tc.startIndex)
4378
4888
  });
4379
4889
  }
4380
4890
  processToolCall({
4381
4891
  toolCall: tc,
4382
4892
  tools,
4383
4893
  options,
4384
- text,
4894
+ text: parseText,
4385
4895
  processedElements,
4386
4896
  parseOptions
4387
4897
  });
4388
4898
  currentIndex = tc.endIndex;
4389
4899
  }
4390
- if (currentIndex < text.length) {
4900
+ if (currentIndex < parseText.length) {
4391
4901
  processedElements.push({
4392
4902
  type: "text",
4393
- text: text.substring(currentIndex)
4903
+ text: parseText.substring(currentIndex)
4394
4904
  });
4395
4905
  }
4396
4906
  return processedElements;
@@ -4429,6 +4939,20 @@ var xmlProtocol = (protocolOptions) => {
4429
4939
  return new TransformStream({
4430
4940
  transform(chunk, controller) {
4431
4941
  var _a2;
4942
+ if (chunk.type === "finish") {
4943
+ if (currentToolCall) {
4944
+ const unfinishedContent = `<${currentToolCall.name}>${currentToolCall.content}${buffer}`;
4945
+ flushText(controller, unfinishedContent);
4946
+ buffer = "";
4947
+ currentToolCall = null;
4948
+ } else if (buffer) {
4949
+ flushText(controller, buffer);
4950
+ buffer = "";
4951
+ }
4952
+ flushText(controller);
4953
+ controller.enqueue(chunk);
4954
+ return;
4955
+ }
4432
4956
  if (chunk.type !== "text-delta") {
4433
4957
  if (buffer) {
4434
4958
  flushText(controller, buffer);
@@ -4474,8 +4998,6 @@ var xmlProtocol = (protocolOptions) => {
4474
4998
 
4475
4999
  // src/core/protocols/yaml-protocol.ts
4476
5000
  var import_yaml = __toESM(require("yaml"), 1);
4477
- var NAME_CHAR_RE3 = /[A-Za-z0-9_:-]/;
4478
- var WHITESPACE_REGEX5 = /\s/;
4479
5001
  var LEADING_WHITESPACE_RE = /^(\s*)/;
4480
5002
  function findClosingTagEnd(text, contentStart, toolName) {
4481
5003
  let pos = contentStart;
@@ -4496,7 +5018,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4496
5018
  p++;
4497
5019
  }
4498
5020
  const nameStart = p;
4499
- while (p < gtIdx && NAME_CHAR_RE3.test(text.charAt(p))) {
5021
+ while (p < gtIdx && NAME_CHAR_RE2.test(text.charAt(p))) {
4500
5022
  p++;
4501
5023
  }
4502
5024
  const name = text.slice(nameStart, p);
@@ -4516,7 +5038,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4516
5038
  p++;
4517
5039
  }
4518
5040
  const nameStart = p;
4519
- while (p < text.length && NAME_CHAR_RE3.test(text.charAt(p))) {
5041
+ while (p < text.length && NAME_CHAR_RE2.test(text.charAt(p))) {
4520
5042
  p++;
4521
5043
  }
4522
5044
  const name = text.slice(nameStart, p);
@@ -4643,22 +5165,14 @@ function parseYamlContent(yamlContent, options) {
4643
5165
  return null;
4644
5166
  }
4645
5167
  }
4646
- function appendTextPart(processedElements, textPart) {
4647
- if (textPart.trim()) {
4648
- processedElements.push({
4649
- type: "text",
4650
- text: textPart
4651
- });
4652
- }
4653
- }
4654
5168
  function processToolCallMatch(text, tc, currentIndex, processedElements, options) {
4655
5169
  var _a;
4656
5170
  if (tc.startIndex < currentIndex) {
4657
5171
  return currentIndex;
4658
5172
  }
4659
- appendTextPart(
4660
- processedElements,
4661
- text.substring(currentIndex, tc.startIndex)
5173
+ addTextSegment(
5174
+ text.substring(currentIndex, tc.startIndex),
5175
+ processedElements
4662
5176
  );
4663
5177
  const parsedArgs = parseYamlContent(tc.content, options);
4664
5178
  if (parsedArgs !== null) {
@@ -4765,18 +5279,32 @@ ${yamlContent}</${toolCall.toolName}>`;
4765
5279
  }
4766
5280
  const processedElements = [];
4767
5281
  let currentIndex = 0;
4768
- const toolCalls = findToolCalls2(text, toolNames);
5282
+ let parseText = text;
5283
+ let toolCalls = findToolCalls2(parseText, toolNames);
5284
+ if (toolCalls.length === 0) {
5285
+ const repaired = tryRepairXmlSelfClosingRootWithBody(
5286
+ parseText,
5287
+ toolNames
5288
+ );
5289
+ if (repaired) {
5290
+ const repairedCalls = findToolCalls2(repaired, toolNames);
5291
+ if (repairedCalls.length > 0) {
5292
+ parseText = repaired;
5293
+ toolCalls = repairedCalls;
5294
+ }
5295
+ }
5296
+ }
4769
5297
  for (const tc of toolCalls) {
4770
5298
  currentIndex = processToolCallMatch(
4771
- text,
5299
+ parseText,
4772
5300
  tc,
4773
5301
  currentIndex,
4774
5302
  processedElements,
4775
5303
  options
4776
5304
  );
4777
5305
  }
4778
- if (currentIndex < text.length) {
4779
- appendTextPart(processedElements, text.substring(currentIndex));
5306
+ if (currentIndex < parseText.length) {
5307
+ addTextSegment(parseText.substring(currentIndex), processedElements);
4780
5308
  }
4781
5309
  return processedElements;
4782
5310
  },
@@ -4872,6 +5400,20 @@ ${yamlContent}</${toolCall.toolName}>`;
4872
5400
  return new TransformStream({
4873
5401
  transform(chunk, controller) {
4874
5402
  var _a;
5403
+ if (chunk.type === "finish") {
5404
+ if (currentToolCall) {
5405
+ const unfinishedContent = `<${currentToolCall.name}>${buffer}`;
5406
+ flushText(controller, unfinishedContent);
5407
+ buffer = "";
5408
+ currentToolCall = null;
5409
+ } else if (buffer) {
5410
+ flushText(controller, buffer);
5411
+ buffer = "";
5412
+ }
5413
+ flushText(controller);
5414
+ controller.enqueue(chunk);
5415
+ return;
5416
+ }
4875
5417
  if (chunk.type !== "text-delta") {
4876
5418
  if (buffer) {
4877
5419
  flushText(controller, buffer);
@@ -4995,17 +5537,56 @@ function encodeOriginalTools(tools) {
4995
5537
  inputSchema: JSON.stringify(t.inputSchema)
4996
5538
  }))) || [];
4997
5539
  }
4998
- function decodeOriginalTools(originalTools) {
5540
+ function decodeOriginalTools(originalTools, options) {
5541
+ var _a, _b, _c;
4999
5542
  if (!originalTools) {
5000
5543
  return [];
5001
5544
  }
5002
- return originalTools.map(
5003
- (t) => ({
5004
- type: "function",
5005
- name: t.name,
5006
- inputSchema: JSON.parse(t.inputSchema)
5007
- })
5008
- );
5545
+ const decodedTools = [];
5546
+ for (const [index, tool] of originalTools.entries()) {
5547
+ if (!tool || typeof tool.name !== "string") {
5548
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Invalid originalTools entry: missing tool name", {
5549
+ index,
5550
+ tool
5551
+ });
5552
+ continue;
5553
+ }
5554
+ if (typeof tool.inputSchema !== "string") {
5555
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5556
+ options,
5557
+ "Invalid originalTools entry: inputSchema must be a string",
5558
+ {
5559
+ index,
5560
+ toolName: tool.name
5561
+ }
5562
+ );
5563
+ continue;
5564
+ }
5565
+ try {
5566
+ decodedTools.push({
5567
+ type: "function",
5568
+ name: tool.name,
5569
+ inputSchema: JSON.parse(tool.inputSchema)
5570
+ });
5571
+ } catch (error) {
5572
+ (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(
5573
+ options,
5574
+ "Failed to decode originalTools input schema, using permissive fallback schema",
5575
+ {
5576
+ index,
5577
+ toolName: tool.name,
5578
+ inputSchema: tool.inputSchema,
5579
+ error: error instanceof Error ? error.message : String(error)
5580
+ }
5581
+ );
5582
+ decodedTools.push({
5583
+ type: "function",
5584
+ name: tool.name,
5585
+ inputSchema: { type: "object" }
5586
+ });
5587
+ }
5588
+ }
5589
+ return decodedTools;
5009
5590
  }
5010
5591
  function isToolChoiceActive(params) {
5011
5592
  var _a, _b, _c;
@@ -5015,23 +5596,337 @@ function isToolChoiceActive(params) {
5015
5596
 
5016
5597
  // src/generate-handler.ts
5017
5598
  var import_provider_utils = require("@ai-sdk/provider-utils");
5018
- function parseToolChoiceJson(text, providerOptions) {
5599
+
5600
+ // src/core/utils/generated-text-json-recovery.ts
5601
+ function isRecord(value) {
5602
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5603
+ }
5604
+ function safeStringify2(value) {
5605
+ try {
5606
+ return JSON.stringify(value != null ? value : {});
5607
+ } catch (e) {
5608
+ return "{}";
5609
+ }
5610
+ }
5611
+ function parseJsonCandidate(candidateText) {
5612
+ try {
5613
+ return parse(candidateText);
5614
+ } catch (e) {
5615
+ return void 0;
5616
+ }
5617
+ }
5618
+ function extractCodeBlockCandidates(text) {
5619
+ var _a, _b;
5620
+ const codeBlockRegex = /```(?:json|yaml|xml)?\s*([\s\S]*?)```/gi;
5621
+ const candidates = [];
5622
+ let match;
5623
+ while (true) {
5624
+ match = codeBlockRegex.exec(text);
5625
+ if (!match) {
5626
+ break;
5627
+ }
5628
+ const body = (_a = match[1]) == null ? void 0 : _a.trim();
5629
+ if (body) {
5630
+ const startIndex = (_b = match.index) != null ? _b : 0;
5631
+ const endIndex = startIndex + match[0].length;
5632
+ candidates.push({
5633
+ text: body,
5634
+ startIndex,
5635
+ endIndex
5636
+ });
5637
+ }
5638
+ }
5639
+ return candidates;
5640
+ }
5641
+ function scanJsonChar(state, char) {
5642
+ if (state.inString) {
5643
+ if (state.escaping) {
5644
+ return { ...state, escaping: false };
5645
+ }
5646
+ if (char === "\\") {
5647
+ return { ...state, escaping: true };
5648
+ }
5649
+ if (char === '"') {
5650
+ return { ...state, inString: false };
5651
+ }
5652
+ return state;
5653
+ }
5654
+ if (char === '"') {
5655
+ return { ...state, inString: true };
5656
+ }
5657
+ if (char === "{") {
5658
+ return { ...state, depth: state.depth + 1 };
5659
+ }
5660
+ if (char === "}") {
5661
+ return { ...state, depth: Math.max(0, state.depth - 1) };
5662
+ }
5663
+ return state;
5664
+ }
5665
+ function extractBalancedJsonObjects(text) {
5666
+ const maxCandidateLength = 1e4;
5667
+ const candidates = [];
5668
+ let state = { depth: 0, inString: false, escaping: false };
5669
+ let currentStart = null;
5670
+ let ignoreCurrent = false;
5671
+ for (let index = 0; index < text.length; index += 1) {
5672
+ const char = text[index];
5673
+ if (!state.inString && char === "{" && state.depth === 0) {
5674
+ currentStart = index;
5675
+ ignoreCurrent = false;
5676
+ }
5677
+ state = scanJsonChar(state, char);
5678
+ if (currentStart !== null && !ignoreCurrent && index - currentStart + 1 > maxCandidateLength) {
5679
+ ignoreCurrent = true;
5680
+ }
5681
+ if (!state.inString && char === "}" && state.depth === 0) {
5682
+ if (currentStart !== null && !ignoreCurrent) {
5683
+ const endIndex = index + 1;
5684
+ const candidate = text.slice(currentStart, endIndex);
5685
+ if (candidate.length > 1) {
5686
+ candidates.push({
5687
+ text: candidate,
5688
+ startIndex: currentStart,
5689
+ endIndex
5690
+ });
5691
+ }
5692
+ }
5693
+ currentStart = null;
5694
+ ignoreCurrent = false;
5695
+ }
5696
+ }
5697
+ return candidates;
5698
+ }
5699
+ function extractTaggedToolCallCandidates(rawText) {
5700
+ var _a, _b;
5701
+ const toolCallRegex = /<tool_call>([\s\S]*?)<\/tool_call>/gi;
5702
+ const candidates = [];
5703
+ let match;
5704
+ while (true) {
5705
+ match = toolCallRegex.exec(rawText);
5706
+ if (!match) {
5707
+ break;
5708
+ }
5709
+ const body = (_a = match[1]) == null ? void 0 : _a.trim();
5710
+ if (!body) {
5711
+ continue;
5712
+ }
5713
+ const startIndex = (_b = match.index) != null ? _b : 0;
5714
+ const endIndex = startIndex + match[0].length;
5715
+ candidates.push({
5716
+ text: body,
5717
+ startIndex,
5718
+ endIndex
5719
+ });
5720
+ }
5721
+ return candidates;
5722
+ }
5723
+ function extractJsonLikeCandidates(rawText) {
5724
+ return mergeJsonCandidatesByStart(
5725
+ extractTaggedToolCallCandidates(rawText),
5726
+ extractCodeBlockCandidates(rawText),
5727
+ extractBalancedJsonObjects(rawText)
5728
+ );
5729
+ }
5730
+ function mergeJsonCandidatesByStart(tagged, codeBlocks, balanced) {
5731
+ return [...tagged, ...codeBlocks, ...balanced].sort(
5732
+ (a, b) => a.startIndex !== b.startIndex ? a.startIndex - b.startIndex : b.endIndex - a.endIndex
5733
+ );
5734
+ }
5735
+ function toToolCallPart(candidate) {
5736
+ return {
5737
+ type: "tool-call",
5738
+ toolCallId: generateId(),
5739
+ toolName: candidate.toolName,
5740
+ input: candidate.input
5741
+ };
5742
+ }
5743
+ function toRecoveredParts(text, candidate, toolCallPart) {
5744
+ const out = [];
5745
+ const prefix = text.slice(0, candidate.startIndex);
5746
+ if (prefix.length > 0) {
5747
+ out.push({ type: "text", text: prefix });
5748
+ }
5749
+ out.push(toolCallPart);
5750
+ const suffix = text.slice(candidate.endIndex);
5751
+ if (suffix.length > 0) {
5752
+ out.push({ type: "text", text: suffix });
5753
+ }
5754
+ return out;
5755
+ }
5756
+ function parseAsToolPayload(payload, tools) {
5757
+ if (!isRecord(payload)) {
5758
+ return null;
5759
+ }
5760
+ const toolName = typeof payload.name === "string" && payload.name.trim().length > 0 ? payload.name.trim() : null;
5761
+ if (!toolName) {
5762
+ return null;
5763
+ }
5764
+ if (!tools.some((tool) => tool.name === toolName)) {
5765
+ return null;
5766
+ }
5767
+ const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
5768
+ if (!isRecord(rawArgs)) {
5769
+ return null;
5770
+ }
5771
+ return {
5772
+ toolName,
5773
+ input: safeStringify2(rawArgs)
5774
+ };
5775
+ }
5776
+ function isLikelyArgumentsShapeForTool(args, tool) {
5777
+ const unwrapped = unwrapJsonSchema(tool.inputSchema);
5778
+ if (!isRecord(unwrapped)) {
5779
+ return false;
5780
+ }
5781
+ if (getSchemaType(unwrapped) !== "object") {
5782
+ return false;
5783
+ }
5784
+ const properties = unwrapped.properties;
5785
+ if (!isRecord(properties)) {
5786
+ return false;
5787
+ }
5788
+ const keys = Object.keys(args);
5789
+ if (keys.length === 0) {
5790
+ return false;
5791
+ }
5792
+ const knownKeys = keys.filter((key) => Object.hasOwn(properties, key));
5793
+ if (knownKeys.length === 0) {
5794
+ return false;
5795
+ }
5796
+ if (unwrapped.additionalProperties === false && knownKeys.length !== keys.length) {
5797
+ return false;
5798
+ }
5799
+ return true;
5800
+ }
5801
+ function parseAsArgumentsOnly(payload, tools) {
5802
+ if (tools.length !== 1) {
5803
+ return null;
5804
+ }
5805
+ if (!isRecord(payload)) {
5806
+ return null;
5807
+ }
5808
+ const hasNameEnvelope = Object.hasOwn(payload, "name") && typeof payload.name === "string" && payload.name.length > 0;
5809
+ const hasArgumentsEnvelope = Object.hasOwn(payload, "arguments") && (typeof payload.arguments === "string" || isRecord(payload.arguments));
5810
+ if (hasNameEnvelope || hasArgumentsEnvelope) {
5811
+ return null;
5812
+ }
5813
+ const tool = tools[0];
5814
+ if (!isLikelyArgumentsShapeForTool(payload, tool)) {
5815
+ return null;
5816
+ }
5817
+ return {
5818
+ toolName: tool.name,
5819
+ input: safeStringify2(payload)
5820
+ };
5821
+ }
5822
+ function recoverToolCallFromJsonCandidates(text, tools) {
5823
+ if (tools.length === 0) {
5824
+ return null;
5825
+ }
5826
+ const jsonCandidates = extractJsonLikeCandidates(text);
5827
+ for (const jsonCandidate of jsonCandidates) {
5828
+ const parsed = parseJsonCandidate(jsonCandidate.text);
5829
+ if (parsed === void 0) {
5830
+ continue;
5831
+ }
5832
+ const toolPayload = parseAsToolPayload(parsed, tools);
5833
+ if (toolPayload) {
5834
+ return toRecoveredParts(text, jsonCandidate, toToolCallPart(toolPayload));
5835
+ }
5836
+ const argsPayload = parseAsArgumentsOnly(parsed, tools);
5837
+ if (argsPayload) {
5838
+ return toRecoveredParts(text, jsonCandidate, toToolCallPart(argsPayload));
5839
+ }
5840
+ }
5841
+ return null;
5842
+ }
5843
+
5844
+ // src/core/utils/tool-call-coercion.ts
5845
+ function coerceToolCallInput(toolName, input, tools) {
5019
5846
  var _a;
5847
+ let args = {};
5848
+ if (typeof input === "string") {
5849
+ try {
5850
+ args = JSON.parse(input);
5851
+ } catch (e) {
5852
+ return;
5853
+ }
5854
+ } else if (input && typeof input === "object") {
5855
+ args = input;
5856
+ } else {
5857
+ return;
5858
+ }
5859
+ const schema = (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
5860
+ const coerced = coerceBySchema(args, schema);
5861
+ return JSON.stringify(coerced != null ? coerced : {});
5862
+ }
5863
+ function coerceToolCallPart(part, tools) {
5864
+ const coercedInput = coerceToolCallInput(part.toolName, part.input, tools);
5865
+ if (coercedInput === void 0) {
5866
+ return part;
5867
+ }
5868
+ return {
5869
+ ...part,
5870
+ input: coercedInput
5871
+ };
5872
+ }
5873
+
5874
+ // src/core/utils/tool-choice.ts
5875
+ function ensureNonEmptyToolName(name) {
5876
+ if (typeof name !== "string") {
5877
+ return "unknown";
5878
+ }
5879
+ const trimmed = name.trim();
5880
+ return trimmed.length > 0 ? trimmed : "unknown";
5881
+ }
5882
+ function safeStringify3(value) {
5883
+ try {
5884
+ return JSON.stringify(value != null ? value : {});
5885
+ } catch (e) {
5886
+ return "{}";
5887
+ }
5888
+ }
5889
+ function parseToolChoicePayload({
5890
+ text,
5891
+ tools,
5892
+ onError,
5893
+ errorMessage
5894
+ }) {
5895
+ let parsed;
5020
5896
  try {
5021
- return JSON.parse(text);
5897
+ parsed = JSON.parse(text);
5022
5898
  } catch (error) {
5023
- const options = extractOnErrorOption(providerOptions);
5024
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
5025
- options,
5026
- "Failed to parse toolChoice JSON from generated model output",
5027
- {
5028
- text,
5029
- error: error instanceof Error ? error.message : String(error)
5030
- }
5031
- );
5032
- return {};
5899
+ onError == null ? void 0 : onError(errorMessage, {
5900
+ text,
5901
+ error: error instanceof Error ? error.message : String(error)
5902
+ });
5903
+ return { toolName: "unknown", input: "{}" };
5033
5904
  }
5905
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
5906
+ onError == null ? void 0 : onError("toolChoice JSON payload must be an object", {
5907
+ parsedType: typeof parsed,
5908
+ parsed
5909
+ });
5910
+ return { toolName: "unknown", input: "{}" };
5911
+ }
5912
+ const payload = parsed;
5913
+ const toolName = ensureNonEmptyToolName(payload.name);
5914
+ const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
5915
+ if (rawArgs == null || typeof rawArgs !== "object" || Array.isArray(rawArgs)) {
5916
+ onError == null ? void 0 : onError("toolChoice arguments must be a JSON object", {
5917
+ toolName,
5918
+ arguments: rawArgs
5919
+ });
5920
+ return { toolName, input: "{}" };
5921
+ }
5922
+ const coercedInput = coerceToolCallInput(toolName, rawArgs, tools);
5923
+ return {
5924
+ toolName,
5925
+ input: coercedInput != null ? coercedInput : safeStringify3(rawArgs)
5926
+ };
5034
5927
  }
5928
+
5929
+ // src/generate-handler.ts
5035
5930
  function logDebugSummary(debugSummary, toolCall, originText) {
5036
5931
  if (debugSummary) {
5037
5932
  debugSummary.originalText = originText;
@@ -5045,25 +5940,34 @@ function logDebugSummary(debugSummary, toolCall, originText) {
5045
5940
  logParsedSummary({ toolCalls: [toolCall], originalText: originText });
5046
5941
  }
5047
5942
  }
5048
- async function handleToolChoice(doGenerate, params) {
5049
- var _a, _b, _c;
5943
+ async function handleToolChoice(doGenerate, params, tools) {
5944
+ var _a, _b, _c, _d;
5050
5945
  const result = await doGenerate();
5051
5946
  const first = (_a = result.content) == null ? void 0 : _a[0];
5052
- let parsed = {};
5947
+ const onError = (_b = extractOnErrorOption(params.providerOptions)) == null ? void 0 : _b.onError;
5948
+ let toolName = "unknown";
5949
+ let input = "{}";
5053
5950
  if (first && first.type === "text") {
5054
5951
  if (getDebugLevel() === "parse") {
5055
5952
  logRawChunk(first.text);
5056
5953
  }
5057
- parsed = parseToolChoiceJson(first.text, params.providerOptions);
5954
+ const parsed = parseToolChoicePayload({
5955
+ text: first.text,
5956
+ tools,
5957
+ onError,
5958
+ errorMessage: "Failed to parse toolChoice JSON from generated model output"
5959
+ });
5960
+ toolName = parsed.toolName;
5961
+ input = parsed.input;
5058
5962
  }
5059
5963
  const toolCall = {
5060
5964
  type: "tool-call",
5061
5965
  toolCallId: (0, import_provider_utils.generateId)(),
5062
- toolName: parsed.name || "unknown",
5063
- input: JSON.stringify(parsed.arguments || {})
5966
+ toolName,
5967
+ input
5064
5968
  };
5065
5969
  const originText = first && first.type === "text" ? first.text : "";
5066
- const debugSummary = (_c = (_b = params.providerOptions) == null ? void 0 : _b.toolCallMiddleware) == null ? void 0 : _c.debugSummary;
5970
+ const debugSummary = (_d = (_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) == null ? void 0 : _d.debugSummary;
5067
5971
  logDebugSummary(debugSummary, toolCall, originText);
5068
5972
  return {
5069
5973
  ...result,
@@ -5078,7 +5982,7 @@ function parseContent(content, protocol, tools, providerOptions) {
5078
5982
  if (getDebugLevel() === "stream") {
5079
5983
  logRawChunk(contentItem.text);
5080
5984
  }
5081
- return protocol.parseGeneratedText({
5985
+ const parsedByProtocol = protocol.parseGeneratedText({
5082
5986
  text: contentItem.text,
5083
5987
  tools,
5084
5988
  options: {
@@ -5086,9 +5990,20 @@ function parseContent(content, protocol, tools, providerOptions) {
5086
5990
  ...providerOptions == null ? void 0 : providerOptions.toolCallMiddleware
5087
5991
  }
5088
5992
  });
5993
+ const hasToolCall = parsedByProtocol.some(
5994
+ (part) => part.type === "tool-call"
5995
+ );
5996
+ if (hasToolCall) {
5997
+ return parsedByProtocol;
5998
+ }
5999
+ const recoveredFromJson = recoverToolCallFromJsonCandidates(
6000
+ contentItem.text,
6001
+ tools
6002
+ );
6003
+ return recoveredFromJson != null ? recoveredFromJson : parsedByProtocol;
5089
6004
  });
5090
6005
  return parsed.map(
5091
- (part) => fixToolCallWithSchema(part, tools)
6006
+ (part) => part.type === "tool-call" ? coerceToolCallPart(part, tools) : part
5092
6007
  );
5093
6008
  }
5094
6009
  function logParsedContent(content) {
@@ -5131,12 +6046,14 @@ async function wrapGenerate({
5131
6046
  params
5132
6047
  }) {
5133
6048
  var _a, _b;
5134
- if (isToolChoiceActive(params)) {
5135
- return handleToolChoice(doGenerate, params);
5136
- }
6049
+ const onError = extractOnErrorOption(params.providerOptions);
5137
6050
  const tools = originalToolsSchema.decode(
5138
- (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
6051
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
6052
+ onError
5139
6053
  );
6054
+ if (isToolChoiceActive(params)) {
6055
+ return handleToolChoice(doGenerate, params, tools);
6056
+ }
5140
6057
  const result = await doGenerate();
5141
6058
  if (result.content.length === 0) {
5142
6059
  return result;
@@ -5160,28 +6077,6 @@ async function wrapGenerate({
5160
6077
  content: newContent
5161
6078
  };
5162
6079
  }
5163
- function fixToolCallWithSchema(part, tools) {
5164
- var _a;
5165
- if (part.type !== "tool-call") {
5166
- return part;
5167
- }
5168
- let args = {};
5169
- if (typeof part.input === "string") {
5170
- try {
5171
- args = JSON.parse(part.input);
5172
- } catch (e) {
5173
- return part;
5174
- }
5175
- } else if (part.input && typeof part.input === "object") {
5176
- args = part.input;
5177
- }
5178
- const schema = (_a = tools.find((t) => t.name === part.toolName)) == null ? void 0 : _a.inputSchema;
5179
- const coerced = coerceBySchema(args, schema);
5180
- return {
5181
- ...part,
5182
- input: JSON.stringify(coerced != null ? coerced : {})
5183
- };
5184
- }
5185
6080
 
5186
6081
  // src/core/prompts/hermes-system-prompt.ts
5187
6082
  function hermesSystemPromptTemplate(tools) {
@@ -5585,19 +6480,22 @@ async function wrapStream({
5585
6480
  params
5586
6481
  }) {
5587
6482
  var _a, _b, _c;
6483
+ const onErrorOptions = extractOnErrorOption(params.providerOptions);
6484
+ const tools = originalToolsSchema.decode(
6485
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
6486
+ onErrorOptions
6487
+ );
5588
6488
  if (isToolChoiceActive(params)) {
5589
6489
  return toolChoiceStream({
5590
6490
  doGenerate,
5591
- options: extractOnErrorOption(params.providerOptions)
6491
+ tools,
6492
+ options: onErrorOptions
5592
6493
  });
5593
6494
  }
5594
6495
  const { stream, ...rest } = await doStream();
5595
6496
  const debugLevel = getDebugLevel();
5596
- const tools = originalToolsSchema.decode(
5597
- (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
5598
- );
5599
6497
  const options = {
5600
- ...extractOnErrorOption(params.providerOptions),
6498
+ ...onErrorOptions,
5601
6499
  ...((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) || {}
5602
6500
  };
5603
6501
  const coreStream = stream.pipeThrough(
@@ -5615,10 +6513,11 @@ async function wrapStream({
5615
6513
  const v3Stream = coreStream.pipeThrough(
5616
6514
  new TransformStream({
5617
6515
  transform(part, controller) {
6516
+ const normalizedPart = part.type === "tool-call" ? coerceToolCallPart(part, tools) : part;
5618
6517
  if (debugLevel === "stream") {
5619
- logParsedChunk(part);
6518
+ logParsedChunk(normalizedPart);
5620
6519
  }
5621
- controller.enqueue(part);
6520
+ controller.enqueue(normalizedPart);
5622
6521
  }
5623
6522
  })
5624
6523
  );
@@ -5629,41 +6528,36 @@ async function wrapStream({
5629
6528
  }
5630
6529
  async function toolChoiceStream({
5631
6530
  doGenerate,
6531
+ tools,
5632
6532
  options
5633
6533
  }) {
5634
- var _a, _b;
6534
+ var _a;
6535
+ const normalizedTools = Array.isArray(tools) ? tools : [];
5635
6536
  const result = await doGenerate();
5636
- let toolJson = {};
6537
+ let toolName = "unknown";
6538
+ let input = "{}";
5637
6539
  if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
5638
- try {
5639
- toolJson = JSON.parse(result.content[0].text);
5640
- } catch (error) {
5641
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5642
- options,
5643
- "Failed to parse toolChoice JSON from streamed model output",
5644
- {
5645
- text: result.content[0].text,
5646
- error: error instanceof Error ? error.message : String(error)
5647
- }
5648
- );
5649
- toolJson = {};
5650
- }
6540
+ const parsed = parseToolChoicePayload({
6541
+ text: result.content[0].text,
6542
+ tools: normalizedTools,
6543
+ onError: options == null ? void 0 : options.onError,
6544
+ errorMessage: "Failed to parse toolChoice JSON from streamed model output"
6545
+ });
6546
+ toolName = parsed.toolName;
6547
+ input = parsed.input;
5651
6548
  }
5652
6549
  const stream = new ReadableStream({
5653
6550
  start(controller) {
5654
6551
  controller.enqueue({
5655
6552
  type: "tool-call",
5656
6553
  toolCallId: (0, import_provider_utils2.generateId)(),
5657
- toolName: toolJson.name || "unknown",
5658
- input: JSON.stringify(toolJson.arguments || {})
6554
+ toolName,
6555
+ input
5659
6556
  });
5660
6557
  controller.enqueue({
5661
6558
  type: "finish",
5662
- usage: (result == null ? void 0 : result.usage) || {
5663
- inputTokens: 0,
5664
- outputTokens: 0
5665
- },
5666
- finishReason: "tool-calls"
6559
+ usage: normalizeUsage(result == null ? void 0 : result.usage),
6560
+ finishReason: normalizeToolCallsFinishReason(result == null ? void 0 : result.finishReason)
5667
6561
  });
5668
6562
  controller.close();
5669
6563
  }
@@ -5674,6 +6568,60 @@ async function toolChoiceStream({
5674
6568
  stream
5675
6569
  };
5676
6570
  }
6571
+ var ZERO_USAGE = {
6572
+ inputTokens: {
6573
+ total: 0,
6574
+ noCache: void 0,
6575
+ cacheRead: void 0,
6576
+ cacheWrite: void 0
6577
+ },
6578
+ outputTokens: {
6579
+ total: 0,
6580
+ text: void 0,
6581
+ reasoning: void 0
6582
+ }
6583
+ };
6584
+ function normalizeToolCallsFinishReason(finishReason) {
6585
+ let raw = "tool-calls";
6586
+ if (typeof finishReason === "string") {
6587
+ raw = finishReason;
6588
+ } else if (finishReason && typeof finishReason === "object" && "raw" in finishReason && typeof finishReason.raw === "string") {
6589
+ raw = finishReason.raw;
6590
+ } else if (finishReason && typeof finishReason === "object" && "unified" in finishReason && typeof finishReason.unified === "string") {
6591
+ raw = finishReason.unified;
6592
+ }
6593
+ return {
6594
+ unified: "tool-calls",
6595
+ raw
6596
+ };
6597
+ }
6598
+ function normalizeUsage(usage) {
6599
+ if (!usage || typeof usage !== "object") {
6600
+ return ZERO_USAGE;
6601
+ }
6602
+ const usageRecord = usage;
6603
+ const input = usageRecord.inputTokens;
6604
+ const output = usageRecord.outputTokens;
6605
+ if (input && typeof input === "object" && output && typeof output === "object") {
6606
+ return usage;
6607
+ }
6608
+ if (typeof input === "number" && typeof output === "number") {
6609
+ return {
6610
+ inputTokens: {
6611
+ total: input,
6612
+ noCache: void 0,
6613
+ cacheRead: void 0,
6614
+ cacheWrite: void 0
6615
+ },
6616
+ outputTokens: {
6617
+ total: output,
6618
+ text: void 0,
6619
+ reasoning: void 0
6620
+ }
6621
+ };
6622
+ }
6623
+ return ZERO_USAGE;
6624
+ }
5677
6625
 
5678
6626
  // src/transform-handler.ts
5679
6627
  function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
@@ -5799,6 +6747,11 @@ function handleToolChoiceRequired(params, baseReturnParams, functionTools) {
5799
6747
  "Tool choice type 'required' is set, but no tools are provided in params.tools."
5800
6748
  );
5801
6749
  }
6750
+ if (functionTools.length === 0) {
6751
+ throw new Error(
6752
+ "Tool choice type 'required' is set, but no function tools are provided. Provider-defined tools are not supported by this middleware."
6753
+ );
6754
+ }
5802
6755
  return {
5803
6756
  ...baseReturnParams,
5804
6757
  responseFormat: {