@openclaw/ai 2026.10.1-beta.2 → 2026.10.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +6 -0
  2. package/dist/{anthropic-CZv6XFER.mjs → anthropic-BAHKgWam.mjs} +30 -59
  3. package/dist/{anthropic-payload-policy-BhCcgNdm.d.mts → anthropic-payload-policy-DGblkHL5.d.mts} +19 -16
  4. package/dist/{anthropic-stream-reducer-BQ1tjd7x.mjs → anthropic-stream-reducer-g6w1YVii.mjs} +197 -285
  5. package/dist/{api-registry-DpU0Rj-I.d.mts → api-registry-BhXXYdRA.d.mts} +2 -2
  6. package/dist/assistant-message-events-CHMJgbhs.mjs +18 -0
  7. package/dist/{assistant-output-OLm-Oln0.mjs → assistant-output-CUEeSotf.mjs} +2 -2
  8. package/dist/{assistant-text-phase-Bl1aDCB7.mjs → assistant-text-phase-BrV8KdFO.mjs} +7 -6
  9. package/dist/{azure-openai-responses-DH7bd3QT.mjs → azure-openai-responses-C7qBuR23.mjs} +8 -9
  10. package/dist/{credential-redaction-BKv49aiv.d.mts → credential-redaction-BHxruEH6.d.mts} +3 -1
  11. package/dist/{diagnostics-Caj-4RBA.mjs → diagnostics-tQasYct1.mjs} +10 -3
  12. package/dist/diagnostics.d.mts +7 -7
  13. package/dist/diagnostics.mjs +3 -3
  14. package/dist/{env-api-keys-CyX4VKGO.mjs → env-api-keys-CrxwdylR.mjs} +24 -35
  15. package/dist/event-stream-6UNs-AhN.d.mts +1 -0
  16. package/dist/{event-stream-DrRM_90c.d.mts → event-stream-BcqWLo_u.d.mts} +1 -1
  17. package/dist/{event-stream-C5AbCAaZ.mjs → event-stream-X2gmsUWv.mjs} +5 -8
  18. package/dist/event-stream.d.mts +2 -2
  19. package/dist/event-stream.mjs +1 -1
  20. package/dist/google-Boz2QcpK.mjs +20 -0
  21. package/dist/{google-interactions-wrnE6MLw.mjs → google-interactions-tjAb1mc5.mjs} +52 -84
  22. package/dist/{google-messages-BwPPycw6.mjs → google-messages-C-RZzloH.mjs} +25 -35
  23. package/dist/google-provider-stream-CMImyxbX.mjs +58 -0
  24. package/dist/{google-shared-Eql1OMPU.mjs → google-shared-OyAtMTZv.mjs} +6 -15
  25. package/dist/google-vertex-hCxTJea7.mjs +40 -0
  26. package/dist/{host-BinBeGcQ.d.mts → host-CTDz7LXD.d.mts} +6 -3
  27. package/dist/{host-DCW52iHe.mjs → host-JWXZWa-c.mjs} +12 -8
  28. package/dist/{host-policy-B3jc4Rpn.mjs → host-policy-q4Azym9F.mjs} +1 -1
  29. package/dist/{index-a8e_oKnu.d.mts → index-BYDvopUB.d.mts} +27 -6
  30. package/dist/index.d.mts +7 -7
  31. package/dist/index.mjs +7 -6
  32. package/dist/internal/anthropic.d.mts +6 -6
  33. package/dist/internal/anthropic.mjs +5 -5
  34. package/dist/internal/openai-completions-compat.d.mts +1 -1
  35. package/dist/internal/openai-completions-compat.mjs +1 -1
  36. package/dist/internal/openai-responses-payload-policy.d.mts +8 -1
  37. package/dist/internal/openai-responses-payload-policy.mjs +3 -3
  38. package/dist/internal/openai.d.mts +9 -9
  39. package/dist/internal/openai.mjs +9 -11
  40. package/dist/internal/runtime.d.mts +14 -11
  41. package/dist/internal/runtime.mjs +10 -13
  42. package/dist/internal/shared.d.mts +5 -5
  43. package/dist/internal/shared.mjs +6 -7
  44. package/dist/internal/tool-schema.mjs +2 -2
  45. package/dist/{llm-request-activity-D8f_oxHj.mjs → llm-request-activity-CfMuh5cC.mjs} +2 -2
  46. package/dist/{mistral-DSt4vQAO.mjs → mistral-DUveP4hF.mjs} +71 -146
  47. package/dist/{model-transport-url-C5f59L3Y.d.mts → model-transport-url-BrsjjdjR.d.mts} +5 -1
  48. package/dist/{number-coercion-V8-BhME4.mjs → number-coercion-C3hztWoY.mjs} +5 -4
  49. package/dist/{openai-chatgpt-responses-BC2x0Oqx.mjs → openai-chatgpt-responses-OCwckGhY.mjs} +173 -242
  50. package/dist/{openai-completions-DNyHnXKg.mjs → openai-completions-DOltBUe9.mjs} +7 -6
  51. package/dist/{openai-completions-compat-BYdYpXhU.d.mts → openai-completions-compat-i-nLZxFy.d.mts} +10 -11
  52. package/dist/{openai-completions-compat-BdmlhD4u.mjs → openai-completions-compat-pg1q4uNG.mjs} +10 -6
  53. package/dist/openai-completions-transport-OMrn7gnZ.mjs +3319 -0
  54. package/dist/{openai-prompt-cache-I8YQTzf8.mjs → openai-prompt-cache-Cr2xKVrS.mjs} +1 -1
  55. package/dist/{openai-prompt-cache-45-AH_xv.d.mts → openai-prompt-cache-DIPMrMFy.d.mts} +2 -2
  56. package/dist/{openai-responses-uZ5oWSp7.mjs → openai-responses-BSBJUA19.mjs} +9 -10
  57. package/dist/{openai-responses-compaction-replay-BClApUIf.d.mts → openai-responses-compaction-replay-B2FE4Nw8.d.mts} +4 -4
  58. package/dist/{openai-responses-contracts-Br5IIw_h.d.mts → openai-responses-contracts-DKqMJ1Ct.d.mts} +9 -4
  59. package/dist/{openai-responses-contracts-BKu8O7l4.mjs → openai-responses-contracts-DlKMMTxK.mjs} +26 -6
  60. package/dist/{openai-responses-compaction-window-m878aVpU.mjs → openai-responses-endpoint-CinGh4VZ.mjs} +14 -4
  61. package/dist/{openai-responses-prompt-observer-internal-CCg7B6l4.mjs → openai-responses-request-lifecycle-D2IFiI0-.mjs} +39 -4
  62. package/dist/{openai-responses-shared-C7oVyjED.mjs → openai-responses-shared-DVGhq5xF.mjs} +1036 -327
  63. package/dist/{openai-responses-terminal-usage-DgImcyJu.d.mts → openai-responses-terminal-usage-BygjiAdi.d.mts} +2 -2
  64. package/dist/{openai-tool-schema-DYNePiF8.mjs → openai-tool-schema-DDPXsvJP.mjs} +236 -399
  65. package/dist/{positive-integer-CwLi8LUL.mjs → positive-integer-CqWjqSi9.mjs} +1 -1
  66. package/dist/{provider-error-DQBE1bUQ.mjs → provider-error-CF9GWCs2.mjs} +5 -3
  67. package/dist/{provider-options-D5ABCV_l.d.mts → provider-options-CVrXZBtA.d.mts} +3 -2
  68. package/dist/{provider-transport-turn-state-_M2kLdUE.mjs → provider-transport-turn-state-LuCaTsSO.mjs} +2 -2
  69. package/dist/{provider-types-F8Mqc9Ma.d.mts → provider-types-CHtRx0dI.d.mts} +3 -3
  70. package/dist/provider-types.d.mts +6 -6
  71. package/dist/providers.d.mts +2 -2
  72. package/dist/providers.mjs +12 -12
  73. package/dist/{reasoning-tag-text-partitioner-Ju9VpUGl.mjs → reasoning-tag-text-partitioner-0-Rsezog.mjs} +13 -12
  74. package/dist/{required-api-key-D4kn3252.mjs → required-api-key-CFJvcFy_.mjs} +1 -1
  75. package/dist/{simple-options-BkKTXxhp.mjs → simple-options-BARFAzk9.mjs} +9 -11
  76. package/dist/{src-B0NIt2UK.mjs → src-C_wfIUmV.mjs} +35 -10
  77. package/dist/{stream-DSdzKsDK.mjs → stream-DwrETW0_.mjs} +12 -21
  78. package/dist/{stream-first-event-timeout-D9ZmL_s9.mjs → stream-first-event-timeout-Dc42hKv6.mjs} +8 -21
  79. package/dist/{streaming-byte-guard-CC-HMn_u.mjs → streaming-byte-guard-DBXr1XYn.mjs} +16 -1
  80. package/dist/{string-normalization-PN10hf6d.mjs → string-normalization-I3ux50s9.mjs} +1 -1
  81. package/dist/{text-signature-MLwfi6fq.mjs → text-signature-B_MB6U_9.mjs} +32 -5
  82. package/dist/{tool-schema-json-projection-Ct8SeBeJ.mjs → tool-schema-json-projection-B8sG1I9v.mjs} +29 -23
  83. package/dist/{transport-stream-shared-BcAKh2XH.d.mts → transport-stream-shared-BmpzDtdQ.d.mts} +4 -4
  84. package/dist/{transport-stream-shared-CxXXz_Dd.mjs → transport-stream-shared-DH08b7Il.mjs} +31 -20
  85. package/dist/transports.d.mts +33 -22
  86. package/dist/transports.mjs +73 -1234
  87. package/dist/{types-DvzmWW8J.d.mts → types-Bd2T86VJ.d.mts} +5 -23
  88. package/dist/types-Kdfw_04V.d.mts +1 -0
  89. package/dist/types.d.mts +6 -6
  90. package/dist/types.mjs +5 -4
  91. package/dist/{validation-B3lQt_VE.d.mts → validation-DdGB1yy3.d.mts} +1 -1
  92. package/dist/{validation-DbqlIfDn.mjs → validation-opC2pjk9.mjs} +2 -3
  93. package/dist/validation.d.mts +1 -1
  94. package/dist/validation.mjs +1 -1
  95. package/package.json +4 -4
  96. package/dist/event-stream-DqDQWqiy.d.mts +0 -1
  97. package/dist/google-1WLOtb8w.mjs +0 -54
  98. package/dist/google-vertex-0LrlRoO3.mjs +0 -88
  99. package/dist/openai-completions-transport-DWM2mQDB.mjs +0 -2081
  100. package/dist/openai-responses-request-lifecycle-Fsag-IGZ.mjs +0 -36
  101. package/dist/openai-transport-params-JFsnIyto.mjs +0 -735
  102. package/dist/openai-web-search-tools-Cfu0uLyN.mjs +0 -14
  103. package/dist/provider-replay-context-C7Bmi84a.mjs +0 -25
  104. package/dist/types-BuiEBM3u.d.mts +0 -1
