@openclaw/ai 2026.8.1-beta.3 → 2026.9.1-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 (79) hide show
  1. package/dist/{anthropic-B8KwTtlb.mjs → anthropic-DI4PZKKB.mjs} +18 -16
  2. package/dist/{anthropic-compaction-replay-4Zx7-aCr.mjs → anthropic-compaction-replay-nhKaCXu6.mjs} +8 -12
  3. package/dist/{anthropic-payload-policy-CSx7MoKH.d.mts → anthropic-payload-policy-B_0n0enE.d.mts} +2 -1
  4. package/dist/{api-registry-DFxSnFqG.d.mts → api-registry-CTd8NzcD.d.mts} +2 -1
  5. package/dist/{azure-openai-responses-Aa4mVcYG.mjs → azure-openai-responses-D8dI0ekg.mjs} +3 -3
  6. package/dist/diagnostics.d.mts +0 -1
  7. package/dist/diagnostics.mjs +1 -1
  8. package/dist/event-stream-BKp4fOt_.d.mts +1 -0
  9. package/dist/{event-stream-D91-ohD_.d.mts → event-stream-LiXePESD.d.mts} +1 -2
  10. package/dist/event-stream.d.mts +2 -1
  11. package/dist/{google-yDRnipeq.mjs → google-Od-LLdVK.mjs} +3 -3
  12. package/dist/{google-shared-M1dl64nz.mjs → google-shared-Bgr9lFPw.mjs} +14 -7
  13. package/dist/{google-vertex-DCJHM_a5.mjs → google-vertex-aerRSXc4.mjs} +4 -4
  14. package/dist/{host-DF_yxOsA.mjs → host-D51fmkH6.mjs} +4 -8
  15. package/dist/{host-DJq_FGcz.d.mts → host-DsbPMFU6.d.mts} +3 -3
  16. package/dist/index-Qbej8io0.d.mts +3 -0
  17. package/dist/index.d.mts +6 -6
  18. package/dist/index.mjs +2 -3
  19. package/dist/internal/anthropic.d.mts +5 -4
  20. package/dist/internal/anthropic.mjs +4 -4
  21. package/dist/internal/openai-responses-payload-policy.d.mts +1 -1
  22. package/dist/internal/openai-responses-payload-policy.mjs +2 -2
  23. package/dist/internal/openai.d.mts +5 -5
  24. package/dist/internal/openai.mjs +8 -7
  25. package/dist/internal/runtime.d.mts +16 -5
  26. package/dist/internal/runtime.mjs +6 -6
  27. package/dist/internal/shared.d.mts +2 -2
  28. package/dist/internal/shared.mjs +3 -3
  29. package/dist/{json-parse-CDnesDM_.mjs → json-parse-BuAJEbdW.mjs} +18 -2
  30. package/dist/{mistral-D6hRXI7A.mjs → mistral-EiHdymeb.mjs} +17 -21
  31. package/dist/{openai-chatgpt-responses-C339VIfT.mjs → openai-chatgpt-responses-DHpF9o1e.mjs} +28 -11
  32. package/dist/openai-completions-EFPiUGfS.mjs +399 -0
  33. package/dist/{openai-completions-compat-B0KTleXp.d.mts → openai-completions-compat-BefmHT26.d.mts} +3 -3
  34. package/dist/openai-completions-stream-DUlGwRMz.mjs +1621 -0
  35. package/dist/{openai-responses-BXEcr-Tp.mjs → openai-responses-BogP8OjX.mjs} +6 -5
  36. package/dist/{openai-responses-contracts-CD75pQ0m.d.mts → openai-responses-contracts-Dvj_UtPy.d.mts} +3 -3
  37. package/dist/{openai-responses-contracts-DvILoqBk.mjs → openai-responses-contracts-QUY12X0B.mjs} +4 -18
  38. package/dist/{openai-responses-payload-policy-BDo8CQsx.mjs → openai-responses-payload-policy-D8EdimYe.mjs} +3 -7
  39. package/dist/{openai-responses-prompt-observer-internal-BG-1AsBI.mjs → openai-responses-prompt-observer-internal-Cd4hJG-S.mjs} +3 -2
  40. package/dist/{openai-responses-shared-Cvt5MgEm.mjs → openai-responses-shared-DJThc6jW.mjs} +150 -1362
  41. package/dist/openai-stop-reason-Drnn_6Qj.mjs +28 -0
  42. package/dist/openai-tool-schema-ho-hIkQf.mjs +1695 -0
  43. package/dist/{provider-error-C8mBRJDl.mjs → provider-error-DDOs_Bz0.mjs} +1 -3
  44. package/dist/{provider-options-Cc5ZQ6Aa.d.mts → provider-options-MdMBLzlU.d.mts} +4 -3
  45. package/dist/{provider-transcript-transform--gtf0ZbR.mjs → provider-transcript-transform-C01bQ5a3.mjs} +1 -1
  46. package/dist/provider-types.d.mts +5 -3
  47. package/dist/providers.d.mts +1 -2
  48. package/dist/providers.mjs +9 -9
  49. package/dist/{sanitize-unicode-BP7HLLZn.mjs → sanitize-unicode-DCkltN94.mjs} +1 -2
  50. package/dist/simple-options-CFj7x3J4.mjs +118 -0
  51. package/dist/{anthropic-BQXQudmA.mjs → src-Bu3FiFAG.mjs} +1 -0
  52. package/dist/{streaming-byte-guard-BrbkbwUu.mjs → streaming-byte-guard-CC-HMn_u.mjs} +5 -6
  53. package/dist/string-normalization--fwJ4S2q.mjs +16 -0
  54. package/dist/{tool-schema-json-projection-FEr-jOoZ.mjs → tool-schema-json-projection-qvTEs5Am.mjs} +2 -2
  55. package/dist/{simple-options-oqsXB6U3.mjs → transport-stream-shared-ljShVIZB.mjs} +10 -118
  56. package/dist/transport-stream-shared-rvaCyFYt.d.mts +138 -0
  57. package/dist/{transport-utils-Bv0FHkd0.mjs → transport-utils-LJ1_rbi-.mjs} +8 -5
  58. package/dist/transports.d.mts +23 -117
  59. package/dist/transports.mjs +43 -1038
  60. package/dist/{types-DTAP49HF.d.mts → types-DhLoJbFm.d.mts} +34 -17
  61. package/dist/types-GiAjXatj.d.mts +1 -0
  62. package/dist/types.d.mts +4 -3
  63. package/dist/types.mjs +1 -2
  64. package/dist/utf16-slice-qz3nsy87.mjs +84 -0
  65. package/dist/{validation-DYNNrU9u.d.mts → validation-Dk7q7NMN.d.mts} +1 -2
  66. package/dist/validation.d.mts +1 -1
  67. package/package.json +5 -5
  68. package/dist/event-stream-BVVgDSdq.d.mts +0 -1
  69. package/dist/headers-B_e4-1J0.mjs +0 -9
  70. package/dist/index-BVVgDSdq.d.mts +0 -1
  71. package/dist/openai-completions-D88orSJ9.mjs +0 -632
  72. package/dist/openai-stop-reason-9OONKyAm.mjs +0 -579
  73. package/dist/openai-tool-projection-CHGLt03m.mjs +0 -426
  74. package/dist/record-coerce-DdXsgUd_.mjs +0 -23
  75. package/dist/src-D2H6yKkH.mjs +0 -2
  76. package/dist/stream-first-event-timeout-DvDeSucC.d.mts +0 -29
  77. package/dist/string-coerce-fsri9iCu.mjs +0 -34
  78. package/dist/types-BVVgDSdq.d.mts +0 -1
  79. package/dist/utf16-slice-CvGodqok.mjs +0 -29
@@ -1,20 +1,19 @@
1
- import { a as normalizeOptionalString, n as normalizeLowercaseStringOrEmpty } from "./string-coerce-fsri9iCu.mjs";
2
- import { i as clampThinkingLevel, r as calculateCost } from "./sanitize-unicode-BP7HLLZn.mjs";
3
- import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, n as getAiTransportHost } from "./host-DF_yxOsA.mjs";
4
- import { a as isRecord } from "./record-coerce-DdXsgUd_.mjs";
5
- import { t as truncateUtf16Safe } from "./utf16-slice-CvGodqok.mjs";
6
- import { n as projectProviderError } from "./provider-error-C8mBRJDl.mjs";
1
+ import { c as normalizeLowercaseStringOrEmpty, d as normalizeOptionalString, o as isRecord, t as truncateUtf16Safe } from "./utf16-slice-qz3nsy87.mjs";
2
+ import { i as clampThinkingLevel, r as calculateCost } from "./sanitize-unicode-DCkltN94.mjs";
3
+ import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, n as getAiTransportHost } from "./host-D51fmkH6.mjs";
4
+ import { n as projectProviderError } from "./provider-error-DDOs_Bz0.mjs";
7
5
  import { t as asFiniteNumber } from "./number-coercion-H9qHik3g.mjs";
8
- import { C as normalizeStringEntries, S as supportsOpenAITemperature, T as uniqueValues, a as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, c as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, f as RESPONSE_FAILED_NO_DETAILS_MESSAGE, o as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, s as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, x as supportsOpenAIReasoningEffort, y as resolveOpenAIReasoningEffortForModel } from "./openai-responses-contracts-DvILoqBk.mjs";
9
- import { C as withProviderResponseHook, P as sortPromptCacheToolsByName, b as sanitizeTransportPayloadText, j as stripSystemPromptCacheBoundary, v as parseTerminalToolCallArguments, x as transportAbortError, y as sanitizeNonEmptyTransportPayloadText } from "./simple-options-oqsXB6U3.mjs";
10
- import { c as transformTransportMessages } from "./tool-schema-json-projection-FEr-jOoZ.mjs";
11
- import { n as parseStreamingJson } from "./json-parse-CDnesDM_.mjs";
6
+ import { f as sortPromptCacheToolsByName, l as stripSystemPromptCacheBoundary } from "./simple-options-CFj7x3J4.mjs";
7
+ import { c as transformTransportMessages } from "./tool-schema-json-projection-qvTEs5Am.mjs";
8
+ import { d as redactSensitiveText, u as redactIdentifier } from "./transport-utils-LJ1_rbi-.mjs";
9
+ import { _ as transportAbortError, g as sanitizeTransportPayloadText, h as sanitizeNonEmptyTransportPayloadText, m as parseTerminalToolCallArguments, y as withProviderResponseHook } from "./transport-stream-shared-ljShVIZB.mjs";
10
+ import { r as parseStreamingJson, t as createToolArgumentPreviewSchedule } from "./json-parse-BuAJEbdW.mjs";
12
11
  import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
13
12
  import { t as shortHash } from "./hash-CHgqbJmD.mjs";
14
- import { l as redactIdentifier, u as redactSensitiveText } from "./transport-utils-Bv0FHkd0.mjs";
15
- import { a as createModelStreamCooperativeScheduler, l as log, o as createOpenAIProviderAcceptanceHook, t as projectOpenAITools } from "./openai-tool-projection-CHGLt03m.mjs";
13
+ import { C as createOpenAIProviderAcceptanceHook, E as log, S as createModelStreamCooperativeScheduler, a as resolveOpenAIProjectedToolsStrictToolFlag, r as normalizeOpenAIStrictToolParameters, t as findOpenAIStrictToolProjectionDiagnostics, v as projectOpenAITools } from "./openai-tool-schema-ho-hIkQf.mjs";
16
14
  import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-MK28puvq.mjs";
17
- import { t as transformProviderMessages } from "./provider-transcript-transform--gtf0ZbR.mjs";
15
+ import { t as transformProviderMessages } from "./provider-transcript-transform-C01bQ5a3.mjs";
16
+ import { S as supportsOpenAITemperature, a as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, c as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, f as RESPONSE_FAILED_NO_DETAILS_MESSAGE, o as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, s as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, x as supportsOpenAIReasoningEffort, y as resolveOpenAIReasoningEffortForModel } from "./openai-responses-contracts-QUY12X0B.mjs";
18
17
  import { createHash, randomUUID } from "node:crypto";
19
18
  //#region packages/ai/src/transports/model-transport-debug.ts
