@ai-sdk-tool/parser 3.3.2 → 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.
@@ -1516,6 +1516,13 @@ var EMPTY_OBJECT_REGEX = /^\{\s*\}$/s;
1516
1516
  var NEWLINE_SPLIT_REGEX = /\n+/;
1517
1517
  var COMMA_SPLIT_REGEX = /,\s*/;
1518
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 = /^_+/;
1519
1526
  function unwrapJsonSchema(schema) {
1520
1527
  if (!schema || typeof schema !== "object") {
1521
1528
  return schema;
@@ -1764,9 +1771,158 @@ function coerceStringToArray(s, unwrapped) {
1764
1771
  }
1765
1772
  return null;
1766
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
+ }
1767
1922
  function coerceObjectToObject(value, unwrapped) {
1923
+ const normalizedInput = applyStrictRequiredKeyRename(value, unwrapped);
1768
1924
  const out = {};
1769
- for (const [k, v] of Object.entries(value)) {
1925
+ for (const [k, v] of Object.entries(normalizedInput)) {
1770
1926
  out[k] = coerceValueForKey(v, k, unwrapped);
1771
1927
  }
1772
1928
  return out;
@@ -1777,6 +1933,109 @@ function coerceArrayToArray(value, prefixItems, itemsSchema) {
1777
1933
  }
1778
1934
  return value.map((v) => coerceBySchema(v, itemsSchema));
1779
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
+ }
1780
2039
  function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
1781
2040
  if (Object.hasOwn(maybe, "item")) {
1782
2041
  const items = maybe.item;
@@ -1788,15 +2047,23 @@ function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
1788
2047
  const arr = keys.sort((a, b) => Number(a) - Number(b)).map((k) => maybe[k]);
1789
2048
  return coerceArrayToArray(arr, prefixItems, itemsSchema);
1790
2049
  }
2050
+ const parallelArrays = coerceParallelArraysObjectToArray(
2051
+ maybe,
2052
+ prefixItems,
2053
+ itemsSchema
2054
+ );
2055
+ if (parallelArrays !== null) {
2056
+ return parallelArrays;
2057
+ }
1791
2058
  if (keys.length === 1) {
1792
2059
  const singleKey = keys[0];
1793
2060
  if (!(schemaIsUnconstrained(itemsSchema) || schemaHasProperty(itemsSchema, singleKey))) {
1794
- const singleValue = maybe[singleKey];
1795
- if (Array.isArray(singleValue)) {
1796
- return singleValue.map((v) => coerceBySchema(v, itemsSchema));
1797
- }
1798
- if (singleValue && typeof singleValue === "object") {
1799
- return [coerceBySchema(singleValue, itemsSchema)];
2061
+ const result = coerceSingleKeyObjectToArray(
2062
+ maybe[singleKey],
2063
+ itemsSchema
2064
+ );
2065
+ if (result !== null) {
2066
+ return result;
1800
2067
  }
1801
2068
  }
1802
2069
  }
@@ -1826,6 +2093,86 @@ function coerceStringToPrimitive(s, schemaType) {
1826
2093
  }
1827
2094
  return null;
1828
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
+ }
1829
2176
  function coerceStringValue(value, schemaType, u) {
1830
2177
  const s = value.trim();
1831
2178
  if (schemaType === "object") {
@@ -1844,6 +2191,10 @@ function coerceStringValue(value, schemaType, u) {
1844
2191
  if (primitiveResult !== null) {
1845
2192
  return primitiveResult;
1846
2193
  }
2194
+ const enumWhitespaceCanonical = coerceStringByEnumWhitespace(s, u);
2195
+ if (enumWhitespaceCanonical !== null) {
2196
+ return enumWhitespaceCanonical;
2197
+ }
1847
2198
  return value;
1848
2199
  }
1849
2200
  function coerceArrayValue(value, prefixItems, itemsSchema) {
@@ -1882,9 +2233,23 @@ function coerceBySchema(value, schema) {
1882
2233
  if (typeof value === "string") {
1883
2234
  return coerceStringValue(value, schemaType, u);
1884
2235
  }
2236
+ const primitiveString = coercePrimitiveToString(value, schemaType);
2237
+ if (primitiveString !== null) {
2238
+ return primitiveString;
2239
+ }
1885
2240
  if (schemaType === "object" && value && typeof value === "object" && !Array.isArray(value)) {
1886
2241
  return coerceObjectToObject(value, u);
1887
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
+ }
1888
2253
  if (schemaType === "array") {
1889
2254
  const prefixItems = Array.isArray(u.prefixItems) ? u.prefixItems : void 0;
1890
2255
  const itemsSchema = u.items;
@@ -2899,7 +3264,7 @@ var XMLTokenizer = class {
2899
3264
  };
2900
3265
 
2901
3266
  // src/rxml/core/parser.ts
2902
- var WHITESPACE_REGEX2 = /\s/;
3267
+ var WHITESPACE_REGEX3 = /\s/;
2903
3268
  var NUMERIC_STRING_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
2904
3269
  var DIGIT_KEY_REGEX2 = /^\d+$/;
2905
3270
  function getTopLevelStringProps(s) {
@@ -3069,7 +3434,7 @@ function parse2(xmlInner, schema, options = {}) {
3069
3434
  const closeHead = s.indexOf(`</${rootName}`, range.end);
3070
3435
  if (closeHead === range.end) {
3071
3436
  let p = closeHead + 2 + rootName.length;
3072
- while (p < s.length && WHITESPACE_REGEX2.test(s[p])) {
3437
+ while (p < s.length && WHITESPACE_REGEX3.test(s[p])) {
3073
3438
  p += 1;
3074
3439
  }
3075
3440
  if (s[p] === ">") {
@@ -3407,7 +3772,7 @@ function createIntermediateCall(toolName, rawSegment, schema) {
3407
3772
  var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
3408
3773
  var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
3409
3774
  var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
3410
- var WHITESPACE_REGEX3 = /\s/;
3775
+ var WHITESPACE_REGEX4 = /\s/;
3411
3776
  var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
3412
3777
  var NAME_START_CHAR_RE = /[A-Za-z_:]/;
3413
3778
  var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
@@ -3548,7 +3913,7 @@ function balanceTags(xml) {
3548
3913
  }
3549
3914
  function skipWs(s, p, len) {
3550
3915
  let idx = p;
3551
- while (idx < len && WHITESPACE_REGEX3.test(s[idx])) {
3916
+ while (idx < len && WHITESPACE_REGEX4.test(s[idx])) {
3552
3917
  idx += 1;
3553
3918
  }
3554
3919
  return idx;
@@ -3601,7 +3966,7 @@ function handleOpeningTagSegment(src, lt, out, stack) {
3601
3966
  return len;
3602
3967
  }
3603
3968
  let r = q - 1;
3604
- while (r >= nameStart && WHITESPACE_REGEX3.test(src[r])) {
3969
+ while (r >= nameStart && WHITESPACE_REGEX4.test(src[r])) {
3605
3970
  r -= 1;
3606
3971
  }
3607
3972
  const selfClosing = src[r] === "/";
@@ -3765,7 +4130,31 @@ function parse3(xml, schema, options = {}) {
3765
4130
 
3766
4131
  // src/core/utils/regex-constants.ts
3767
4132
  var NAME_CHAR_RE2 = /[A-Za-z0-9_:-]/;
3768
- 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
+ }
3769
4158
 
3770
4159
  // src/core/protocols/xml-protocol.ts
3771
4160
  function getToolSchema(tools, toolName) {
@@ -3869,7 +4258,7 @@ function consumeClosingTag(text, lt) {
3869
4258
  }
3870
4259
  function consumeOpenTag(text, lt) {
3871
4260
  let p = lt + 1;
3872
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
4261
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3873
4262
  p += 1;
3874
4263
  }
3875
4264
  const nameStart = p;
@@ -3882,7 +4271,7 @@ function consumeOpenTag(text, lt) {
3882
4271
  return null;
3883
4272
  }
3884
4273
  let r = q - 1;
3885
- while (r >= nameStart && WHITESPACE_REGEX4.test(text[r])) {
4274
+ while (r >= nameStart && WHITESPACE_REGEX5.test(text[r])) {
3886
4275
  r -= 1;
3887
4276
  }
3888
4277
  const selfClosing = text[r] === "/";
@@ -3911,7 +4300,7 @@ function nextTagToken(text, fromPos) {
3911
4300
  if (next === "/") {
3912
4301
  const closing = consumeClosingTag(text, lt);
3913
4302
  let p = lt + 2;
3914
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
4303
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3915
4304
  p += 1;
3916
4305
  }
3917
4306
  const nameStart = p;
@@ -4048,6 +4437,102 @@ function findToolCalls(text, toolNames) {
4048
4437
  }
4049
4438
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
4050
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
+ }
4051
4536
  function findEarliestToolTag(buffer, toolNames) {
4052
4537
  var _a, _b;
4053
4538
  let bestIndex = -1;
@@ -4086,7 +4571,7 @@ function isOpenTagPrefix(suffix, toolName) {
4086
4571
  }
4087
4572
  function consumeWhitespace(text, index) {
4088
4573
  let i = index;
4089
- while (i < text.length && WHITESPACE_REGEX4.test(text.charAt(i))) {
4574
+ while (i < text.length && WHITESPACE_REGEX5.test(text.charAt(i))) {
4090
4575
  i += 1;
4091
4576
  }
4092
4577
  return i;
@@ -4337,6 +4822,27 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
4337
4822
  }
4338
4823
  };
4339
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
+ }
4340
4846
  var xmlProtocol = (protocolOptions) => {
4341
4847
  var _a;
4342
4848
  const parseOptions = {
@@ -4370,28 +4876,31 @@ var xmlProtocol = (protocolOptions) => {
4370
4876
  }
4371
4877
  const processedElements = [];
4372
4878
  let currentIndex = 0;
4373
- const toolCalls = findToolCalls(text, toolNames);
4879
+ const { parseText, toolCalls } = findToolCallsWithFallbacks(
4880
+ text,
4881
+ toolNames
4882
+ );
4374
4883
  for (const tc of toolCalls) {
4375
4884
  if (tc.startIndex > currentIndex) {
4376
4885
  processedElements.push({
4377
4886
  type: "text",
4378
- text: text.substring(currentIndex, tc.startIndex)
4887
+ text: parseText.substring(currentIndex, tc.startIndex)
4379
4888
  });
4380
4889
  }
4381
4890
  processToolCall({
4382
4891
  toolCall: tc,
4383
4892
  tools,
4384
4893
  options,
4385
- text,
4894
+ text: parseText,
4386
4895
  processedElements,
4387
4896
  parseOptions
4388
4897
  });
4389
4898
  currentIndex = tc.endIndex;
4390
4899
  }
4391
- if (currentIndex < text.length) {
4900
+ if (currentIndex < parseText.length) {
4392
4901
  processedElements.push({
4393
4902
  type: "text",
4394
- text: text.substring(currentIndex)
4903
+ text: parseText.substring(currentIndex)
4395
4904
  });
4396
4905
  }
4397
4906
  return processedElements;
@@ -4430,6 +4939,20 @@ var xmlProtocol = (protocolOptions) => {
4430
4939
  return new TransformStream({
4431
4940
  transform(chunk, controller) {
4432
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
+ }
4433
4956
  if (chunk.type !== "text-delta") {
4434
4957
  if (buffer) {
4435
4958
  flushText(controller, buffer);
@@ -4491,7 +5014,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4491
5014
  break;
4492
5015
  }
4493
5016
  let p = ltIdx + 2;
4494
- while (p < gtIdx && WHITESPACE_REGEX4.test(text[p])) {
5017
+ while (p < gtIdx && WHITESPACE_REGEX5.test(text[p])) {
4495
5018
  p++;
4496
5019
  }
4497
5020
  const nameStart = p;
@@ -4511,7 +5034,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4511
5034
  pos = gtIdx === -1 ? text.length : gtIdx + 1;
4512
5035
  } else {
4513
5036
  let p = ltIdx + 1;
4514
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
5037
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
4515
5038
  p++;
4516
5039
  }
4517
5040
  const nameStart = p;
@@ -4524,7 +5047,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4524
5047
  break;
4525
5048
  }
4526
5049
  let r = gtIdx - 1;
4527
- while (r >= nameStart && WHITESPACE_REGEX4.test(text[r])) {
5050
+ while (r >= nameStart && WHITESPACE_REGEX5.test(text[r])) {
4528
5051
  r--;
4529
5052
  }
4530
5053
  const selfClosing = text[r] === "/";
@@ -4756,18 +5279,32 @@ ${yamlContent}</${toolCall.toolName}>`;
4756
5279
  }
4757
5280
  const processedElements = [];
4758
5281
  let currentIndex = 0;
4759
- 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
+ }
4760
5297
  for (const tc of toolCalls) {
4761
5298
  currentIndex = processToolCallMatch(
4762
- text,
5299
+ parseText,
4763
5300
  tc,
4764
5301
  currentIndex,
4765
5302
  processedElements,
4766
5303
  options
4767
5304
  );
4768
5305
  }
4769
- if (currentIndex < text.length) {
4770
- addTextSegment(text.substring(currentIndex), processedElements);
5306
+ if (currentIndex < parseText.length) {
5307
+ addTextSegment(parseText.substring(currentIndex), processedElements);
4771
5308
  }
4772
5309
  return processedElements;
4773
5310
  },
@@ -4863,6 +5400,20 @@ ${yamlContent}</${toolCall.toolName}>`;
4863
5400
  return new TransformStream({
4864
5401
  transform(chunk, controller) {
4865
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
+ }
4866
5417
  if (chunk.type !== "text-delta") {
4867
5418
  if (buffer) {
4868
5419
  flushText(controller, buffer);
@@ -4986,17 +5537,56 @@ function encodeOriginalTools(tools) {
4986
5537
  inputSchema: JSON.stringify(t.inputSchema)
4987
5538
  }))) || [];
4988
5539
  }
4989
- function decodeOriginalTools(originalTools) {
5540
+ function decodeOriginalTools(originalTools, options) {
5541
+ var _a, _b, _c;
4990
5542
  if (!originalTools) {
4991
5543
  return [];
4992
5544
  }
4993
- return originalTools.map(
4994
- (t) => ({
4995
- type: "function",
4996
- name: t.name,
4997
- inputSchema: JSON.parse(t.inputSchema)
4998
- })
4999
- );
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;
5000
5590
  }
5001
5591
  function isToolChoiceActive(params) {
5002
5592
  var _a, _b, _c;
@@ -5006,23 +5596,337 @@ function isToolChoiceActive(params) {
5006
5596
 
5007
5597
  // src/generate-handler.ts
5008
5598
  var import_provider_utils = require("@ai-sdk/provider-utils");
5009
- 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) {
5010
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;
5011
5896
  try {
5012
- return JSON.parse(text);
5897
+ parsed = JSON.parse(text);
5013
5898
  } catch (error) {
5014
- const options = extractOnErrorOption(providerOptions);
5015
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
5016
- options,
5017
- "Failed to parse toolChoice JSON from generated model output",
5018
- {
5019
- text,
5020
- error: error instanceof Error ? error.message : String(error)
5021
- }
5022
- );
5023
- 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: "{}" };
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: "{}" };
5024
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
+ };
5025
5927
  }
5928
+
5929
+ // src/generate-handler.ts
5026
5930
  function logDebugSummary(debugSummary, toolCall, originText) {
5027
5931
  if (debugSummary) {
5028
5932
  debugSummary.originalText = originText;
@@ -5036,25 +5940,34 @@ function logDebugSummary(debugSummary, toolCall, originText) {
5036
5940
  logParsedSummary({ toolCalls: [toolCall], originalText: originText });
5037
5941
  }
5038
5942
  }
5039
- async function handleToolChoice(doGenerate, params) {
5040
- var _a, _b, _c;
5943
+ async function handleToolChoice(doGenerate, params, tools) {
5944
+ var _a, _b, _c, _d;
5041
5945
  const result = await doGenerate();
5042
5946
  const first = (_a = result.content) == null ? void 0 : _a[0];
5043
- let parsed = {};
5947
+ const onError = (_b = extractOnErrorOption(params.providerOptions)) == null ? void 0 : _b.onError;
5948
+ let toolName = "unknown";
5949
+ let input = "{}";
5044
5950
  if (first && first.type === "text") {
5045
5951
  if (getDebugLevel() === "parse") {
5046
5952
  logRawChunk(first.text);
5047
5953
  }
5048
- 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;
5049
5962
  }
5050
5963
  const toolCall = {
5051
5964
  type: "tool-call",
5052
5965
  toolCallId: (0, import_provider_utils.generateId)(),
5053
- toolName: parsed.name || "unknown",
5054
- input: JSON.stringify(parsed.arguments || {})
5966
+ toolName,
5967
+ input
5055
5968
  };
5056
5969
  const originText = first && first.type === "text" ? first.text : "";
5057
- 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;
5058
5971
  logDebugSummary(debugSummary, toolCall, originText);
5059
5972
  return {
5060
5973
  ...result,
@@ -5069,7 +5982,7 @@ function parseContent(content, protocol, tools, providerOptions) {
5069
5982
  if (getDebugLevel() === "stream") {
5070
5983
  logRawChunk(contentItem.text);
5071
5984
  }
5072
- return protocol.parseGeneratedText({
5985
+ const parsedByProtocol = protocol.parseGeneratedText({
5073
5986
  text: contentItem.text,
5074
5987
  tools,
5075
5988
  options: {
@@ -5077,9 +5990,20 @@ function parseContent(content, protocol, tools, providerOptions) {
5077
5990
  ...providerOptions == null ? void 0 : providerOptions.toolCallMiddleware
5078
5991
  }
5079
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;
5080
6004
  });
5081
6005
  return parsed.map(
5082
- (part) => fixToolCallWithSchema(part, tools)
6006
+ (part) => part.type === "tool-call" ? coerceToolCallPart(part, tools) : part
5083
6007
  );
5084
6008
  }
5085
6009
  function logParsedContent(content) {
@@ -5122,12 +6046,14 @@ async function wrapGenerate({
5122
6046
  params
5123
6047
  }) {
5124
6048
  var _a, _b;
5125
- if (isToolChoiceActive(params)) {
5126
- return handleToolChoice(doGenerate, params);
5127
- }
6049
+ const onError = extractOnErrorOption(params.providerOptions);
5128
6050
  const tools = originalToolsSchema.decode(
5129
- (_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
5130
6053
  );
6054
+ if (isToolChoiceActive(params)) {
6055
+ return handleToolChoice(doGenerate, params, tools);
6056
+ }
5131
6057
  const result = await doGenerate();
5132
6058
  if (result.content.length === 0) {
5133
6059
  return result;
@@ -5151,28 +6077,6 @@ async function wrapGenerate({
5151
6077
  content: newContent
5152
6078
  };
5153
6079
  }
5154
- function fixToolCallWithSchema(part, tools) {
5155
- var _a;
5156
- if (part.type !== "tool-call") {
5157
- return part;
5158
- }
5159
- let args = {};
5160
- if (typeof part.input === "string") {
5161
- try {
5162
- args = JSON.parse(part.input);
5163
- } catch (e) {
5164
- return part;
5165
- }
5166
- } else if (part.input && typeof part.input === "object") {
5167
- args = part.input;
5168
- }
5169
- const schema = (_a = tools.find((t) => t.name === part.toolName)) == null ? void 0 : _a.inputSchema;
5170
- const coerced = coerceBySchema(args, schema);
5171
- return {
5172
- ...part,
5173
- input: JSON.stringify(coerced != null ? coerced : {})
5174
- };
5175
- }
5176
6080
 
5177
6081
  // src/core/prompts/hermes-system-prompt.ts
5178
6082
  function hermesSystemPromptTemplate(tools) {
@@ -5576,19 +6480,22 @@ async function wrapStream({
5576
6480
  params
5577
6481
  }) {
5578
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
+ );
5579
6488
  if (isToolChoiceActive(params)) {
5580
6489
  return toolChoiceStream({
5581
6490
  doGenerate,
5582
- options: extractOnErrorOption(params.providerOptions)
6491
+ tools,
6492
+ options: onErrorOptions
5583
6493
  });
5584
6494
  }
5585
6495
  const { stream, ...rest } = await doStream();
5586
6496
  const debugLevel = getDebugLevel();
5587
- const tools = originalToolsSchema.decode(
5588
- (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
5589
- );
5590
6497
  const options = {
5591
- ...extractOnErrorOption(params.providerOptions),
6498
+ ...onErrorOptions,
5592
6499
  ...((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) || {}
5593
6500
  };
5594
6501
  const coreStream = stream.pipeThrough(
@@ -5606,10 +6513,11 @@ async function wrapStream({
5606
6513
  const v3Stream = coreStream.pipeThrough(
5607
6514
  new TransformStream({
5608
6515
  transform(part, controller) {
6516
+ const normalizedPart = part.type === "tool-call" ? coerceToolCallPart(part, tools) : part;
5609
6517
  if (debugLevel === "stream") {
5610
- logParsedChunk(part);
6518
+ logParsedChunk(normalizedPart);
5611
6519
  }
5612
- controller.enqueue(part);
6520
+ controller.enqueue(normalizedPart);
5613
6521
  }
5614
6522
  })
5615
6523
  );
@@ -5620,41 +6528,36 @@ async function wrapStream({
5620
6528
  }
5621
6529
  async function toolChoiceStream({
5622
6530
  doGenerate,
6531
+ tools,
5623
6532
  options
5624
6533
  }) {
5625
- var _a, _b;
6534
+ var _a;
6535
+ const normalizedTools = Array.isArray(tools) ? tools : [];
5626
6536
  const result = await doGenerate();
5627
- let toolJson = {};
6537
+ let toolName = "unknown";
6538
+ let input = "{}";
5628
6539
  if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
5629
- try {
5630
- toolJson = JSON.parse(result.content[0].text);
5631
- } catch (error) {
5632
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5633
- options,
5634
- "Failed to parse toolChoice JSON from streamed model output",
5635
- {
5636
- text: result.content[0].text,
5637
- error: error instanceof Error ? error.message : String(error)
5638
- }
5639
- );
5640
- toolJson = {};
5641
- }
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;
5642
6548
  }
5643
6549
  const stream = new ReadableStream({
5644
6550
  start(controller) {
5645
6551
  controller.enqueue({
5646
6552
  type: "tool-call",
5647
6553
  toolCallId: (0, import_provider_utils2.generateId)(),
5648
- toolName: toolJson.name || "unknown",
5649
- input: JSON.stringify(toolJson.arguments || {})
6554
+ toolName,
6555
+ input
5650
6556
  });
5651
6557
  controller.enqueue({
5652
6558
  type: "finish",
5653
- usage: (result == null ? void 0 : result.usage) || {
5654
- inputTokens: 0,
5655
- outputTokens: 0
5656
- },
5657
- finishReason: "tool-calls"
6559
+ usage: normalizeUsage(result == null ? void 0 : result.usage),
6560
+ finishReason: normalizeToolCallsFinishReason(result == null ? void 0 : result.finishReason)
5658
6561
  });
5659
6562
  controller.close();
5660
6563
  }
@@ -5665,6 +6568,60 @@ async function toolChoiceStream({
5665
6568
  stream
5666
6569
  };
5667
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
+ }
5668
6625
 
5669
6626
  // src/transform-handler.ts
5670
6627
  function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
@@ -5790,6 +6747,11 @@ function handleToolChoiceRequired(params, baseReturnParams, functionTools) {
5790
6747
  "Tool choice type 'required' is set, but no tools are provided in params.tools."
5791
6748
  );
5792
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
+ }
5793
6755
  return {
5794
6756
  ...baseReturnParams,
5795
6757
  responseFormat: {