@@ -1,8 +1,8 @@
1
1
  import { o as isRecord } from "./record-coerce-CNDovvft.mjs";
2
2
  import { t as parseLocalSchemaRefPointer } from "./json-schema-Bp07Qui3.mjs";
3
3
  import { n as normalizeLowercaseStringOrEmpty } from "./string-coerce-CtgOVOSv.mjs";
4
- import { i as uniqueValues, t as normalizeStringEntries } from "./string-normalization-PN10hf6d.mjs";
5
- import { a as SCHEMA_OBJECT_KEYS$1, i as SCHEMA_MAP_KEYS$1, o as evaluateSchemaWalk, r as SCHEMA_ARRAY_KEYS$1 } from "./tool-schema-json-projection-Ct8SeBeJ.mjs";
4
+ import { i as uniqueValues, t as normalizeStringEntries } from "./string-normalization-I3ux50s9.mjs";
5
+ import { a as SCHEMA_NESTED_KEYS, c as walkSchemaArray, i as SCHEMA_MAP_KEYS$1, l as walkSchemaValue, o as SCHEMA_OBJECT_KEYS$1, r as SCHEMA_ARRAY_KEYS$1, s as evaluateSchemaWalk } from "./tool-schema-json-projection-B8sG1I9v.mjs";
6
6
  //#region packages/ai/src/providers/clean-for-gemini.ts
7
7
  const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
8
8
  "~optional",
@@ -35,18 +35,11 @@ const SCHEMA_META_KEYS = [
35
35
  ];
36
36
  function copySchemaMeta$1(from, to) {
37
37
  for (const key of SCHEMA_META_KEYS) if (key in from && from[key] !== void 0) to[key] = from[key];
38
- }
39
- function stringifyGeminiEnumValue(value) {
40
- if (typeof value === "string") return value;
41
- if (typeof value === "number" && Number.isFinite(value)) return String(value);
42
- if (typeof value === "boolean") return String(value);
38
+ return to;
43
39
  }
44
40
  function cleanGeminiEnumValues(value) {
45
41
  if (!Array.isArray(value)) return;
46
- const values = value.flatMap((entry) => {
47
- const stringified = stringifyGeminiEnumValue(entry);
48
- return stringified === void 0 ? [] : [stringified];
49
- });
42
+ const values = value.filter((entry) => typeof entry === "string" || typeof entry === "boolean" || typeof entry === "number" && Number.isFinite(entry)).map(String);
50
43
  const unique = [...new Set(values)];
51
44
  return unique.length > 0 ? unique : void 0;
52
45
  }
@@ -62,9 +55,8 @@ function tryFlattenLiteralAnyOf(variants) {
62
55
  else if (Array.isArray(v.enum) && v.enum.length === 1) literalValue = v.enum[0];
63
56
  else return null;
64
57
  const variantType = typeof v.type === "string" ? v.type : null;
65
- if (!variantType) return null;
66
- if (commonType === null) commonType = variantType;
67
- else if (commonType !== variantType) return null;
58
+ if (!variantType || commonType !== null && commonType !== variantType) return null;
59
+ commonType = variantType;
68
60
  allValues.push(literalValue);
69
61
  }
