@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.
package/dist/index.cjs CHANGED
@@ -1577,6 +1577,13 @@ var EMPTY_OBJECT_REGEX = /^\{\s*\}$/s;
1577
1577
  var NEWLINE_SPLIT_REGEX = /\n+/;
1578
1578
  var COMMA_SPLIT_REGEX = /,\s*/;
1579
1579
  var DIGIT_KEY_REGEX = /^\d+$/;
1580
+ var WHITESPACE_REGEX2 = /\s+/g;
1581
+ var HAS_WHITESPACE_REGEX = /\s/;
1582
+ var SINGLE_QUOTE = "'";
1583
+ var DOUBLE_QUOTE = '"';
1584
+ var SNAKE_SEGMENT_REGEX = /_([a-zA-Z0-9])/g;
1585
+ var CAMEL_BOUNDARY_REGEX = /([a-z0-9])([A-Z])/g;
1586
+ var LEADING_UNDERSCORES_REGEX = /^_+/;
1580
1587
  function unwrapJsonSchema(schema) {
1581
1588
  if (!schema || typeof schema !== "object") {
1582
1589
  return schema;
@@ -1825,9 +1832,158 @@ function coerceStringToArray(s, unwrapped) {
1825
1832
  }
1826
1833
  return null;
1827
1834
  }
1835
+ function getStrictObjectSchemaInfo(unwrapped) {
1836
+ if (getSchemaType(unwrapped) !== "object") {
1837
+ return null;
1838
+ }
1839
+ if (unwrapped.additionalProperties !== false) {
1840
+ return null;
1841
+ }
1842
+ const properties = unwrapped.properties;
1843
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
1844
+ return null;
1845
+ }
1846
+ const propertyMap = properties;
1847
+ const required = Array.isArray(unwrapped.required) ? unwrapped.required.filter(
1848
+ (value) => typeof value === "string" && value.length > 0
1849
+ ) : [];
1850
+ const patternProps = unwrapped.patternProperties;
1851
+ const patternProperties = patternProps && typeof patternProps === "object" && !Array.isArray(patternProps) ? patternProps : void 0;
1852
+ return {
1853
+ properties: propertyMap,
1854
+ required,
1855
+ patternProperties
1856
+ };
1857
+ }
1858
+ function isSingularPluralPair(left, right) {
1859
+ return left.length > 1 && right.length > 1 && (left === `${right}s` || right === `${left}s`);
1860
+ }
1861
+ function snakeToCamel(value) {
1862
+ const trimmed = value.replace(LEADING_UNDERSCORES_REGEX, "");
1863
+ if (trimmed.length === 0) {
1864
+ return value;
1865
+ }
1866
+ const camelized = trimmed.replace(
1867
+ SNAKE_SEGMENT_REGEX,
1868
+ (_, c) => c.toUpperCase()
1869
+ );
1870
+ return camelized.charAt(0).toLowerCase() + camelized.slice(1);
1871
+ }
1872
+ function camelToSnake(value) {
1873
+ return value.replace(CAMEL_BOUNDARY_REGEX, "$1_$2").toLowerCase();
1874
+ }
1875
+ function isCaseStylePair(targetKey, sourceKey) {
1876
+ if (targetKey === sourceKey) {
1877
+ return false;
1878
+ }
1879
+ const sourceLooksSnake = sourceKey.includes("_");
1880
+ const targetLooksSnake = targetKey.includes("_");
1881
+ if (sourceLooksSnake && snakeToCamel(sourceKey) === targetKey) {
1882
+ return true;
1883
+ }
1884
+ if (!sourceLooksSnake && targetLooksSnake && camelToSnake(sourceKey) === targetKey) {
1885
+ return true;
1886
+ }
1887
+ return false;
1888
+ }
1889
+ function isUnexpectedKey(key, schemaInfo) {
1890
+ if (Object.hasOwn(schemaInfo.properties, key)) {
1891
+ return false;
1892
+ }
1893
+ const patternSchemas = getPatternSchemasForKey(
1894
+ schemaInfo.patternProperties,
1895
+ key
1896
+ );
1897
+ if (patternSchemas.length > 0) {
1898
+ return patternSchemas.every((schema) => schema === false);
1899
+ }
1900
+ return true;
1901
+ }
1902
+ function computeMissingAndUnexpectedKeys(input, schemaInfo) {
1903
+ const missingRequired = schemaInfo.required.filter(
1904
+ (key) => !Object.hasOwn(input, key)
1905
+ );
1906
+ const unexpectedKeys = Object.keys(input).filter(
1907
+ (key) => isUnexpectedKey(key, schemaInfo)
1908
+ );
1909
+ return { missingRequired, unexpectedKeys };
1910
+ }
1911
+ function applySingularPluralRequiredKeyRename(input, schemaInfo) {
1912
+ const { missingRequired, unexpectedKeys } = computeMissingAndUnexpectedKeys(
1913
+ input,
1914
+ schemaInfo
1915
+ );
1916
+ if (missingRequired.length !== 1 || unexpectedKeys.length !== 1) {
1917
+ return null;
1918
+ }
1919
+ const targetKey = missingRequired[0];
1920
+ const sourceKey = unexpectedKeys[0];
1921
+ if (!Object.hasOwn(schemaInfo.properties, targetKey)) {
1922
+ return null;
1923
+ }
1924
+ if (!isSingularPluralPair(targetKey, sourceKey)) {
1925
+ return null;
1926
+ }
1927
+ if (getSchemaType(schemaInfo.properties[targetKey]) !== "array") {
1928
+ return null;
1929
+ }
1930
+ if (!Array.isArray(input[sourceKey])) {
1931
+ return null;
1932
+ }
1933
+ if (!Object.hasOwn(input, sourceKey) || Object.hasOwn(input, targetKey)) {
1934
+ return null;
1935
+ }
1936
+ const output = { ...input };
1937
+ output[targetKey] = output[sourceKey];
1938
+ delete output[sourceKey];
1939
+ return output;
1940
+ }
1941
+ function applyCaseStyleRequiredKeyRename(input, schemaInfo) {
1942
+ const { missingRequired, unexpectedKeys } = computeMissingAndUnexpectedKeys(
1943
+ input,
1944
+ schemaInfo
1945
+ );
1946
+ if (missingRequired.length !== 1 || unexpectedKeys.length !== 1) {
1947
+ return null;
1948
+ }
1949
+ const targetKey = missingRequired[0];
1950
+ const sourceKey = unexpectedKeys[0];
1951
+ if (!Object.hasOwn(schemaInfo.properties, targetKey)) {
1952
+ return null;
1953
+ }
1954
+ if (!isCaseStylePair(targetKey, sourceKey)) {
1955
+ return null;
1956
+ }
1957
+ if (!Object.hasOwn(input, sourceKey) || Object.hasOwn(input, targetKey)) {
1958
+ return null;
1959
+ }
1960
+ const output = { ...input };
1961
+ output[targetKey] = output[sourceKey];
1962
+ delete output[sourceKey];
1963
+ return output;
1964
+ }
1965
+ function applyStrictRequiredKeyRename(input, unwrapped) {
1966
+ const schemaInfo = getStrictObjectSchemaInfo(unwrapped);
1967
+ if (!schemaInfo) {
1968
+ return input;
1969
+ }
1970
+ const singularPlural = applySingularPluralRequiredKeyRename(
1971
+ input,
1972
+ schemaInfo
1973
+ );
1974
+ if (singularPlural) {
1975
+ return singularPlural;
1976
+ }
1977
+ const caseStyle = applyCaseStyleRequiredKeyRename(input, schemaInfo);
1978
+ if (caseStyle) {
1979
+ return caseStyle;
1980
+ }
1981
+ return input;
1982
+ }
1828
1983
  function coerceObjectToObject(value, unwrapped) {
1984
+ const normalizedInput = applyStrictRequiredKeyRename(value, unwrapped);
1829
1985
  const out = {};
1830
- for (const [k, v] of Object.entries(value)) {
1986
+ for (const [k, v] of Object.entries(normalizedInput)) {
1831
1987
  out[k] = coerceValueForKey(v, k, unwrapped);
1832
1988
  }
1833
1989
  return out;
@@ -1838,6 +1994,109 @@ function coerceArrayToArray(value, prefixItems, itemsSchema) {
1838
1994
  }
1839
1995
  return value.map((v) => coerceBySchema(v, itemsSchema));
1840
1996
  }
1997
+ function isPrimitiveSchemaType(schemaType) {
1998
+ return schemaType === "string" || schemaType === "number" || schemaType === "integer" || schemaType === "boolean";
1999
+ }
2000
+ function isPrimitiveMatchForSchemaType(value, schemaType) {
2001
+ if (schemaType === "string") {
2002
+ return typeof value === "string";
2003
+ }
2004
+ if (schemaType === "number") {
2005
+ return typeof value === "number" && Number.isFinite(value);
2006
+ }
2007
+ if (schemaType === "integer") {
2008
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value);
2009
+ }
2010
+ return typeof value === "boolean";
2011
+ }
2012
+ function coercePrimitiveWrappedObject(value, itemsSchema) {
2013
+ const schemaType = getSchemaType(itemsSchema);
2014
+ if (!isPrimitiveSchemaType(schemaType)) {
2015
+ return null;
2016
+ }
2017
+ const keys = Object.keys(value);
2018
+ if (keys.length !== 1) {
2019
+ return null;
2020
+ }
2021
+ const singleValue = value[keys[0]];
2022
+ if (singleValue && typeof singleValue === "object") {
2023
+ return null;
2024
+ }
2025
+ const coerced = coerceBySchema(singleValue, itemsSchema);
2026
+ return isPrimitiveMatchForSchemaType(coerced, schemaType) ? coerced : null;
2027
+ }
2028
+ function coerceParallelArraysObjectToArray(maybe, prefixItems, itemsSchema) {
2029
+ if (prefixItems && prefixItems.length > 0) {
2030
+ return null;
2031
+ }
2032
+ const unwrappedItems = unwrapJsonSchema(itemsSchema);
2033
+ if (!unwrappedItems || typeof unwrappedItems !== "object" || Array.isArray(unwrappedItems)) {
2034
+ return null;
2035
+ }
2036
+ const itemSchema = unwrappedItems;
2037
+ if (getSchemaType(itemSchema) !== "object") {
2038
+ return null;
2039
+ }
2040
+ if (itemSchema.additionalProperties !== false) {
2041
+ return null;
2042
+ }
2043
+ const properties = itemSchema.properties;
2044
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
2045
+ return null;
2046
+ }
2047
+ const propertyMap = properties;
2048
+ const entries = Object.entries(maybe);
2049
+ if (entries.length < 2) {
2050
+ return null;
2051
+ }
2052
+ if (!entries.every(([, value]) => Array.isArray(value))) {
2053
+ return null;
2054
+ }
2055
+ if (!entries.every(([key]) => Object.hasOwn(propertyMap, key))) {
2056
+ return null;
2057
+ }
2058
+ if (!entries.every(([key]) => {
2059
+ const schemaType = getSchemaType(propertyMap[key]);
2060
+ return schemaType !== "array" && schemaType !== "object";
2061
+ })) {
2062
+ return null;
2063
+ }
2064
+ const lengths = [
2065
+ ...new Set(entries.map(([, value]) => value.length))
2066
+ ];
2067
+ if (lengths.length !== 1) {
2068
+ return null;
2069
+ }
2070
+ const length = lengths[0];
2071
+ if (length < 2) {
2072
+ return null;
2073
+ }
2074
+ const zipped = [];
2075
+ for (let index = 0; index < length; index += 1) {
2076
+ const item = {};
2077
+ for (const [key, value] of entries) {
2078
+ item[key] = value[index];
2079
+ }
2080
+ zipped.push(item);
2081
+ }
2082
+ return coerceArrayToArray(zipped, prefixItems, itemsSchema);
2083
+ }
2084
+ function coerceSingleKeyObjectToArray(singleValue, itemsSchema) {
2085
+ if (Array.isArray(singleValue)) {
2086
+ return singleValue.map((v) => coerceBySchema(v, itemsSchema));
2087
+ }
2088
+ if (singleValue && typeof singleValue === "object") {
2089
+ const primitiveWrapped = coercePrimitiveWrappedObject(
2090
+ singleValue,
2091
+ itemsSchema
2092
+ );
2093
+ if (primitiveWrapped !== null) {
2094
+ return [primitiveWrapped];
2095
+ }
2096
+ return [coerceBySchema(singleValue, itemsSchema)];
2097
+ }
2098
+ return null;
2099
+ }
1841
2100
  function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