20
19
  /**
@@ -57,1270 +56,6 @@ function emitModelTransportDebug(log, message) {
57
56
  log.debug(message);
58
57
  }
59
58
  //#endregion
60
- //#region packages/ai/src/providers/clean-for-gemini.ts
61
- const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
62
- "patternProperties",
63
- "additionalProperties",
64
- "$schema",
65
- "$id",
66
- "$ref",
67
- "$defs",
68
- "definitions",
69
- "examples",
70
- "minLength",
71
- "maxLength",
72
- "minimum",
73
- "maximum",
74
- "multipleOf",
75
- "pattern",
76
- "format",
77
- "minItems",
78
- "maxItems",
79
- "uniqueItems",
80
- "minProperties",
81
- "maxProperties",
82
- "not"
83
- ]);
84
- const SCHEMA_META_KEYS = [
85
- "description",
86
- "title",
87
- "default"
88
- ];
89
- function copySchemaMeta$1(from, to) {
90
- for (const key of SCHEMA_META_KEYS) if (key in from && from[key] !== void 0) to[key] = from[key];
91
- }
92
- function stringifyGeminiEnumValue(value) {
93
- if (typeof value === "string") return value;
94
- if (typeof value === "number" && Number.isFinite(value)) return String(value);
95
- if (typeof value === "boolean") return String(value);
96
- }
97
- function cleanGeminiEnumValues(value) {
98
- if (!Array.isArray(value)) return;
99
- const values = value.flatMap((entry) => {
100
- const stringified = stringifyGeminiEnumValue(entry);
101
- return stringified === void 0 ? [] : [stringified];
102
- });
103
- const unique = [...new Set(values)];
104
- return unique.length > 0 ? unique : void 0;
105
- }
106
- function tryFlattenLiteralAnyOf(variants) {
107
- if (variants.length === 0) return null;
108
- const allValues = [];
109
- let commonType = null;
110
- for (const variant of variants) {
111
- if (!variant || typeof variant !== "object") return null;
112
- const v = variant;
113
- let literalValue;
114
- if ("const" in v) literalValue = v.const;
115
- else if (Array.isArray(v.enum) && v.enum.length === 1) literalValue = v.enum[0];
116
- else return null;
117
- const variantType = typeof v.type === "string" ? v.type : null;
118
- if (!variantType) return null;
119
- if (commonType === null) commonType = variantType;
120
- else if (commonType !== variantType) return null;
121
- allValues.push(literalValue);
122
- }
123
- if (commonType && allValues.length > 0) return {
124
- type: commonType,
125
- enum: allValues
126
- };
127
- return null;
128
- }
129
- function isNullSchema(variant) {
130
- if (!variant || typeof variant !== "object" || Array.isArray(variant)) return false;
131
- const record = variant;
132
- if ("const" in record && record.const === null) return true;
133
- if (Array.isArray(record.enum) && record.enum.length === 1) return record.enum[0] === null;
134
- const typeValue = record.type;
135
- if (typeValue === "null") return true;
136
- if (Array.isArray(typeValue) && typeValue.length === 1 && typeValue[0] === "null") return true;
137
- return false;
138
- }
139
- function stripNullVariants(variants) {
140
- if (variants.length === 0) return {
141
- variants,
142
- stripped: false
143
- };
144
- const nonNull = variants.filter((variant) => !isNullSchema(variant));
145
- return {
146
- variants: nonNull,
147
- stripped: nonNull.length !== variants.length
148
- };
149
- }
150
- function extendSchemaDefs$1(defs, schema) {
151
- const defsEntry = schema.$defs && typeof schema.$defs === "object" && !Array.isArray(schema.$defs) ? schema.$defs : void 0;
152
- const legacyDefsEntry = schema.definitions && typeof schema.definitions === "object" && !Array.isArray(schema.definitions) ? schema.definitions : void 0;
153
- if (!defsEntry && !legacyDefsEntry) return defs;
154
- const next = defs ? new Map(defs) : /* @__PURE__ */ new Map();
155
- if (defsEntry) for (const [key, value] of Object.entries(defsEntry)) next.set(key, value);
156
- if (legacyDefsEntry) for (const [key, value] of Object.entries(legacyDefsEntry)) next.set(key, value);
157
- return next;
158
- }
159
- function decodeJsonPointerSegment$1(segment) {
160
- return segment.replaceAll("~1", "/").replaceAll("~0", "~");
161
- }
162
- function tryResolveLocalRef$1(ref, defs) {
163
- if (!defs) return;
164
- const match = ref.match(/^#\/(?:\$defs|definitions)\/(.+)$/);
165
- if (!match) return;
166
- const name = decodeJsonPointerSegment$1(match[1] ?? "");
167
- if (!name) return;
168
- return defs.get(name);
169
- }
170
- function simplifyUnionVariants(params) {
171
- const { obj, variants } = params;
172
- const { variants: nonNullVariants, stripped } = stripNullVariants(variants);
173
- const flattened = tryFlattenLiteralAnyOf(nonNullVariants);
174
- if (flattened) {
175
- const result = {
176
- type: flattened.type,
177
- enum: flattened.enum
178
- };
179
- copySchemaMeta$1(obj, result);
180
- return {
181
- kind: "simplified",
182
- value: result
183
- };
184
- }
185
- if (stripped && nonNullVariants.length === 1) {
186
- const lone = nonNullVariants[0];
187
- if (lone && typeof lone === "object" && !Array.isArray(lone)) {
188
- const result = { ...lone };
189
- copySchemaMeta$1(obj, result);
190
- return {
191
- kind: "simplified",
192
- value: result
193
- };
194
- }
195
- return {
196
- kind: "simplified",
197
- value: lone
198
- };
199
- }
200
- return {
201
- kind: "variants",
202
- value: stripped ? nonNullVariants : variants
203
- };
204
- }
205
- function sanitizeRequiredFields(schema) {
206
- if (!Array.isArray(schema.required)) return schema;
207
- if (!schema.properties || typeof schema.properties !== "object" || Array.isArray(schema.properties)) {
208
- if (schema.type === "object") delete schema.required;
209
- return schema;
210
- }
211
- const properties = schema.properties;
212
- const required = schema.required.filter((key) => typeof key === "string" && Object.hasOwn(properties, key));
213
- if (required.length > 0) schema.required = required;
214
- else delete schema.required;
215
- return schema;
216
- }
217
- function cleanSchemaForGeminiWithDefs(schema, defs, refStack) {
218
- if (!schema || typeof schema !== "object") return schema;
219
- if (Array.isArray(schema)) return schema.map((item) => cleanSchemaForGeminiWithDefs(item, defs, refStack));
220
- const obj = schema;
221
- const nextDefs = extendSchemaDefs$1(defs, obj);
222
- const refValue = typeof obj.$ref === "string" ? obj.$ref : void 0;
223
- if (refValue) {
224
- if (refStack?.has(refValue)) return {};
225
- const resolved = tryResolveLocalRef$1(refValue, nextDefs);
226
- if (resolved) {
227
- const nextRefStack = refStack ? new Set(refStack) : /* @__PURE__ */ new Set();
228
- nextRefStack.add(refValue);
229
- const cleaned = cleanSchemaForGeminiWithDefs(resolved, nextDefs, nextRefStack);
230
- if (!cleaned || typeof cleaned !== "object" || Array.isArray(cleaned)) return cleaned;
231
- const result = { ...cleaned };
232
- copySchemaMeta$1(obj, result);
233
- return result;
234
- }
235
- const result = {};
236
- copySchemaMeta$1(obj, result);
237
- return result;
238
- }
239
- const hasAnyOf = "anyOf" in obj && Array.isArray(obj.anyOf);
240
- const hasOneOf = "oneOf" in obj && Array.isArray(obj.oneOf);
241
- let cleanedAnyOf = hasAnyOf ? obj.anyOf.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack)) : void 0;
242
- let cleanedOneOf = hasOneOf ? obj.oneOf.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack)) : void 0;
243
- if (hasAnyOf) {
244
- const simplified = simplifyUnionVariants({
245
- obj,
246
- variants: cleanedAnyOf ?? []
247
- });
248
- if (simplified.kind === "simplified") return simplified.value;
249
- cleanedAnyOf = simplified.value;
250
- }
251
- if (hasOneOf) {
252
- const simplified = simplifyUnionVariants({
253
- obj,
254
- variants: cleanedOneOf ?? []
255
- });
256
- if (simplified.kind === "simplified") return simplified.value;
257
- cleanedOneOf = simplified.value;
258
- }
259
- const cleaned = {};
260
- for (const [key, value] of Object.entries(obj)) {
261
- if (GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS.has(key)) continue;
262
- if (key === "const") {
263
- const enumValues = cleanGeminiEnumValues([value]);
264
- if (enumValues) cleaned.enum = enumValues;
265
- continue;
266
- }
267
- if (key === "enum") {
268
- const enumValues = cleanGeminiEnumValues(value);
269
- if (enumValues) cleaned.enum = enumValues;
270
- continue;
271
- }
272
- if (key === "required" && Array.isArray(value) && value.length === 0) continue;
273
- if (key === "type" && (hasAnyOf || hasOneOf)) continue;
274
- if (key === "type" && Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
275
- const types = value.filter((entry) => entry !== "null");
276
- cleaned.type = types.length === 1 ? types[0] : types;
277
- continue;
278
- }
279
- if (key === "properties") if (value && typeof value === "object" && !Array.isArray(value)) cleaned[key] = Object.fromEntries(Object.entries(value).map(([k, v]) => [k, cleanSchemaForGeminiWithDefs(v, nextDefs, refStack)]));
280
- else cleaned[key] = {};
281
- else if (key === "items" && value) if (Array.isArray(value)) cleaned[key] = value.map((entry) => cleanSchemaForGeminiWithDefs(entry, nextDefs, refStack));
282
- else if (typeof value === "object") cleaned[key] = cleanSchemaForGeminiWithDefs(value, nextDefs, refStack);
283
- else cleaned[key] = value;
284
- else if (key === "anyOf" && Array.isArray(value)) cleaned[key] = cleanedAnyOf ?? value.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack));
285
- else if (key === "oneOf" && Array.isArray(value)) cleaned[key] = cleanedOneOf ?? value.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack));
286
- else if (key === "allOf" && Array.isArray(value)) cleaned[key] = value.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack));
287
- else cleaned[key] = value;
288
- }
289
- if (cleaned.anyOf && Array.isArray(cleaned.anyOf)) {
290
- const flattened = flattenUnionFallback(cleaned, cleaned.anyOf);
291
- if (flattened) return sanitizeRequiredFields(flattened);
292
- }
293
- if (cleaned.oneOf && Array.isArray(cleaned.oneOf)) {
294
- const flattened = flattenUnionFallback(cleaned, cleaned.oneOf);
295
- if (flattened) return sanitizeRequiredFields(flattened);
296
- }
297
- return sanitizeRequiredFields(cleaned);
298
- }
299
- /**
300
- * Last-resort flattening for anyOf/oneOf arrays that could not be simplified
301
- * by `simplifyUnionVariants`. Picks a representative type so the schema is
302
- * accepted by Google's restricted JSON Schema validation.
303
- */
304
- function flattenUnionFallback(obj, variants) {
305
- const objects = variants.filter((v) => Boolean(v) && typeof v === "object");
306
- if (objects.length === 0) return;
307
- const types = new Set(objects.map((v) => v.type).filter(Boolean));
308
- if (objects.length === 1) {
309
- const merged = { ...objects[0] };
310
- copySchemaMeta$1(obj, merged);
311
- return merged;
312
- }
313
- if (types.size === 1) {
314
- const merged = { type: Array.from(types)[0] };
315
- copySchemaMeta$1(obj, merged);
316
- return merged;
317
- }
318
- const first = objects[0];
319
- if (first?.type) {
320
- const merged = { type: first.type };
321
- copySchemaMeta$1(obj, merged);
322
- return merged;
323
- }
324
- const merged = {};
325
- copySchemaMeta$1(obj, merged);
326
- return merged;
327
- }
328
- function cleanSchemaForGemini(schema) {
329
- if (!schema || typeof schema !== "object") return schema;
330
- if (Array.isArray(schema)) return schema.map(cleanSchemaForGemini);
331
- return cleanSchemaForGeminiWithDefs(schema, extendSchemaDefs$1(void 0, schema), void 0);
332
- }
333
- //#endregion
334
- //#region packages/ai/src/providers/clean-for-llamacpp-gbnf.ts
335
- /** llama.cpp rejects grammar repetitions whose expanded rule count reaches 2000. */
336
- const LLAMACPP_GBNF_MAX_REPETITION_THRESHOLD = 2e3;
337
- const SCHEMA_MAP_KEYS$2 = /* @__PURE__ */ new Set([
338
- "$defs",
339
- "definitions",
340
- "dependentSchemas",
341
- "patternProperties",
342
- "properties"
343
- ]);
344
- const SCHEMA_CHILD_KEYS = /* @__PURE__ */ new Set([
345
- "additionalItems",
346
- "additionalProperties",
347
- "allOf",
348
- "anyOf",
349
- "contains",
350
- "else",
351
- "if",
352
- "items",
353
- "not",
354
- "oneOf",
355
- "prefixItems",
356
- "propertyNames",
357
- "then",
358
- "unevaluatedItems",
359
- "unevaluatedProperties"
360
- ]);
361
- function cleanSchemaNode(node) {
362
- if (Array.isArray(node)) {
363
- let changed = false;
364
- const entries = node.map((entry) => {
365
- const next = cleanSchemaNode(entry);
366
- changed ||= next !== entry;
367
- return next;
368
- });
369
- return changed ? entries : node;
370
- }
371
- if (!isRecord(node)) return node;
372
- let changed = false;
373
- const cleaned = {};
374
- for (const [key, value] of Object.entries(node)) {
375
- if (key === "pattern") {
376
- changed = true;
377
- continue;
378
- }
379
- if (key === "maxLength" && typeof value === "number" && value >= 2e3) {
380
- changed = true;
381
- continue;
382
- }
383
- let next = value;
384
- if (SCHEMA_MAP_KEYS$2.has(key) && isRecord(value)) {
385
- let mapChanged = false;
386
- next = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => {
387
- const cleanedChild = cleanSchemaNode(childValue);
388
- mapChanged ||= cleanedChild !== childValue;
389
- return [childKey, cleanedChild];
390
- }));
391
- if (!mapChanged) next = value;
392
- } else if (SCHEMA_CHILD_KEYS.has(key)) next = cleanSchemaNode(value);
393
- cleaned[key] = next;
394
- changed ||= next !== value;
395
- }
396
- return changed ? cleaned : node;
397
- }
398
- function collectSchemaViolations(node, path, violations) {
399
- if (Array.isArray(node)) {
400
- node.forEach((entry, index) => collectSchemaViolations(entry, `${path}[${index}]`, violations));
401
- return;
402
- }
403
- if (!isRecord(node)) return;
404
- if ("pattern" in node) violations.push(`${path}.pattern`);
405
- if (typeof node.maxLength === "number" && node.maxLength >= 2e3) violations.push(`${path}.maxLength`);
406
- for (const [key, value] of Object.entries(node)) if (SCHEMA_MAP_KEYS$2.has(key) && isRecord(value)) for (const [childKey, childValue] of Object.entries(value)) collectSchemaViolations(childValue, `${path}.${key}.${childKey}`, violations);
407
- else if (SCHEMA_CHILD_KEYS.has(key)) collectSchemaViolations(value, `${path}.${key}`, violations);
408
- }
409
- /** Removes JSON Schema constraints that llama.cpp cannot compile into GBNF. */
410
- function cleanSchemaForLlamacppGbnf(schema) {
411
- return cleanSchemaNode(schema);
412
- }
413
- /** Reports schema paths that llama.cpp cannot compile into GBNF. */
414
- function findLlamacppGbnfSchemaViolations(schema, path) {
415
- const violations = [];
416
- collectSchemaViolations(schema, path, violations);
417
- return violations;
418
- }
419
- //#endregion
420
- //#region packages/ai/src/providers/schema-keyword-strip.ts
421
- const SCHEMA_MAP_KEYS$1 = /* @__PURE__ */ new Set([
422
- "$defs",
423
- "definitions",
424
- "dependentSchemas",
425
- "dependencies",
426
- "patternProperties",
427
- "properties"
428
- ]);
429
- /** Containers whose value is a single nested schema. */
430
- const SCHEMA_OBJECT_KEYS$1 = /* @__PURE__ */ new Set([
431
- "additionalItems",
432
- "additionalProperties",
433
- "contains",
434
- "contentSchema",
435
- "else",
436
- "if",
437
- "items",
438
- "not",
439
- "propertyNames",
440
- "then",
441
- "unevaluatedItems",
442
- "unevaluatedProperties"
443
- ]);
444
- /** Containers whose value is a list of nested schemas. */
445
- const SCHEMA_ARRAY_KEYS$1 = /* @__PURE__ */ new Set([
446
- "allOf",
447
- "anyOf",
448
- "items",
449
- "oneOf",
450
- "prefixItems"
451
- ]);
452
- /** Recursively remove schema keywords unsupported by a target provider/tool surface. */
453
- function stripUnsupportedSchemaKeywords(schema, unsupportedKeywords) {
454
- if (!schema || typeof schema !== "object") return schema;
455
- if (Array.isArray(schema)) return schema.map((entry) => stripUnsupportedSchemaKeywords(entry, unsupportedKeywords));
456
- const obj = schema;
457
- const cleaned = {};
458
- for (const [key, value] of Object.entries(obj)) {
459
- if (unsupportedKeywords.has(key)) continue;
460
- if (SCHEMA_MAP_KEYS$1.has(key) && value && typeof value === "object" && !Array.isArray(value)) {
461
- cleaned[key] = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => [childKey, stripUnsupportedSchemaKeywords(childValue, unsupportedKeywords)]));
462
- continue;
463
- }
464
- if (SCHEMA_ARRAY_KEYS$1.has(key) && Array.isArray(value)) {
465
- cleaned[key] = value.map((entry) => stripUnsupportedSchemaKeywords(entry, unsupportedKeywords));
466
- continue;
467
- }
468
- if (SCHEMA_OBJECT_KEYS$1.has(key) && value && typeof value === "object") {
469
- cleaned[key] = stripUnsupportedSchemaKeywords(value, unsupportedKeywords);
470
- continue;
471
- }
472
- cleaned[key] = value;
473
- }
474
- return cleaned;
475
- }
476
- //#endregion
477
- //#region packages/ai/src/providers/agent-tools-parameter-schema.ts
478
- /**
479
- * Normalizes model-facing tool parameter schemas across provider quirks.
480
- * Handles local JSON Schema refs, OpenAPI nullable syntax, top-level unions,
481
- * and provider-specific unsupported keyword stripping.
482
- */
483
- /** Extracts the compat record whether callers pass a model (`{ compat }`) or the compat itself. */
484
- function extractToolSchemaModelCompat(modelOrCompat) {
485
- if (!modelOrCompat || typeof modelOrCompat !== "object") return;
486
- if ("compat" in modelOrCompat) {
487
- const compat = modelOrCompat.compat;
488
- return compat && typeof compat === "object" ? compat : void 0;
489
- }
490
- return modelOrCompat;
491
- }
492
- /** JSON Schema keywords this model/provider rejects in tool schemas. */
493
- function resolveUnsupportedToolSchemaKeywords(modelOrCompat) {
494
- const keywords = extractToolSchemaModelCompat(modelOrCompat)?.unsupportedToolSchemaKeywords ?? [];
495
- return new Set(normalizeStringEntries(keywords.filter((keyword) => typeof keyword === "string")));
496
- }
497
- /** Whether empty `items: {}` on array schemas must be omitted for this model/provider. */
498
- function shouldOmitEmptyArrayItems(modelOrCompat) {
499
- return extractToolSchemaModelCompat(modelOrCompat)?.omitEmptyArrayItems === true;
500
- }
501
- const MAX_TOOL_PARAMETER_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
502
- const toolParameterSchemaCache = /* @__PURE__ */ new WeakMap();
503
- function resolveToolParameterSchemaCacheKey(options) {
504
- const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
505
- const normalizedModelId = normalizeLowercaseStringOrEmpty(options?.modelId);
506
- const toolSchemaProfile = normalizeLowercaseStringOrEmpty(options?.modelCompat?.toolSchemaProfile);
507
- const unsupportedKeywords = Array.from(resolveUnsupportedToolSchemaKeywords(options?.modelCompat)).toSorted();
508
- const omitEmptyArrayItems = shouldOmitEmptyArrayItems(options?.modelCompat);
509
- return JSON.stringify([
510
- normalizedProvider,
511
- normalizedModelId,
512
- toolSchemaProfile,
513
- unsupportedKeywords,
514
- omitEmptyArrayItems
515
- ]);
516
- }
517
- function getCachedToolParameterSchema(schema, key) {
518
- return toolParameterSchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
519
- }
520
- function rememberCachedToolParameterSchema(schema, key, value) {
521
- const entries = toolParameterSchemaCache.get(schema) ?? [];
522
- toolParameterSchemaCache.set(schema, [{
523
- key,
524
- value
525
- }, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_TOOL_PARAMETER_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
526
- return value;
527
- }
528
- function isGeminiModelId(modelId) {
529
- return /(?:^|[/:])gemini(?:$|[-/:.])/.test(modelId);
530
- }
531
- function extractEnumValues(schema) {
532
- if (!schema || typeof schema !== "object") return;
533
- const record = schema;
534
- if (Array.isArray(record.enum)) return record.enum;
535
- if ("const" in record) return [record.const];
536
- const variants = Array.isArray(record.anyOf) ? record.anyOf : Array.isArray(record.oneOf) ? record.oneOf : null;
537
- if (variants) {
538
- const values = variants.flatMap((variant) => {
539
- return extractEnumValues(variant) ?? [];
540
- });
541
- return values.length > 0 ? values : void 0;
542
- }
543
- }
544
- function mergePropertySchemas(existing, incoming) {
545
- if (!existing) return incoming;
546
- if (!incoming) return existing;
547
- const existingEnum = extractEnumValues(existing);
548
- const incomingEnum = extractEnumValues(incoming);
549
- if (existingEnum || incomingEnum) {
550
- const values = uniqueValues([...existingEnum ?? [], ...incomingEnum ?? []]);
551
- const merged = {};
552
- for (const source of [existing, incoming]) {
553
- if (!source || typeof source !== "object") continue;
554
- const record = source;
555
- for (const key of [
556
- "title",
557
- "description",
558
- "default"
559
- ]) if (!(key in merged) && key in record) merged[key] = record[key];
560
- }
561
- const types = new Set(values.map((value) => typeof value));
562
- if (types.size === 1) merged.type = Array.from(types)[0];
563
- merged.enum = values;
564
- return merged;
565
- }
566
- return existing;
567
- }
568
- function setOwnSchemaProperty(target, key, value) {
569
- Object.defineProperty(target, key, {
570
- value,
571
- enumerable: true,
572
- configurable: true,
573
- writable: true
574
- });
575
- }
576
- function hasTopLevelArrayKeyword(schemaRecord, key) {
577
- return Array.isArray(schemaRecord[key]);
578
- }
579
- function getFlattenableVariantKey(schemaRecord) {
580
- if (hasTopLevelArrayKeyword(schemaRecord, "anyOf")) return "anyOf";
581
- if (hasTopLevelArrayKeyword(schemaRecord, "oneOf")) return "oneOf";
582
- return null;
583
- }
584
- function getTopLevelConditionalKey(schemaRecord) {
585
- return getFlattenableVariantKey(schemaRecord) ?? (hasTopLevelArrayKeyword(schemaRecord, "allOf") ? "allOf" : null);
586
- }
587
- function hasTopLevelObjectSchema(schemaRecord, conditionalKey) {
588
- return schemaRecord.type === "object" && isRecord(schemaRecord.properties) && conditionalKey === null;
589
- }
590
- function isObjectLikeSchemaMissingType(schemaRecord, conditionalKey) {
591
- return !("type" in schemaRecord) && (isRecord(schemaRecord.properties) || Array.isArray(schemaRecord.required)) && conditionalKey === null;
592
- }
593
- function isTypedObjectSchemaMissingValidProperties(schemaRecord, conditionalKey) {
594
- return schemaRecord.type === "object" && !isRecord(schemaRecord.properties) && conditionalKey === null;
595
- }
596
- function isTrulyEmptySchema(schemaRecord) {
597
- return Object.keys(schemaRecord).length === 0;
598
- }
599
- function normalizeArraySchemasMissingItems(schema) {
600
- if (!isRecord(schema)) return schema;
601
- let changed = false;
602
- const nextSchema = { ...schema };
603
- if (nextSchema.type === "array" && nextSchema.items === void 0) {
604
- nextSchema.items = {};
605
- changed = true;
606
- }
607
- const normalizeSchemaValue = (key) => {
608
- if (!(key in nextSchema)) return;
609
- const value = nextSchema[key];
610
- if (Array.isArray(value)) {
611
- const normalized = value.map(normalizeArraySchemasMissingItems);
612
- if (normalized.some((entry, index) => entry !== value[index])) {
613
- nextSchema[key] = normalized;
614
- changed = true;
615
- }
616
- return;
617
- }
618
- const normalized = normalizeArraySchemasMissingItems(value);
619
- if (normalized !== value) {
620
- nextSchema[key] = normalized;
621
- changed = true;
622
- }
623
- };
624
- for (const key of [
625
- "items",
626
- "contains",
627
- "additionalProperties",
628
- "propertyNames",
629
- "not",
630
- "if",
631
- "then",
632
- "else"
633
- ]) normalizeSchemaValue(key);
634
- for (const key of [
635
- "anyOf",
636
- "oneOf",
637
- "allOf",
638
- "prefixItems"
639
- ]) normalizeSchemaValue(key);
640
- for (const key of [
641
- "properties",
642
- "patternProperties",
643
- "dependentSchemas",
644
- "$defs",
645
- "definitions"
646
- ]) {
647
- const value = nextSchema[key];
648
- if (!isRecord(value)) continue;
649
- let entriesChanged = false;
650
- const normalizedEntries = Object.entries(value).map(([entryKey, entryValue]) => {
651
- const normalizedEntryValue = normalizeArraySchemasMissingItems(entryValue);
652
- if (normalizedEntryValue !== entryValue) entriesChanged = true;
653
- return [entryKey, normalizedEntryValue];
654
- });
655
- if (entriesChanged) {
656
- nextSchema[key] = Object.fromEntries(normalizedEntries);
657
- changed = true;
658
- }
659
- }
660
- return changed ? nextSchema : schema;
661
- }
662
- function schemaAllowsArrayType(schema) {
663
- const type = schema.type;
664
- return type === "array" || Array.isArray(type) && type.includes("array");
665
- }
666
- const ARRAY_ITEMS_SCHEMA_OBJECT_KEYS = /* @__PURE__ */ new Set([
667
- "additionalProperties",
668
- "contains",
669
- "else",
670
- "if",
671
- "items",
672
- "not",
673
- "propertyNames",
674
- "then"
675
- ]);
676
- const ARRAY_ITEMS_SCHEMA_ARRAY_KEYS = /* @__PURE__ */ new Set([
677
- "allOf",
678
- "anyOf",
679
- "oneOf",
680
- "prefixItems"
681
- ]);
682
- const ARRAY_ITEMS_SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
683
- "$defs",
684
- "definitions",
685
- "dependentSchemas",
686
- "patternProperties",
687
- "properties"
688
- ]);
689
- function stripEmptyArrayItemsFromArraySchemas(schema) {
690
- if (Array.isArray(schema)) {
691
- let changed = false;
692
- const entries = schema.map((entry) => {
693
- const next = stripEmptyArrayItemsFromArraySchemas(entry);
694
- changed ||= next !== entry;
695
- return next;
696
- });
697
- return changed ? entries : schema;
698
- }
699
- if (!isRecord(schema)) return schema;
700
- let changed = false;
701
- const entries = Object.entries(schema).flatMap(([key, value]) => {
702
- if (key === "items" && schemaAllowsArrayType(schema) && isRecord(value) && isTrulyEmptySchema(value)) {
703
- changed = true;
704
- return [];
705
- }
706
- if (ARRAY_ITEMS_SCHEMA_OBJECT_KEYS.has(key)) {
707
- const next = stripEmptyArrayItemsFromArraySchemas(value);
708
- changed ||= next !== value;
709
- return [[key, next]];
710
- }
711
- if (ARRAY_ITEMS_SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
712
- const next = stripEmptyArrayItemsFromArraySchemas(value);
713
- changed ||= next !== value;
714
- return [[key, next]];
715
- }
716
- if (ARRAY_ITEMS_SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
717
- let mapChanged = false;
718
- const next = Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => {
719
- const entryNext = stripEmptyArrayItemsFromArraySchemas(entryValue);
720
- mapChanged ||= entryNext !== entryValue;
721
- return [entryKey, entryNext];
722
- }));
723
- changed ||= mapChanged;
724
- return [[key, mapChanged ? next : value]];
725
- }
726
- return [[key, value]];
727
- });
728
- return changed ? Object.fromEntries(entries) : schema;
729
- }
730
- function copySchemaMeta(from, to) {
731
- for (const key of [
732
- "title",
733
- "description",
734
- "default"
735
- ]) if (key in from && from[key] !== void 0) to[key] = from[key];
736
- }
737
- function extendSchemaDefs(defs, schema) {
738
- const defsEntry = schema.$defs && typeof schema.$defs === "object" && !Array.isArray(schema.$defs) ? schema.$defs : void 0;
739
- const legacyDefsEntry = schema.definitions && typeof schema.definitions === "object" && !Array.isArray(schema.definitions) ? schema.definitions : void 0;
740
- if (!defsEntry && !legacyDefsEntry) return defs;
741
- const next = defs ? {
742
- $defs: new Map(defs.$defs),
743
- definitions: new Map(defs.definitions)
744
- } : {
745
- $defs: /* @__PURE__ */ new Map(),
746
- definitions: /* @__PURE__ */ new Map()
747
- };
748
- if (defsEntry) for (const [key, value] of Object.entries(defsEntry)) next.$defs.set(key, value);
749
- if (legacyDefsEntry) for (const [key, value] of Object.entries(legacyDefsEntry)) next.definitions.set(key, value);
750
- return next;
751
- }
752
- function decodeJsonPointerSegment(segment) {
753
- return segment.replaceAll("~1", "/").replaceAll("~0", "~");
754
- }
755
- function resolveJsonPointerPath(value, segments) {
756
- let current = value;
757
- for (const segment of segments) {
758
- if (!current || typeof current !== "object") return;
759
- const key = decodeJsonPointerSegment(segment);
760
- if (Array.isArray(current)) {
761
- const index = /^(?:0|[1-9]\d*)$/.test(key) ? Number(key) : -1;
762
- if (index < 0 || index >= current.length) return;
763
- current = current[index];
764
- continue;
765
- }
766
- const record = current;
767
- if (!Object.hasOwn(record, key)) return;
768
- current = record[key];
769
- }
770
- return current;
771
- }
772
- function resolveLocalJsonPointer(rootDocument, ref) {
773
- if (!ref.startsWith("#/")) return;
774
- return resolveJsonPointerPath(rootDocument, ref.slice(2).split("/"));
775
- }
776
- const SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
777
- "$defs",
778
- "definitions",
779
- "dependentSchemas",
780
- "patternProperties",
781
- "properties"
782
- ]);
783
- const SCHEMA_OBJECT_KEYS = /* @__PURE__ */ new Set([
784
- "additionalProperties",
785
- "contains",
786
- "else",
787
- "if",
788
- "items",
789
- "not",
790
- "propertyNames",
791
- "then"
792
- ]);
793
- const SCHEMA_ARRAY_KEYS = /* @__PURE__ */ new Set([
794
- "allOf",
795
- "anyOf",
796
- "items",
797
- "oneOf",
798
- "prefixItems"
799
- ]);
800
- const SCHEMA_LITERAL_KEYS = /* @__PURE__ */ new Set([
801
- "const",
802
- "default",
803
- "enum",
804
- "examples"
805
- ]);
806
- function tryResolveLocalRef(ref, defs, rootDocument) {
807
- const match = ref.match(/^#\/(\$defs|definitions)\/([^/]+)(?:\/(.*))?$/);
808
- if (match && defs) {
809
- const namespace = match[1] === "$defs" ? defs.$defs : defs.definitions;
810
- const name = decodeJsonPointerSegment(match[2] ?? "");
811
- const resolved = name ? namespace.get(name) : void 0;
812
- if (resolved !== void 0) return resolveJsonPointerPath(resolved, match[3] ? match[3].split("/") : []);
813
- }
814
- return resolveLocalJsonPointer(rootDocument, ref);
815
- }
816
- function inlineLocalSchemaRefsWithDefs(schema, defs, refStack, state, rootDocument) {
817
- if (!schema || typeof schema !== "object") return schema;
818
- if (Array.isArray(schema)) return schema.map((entry) => inlineLocalSchemaRefsWithDefs(entry, defs, refStack, state, rootDocument));
819
- const obj = schema;
820
- const nextDefs = extendSchemaDefs(defs, obj);
821
- const refValue = typeof obj.$ref === "string" ? obj.$ref : void 0;
822
- if (refValue) {
823
- if (refStack?.has(refValue)) return {};
824
- const resolved = tryResolveLocalRef(refValue, nextDefs, rootDocument);
825
- if (resolved === void 0) {
826
- if (refValue.startsWith("#/")) state.unresolvedLocalRefs = true;
827
- return { ...obj };
828
- }
829
- const nextRefStack = refStack ? new Set(refStack) : /* @__PURE__ */ new Set();
830
- nextRefStack.add(refValue);
831
- const inlined = inlineLocalSchemaRefsWithDefs(resolved, nextDefs, nextRefStack, state, rootDocument);
832
- if (!inlined || typeof inlined !== "object" || Array.isArray(inlined)) return inlined;
833
- const result = { ...inlined };
834
- copySchemaMeta(obj, result);
835
- if (obj.nullable === true) result.nullable = true;
836
- return result;
837
- }
838
- const result = {};
839
- for (const [key, value] of Object.entries(obj)) {
840
- if (key === "$defs" || key === "definitions" || key === "components") continue;
841
- if (SCHEMA_LITERAL_KEYS.has(key)) {
842
- setOwnSchemaProperty(result, key, value);
843
- continue;
844
- }
845
- if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
846
- setOwnSchemaProperty(result, key, Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [entryKey, inlineLocalSchemaRefsWithDefs(entryValue, nextDefs, refStack, state, rootDocument)])));
847
- continue;
848
- }
849
- if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) {
850
- setOwnSchemaProperty(result, key, inlineLocalSchemaRefsWithDefs(value, nextDefs, refStack, state, rootDocument));
851
- continue;
852
- }
853
- if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
854
- setOwnSchemaProperty(result, key, value.map((entry) => inlineLocalSchemaRefsWithDefs(entry, nextDefs, refStack, state, rootDocument)));
855
- continue;
856
- }
857
- setOwnSchemaProperty(result, key, value);
858
- }
859
- if (state.unresolvedLocalRefs) {
860
- if ("$defs" in obj) result.$defs = obj.$defs;
861
- if ("definitions" in obj) result.definitions = obj.definitions;
862
- if ("components" in obj) result.components = obj.components;
863
- }
864
- return result;
865
- }
866
- /** Inline local $ref pointers so providers receive self-contained tool schemas. */
867
- function inlineLocalToolSchemaRefs(schema) {
868
- if (!schema || typeof schema !== "object") return schema;
869
- return inlineLocalSchemaRefsWithDefs(schema, extendSchemaDefs(void 0, schema), void 0, { unresolvedLocalRefs: false }, schema);
870
- }
871
- const OPENAPI_SCHEMA_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
872
- "discriminator",
873
- "externalDocs",
874
- "readOnly",
875
- "writeOnly",
876
- "xml",
877
- "example"
878
- ]);
879
- function appendNullSchemaType(type) {
880
- if (type === "null") return type;
881
- if (typeof type === "string") return [type, "null"];
882
- if (Array.isArray(type)) return type.includes("null") ? type : [...type, "null"];
883
- return type;
884
- }
885
- function isNullSchemaLike(schema) {
886
- if (!isRecord(schema)) return false;
887
- if (schema.type === "null") return true;
888
- if (Array.isArray(schema.type) && schema.type.includes("null")) return true;
889
- if ("const" in schema && schema.const === null) return true;
890
- return Array.isArray(schema.enum) && schema.enum.includes(null);
891
- }
892
- function hasOpenApiComposition(schema) {
893
- return [
894
- "allOf",
895
- "anyOf",
896
- "oneOf"
897
- ].some((key) => Array.isArray(schema[key]));
898
- }
899
- function schemaCompositionAlreadyAllowsNull(schema) {
900
- return Array.isArray(schema.anyOf) && schema.anyOf.some(isNullSchemaLike) || Array.isArray(schema.oneOf) && schema.oneOf.some(isNullSchemaLike);
901
- }
902
- function wrapNullableComposedSchema(schema) {
903
- if (schemaCompositionAlreadyAllowsNull(schema)) return schema;
904
- const wrapped = { anyOf: [schema, { type: "null" }] };
905
- copySchemaMeta(schema, wrapped);
906
- return wrapped;
907
- }
908
- function normalizeOpenApiSchemaKeywords(schema) {
909
- if (Array.isArray(schema)) {
910
- let changed = false;
911
- const normalized = schema.map((entry) => {
912
- const next = normalizeOpenApiSchemaKeywords(entry);
913
- changed ||= next !== entry;
914
- return next;
915
- });
916
- return changed ? normalized : schema;
917
- }
918
- if (!isRecord(schema)) return schema;
919
- let changed = false;
920
- const nullable = schema.nullable === true;
921
- const normalized = {};
922
- for (const [key, value] of Object.entries(schema)) {
923
- if (key === "nullable" || OPENAPI_SCHEMA_ANNOTATION_KEYS.has(key)) {
924
- changed = true;
925
- continue;
926
- }
927
- if (SCHEMA_LITERAL_KEYS.has(key)) {
928
- normalized[key] = value;
929
- continue;
930
- }
931
- if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
932
- let mapChanged = false;
933
- const next = Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => {
934
- const nextEntry = normalizeOpenApiSchemaKeywords(entryValue);
935
- mapChanged ||= nextEntry !== entryValue;
936
- return [entryKey, nextEntry];
937
- }));
938
- normalized[key] = mapChanged ? next : value;
939
- changed ||= mapChanged;
940
- continue;
941
- }
942
- if (key === "components") {
943
- normalized[key] = value;
944
- continue;
945
- }
946
- if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) {
947
- const next = normalizeOpenApiSchemaKeywords(value);
948
- normalized[key] = next;
949
- changed ||= next !== value;
950
- continue;
951
- }
952
- if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
953
- const next = value.map(normalizeOpenApiSchemaKeywords);
954
- normalized[key] = next;
955
- changed ||= next.some((entry, index) => entry !== value[index]);
956
- continue;
957
- }
958
- normalized[key] = value;
959
- }
960
- if (nullable) {
961
- if (hasOpenApiComposition(normalized)) return wrapNullableComposedSchema(normalized);
962
- if ("type" in normalized) {
963
- const nextType = appendNullSchemaType(normalized.type);
964
- if (nextType !== normalized.type) normalized.type = nextType;
965
- }
966
- if (Array.isArray(normalized.enum) && !normalized.enum.includes(null)) normalized.enum = [...normalized.enum, null];
967
- }
968
- return changed || nullable ? normalized : schema;
969
- }
970
- function normalizeToolParameterSchemaUncached(schema, options) {
971
- const inlinedSchema = normalizeOpenApiSchemaKeywords(inlineLocalToolSchemaRefs(schema));
972
- const schemaRecord = inlinedSchema && typeof inlinedSchema === "object" ? inlinedSchema : void 0;
973
- if (!schemaRecord) return inlinedSchema;
974
- const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
975
- const normalizedModelId = normalizeLowercaseStringOrEmpty(options?.modelId);
976
- const normalizedToolSchemaProfile = normalizeLowercaseStringOrEmpty(options?.modelCompat?.toolSchemaProfile);
977
- const isGeminiProvider = normalizedProvider.includes("google") || normalizedProvider.includes("gemini") || isGeminiModelId(normalizedModelId) || normalizedToolSchemaProfile === "gemini";
978
- const isAnthropicProvider = normalizedProvider.includes("anthropic");
979
- const unsupportedToolSchemaKeywords = resolveUnsupportedToolSchemaKeywords(options?.modelCompat);
980
- const omitEmptyArrayItems = shouldOmitEmptyArrayItems(options?.modelCompat);
981
- const isLlamacppGbnfProfile = normalizedToolSchemaProfile === "llamacpp";
982
- function applyProviderCleaning(s) {
983
- const normalizedSchema = normalizeArraySchemasMissingItems(s);
984
- let arrayItemsCompatibleSchema = omitEmptyArrayItems ? stripEmptyArrayItemsFromArraySchemas(normalizedSchema) : normalizedSchema;
985
- if (isLlamacppGbnfProfile) arrayItemsCompatibleSchema = cleanSchemaForLlamacppGbnf(arrayItemsCompatibleSchema);
986
- if (isGeminiProvider && !isAnthropicProvider) {
987
- const geminiCompatibleSchema = cleanSchemaForGemini(arrayItemsCompatibleSchema);
988
- return unsupportedToolSchemaKeywords.size > 0 ? stripUnsupportedSchemaKeywords(geminiCompatibleSchema, unsupportedToolSchemaKeywords) : geminiCompatibleSchema;
989
- }
990
- if (unsupportedToolSchemaKeywords.size > 0) return stripUnsupportedSchemaKeywords(arrayItemsCompatibleSchema, unsupportedToolSchemaKeywords);
991
- return arrayItemsCompatibleSchema;
992
- }
993
- const conditionalKey = getTopLevelConditionalKey(schemaRecord);
994
- const flattenableVariantKey = getFlattenableVariantKey(schemaRecord);
995
- if (hasTopLevelObjectSchema(schemaRecord, conditionalKey)) return applyProviderCleaning(schemaRecord);
996
- if (isObjectLikeSchemaMissingType(schemaRecord, conditionalKey)) return applyProviderCleaning({
997
- ...schemaRecord,
998
- type: "object",
999
- properties: isRecord(schemaRecord.properties) ? schemaRecord.properties : {}
1000
- });
1001
- if (isTypedObjectSchemaMissingValidProperties(schemaRecord, conditionalKey)) return applyProviderCleaning({
1002
- ...schemaRecord,
1003
- properties: {}
1004
- });
1005
- if (!flattenableVariantKey) {
1006
- if (isTrulyEmptySchema(schemaRecord)) return applyProviderCleaning({
1007
- type: "object",
1008
- properties: {}
1009
- });
1010
- if (conditionalKey === "allOf") return applyProviderCleaning(inlinedSchema);
1011
- return applyProviderCleaning(inlinedSchema);
1012
- }
1013
- const variants = schemaRecord[flattenableVariantKey];
1014
- const mergedProperties = {};
1015
- const requiredCounts = /* @__PURE__ */ new Map();
1016
- let objectVariants = 0;
1017
- for (const entry of variants) {
1018
- if (!entry || typeof entry !== "object") continue;
1019
- const props = entry.properties;
1020
- if (!props || typeof props !== "object") continue;
1021
- objectVariants += 1;
1022
- for (const [key, value] of Object.entries(props)) {
1023
- if (!(key in mergedProperties)) {
1024
- mergedProperties[key] = value;
1025
- continue;
1026
- }
1027
- mergedProperties[key] = mergePropertySchemas(mergedProperties[key], value);
1028
- }
1029
- const required = Array.isArray(entry.required) ? entry.required : [];
1030
- for (const key of required) {
1031
- if (typeof key !== "string") continue;
1032
- requiredCounts.set(key, (requiredCounts.get(key) ?? 0) + 1);
1033
- }
1034
- }
1035
- const baseRequired = Array.isArray(schemaRecord.required) ? schemaRecord.required.filter((key) => typeof key === "string") : void 0;
1036
- const mergedRequired = baseRequired && baseRequired.length > 0 ? baseRequired : objectVariants > 0 ? Array.from(requiredCounts.entries()).filter(([, count]) => count === objectVariants).map(([key]) => key) : void 0;
1037
- const nextSchema = { ...schemaRecord };
1038
- return applyProviderCleaning({
1039
- type: "object",
1040
- ...typeof nextSchema.title === "string" ? { title: nextSchema.title } : {},
1041
- ...typeof nextSchema.description === "string" ? { description: nextSchema.description } : {},
1042
- properties: Object.keys(mergedProperties).length > 0 ? mergedProperties : schemaRecord.properties ?? {},
1043
- ...mergedRequired && mergedRequired.length > 0 ? { required: mergedRequired } : {},
1044
- additionalProperties: "additionalProperties" in schemaRecord ? schemaRecord.additionalProperties : true
1045
- });
1046
- }
1047
- /** Return a provider-compatible JSON schema for a model-facing tool. */
1048
- function normalizeToolParameterSchema(schema, options) {
1049
- if (!schema || typeof schema !== "object") return normalizeToolParameterSchemaUncached(schema, options);
1050
- const cacheKey = resolveToolParameterSchemaCacheKey(options);
1051
- const cached = getCachedToolParameterSchema(schema, cacheKey);
1052
- if (cached) return cached;
1053
- return rememberCachedToolParameterSchema(schema, cacheKey, normalizeToolParameterSchemaUncached(schema, options));
1054
- }
1055
- //#endregion
1056
- //#region packages/ai/src/providers/openai-tool-schema-compat.ts
1057
- const OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
1058
- "$defs",
1059
- "definitions",
1060
- "dependentSchemas",
1061
- "dependencies",
1062
- "patternProperties",
1063
- "properties"
1064
- ]);
1065
- const OPENAI_NULLABLE_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
1066
- "default",
1067
- "description",
1068
- "examples",
1069
- "format",
1070
- "title"
1071
- ]);
1072
- const OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS = /* @__PURE__ */ new Set([
1073
- "additionalItems",
1074
- "additionalProperties",
1075
- "allOf",
1076
- "anyOf",
1077
- "contains",
1078
- "contentSchema",
1079
- "else",
1080
- "if",
1081
- "items",
1082
- "not",
1083
- "oneOf",
1084
- "prefixItems",
1085
- "propertyNames",
1086
- "then",
1087
- "unevaluatedItems",
1088
- "unevaluatedProperties"
1089
- ]);
1090
- function normalizeOpenAIStrictCompatSchemaMap(schema) {
1091
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
1092
- let changed = false;
1093
- const normalized = {};
1094
- for (const [key, value] of Object.entries(schema)) {
1095
- const next = normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false });
1096
- normalized[key] = next;
1097
- changed ||= next !== value;
1098
- }
1099
- return changed ? normalized : schema;
1100
- }
1101
- function normalizeOpenAIStrictCompatSchemaRecursive(schema, options) {
1102
- if (Array.isArray(schema)) {
1103
- let changed = false;
1104
- const normalized = schema.map((entry) => {
1105
- const next = normalizeOpenAIStrictCompatSchemaRecursive(entry, { promoteEmptyObject: false });
1106
- changed ||= next !== entry;
1107
- return next;
1108
- });
1109
- return changed ? normalized : schema;
1110
- }
1111
- if (!schema || typeof schema !== "object") return schema;
1112
- const record = schema;
1113
- let changed = false;
1114
- let hadNullType = false;
1115
- const normalized = {};
1116
- for (const [key, value] of Object.entries(record)) {
1117
- if (value === null && OPENAI_NULLABLE_ANNOTATION_KEYS.has(key)) {
1118
- changed = true;
1119
- continue;
1120
- }
1121
- if (value === null && key === "type") {
1122
- hadNullType = true;
1123
- changed = true;
1124
- continue;
1125
- }
1126
- const next = OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaMap(value) : OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false }) : value;
1127
- normalized[key] = next;
1128
- changed ||= next !== value;
1129
- }
1130
- if (Object.keys(normalized).length === 0) {
1131
- if (!options.promoteEmptyObject) return schema;
1132
- return {
1133
- type: "object",
1134
- properties: {},
1135
- required: [],
1136
- additionalProperties: false
1137
- };
1138
- }
1139
- const hasObjectShapeHints = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) || Array.isArray(normalized.required);
1140
- const hasArrayShapeHints = "items" in normalized;
1141
- if (!("type" in normalized) && hasObjectShapeHints !== hasArrayShapeHints) {
1142
- normalized.type = hasObjectShapeHints ? "object" : "array";
1143
- changed = true;
1144
- } else if (hadNullType && !("type" in normalized)) normalized.type = null;
1145
- if (normalized.type === "object" && !("properties" in normalized)) {
1146
- normalized.properties = {};
1147
- changed = true;
1148
- }
1149
- const hasEmptyProperties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) && Object.keys(normalized.properties).length === 0;
1150
- if (normalized.type === "object" && !Array.isArray(normalized.required) && hasEmptyProperties) {
1151
- normalized.required = [];
1152
- changed = true;
1153
- }
1154
- if (normalized.type === "object" && hasEmptyProperties && !("additionalProperties" in normalized)) {
1155
- normalized.additionalProperties = false;
1156
- changed = true;
1157
- }
1158
- return changed ? normalized : schema;
1159
- }
1160
- /** Repairs recoverable OpenAI tool-schema shapes before canonical normalization. */
1161
- function normalizeOpenAIStrictCompatSchema(schema) {
1162
- return normalizeOpenAIStrictCompatSchemaRecursive(schema, { promoteEmptyObject: true });
1163
- }
1164
- /** Finds schema paths that violate OpenAI strict tool-schema requirements. */
1165
- function findOpenAIStrictSchemaViolations(schema, path, options) {
1166
- if (Array.isArray(schema)) {
1167
- if (options?.requireObjectRoot) return [`${path}.type`];
1168
- return schema.flatMap((item, index) => findOpenAIStrictSchemaViolations(item, `${path}[${index}]`));
1169
- }
1170
- if (!schema || typeof schema !== "object") return options?.requireObjectRoot ? [`${path}.type`] : [];
1171
- const record = schema;
1172
- const violations = [];
1173
- for (const key of [
1174
- "anyOf",
1175
- "oneOf",
1176
- "allOf"
1177
- ]) if (key in record) violations.push(`${path}.${key}`);
1178
- if (Array.isArray(record.type)) violations.push(`${path}.type`);
1179
- const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : void 0;
1180
- if (record.type === "object") {
1181
- if (record.additionalProperties !== false) violations.push(`${path}.additionalProperties`);
1182
- const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
1183
- if (!required) violations.push(`${path}.required`);
1184
- else if (properties) {
1185
- const requiredSet = new Set(required);
1186
- for (const key of Object.keys(properties)) if (!requiredSet.has(key)) violations.push(`${path}.required.${key}`);
1187
- }
1188
- }
1189
- for (const key of OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS) {
1190
- const schemaMap = record[key];
1191
- if (!schemaMap || typeof schemaMap !== "object" || Array.isArray(schemaMap)) continue;
1192
- for (const [entryKey, value] of Object.entries(schemaMap)) violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}.${entryKey}`));
1193
- }
1194
- for (const key of OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS) {
1195
- const value = record[key];
1196
- if (value && typeof value === "object") violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}`));
1197
- }
1198
- return violations;
1199
- }
1200
- //#endregion
1201
- //#region packages/ai/src/providers/openai-tool-schema.ts
1202
- /**
1203
- * OpenAI strict JSON-schema normalization for tool inventories and request payloads.
1204
- *
1205
- * Caches normalized object inputs by provider compatibility so repeated inventory builds preserve identity.
1206
- */
1207
- const MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
1208
- const strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
1209
- function resolveToolSchemaModelCompat(compat) {
1210
- if (!compat) return;
1211
- const unsupportedToolSchemaKeywords = Array.isArray(compat.unsupportedToolSchemaKeywords) ? compat.unsupportedToolSchemaKeywords.filter((keyword) => typeof keyword === "string") : [];
1212
- if (unsupportedToolSchemaKeywords.length === 0 && compat.omitEmptyArrayItems !== true) return;
1213
- return {
1214
- ...unsupportedToolSchemaKeywords.length > 0 ? { unsupportedToolSchemaKeywords } : {},
1215
- ...compat.omitEmptyArrayItems === true ? { omitEmptyArrayItems: true } : {}
1216
- };
1217
- }
1218
- function resolveStrictOpenAISchemaCacheKey(modelCompat) {
1219
- const compat = resolveToolSchemaModelCompat(modelCompat);
1220
- return JSON.stringify([[...compat?.unsupportedToolSchemaKeywords ?? []].toSorted(), shouldOmitEmptyArrayItems(compat)]);
1221
- }
1222
- function readCachedStrictOpenAISchema(schema, key) {
1223
- return strictOpenAISchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
1224
- }
1225
- function rememberStrictOpenAISchema(schema, key, value) {
1226
- const entries = strictOpenAISchemaCache.get(schema) ?? [];
1227
- strictOpenAISchemaCache.set(schema, [{
1228
- key,
1229
- value
1230
- }, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
1231
- return value;
1232
- }
1233
- /** Normalizes a tool parameter schema into the OpenAI strict JSON-schema subset. */
1234
- function normalizeStrictOpenAIJsonSchema(schema, modelCompat) {
1235
- const schemaInput = schema ?? {};
1236
- if (!schemaInput || typeof schemaInput !== "object") return normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0);
1237
- const cacheKey = resolveStrictOpenAISchemaCacheKey(modelCompat);
1238
- const cached = readCachedStrictOpenAISchema(schemaInput, cacheKey);
1239
- if (cached !== void 0) return cached;
1240
- return rememberStrictOpenAISchema(schemaInput, cacheKey, normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0));
1241
- }
1242
- function normalizeStrictOpenAIJsonSchemaRecursive(schema, depth) {
1243
- if (Array.isArray(schema)) {
1244
- let changed = false;
1245
- const normalized = schema.map((entry) => {
1246
- const next = normalizeStrictOpenAIJsonSchemaRecursive(entry, depth);
1247
- changed ||= next !== entry;
1248
- return next;
1249
- });
1250
- return changed ? normalized : schema;
1251
- }
1252
- if (!schema || typeof schema !== "object") return schema;
1253
- const record = schema;
1254
- let changed = false;
1255
- const normalized = {};
1256
- for (const [key, value] of Object.entries(record)) {
1257
- const next = normalizeStrictOpenAIJsonSchemaRecursive(value, key === "properties" ? depth : depth + 1);
1258
- normalized[key] = next;
1259
- changed ||= next !== value;
1260
- }
1261
- if (normalized.type === "object") {
1262
- const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : void 0;
1263
- if (properties && Object.keys(properties).length === 0 && !Array.isArray(normalized.required)) {
1264
- normalized.required = [];
1265
- changed = true;
1266
- }
1267
- if (depth === 0 && !("additionalProperties" in normalized)) {
1268
- normalized.additionalProperties = false;
1269
- changed = true;
1270
- }
1271
- }
1272
- return changed ? normalized : schema;
1273
- }
1274
- /** Normalizes tool parameters using strict OpenAI rules only when strict mode is active. */
1275
- function normalizeOpenAIStrictToolParameters(schema, strict, modelCompat) {
1276
- const toolSchemaCompat = resolveToolSchemaModelCompat(modelCompat);
1277
- if (!strict) return normalizeToolParameterSchema(schema ?? {}, { modelCompat: toolSchemaCompat });
1278
- return normalizeStrictOpenAIJsonSchema(schema, toolSchemaCompat);
1279
- }
1280
- /** Returns whether a schema already satisfies OpenAI strict tool-schema constraints. */
1281
- function isStrictOpenAIJsonSchemaCompatible(schema) {
1282
- return isStrictOpenAIJsonSchemaCompatibleRecursive(normalizeStrictOpenAIJsonSchema(schema));
1283
- }
1284
- /** Returns strict-schema diagnostics for an already materialized OpenAI tool projection. */
1285
- function findOpenAIStrictToolProjectionDiagnostics(projection) {
1286
- return [...projection.diagnostics.map((diagnostic) => ({
1287
- toolIndex: diagnostic.toolIndex,
1288
- ...diagnostic.toolName ? { toolName: diagnostic.toolName } : {},
1289
- violations: [...diagnostic.violations]
1290
- })), ...projection.tools.flatMap((tool) => {
1291
- const violations = findOpenAIStrictSchemaViolations(normalizeStrictOpenAIJsonSchema(tool.parameters), `${tool.name}.parameters`);
1292
- return violations.length > 0 ? [{
1293
- toolIndex: tool.toolIndex,
1294
- toolName: tool.name,
1295
- violations
1296
- }] : [];
1297
- })];
1298
- }
1299
- function isStrictOpenAIJsonSchemaCompatibleRecursive(schema) {
1300
- if (Array.isArray(schema)) return schema.every((entry) => isStrictOpenAIJsonSchemaCompatibleRecursive(entry));
1301
- if (!schema || typeof schema !== "object") return true;
1302
- const record = schema;
1303
- if ("anyOf" in record || "oneOf" in record || "allOf" in record) return false;
1304
- if (Array.isArray(record.type)) return false;
1305
- if (record.type === "object" && record.additionalProperties !== false) return false;
1306
- if (record.type === "object") {
1307
- const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : {};
1308
- const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
1309
- if (!required) return false;
1310
- const requiredSet = new Set(required);
1311
- if (Object.keys(properties).some((key) => !requiredSet.has(key))) return false;
1312
- }
1313
- return Object.entries(record).every(([key, entry]) => {
1314
- if (key === "properties" && entry && typeof entry === "object" && !Array.isArray(entry)) return Object.values(entry).every((value) => isStrictOpenAIJsonSchemaCompatibleRecursive(value));
1315
- return isStrictOpenAIJsonSchemaCompatibleRecursive(entry);
1316
- });
1317
- }
1318
- /** Resolves strict mode for the projected tools that will be emitted in the request payload. */
1319
- function resolveOpenAIProjectedToolsStrictToolFlag(projection, strict) {
1320
- if (strict !== true) return strict === false ? false : void 0;
1321
- return projection.tools.every((tool) => isStrictOpenAIJsonSchemaCompatible(tool.parameters));
1322
- }
1323
- //#endregion
1324
59
  //#region packages/ai/src/transports/openai-responses-replay.ts