70
62
  if (commonType && allValues.length > 0) return {
@@ -75,21 +67,17 @@ function tryFlattenLiteralAnyOf(variants) {
75
67
  }
76
68
  function isNullSchema(variant) {
77
69
  if (!isRecord(variant)) return false;
78
- const record = variant;
79
- if ("const" in record && record.const === null) return true;
80
- if (Array.isArray(record.enum) && record.enum.length === 1) return record.enum[0] === null;
81
- const typeValue = record.type;
82
- if (typeValue === "null") return true;
83
- if (Array.isArray(typeValue) && typeValue.length === 1 && typeValue[0] === "null") return true;
84
- return false;
70
+ if ("const" in variant && variant.const === null) return true;
71
+ if (Array.isArray(variant.enum) && variant.enum.length === 1) return variant.enum[0] === null;
72
+ const typeValue = variant.type;
73
+ return typeValue === "null" || Array.isArray(typeValue) && typeValue.length === 1 && typeValue[0] === "null";
85
74
  }
86
75
  function extendSchemaDefs$1(defs, schema) {
87
76
  const defsEntry = isRecord(schema.$defs) ? schema.$defs : void 0;
88
77
  const legacyDefsEntry = isRecord(schema.definitions) ? schema.definitions : void 0;
89
78
  if (!defsEntry && !legacyDefsEntry) return defs;
90
- const next = defs ? new Map(defs) : /* @__PURE__ */ new Map();
91
- if (defsEntry) for (const [key, value] of Object.entries(defsEntry)) next.set(key, value);
92
- if (legacyDefsEntry) for (const [key, value] of Object.entries(legacyDefsEntry)) next.set(key, value);
79
+ const next = new Map(defs);
80
+ for (const entry of [defsEntry, legacyDefsEntry]) for (const [key, value] of Object.entries(entry ?? {})) next.set(key, value);
93
81
  return next;
94
82
  }
95
83
  function tryResolveLocalRef$1(ref, defs) {
@@ -104,30 +92,15 @@ function simplifyUnionVariants(params) {
104
92
  const nonNullVariants = variants.filter((variant) => !isNullSchema(variant));
105
93
  const stripped = nonNullVariants.length !== variants.length;
106
94
  const flattened = tryFlattenLiteralAnyOf(nonNullVariants);
107
- if (flattened) {
108
- const result = {
109
- type: flattened.type,
110
- enum: flattened.enum
111
- };
112
- copySchemaMeta$1(obj, result);
113
- return {
114
- kind: "simplified",
115
- value: result
116
- };
117
- }
95
+ if (flattened) return {
96
+ kind: "simplified",
97
+ value: copySchemaMeta$1(obj, flattened)
98
+ };
118
99
  if (stripped && nonNullVariants.length === 1) {
119
100
  const lone = nonNullVariants[0];
120
- if (lone && typeof lone === "object" && !Array.isArray(lone)) {
121
- const result = { ...lone };
122
- copySchemaMeta$1(obj, result);
123
- return {
124
- kind: "simplified",
125
- value: result
126
- };
127
- }
128
101
  return {
129
102
  kind: "simplified",
130
- value: lone
103
+ value: isRecord(lone) ? copySchemaMeta$1(obj, { ...lone }) : lone
131
104
  };
132
105
  }
133
106
  return {
@@ -147,69 +120,42 @@ function sanitizeRequiredFields(schema) {
147
120
  else delete schema.required;
148
121
  return schema;
149
122
  }
150
- function* cleanSchemaArray(schemas, defs, refStack, ancestors, result) {
151
- result.length = schemas.length;
152
- for (let index = 0; index < result.length; index += 1) if (index in schemas) result[index] = yield cleanSchemaForGeminiWithDefs(schemas[index], defs, refStack, ancestors);
153
- return result;
154
- }
155
123
  function* cleanSchemaForGeminiWithDefs(schema, defs, refStack, ancestors) {
156
- if (!schema || typeof schema !== "object") return schema;
157
- if (ancestors.has(schema)) throw new TypeError("Tool schema contains a circular reference.");
158
- ancestors.add(schema);
159
- try {
160
- if (Array.isArray(schema)) {
161
- const result = [];
162
- yield cleanSchemaArray(schema, defs, refStack, ancestors, result);
163
- return result;
164
- }
165
- const obj = schema;
124
+ return yield walkSchemaValue(schema, ancestors, function* (obj) {
166
125
  const nextDefs = extendSchemaDefs$1(defs, obj);
126
+ const visit = (value) => cleanSchemaForGeminiWithDefs(value, nextDefs, refStack, ancestors);
167
127
  const refValue = typeof obj.$ref === "string" ? obj.$ref : void 0;
168
128
  if (refValue) {
169
129
  if (refStack?.has(refValue)) return {};
170
130
  const resolved = tryResolveLocalRef$1(refValue, nextDefs);
171
131
  if (resolved) {
172
- const nextRefStack = refStack ? new Set(refStack) : /* @__PURE__ */ new Set();
132
+ const nextRefStack = new Set(refStack);
173
133
  nextRefStack.add(refValue);
174
134
  const cleaned = yield cleanSchemaForGeminiWithDefs(resolved, nextDefs, nextRefStack, /* @__PURE__ */ new Set());
175
135
  if (!cleaned || typeof cleaned !== "object" || Array.isArray(cleaned)) return cleaned;
176
- const result = { ...cleaned };
177
- copySchemaMeta$1(obj, result);
178
- return result;
136
+ return copySchemaMeta$1(obj, { ...cleaned });
137
+ }
138
+ return copySchemaMeta$1(obj, {});
139
+ }
140
+ const unions = {};
141
+ for (const key of ["anyOf", "oneOf"]) {
142
+ const variants = obj[key];
143
+ if (Array.isArray(variants)) {
144
+ const cleaned = [];
145
+ yield walkSchemaArray(variants, visit, cleaned);
146
+ unions[key] = cleaned;
179
147
  }
180
- const result = {};
181
- copySchemaMeta$1(obj, result);
182
- return result;
183
- }
184
- const hasAnyOf = "anyOf" in obj && Array.isArray(obj.anyOf);
185
- const hasOneOf = "oneOf" in obj && Array.isArray(obj.oneOf);
186
- let cleanedAnyOf;
187
- if (hasAnyOf) {
188
- const variants = obj.anyOf;
189
- cleanedAnyOf = [];
190
- yield cleanSchemaArray(variants, nextDefs, refStack, ancestors, cleanedAnyOf);
191
- }
192
- let cleanedOneOf;
193
- if (hasOneOf) {
194
- const variants = obj.oneOf;
195
- cleanedOneOf = [];
196
- yield cleanSchemaArray(variants, nextDefs, refStack, ancestors, cleanedOneOf);
197
- }
198
- if (hasAnyOf) {
199
- const simplified = simplifyUnionVariants({
200
- obj,
201
- variants: cleanedAnyOf ?? []
202
- });
203
- if (simplified.kind === "simplified") return simplified.value;
204
- cleanedAnyOf = simplified.value;
205
148
  }
206
- if (hasOneOf) {
207
- const simplified = simplifyUnionVariants({
208
- obj,
209
- variants: cleanedOneOf ?? []
210
- });
211
- if (simplified.kind === "simplified") return simplified.value;
212
- cleanedOneOf = simplified.value;
149
+ for (const key of ["anyOf", "oneOf"]) {
150
+ const variants = unions[key];
151
+ if (variants) {
152
+ const simplified = simplifyUnionVariants({
153
+ obj,
154
+ variants
155
+ });
156
+ if (simplified.kind === "simplified") return simplified.value;
157
+ unions[key] = simplified.value;
158
+ }
213
159
  }
214
160
  const cleaned = {};
215
161
  for (const [key, value] of Object.entries(obj)) {
@@ -220,7 +166,7 @@ function* cleanSchemaForGeminiWithDefs(schema, defs, refStack, ancestors) {
220
166
  continue;
221
167
  }
222
168
  if (key === "required" && Array.isArray(value) && value.length === 0) continue;
223
- if (key === "type" && (hasAnyOf || hasOneOf)) continue;
169
+ if (key === "type" && (unions.anyOf || unions.oneOf)) continue;
224
170
  if (key === "type" && Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
225
171
  const types = value.filter((entry) => entry !== "null");
226
172
  cleaned.type = types.length === 1 ? types[0] : types;
@@ -229,32 +175,20 @@ function* cleanSchemaForGeminiWithDefs(schema, defs, refStack, ancestors) {
229
175
  if (key === "properties") {
230
176
  if (value && typeof value === "object" && !Array.isArray(value)) {
231
177
  const entries = Object.entries(value);
232
- for (const entry of entries) entry[1] = yield cleanSchemaForGeminiWithDefs(entry[1], nextDefs, refStack, ancestors);
178
+ for (const entry of entries) entry[1] = yield visit(entry[1]);
233
179
  cleaned[key] = Object.fromEntries(entries);
234
180
  } else cleaned[key] = {};
235
- } else if (key === "items" && value) {
236
- if (Array.isArray(value)) {
237
- const result = [];
238
- yield cleanSchemaArray(value, nextDefs, refStack, ancestors, result);
239
- cleaned[key] = result;
240
- } else if (typeof value === "object") cleaned[key] = yield cleanSchemaForGeminiWithDefs(value, nextDefs, refStack, ancestors);
241
- else cleaned[key] = value;
242
- } else if (key === "anyOf" && Array.isArray(value)) cleaned[key] = cleanedAnyOf;
243
- else if (key === "oneOf" && Array.isArray(value)) cleaned[key] = cleanedOneOf;
244
- else if (key === "allOf" && Array.isArray(value)) {
245
- const result = [];
246
- yield cleanSchemaArray(value, nextDefs, refStack, ancestors, result);
247
- cleaned[key] = result;
248
- } else cleaned[key] = value;
181
+ } else if ((key === "items" || key === "allOf") && Array.isArray(value)) cleaned[key] = yield walkSchemaArray(value, visit);
182
+ else if (key === "items" && value && typeof value === "object") cleaned[key] = yield visit(value);
183
+ else if ((key === "anyOf" || key === "oneOf") && Array.isArray(value)) cleaned[key] = unions[key];
184
+ else cleaned[key] = value;
249
185
  }
250
186
  for (const variants of [cleaned.anyOf, cleaned.oneOf]) if (Array.isArray(variants)) {
251
187
  const flattened = flattenUnionFallback(cleaned, variants);
252
188
  if (flattened) return sanitizeRequiredFields(flattened);
253
189
  }
254
190
  return sanitizeRequiredFields(cleaned);
255
- } finally {
256
- ancestors.delete(schema);
257
- }
191
+ });
258
192
  }
259
193
  /**
260
194
  * Last-resort flattening for anyOf/oneOf arrays that could not be simplified
@@ -267,9 +201,7 @@ function flattenUnionFallback(obj, variants) {
267
201
  const types = new Set(objects.map((v) => v.type).filter(Boolean));
268
202
  const first = objects[0];
269
203
  const type = types.size === 1 ? Array.from(types)[0] : first?.type;
270
- const merged = objects.length === 1 ? { ...first } : type ? { type } : {};
271
- copySchemaMeta$1(obj, merged);
272
- return merged;
204
+ return copySchemaMeta$1(obj, objects.length === 1 ? { ...first } : type ? { type } : {});
273
205
  }
274
206
  function cleanSchemaForGemini(schema) {
275
207
  return evaluateSchemaWalk(cleanSchemaForGeminiWithDefs(schema, void 0, void 0, /* @__PURE__ */ new Set()));
@@ -295,12 +227,9 @@ function extendSchemaDefs(defs, schema) {
295
227
  const defsEntry = isRecord(schema.$defs) ? schema.$defs : void 0;
296
228
  const legacyDefsEntry = isRecord(schema.definitions) ? schema.definitions : void 0;
297
229
  if (!defsEntry && !legacyDefsEntry) return defs;
298
- const next = defs ? {
299
- $defs: new Map(defs.$defs),
300
- definitions: new Map(defs.definitions)
301
- } : {
302
- $defs: /* @__PURE__ */ new Map(),
303
- definitions: /* @__PURE__ */ new Map()
230
+ const next = {
231
+ $defs: new Map(defs?.$defs),
232
+ definitions: new Map(defs?.definitions)
304
233
  };
305
234
  if (defsEntry) for (const [key, value] of Object.entries(defsEntry)) next.$defs.set(key, value);
306
235
  if (legacyDefsEntry) for (const [key, value] of Object.entries(legacyDefsEntry)) next.definitions.set(key, value);
@@ -321,10 +250,6 @@ function resolveJsonPointerPath(value, tokens) {
321
250
  }
322
251
  return current;
323
252
  }
324
- function resolveLocalJsonPointer(rootDocument, ref) {
325
- const tokens = parseLocalSchemaRefPointer(ref);
326
- return tokens ? resolveJsonPointerPath(rootDocument, tokens) : void 0;
327
- }
328
253
  const SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
329
254
  "$defs",
330
255
  "definitions",
@@ -378,7 +303,7 @@ function inlineLocalSchemaRefsWithDefs(schema, defs, refStack, state, rootDocume
378
303
  if (refValue.startsWith("#/") || parseLocalSchemaRefPointer(refValue)) state.unresolvedLocalRefs = true;
379
304
  return { ...obj };
380
305
  }
381
- const nextRefStack = refStack ? new Set(refStack) : /* @__PURE__ */ new Set();
306
+ const nextRefStack = new Set(refStack);
382
307
  nextRefStack.add(refValue);
383
308
  const inlined = inlineLocalSchemaRefsWithDefs(resolved, nextDefs, nextRefStack, state, rootDocument);
384
309
  if (!isRecord(inlined)) return inlined;
@@ -400,9 +325,11 @@ function inlineLocalSchemaRefsWithDefs(schema, defs, refStack, state, rootDocume
400
325
  setOwnSchemaProperty(result, key, next);
401
326
  }
402
327
  if (state.unresolvedLocalRefs) {
403
- if ("$defs" in obj) result.$defs = obj.$defs;
404
- if ("definitions" in obj) result.definitions = obj.definitions;
405
- if ("components" in obj) result.components = obj.components;
328
+ for (const key of [
329
+ "$defs",
330
+ "definitions",
331
+ "components"
332
+ ]) if (key in obj) result[key] = obj[key];
406
333
  }
407
334
  return result;
408
335
  }
@@ -425,7 +352,7 @@ function canPreserveRootSchemaRefs(schema) {
425
352
  if (!isRecord(node)) return true;
426
353
  if (ancestors.has(node) || "$id" in node || "id" in node || "components" in node || node !== schema && ("$defs" in node || "definitions" in node)) return false;
427
354
  if ("$ref" in node) {
428
- if (typeof node.$ref !== "string" || !/^#\/(\$defs|definitions)\/[^/]+$/.test(node.$ref) || node.nullable === true || resolveLocalJsonPointer(schema, node.$ref) === void 0) return false;
355
+ if (typeof node.$ref !== "string" || !/^#\/(\$defs|definitions)\/[^/]+$/.test(node.$ref) || node.nullable === true || tryResolveLocalRef(node.$ref, void 0, schema) === void 0) return false;
429
356
  hasRefs ||= !inDefinitions;
430
357
  }
431
358
  ancestors.add(node);
@@ -521,34 +448,22 @@ function findLlamacppGbnfSchemaViolations(schema, path) {
521
448
  }
522
449
  //#endregion
523
450
  //#region packages/ai/src/providers/schema-keyword-strip.ts
524
- function* stripSchemaArray(schemas, unsupportedKeywords, ancestors) {
525
- const result = [];
526
- result.length = schemas.length;
527
- for (let index = 0; index < result.length; index += 1) if (index in schemas) result[index] = yield stripSchemaKeywords(schemas[index], unsupportedKeywords, ancestors);
528
- return result;
529
- }
530
451
  function* stripSchemaKeywords(schema, unsupportedKeywords, ancestors) {
531
- if (!schema || typeof schema !== "object") return schema;
532
- if (ancestors.has(schema)) throw new TypeError("Tool schema contains a circular reference.");
533
- ancestors.add(schema);
534
- try {
535
- if (Array.isArray(schema)) return yield stripSchemaArray(schema, unsupportedKeywords, ancestors);
536
- const obj = schema;
452
+ const visit = (value) => stripSchemaKeywords(value, unsupportedKeywords, ancestors);
453
+ return yield walkSchemaValue(schema, ancestors, function* (obj) {
537
454
  const cleaned = {};
538
455
  for (const [key, value] of Object.entries(obj)) {
539
456
  if (unsupportedKeywords.has(key)) continue;
540
457
  if (SCHEMA_MAP_KEYS$1.has(key) && value && typeof value === "object" && !Array.isArray(value)) {
541
458
  const entries = Object.entries(value);
542
- for (const entry of entries) entry[1] = yield stripSchemaKeywords(entry[1], unsupportedKeywords, ancestors);
459
+ for (const entry of entries) entry[1] = yield visit(entry[1]);
543
460
  cleaned[key] = Object.fromEntries(entries);
544
- } else if (SCHEMA_ARRAY_KEYS$1.has(key) && Array.isArray(value)) cleaned[key] = yield stripSchemaArray(value, unsupportedKeywords, ancestors);
545
- else if (SCHEMA_OBJECT_KEYS$1.has(key) && value && typeof value === "object") cleaned[key] = yield stripSchemaKeywords(value, unsupportedKeywords, ancestors);
461
+ } else if (SCHEMA_ARRAY_KEYS$1.has(key) && Array.isArray(value)) cleaned[key] = yield walkSchemaArray(value, visit);
462
+ else if (SCHEMA_OBJECT_KEYS$1.has(key) && value && typeof value === "object") cleaned[key] = yield visit(value);
546
463
  else cleaned[key] = value;
547
464
  }
548
465
  return cleaned;
549
- } finally {
550
- ancestors.delete(schema);
551
- }
466
+ });
552
467
  }
553
468
  /** Remove schema keywords unsupported by a target provider/tool surface. */
554
469
  function stripUnsupportedSchemaKeywords(schema, unsupportedKeywords) {
@@ -607,6 +522,136 @@ function createToolSchemaNormalizationCache(maxEntries) {
607
522
  };
608
523
  }
609
524
  //#endregion
525
+ //#region packages/ai/src/providers/tool-schema-normalization.ts
526
+ const OPENAPI_SCHEMA_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
527
+ "discriminator",
528
+ "externalDocs",
529
+ "readOnly",
530
+ "writeOnly",
531
+ "xml",
532
+ "example"
533
+ ]);
534
+ function isNullSchemaLike(schema) {
535
+ if (!isRecord(schema)) return false;
536
+ if (schema.type === "null") return true;
537
+ if (Array.isArray(schema.type) && schema.type.includes("null")) return true;
538
+ if ("const" in schema && schema.const === null) return true;
539
+ return Array.isArray(schema.enum) && schema.enum.includes(null);
540
+ }
541
+ const OPENAI_NULLABLE_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
542
+ "default",
543
+ "description",
544
+ "examples",
545
+ "format",
546
+ "title"
547
+ ]);
548
+ function normalizeToolSchema(schema, profile, depth = 0) {
549
+ if (Array.isArray(schema)) {
550
+ if (profile === "compat-map" || profile === "openapi-map") return schema;
551
+ let changed = false;
552
+ const normalized = schema.map((entry) => {
553
+ const next = normalizeToolSchema(entry, profile, profile === "strict" ? depth : 1);
554
+ changed ||= next !== entry;
555
+ return next;
556
+ });
557
+ return changed ? normalized : schema;
558
+ }
559
+ if (!isRecord(schema)) return schema;
560
+ const record = schema;
561
+ let changed = false;
562
+ let hadNullType = false;
563
+ const nullable = profile === "openapi" && record.nullable === true;
564
+ const entries = [];
565
+ for (const [key, value] of Object.entries(record)) {
566
+ if (profile === "compat" && value === null && (OPENAI_NULLABLE_ANNOTATION_KEYS.has(key) || key === "type")) {
567
+ hadNullType ||= key === "type";
568
+ changed = true;
569
+ continue;
570
+ }
571
+ if (profile === "openapi") {
572
+ if (key === "nullable" || OPENAPI_SCHEMA_ANNOTATION_KEYS.has(key)) {
573
+ changed = true;
574
+ continue;
575
+ }
576
+ if (SCHEMA_LITERAL_KEYS.has(key) || key === "components") {
577
+ entries.push([key, value]);
578
+ continue;
579
+ }
580
+ let next = value;
581
+ if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) next = normalizeToolSchema(value, "openapi-map", 1);
582
+ else if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) next = normalizeToolSchema(value, profile, 1);
583
+ else if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
584
+ const nextEntries = value.map((entry) => normalizeToolSchema(entry, profile, 1));
585
+ changed ||= nextEntries.some((entry, index) => entry !== value[index]);
586
+ entries.push([key, nextEntries]);
587
+ continue;
588
+ }
589
+ changed ||= next !== value;
590
+ entries.push([key, next]);
591
+ continue;
592
+ }
593
+ let next = value;
594
+ if (profile === "strict") next = normalizeToolSchema(value, profile, key === "properties" ? depth : depth + 1);
595
+ else if (profile === "compat-map" || profile === "openapi-map") next = normalizeToolSchema(value, profile === "compat-map" ? "compat" : "openapi", 1);
596
+ else if (SCHEMA_MAP_KEYS$1.has(key)) next = normalizeToolSchema(value, "compat-map", 1);
597
+ else if (SCHEMA_NESTED_KEYS.has(key)) next = normalizeToolSchema(value, "compat", 1);
598
+ changed ||= next !== value;
599
+ entries.push([key, next]);
600
+ }
601
+ const normalized = Object.fromEntries(entries);
602
+ if (profile === "compat-map" || profile === "openapi-map") return changed ? normalized : schema;
603
+ if (profile === "openapi") {
604
+ if (nullable) {
605
+ if ([
606
+ normalized.allOf,
607
+ normalized.anyOf,
608
+ normalized.oneOf
609
+ ].some(Array.isArray)) {
610
+ if (Array.isArray(normalized.anyOf) && normalized.anyOf.some(isNullSchemaLike) || Array.isArray(normalized.oneOf) && normalized.oneOf.some(isNullSchemaLike)) return normalized;
611
+ const wrapped = { anyOf: [normalized, { type: "null" }] };
612
+ copySchemaMeta(normalized, wrapped);
613
+ return wrapped;
614
+ }
615
+ const type = normalized.type;
616
+ if (typeof type === "string" && type !== "null") normalized.type = [type, "null"];
617
+ else if (Array.isArray(type) && !type.includes("null")) normalized.type = [...type, "null"];
618
+ if (Array.isArray(normalized.enum) && !normalized.enum.includes(null)) normalized.enum = [...normalized.enum, null];
619
+ }
620
+ return changed || nullable ? normalized : schema;
621
+ }
622
+ if (profile === "compat") {
623
+ if (Object.keys(normalized).length === 0) {
624
+ if (depth !== 0) return schema;
625
+ return {
626
+ type: "object",
627
+ properties: {},
628
+ required: [],
629
+ additionalProperties: false
630
+ };
631
+ }
632
+ const hasObjectShapeHints = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) || Array.isArray(normalized.required);
633
+ const hasArrayShapeHints = "items" in normalized;
634
+ if (!("type" in normalized) && hasObjectShapeHints !== hasArrayShapeHints) {
635
+ normalized.type = hasObjectShapeHints ? "object" : "array";
636
+ changed = true;
637
+ } else if (hadNullType && !("type" in normalized)) normalized.type = null;
638
+ if (normalized.type === "object" && !("properties" in normalized)) {
639
+ normalized.properties = {};
640
+ changed = true;
641
+ }
642
+ }
643
+ const hasEmptyProperties = isRecord(normalized.properties) && Object.keys(normalized.properties).length === 0;
644
+ if (normalized.type === "object" && !Array.isArray(normalized.required) && hasEmptyProperties) {
645
+ normalized.required = [];
646
+ changed = true;
647
+ }
648
+ if (normalized.type === "object" && (profile === "strict" ? depth === 0 : hasEmptyProperties) && !("additionalProperties" in normalized)) {
649
+ normalized.additionalProperties = false;
650
+ changed = true;
651
+ }
652
+ return changed ? normalized : schema;
653
+ }
654
+ //#endregion
610
655
  //#region packages/ai/src/providers/agent-tools-parameter-schema.ts