1842
2101
  if (Object.hasOwn(maybe, "item")) {
1843
2102
  const items = maybe.item;
@@ -1849,15 +2108,23 @@ function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
1849
2108
  const arr = keys.sort((a, b) => Number(a) - Number(b)).map((k) => maybe[k]);
1850
2109
  return coerceArrayToArray(arr, prefixItems, itemsSchema);
1851
2110
  }
2111
+ const parallelArrays = coerceParallelArraysObjectToArray(
2112
+ maybe,
2113
+ prefixItems,
2114
+ itemsSchema
2115
+ );
2116
+ if (parallelArrays !== null) {
2117
+ return parallelArrays;
2118
+ }
1852
2119
  if (keys.length === 1) {
1853
2120
  const singleKey = keys[0];
1854
2121
  if (!(schemaIsUnconstrained(itemsSchema) || schemaHasProperty(itemsSchema, singleKey))) {
1855
- const singleValue = maybe[singleKey];
1856
- if (Array.isArray(singleValue)) {
1857
- return singleValue.map((v) => coerceBySchema(v, itemsSchema));
1858
- }
1859
- if (singleValue && typeof singleValue === "object") {
1860
- return [coerceBySchema(singleValue, itemsSchema)];
2122
+ const result = coerceSingleKeyObjectToArray(
2123
+ maybe[singleKey],
2124
+ itemsSchema
2125
+ );
2126
+ if (result !== null) {
2127
+ return result;
1861
2128
  }
1862
2129
  }
1863
2130
  }
@@ -1887,6 +2154,86 @@ function coerceStringToPrimitive(s, schemaType) {
1887
2154
  }
1888
2155
  return null;
1889
2156
  }