1325
60
  /** Resolves the assistant message id that can be replayed to OpenAI Responses. */
1326
61
  function resolveReplayableResponsesMessageId(params) {
@@ -1799,8 +534,8 @@ function isInvalidEncryptedContentError(error) {
1799
534
  if (!error || typeof error !== "object") return false;
1800
535
  const record = error;
1801
536
  if (record.code === "invalid_encrypted_content" || record.code === "thinking_signature_invalid") return true;
1802
- const message = typeof record.message === "string" ? record.message : "";
1803
- return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || record.status === 400 && message.toLowerCase().includes("could not decrypt the provided encrypted_content");
537
+ const message = typeof record.message === "string" ? record.message.toLowerCase() : "";
538
+ return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || (record.status === 400 || record.status == null && /(?:^|[\s(])400(?:[\s):]|$)/.test(message)) && (message.includes("could not decrypt the provided encrypted_content") || message.includes("encrypted content") && (message.includes("could not be verified") || message.includes("could not be decrypted or parsed")));
1804
539
  }
1805
540
  function isOrphanedFunctionCallOutputError(error) {
1806
541
  if (!error || typeof error !== "object") return false;
@@ -1880,7 +615,45 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
1880
615
  payloadVariant: attempt.kind
1881
616
  });
1882
617
  try {
1883
- return await sendAttempt(attempt);
618
+ const result = await sendAttempt(attempt);
619
+ return {
620
+ ...result,
621
+ stream: { async *[Symbol.asyncIterator]() {
622
+ let rejectedEvent;
623
+ try {
624
+ for await (const event of params.wrapStream?.(result) ?? result.stream) {
625
+ if (isRecord(event)) {
626
+ const failure = event.type === "response.failed" && isRecord(event.response) ? event.response.error : event.type === "error" ? event.error ?? event : void 0;
627
+ if (isRecord(failure) && params.canRetryStream?.() === true && isInvalidEncryptedContentError(failure)) {
628
+ rejectedEvent = event;
629
+ const message = typeof failure.message === "string" ? failure.message : "";
630
+ throw Object.assign(new Error(message), {
631
+ code: failure.code,
632
+ status: failure.status
633
+ });
634
+ }
635
+ }
636
+ yield event;
637
+ }
638
+ } catch (error) {
639
+ const nextAttempt = params.canRetryStream?.() === true && !params.requestOptions?.signal?.aborted ? await resolveNextResponsesEncryptedContentAttempt(result.attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest }) : void 0;
640
+ if (!nextAttempt) {
641
+ if (rejectedEvent !== void 0) {
642
+ yield rejectedEvent;
643
+ return;
644
+ }
645
+ throw error;
646
+ }
647
+ log.warn(`[responses] retrying streamed encrypted content provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
648
+ yield* (await createResponsesStreamWithEncryptedContentRetry({
649
+ ...params,
650
+ request: nextAttempt.request,
651
+ initialAttemptKind: nextAttempt.kind,
652
+ initialRejectedCompaction: nextAttempt.rejectedCompaction
653
+ })).stream;
654
+ }
655
+ } }
656
+ };
1884
657
  } catch (error) {
1885
658
  let nextAttempt = await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
1886
659
  if (!nextAttempt && attempt.request.previous_response_id && error && typeof error === "object" && typeof error.status === "number" && error.code === "previous_response_not_found") {
@@ -2346,20 +1119,38 @@ async function* observeResponsesStream(stream, model, requestStartedAt) {
2346
1119
  }
2347
1120
  //#endregion
2348
1121
  //#region packages/ai/src/transports/openai-responses-stream-slots-internal.ts
2349
- function createResponsesOutputContentIndex() {
2350
- const indexes = /* @__PURE__ */ new Map();
1122
+ function createResponsesOutputTracker() {
1123
+ const outputs = /* @__PURE__ */ new Map();
2351
1124
  const identity = (item) => {
2352
1125
  if ((item.type === "reasoning" || item.type === "message") && item.id) return `${item.type}:${item.id}`;
2353
1126
  return item.type === "function_call" ? `function_call:${item.call_id ?? item.id ?? ""}` : void 0;
2354
1127
  };
1128
+ const get = (item, outputIndex) => {
1129
+ const key = identity(item);
1130
+ const output = (outputIndex === void 0 ? void 0 : outputs.get(outputIndex)) ?? (key === void 0 ? void 0 : outputs.get(key));
1131
+ if (!output || outputIndex !== void 0 && output.outputIndex !== void 0 && output.outputIndex !== outputIndex) return;
1132
+ if (output.type !== item.type || output.callId && item.call_id && output.callId !== item.call_id) throw new Error("Responses stream changed output item identity");
1133
+ return output;
1134
+ };
2355
1135
  return {
2356
- get(item) {
2357
- const key = identity(item);
2358
- return key === void 0 ? void 0 : indexes.get(key);
2359
- },
2360
- set(item, contentIndex) {
1136
+ get,
1137
+ set(item, contentIndex, outputIndex, completed = false) {
1138
+ const output = get(item, outputIndex) ?? {
1139
+ type: item.type,
1140
+ contentIndex,
1141
+ completed
1142
+ };
1143
+ Object.assign(output, {
1144
+ contentIndex,
1145
+ completed
1146
+ });
1147
+ if (item.call_id) output.callId = item.call_id;
1148
+ if (outputIndex !== void 0) {
1149
+ output.outputIndex = outputIndex;
1150
+ outputs.set(outputIndex, output);
1151
+ }
2361
1152
  const key = identity(item);
2362
- if (key !== void 0) indexes.set(key, contentIndex);
1153
+ if (key !== void 0) outputs.set(key, output);
2363
1154
  }
2364
1155
  };
2365
1156
  }
@@ -2509,51 +1300,52 @@ function createResponsesTerminalController(params) {
2509
1300
  const { output, stream, model, options } = params;
2510
1301
  const blocks = output.content;
2511
1302
  const backfillReasoning = (items) => {
2512
- for (const item of items) {
1303
+ for (const [outputIndex, item] of items.entries()) {
2513
1304
  if (item.type !== "reasoning" || !item.encrypted_content) continue;
2514
- const block = params.reasoningBlocksById.get(item.id);
2515
- if (!block?.thinkingSignature) continue;
1305
+ const tracked = params.outputs.get(item, outputIndex);
1306
+ const block = tracked && blocks[tracked.contentIndex];
1307
+ if (block?.type !== "thinking" || !block.thinkingSignature) continue;
2516
1308
  const stored = JSON.parse(block.thinkingSignature);
2517
1309
  if (!stored.encrypted_content) block.thinkingSignature = JSON.stringify({
2518
1310
  ...stored,
2519
1311
  encrypted_content: item.encrypted_content
2520
1312
  });
2521
- if (options?.reasoningReplayMetadata) block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
1313
+ if (options?.reasoningReplayMetadata) Object.assign(block, { [OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY]: options.reasoningReplayMetadata });
2522
1314
  }
2523
1315
  };
2524
- const appendText = (item) => {
1316
+ const appendText = (item, contentIndex) => {
2525
1317
  const text = (Array.isArray(item.content) ? item.content : []).map((part) => {
2526
1318
  const content = part;
2527
1319
  return content.type === "output_text" || content.type === "text" ? content.text ?? "" : content.refusal ?? "";
2528
1320
  }).join("");
2529
- const started = params.startedTextBlocksByItemId.get(item.id);
1321
+ const block = contentIndex === void 0 ? void 0 : blocks[contentIndex];
1322
+ const started = block?.type === "text" ? block : void 0;
2530
1323
  if (!text && !started) return;
2531
1324
  const phase = item.phase ?? void 0;
2532
- if (started) {
2533
- const previousText = started.block.text;
2534
- started.block.text = text;
2535
- started.block.textSignature = encodeTextSignatureV1(item.id, phase);
1325
+ if (started && contentIndex !== void 0) {
1326
+ const previousText = started.text;
1327
+ started.text = text;
1328
+ started.textSignature = encodeTextSignatureV1(item.id, phase);
2536
1329
  params.setLastTextBlock({
2537
- block: started.block,
2538
- index: started.index,
1330
+ block: started,
1331
+ index: contentIndex,
2539
1332
  phase
2540
1333
  });
2541
- params.startedTextBlocksByItemId.delete(item.id);
2542
1334
  if (text.startsWith(previousText)) {
2543
1335
  const delta = text.slice(previousText.length);
2544
1336
  if (delta) stream.push({
2545
1337
  type: "text_delta",
2546
- contentIndex: started.index,
1338
+ contentIndex,
2547
1339
  delta
2548
1340
  });
2549
1341
  }
2550
1342
  stream.push({
2551
1343
  type: "text_end",
2552
- contentIndex: started.index,
1344
+ contentIndex,
2553
1345
  content: text,
2554
1346
  partial: output
2555
1347
  });
2556
- return started.index;
1348
+ return contentIndex;
2557
1349
  }
2558
1350
  const previous = params.getLastTextBlock();
2559
1351
  const collapse = resolveResponsesMessageSnapshotCollapse({
@@ -2575,15 +1367,15 @@ function createResponsesTerminalController(params) {
2575
1367
  });
2576
1368
  return previous.index;
2577
1369
  }
2578
- const block = {
1370
+ const newBlock = {
2579
1371
  type: "text",
2580
1372
  text,
2581
1373
  textSignature: encodeTextSignatureV1(item.id, phase)
2582
1374
  };
2583
- blocks.push(block);
1375
+ blocks.push(newBlock);
2584
1376
  const index = blocks.length - 1;
2585
1377
  params.setLastTextBlock({
2586
- block,
1378
+ block: newBlock,
2587
1379
  index,
2588
1380
  phase
2589
1381
  });
@@ -2625,13 +1417,14 @@ function createResponsesTerminalController(params) {
2625
1417
  };
2626
1418
  const recoverTerminalOutput = (items, includeToolCalls) => {
2627
1419
  let hasCompletedLaterOutput = false;
2628
- for (const item of items.toReversed()) {
1420
+ for (const [outputIndex, item] of [...items.entries()].toReversed()) {
1421
+ const tracked = params.outputs.get(item, outputIndex);
2629
1422
  if (item.type === "reasoning") {
2630
- hasCompletedLaterOutput ||= params.outputItemContentIndexes.get(item) !== void 0;
1423
+ hasCompletedLaterOutput ||= tracked !== void 0;
2631
1424
  continue;
2632
1425
  }
2633
1426
  if (item.type !== "message" && item.type !== "function_call") continue;
2634
- if (params.outputItemContentIndexes.get(item) !== void 0 || item.type === "message" && params.startedTextBlocksByItemId.has(item.id)) {
1427
+ if (tracked) {
2635
1428
  hasCompletedLaterOutput = true;
2636
1429
  continue;
2637
1430
  }
@@ -2640,16 +1433,18 @@ function createResponsesTerminalController(params) {
2640
1433
  if (item.type === "function_call") resolveCompletedResponsesToolCall(item);
2641
1434
  }
2642
1435
  for (const [terminalIndex, item] of items.entries()) if (item.type === "message") {
2643
- if (params.outputItemContentIndexes.get(item) !== void 0 && !params.startedTextBlocksByItemId.has(item.id)) continue;
2644
- const appendedIndex = appendText(item);
2645
- if (appendedIndex !== void 0) params.outputItemContentIndexes.set(item, appendedIndex);
1436
+ const tracked = params.outputs.get(item, terminalIndex);
1437
+ if (tracked?.completed) continue;
1438
+ const appendedIndex = appendText(item, tracked?.contentIndex);
1439
+ if (appendedIndex !== void 0) params.outputs.set(item, appendedIndex, terminalIndex, true);
2646
1440
  } else {
2647
1441
  params.setLastTextBlock(null);
2648
1442
  const alreadyCapturedCompaction = item.type === "compaction" && output.providerReplay?.type === "openai-responses-compaction" && output.providerReplay.id === item.id && output.providerReplay.data === item.encrypted_content;
2649
1443
  if (item.type === "compaction" && !alreadyCapturedCompaction) {
2650
1444
  let replayIndex = blocks.length;
2651
- for (const laterItem of items.slice(terminalIndex + 1)) {
2652
- const laterContentIndex = params.outputItemContentIndexes.get(laterItem);
1445
+ for (const [laterIndex, laterItem] of items.entries()) {
1446
+ if (laterIndex <= terminalIndex) continue;
1447
+ const laterContentIndex = params.outputs.get(laterItem, laterIndex)?.contentIndex;
2653
1448
  if (laterContentIndex !== void 0) {
2654
1449
  replayIndex = laterContentIndex;
2655
1450
  break;
@@ -2657,8 +1452,8 @@ function createResponsesTerminalController(params) {
2657
1452
  }
2658
1453
  captureOpenAIResponsesCompaction(output, item, replayIndex, model, options?.reasoningReplayMetadata);
2659
1454
  } else if (includeToolCalls && item.type === "function_call") {
2660
- if (params.outputItemContentIndexes.get(item) !== void 0) continue;
2661
- params.outputItemContentIndexes.set(item, appendToolCall(item));
1455
+ if (params.outputs.get(item, terminalIndex)) continue;
1456
+ params.outputs.set(item, appendToolCall(item), terminalIndex, true);
2662
1457
  }
2663
1458
  }
2664
1459
  };
@@ -2708,9 +1503,7 @@ function createResponsesTerminalController(params) {
2708
1503
  async function processResponsesStream(openaiStream, output, stream, model, options) {
2709
1504
  const streamingToolCalls = createResponsesToolCallTracker();
2710
1505
  const outputSlots = createResponsesOutputSlotTracker();
2711
- const reasoningBlocksById = /* @__PURE__ */ new Map();
2712
- const outputItemContentIndexes = createResponsesOutputContentIndex();
2713
- const startedTextBlocksByItemId = /* @__PURE__ */ new Map();
1506
+ const outputs = createResponsesOutputTracker();
2714
1507
  let terminalResponse;
2715
1508
  let lastTextBlock = null;
2716
1509
  const blocks = output.content;
@@ -2725,11 +1518,11 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2725
1518
  type: "thinking",
2726
1519
  item,
2727
1520
  block,
2728
- contentIndex: blocks.length
1521
+ contentIndex: blocks.length,
1522
+ outputIndex: readResponsesOutputIndex(event)
2729
1523
  };
2730
1524
  blocks.push(block);
2731
- reasoningBlocksById.set(item.id, block);
2732
- outputItemContentIndexes.set(item, slot.contentIndex);
1525
+ outputs.set(item, slot.contentIndex, slot.outputIndex);
2733
1526
  outputSlots.register(event, slot);
2734
1527
  stream.push({
2735
1528
  type: "thinking_start",
@@ -2751,17 +1544,13 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2751
1544
  item: messageItem,
2752
1545
  block,
2753
1546
  contentIndex: block ? blocks.length : void 0,
1547
+ outputIndex: readResponsesOutputIndex(event),
2754
1548
  pendingText: collapseCandidate ? "" : null,
2755
1549
  collapseCandidate
2756
1550
  };
2757
1551
  if (block) {
2758
1552
  blocks.push(block);
2759
- outputItemContentIndexes.set(messageItem, slot.contentIndex ?? blocks.length - 1);
2760
- startedTextBlocksByItemId.set(messageItem.id, {
2761
- block,
2762
- index: slot.contentIndex ?? blocks.length - 1,
2763
- phase: messageItem.phase ?? void 0
2764
- });
1553
+ outputs.set(messageItem, slot.contentIndex ?? blocks.length - 1, slot.outputIndex);
2765
1554
  }
2766
1555
  outputSlots.register(event, slot);
2767
1556
  if (slot.contentIndex !== void 0) stream.push({
@@ -2777,9 +1566,6 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2777
1566
  if (item.type === "message") return outputSlots.resolve(event, "text");
2778
1567
  return readResponsesOutputIndex(event) === void 0 ? void 0 : outputSlots.get(event);
2779
1568
  };
2780
- const getOrCreateOutputSlot = (event, item) => {
2781
- return resolveOutputItemSlot(event, item) ?? createOutputSlot(event, item);
2782
- };
2783
1569
  const materializeDeferredTextSlot = (slot) => {
2784
1570
  if (slot.block || slot.pendingText === null) return;
2785
1571
  const text = slot.pendingText;
@@ -2790,12 +1576,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2790
1576
  };
2791
1577
  blocks.push(slot.block);
2792
1578
  slot.contentIndex = blocks.length - 1;
2793
- outputItemContentIndexes.set(slot.item, slot.contentIndex);
2794
- startedTextBlocksByItemId.set(slot.item.id, {
2795
- block: slot.block,
2796
- index: slot.contentIndex,
2797
- phase: slot.item.phase ?? void 0
2798
- });
1579
+ outputs.set(slot.item, slot.contentIndex, slot.outputIndex);
2799
1580
  stream.push({
2800
1581
  type: "text_start",
2801
1582
  contentIndex: slot.contentIndex,
@@ -2818,9 +1599,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2818
1599
  stream,
2819
1600
  model,
2820
1601
  options,
2821
- reasoningBlocksById,
2822
- startedTextBlocksByItemId,
2823
- outputItemContentIndexes,
1602
+ outputs,
2824
1603
  getLastTextBlock: () => lastTextBlock,
2825
1604
  setLastTextBlock: (block) => {
2826
1605
  lastTextBlock = block;
@@ -2860,6 +1639,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2860
1639
  block: toolCallBlock,
2861
1640
  contentIndex,
2862
1641
  argumentStreamReliable: true,
1642
+ previewSchedule: createToolArgumentPreviewSchedule(),
2863
1643
  ...readResponsesToolCallItemIdentity(item)
2864
1644
  };
2865
1645
  streamingToolCalls.register(event, toolCallState);
@@ -2868,7 +1648,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2868
1648
  toolCall: toolCallState
2869
1649
  });
2870
1650
  output.content.push(toolCallBlock);
2871
- outputItemContentIndexes.set(item, contentIndex);
1651
+ outputs.set(item, contentIndex, readResponsesOutputIndex(event));
2872
1652
  stream.push({
2873
1653
  type: "toolcall_start",
2874
1654
  contentIndex,
@@ -2994,7 +1774,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2994
1774
  const toolCall = streamingToolCalls.resolve(event);
2995
1775
  if (toolCall) {
2996
1776
  toolCall.block.partialJson += event.delta;
2997
- toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
1777
+ if (toolCall.previewSchedule(toolCall.block.partialJson.length)) toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
2998
1778
  stream.push({
2999
1779
  type: "toolcall_delta",
3000
1780
  contentIndex: toolCall.contentIndex,
@@ -3027,13 +1807,14 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
3027
1807
  if (item.type !== "message") lastTextBlock = null;
3028
1808
  const existingOutputSlot = resolveOutputItemSlot(event, item);
3029
1809
  materializeDeferredTextSlots(existingOutputSlot);
3030
- const outputSlot = existingOutputSlot ?? getOrCreateOutputSlot(event, item);
1810
+ const outputSlot = existingOutputSlot ?? createOutputSlot(event, item);
3031
1811
  compactionTracker.completed(item, blocks.length);
3032
1812
  if (item.type === "reasoning" && outputSlot?.type === "thinking") {
3033
1813
  const summaryText = item.summary?.map((s) => s.text).join("\n\n") || "";
3034
1814
  const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
3035
1815
  outputSlot.block.thinking = summaryText || contentText || outputSlot.block.thinking;
3036
1816
  outputSlot.block.thinkingSignature = JSON.stringify(item);
1817
+ outputs.set(item, outputSlot.contentIndex, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
3037
1818
  if (item.encrypted_content && options?.reasoningReplayMetadata) outputSlot.block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
3038
1819
  stream.push({
3039
1820
  type: "thinking_end",
@@ -3065,7 +1846,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
3065
1846
  partial: output
3066
1847
  });
3067
1848
  lastTextBlock = outputSlot.collapseCandidate;
3068
- outputItemContentIndexes.set(item, outputSlot.collapseCandidate.index);
1849
+ outputs.set(item, outputSlot.collapseCandidate.index, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
3069
1850
  } else {
3070
1851
  if (!outputSlot.block) {
3071
1852
  outputSlot.block = {
@@ -3090,7 +1871,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
3090
1871
  index: contentIndex,
3091
1872
  phase
3092
1873
  };
3093
- outputItemContentIndexes.set(item, contentIndex);
1874
+ outputs.set(item, contentIndex, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
3094
1875
  stream.push({
3095
1876
  type: "text_end",
3096
1877
  contentIndex,
@@ -3099,7 +1880,6 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
3099
1880
  });
3100
1881
  }
3101
1882
  outputSlots.forget(outputSlot);
3102
- startedTextBlocksByItemId.delete(item.id);
3103
1883
  } else if (item.type === "function_call") {
3104
1884
  const streamingToolCall = streamingToolCalls.resolve(event, readResponsesToolCallItemIdentity(item));
3105
1885
  if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
@@ -3146,7 +1926,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
3146
1926
  toolCall,
3147
1927
  partial: output
3148
1928
  });
3149
- outputItemContentIndexes.set(item, contentIndex);
1929
+ outputs.set(item, contentIndex, readResponsesOutputIndex(event), true);
3150
1930
  }
3151
1931
  } else if (event.type === "response.completed" || event.type === "response.incomplete") {
3152
1932
  if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
@@ -3312,26 +2092,34 @@ async function runResponsesStreamLifecycle(params) {
3312
2092
  return request;
3313
2093
  };
3314
2094
  const requestParams = await buildRequest("checkpoint");
3315
- firstEventAbort = createFirstStreamEventAbortController(options?.signal);
3316
- const { stream: openaiStream, response } = await createResponsesStreamWithEncryptedContentRetry({
2095
+ const firstEvent = createFirstStreamEventAbortController(options?.signal);
2096
+ firstEventAbort = firstEvent;
2097
+ let started = false;
2098
+ const { stream: hookedOpenAIStream } = await createResponsesStreamWithEncryptedContentRetry({
3317
2099
  client,
3318
2100
  request: requestParams,
3319
2101
  requestOptions: {
3320
2102
  ...buildResponsesRequestOptions(options),
3321
- signal: firstEventAbort.signal
2103
+ signal: firstEvent.signal
3322
2104
  },
3323
2105
  model,
3324
2106
  buildFullHistoryRequest: () => buildRequest("full-history"),
3325
- onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint)
3326
- });
3327
- const hookedOpenAIStream = withProviderResponseHook({
3328
- stream: openaiStream,
3329
- signal: firstEventAbort.signal,
3330
- abort: firstEventAbort.abort,
3331
- hook: createOpenAIProviderAcceptanceHook(options, response, model),
3332
- onReady: () => stream.push({
3333
- type: "start",
3334
- partial: output
2107
+ onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint),
2108
+ canRetryStream: () => output.content.length === 0,
2109
+ wrapStream: ({ stream: openaiStream, response }) => withProviderResponseHook({
2110
+ stream: openaiStream,
2111
+ signal: firstEvent.signal,
2112
+ abort: firstEvent.abort,
2113
+ hook: createOpenAIProviderAcceptanceHook(options, response, model),
2114
+ onReady: () => {
2115
+ if (!started) {
2116
+ started = true;
2117
+ stream.push({
2118
+ type: "start",
2119
+ partial: output
2120
+ });
2121
+ }
2122
+ }
3335
2123
  })
3336
2124
  });
3337
2125
  const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
@@ -3372,4 +2160,4 @@ async function runResponsesStreamLifecycle(params) {
3372
2160
  }
3373
2161
  }
3374
2162
  //#endregion
3375
- export { normalizeOpenAIStrictCompatSchema as $, isAzureResponsesTextDeltaEvent as A, buildResponsesInputMessage as B, summarizeResponsesTools as C, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as D, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as E, commitResponsesEncryptedContentAttempt as F, suppressOpenAIResponsesCompaction as G, createOpenAIResponsesAssistantOutput as H, createResponsesStreamWithEncryptedContentRetry as I, isStrictOpenAIJsonSchemaCompatible as J, resolveReplayableResponsesMessageId as K, isInvalidEncryptedContentError as L, isResponsesTextContentPartType as M, isResponsesTextDeltaEventType as N, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as O, resolveResponsesMessageSnapshotCollapse as P, findOpenAIStrictSchemaViolations as Q, resolveAzureOpenAIApiVersion as R, summarizeResponsesPayload as S, readResponsesToolCallItemIdentity as T, buildOpenAIResponsesReasoningReplayMetadata as U, convertResponsesMessages$1 as V, captureOpenAIResponsesCompaction as W, normalizeStrictOpenAIJsonSchema as X, normalizeOpenAIStrictToolParameters as Y, resolveOpenAIProjectedToolsStrictToolFlag as Z, safeDebugValue as _, resolveResponsesReasoningEffort as a, LLAMACPP_GBNF_MAX_REPETITION_THRESHOLD as at, summarizeOpenAITransportError as b, processResponsesStream as c, GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS as ct, resolveResponsesTerminalStopReason as d, resolveModelPayloadDebugMode as dt, extractToolSchemaModelCompat as et, observeResponsesStream as f, resolveModelSseDebugMode as ft, normalizeResponsesFailedEvent as g, logResponsesFailedNoDetails as h, createResponsesAssistantOutput as i, stripUnsupportedSchemaKeywords as it, isAzureResponsesTextDeltaEventType as j, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as k, mapResponsesTerminalUsage as l, cleanSchemaForGemini as lt, buildResponsesFailedNoDetailsObservation as m, applyResponsesServiceTierPricing as n, resolveUnsupportedToolSchemaKeywords as nt, runResponsesStreamLifecycle as o, cleanSchemaForLlamacppGbnf as ot, ResponsesStreamFailure as p, findOpenAIStrictToolProjectionDiagnostics as q, convertResponsesMessages as r, shouldOmitEmptyArrayItems as rt, convertResponsesToolPayload as s, findLlamacppGbnfSchemaViolations as st, applyCommonResponsesParams as t, normalizeToolParameterSchema as tt, readResponsesReasoningTokens as u, emitModelTransportDebug as ut, stringifyRedactedEvent as v, createResponsesToolCallTracker as w, summarizeResponsesFailedNoDetailsObservation as x, stringifyRedactedPayload as y, resolveNextResponsesEncryptedContentAttempt as z };
2163
+ export { isAzureResponsesTextDeltaEvent as A, buildResponsesInputMessage as B, summarizeResponsesTools as C, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as D, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as E, commitResponsesEncryptedContentAttempt as F, suppressOpenAIResponsesCompaction as G, createOpenAIResponsesAssistantOutput as H, createResponsesStreamWithEncryptedContentRetry as I, resolveModelPayloadDebugMode as J, resolveReplayableResponsesMessageId as K, isInvalidEncryptedContentError as L, isResponsesTextContentPartType as M, isResponsesTextDeltaEventType as N, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as O, resolveResponsesMessageSnapshotCollapse as P, resolveAzureOpenAIApiVersion as R, summarizeResponsesPayload as S, readResponsesToolCallItemIdentity as T, buildOpenAIResponsesReasoningReplayMetadata as U, convertResponsesMessages$1 as V, captureOpenAIResponsesCompaction as W, resolveModelSseDebugMode as Y, safeDebugValue as _, resolveResponsesReasoningEffort as a, summarizeOpenAITransportError as b, processResponsesStream as c, resolveResponsesTerminalStopReason as d, observeResponsesStream as f, normalizeResponsesFailedEvent as g, logResponsesFailedNoDetails as h, createResponsesAssistantOutput as i, isAzureResponsesTextDeltaEventType as j, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as k, mapResponsesTerminalUsage as l, buildResponsesFailedNoDetailsObservation as m, applyResponsesServiceTierPricing as n, runResponsesStreamLifecycle as o, ResponsesStreamFailure as p, emitModelTransportDebug as q, convertResponsesMessages as r, convertResponsesToolPayload as s, applyCommonResponsesParams as t, readResponsesReasoningTokens as u, stringifyRedactedEvent as v, createResponsesToolCallTracker as w, summarizeResponsesFailedNoDetailsObservation as x, stringifyRedactedPayload as y, resolveNextResponsesEncryptedContentAttempt as z };