611
656
  /**
612
657
  * Normalizes model-facing tool parameter schemas across provider quirks.
@@ -632,20 +677,6 @@ function shouldOmitEmptyArrayItems(modelOrCompat) {
632
677
  return extractToolSchemaModelCompat(modelOrCompat)?.omitEmptyArrayItems === true;
633
678
  }
634
679
  const toolParameterSchemaCache = createToolSchemaNormalizationCache(8);
635
- function resolveToolParameterSchemaCacheKey(options) {
636
- const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
637
- const normalizedModelId = normalizeLowercaseStringOrEmpty(options?.modelId);
638
- const toolSchemaProfile = normalizeLowercaseStringOrEmpty(options?.modelCompat?.toolSchemaProfile);
639
- const unsupportedKeywords = Array.from(resolveUnsupportedToolSchemaKeywords(options?.modelCompat)).toSorted();
640
- const omitEmptyArrayItems = shouldOmitEmptyArrayItems(options?.modelCompat);
641
- return JSON.stringify([
642
- normalizedProvider,
643
- normalizedModelId,
644
- toolSchemaProfile,
645
- unsupportedKeywords,
646
- omitEmptyArrayItems
647
- ]);
648
- }
649
680
  function isGeminiModelId(modelId) {
650
681
  return /(?:^|[/:])gemini(?:$|[-/:.])/.test(modelId);
651
682
  }
@@ -750,121 +781,42 @@ function normalizeArraySchemaItems(schema, mode) {
750
781
  }
751
782
  return changed ? normalized : schema;
752
783
  }
753
- const OPENAPI_SCHEMA_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
754
- "discriminator",
755
- "externalDocs",
756
- "readOnly",
757
- "writeOnly",
758
- "xml",
759
- "example"
760
- ]);
761
- function appendNullSchemaType(type) {
762
- if (type === "null") return type;
763
- if (typeof type === "string") return [type, "null"];
764
- if (Array.isArray(type)) return type.includes("null") ? type : [...type, "null"];
765
- return type;
766
- }
767
- function isNullSchemaLike(schema) {
768
- if (!isRecord(schema)) return false;
769
- if (schema.type === "null") return true;
770
- if (Array.isArray(schema.type) && schema.type.includes("null")) return true;
771
- if ("const" in schema && schema.const === null) return true;
772
- return Array.isArray(schema.enum) && schema.enum.includes(null);
773
- }
774
- function hasOpenApiComposition(schema) {
775
- return [
776
- "allOf",
777
- "anyOf",
778
- "oneOf"
779
- ].some((key) => Array.isArray(schema[key]));
780
- }
781
- function schemaCompositionAlreadyAllowsNull(schema) {
782
- return Array.isArray(schema.anyOf) && schema.anyOf.some(isNullSchemaLike) || Array.isArray(schema.oneOf) && schema.oneOf.some(isNullSchemaLike);
783
- }
784
- function wrapNullableComposedSchema(schema) {
785
- if (schemaCompositionAlreadyAllowsNull(schema)) return schema;
786
- const wrapped = { anyOf: [schema, { type: "null" }] };
787
- copySchemaMeta(schema, wrapped);
788
- return wrapped;
789
- }
790
- function normalizeOpenApiSchemaKeywords(schema) {
791
- if (Array.isArray(schema)) {
792
- let changed = false;
793
- const normalized = schema.map((entry) => {
794
- const next = normalizeOpenApiSchemaKeywords(entry);
795
- changed ||= next !== entry;
796
- return next;
797
- });
798
- return changed ? normalized : schema;
799
- }
800
- if (!isRecord(schema)) return schema;
801
- let changed = false;
802
- const nullable = schema.nullable === true;
803
- const entries = Object.entries(schema);
804
- let normalized;
805
- for (const [key, value] of entries) {
806
- if (key === "nullable" || OPENAPI_SCHEMA_ANNOTATION_KEYS.has(key)) {
807
- normalized ??= Object.fromEntries(entries);
808
- delete normalized[key];
809
- changed = true;
810
- continue;
811
- }
812
- if (SCHEMA_LITERAL_KEYS.has(key) || key === "components") continue;
813
- let next = value;
814
- if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
815
- let mapChanged = false;
816
- const mapEntries = Object.entries(value);
817
- for (const entry of mapEntries) {
818
- const nextEntry = normalizeOpenApiSchemaKeywords(entry[1]);
819
- mapChanged ||= nextEntry !== entry[1];
820
- entry[1] = nextEntry;
821
- }
822
- next = mapChanged ? Object.fromEntries(mapEntries) : value;
823
- } else if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) next = normalizeOpenApiSchemaKeywords(value);
824
- else if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
825
- const nextEntries = value.map(normalizeOpenApiSchemaKeywords);
826
- (normalized ??= Object.fromEntries(entries))[key] = nextEntries;
827
- changed ||= nextEntries.some((entry, index) => entry !== value[index]);
828
- continue;
829
- }
830
- if (next !== value) {
831
- (normalized ??= Object.fromEntries(entries))[key] = next;
832
- changed = true;
833
- }
834
- }
835
- if (nullable) {
836
- normalized ??= Object.fromEntries(entries);
837
- if (hasOpenApiComposition(normalized)) return wrapNullableComposedSchema(normalized);
838
- if ("type" in normalized) {
839
- const nextType = appendNullSchemaType(normalized.type);
840
- if (nextType !== normalized.type) normalized.type = nextType;
841
- }
842
- if (Array.isArray(normalized.enum) && !normalized.enum.includes(null)) normalized.enum = [...normalized.enum, null];
843
- }
844
- return changed || nullable ? normalized ?? schema : schema;
845
- }
846
- function normalizeToolParameterSchemaUncached(schema, options) {
784
+ /** Return a provider-compatible JSON schema for a model-facing tool. */
785
+ function normalizeToolParameterSchema(schema, options) {
847
786
  const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
848
787
  const normalizedModelId = normalizeLowercaseStringOrEmpty(options?.modelId);
849
788
  const normalizedToolSchemaProfile = normalizeLowercaseStringOrEmpty(options?.modelCompat?.toolSchemaProfile);
850
- const isGeminiProvider = normalizedProvider.includes("google") || normalizedProvider.includes("gemini") || isGeminiModelId(normalizedModelId) || normalizedToolSchemaProfile === "gemini";
851
- const isAnthropicProvider = normalizedProvider.includes("anthropic");
852
789
  const unsupportedToolSchemaKeywords = resolveUnsupportedToolSchemaKeywords(options?.modelCompat);
853
790
  const omitEmptyArrayItems = shouldOmitEmptyArrayItems(options?.modelCompat);
791
+ const source = schema && typeof schema === "object" ? schema : void 0;
792
+ const cacheKey = source ? JSON.stringify([
793
+ normalizedProvider,
794
+ normalizedModelId,
795
+ normalizedToolSchemaProfile,
796
+ [...unsupportedToolSchemaKeywords].toSorted(),
797
+ omitEmptyArrayItems
798
+ ]) : "";
799
+ if (source) {
800
+ const cached = toolParameterSchemaCache.get(source, cacheKey);
801
+ if (cached) return cached;
802
+ }
803
+ const rememberResult = (normalized) => source ? toolParameterSchemaCache.remember(source, cacheKey, normalized) : normalized;
804
+ const isGeminiProvider = normalizedProvider.includes("google") || normalizedProvider.includes("gemini") || isGeminiModelId(normalizedModelId) || normalizedToolSchemaProfile === "gemini";
805
+ const isAnthropicProvider = normalizedProvider.includes("anthropic");
854
806
  const isLlamacppGbnfProfile = normalizedToolSchemaProfile === "llamacpp";
855
- const inlinedSchema = normalizeOpenApiSchemaKeywords(normalizedProvider === "openai" && !isGeminiProvider && !isLlamacppGbnfProfile && ![
807
+ const inlinedSchema = normalizeToolSchema(normalizedProvider === "openai" && !isGeminiProvider && !isLlamacppGbnfProfile && ![
856
808
  "$ref",
857
809
  "$defs",
858
810
  "definitions"
859
- ].some((key) => unsupportedToolSchemaKeywords.has(key)) && canPreserveRootSchemaRefs(schema) ? schema : inlineLocalToolSchemaRefs(schema));
811
+ ].some((key) => unsupportedToolSchemaKeywords.has(key)) && canPreserveRootSchemaRefs(schema) ? schema : inlineLocalToolSchemaRefs(schema), "openapi");
860
812
  const schemaRecord = inlinedSchema && typeof inlinedSchema === "object" ? inlinedSchema : void 0;
861
- if (!schemaRecord) return inlinedSchema;
813
+ if (!schemaRecord) return rememberResult(inlinedSchema);
862
814
  function applyProviderCleaning(s) {
863
815
  let arrayItemsCompatibleSchema = normalizeArraySchemaItems(s, omitEmptyArrayItems ? "normalize" : "add");
864
816
  if (isLlamacppGbnfProfile) arrayItemsCompatibleSchema = cleanSchemaForLlamacppGbnf(arrayItemsCompatibleSchema);
865
817
  if (isGeminiProvider && !isAnthropicProvider) arrayItemsCompatibleSchema = cleanSchemaForGemini(arrayItemsCompatibleSchema);
866
818
  if (unsupportedToolSchemaKeywords.size > 0) arrayItemsCompatibleSchema = stripUnsupportedSchemaKeywords(arrayItemsCompatibleSchema, unsupportedToolSchemaKeywords);
867
- return arrayItemsCompatibleSchema;
819
+ return rememberResult(arrayItemsCompatibleSchema);
868
820
  }
869
821
  const flattenableVariantKey = Array.isArray(schemaRecord.anyOf) ? "anyOf" : Array.isArray(schemaRecord.oneOf) ? "oneOf" : void 0;
870
822
  if (!flattenableVariantKey && !Array.isArray(schemaRecord.allOf)) {
@@ -922,92 +874,26 @@ function normalizeToolParameterSchemaUncached(schema, options) {
922
874
  additionalProperties: "additionalProperties" in schemaRecord ? schemaRecord.additionalProperties : true
923
875
  });
924
876
  }