2157
+ function coercePrimitiveToString(value, schemaType) {
2158
+ if (schemaType !== "string") {
2159
+ return null;
2160
+ }
2161
+ if (typeof value === "boolean") {
2162
+ return value ? "true" : "false";
2163
+ }
2164
+ if (typeof value === "number" && Number.isFinite(value)) {
2165
+ return String(value);
2166
+ }
2167
+ return null;
2168
+ }
2169
+ function coerceStringByEnumWhitespace(rawValue, unwrapped) {
2170
+ const enumValues = unwrapped.enum;
2171
+ if (!Array.isArray(enumValues) || enumValues.length === 0) {
2172
+ return null;
2173
+ }
2174
+ if (!enumValues.every((item) => typeof item === "string")) {
2175
+ return null;
2176
+ }
2177
+ const normalizedEnumValues = enumValues;
2178
+ if (normalizedEnumValues.includes(rawValue)) {
2179
+ return null;
2180
+ }
2181
+ const unquoted = unwrapMatchingQuotes(rawValue);
2182
+ if (unquoted !== null) {
2183
+ const exactMatches = normalizedEnumValues.filter(
2184
+ (item) => item === unquoted
2185
+ );
2186
+ if (exactMatches.length === 1) {
2187
+ return exactMatches[0];
2188
+ }
2189
+ }
2190
+ const candidates = [rawValue, unquoted].filter(
2191
+ (item) => item !== null
2192
+ );
2193
+ for (const candidate of candidates) {
2194
+ if (!HAS_WHITESPACE_REGEX.test(candidate)) {
2195
+ continue;
2196
+ }
2197
+ const normalizedInput = candidate.replace(WHITESPACE_REGEX2, "");
2198
+ const matches = normalizedEnumValues.filter(
2199
+ (item) => item.replace(WHITESPACE_REGEX2, "") === normalizedInput
2200
+ );
2201
+ if (matches.length === 1) {
2202
+ return matches[0];
2203
+ }
2204
+ }
2205
+ return null;
2206
+ }
2207
+ function unwrapMatchingQuotes(value) {
2208
+ if (value.length < 2) {
2209
+ return null;
2210
+ }
2211
+ const first = value[0];
2212
+ const last = value.at(-1);
2213
+ const isQuote = (first === SINGLE_QUOTE || first === DOUBLE_QUOTE) && first === last;
2214
+ if (!isQuote) {
2215
+ return null;
2216
+ }
2217
+ return value.slice(1, -1);
2218
+ }
2219
+ function coerceObjectToPrimitive(value, schemaType, fullSchema) {
2220
+ if (!isPrimitiveSchemaType(schemaType)) {
2221
+ return null;
2222
+ }
2223
+ const keys = Object.keys(value);
2224
+ if (keys.length !== 1) {
2225
+ return null;
2226
+ }
2227
+ const singleValue = value[keys[0]];
2228
+ if (singleValue && typeof singleValue === "object") {
2229
+ return null;
2230
+ }
2231
+ const coerced = coerceBySchema(
2232
+ singleValue,
2233
+ fullSchema != null ? fullSchema : { type: schemaType }
2234
+ );
2235
+ return isPrimitiveMatchForSchemaType(coerced, schemaType) ? coerced : null;
2236
+ }
1890
2237
  function coerceStringValue(value, schemaType, u) {
1891
2238
  const s = value.trim();
1892
2239
  if (schemaType === "object") {
@@ -1905,6 +2252,10 @@ function coerceStringValue(value, schemaType, u) {
1905
2252
  if (primitiveResult !== null) {
1906
2253
  return primitiveResult;
1907
2254
  }
2255
+ const enumWhitespaceCanonical = coerceStringByEnumWhitespace(s, u);
2256
+ if (enumWhitespaceCanonical !== null) {
2257
+ return enumWhitespaceCanonical;
2258
+ }
1908
2259
  return value;
1909
2260
  }
1910
2261
  function coerceArrayValue(value, prefixItems, itemsSchema) {
@@ -1943,9 +2294,23 @@ function coerceBySchema(value, schema) {
1943
2294
  if (typeof value === "string") {
1944
2295
  return coerceStringValue(value, schemaType, u);
1945
2296
  }
2297
+ const primitiveString = coercePrimitiveToString(value, schemaType);
2298
+ if (primitiveString !== null) {
2299
+ return primitiveString;
2300
+ }
1946
2301
  if (schemaType === "object" && value && typeof value === "object" && !Array.isArray(value)) {
1947
2302
  return coerceObjectToObject(value, u);
1948
2303
  }
2304
+ if (value && typeof value === "object" && !Array.isArray(value) && isPrimitiveSchemaType(schemaType)) {
2305
+ const primitiveResult = coerceObjectToPrimitive(
2306
+ value,
2307
+ schemaType,
2308
+ u
2309
+ );
2310
+ if (primitiveResult !== null) {
2311
+ return primitiveResult;
2312
+ }
2313
+ }
1949
2314
  if (schemaType === "array") {
1950
2315
  const prefixItems = Array.isArray(u.prefixItems) ? u.prefixItems : void 0;
1951
2316
  const itemsSchema = u.items;
@@ -2960,7 +3325,7 @@ var XMLTokenizer = class {
2960
3325
  };
2961
3326
 
2962
3327
  // src/rxml/core/parser.ts
2963
- var WHITESPACE_REGEX2 = /\s/;
3328
+ var WHITESPACE_REGEX3 = /\s/;
2964
3329
  var NUMERIC_STRING_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
2965
3330
  var DIGIT_KEY_REGEX2 = /^\d+$/;
2966
3331
  function getTopLevelStringProps(s) {
@@ -3130,7 +3495,7 @@ function parse2(xmlInner, schema, options = {}) {
3130
3495
  const closeHead = s.indexOf(`</${rootName}`, range.end);
3131
3496
  if (closeHead === range.end) {
3132
3497
  let p = closeHead + 2 + rootName.length;
3133
- while (p < s.length && WHITESPACE_REGEX2.test(s[p])) {
3498
+ while (p < s.length && WHITESPACE_REGEX3.test(s[p])) {
3134
3499
  p += 1;
3135
3500
  }
3136
3501
  if (s[p] === ">") {
@@ -3468,7 +3833,7 @@ function createIntermediateCall(toolName, rawSegment, schema) {
3468
3833
  var MALFORMED_CLOSE_RE_G = /<\/\s+([A-Za-z0-9_:-]+)\s*>/g;
3469
3834
  var MALFORMED_CLOSE_RE = /<\/\s+([A-Za-z0-9_:-]+)\s*>/;
3470
3835
  var STATUS_TO_STEP_BOUNDARY_RE = /<\/status>\s*<step>/g;
3471
- var WHITESPACE_REGEX3 = /\s/;
3836
+ var WHITESPACE_REGEX4 = /\s/;
3472
3837
  var NAME_CHAR_RE = /[A-Za-z0-9_:-]/;
3473
3838
  var NAME_START_CHAR_RE = /[A-Za-z_:]/;
3474
3839
  var STEP_TAG_RE = /<step>([\s\S]*?)<\/step>/i;
@@ -3609,7 +3974,7 @@ function balanceTags(xml) {
3609
3974
  }
3610
3975
  function skipWs(s, p, len) {
3611
3976
  let idx = p;
3612
- while (idx < len && WHITESPACE_REGEX3.test(s[idx])) {
3977
+ while (idx < len && WHITESPACE_REGEX4.test(s[idx])) {
3613
3978
  idx += 1;
3614
3979
  }
3615
3980
  return idx;
@@ -3662,7 +4027,7 @@ function handleOpeningTagSegment(src, lt, out, stack) {
3662
4027
  return len;
3663
4028
  }
3664
4029
  let r = q - 1;
3665
- while (r >= nameStart && WHITESPACE_REGEX3.test(src[r])) {
4030
+ while (r >= nameStart && WHITESPACE_REGEX4.test(src[r])) {
3666
4031
  r -= 1;
3667
4032
  }
3668
4033
  const selfClosing = src[r] === "/";
@@ -3826,7 +4191,31 @@ function parse3(xml, schema, options = {}) {
3826
4191
 
3827
4192
  // src/core/utils/regex-constants.ts
3828
4193
  var NAME_CHAR_RE2 = /[A-Za-z0-9_:-]/;
3829
- var WHITESPACE_REGEX4 = /\s/;
4194
+ var WHITESPACE_REGEX5 = /\s/;
4195
+
4196
+ // src/core/utils/xml-root-repair.ts
4197
+ var XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX = /^<([A-Za-z_][A-Za-z0-9_-]*)\s*\r?\n([\s\S]+?)\r?\n\s*\/>\s*$/;
4198
+ function tryRepairXmlSelfClosingRootWithBody(rawText, toolNames) {
4199
+ const trimmed = rawText.trim();
4200
+ if (trimmed.length === 0) {
4201
+ return null;
4202
+ }
4203
+ const match = trimmed.match(XML_SELF_CLOSING_ROOT_WITH_BODY_REGEX);
4204
+ if (!match) {
4205
+ return null;
4206
+ }
4207
+ const rootTag = match[1];
4208
+ if (!toolNames.includes(rootTag)) {
4209
+ return null;
4210
+ }
4211
+ const body = match[2].trimEnd();
4212
+ if (body.trim().length === 0 || body.includes(`</${rootTag}>`)) {
4213
+ return null;
4214
+ }
4215
+ return `<${rootTag}>
4216
+ ${body}
4217
+ </${rootTag}>`;
4218
+ }
3830
4219
 
3831
4220
  // src/core/protocols/xml-protocol.ts
3832
4221
  function getToolSchema(tools, toolName) {
@@ -3930,7 +4319,7 @@ function consumeClosingTag(text, lt) {
3930
4319
  }
3931
4320
  function consumeOpenTag(text, lt) {
3932
4321
  let p = lt + 1;
3933
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
4322
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3934
4323
  p += 1;
3935
4324
  }
3936
4325
  const nameStart = p;
@@ -3943,7 +4332,7 @@ function consumeOpenTag(text, lt) {
3943
4332
  return null;
3944
4333
  }
3945
4334
  let r = q - 1;
3946
- while (r >= nameStart && WHITESPACE_REGEX4.test(text[r])) {
4335
+ while (r >= nameStart && WHITESPACE_REGEX5.test(text[r])) {
3947
4336
  r -= 1;
3948
4337
  }
3949
4338
  const selfClosing = text[r] === "/";
@@ -3972,7 +4361,7 @@ function nextTagToken(text, fromPos) {
3972
4361
  if (next === "/") {
3973
4362
  const closing = consumeClosingTag(text, lt);
3974
4363
  let p = lt + 2;
3975
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
4364
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
3976
4365
  p += 1;
3977
4366
  }
3978
4367
  const nameStart = p;
@@ -4109,6 +4498,102 @@ function findToolCalls(text, toolNames) {
4109
4498
  }
4110
4499
  return toolCalls.sort((a, b) => a.startIndex - b.startIndex);
4111
4500
  }
4501
+ function handleSpecialToken(depth) {
4502
+ return { depth, lastCompleteEnd: -1, shouldBreak: false };
4503
+ }
4504
+ function handleOpenToken(token, depth, lastCompleteEnd) {
4505
+ if (token.selfClosing) {
4506
+ return {
4507
+ depth,
4508
+ lastCompleteEnd: depth === 0 ? token.nextPos : lastCompleteEnd,
4509
+ shouldBreak: false
4510
+ };
4511
+ }
4512
+ return { depth: depth + 1, lastCompleteEnd, shouldBreak: false };
4513
+ }
4514
+ function handleCloseToken(token, depth) {
4515
+ if (depth <= 0) {
4516
+ return { depth, lastCompleteEnd: -1, shouldBreak: true };
4517
+ }
4518
+ const newDepth = depth - 1;
4519
+ return {
4520
+ depth: newDepth,
4521
+ lastCompleteEnd: newDepth === 0 ? token.nextPos : -1,
4522
+ shouldBreak: false
4523
+ };
4524
+ }
4525
+ function findLinePrefixedXmlBodyEnd(text, bodyStartIndex) {
4526
+ let cursor = bodyStartIndex;
4527
+ let depth = 0;
4528
+ let lastCompleteEnd = -1;
4529
+ while (cursor < text.length) {
4530
+ if (depth === 0) {
4531
+ cursor = consumeWhitespace(text, cursor);
4532
+ if (cursor >= text.length || text.charAt(cursor) !== "<") {
4533
+ break;
4534
+ }
4535
+ }
4536
+ const token = nextTagToken(text, cursor);
4537
+ if (token.kind === "eof") {
4538
+ break;
4539
+ }
4540
+ let result;
4541
+ if (token.kind === "special") {
4542
+ result = handleSpecialToken(depth);
4543
+ } else if (token.kind === "open") {
4544
+ result = handleOpenToken(token, depth, lastCompleteEnd);
4545
+ } else {
4546
+ result = handleCloseToken(token, depth);
4547
+ }
4548
+ depth = result.depth;
4549
+ if (result.lastCompleteEnd !== -1) {
4550
+ lastCompleteEnd = result.lastCompleteEnd;
4551
+ }
4552
+ if (result.shouldBreak) {
4553
+ break;
4554
+ }
4555
+ cursor = token.nextPos;
4556
+ }
4557
+ return lastCompleteEnd;
4558
+ }
4559
+ function findLinePrefixedToolCall(text, toolNames) {
4560
+ var _a;
4561
+ let best = null;
4562
+ for (const toolName of toolNames) {
4563
+ const linePattern = new RegExp(
4564
+ `(^|\\n)[\\t ]*${escapeRegExp(toolName)}[\\t ]*:?[\\t ]*(?:\\r?\\n|$)`,
4565
+ "g"
4566
+ );
4567
+ let match = linePattern.exec(text);
4568
+ while (match !== null) {
4569
+ const prefix = (_a = match[1]) != null ? _a : "";
4570
+ const startIndex = match.index + prefix.length;
4571
+ const contentStart = consumeWhitespace(text, linePattern.lastIndex);
4572
+ if (contentStart >= text.length || text.charAt(contentStart) !== "<") {
4573
+ match = linePattern.exec(text);
4574
+ continue;
4575
+ }
4576
+ const contentEnd = findLinePrefixedXmlBodyEnd(text, contentStart);
4577
+ if (contentEnd === -1 || contentEnd <= contentStart) {
4578
+ match = linePattern.exec(text);
4579
+ continue;
4580
+ }
4581
+ const content = text.slice(contentStart, contentEnd);
4582
+ const candidate = {
4583
+ toolName,
4584
+ startIndex,
4585
+ endIndex: contentEnd,
4586
+ content,
4587
+ segment: text.slice(startIndex, contentEnd)
4588
+ };
4589
+ if (best === null || candidate.startIndex < best.startIndex) {
4590
+ best = candidate;
4591
+ }
4592
+ break;
4593
+ }
4594
+ }
4595
+ return best;
4596
+ }
4112
4597
  function findEarliestToolTag(buffer, toolNames) {
4113
4598
  var _a, _b;
4114
4599
  let bestIndex = -1;
@@ -4147,7 +4632,7 @@ function isOpenTagPrefix(suffix, toolName) {
4147
4632
  }
4148
4633
  function consumeWhitespace(text, index) {
4149
4634
  let i = index;
4150
- while (i < text.length && WHITESPACE_REGEX4.test(text.charAt(i))) {
4635
+ while (i < text.length && WHITESPACE_REGEX5.test(text.charAt(i))) {
4151
4636
  i += 1;
4152
4637
  }
4153
4638
  return i;
@@ -4398,6 +4883,27 @@ function createProcessBufferHandler(getBuffer, setBuffer, getCurrentToolCall, se
4398
4883
  }
4399
4884
  };
4400
4885
  }
4886
+ function findToolCallsWithFallbacks(text, toolNames) {
4887
+ let parseText = text;
4888
+ let toolCalls = findToolCalls(parseText, toolNames);
4889
+ if (toolCalls.length === 0) {
4890
+ const fallbackToolCall = findLinePrefixedToolCall(parseText, toolNames);
4891
+ if (fallbackToolCall !== null) {
4892
+ toolCalls.push(fallbackToolCall);
4893
+ }
4894
+ }
4895
+ if (toolCalls.length === 0) {
4896
+ const repaired = tryRepairXmlSelfClosingRootWithBody(parseText, toolNames);
4897
+ if (repaired) {
4898
+ const repairedCalls = findToolCalls(repaired, toolNames);
4899
+ if (repairedCalls.length > 0) {
4900
+ parseText = repaired;
4901
+ toolCalls = repairedCalls;
4902
+ }
4903
+ }
4904
+ }
4905
+ return { parseText, toolCalls };
4906
+ }
4401
4907
  var xmlProtocol = (protocolOptions) => {
4402
4908
  var _a;
4403
4909
  const parseOptions = {
@@ -4431,28 +4937,31 @@ var xmlProtocol = (protocolOptions) => {
4431
4937
  }
4432
4938
  const processedElements = [];
4433
4939
  let currentIndex = 0;
4434
- const toolCalls = findToolCalls(text, toolNames);
4940
+ const { parseText, toolCalls } = findToolCallsWithFallbacks(
4941
+ text,
4942
+ toolNames
4943
+ );
4435
4944
  for (const tc of toolCalls) {
4436
4945
  if (tc.startIndex > currentIndex) {
4437
4946
  processedElements.push({
4438
4947
  type: "text",
4439
- text: text.substring(currentIndex, tc.startIndex)
4948
+ text: parseText.substring(currentIndex, tc.startIndex)
4440
4949
  });
4441
4950
  }
4442
4951
  processToolCall({
4443
4952
  toolCall: tc,
4444
4953
  tools,
4445
4954
  options,
4446
- text,
4955
+ text: parseText,
4447
4956
  processedElements,
4448
4957
  parseOptions
4449
4958
  });
4450
4959
  currentIndex = tc.endIndex;
4451
4960
  }
4452
- if (currentIndex < text.length) {
4961
+ if (currentIndex < parseText.length) {
4453
4962
  processedElements.push({
4454
4963
  type: "text",
4455
- text: text.substring(currentIndex)
4964
+ text: parseText.substring(currentIndex)
4456
4965
  });
4457
4966
  }
4458
4967
  return processedElements;
@@ -4491,6 +5000,20 @@ var xmlProtocol = (protocolOptions) => {
4491
5000
  return new TransformStream({
4492
5001
  transform(chunk, controller) {
4493
5002
  var _a2;
5003
+ if (chunk.type === "finish") {
5004
+ if (currentToolCall) {
5005
+ const unfinishedContent = `<${currentToolCall.name}>${currentToolCall.content}${buffer}`;
5006
+ flushText(controller, unfinishedContent);
5007
+ buffer = "";
5008
+ currentToolCall = null;
5009
+ } else if (buffer) {
5010
+ flushText(controller, buffer);
5011
+ buffer = "";
5012
+ }
5013
+ flushText(controller);
5014
+ controller.enqueue(chunk);
5015
+ return;
5016
+ }
4494
5017
  if (chunk.type !== "text-delta") {
4495
5018
  if (buffer) {
4496
5019
  flushText(controller, buffer);
@@ -4552,7 +5075,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4552
5075
  break;
4553
5076
  }
4554
5077
  let p = ltIdx + 2;
4555
- while (p < gtIdx && WHITESPACE_REGEX4.test(text[p])) {
5078
+ while (p < gtIdx && WHITESPACE_REGEX5.test(text[p])) {
4556
5079
  p++;
4557
5080
  }
4558
5081
  const nameStart = p;
@@ -4572,7 +5095,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4572
5095
  pos = gtIdx === -1 ? text.length : gtIdx + 1;
4573
5096
  } else {
4574
5097
  let p = ltIdx + 1;
4575
- while (p < text.length && WHITESPACE_REGEX4.test(text[p])) {
5098
+ while (p < text.length && WHITESPACE_REGEX5.test(text[p])) {
4576
5099
  p++;
4577
5100
  }
4578
5101
  const nameStart = p;
@@ -4585,7 +5108,7 @@ function findClosingTagEnd(text, contentStart, toolName) {
4585
5108
  break;
4586
5109
  }
4587
5110
  let r = gtIdx - 1;
4588
- while (r >= nameStart && WHITESPACE_REGEX4.test(text[r])) {
5111
+ while (r >= nameStart && WHITESPACE_REGEX5.test(text[r])) {
4589
5112
  r--;
4590
5113
  }
4591
5114
  const selfClosing = text[r] === "/";
@@ -4817,18 +5340,32 @@ ${yamlContent}</${toolCall.toolName}>`;
4817
5340
  }
4818
5341
  const processedElements = [];
4819
5342
  let currentIndex = 0;
4820
- const toolCalls = findToolCalls2(text, toolNames);
5343
+ let parseText = text;
5344
+ let toolCalls = findToolCalls2(parseText, toolNames);
5345
+ if (toolCalls.length === 0) {
5346
+ const repaired = tryRepairXmlSelfClosingRootWithBody(
5347
+ parseText,
5348
+ toolNames
5349
+ );
5350
+ if (repaired) {
5351
+ const repairedCalls = findToolCalls2(repaired, toolNames);
5352
+ if (repairedCalls.length > 0) {
5353
+ parseText = repaired;
5354
+ toolCalls = repairedCalls;
5355
+ }
5356
+ }
5357
+ }
4821
5358
  for (const tc of toolCalls) {
4822
5359
  currentIndex = processToolCallMatch(
4823
- text,
5360
+ parseText,
4824
5361
  tc,
4825
5362
  currentIndex,
4826
5363
  processedElements,
4827
5364
  options
4828
5365
  );
4829
5366
  }
4830
- if (currentIndex < text.length) {
4831
- addTextSegment(text.substring(currentIndex), processedElements);
5367
+ if (currentIndex < parseText.length) {
5368
+ addTextSegment(parseText.substring(currentIndex), processedElements);
4832
5369
  }
4833
5370
  return processedElements;
4834
5371
  },
@@ -4924,6 +5461,20 @@ ${yamlContent}</${toolCall.toolName}>`;
4924
5461
  return new TransformStream({
4925
5462
  transform(chunk, controller) {
4926
5463
  var _a;
5464
+ if (chunk.type === "finish") {
5465
+ if (currentToolCall) {
5466
+ const unfinishedContent = `<${currentToolCall.name}>${buffer}`;
5467
+ flushText(controller, unfinishedContent);
5468
+ buffer = "";
5469
+ currentToolCall = null;
5470
+ } else if (buffer) {
5471
+ flushText(controller, buffer);
5472
+ buffer = "";
5473
+ }
5474
+ flushText(controller);
5475
+ controller.enqueue(chunk);
5476
+ return;
5477
+ }
4927
5478
  if (chunk.type !== "text-delta") {
4928
5479
  if (buffer) {
4929
5480
  flushText(controller, buffer);
@@ -5047,17 +5598,56 @@ function encodeOriginalTools(tools) {
5047
5598
  inputSchema: JSON.stringify(t.inputSchema)
5048
5599
  }))) || [];
5049
5600
  }
5050
- function decodeOriginalTools(originalTools) {
5601
+ function decodeOriginalTools(originalTools, options) {
5602
+ var _a, _b, _c;
5051
5603
  if (!originalTools) {
5052
5604
  return [];
5053
5605
  }
5054
- return originalTools.map(
5055
- (t) => ({
5056
- type: "function",
5057
- name: t.name,
5058
- inputSchema: JSON.parse(t.inputSchema)
5059
- })
5060
- );
5606
+ const decodedTools = [];
5607
+ for (const [index, tool] of originalTools.entries()) {
5608
+ if (!tool || typeof tool.name !== "string") {
5609
+ (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, "Invalid originalTools entry: missing tool name", {
5610
+ index,
5611
+ tool
5612
+ });
5613
+ continue;
5614
+ }
5615
+ if (typeof tool.inputSchema !== "string") {
5616
+ (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5617
+ options,
5618
+ "Invalid originalTools entry: inputSchema must be a string",
5619
+ {
5620
+ index,
5621
+ toolName: tool.name
5622
+ }
5623
+ );
5624
+ continue;
5625
+ }
5626
+ try {
5627
+ decodedTools.push({
5628
+ type: "function",
5629
+ name: tool.name,
5630
+ inputSchema: JSON.parse(tool.inputSchema)
5631
+ });
5632
+ } catch (error) {
5633
+ (_c = options == null ? void 0 : options.onError) == null ? void 0 : _c.call(
5634
+ options,
5635
+ "Failed to decode originalTools input schema, using permissive fallback schema",
5636
+ {
5637
+ index,
5638
+ toolName: tool.name,
5639
+ inputSchema: tool.inputSchema,
5640
+ error: error instanceof Error ? error.message : String(error)
5641
+ }
5642
+ );
5643
+ decodedTools.push({
5644
+ type: "function",
5645
+ name: tool.name,
5646
+ inputSchema: { type: "object" }
5647
+ });
5648
+ }
5649
+ }
5650
+ return decodedTools;
5061
5651
  }
5062
5652
  function extractToolNamesFromOriginalTools(originalTools) {
5063
5653
  return (originalTools == null ? void 0 : originalTools.map((t) => t.name)) || [];
@@ -5082,23 +5672,337 @@ function hasInputProperty(obj) {
5082
5672
 
5083
5673
  // src/generate-handler.ts
5084
5674
  var import_provider_utils = require("@ai-sdk/provider-utils");
5085
- function parseToolChoiceJson(text, providerOptions) {
5675
+
5676
+ // src/core/utils/generated-text-json-recovery.ts
5677
+ function isRecord(value) {
5678
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5679
+ }
5680
+ function safeStringify2(value) {
5681
+ try {
5682
+ return JSON.stringify(value != null ? value : {});
5683
+ } catch (e) {
5684
+ return "{}";
5685
+ }
5686
+ }
5687
+ function parseJsonCandidate(candidateText) {
5688
+ try {
5689
+ return parse(candidateText);
5690
+ } catch (e) {
5691
+ return void 0;
5692
+ }
5693
+ }
5694
+ function extractCodeBlockCandidates(text) {
5695
+ var _a, _b;
5696
+ const codeBlockRegex = /```(?:json|yaml|xml)?\s*([\s\S]*?)```/gi;
5697
+ const candidates = [];
5698
+ let match;
5699
+ while (true) {
5700
+ match = codeBlockRegex.exec(text);
5701
+ if (!match) {
5702
+ break;
5703
+ }
5704
+ const body = (_a = match[1]) == null ? void 0 : _a.trim();
5705
+ if (body) {
5706
+ const startIndex = (_b = match.index) != null ? _b : 0;
5707
+ const endIndex = startIndex + match[0].length;
5708
+ candidates.push({
5709
+ text: body,
5710
+ startIndex,
5711
+ endIndex
5712
+ });
5713
+ }
5714
+ }
5715
+ return candidates;
5716
+ }
5717
+ function scanJsonChar(state, char) {
5718
+ if (state.inString) {
5719
+ if (state.escaping) {
5720
+ return { ...state, escaping: false };
5721
+ }
5722
+ if (char === "\\") {
5723
+ return { ...state, escaping: true };
5724
+ }
5725
+ if (char === '"') {
5726
+ return { ...state, inString: false };
5727
+ }
5728
+ return state;
5729
+ }
5730
+ if (char === '"') {
5731
+ return { ...state, inString: true };
5732
+ }
5733
+ if (char === "{") {
5734
+ return { ...state, depth: state.depth + 1 };
5735
+ }
5736
+ if (char === "}") {
5737
+ return { ...state, depth: Math.max(0, state.depth - 1) };
5738
+ }
5739
+ return state;
5740
+ }
5741
+ function extractBalancedJsonObjects(text) {
5742
+ const maxCandidateLength = 1e4;
5743
+ const candidates = [];
5744
+ let state = { depth: 0, inString: false, escaping: false };
5745
+ let currentStart = null;
5746
+ let ignoreCurrent = false;
5747
+ for (let index = 0; index < text.length; index += 1) {
5748
+ const char = text[index];
5749
+ if (!state.inString && char === "{" && state.depth === 0) {
5750
+ currentStart = index;
5751
+ ignoreCurrent = false;
5752
+ }
5753
+ state = scanJsonChar(state, char);
5754
+ if (currentStart !== null && !ignoreCurrent && index - currentStart + 1 > maxCandidateLength) {
5755
+ ignoreCurrent = true;
5756
+ }
5757
+ if (!state.inString && char === "}" && state.depth === 0) {
5758
+ if (currentStart !== null && !ignoreCurrent) {
5759
+ const endIndex = index + 1;
5760
+ const candidate = text.slice(currentStart, endIndex);
5761
+ if (candidate.length > 1) {
5762
+ candidates.push({
5763
+ text: candidate,
5764
+ startIndex: currentStart,
5765
+ endIndex
5766
+ });
5767
+ }
5768
+ }
5769
+ currentStart = null;
5770
+ ignoreCurrent = false;
5771
+ }
5772
+ }
5773
+ return candidates;
5774
+ }
5775
+ function extractTaggedToolCallCandidates(rawText) {
5776
+ var _a, _b;
5777
+ const toolCallRegex = /<tool_call>([\s\S]*?)<\/tool_call>/gi;
5778
+ const candidates = [];
5779
+ let match;
5780
+ while (true) {
5781
+ match = toolCallRegex.exec(rawText);
5782
+ if (!match) {
5783
+ break;
5784
+ }
5785
+ const body = (_a = match[1]) == null ? void 0 : _a.trim();
5786
+ if (!body) {
5787
+ continue;
5788
+ }
5789
+ const startIndex = (_b = match.index) != null ? _b : 0;
5790
+ const endIndex = startIndex + match[0].length;
5791
+ candidates.push({
5792
+ text: body,
5793
+ startIndex,
5794
+ endIndex
5795
+ });
5796
+ }
5797
+ return candidates;
5798
+ }
5799
+ function extractJsonLikeCandidates(rawText) {
5800
+ return mergeJsonCandidatesByStart(
5801
+ extractTaggedToolCallCandidates(rawText),
5802
+ extractCodeBlockCandidates(rawText),
5803
+ extractBalancedJsonObjects(rawText)
5804
+ );
5805
+ }
5806
+ function mergeJsonCandidatesByStart(tagged, codeBlocks, balanced) {
5807
+ return [...tagged, ...codeBlocks, ...balanced].sort(
5808
+ (a, b) => a.startIndex !== b.startIndex ? a.startIndex - b.startIndex : b.endIndex - a.endIndex
5809
+ );
5810
+ }
5811
+ function toToolCallPart(candidate) {
5812
+ return {
5813
+ type: "tool-call",
5814
+ toolCallId: generateId(),
5815
+ toolName: candidate.toolName,
5816
+ input: candidate.input
5817
+ };
5818
+ }
5819
+ function toRecoveredParts(text, candidate, toolCallPart) {
5820
+ const out = [];
5821
+ const prefix = text.slice(0, candidate.startIndex);
5822
+ if (prefix.length > 0) {
5823
+ out.push({ type: "text", text: prefix });
5824
+ }
5825
+ out.push(toolCallPart);
5826
+ const suffix = text.slice(candidate.endIndex);
5827
+ if (suffix.length > 0) {
5828
+ out.push({ type: "text", text: suffix });
5829
+ }
5830
+ return out;
5831
+ }
5832
+ function parseAsToolPayload(payload, tools) {
5833
+ if (!isRecord(payload)) {
5834
+ return null;
5835
+ }
5836
+ const toolName = typeof payload.name === "string" && payload.name.trim().length > 0 ? payload.name.trim() : null;
5837
+ if (!toolName) {
5838
+ return null;
5839
+ }
5840
+ if (!tools.some((tool) => tool.name === toolName)) {
5841
+ return null;
5842
+ }
5843
+ const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
5844
+ if (!isRecord(rawArgs)) {
5845
+ return null;
5846
+ }
5847
+ return {
5848
+ toolName,
5849
+ input: safeStringify2(rawArgs)
5850
+ };
5851
+ }
5852
+ function isLikelyArgumentsShapeForTool(args, tool) {
5853
+ const unwrapped = unwrapJsonSchema(tool.inputSchema);
5854
+ if (!isRecord(unwrapped)) {
5855
+ return false;
5856
+ }
5857
+ if (getSchemaType(unwrapped) !== "object") {
5858
+ return false;
5859
+ }
5860
+ const properties = unwrapped.properties;
5861
+ if (!isRecord(properties)) {
5862
+ return false;
5863
+ }
5864
+ const keys = Object.keys(args);
5865
+ if (keys.length === 0) {
5866
+ return false;
5867
+ }
5868
+ const knownKeys = keys.filter((key) => Object.hasOwn(properties, key));
5869
+ if (knownKeys.length === 0) {
5870
+ return false;
5871
+ }
5872
+ if (unwrapped.additionalProperties === false && knownKeys.length !== keys.length) {
5873
+ return false;
5874
+ }
5875
+ return true;
5876
+ }
5877
+ function parseAsArgumentsOnly(payload, tools) {
5878
+ if (tools.length !== 1) {
5879
+ return null;
5880
+ }
5881
+ if (!isRecord(payload)) {
5882
+ return null;
5883
+ }
5884
+ const hasNameEnvelope = Object.hasOwn(payload, "name") && typeof payload.name === "string" && payload.name.length > 0;
5885
+ const hasArgumentsEnvelope = Object.hasOwn(payload, "arguments") && (typeof payload.arguments === "string" || isRecord(payload.arguments));
5886
+ if (hasNameEnvelope || hasArgumentsEnvelope) {
5887
+ return null;
5888
+ }
5889
+ const tool = tools[0];
5890
+ if (!isLikelyArgumentsShapeForTool(payload, tool)) {
5891
+ return null;
5892
+ }
5893
+ return {
5894
+ toolName: tool.name,
5895
+ input: safeStringify2(payload)
5896
+ };
5897
+ }
5898
+ function recoverToolCallFromJsonCandidates(text, tools) {
5899
+ if (tools.length === 0) {
5900
+ return null;
5901
+ }
5902
+ const jsonCandidates = extractJsonLikeCandidates(text);
5903
+ for (const jsonCandidate of jsonCandidates) {
5904
+ const parsed = parseJsonCandidate(jsonCandidate.text);
5905
+ if (parsed === void 0) {
5906
+ continue;
5907
+ }
5908
+ const toolPayload = parseAsToolPayload(parsed, tools);
5909
+ if (toolPayload) {
5910
+ return toRecoveredParts(text, jsonCandidate, toToolCallPart(toolPayload));
5911
+ }
5912
+ const argsPayload = parseAsArgumentsOnly(parsed, tools);
5913
+ if (argsPayload) {
5914
+ return toRecoveredParts(text, jsonCandidate, toToolCallPart(argsPayload));
5915
+ }
5916
+ }
5917
+ return null;
5918
+ }
5919
+
5920
+ // src/core/utils/tool-call-coercion.ts
5921
+ function coerceToolCallInput(toolName, input, tools) {
5086
5922
  var _a;
5923
+ let args = {};
5924
+ if (typeof input === "string") {
5925
+ try {
5926
+ args = JSON.parse(input);
5927
+ } catch (e) {
5928
+ return;
5929
+ }
5930
+ } else if (input && typeof input === "object") {
5931
+ args = input;
5932
+ } else {
5933
+ return;
5934
+ }
5935
+ const schema = (_a = tools.find((t) => t.name === toolName)) == null ? void 0 : _a.inputSchema;
5936
+ const coerced = coerceBySchema(args, schema);
5937
+ return JSON.stringify(coerced != null ? coerced : {});
5938
+ }
5939
+ function coerceToolCallPart(part, tools) {
5940
+ const coercedInput = coerceToolCallInput(part.toolName, part.input, tools);
5941
+ if (coercedInput === void 0) {
5942
+ return part;
5943
+ }
5944
+ return {
5945
+ ...part,
5946
+ input: coercedInput
5947
+ };
5948
+ }
5949
+
5950
+ // src/core/utils/tool-choice.ts
5951
+ function ensureNonEmptyToolName(name) {
5952
+ if (typeof name !== "string") {
5953
+ return "unknown";
5954
+ }
5955
+ const trimmed = name.trim();
5956
+ return trimmed.length > 0 ? trimmed : "unknown";
5957
+ }
5958
+ function safeStringify3(value) {
5959
+ try {
5960
+ return JSON.stringify(value != null ? value : {});
5961
+ } catch (e) {
5962
+ return "{}";
5963
+ }
5964
+ }
5965
+ function parseToolChoicePayload({
5966
+ text,
5967
+ tools,
5968
+ onError,
5969
+ errorMessage
5970
+ }) {
5971
+ let parsed;
5087
5972
  try {
5088
- return JSON.parse(text);
5973
+ parsed = JSON.parse(text);
5089
5974
  } catch (error) {
5090
- const options = extractOnErrorOption(providerOptions);
5091
- (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(
5092
- options,
5093
- "Failed to parse toolChoice JSON from generated model output",
5094
- {
5095
- text,
5096
- error: error instanceof Error ? error.message : String(error)
5097
- }
5098
- );
5099
- return {};
5975
+ onError == null ? void 0 : onError(errorMessage, {
5976
+ text,
5977
+ error: error instanceof Error ? error.message : String(error)
5978
+ });
5979
+ return { toolName: "unknown", input: "{}" };
5980
+ }
5981
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
5982
+ onError == null ? void 0 : onError("toolChoice JSON payload must be an object", {
5983
+ parsedType: typeof parsed,
5984
+ parsed
5985
+ });
5986
+ return { toolName: "unknown", input: "{}" };
5100
5987
  }
5988
+ const payload = parsed;
5989
+ const toolName = ensureNonEmptyToolName(payload.name);
5990
+ const rawArgs = Object.hasOwn(payload, "arguments") ? payload.arguments : {};
5991
+ if (rawArgs == null || typeof rawArgs !== "object" || Array.isArray(rawArgs)) {
5992
+ onError == null ? void 0 : onError("toolChoice arguments must be a JSON object", {
5993
+ toolName,
5994
+ arguments: rawArgs
5995
+ });
5996
+ return { toolName, input: "{}" };
5997
+ }
5998
+ const coercedInput = coerceToolCallInput(toolName, rawArgs, tools);
5999
+ return {
6000
+ toolName,
6001
+ input: coercedInput != null ? coercedInput : safeStringify3(rawArgs)
6002
+ };
5101
6003
  }
6004
+
6005
+ // src/generate-handler.ts
5102
6006
  function logDebugSummary(debugSummary, toolCall, originText) {
5103
6007
  if (debugSummary) {
5104
6008
  debugSummary.originalText = originText;
@@ -5112,25 +6016,34 @@ function logDebugSummary(debugSummary, toolCall, originText) {
5112
6016
  logParsedSummary({ toolCalls: [toolCall], originalText: originText });
5113
6017
  }
5114
6018
  }
5115
- async function handleToolChoice(doGenerate, params) {
5116
- var _a, _b, _c;
6019
+ async function handleToolChoice(doGenerate, params, tools) {
6020
+ var _a, _b, _c, _d;
5117
6021
  const result = await doGenerate();
5118
6022
  const first = (_a = result.content) == null ? void 0 : _a[0];
5119
- let parsed = {};
6023
+ const onError = (_b = extractOnErrorOption(params.providerOptions)) == null ? void 0 : _b.onError;
6024
+ let toolName = "unknown";
6025
+ let input = "{}";
5120
6026
  if (first && first.type === "text") {
5121
6027
  if (getDebugLevel() === "parse") {
5122
6028
  logRawChunk(first.text);
5123
6029
  }
5124
- parsed = parseToolChoiceJson(first.text, params.providerOptions);
6030
+ const parsed = parseToolChoicePayload({
6031
+ text: first.text,
6032
+ tools,
6033
+ onError,
6034
+ errorMessage: "Failed to parse toolChoice JSON from generated model output"
6035
+ });
6036
+ toolName = parsed.toolName;
6037
+ input = parsed.input;
5125
6038
  }
5126
6039
  const toolCall = {
5127
6040
  type: "tool-call",
5128
6041
  toolCallId: (0, import_provider_utils.generateId)(),
5129
- toolName: parsed.name || "unknown",
5130
- input: JSON.stringify(parsed.arguments || {})
6042
+ toolName,
6043
+ input
5131
6044
  };
5132
6045
  const originText = first && first.type === "text" ? first.text : "";
5133
- const debugSummary = (_c = (_b = params.providerOptions) == null ? void 0 : _b.toolCallMiddleware) == null ? void 0 : _c.debugSummary;
6046
+ const debugSummary = (_d = (_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) == null ? void 0 : _d.debugSummary;
5134
6047
  logDebugSummary(debugSummary, toolCall, originText);
5135
6048
  return {
5136
6049
  ...result,
@@ -5145,7 +6058,7 @@ function parseContent(content, protocol, tools, providerOptions) {
5145
6058
  if (getDebugLevel() === "stream") {
5146
6059
  logRawChunk(contentItem.text);
5147
6060
  }
5148
- return protocol.parseGeneratedText({
6061
+ const parsedByProtocol = protocol.parseGeneratedText({
5149
6062
  text: contentItem.text,
5150
6063
  tools,
5151
6064
  options: {
@@ -5153,9 +6066,20 @@ function parseContent(content, protocol, tools, providerOptions) {
5153
6066
  ...providerOptions == null ? void 0 : providerOptions.toolCallMiddleware
5154
6067
  }
5155
6068
  });
6069
+ const hasToolCall = parsedByProtocol.some(
6070
+ (part) => part.type === "tool-call"
6071
+ );
6072
+ if (hasToolCall) {
6073
+ return parsedByProtocol;
6074
+ }
6075
+ const recoveredFromJson = recoverToolCallFromJsonCandidates(
6076
+ contentItem.text,
6077
+ tools
6078
+ );
6079
+ return recoveredFromJson != null ? recoveredFromJson : parsedByProtocol;
5156
6080
  });
5157
6081
  return parsed.map(
5158
- (part) => fixToolCallWithSchema(part, tools)
6082
+ (part) => part.type === "tool-call" ? coerceToolCallPart(part, tools) : part
5159
6083
  );
5160
6084
  }
5161
6085
  function logParsedContent(content) {
@@ -5198,12 +6122,14 @@ async function wrapGenerate({
5198
6122
  params
5199
6123
  }) {
5200
6124
  var _a, _b;
5201
- if (isToolChoiceActive(params)) {
5202
- return handleToolChoice(doGenerate, params);
5203
- }
6125
+ const onError = extractOnErrorOption(params.providerOptions);
5204
6126
  const tools = originalToolsSchema.decode(
5205
- (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
6127
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
6128
+ onError
5206
6129
  );
6130
+ if (isToolChoiceActive(params)) {
6131
+ return handleToolChoice(doGenerate, params, tools);
6132
+ }
5207
6133
  const result = await doGenerate();
5208
6134
  if (result.content.length === 0) {
5209
6135
  return result;
@@ -5227,28 +6153,6 @@ async function wrapGenerate({
5227
6153
  content: newContent
5228
6154
  };
5229
6155
  }
5230
- function fixToolCallWithSchema(part, tools) {
5231
- var _a;
5232
- if (part.type !== "tool-call") {
5233
- return part;
5234
- }
5235
- let args = {};
5236
- if (typeof part.input === "string") {
5237
- try {
5238
- args = JSON.parse(part.input);
5239
- } catch (e) {
5240
- return part;
5241
- }
5242
- } else if (part.input && typeof part.input === "object") {
5243
- args = part.input;
5244
- }
5245
- const schema = (_a = tools.find((t) => t.name === part.toolName)) == null ? void 0 : _a.inputSchema;
5246
- const coerced = coerceBySchema(args, schema);
5247
- return {
5248
- ...part,
5249
- input: JSON.stringify(coerced != null ? coerced : {})
5250
- };
5251
- }
5252
6156
 
5253
6157
  // src/core/prompts/hermes-system-prompt.ts
5254
6158
  function hermesSystemPromptTemplate(tools) {
@@ -5652,19 +6556,22 @@ async function wrapStream({
5652
6556
  params
5653
6557
  }) {
5654
6558
  var _a, _b, _c;
6559
+ const onErrorOptions = extractOnErrorOption(params.providerOptions);
6560
+ const tools = originalToolsSchema.decode(
6561
+ (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools,
6562
+ onErrorOptions
6563
+ );
5655
6564
  if (isToolChoiceActive(params)) {
5656
6565
  return toolChoiceStream({
5657
6566
  doGenerate,
5658
- options: extractOnErrorOption(params.providerOptions)
6567
+ tools,
6568
+ options: onErrorOptions
5659
6569
  });
5660
6570
  }
5661
6571
  const { stream, ...rest } = await doStream();
5662
6572
  const debugLevel = getDebugLevel();
5663
- const tools = originalToolsSchema.decode(
5664
- (_b = (_a = params.providerOptions) == null ? void 0 : _a.toolCallMiddleware) == null ? void 0 : _b.originalTools
5665
- );
5666
6573
  const options = {
5667
- ...extractOnErrorOption(params.providerOptions),
6574
+ ...onErrorOptions,
5668
6575
  ...((_c = params.providerOptions) == null ? void 0 : _c.toolCallMiddleware) || {}
5669
6576
  };
5670
6577
  const coreStream = stream.pipeThrough(
@@ -5682,10 +6589,11 @@ async function wrapStream({
5682
6589
  const v3Stream = coreStream.pipeThrough(
5683
6590
  new TransformStream({
5684
6591
  transform(part, controller) {
6592
+ const normalizedPart = part.type === "tool-call" ? coerceToolCallPart(part, tools) : part;
5685
6593
  if (debugLevel === "stream") {
5686
- logParsedChunk(part);
6594
+ logParsedChunk(normalizedPart);
5687
6595
  }
5688
- controller.enqueue(part);
6596
+ controller.enqueue(normalizedPart);
5689
6597
  }
5690
6598
  })
5691
6599
  );
@@ -5696,41 +6604,36 @@ async function wrapStream({
5696
6604
  }
5697
6605
  async function toolChoiceStream({
5698
6606
  doGenerate,
6607
+ tools,
5699
6608
  options
5700
6609
  }) {
5701
- var _a, _b;
6610
+ var _a;
6611
+ const normalizedTools = Array.isArray(tools) ? tools : [];
5702
6612
  const result = await doGenerate();
5703
- let toolJson = {};
6613
+ let toolName = "unknown";
6614
+ let input = "{}";
5704
6615
  if ((result == null ? void 0 : result.content) && result.content.length > 0 && ((_a = result.content[0]) == null ? void 0 : _a.type) === "text") {
5705
- try {
5706
- toolJson = JSON.parse(result.content[0].text);
5707
- } catch (error) {
5708
- (_b = options == null ? void 0 : options.onError) == null ? void 0 : _b.call(
5709
- options,
5710
- "Failed to parse toolChoice JSON from streamed model output",
5711
- {
5712
- text: result.content[0].text,
5713
- error: error instanceof Error ? error.message : String(error)
5714
- }
5715
- );
5716
- toolJson = {};
5717
- }
6616
+ const parsed = parseToolChoicePayload({
6617
+ text: result.content[0].text,
6618
+ tools: normalizedTools,
6619
+ onError: options == null ? void 0 : options.onError,
6620
+ errorMessage: "Failed to parse toolChoice JSON from streamed model output"
6621
+ });
6622
+ toolName = parsed.toolName;
6623
+ input = parsed.input;
5718
6624
  }
5719
6625
  const stream = new ReadableStream({
5720
6626
  start(controller) {
5721
6627
  controller.enqueue({
5722
6628
  type: "tool-call",
5723
6629
  toolCallId: (0, import_provider_utils2.generateId)(),
5724
- toolName: toolJson.name || "unknown",
5725
- input: JSON.stringify(toolJson.arguments || {})
6630
+ toolName,
6631
+ input
5726
6632
  });
5727
6633
  controller.enqueue({
5728
6634
  type: "finish",
5729
- usage: (result == null ? void 0 : result.usage) || {
5730
- inputTokens: 0,
5731
- outputTokens: 0
5732
- },
5733
- finishReason: "tool-calls"
6635
+ usage: normalizeUsage(result == null ? void 0 : result.usage),
6636
+ finishReason: normalizeToolCallsFinishReason(result == null ? void 0 : result.finishReason)
5734
6637
  });
5735
6638
  controller.close();
5736
6639
  }
@@ -5741,6 +6644,60 @@ async function toolChoiceStream({
5741
6644
  stream
5742
6645
  };
5743
6646
  }
6647
+ var ZERO_USAGE = {
6648
+ inputTokens: {
6649
+ total: 0,
6650
+ noCache: void 0,
6651
+ cacheRead: void 0,
6652
+ cacheWrite: void 0
6653
+ },
6654
+ outputTokens: {
6655
+ total: 0,
6656
+ text: void 0,
6657
+ reasoning: void 0
6658
+ }
6659
+ };
6660
+ function normalizeToolCallsFinishReason(finishReason) {
6661
+ let raw = "tool-calls";
6662
+ if (typeof finishReason === "string") {
6663
+ raw = finishReason;
6664
+ } else if (finishReason && typeof finishReason === "object" && "raw" in finishReason && typeof finishReason.raw === "string") {
6665
+ raw = finishReason.raw;
6666
+ } else if (finishReason && typeof finishReason === "object" && "unified" in finishReason && typeof finishReason.unified === "string") {
6667
+ raw = finishReason.unified;
6668
+ }
6669
+ return {
6670
+ unified: "tool-calls",
6671
+ raw
6672
+ };
6673
+ }
6674
+ function normalizeUsage(usage) {
6675
+ if (!usage || typeof usage !== "object") {
6676
+ return ZERO_USAGE;
6677
+ }
6678
+ const usageRecord = usage;
6679
+ const input = usageRecord.inputTokens;
6680
+ const output = usageRecord.outputTokens;
6681
+ if (input && typeof input === "object" && output && typeof output === "object") {
6682
+ return usage;
6683
+ }
6684
+ if (typeof input === "number" && typeof output === "number") {
6685
+ return {
6686
+ inputTokens: {
6687
+ total: input,
6688
+ noCache: void 0,
6689
+ cacheRead: void 0,
6690
+ cacheWrite: void 0
6691
+ },
6692
+ outputTokens: {
6693
+ total: output,
6694
+ text: void 0,
6695
+ reasoning: void 0
6696
+ }
6697
+ };
6698
+ }
6699
+ return ZERO_USAGE;
6700
+ }
5744
6701
 
5745
6702
  // src/transform-handler.ts
5746
6703
  function buildFinalPrompt(systemPrompt, processedPrompt, placement) {
@@ -5866,6 +6823,11 @@ function handleToolChoiceRequired(params, baseReturnParams, functionTools) {
5866
6823
  "Tool choice type 'required' is set, but no tools are provided in params.tools."
5867
6824
  );
5868
6825
  }
6826
+ if (functionTools.length === 0) {
6827
+ throw new Error(
6828
+ "Tool choice type 'required' is set, but no function tools are provided. Provider-defined tools are not supported by this middleware."
6829
+ );
6830
+ }
5869
6831
  return {
5870
6832
  ...baseReturnParams,
5871
6833
  responseFormat: {