@openclaw/ai 2026.8.1-beta.3 → 2026.8.2

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 (91) hide show
  1. package/dist/{anthropic-B8KwTtlb.mjs → anthropic-DTGZ4VMY.mjs} +25 -23
  2. package/dist/{anthropic-compaction-replay-4Zx7-aCr.mjs → anthropic-compaction-replay-CKCDrZJv.mjs} +34 -35
  3. package/dist/{anthropic-payload-policy-CSx7MoKH.d.mts → anthropic-payload-policy-BTzmNC14.d.mts} +3 -2
  4. package/dist/{api-registry-DFxSnFqG.d.mts → api-registry-BbUHEKER.d.mts} +2 -1
  5. package/dist/{azure-openai-responses-Aa4mVcYG.mjs → azure-openai-responses-BmqaDXM1.mjs} +6 -5
  6. package/dist/{number-coercion-H9qHik3g.mjs → base64-CEFBpSkN.mjs} +73 -1
  7. package/dist/diagnostics.d.mts +2 -3
  8. package/dist/diagnostics.mjs +1 -1
  9. package/dist/{env-api-keys-DrgeBuva.mjs → env-api-keys-bktO00EJ.mjs} +2 -15
  10. package/dist/{event-stream-D91-ohD_.d.mts → event-stream-DcvAPSBe.d.mts} +1 -2
  11. package/dist/event-stream-pXT3FI6X.d.mts +1 -0
  12. package/dist/event-stream.d.mts +2 -1
  13. package/dist/{google-yDRnipeq.mjs → google-CqjVZMwo.mjs} +8 -6
  14. package/dist/{google-shared-M1dl64nz.mjs → google-shared-Bnqni5j3.mjs} +34 -25
  15. package/dist/{google-vertex-DCJHM_a5.mjs → google-vertex-D_WREEJi.mjs} +8 -6
  16. package/dist/{host-DF_yxOsA.mjs → host-BIaiBURL.mjs} +4 -8
  17. package/dist/{host-DJq_FGcz.d.mts → host-DKFUAmCn.d.mts} +3 -3
  18. package/dist/index-CefaUGSS.d.mts +111 -0
  19. package/dist/index.d.mts +9 -10
  20. package/dist/index.mjs +4 -5
  21. package/dist/internal/anthropic.d.mts +51 -49
  22. package/dist/internal/anthropic.mjs +5 -5
  23. package/dist/internal/openai-responses-payload-policy.d.mts +3 -3
  24. package/dist/internal/openai-responses-payload-policy.mjs +2 -3
  25. package/dist/internal/openai.d.mts +65 -63
  26. package/dist/internal/openai.mjs +10 -9
  27. package/dist/internal/retry-after.d.mts +2 -3
  28. package/dist/internal/runtime.d.mts +51 -40
  29. package/dist/internal/runtime.mjs +9 -9
  30. package/dist/internal/shared.d.mts +25 -25
  31. package/dist/internal/shared.mjs +3 -3
  32. package/dist/{json-parse-CDnesDM_.mjs → json-parse-BuAJEbdW.mjs} +18 -2
  33. package/dist/{mistral-D6hRXI7A.mjs → mistral-C24jVd6f.mjs} +34 -32
  34. package/dist/{openai-chatgpt-responses-C339VIfT.mjs → openai-chatgpt-responses-Czum0oXz.mjs} +38 -20
  35. package/dist/openai-completions-BfFwac6f.mjs +404 -0
  36. package/dist/{openai-completions-compat-B0KTleXp.d.mts → openai-completions-compat-SZhi0Lf4.d.mts} +3 -3
  37. package/dist/openai-completions-stream-DGOvau4J.mjs +1625 -0
  38. package/dist/{openai-responses-BXEcr-Tp.mjs → openai-responses-BAryVEJM.mjs} +11 -7
  39. package/dist/openai-responses-compaction-window-DO7yV7az.mjs +686 -0
  40. package/dist/{openai-responses-contracts-CD75pQ0m.d.mts → openai-responses-contracts-BthRXano.d.mts} +14 -5
  41. package/dist/{openai-responses-payload-policy-CNGFT9zr.d.mts → openai-responses-payload-policy-rLRPsSmB.d.mts} +1 -0
  42. package/dist/{openai-responses-prompt-observer-internal-BG-1AsBI.mjs → openai-responses-prompt-observer-internal--R0kZLOZ.mjs} +3 -2
  43. package/dist/{openai-responses-shared-Cvt5MgEm.mjs → openai-responses-shared-CxgdGBvm.mjs} +332 -1484
  44. package/dist/openai-stop-reason-Drnn_6Qj.mjs +28 -0
  45. package/dist/openai-tool-schema-CSMh5e9O.mjs +1697 -0
  46. package/dist/{provider-error-C8mBRJDl.mjs → provider-error-BI8kIViN.mjs} +14 -88
  47. package/dist/{provider-options-Cc5ZQ6Aa.d.mts → provider-options-DJd_9euj.d.mts} +13 -4
  48. package/dist/{provider-transcript-transform--gtf0ZbR.mjs → provider-transcript-transform-WvJmFUAf.mjs} +1 -1
  49. package/dist/provider-types.d.mts +18 -17
  50. package/dist/providers.d.mts +5 -6
  51. package/dist/providers.mjs +9 -9
  52. package/dist/{reasoning-tag-text-partitioner-5ygO2rZc.mjs → reasoning-tag-text-partitioner-BsUX44Tq.mjs} +30 -20
  53. package/dist/rolldown-runtime-BhDjJH2R.mjs +15 -0
  54. package/dist/{sanitize-unicode-BP7HLLZn.mjs → sanitize-unicode-S6binQG-.mjs} +2 -9
  55. package/dist/simple-options-rdOPzr7Z.mjs +155 -0
  56. package/dist/{anthropic-BQXQudmA.mjs → src-C8U7lkoa.mjs} +75 -1
  57. package/dist/{stream-first-event-timeout-MK28puvq.mjs → stream-first-event-timeout-DcNjoFQE.mjs} +1 -1
  58. package/dist/{streaming-byte-guard-BrbkbwUu.mjs → streaming-byte-guard-CC-HMn_u.mjs} +5 -6
  59. package/dist/string-normalization--fwJ4S2q.mjs +16 -0
  60. package/dist/{tool-schema-json-projection-FEr-jOoZ.mjs → tool-schema-json-projection-BtZiml7r.mjs} +22 -32
  61. package/dist/transport-stream-shared-BbG7PThh.d.mts +138 -0
  62. package/dist/{simple-options-oqsXB6U3.mjs → transport-stream-shared-D8nQWCUo.mjs} +10 -118
  63. package/dist/{transport-utils-Bv0FHkd0.mjs → transport-utils-CtuS1Upe.mjs} +10 -10
  64. package/dist/transports.d.mts +130 -189
  65. package/dist/transports.mjs +227 -1249
  66. package/dist/{types-DTAP49HF.d.mts → types-Beemor2E.d.mts} +58 -24
  67. package/dist/types-COdhCX0U.d.mts +1 -0
  68. package/dist/types.d.mts +6 -5
  69. package/dist/types.mjs +3 -4
  70. package/dist/utf16-slice-qz3nsy87.mjs +84 -0
  71. package/dist/{validation-DYNNrU9u.d.mts → validation-CC6s7Smp.d.mts} +1 -2
  72. package/dist/{validation-B61OhAio.mjs → validation-CJZtym2g.mjs} +7 -5
  73. package/dist/validation.d.mts +1 -1
  74. package/dist/validation.mjs +1 -1
  75. package/package.json +6 -6
  76. package/dist/anthropic-BECQCNdF.d.mts +0 -98
  77. package/dist/event-stream-BVVgDSdq.d.mts +0 -1
  78. package/dist/headers-B_e4-1J0.mjs +0 -9
  79. package/dist/index-BVVgDSdq.d.mts +0 -1
  80. package/dist/openai-completions-D88orSJ9.mjs +0 -632
  81. package/dist/openai-responses-contracts-DvILoqBk.mjs +0 -247
  82. package/dist/openai-responses-payload-policy-BDo8CQsx.mjs +0 -208
  83. package/dist/openai-stop-reason-9OONKyAm.mjs +0 -579
  84. package/dist/openai-tool-projection-CHGLt03m.mjs +0 -426
  85. package/dist/provider-options-AvldWZt8.mjs +0 -21
  86. package/dist/record-coerce-DdXsgUd_.mjs +0 -23
  87. package/dist/src-D2H6yKkH.mjs +0 -2
  88. package/dist/stream-first-event-timeout-DvDeSucC.d.mts +0 -29
  89. package/dist/string-coerce-fsri9iCu.mjs +0 -34
  90. package/dist/types-BVVgDSdq.d.mts +0 -1
  91. 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";