925
- /** Return a provider-compatible JSON schema for a model-facing tool. */
926
- function normalizeToolParameterSchema(schema, options) {
927
- if (!schema || typeof schema !== "object") return normalizeToolParameterSchemaUncached(schema, options);
928
- const cacheKey = resolveToolParameterSchemaCacheKey(options);
929
- const cached = toolParameterSchemaCache.get(schema, cacheKey);
930
- if (cached) return cached;
931
- return toolParameterSchemaCache.remember(schema, cacheKey, normalizeToolParameterSchemaUncached(schema, options));
932
- }
933
877
  //#endregion
934
878
  //#region packages/ai/src/providers/openai-tool-schema-compat.ts
935
- const OPENAI_NULLABLE_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
936
- "default",
937
- "description",
938
- "examples",
939
- "format",
940
- "title"
941
- ]);
942
- const OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS = new Set([...SCHEMA_OBJECT_KEYS$1, ...SCHEMA_ARRAY_KEYS$1].toSorted());
943
- function normalizeOpenAIStrictCompatSchemaMap(schema) {
944
- if (!isRecord(schema)) return schema;
945
- let changed = false;
946
- const normalized = Object.fromEntries(Object.entries(schema).map(([key, value]) => {
947
- const next = normalizeOpenAIStrictCompatSchemaRecursive(value);
948
- changed ||= next !== value;
949
- return [key, next];
950
- }));
951
- return changed ? normalized : schema;
952
- }
953
- function normalizeOpenAIStrictCompatSchemaRecursive(schema, promoteEmptyObject = false) {
954
- if (Array.isArray(schema)) {
955
- let changed = false;
956
- const normalized = schema.map((entry) => {
957
- const next = normalizeOpenAIStrictCompatSchemaRecursive(entry);
958
- changed ||= next !== entry;
959
- return next;
960
- });
961
- return changed ? normalized : schema;
962
- }
963
- if (!schema || typeof schema !== "object") return schema;
964
- const record = schema;
965
- let changed = false;
966
- let hadNullType = false;
967
- const entries = Object.entries(record).flatMap(([key, value]) => {
968
- if (value === null && (OPENAI_NULLABLE_ANNOTATION_KEYS.has(key) || key === "type")) {
969
- hadNullType ||= key === "type";
970
- changed = true;
971
- return [];
972
- }
973
- const next = SCHEMA_MAP_KEYS$1.has(key) ? normalizeOpenAIStrictCompatSchemaMap(value) : OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaRecursive(value) : value;
974
- changed ||= next !== value;
975
- return [[key, next]];
976
- });
977
- const normalized = Object.fromEntries(entries);
978
- if (Object.keys(normalized).length === 0) {
979
- if (!promoteEmptyObject) return schema;
980
- return {
981
- type: "object",
982
- properties: {},
983
- required: [],
984
- additionalProperties: false
985
- };
986
- }
987
- const hasObjectShapeHints = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) || Array.isArray(normalized.required);
988
- const hasArrayShapeHints = "items" in normalized;
989
- if (!("type" in normalized) && hasObjectShapeHints !== hasArrayShapeHints) {
990
- normalized.type = hasObjectShapeHints ? "object" : "array";
991
- changed = true;
992
- } else if (hadNullType && !("type" in normalized)) normalized.type = null;
993
- if (normalized.type === "object" && !("properties" in normalized)) {
994
- normalized.properties = {};
995
- changed = true;
996
- }
997
- const hasEmptyProperties = isRecord(normalized.properties) && Object.keys(normalized.properties).length === 0;
998
- if (normalized.type === "object" && !Array.isArray(normalized.required) && hasEmptyProperties) {
999
- normalized.required = [];
1000
- changed = true;
1001
- }
1002
- if (normalized.type === "object" && hasEmptyProperties && !("additionalProperties" in normalized)) {
1003
- normalized.additionalProperties = false;
1004
- changed = true;
1005
- }
1006
- return changed ? normalized : schema;
1007
- }
1008
879
  /** Repairs recoverable OpenAI tool-schema shapes before canonical normalization. */
1009
880
  function normalizeOpenAIStrictCompatSchema(schema) {
1010
- return normalizeOpenAIStrictCompatSchemaRecursive(schema, true);
881
+ return normalizeToolSchema(schema, "compat");
882
+ }
883
+ /**
884
+ * Returns whether a regex pattern contains a lookahead or lookbehind group.
885
+ * Escaped parentheses, character classes, and named groups are not lookarounds.
886
+ */
887
+ function hasRegexLookaround(pattern) {
888
+ let inCharacterClass = false;
889
+ for (let index = 0; index < pattern.length; index += 1) {
890
+ const char = pattern[index];
891
+ if (char === "\\") index += 1;
892
+ else if (inCharacterClass) inCharacterClass = char !== "]";
893
+ else if (char === "[") inCharacterClass = true;
894
+ else if (char === "(" && /^\?<?[=!]/.test(pattern.slice(index + 1, index + 4))) return true;
895
+ }
896
+ return false;
1011
897
  }
1012
898
  /** Finds schema paths that violate OpenAI strict tool-schema requirements. */
1013
899
  function findOpenAIStrictSchemaViolations(schema, path, options) {
@@ -1024,6 +910,7 @@ function findOpenAIStrictSchemaViolations(schema, path, options) {
1024
910
  "allOf"
1025
911
  ]) if (key in record) violations.push(`${path}.${key}`);