7
- 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";
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-S6binQG-.mjs";
3
+ import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, n as getAiTransportHost } from "./host-BIaiBURL.mjs";
4
+ import { n as projectProviderError } from "./provider-error-BI8kIViN.mjs";
5
+ import { r as asFiniteNumber } from "./base64-CEFBpSkN.mjs";
6
+ import { d as stripSystemPromptCacheBoundary, m as sortPromptCacheToolsByName } from "./simple-options-rdOPzr7Z.mjs";
7
+ import { c as transformTransportMessages } from "./tool-schema-json-projection-BtZiml7r.mjs";
8
+ import { d as redactSensitiveText, u as redactIdentifier } from "./transport-utils-CtuS1Upe.mjs";
9
+ import { _ as transportAbortError, g as sanitizeTransportPayloadText, h as sanitizeNonEmptyTransportPayloadText, m as parseTerminalToolCallArguments, y as withProviderResponseHook } from "./transport-stream-shared-D8nQWCUo.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";
16
- 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";
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-CSMh5e9O.mjs";
14
+ import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-DcNjoFQE.mjs";
15
+ import { t as transformProviderMessages } from "./provider-transcript-transform-WvJmFUAf.mjs";
16
+ import { A as supportsOpenAITemperature, D as resolveOpenAIReasoningEffortForModel, b as RESPONSE_FAILED_NO_DETAILS_MESSAGE, g as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, h as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, k as supportsOpenAIReasoningEffort, m as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, n as isOpenAIResponsesCompactionOutput, p as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, r as readOpenAIResponsesCompactionWindow } from "./openai-responses-compaction-window-DO7yV7az.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) {
@@ -1362,7 +97,7 @@ function readOpenAIResponsesCompactionReplayState(value) {
1362
97
  function openAIResponsesReplayContextMatches(state, context) {
1363
98
  return state.provider === context.provider && state.api === context.api && state.model === context.model && state.baseUrlHash === context.baseUrlHash && state.sessionHash === context.sessionHash && state.authProfileHash === context.authProfileHash;
1364
99
  }
1365
- function captureOpenAIResponsesCompaction(output, item, boundary, model, captureMetadata) {
100
+ function captureOpenAIResponsesCompaction(output, item, boundary, model, captureMetadata, compactedOutput) {
1366
101
  const metadata = captureMetadata ?? buildOpenAIResponsesReasoningReplayMetadata(model);
1367
102
  if (!item.encrypted_content) return;
1368
103
  if (!metadata?.baseUrlHash) {
@@ -1371,19 +106,28 @@ function captureOpenAIResponsesCompaction(output, item, boundary, model, capture
1371
106
  }
1372
107
  const currentReplay = readOpenAIResponsesCompactionReplayState(output.providerReplay);
1373
108
  if (typeof boundary === "number" && currentReplay?.type === "openai-responses-compaction" && (currentReplay.replayIndex ?? -1) > boundary) return;
1374
- output.providerReplay = {
109
+ if (compactedOutput && !isOpenAIResponsesCompactionOutput(compactedOutput, model)) throw new Error("Responses compact endpoint checkpoint is invalid");
110
+ const replay = {
1375
111
  v: 1,
1376
- type: boundary === "retained-users" ? OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE : OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE,
112
+ ...boundary === "retained-users" ? { type: OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE } : {
113
+ type: OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE,
114
+ replayIndex: boundary
115
+ },
1377
116
  ...item.id ? { id: item.id } : {},
1378
117
  data: item.encrypted_content,
1379
- ...typeof boundary === "number" ? { replayIndex: boundary } : {},
1380
118
  provider: metadata.provider,
1381
119
  api: metadata.api,
1382
120
  model: metadata.model,
1383
121
  baseUrlHash: metadata.baseUrlHash,
1384
122
  ...metadata.sessionHash ? { sessionHash: metadata.sessionHash } : {},
1385
- ...metadata.authProfileHash ? { authProfileHash: metadata.authProfileHash } : {}
123
+ ...metadata.authProfileHash ? { authProfileHash: metadata.authProfileHash } : {},
124
+ ...compactedOutput ? { compactedWindow: {
125
+ state: "ready",
126
+ output: JSON.stringify(compactedOutput)
127
+ } } : {}
1386
128
  };
129
+ if (compactedOutput && !readOpenAIResponsesCompactionWindow(replay, model)) throw new Error("Responses compact endpoint checkpoint is invalid or exceeds 16 MiB");
130
+ output.providerReplay = replay;
1387
131
  }
1388
132
  function suppressOpenAIResponsesCompaction(output, model, options, rejectedCheckpoint) {
1389
133
  const context = buildOpenAIResponsesReplayContext(model, options);
@@ -1432,6 +176,21 @@ function resolveNewestOpenAIResponsesCompactionReplay(messages, model, options)
1432
176
  continue;
1433
177
  }
1434
178
  if (!openAIResponsesReplayContextMatches(replay, context)) return;
179
+ if (replay.compactedWindow !== void 0 || replay.type === "openai-responses-retained-compaction") {
180
+ const output = readOpenAIResponsesCompactionWindow(replay, model);
181
+ const item = output?.at(-1);
182
+ if (!output || item?.type !== "compaction") return {
183
+ owner: message,
184
+ mode: "refresh-required"
185
+ };
186
+ return {
187
+ owner: message,
188
+ mode: "complete-window",
189
+ output,
190
+ item,
191
+ replayIndex: replay.type === "openai-responses-retained-compaction" ? message.content.length : replay.replayIndex ?? 0
192
+ };
193
+ }
1435
194
  return {
1436
195
  owner: message,
1437
196
  item: {
@@ -1439,13 +198,17 @@ function resolveNewestOpenAIResponsesCompactionReplay(messages, model, options)
1439
198
  ...isSafeResponsesReplayItemId(replay.id) ? { id: replay.id } : {},
1440
199
  encrypted_content: replay.data
1441
200
  },
1442
- ...replay.type === "openai-responses-retained-compaction" ? { mode: "retained-users" } : {
1443
- mode: "compacted-prefix",
1444
- replayIndex: replay.replayIndex ?? 0
1445
- }
201
+ mode: "compacted-prefix",
202
+ replayIndex: replay.replayIndex ?? 0
1446
203
  };
1447
204
  }
1448
205
  }
206
+ var CompactionReplayRefreshRequiredError = class extends Error {
207
+ constructor() {
208
+ super("Provider compaction checkpoint needs rebuilding. Run /compact to rebuild from saved conversation history.");
209
+ this.name = "CompactionReplayRefreshRequiredError";
210
+ }
211
+ };
1449
212
  function buildOpenAIResponsesCompactionReplayPlan(messages, model, options) {
1450
213
  if (options?.mode === "full-history") return {
1451
214
  messages,
@@ -1456,22 +219,14 @@ function buildOpenAIResponsesCompactionReplayPlan(messages, model, options) {
1456
219
  messages,
1457
220
  preserveUnframedToolResults: false
1458
221
  };
222
+ if (compaction.mode === "refresh-required") throw new CompactionReplayRefreshRequiredError();
1459
223
  const ownerIndex = messages.indexOf(compaction.owner);
1460
- const collectRetainedUserMessages = (prefix) => {
1461
- const previous = resolveNewestOpenAIResponsesCompactionReplay(prefix, model, options);
1462
- if (!previous) return prefix.filter((message) => message.role === "user");
1463
- const previousOwnerIndex = prefix.indexOf(previous.owner);
1464
- const laterUsers = prefix.slice(previousOwnerIndex + 1).filter((message) => message.role === "user");
1465
- return previous.mode === "retained-users" ? [...collectRetainedUserMessages(prefix.slice(0, previousOwnerIndex)), ...laterUsers] : laterUsers;
1466
- };
1467
- const retainedMessages = compaction.mode === "retained-users" ? collectRetainedUserMessages(messages.slice(0, ownerIndex)) : void 0;
1468
224
  return {
1469
225
  messages: [{
1470
226
  ...compaction.owner,
1471
- content: compaction.mode === "retained-users" ? [] : compaction.owner.content.slice(compaction.replayIndex)
227
+ content: compaction.owner.content.slice(compaction.replayIndex)
1472
228
  }, ...messages.slice(ownerIndex + 1)],
1473
- ...retainedMessages?.length ? { retainedMessages } : {},
1474
- compaction: compaction.item,
229
+ ...compaction.mode === "complete-window" ? { compactedWindow: compaction.output } : { compaction: compaction.item },
1475
230
  preserveUnframedToolResults: true
1476
231
  };
1477
232
  }
@@ -1663,39 +418,47 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
1663
418
  preserveUnframedToolResults: replayPlan.preserveUnframedToolResults
1664
419
  });
1665
420
  const transformedMessages = transformMessages(replayPlan.messages);
1666
- const transformedRetainedMessages = replayPlan.retainedMessages ? transformMessages(replayPlan.retainedMessages) : [];
1667
- if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) messages.push(buildResponsesInputMessage(model.reasoning && (providerStyle ? model.compat?.supportsDeveloperRole !== false : options?.supportsDeveloperRole !== false) ? "developer" : "system", [{
421
+ if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) messages.push(buildResponsesInputMessage(model.reasoning && model.compat?.supportsDeveloperRole !== false ? "developer" : "system", [{
1668
422
  type: "input_text",
1669
423
  text: sanitizeTransportPayloadText(stripSystemPromptCacheBoundary(context.systemPrompt))
1670
424
  }]));
1671
- const replayMessages = replayPlan.compaction ? [
1672
- ...transformedRetainedMessages,
1673
- replayPlan.compaction,
1674
- ...transformedMessages
1675
- ] : transformedMessages;
425
+ if (replayPlan.compactedWindow) messages.push(...replayPlan.compactedWindow);
426
+ let replayMessages = replayPlan.compaction ? [replayPlan.compaction, ...transformedMessages] : transformedMessages;
427
+ const isCarrier = (message) => "role" in message && message.role === "user" && message.runtimeContextCarrier === true;
428
+ const carriers = replayMessages.filter(isCarrier);
429
+ if (carriers.length > 0) {
430
+ const stableMessages = replayMessages.filter((message) => !isCarrier(message));
431
+ const insertionIndex = stableMessages.findLastIndex((message) => "role" in message ? message.role === "user" : message.type === "compaction") + 1;
432
+ if (insertionIndex > 0 || replayPlan.compactedWindow) replayMessages = [
433
+ ...stableMessages.slice(0, insertionIndex),
434
+ ...carriers,
435
+ ...stableMessages.slice(insertionIndex)
436
+ ];
437
+ }
1676
438
  let msgIndex = 0;
1677
439
  for (const msg of replayMessages) {
1678
440
  if (!("role" in msg)) {
1679
441
  messages.push(msg);
1680
442
  continue;
1681
443
  }
1682
- if (msg.role === "user") if (typeof msg.content === "string") messages.push(buildResponsesInputMessage("user", [{
1683
- type: "input_text",
1684
- text: sanitizeTransportPayloadText(msg.content)
1685
- }]));
1686
- else {
1687
- const content = msg.content.map((item) => item.type === "text" ? {
444
+ if (msg.role === "user") {
445
+ if (typeof msg.content === "string") messages.push(buildResponsesInputMessage("user", [{
1688
446
  type: "input_text",
1689
- text: sanitizeTransportPayloadText(item.text)
1690
- } : {
1691
- type: "input_image",
1692
- detail: "auto",
1693
- image_url: `data:${item.mimeType};base64,${item.data}`
1694
- }).filter((item) => providerStyle || model.input.includes("image") || item.type !== "input_image");
1695
- if (content.length > 0) messages.push(buildResponsesInputMessage("user", content));
1696
- else if (providerStyle) continue;
1697
- }
1698
- else if (msg.role === "assistant") {
447
+ text: sanitizeTransportPayloadText(msg.content)
448
+ }]));
449
+ else {
450
+ const content = msg.content.map((item) => item.type === "text" ? {
451
+ type: "input_text",
452
+ text: sanitizeTransportPayloadText(item.text)
453
+ } : {
454
+ type: "input_image",
455
+ detail: "auto",
456
+ image_url: `data:${item.mimeType};base64,${item.data}`
457
+ }).filter((item) => providerStyle || model.input.includes("image") || item.type !== "input_image");
458
+ if (content.length > 0) messages.push(buildResponsesInputMessage("user", content));
459
+ else if (providerStyle) continue;
460
+ }
461
+ } else if (msg.role === "assistant") {
1699
462
  const output = [];
1700
463
  let textFallbackOrdinal = 0;
1701
464
  let previousReplayItemWasReasoning = false;
@@ -1799,8 +562,8 @@ function isInvalidEncryptedContentError(error) {
1799
562
  if (!error || typeof error !== "object") return false;
1800
563
  const record = error;
1801
564
  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");
565
+ const message = typeof record.message === "string" ? record.message.toLowerCase() : "";
566
+ 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
567
  }
1805
568
  function isOrphanedFunctionCallOutputError(error) {
1806
569
  if (!error || typeof error !== "object") return false;
@@ -1880,7 +643,45 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
1880
643
  payloadVariant: attempt.kind
1881
644
  });
1882
645
  try {
1883
- return await sendAttempt(attempt);
646
+ const result = await sendAttempt(attempt);
647
+ return {
648
+ ...result,
649
+ stream: { async *[Symbol.asyncIterator]() {
650
+ let rejectedEvent;
651
+ try {
652
+ for await (const event of params.wrapStream?.(result) ?? result.stream) {
653
+ if (isRecord(event)) {
654
+ const failure = event.type === "response.failed" && isRecord(event.response) ? event.response.error : event.type === "error" ? event.error ?? event : void 0;
655
+ if (isRecord(failure) && params.canRetryStream?.() === true && isInvalidEncryptedContentError(failure)) {
656
+ rejectedEvent = event;
657
+ const message = typeof failure.message === "string" ? failure.message : "";
658
+ throw Object.assign(new Error(message), {
659
+ code: failure.code,
660
+ status: failure.status
661
+ });
662
+ }
663
+ }
664
+ yield event;
665
+ }
666
+ } catch (error) {
667
+ const nextAttempt = params.canRetryStream?.() === true && !params.requestOptions?.signal?.aborted ? await resolveNextResponsesEncryptedContentAttempt(result.attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest }) : void 0;
668
+ if (!nextAttempt) {
669
+ if (rejectedEvent !== void 0) {
670
+ yield rejectedEvent;
671
+ return;
672
+ }
673
+ throw error;
674
+ }
675
+ log.warn(`[responses] retrying streamed encrypted content provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
676
+ yield* (await createResponsesStreamWithEncryptedContentRetry({
677
+ ...params,
678
+ request: nextAttempt.request,
679
+ initialAttemptKind: nextAttempt.kind,
680
+ initialRejectedCompaction: nextAttempt.rejectedCompaction
681
+ })).stream;
682
+ }
683
+ } }
684
+ };
1884
685
  } catch (error) {
1885
686
  let nextAttempt = await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
1886
687
  if (!nextAttempt && attempt.request.previous_response_id && error && typeof error === "object" && typeof error.status === "number" && error.code === "previous_response_not_found") {
@@ -1952,14 +753,14 @@ function createResponsesToolCallTracker() {
1952
753
  state.callId ??= identity.callId;
1953
754
  return state;
1954
755
  };
1955
- const resolveCompatible = (candidates, identity) => {
756
+ const resolveCompatible = (candidates, identity, allowUnmatchedIdentity) => {
1956
757
  const uniqueCandidates = [...new Set(candidates)];
1957
- if (!identity.itemId && !identity.callId) return uniqueCandidates.length === 1 ? uniqueCandidates.at(0) : void 0;
758
+ if (!identity.itemId && !identity.callId) return allowUnmatchedIdentity && uniqueCandidates.length === 1 ? uniqueCandidates.at(0) : void 0;
1958
759
  const compatible = uniqueCandidates.filter((state) => !identitiesConflict(state, identity));
1959
760
  const matches = compatible.filter((state) => sharesIdentity(state, identity));
1960
761
  const matched = matches.length === 1 ? matches.at(0) : void 0;
1961
762
  if (matched) return adoptIdentity(matched, identity);
1962
- const soleCompatible = uniqueCandidates.length === 1 && compatible.length === 1 && matches.length === 0 ? compatible.at(0) : void 0;
763
+ const soleCompatible = allowUnmatchedIdentity && uniqueCandidates.length === 1 && compatible.length === 1 && matches.length === 0 ? compatible.at(0) : void 0;
1963
764
  return soleCompatible ? adoptIdentity(soleCompatible, identity) : void 0;
1964
765
  };
1965
766
  return {
@@ -1970,9 +771,10 @@ function createResponsesToolCallTracker() {
1970
771
  return;
1971
772
  }
1972
773
  if (indexedCalls.has(outputIndex)) throw new Error(`Responses stream reused active tool-call output index ${outputIndex}`);
774
+ state.outputIndex = outputIndex;
1973
775
  indexedCalls.set(outputIndex, state);
1974
776
  },
1975
- resolve(event, identity = readEventIdentity(event)) {
777
+ resolve(event, identity = readEventIdentity(event), allowUnmatchedIdentity = true) {
1976
778
  const outputIndex = readOutputIndex(event);
1977
779
  if (outputIndex !== void 0) {
1978
780
  const indexed = indexedCalls.get(outputIndex);
@@ -1980,14 +782,15 @@ function createResponsesToolCallTracker() {
1980
782
  if (indexed.callId && identity.callId && indexed.callId !== identity.callId) return;
1981
783
  return adoptIdentity(indexed, identity);
1982
784
  }
1983
- const unindexed = resolveCompatible(unindexedCalls, identity);
785
+ const unindexed = resolveCompatible(unindexedCalls, identity, allowUnmatchedIdentity);
1984
786
  if (unindexed) {
1985
787
  unindexedCalls.delete(unindexed);
788
+ unindexed.outputIndex = outputIndex;
1986
789
  indexedCalls.set(outputIndex, unindexed);
1987
790
  }
1988
791
  return unindexed;
1989
792
  }
1990
- return resolveCompatible([...indexedCalls.values(), ...unindexedCalls], identity);
793
+ return resolveCompatible([...indexedCalls.values(), ...unindexedCalls], identity, allowUnmatchedIdentity);
1991
794
  },
1992
795
  forget(toolCall) {
1993
796
  for (const [outputIndex, tracked] of indexedCalls) if (tracked === toolCall) indexedCalls.delete(outputIndex);
@@ -1998,6 +801,10 @@ function createResponsesToolCallTracker() {
1998
801
  },
1999
802
  hasActive() {
2000
803
  return indexedCalls.size > 0 || unindexedCalls.size > 0;
804
+ },
805
+ hasExactlyActive(expected) {
806
+ const active = /* @__PURE__ */ new Set([...indexedCalls.values(), ...unindexedCalls]);
807
+ return active.size === expected.length && expected.every((state) => active.has(state));
2001
808
  }
2002
809
  };
2003
810
  }
@@ -2123,9 +930,10 @@ const RESPONSE_FAILED_FAILURE_FIELD_KEYS = [
2123
930
  function readResponseFailedString(record, key) {
2124
931
  return stringifyUnknown(record?.[key]);
2125
932
  }
2126
- function buildResponsesFailedEventSummary(message, responseId, observation) {
933
+ function buildResponsesFailedEventSummary(message, responseId, code, observation) {
2127
934
  const summary = { message };
2128
935
  if (responseId) summary.responseId = responseId;
936
+ if (code) summary.code = code;
2129
937
  if (observation) summary.observation = observation;
2130
938
  return summary;
2131
939
  }
@@ -2244,11 +1052,11 @@ function normalizeResponsesFailedEvent(event, model) {
2244
1052
  if (error) {
2245
1053
  const code = readResponseFailedString(error, "code").trim();
2246
1054
  const message = readResponseFailedString(error, "message").trim();
2247
- if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId);
1055
+ if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId, code || void 0);
2248
1056
  }
2249
1057
  const incompleteReason = readResponseFailedString(isRecord(response?.incomplete_details) ? response.incomplete_details : void 0, "reason");
2250
1058
  if (incompleteReason) return buildResponsesFailedEventSummary(`incomplete: ${incompleteReason}`, responseId);
2251
- return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, buildResponsesFailedNoDetailsObservation(event, model, response));
1059
+ return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, void 0, buildResponsesFailedNoDetailsObservation(event, model, response));
2252
1060
  }
2253
1061
  var ResponsesStreamFailure = class extends Error {
2254
1062
  constructor(failure, response) {
@@ -2256,6 +1064,7 @@ var ResponsesStreamFailure = class extends Error {
2256
1064
  this.name = "ResponsesStreamFailure";
2257
1065
  this.responseId = failure.responseId;
2258
1066
  this.response = response;
1067
+ this.code = failure.code;
2259
1068
  this.observation = failure.observation;
2260
1069
  }
2261
1070
  };
@@ -2346,20 +1155,39 @@ async function* observeResponsesStream(stream, model, requestStartedAt) {
2346
1155
  }
2347
1156
  //#endregion
2348
1157
  //#region packages/ai/src/transports/openai-responses-stream-slots-internal.ts
2349
- function createResponsesOutputContentIndex() {
2350
- const indexes = /* @__PURE__ */ new Map();
1158
+ function createResponsesOutputTracker() {
1159
+ const outputs = /* @__PURE__ */ new Map();
2351
1160
  const identity = (item) => {
2352
1161
  if ((item.type === "reasoning" || item.type === "message") && item.id) return `${item.type}:${item.id}`;
2353
- return item.type === "function_call" ? `function_call:${item.call_id ?? item.id ?? ""}` : void 0;
1162
+ const callId = item.call_id ?? item.id;
1163
+ return item.type === "function_call" && callId ? `function_call:${callId}` : void 0;
1164
+ };
1165
+ const get = (item, outputIndex) => {
1166
+ const key = identity(item);
1167
+ const output = (outputIndex === void 0 ? void 0 : outputs.get(outputIndex)) ?? (key === void 0 ? void 0 : outputs.get(key));
1168
+ if (!output || outputIndex !== void 0 && output.outputIndex !== void 0 && output.outputIndex !== outputIndex) return;
1169
+ if (output.type !== item.type || output.callId && item.call_id && output.callId !== item.call_id) throw new Error("Responses stream changed output item identity");
1170
+ return output;
2354
1171
  };
2355
1172
  return {
2356
- get(item) {
2357
- const key = identity(item);
2358
- return key === void 0 ? void 0 : indexes.get(key);
2359
- },
2360
- set(item, contentIndex) {
1173
+ get,
1174
+ set(item, contentIndex, outputIndex, completed = false) {
1175
+ const output = get(item, outputIndex) ?? {
1176
+ type: item.type,
1177
+ contentIndex,
1178
+ completed
1179
+ };
1180
+ Object.assign(output, {
1181
+ contentIndex,
1182
+ completed
1183
+ });
1184
+ if (item.call_id) output.callId = item.call_id;
1185
+ if (outputIndex !== void 0) {
1186
+ output.outputIndex = outputIndex;
1187
+ outputs.set(outputIndex, output);
1188
+ }
2361
1189
  const key = identity(item);
2362
- if (key !== void 0) indexes.set(key, contentIndex);
1190
+ if (key !== void 0) outputs.set(key, output);
2363
1191
  }
2364
1192
  };
2365
1193
  }
@@ -2419,8 +1247,11 @@ function createResponsesOutputSlotTracker() {
2419
1247
  * package and managed transports from drifting on token buckets, service-tier pricing, or future
2420
1248
  * terminal-event semantics.
2421
1249
  */
1250
+ function readReportedCount(value) {
1251
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
1252
+ }
2422
1253
  function readCount(value) {
2423
- return typeof value === "number" && Number.isFinite(value) ? value : 0;
1254
+ return readReportedCount(value) ?? 0;
2424
1255
  }
2425
1256
  /**
2426
1257
  * Split a terminal usage payload into the priced buckets.
@@ -2438,12 +1269,21 @@ function mapResponsesTerminalUsage(usage) {
2438
1269
  const input = Math.max(0, readCount(usage.input_tokens) - cacheRead - cacheWrite);
2439
1270
  const output = readCount(usage.output_tokens);
2440
1271
  const bucketTotal = input + output + cacheRead + cacheWrite;
1272
+ const totalTokens = Math.max(bucketTotal, readCount(usage.total_tokens));
1273
+ const reportedInput = readReportedCount(usage.input_tokens);
1274
+ const reportedOutput = readReportedCount(usage.output_tokens);
1275
+ const reportedTotal = readReportedCount(usage.total_tokens);
2441
1276
  return {
2442
1277
  input,
2443
1278
  output,
2444
1279
  cacheRead,
2445
1280
  cacheWrite,
2446
- totalTokens: Math.max(bucketTotal, readCount(usage.total_tokens))
1281
+ contextUsage: reportedInput !== void 0 && (reportedOutput !== void 0 || reportedTotal !== void 0 && reportedTotal >= reportedInput) && cacheRead + cacheWrite <= reportedInput ? {
1282
+ state: "available",
1283
+ promptTokens: reportedInput,
1284
+ totalTokens: Math.max(totalTokens, reportedInput + (reportedOutput ?? 0))
1285
+ } : { state: "unavailable" },
1286
+ totalTokens
2447
1287
  };
2448
1288
  }
2449
1289
  /** Reasoning tokens are reported by the agent path only; the package path does not track them. */
@@ -2509,51 +1349,52 @@ function createResponsesTerminalController(params) {
2509
1349
  const { output, stream, model, options } = params;
2510
1350
  const blocks = output.content;
2511
1351
  const backfillReasoning = (items) => {
2512
- for (const item of items) {
1352
+ for (const [outputIndex, item] of items.entries()) {
2513
1353
  if (item.type !== "reasoning" || !item.encrypted_content) continue;
2514
- const block = params.reasoningBlocksById.get(item.id);
2515
- if (!block?.thinkingSignature) continue;
1354
+ const tracked = params.outputs.get(item, outputIndex);
1355
+ const block = tracked && blocks[tracked.contentIndex];
1356
+ if (block?.type !== "thinking" || !block.thinkingSignature) continue;
2516
1357
  const stored = JSON.parse(block.thinkingSignature);
2517
1358
  if (!stored.encrypted_content) block.thinkingSignature = JSON.stringify({
2518
1359
  ...stored,
2519
1360
  encrypted_content: item.encrypted_content
2520
1361
  });
2521
- if (options?.reasoningReplayMetadata) block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
1362
+ if (options?.reasoningReplayMetadata) Object.assign(block, { [OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY]: options.reasoningReplayMetadata });
2522
1363
  }
2523
1364
  };
2524
- const appendText = (item) => {
1365
+ const appendText = (item, contentIndex) => {
2525
1366
  const text = (Array.isArray(item.content) ? item.content : []).map((part) => {
2526
1367
  const content = part;
2527
1368
  return content.type === "output_text" || content.type === "text" ? content.text ?? "" : content.refusal ?? "";
2528
1369
  }).join("");
2529
- const started = params.startedTextBlocksByItemId.get(item.id);
1370
+ const block = contentIndex === void 0 ? void 0 : blocks[contentIndex];
1371
+ const started = block?.type === "text" ? block : void 0;
2530
1372
  if (!text && !started) return;
2531
1373
  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);
1374
+ if (started && contentIndex !== void 0) {
1375
+ const previousText = started.text;
1376
+ started.text = text;
1377
+ started.textSignature = encodeTextSignatureV1(item.id, phase);
2536
1378
  params.setLastTextBlock({
2537
- block: started.block,
2538
- index: started.index,
1379
+ block: started,
1380
+ index: contentIndex,
2539
1381
  phase
2540
1382
  });
2541
- params.startedTextBlocksByItemId.delete(item.id);
2542
1383
  if (text.startsWith(previousText)) {
2543
1384
  const delta = text.slice(previousText.length);
2544
1385
  if (delta) stream.push({
2545
1386
  type: "text_delta",
2546
- contentIndex: started.index,
1387
+ contentIndex,
2547
1388
  delta
2548
1389
  });
2549
1390
  }
2550
1391
  stream.push({
2551
1392
  type: "text_end",
2552
- contentIndex: started.index,
1393
+ contentIndex,
2553
1394
  content: text,
2554
1395
  partial: output
2555
1396
  });
2556
- return started.index;
1397
+ return contentIndex;
2557
1398
  }
2558
1399
  const previous = params.getLastTextBlock();
2559
1400
  const collapse = resolveResponsesMessageSnapshotCollapse({
@@ -2575,15 +1416,15 @@ function createResponsesTerminalController(params) {
2575
1416
  });
2576
1417
  return previous.index;
2577
1418
  }
2578
- const block = {
1419
+ const newBlock = {
2579
1420
  type: "text",
2580
1421
  text,
2581
1422
  textSignature: encodeTextSignatureV1(item.id, phase)
2582
1423
  };
2583
- blocks.push(block);
1424
+ blocks.push(newBlock);
2584
1425
  const index = blocks.length - 1;
2585
1426
  params.setLastTextBlock({
2586
- block,
1427
+ block: newBlock,
2587
1428
  index,
2588
1429
  phase
2589
1430
  });
@@ -2600,65 +1441,71 @@ function createResponsesTerminalController(params) {
2600
1441
  });
2601
1442
  return index;
2602
1443
  };
2603
- const appendToolCall = (item) => {
2604
- const validated = resolveCompletedResponsesToolCall(item);
2605
- const toolCall = {
1444
+ const emitToolCallCompletion = (item, outputIndex, started, validated) => {
1445
+ const completed = {
1446
+ id: resolveResponsesToolCallId(item, started?.block.id),
1447
+ ...validated
1448
+ };
1449
+ const toolCall = started ? Object.assign(started.block, completed) : {
2606
1450
  type: "toolCall",
2607
- id: resolveResponsesToolCallId(item),
2608
- name: validated.name,
2609
- arguments: validated.arguments
1451
+ ...completed
2610
1452
  };
2611
- blocks.push(toolCall);
2612
- const contentIndex = blocks.length - 1;
2613
- stream.push({
2614
- type: "toolcall_start",
2615
- contentIndex,
2616
- partial: output
2617
- });
1453
+ delete toolCall.partialJson;
1454
+ const contentIndex = started?.contentIndex ?? blocks.length;
1455
+ if (!started) {
1456
+ blocks.push(toolCall);
1457
+ stream.push({
1458
+ type: "toolcall_start",
1459
+ contentIndex,
1460
+ partial: output
1461
+ });
1462
+ }
1463
+ params.outputs.set(item, contentIndex, outputIndex, true);
2618
1464
  stream.push({
2619
1465
  type: "toolcall_end",
2620
1466
  contentIndex,
2621
1467
  toolCall,
2622
1468
  partial: output
2623
1469
  });
2624
- return contentIndex;
2625
1470
  };
2626
- const recoverTerminalOutput = (items, includeToolCalls) => {
1471
+ const recoverTerminalOutput = (items, completeToolCall) => {
2627
1472
  let hasCompletedLaterOutput = false;
2628
- for (const item of items.toReversed()) {
1473
+ for (const [outputIndex, item] of [...items.entries()].toReversed()) {
1474
+ const tracked = params.outputs.get(item, outputIndex);
2629
1475
  if (item.type === "reasoning") {
2630
- hasCompletedLaterOutput ||= params.outputItemContentIndexes.get(item) !== void 0;
1476
+ hasCompletedLaterOutput ||= tracked !== void 0;
2631
1477
  continue;
2632
1478
  }
2633
1479
  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)) {
1480
+ if (tracked) {
2635
1481
  hasCompletedLaterOutput = true;
2636
1482
  continue;
2637
1483
  }
2638
- if (item.type === "function_call" && !includeToolCalls) continue;
1484
+ if (item.type === "function_call" && !completeToolCall) continue;
2639
1485
  if (hasCompletedLaterOutput) throw new Error("Responses stream omitted an output item before completed output");
2640
- if (item.type === "function_call") resolveCompletedResponsesToolCall(item);
2641
1486
  }
2642
1487
  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);
1488
+ const tracked = params.outputs.get(item, terminalIndex);
1489
+ if (tracked?.completed) continue;
1490
+ const appendedIndex = appendText(item, tracked?.contentIndex);
1491
+ if (appendedIndex !== void 0) params.outputs.set(item, appendedIndex, terminalIndex, true);
2646
1492
  } else {
2647
1493
  params.setLastTextBlock(null);
2648
1494
  const alreadyCapturedCompaction = item.type === "compaction" && output.providerReplay?.type === "openai-responses-compaction" && output.providerReplay.id === item.id && output.providerReplay.data === item.encrypted_content;
2649
1495
  if (item.type === "compaction" && !alreadyCapturedCompaction) {
2650
1496
  let replayIndex = blocks.length;
2651
- for (const laterItem of items.slice(terminalIndex + 1)) {
2652
- const laterContentIndex = params.outputItemContentIndexes.get(laterItem);
1497
+ for (const [laterIndex, laterItem] of items.entries()) {
1498
+ if (laterIndex <= terminalIndex) continue;
1499
+ const laterContentIndex = params.outputs.get(laterItem, laterIndex)?.contentIndex;
2653
1500
  if (laterContentIndex !== void 0) {
2654
1501
  replayIndex = laterContentIndex;
2655
1502
  break;
2656
1503
  }
2657
1504
  }
2658
1505
  captureOpenAIResponsesCompaction(output, item, replayIndex, model, options?.reasoningReplayMetadata);
2659
- } else if (includeToolCalls && item.type === "function_call") {
2660
- if (params.outputItemContentIndexes.get(item) !== void 0) continue;
2661
- params.outputItemContentIndexes.set(item, appendToolCall(item));
1506
+ } else if (completeToolCall && item.type === "function_call") {
1507
+ if (params.outputs.get(item, terminalIndex)?.completed) continue;
1508
+ completeToolCall(terminalIndex);
2662
1509
  }
2663
1510
  }
2664
1511
  };
@@ -2685,7 +1532,6 @@ function createResponsesTerminalController(params) {
2685
1532
  }
2686
1533
  };
2687
1534
  const finalizeResponse = (response, terminalEventType) => {
2688
- params.markFinalized();
2689
1535
  backfillReasoning(response.output ?? []);
2690
1536
  finalizeTerminalFacts(response);
2691
1537
  const terminal = resolveResponsesTerminalStopReason({
@@ -2700,7 +1546,8 @@ function createResponsesTerminalController(params) {
2700
1546
  return {
2701
1547
  finalizeResponse,
2702
1548
  finalizeFailedResponse: finalizeTerminalFacts,
2703
- recoverTerminalOutput
1549
+ recoverTerminalOutput,
1550
+ emitToolCallCompletion
2704
1551
  };
2705
1552
  }
2706
1553
  //#endregion
@@ -2708,9 +1555,7 @@ function createResponsesTerminalController(params) {
2708
1555
  async function processResponsesStream(openaiStream, output, stream, model, options) {
2709
1556
  const streamingToolCalls = createResponsesToolCallTracker();
2710
1557
  const outputSlots = createResponsesOutputSlotTracker();
2711
- const reasoningBlocksById = /* @__PURE__ */ new Map();
2712
- const outputItemContentIndexes = createResponsesOutputContentIndex();
2713
- const startedTextBlocksByItemId = /* @__PURE__ */ new Map();
1558
+ const outputs = createResponsesOutputTracker();
2714
1559
  let terminalResponse;
2715
1560
  let lastTextBlock = null;
2716
1561
  const blocks = output.content;
@@ -2725,11 +1570,11 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2725
1570
  type: "thinking",
2726
1571
  item,
2727
1572
  block,
2728
- contentIndex: blocks.length
1573
+ contentIndex: blocks.length,
1574
+ outputIndex: readResponsesOutputIndex(event)
2729
1575
  };
2730
1576
  blocks.push(block);
2731
- reasoningBlocksById.set(item.id, block);
2732
- outputItemContentIndexes.set(item, slot.contentIndex);
1577
+ outputs.set(item, slot.contentIndex, slot.outputIndex);
2733
1578
  outputSlots.register(event, slot);
2734
1579
  stream.push({
2735
1580
  type: "thinking_start",
@@ -2751,17 +1596,13 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2751
1596
  item: messageItem,
2752
1597
  block,
2753
1598
  contentIndex: block ? blocks.length : void 0,
1599
+ outputIndex: readResponsesOutputIndex(event),
2754
1600
  pendingText: collapseCandidate ? "" : null,
2755
1601
  collapseCandidate
2756
1602
  };
2757
1603
  if (block) {
2758
1604
  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
- });
1605
+ outputs.set(messageItem, slot.contentIndex ?? blocks.length - 1, slot.outputIndex);
2765
1606
  }
2766
1607
  outputSlots.register(event, slot);
2767
1608
  if (slot.contentIndex !== void 0) stream.push({
@@ -2777,9 +1618,6 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2777
1618
  if (item.type === "message") return outputSlots.resolve(event, "text");
2778
1619
  return readResponsesOutputIndex(event) === void 0 ? void 0 : outputSlots.get(event);
2779
1620
  };
2780
- const getOrCreateOutputSlot = (event, item) => {
2781
- return resolveOutputItemSlot(event, item) ?? createOutputSlot(event, item);
2782
- };
2783
1621
  const materializeDeferredTextSlot = (slot) => {
2784
1622
  if (slot.block || slot.pendingText === null) return;
2785
1623
  const text = slot.pendingText;
@@ -2790,12 +1628,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2790
1628
  };
2791
1629
  blocks.push(slot.block);
2792
1630
  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
- });
1631
+ outputs.set(slot.item, slot.contentIndex, slot.outputIndex);
2799
1632
  stream.push({
2800
1633
  type: "text_start",
2801
1634
  contentIndex: slot.contentIndex,
@@ -2813,20 +1646,58 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2813
1646
  const materializeDeferredTextSlots = (except) => {
2814
1647
  for (const slot of outputSlots.values()) if (slot !== except && slot.type === "text") materializeDeferredTextSlot(slot);
2815
1648
  };
2816
- const { finalizeResponse, finalizeFailedResponse, recoverTerminalOutput } = createResponsesTerminalController({
1649
+ const terminal = createResponsesTerminalController({
2817
1650
  output,
2818
1651
  stream,
2819
1652
  model,
2820
1653
  options,
2821
- reasoningBlocksById,
2822
- startedTextBlocksByItemId,
2823
- outputItemContentIndexes,
1654
+ outputs,
2824
1655
  getLastTextBlock: () => lastTextBlock,
2825
1656
  setLastTextBlock: (block) => {
2826
1657
  lastTextBlock = block;
2827
- },
2828
- markFinalized: () => void 0
1658
+ }
2829
1659
  });
1660
+ const finalizeToolCall = (item, outputIndex, streamingToolCall, validated) => {
1661
+ const identity = {
1662
+ type: item.type,
1663
+ id: item.id || streamingToolCall?.itemId,
1664
+ call_id: item.call_id || streamingToolCall?.callId
1665
+ };
1666
+ const finalOutputIndex = outputIndex ?? streamingToolCall?.outputIndex;
1667
+ if (finalOutputIndex === void 0 && !identity.id && !identity.call_id) {
1668
+ if (!streamingToolCall) throw new Error("Responses stream completed tool call without an output identity");
1669
+ return;
1670
+ }
1671
+ if (streamingToolCall) {
1672
+ streamingToolCalls.forget(streamingToolCall);
1673
+ for (const slot of outputSlots.values()) if (slot.type === "toolCall" && slot.toolCall === streamingToolCall) outputSlots.forget(slot);
1674
+ }
1675
+ terminal.emitToolCallCompletion(identity, finalOutputIndex, streamingToolCall, validated);
1676
+ };
1677
+ const prepareTerminalToolCalls = (items) => {
1678
+ const prepared = /* @__PURE__ */ new Map();
1679
+ const recovered = [];
1680
+ const callIds = /* @__PURE__ */ new Set();
1681
+ const allowUnmatchedIdentity = items.filter((item, index) => item.type === "function_call" && !outputs.get(item, index)?.completed).length === 1;
1682
+ for (const [outputIndex, item] of items.entries()) {
1683
+ const tracked = outputs.get(item, outputIndex);
1684
+ if (item.type !== "function_call") continue;
1685
+ if (item.call_id && callIds.has(item.call_id)) throw new Error("Responses stream repeated a terminal tool-call identity");
1686
+ if (item.call_id) callIds.add(item.call_id);
1687
+ if (tracked?.completed) continue;
1688
+ const state = streamingToolCalls.resolve({ output_index: outputIndex }, readResponsesToolCallItemIdentity(item), allowUnmatchedIdentity);
1689
+ if (tracked && !state) throw new Error("Responses stream completed with unresolved tool calls");
1690
+ const validated = resolveCompletedResponsesToolCall(item, { name: state?.block.name });
1691
+ if (state) recovered.push(state);
1692
+ prepared.set(outputIndex, () => finalizeToolCall(item, outputIndex, state, validated));
1693
+ }
1694
+ if (!streamingToolCalls.hasExactlyActive(recovered)) throw new Error("Responses stream completed with unresolved tool calls");
1695
+ return (outputIndex) => {
1696
+ const complete = prepared.get(outputIndex);
1697
+ if (!complete) throw new Error("Responses stream completed with unresolved tool calls");
1698
+ complete();
1699
+ };
1700
+ };
2830
1701
  const guardedStream = adaptResponsesStream(withFirstStreamEventTimeout(openaiStream, {
2831
1702
  provider: model.provider,
2832
1703
  api: model.api,
@@ -2860,6 +1731,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2860
1731
  block: toolCallBlock,
2861
1732
  contentIndex,
2862
1733
  argumentStreamReliable: true,
1734
+ previewSchedule: createToolArgumentPreviewSchedule(),
2863
1735
  ...readResponsesToolCallItemIdentity(item)
2864
1736
  };
2865
1737
  streamingToolCalls.register(event, toolCallState);
@@ -2868,7 +1740,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2868
1740
  toolCall: toolCallState
2869
1741
  });
2870
1742
  output.content.push(toolCallBlock);
2871
- outputItemContentIndexes.set(item, contentIndex);
1743
+ outputs.set(item, contentIndex, readResponsesOutputIndex(event));
2872
1744
  stream.push({
2873
1745
  type: "toolcall_start",
2874
1746
  contentIndex,
@@ -2994,7 +1866,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2994
1866
  const toolCall = streamingToolCalls.resolve(event);
2995
1867
  if (toolCall) {
2996
1868
  toolCall.block.partialJson += event.delta;
2997
- toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
1869
+ if (toolCall.previewSchedule(toolCall.block.partialJson.length)) toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
2998
1870
  stream.push({
2999
1871
  type: "toolcall_delta",
3000
1872
  contentIndex: toolCall.contentIndex,
@@ -3027,13 +1899,14 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
3027
1899
  if (item.type !== "message") lastTextBlock = null;
3028
1900
  const existingOutputSlot = resolveOutputItemSlot(event, item);
3029
1901
  materializeDeferredTextSlots(existingOutputSlot);
3030
- const outputSlot = existingOutputSlot ?? getOrCreateOutputSlot(event, item);
1902
+ const outputSlot = existingOutputSlot ?? createOutputSlot(event, item);
3031
1903
  compactionTracker.completed(item, blocks.length);
3032
1904
  if (item.type === "reasoning" && outputSlot?.type === "thinking") {
3033
1905
  const summaryText = item.summary?.map((s) => s.text).join("\n\n") || "";
3034
1906
  const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
3035
1907
  outputSlot.block.thinking = summaryText || contentText || outputSlot.block.thinking;
3036
1908
  outputSlot.block.thinkingSignature = JSON.stringify(item);
1909
+ outputs.set(item, outputSlot.contentIndex, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
3037
1910
  if (item.encrypted_content && options?.reasoningReplayMetadata) outputSlot.block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
3038
1911
  stream.push({
3039
1912
  type: "thinking_end",
@@ -3065,7 +1938,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
3065
1938
  partial: output
3066
1939
  });
3067
1940
  lastTextBlock = outputSlot.collapseCandidate;
3068
- outputItemContentIndexes.set(item, outputSlot.collapseCandidate.index);
1941
+ outputs.set(item, outputSlot.collapseCandidate.index, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
3069
1942
  } else {
3070
1943
  if (!outputSlot.block) {
3071
1944
  outputSlot.block = {
@@ -3090,7 +1963,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
3090
1963
  index: contentIndex,
3091
1964
  phase
3092
1965
  };
3093
- outputItemContentIndexes.set(item, contentIndex);
1966
+ outputs.set(item, contentIndex, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
3094
1967
  stream.push({
3095
1968
  type: "text_end",
3096
1969
  contentIndex,
@@ -3099,66 +1972,33 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
3099
1972
  });
3100
1973
  }
3101
1974
  outputSlots.forget(outputSlot);
3102
- startedTextBlocksByItemId.delete(item.id);
3103
1975
  } else if (item.type === "function_call") {
1976
+ if (outputs.get(item, readResponsesOutputIndex(event))?.completed) continue;
3104
1977
  const streamingToolCall = streamingToolCalls.resolve(event, readResponsesToolCallItemIdentity(item));
3105
1978
  if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
3106
- const streamedArguments = streamingToolCall?.block.partialJson ?? "";
3107
1979
  const completedArguments = typeof item.arguments === "string" ? item.arguments : void 0;
3108
1980
  if (streamingToolCall && !streamingToolCall.argumentStreamReliable && !completedArguments) continue;
3109
- const finalArguments = completedArguments !== void 0 && (completedArguments.length > 0 || !streamedArguments) ? completedArguments : streamedArguments;
3110
1981
  const validated = resolveCompletedResponsesToolCall(item, {
3111
1982
  name: streamingToolCall?.block.name,
3112
- arguments: finalArguments
1983
+ arguments: completedArguments || streamingToolCall?.block.partialJson || ""
3113
1984
  });
3114
- let toolCall;
3115
- let contentIndex;
3116
- if (streamingToolCall) {
3117
- const block = streamingToolCall.block;
3118
- block.id = resolveResponsesToolCallId(item, block.id);
3119
- block.name = validated.name;
3120
- block.arguments = validated.arguments;
3121
- delete block.partialJson;
3122
- toolCall = block;
3123
- contentIndex = streamingToolCall.contentIndex;
3124
- } else {
3125
- toolCall = {
3126
- type: "toolCall",
3127
- id: resolveResponsesToolCallId(item),
3128
- name: validated.name,
3129
- arguments: validated.arguments
3130
- };
3131
- blocks.push(toolCall);
3132
- contentIndex = blocks.length - 1;
3133
- stream.push({
3134
- type: "toolcall_start",
3135
- contentIndex,
3136
- partial: output
3137
- });
3138
- }
3139
- if (streamingToolCall) {
3140
- streamingToolCalls.forget(streamingToolCall);
3141
- for (const slot of outputSlots.values()) if (slot.type === "toolCall" && slot.toolCall === streamingToolCall) outputSlots.forget(slot);
3142
- }
3143
- stream.push({
3144
- type: "toolcall_end",
3145
- contentIndex,
3146
- toolCall,
3147
- partial: output
3148
- });
3149
- outputItemContentIndexes.set(item, contentIndex);
1985
+ finalizeToolCall(item, readResponsesOutputIndex(event), streamingToolCall, validated);
3150
1986
  }
3151
1987
  } else if (event.type === "response.completed" || event.type === "response.incomplete") {
3152
- if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
3153
- finalizeResponse(event.response, event.type);
3154
- if (event.type === "response.completed" || output.stopReason === "length") recoverTerminalOutput(event.response.output ?? [], event.type === "response.completed");
1988
+ if (event.type === "response.incomplete" && streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
1989
+ terminal.finalizeResponse(event.response, event.type);
1990
+ if (event.type === "response.completed" || output.stopReason === "length") {
1991
+ const items = event.response.output ?? [];
1992
+ const completeToolCall = event.type === "response.completed" ? prepareTerminalToolCalls(items) : void 0;
1993
+ terminal.recoverTerminalOutput(items, completeToolCall);
1994
+ }
3155
1995
  terminalResponse = event.type === "response.completed" ? event.response : null;
3156
1996
  if (output.stopReason === "stop" && output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
3157
1997
  break;
3158
1998
  } else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
3159
1999
  else if (event.type === "response.failed") {
3160
2000
  const failure = normalizeResponsesFailedEvent(isRecord(event) ? event : {}, model);
3161
- finalizeFailedResponse(event.response, failure.responseId);
2001
+ terminal.finalizeFailedResponse(event.response, failure.responseId);
3162
2002
  throw new ResponsesStreamFailure(failure, event.response);
3163
2003
  }
3164
2004
  }
@@ -3312,26 +2152,34 @@ async function runResponsesStreamLifecycle(params) {
3312
2152
  return request;
3313
2153
  };
3314
2154
  const requestParams = await buildRequest("checkpoint");
3315
- firstEventAbort = createFirstStreamEventAbortController(options?.signal);
3316
- const { stream: openaiStream, response } = await createResponsesStreamWithEncryptedContentRetry({
2155
+ const firstEvent = createFirstStreamEventAbortController(options?.signal);
2156
+ firstEventAbort = firstEvent;
2157
+ let started = false;
2158
+ const { stream: hookedOpenAIStream } = await createResponsesStreamWithEncryptedContentRetry({
3317
2159
  client,
3318
2160
  request: requestParams,
3319
2161
  requestOptions: {
3320
2162
  ...buildResponsesRequestOptions(options),
3321
- signal: firstEventAbort.signal
2163
+ signal: firstEvent.signal
3322
2164
  },
3323
2165
  model,
3324
2166
  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
2167
+ onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint),
2168
+ canRetryStream: () => output.content.length === 0,
2169
+ wrapStream: ({ stream: openaiStream, response }) => withProviderResponseHook({
2170
+ stream: openaiStream,
2171
+ signal: firstEvent.signal,
2172
+ abort: firstEvent.abort,
2173
+ hook: createOpenAIProviderAcceptanceHook(options, response, model),
2174
+ onReady: () => {
2175
+ if (!started) {
2176
+ started = true;
2177
+ stream.push({
2178
+ type: "start",
2179
+ partial: output
2180
+ });
2181
+ }
2182
+ }
3335
2183
  })
3336
2184
  });
3337
2185
  const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
@@ -3372,4 +2220,4 @@ async function runResponsesStreamLifecycle(params) {
3372
2220
  }
3373
2221
  }
3374
2222
  //#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 };
2223
+ 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, captureOpenAIResponsesCompaction as G, createOpenAIResponsesAssistantOutput as H, createResponsesStreamWithEncryptedContentRetry as I, resolveReplayableResponsesMessageId as J, resolveNewestOpenAIResponsesCompactionReplay 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, CompactionReplayRefreshRequiredError as U, convertResponsesMessages$1 as V, buildOpenAIResponsesReasoningReplayMetadata as W, resolveModelPayloadDebugMode as X, emitModelTransportDebug as Y, resolveModelSseDebugMode as Z, 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, suppressOpenAIResponsesCompaction 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 };