1026
912
  if (Array.isArray(record.type)) violations.push(`${path}.type`);
913
+ if (typeof record.pattern === "string" && hasRegexLookaround(record.pattern)) violations.push(`${path}.pattern`);
1027
914
  const properties = isRecord(record.properties) ? record.properties : void 0;
1028
915
  if (record.type === "object") {
1029
916
  if (record.additionalProperties !== false) violations.push(`${path}.additionalProperties`);
@@ -1039,7 +926,7 @@ function findOpenAIStrictSchemaViolations(schema, path, options) {
1039
926
  if (!isRecord(schemaMap)) continue;
1040
927
  for (const [entryKey, value] of Object.entries(schemaMap)) violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}.${entryKey}`));
1041
928
  }
1042
- for (const key of OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS) {
929
+ for (const key of SCHEMA_NESTED_KEYS) {
1043
930
  const value = record[key];
1044
931
  if (value && typeof value === "object") violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}`));
1045
932
  }
@@ -1070,40 +957,9 @@ function normalizeStrictOpenAIJsonSchema(schema, modelCompat) {
1070
957
  const cached = strictOpenAISchemaCache.get(schemaInput, cacheKey);
1071
958
  if (cached !== void 0) return cached;
1072
959
  }
1073
- const normalized = normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0);
960
+ const normalized = normalizeToolSchema(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), "strict");
1074
961
  return cacheable ? strictOpenAISchemaCache.remember(schemaInput, cacheKey, normalized) : normalized;
1075
962
  }
1076
- function normalizeStrictOpenAIJsonSchemaRecursive(schema, depth) {
1077
- if (Array.isArray(schema)) {
1078
- let changed = false;
1079
- const normalized = schema.map((entry) => {
1080
- const next = normalizeStrictOpenAIJsonSchemaRecursive(entry, depth);
1081
- changed ||= next !== entry;
1082
- return next;
1083
- });
1084
- return changed ? normalized : schema;
1085
- }
1086
- if (!schema || typeof schema !== "object") return schema;
1087
- const record = schema;
1088
- let changed = false;
1089
- const normalized = Object.fromEntries(Object.entries(record).map(([key, value]) => {
1090
- const next = normalizeStrictOpenAIJsonSchemaRecursive(value, key === "properties" ? depth : depth + 1);
1091
- changed ||= next !== value;
1092
- return [key, next];
1093
- }));
1094
- if (normalized.type === "object") {
1095
- const properties = isRecord(normalized.properties) ? normalized.properties : void 0;
1096
- if (properties && Object.keys(properties).length === 0 && !Array.isArray(normalized.required)) {
1097
- normalized.required = [];
1098
- changed = true;
1099
- }
1100
- if (depth === 0 && !("additionalProperties" in normalized)) {
1101
- normalized.additionalProperties = false;
1102
- changed = true;
1103
- }
1104
- }
1105
- return changed ? normalized : schema;
1106
- }
1107
963
  /** Normalizes tool parameters using strict OpenAI rules only when strict mode is active. */
1108
964
  function normalizeOpenAIStrictToolParameters(schema, strict, modelCompat) {
1109
965
  const toolSchemaCompat = resolveToolSchemaModelCompat(modelCompat);
@@ -1112,7 +968,7 @@ function normalizeOpenAIStrictToolParameters(schema, strict, modelCompat) {
1112
968
  }
1113
969
  /** Returns whether a schema already satisfies OpenAI strict tool-schema constraints. */
1114
970
  function isStrictOpenAIJsonSchemaCompatible(schema) {
1115
- return isStrictOpenAIJsonSchemaCompatibleRecursive(normalizeStrictOpenAIJsonSchema(schema));
971
+ return findOpenAIStrictSchemaViolations(normalizeStrictOpenAIJsonSchema(schema), "parameters").length === 0;
1116
972
  }
1117
973
  /** Returns strict-schema diagnostics for an already materialized OpenAI tool projection. */
1118
974
  function findOpenAIStrictToolProjectionDiagnostics(projection) {
@@ -1129,25 +985,6 @@ function findOpenAIStrictToolProjectionDiagnostics(projection) {
1129
985
  }] : [];
1130
986
  })];
1131
987
  }
1132
- function isStrictOpenAIJsonSchemaCompatibleRecursive(schema) {
1133
- if (Array.isArray(schema)) return schema.every((entry) => isStrictOpenAIJsonSchemaCompatibleRecursive(entry));
1134
- if (!schema || typeof schema !== "object") return true;
1135
- const record = schema;
1136
- if ("anyOf" in record || "oneOf" in record || "allOf" in record) return false;
1137
- if (Array.isArray(record.type)) return false;
1138
- if (record.type === "object" && record.additionalProperties !== false) return false;
1139
- if (record.type === "object") {
1140
- const properties = isRecord(record.properties) ? record.properties : {};
1141
- const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
1142
- if (!required) return false;
1143
- const requiredSet = new Set(required);
1144
- if (Object.keys(properties).some((key) => !requiredSet.has(key))) return false;
1145
- }
1146
- return Object.entries(record).every(([key, entry]) => {
1147
- if (key === "properties" && isRecord(entry)) return Object.values(entry).every(isStrictOpenAIJsonSchemaCompatibleRecursive);
1148
- return isStrictOpenAIJsonSchemaCompatibleRecursive(entry);
1149
- });
1150
- }
1151
988
  /** Resolves strict mode for the projected tools that will be emitted in the request payload. */
1152
989
  function resolveOpenAIProjectedToolsStrictToolFlag(projection, strict) {
1153
990
  if (strict !== true) return strict === false ? false : void 0;