@openclaw/ai 2026.8.1-beta.2 → 2026.9.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{anthropic-SrGtwsJu.d.mts → anthropic-BECQCNdF.d.mts} +0 -2
- package/dist/{anthropic-B6dLpq5L.mjs → anthropic-DI4PZKKB.mjs} +46 -34
- package/dist/{anthropic-compaction-replay-8lJNKXOE.mjs → anthropic-compaction-replay-nhKaCXu6.mjs} +17 -22
- package/dist/{anthropic-payload-policy-CiEuQS72.d.mts → anthropic-payload-policy-B_0n0enE.d.mts} +3 -1
- package/dist/{api-registry-k3zTz0cV.d.mts → api-registry-CTd8NzcD.d.mts} +2 -1
- package/dist/{azure-openai-responses-mxIOtUnn.mjs → azure-openai-responses-D8dI0ekg.mjs} +3 -3
- package/dist/diagnostics.d.mts +0 -1
- package/dist/diagnostics.mjs +1 -1
- package/dist/event-stream-BKp4fOt_.d.mts +1 -0
- package/dist/{event-stream-BP6AWT8j.d.mts → event-stream-LiXePESD.d.mts} +1 -2
- package/dist/event-stream.d.mts +2 -1
- package/dist/{google-C7h2QzDX.mjs → google-Od-LLdVK.mjs} +3 -3
- package/dist/{google-shared-B0Qr9OR7.mjs → google-shared-Bgr9lFPw.mjs} +22 -8
- package/dist/{google-vertex-Bhc3TjDl.mjs → google-vertex-aerRSXc4.mjs} +4 -4
- package/dist/{host-DTqNc7ad.mjs → host-D51fmkH6.mjs} +40 -33
- package/dist/{host-vWgMMhiJ.d.mts → host-DsbPMFU6.d.mts} +7 -7
- package/dist/index-Qbej8io0.d.mts +3 -0
- package/dist/index.d.mts +8 -8
- package/dist/index.mjs +2 -3
- package/dist/internal/anthropic.d.mts +13 -6
- package/dist/internal/anthropic.mjs +4 -4
- package/dist/internal/openai-responses-payload-policy.d.mts +2 -2
- package/dist/internal/openai-responses-payload-policy.mjs +2 -2
- package/dist/internal/openai.d.mts +6 -6
- package/dist/internal/openai.mjs +10 -8
- package/dist/internal/runtime.d.mts +18 -5
- package/dist/internal/runtime.mjs +8 -7
- package/dist/internal/shared.d.mts +18 -4
- package/dist/internal/shared.mjs +4 -4
- package/dist/{json-parse-CDnesDM_.mjs → json-parse-BuAJEbdW.mjs} +18 -2
- package/dist/{headers-DdOQtGuU.mjs → llm-request-activity-BjtkplhG.mjs} +1 -9
- package/dist/{mistral-CEWoQI_g.mjs → mistral-EiHdymeb.mjs} +59 -49
- package/dist/{openai-chatgpt-responses-CrPmqERt.mjs → openai-chatgpt-responses-DHpF9o1e.mjs} +42 -17
- package/dist/{openai-completions-BPnt4Sml.mjs → openai-completions-EFPiUGfS.mjs} +60 -257
- package/dist/{openai-completions-compat-Dt3dcawL.d.mts → openai-completions-compat-BefmHT26.d.mts} +3 -3
- package/dist/openai-completions-stream-DUlGwRMz.mjs +1621 -0
- package/dist/{openai-responses-DhIKtOup.mjs → openai-responses-BogP8OjX.mjs} +6 -5
- package/dist/{openai-responses-contracts-XpZJxrRG.d.mts → openai-responses-contracts-Dvj_UtPy.d.mts} +3 -3
- package/dist/{openai-responses-contracts-CyfIkQi5.mjs → openai-responses-contracts-QUY12X0B.mjs} +6 -26
- package/dist/{openai-responses-payload-policy-BSs371VM.d.mts → openai-responses-payload-policy-CNGFT9zr.d.mts} +1 -0
- package/dist/{openai-responses-payload-policy-BDxV-W0c.mjs → openai-responses-payload-policy-D8EdimYe.mjs} +6 -8
- package/dist/{openai-responses-prompt-observer-internal-DgNTYnRY.mjs → openai-responses-prompt-observer-internal-Cd4hJG-S.mjs} +3 -3
- package/dist/{openai-responses-shared-DXIt3iY5.mjs → openai-responses-shared-DJThc6jW.mjs} +205 -1472
- package/dist/openai-stop-reason-Drnn_6Qj.mjs +28 -0
- package/dist/openai-tool-schema-ho-hIkQf.mjs +1695 -0
- package/dist/{provider-error-BUwEnjXq.mjs → provider-error-DDOs_Bz0.mjs} +20 -27
- package/dist/provider-options-AvldWZt8.mjs +21 -0
- package/dist/{provider-options-B96RdNpH.d.mts → provider-options-MdMBLzlU.d.mts} +15 -4
- package/dist/provider-transcript-transform-C01bQ5a3.mjs +32 -0
- package/dist/provider-types.d.mts +7 -5
- package/dist/providers.d.mts +1 -2
- package/dist/providers.mjs +9 -9
- package/dist/{reasoning-tag-text-partitioner-rnPwX2pg.mjs → reasoning-tag-text-partitioner-5ygO2rZc.mjs} +3 -0
- package/dist/{sanitize-unicode-BYqrYtC_.mjs → sanitize-unicode-DCkltN94.mjs} +1 -2
- package/dist/{simple-options-D58D5Kvw.mjs → simple-options-CFj7x3J4.mjs} +5 -4
- package/dist/{anthropic-JsNA5KCu.mjs → src-Bu3FiFAG.mjs} +1 -1
- package/dist/{streaming-byte-guard-BrbkbwUu.mjs → streaming-byte-guard-CC-HMn_u.mjs} +5 -6
- package/dist/string-normalization--fwJ4S2q.mjs +16 -0
- package/dist/{tool-schema-json-projection-q5d7QX5c.mjs → tool-schema-json-projection-qvTEs5Am.mjs} +17 -8
- package/dist/transport-stream-shared-ljShVIZB.mjs +342 -0
- package/dist/transport-stream-shared-rvaCyFYt.d.mts +138 -0
- package/dist/{transport-utils-DJqkxbhC.mjs → transport-utils-LJ1_rbi-.mjs} +8 -5
- package/dist/transports.d.mts +45 -106
- package/dist/transports.mjs +134 -1089
- package/dist/{types-BHNrPS1l.d.mts → types-DhLoJbFm.d.mts} +49 -17
- package/dist/types-GiAjXatj.d.mts +1 -0
- package/dist/types.d.mts +6 -5
- package/dist/types.mjs +1 -2
- package/dist/utf16-slice-qz3nsy87.mjs +84 -0
- package/dist/{validation-DT9SrFn3.d.mts → validation-Dk7q7NMN.d.mts} +1 -2
- package/dist/validation.d.mts +1 -1
- package/package.json +5 -5
- package/dist/index-BVVgDSdq.d.mts +0 -1
- package/dist/openai-stop-reason-BkFkqqK0.mjs +0 -563
- package/dist/openai-tool-projection-CY04OcvQ.mjs +0 -338
- package/dist/provider-transcript-transform-ePx-Bbfr.mjs +0 -155
- package/dist/record-coerce-DdXsgUd_.mjs +0 -23
- package/dist/src-D2H6yKkH.mjs +0 -2
- package/dist/stream-first-event-timeout-DvDeSucC.d.mts +0 -29
- package/dist/string-coerce-fsri9iCu.mjs +0 -34
- package/dist/types-BVVgDSdq.d.mts +0 -1
- package/dist/utf16-slice-CvGodqok.mjs +0 -29
|
@@ -1,113 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as clampThinkingLevel, r as calculateCost } from "./sanitize-unicode-
|
|
3
|
-
import { a as describeToolResultMediaPlaceholder,
|
|
4
|
-
import {
|
|
5
|
-
import { t as truncateUtf16Safe } from "./utf16-slice-CvGodqok.mjs";
|
|
6
|
-
import { n as projectProviderError } from "./provider-error-BUwEnjXq.mjs";
|
|
1
|
+
import { c as normalizeLowercaseStringOrEmpty, d as normalizeOptionalString, o as isRecord, t as truncateUtf16Safe } from "./utf16-slice-qz3nsy87.mjs";
|
|
2
|
+
import { i as clampThinkingLevel, r as calculateCost } from "./sanitize-unicode-DCkltN94.mjs";
|
|
3
|
+
import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, n as getAiTransportHost } from "./host-D51fmkH6.mjs";
|
|
4
|
+
import { n as projectProviderError } from "./provider-error-DDOs_Bz0.mjs";
|
|
7
5
|
import { t as asFiniteNumber } from "./number-coercion-H9qHik3g.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
6
|
+
import { f as sortPromptCacheToolsByName, l as stripSystemPromptCacheBoundary } from "./simple-options-CFj7x3J4.mjs";
|
|
7
|
+
import { c as transformTransportMessages } from "./tool-schema-json-projection-qvTEs5Am.mjs";
|
|
8
|
+
import { d as redactSensitiveText, u as redactIdentifier } from "./transport-utils-LJ1_rbi-.mjs";
|
|
9
|
+
import { _ as transportAbortError, g as sanitizeTransportPayloadText, h as sanitizeNonEmptyTransportPayloadText, m as parseTerminalToolCallArguments, y as withProviderResponseHook } from "./transport-stream-shared-ljShVIZB.mjs";
|
|
10
|
+
import { r as parseStreamingJson, t as createToolArgumentPreviewSchedule } from "./json-parse-BuAJEbdW.mjs";
|
|
11
|
+
import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
|
|
13
12
|
import { t as shortHash } from "./hash-CHgqbJmD.mjs";
|
|
14
|
-
import {
|
|
15
|
-
import { l as redactIdentifier, u as redactSensitiveText } from "./transport-utils-DJqkxbhC.mjs";
|
|
16
|
-
import { a as createModelStreamCooperativeScheduler, c as log, o as createOpenAIResponseHook, t as projectOpenAITools } from "./openai-tool-projection-CY04OcvQ.mjs";
|
|
13
|
+
import { C as createOpenAIProviderAcceptanceHook, E as log, S as createModelStreamCooperativeScheduler, a as resolveOpenAIProjectedToolsStrictToolFlag, r as normalizeOpenAIStrictToolParameters, t as findOpenAIStrictToolProjectionDiagnostics, v as projectOpenAITools } from "./openai-tool-schema-ho-hIkQf.mjs";
|
|
17
14
|
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-MK28puvq.mjs";
|
|
15
|
+
import { t as transformProviderMessages } from "./provider-transcript-transform-C01bQ5a3.mjs";
|
|
16
|
+
import { S as supportsOpenAITemperature, a as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, c as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, f as RESPONSE_FAILED_NO_DETAILS_MESSAGE, o as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, s as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, x as supportsOpenAIReasoningEffort, y as resolveOpenAIReasoningEffortForModel } from "./openai-responses-contracts-QUY12X0B.mjs";
|
|
18
17
|
import { createHash, randomUUID } from "node:crypto";
|
|
19
|
-
//#region packages/ai/src/transports/json-unsafe-integers.ts
|
|
20
|
-
/**
|
|
21
|
-
* JSON parsing helpers that preserve integer literals larger than
|
|
22
|
-
* Number.MAX_SAFE_INTEGER as strings before JSON.parse can round them.
|
|
23
|
-
*/
|
|
24
|
-
const MAX_SAFE_INTEGER_ABS_STR = String(Number.MAX_SAFE_INTEGER);
|
|
25
|
-
function isAsciiDigit(ch) {
|
|
26
|
-
return ch !== void 0 && ch >= "0" && ch <= "9";
|
|
27
|
-
}
|
|
28
|
-
function parseJsonNumberToken(input, start) {
|
|
29
|
-
let idx = start;
|
|
30
|
-
if (input[idx] === "-") idx += 1;
|
|
31
|
-
if (idx >= input.length) return null;
|
|
32
|
-
if (input[idx] === "0") idx += 1;
|
|
33
|
-
else if (isAsciiDigit(input[idx]) && input[idx] !== "0") while (isAsciiDigit(input[idx])) idx += 1;
|
|
34
|
-
else return null;
|
|
35
|
-
let isInteger = true;
|
|
36
|
-
if (input[idx] === ".") {
|
|
37
|
-
isInteger = false;
|
|
38
|
-
idx += 1;
|
|
39
|
-
if (!isAsciiDigit(input[idx])) return null;
|
|
40
|
-
while (isAsciiDigit(input[idx])) idx += 1;
|
|
41
|
-
}
|
|
42
|
-
if (input[idx] === "e" || input[idx] === "E") {
|
|
43
|
-
isInteger = false;
|
|
44
|
-
idx += 1;
|
|
45
|
-
if (input[idx] === "+" || input[idx] === "-") idx += 1;
|
|
46
|
-
if (!isAsciiDigit(input[idx])) return null;
|
|
47
|
-
while (isAsciiDigit(input[idx])) idx += 1;
|
|
48
|
-
}
|
|
49
|
-
return {
|
|
50
|
-
token: input.slice(start, idx),
|
|
51
|
-
end: idx,
|
|
52
|
-
isInteger
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function isUnsafeIntegerLiteral(token) {
|
|
56
|
-
const digits = token[0] === "-" ? token.slice(1) : token;
|
|
57
|
-
if (digits.length < MAX_SAFE_INTEGER_ABS_STR.length) return false;
|
|
58
|
-
if (digits.length > MAX_SAFE_INTEGER_ABS_STR.length) return true;
|
|
59
|
-
return digits > MAX_SAFE_INTEGER_ABS_STR;
|
|
60
|
-
}
|
|
61
|
-
/** Quotes integer literals above Number.MAX_SAFE_INTEGER before JSON.parse. */
|
|
62
|
-
function quoteUnsafeIntegerLiterals(input) {
|
|
63
|
-
let out = "";
|
|
64
|
-
let inString = false;
|
|
65
|
-
let escaped = false;
|
|
66
|
-
let idx = 0;
|
|
67
|
-
while (idx < input.length) {
|
|
68
|
-
const ch = input[idx] ?? "";
|
|
69
|
-
if (inString) {
|
|
70
|
-
out += ch;
|
|
71
|
-
if (escaped) escaped = false;
|
|
72
|
-
else if (ch === "\\") escaped = true;
|
|
73
|
-
else if (ch === "\"") inString = false;
|
|
74
|
-
idx += 1;
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (ch === "\"") {
|
|
78
|
-
inString = true;
|
|
79
|
-
out += ch;
|
|
80
|
-
idx += 1;
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
if (ch === "-" || isAsciiDigit(ch)) {
|
|
84
|
-
const parsed = parseJsonNumberToken(input, idx);
|
|
85
|
-
if (parsed) {
|
|
86
|
-
if (parsed.isInteger && isUnsafeIntegerLiteral(parsed.token)) out += `"${parsed.token}"`;
|
|
87
|
-
else out += parsed.token;
|
|
88
|
-
idx = parsed.end;
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
out += ch;
|
|
93
|
-
idx += 1;
|
|
94
|
-
}
|
|
95
|
-
return out;
|
|
96
|
-
}
|
|
97
|
-
/** Parses JSON while preserving unsafe integer literals as strings. */
|
|
98
|
-
function parseJsonPreservingUnsafeIntegers(input) {
|
|
99
|
-
return JSON.parse(quoteUnsafeIntegerLiterals(input));
|
|
100
|
-
}
|
|
101
|
-
/** Parses or accepts an object while preserving unsafe integer literals in string input. */
|
|
102
|
-
function parseJsonObjectPreservingUnsafeIntegers(value) {
|
|
103
|
-
if (typeof value === "string") try {
|
|
104
|
-
return asNullableRecord(parseJsonPreservingUnsafeIntegers(value));
|
|
105
|
-
} catch {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
return asNullableRecord(value);
|
|
109
|
-
}
|
|
110
|
-
//#endregion
|
|
111
18
|
//#region packages/ai/src/transports/model-transport-debug.ts
|
|
112
19
|
/**
|
|
113
20
|
* Environment-driven debug controls for model transport logging.
|
|
@@ -149,1267 +56,6 @@ function emitModelTransportDebug(log, message) {
|
|
|
149
56
|
log.debug(message);
|
|
150
57
|
}
|
|
151
58
|
//#endregion
|
|
152
|
-
//#region packages/ai/src/providers/clean-for-gemini.ts
|
|
153
|
-
const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
154
|
-
"patternProperties",
|
|
155
|
-
"additionalProperties",
|
|
156
|
-
"$schema",
|
|
157
|
-
"$id",
|
|
158
|
-
"$ref",
|
|
159
|
-
"$defs",
|
|
160
|
-
"definitions",
|
|
161
|
-
"examples",
|
|
162
|
-
"minLength",
|
|
163
|
-
"maxLength",
|
|
164
|
-
"minimum",
|
|
165
|
-
"maximum",
|
|
166
|
-
"multipleOf",
|
|
167
|
-
"pattern",
|
|
168
|
-
"format",
|
|
169
|
-
"minItems",
|
|
170
|
-
"maxItems",
|
|
171
|
-
"uniqueItems",
|
|
172
|
-
"minProperties",
|
|
173
|
-
"maxProperties",
|
|
174
|
-
"not"
|
|
175
|
-
]);
|
|
176
|
-
const SCHEMA_META_KEYS = [
|
|
177
|
-
"description",
|
|
178
|
-
"title",
|
|
179
|
-
"default"
|
|
180
|
-
];
|
|
181
|
-
function copySchemaMeta$1(from, to) {
|
|
182
|
-
for (const key of SCHEMA_META_KEYS) if (key in from && from[key] !== void 0) to[key] = from[key];
|
|
183
|
-
}
|
|
184
|
-
function stringifyGeminiEnumValue(value) {
|
|
185
|
-
if (typeof value === "string") return value;
|
|
186
|
-
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
187
|
-
if (typeof value === "boolean") return String(value);
|
|
188
|
-
}
|
|
189
|
-
function cleanGeminiEnumValues(value) {
|
|
190
|
-
if (!Array.isArray(value)) return;
|
|
191
|
-
const values = value.flatMap((entry) => {
|
|
192
|
-
const stringified = stringifyGeminiEnumValue(entry);
|
|
193
|
-
return stringified === void 0 ? [] : [stringified];
|
|
194
|
-
});
|
|
195
|
-
const unique = [...new Set(values)];
|
|
196
|
-
return unique.length > 0 ? unique : void 0;
|
|
197
|
-
}
|
|
198
|
-
function tryFlattenLiteralAnyOf(variants) {
|
|
199
|
-
if (variants.length === 0) return null;
|
|
200
|
-
const allValues = [];
|
|
201
|
-
let commonType = null;
|
|
202
|
-
for (const variant of variants) {
|
|
203
|
-
if (!variant || typeof variant !== "object") return null;
|
|
204
|
-
const v = variant;
|
|
205
|
-
let literalValue;
|
|
206
|
-
if ("const" in v) literalValue = v.const;
|
|
207
|
-
else if (Array.isArray(v.enum) && v.enum.length === 1) literalValue = v.enum[0];
|
|
208
|
-
else return null;
|
|
209
|
-
const variantType = typeof v.type === "string" ? v.type : null;
|
|
210
|
-
if (!variantType) return null;
|
|
211
|
-
if (commonType === null) commonType = variantType;
|
|
212
|
-
else if (commonType !== variantType) return null;
|
|
213
|
-
allValues.push(literalValue);
|
|
214
|
-
}
|
|
215
|
-
if (commonType && allValues.length > 0) return {
|
|
216
|
-
type: commonType,
|
|
217
|
-
enum: allValues
|
|
218
|
-
};
|
|
219
|
-
return null;
|
|
220
|
-
}
|
|
221
|
-
function isNullSchema(variant) {
|
|
222
|
-
if (!variant || typeof variant !== "object" || Array.isArray(variant)) return false;
|
|
223
|
-
const record = variant;
|
|
224
|
-
if ("const" in record && record.const === null) return true;
|
|
225
|
-
if (Array.isArray(record.enum) && record.enum.length === 1) return record.enum[0] === null;
|
|
226
|
-
const typeValue = record.type;
|
|
227
|
-
if (typeValue === "null") return true;
|
|
228
|
-
if (Array.isArray(typeValue) && typeValue.length === 1 && typeValue[0] === "null") return true;
|
|
229
|
-
return false;
|
|
230
|
-
}
|
|
231
|
-
function stripNullVariants(variants) {
|
|
232
|
-
if (variants.length === 0) return {
|
|
233
|
-
variants,
|
|
234
|
-
stripped: false
|
|
235
|
-
};
|
|
236
|
-
const nonNull = variants.filter((variant) => !isNullSchema(variant));
|
|
237
|
-
return {
|
|
238
|
-
variants: nonNull,
|
|
239
|
-
stripped: nonNull.length !== variants.length
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
function extendSchemaDefs$1(defs, schema) {
|
|
243
|
-
const defsEntry = schema.$defs && typeof schema.$defs === "object" && !Array.isArray(schema.$defs) ? schema.$defs : void 0;
|
|
244
|
-
const legacyDefsEntry = schema.definitions && typeof schema.definitions === "object" && !Array.isArray(schema.definitions) ? schema.definitions : void 0;
|
|
245
|
-
if (!defsEntry && !legacyDefsEntry) return defs;
|
|
246
|
-
const next = defs ? new Map(defs) : /* @__PURE__ */ new Map();
|
|
247
|
-
if (defsEntry) for (const [key, value] of Object.entries(defsEntry)) next.set(key, value);
|
|
248
|
-
if (legacyDefsEntry) for (const [key, value] of Object.entries(legacyDefsEntry)) next.set(key, value);
|
|
249
|
-
return next;
|
|
250
|
-
}
|
|
251
|
-
function decodeJsonPointerSegment$1(segment) {
|
|
252
|
-
return segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
253
|
-
}
|
|
254
|
-
function tryResolveLocalRef$1(ref, defs) {
|
|
255
|
-
if (!defs) return;
|
|
256
|
-
const match = ref.match(/^#\/(?:\$defs|definitions)\/(.+)$/);
|
|
257
|
-
if (!match) return;
|
|
258
|
-
const name = decodeJsonPointerSegment$1(match[1] ?? "");
|
|
259
|
-
if (!name) return;
|
|
260
|
-
return defs.get(name);
|
|
261
|
-
}
|
|
262
|
-
function simplifyUnionVariants(params) {
|
|
263
|
-
const { obj, variants } = params;
|
|
264
|
-
const { variants: nonNullVariants, stripped } = stripNullVariants(variants);
|
|
265
|
-
const flattened = tryFlattenLiteralAnyOf(nonNullVariants);
|
|
266
|
-
if (flattened) {
|
|
267
|
-
const result = {
|
|
268
|
-
type: flattened.type,
|
|
269
|
-
enum: flattened.enum
|
|
270
|
-
};
|
|
271
|
-
copySchemaMeta$1(obj, result);
|
|
272
|
-
return {
|
|
273
|
-
variants: nonNullVariants,
|
|
274
|
-
simplified: result
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
if (stripped && nonNullVariants.length === 1) {
|
|
278
|
-
const lone = nonNullVariants[0];
|
|
279
|
-
if (lone && typeof lone === "object" && !Array.isArray(lone)) {
|
|
280
|
-
const result = { ...lone };
|
|
281
|
-
copySchemaMeta$1(obj, result);
|
|
282
|
-
return {
|
|
283
|
-
variants: nonNullVariants,
|
|
284
|
-
simplified: result
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
return {
|
|
288
|
-
variants: nonNullVariants,
|
|
289
|
-
simplified: lone
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
return { variants: stripped ? nonNullVariants : variants };
|
|
293
|
-
}
|
|
294
|
-
function sanitizeRequiredFields(schema) {
|
|
295
|
-
if (!Array.isArray(schema.required)) return schema;
|
|
296
|
-
if (!schema.properties || typeof schema.properties !== "object" || Array.isArray(schema.properties)) {
|
|
297
|
-
if (schema.type === "object") delete schema.required;
|
|
298
|
-
return schema;
|
|
299
|
-
}
|
|
300
|
-
const properties = schema.properties;
|
|
301
|
-
const required = schema.required.filter((key) => typeof key === "string" && Object.hasOwn(properties, key));
|
|
302
|
-
if (required.length > 0) schema.required = required;
|
|
303
|
-
else delete schema.required;
|
|
304
|
-
return schema;
|
|
305
|
-
}
|
|
306
|
-
function cleanSchemaForGeminiWithDefs(schema, defs, refStack) {
|
|
307
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
308
|
-
if (Array.isArray(schema)) return schema.map((item) => cleanSchemaForGeminiWithDefs(item, defs, refStack));
|
|
309
|
-
const obj = schema;
|
|
310
|
-
const nextDefs = extendSchemaDefs$1(defs, obj);
|
|
311
|
-
const refValue = typeof obj.$ref === "string" ? obj.$ref : void 0;
|
|
312
|
-
if (refValue) {
|
|
313
|
-
if (refStack?.has(refValue)) return {};
|
|
314
|
-
const resolved = tryResolveLocalRef$1(refValue, nextDefs);
|
|
315
|
-
if (resolved) {
|
|
316
|
-
const nextRefStack = refStack ? new Set(refStack) : /* @__PURE__ */ new Set();
|
|
317
|
-
nextRefStack.add(refValue);
|
|
318
|
-
const cleaned = cleanSchemaForGeminiWithDefs(resolved, nextDefs, nextRefStack);
|
|
319
|
-
if (!cleaned || typeof cleaned !== "object" || Array.isArray(cleaned)) return cleaned;
|
|
320
|
-
const result = { ...cleaned };
|
|
321
|
-
copySchemaMeta$1(obj, result);
|
|
322
|
-
return result;
|
|
323
|
-
}
|
|
324
|
-
const result = {};
|
|
325
|
-
copySchemaMeta$1(obj, result);
|
|
326
|
-
return result;
|
|
327
|
-
}
|
|
328
|
-
const hasAnyOf = "anyOf" in obj && Array.isArray(obj.anyOf);
|
|
329
|
-
const hasOneOf = "oneOf" in obj && Array.isArray(obj.oneOf);
|
|
330
|
-
let cleanedAnyOf = hasAnyOf ? obj.anyOf.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack)) : void 0;
|
|
331
|
-
let cleanedOneOf = hasOneOf ? obj.oneOf.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack)) : void 0;
|
|
332
|
-
if (hasAnyOf) {
|
|
333
|
-
const simplified = simplifyUnionVariants({
|
|
334
|
-
obj,
|
|
335
|
-
variants: cleanedAnyOf ?? []
|
|
336
|
-
});
|
|
337
|
-
cleanedAnyOf = simplified.variants;
|
|
338
|
-
if ("simplified" in simplified) return simplified.simplified;
|
|
339
|
-
}
|
|
340
|
-
if (hasOneOf) {
|
|
341
|
-
const simplified = simplifyUnionVariants({
|
|
342
|
-
obj,
|
|
343
|
-
variants: cleanedOneOf ?? []
|
|
344
|
-
});
|
|
345
|
-
cleanedOneOf = simplified.variants;
|
|
346
|
-
if ("simplified" in simplified) return simplified.simplified;
|
|
347
|
-
}
|
|
348
|
-
const cleaned = {};
|
|
349
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
350
|
-
if (GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS.has(key)) continue;
|
|
351
|
-
if (key === "const") {
|
|
352
|
-
const enumValues = cleanGeminiEnumValues([value]);
|
|
353
|
-
if (enumValues) cleaned.enum = enumValues;
|
|
354
|
-
continue;
|
|
355
|
-
}
|
|
356
|
-
if (key === "enum") {
|
|
357
|
-
const enumValues = cleanGeminiEnumValues(value);
|
|
358
|
-
if (enumValues) cleaned.enum = enumValues;
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
if (key === "required" && Array.isArray(value) && value.length === 0) continue;
|
|
362
|
-
if (key === "type" && (hasAnyOf || hasOneOf)) continue;
|
|
363
|
-
if (key === "type" && Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
|
|
364
|
-
const types = value.filter((entry) => entry !== "null");
|
|
365
|
-
cleaned.type = types.length === 1 ? types[0] : types;
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
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)]));
|
|
369
|
-
else cleaned[key] = {};
|
|
370
|
-
else if (key === "items" && value) if (Array.isArray(value)) cleaned[key] = value.map((entry) => cleanSchemaForGeminiWithDefs(entry, nextDefs, refStack));
|
|
371
|
-
else if (typeof value === "object") cleaned[key] = cleanSchemaForGeminiWithDefs(value, nextDefs, refStack);
|
|
372
|
-
else cleaned[key] = value;
|
|
373
|
-
else if (key === "anyOf" && Array.isArray(value)) cleaned[key] = cleanedAnyOf ?? value.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack));
|
|
374
|
-
else if (key === "oneOf" && Array.isArray(value)) cleaned[key] = cleanedOneOf ?? value.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack));
|
|
375
|
-
else if (key === "allOf" && Array.isArray(value)) cleaned[key] = value.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack));
|
|
376
|
-
else cleaned[key] = value;
|
|
377
|
-
}
|
|
378
|
-
if (cleaned.anyOf && Array.isArray(cleaned.anyOf)) {
|
|
379
|
-
const flattened = flattenUnionFallback(cleaned, cleaned.anyOf);
|
|
380
|
-
if (flattened) return sanitizeRequiredFields(flattened);
|
|
381
|
-
}
|
|
382
|
-
if (cleaned.oneOf && Array.isArray(cleaned.oneOf)) {
|
|
383
|
-
const flattened = flattenUnionFallback(cleaned, cleaned.oneOf);
|
|
384
|
-
if (flattened) return sanitizeRequiredFields(flattened);
|
|
385
|
-
}
|
|
386
|
-
return sanitizeRequiredFields(cleaned);
|
|
387
|
-
}
|
|
388
|
-
/**
|
|
389
|
-
* Last-resort flattening for anyOf/oneOf arrays that could not be simplified
|
|
390
|
-
* by `simplifyUnionVariants`. Picks a representative type so the schema is
|
|
391
|
-
* accepted by Google's restricted JSON Schema validation.
|
|
392
|
-
*/
|
|
393
|
-
function flattenUnionFallback(obj, variants) {
|
|
394
|
-
const objects = variants.filter((v) => Boolean(v) && typeof v === "object");
|
|
395
|
-
if (objects.length === 0) return;
|
|
396
|
-
const types = new Set(objects.map((v) => v.type).filter(Boolean));
|
|
397
|
-
if (objects.length === 1) {
|
|
398
|
-
const merged = { ...objects[0] };
|
|
399
|
-
copySchemaMeta$1(obj, merged);
|
|
400
|
-
return merged;
|
|
401
|
-
}
|
|
402
|
-
if (types.size === 1) {
|
|
403
|
-
const merged = { type: Array.from(types)[0] };
|
|
404
|
-
copySchemaMeta$1(obj, merged);
|
|
405
|
-
return merged;
|
|
406
|
-
}
|
|
407
|
-
const first = objects[0];
|
|
408
|
-
if (first?.type) {
|
|
409
|
-
const merged = { type: first.type };
|
|
410
|
-
copySchemaMeta$1(obj, merged);
|
|
411
|
-
return merged;
|
|
412
|
-
}
|
|
413
|
-
const merged = {};
|
|
414
|
-
copySchemaMeta$1(obj, merged);
|
|
415
|
-
return merged;
|
|
416
|
-
}
|
|
417
|
-
function cleanSchemaForGemini(schema) {
|
|
418
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
419
|
-
if (Array.isArray(schema)) return schema.map(cleanSchemaForGemini);
|
|
420
|
-
return cleanSchemaForGeminiWithDefs(schema, extendSchemaDefs$1(void 0, schema), void 0);
|
|
421
|
-
}
|
|
422
|
-
//#endregion
|
|
423
|
-
//#region packages/ai/src/providers/clean-for-llamacpp-gbnf.ts
|
|
424
|
-
/** llama.cpp rejects grammar repetitions whose expanded rule count reaches 2000. */
|
|
425
|
-
const LLAMACPP_GBNF_MAX_REPETITION_THRESHOLD = 2e3;
|
|
426
|
-
const SCHEMA_MAP_KEYS$2 = /* @__PURE__ */ new Set([
|
|
427
|
-
"$defs",
|
|
428
|
-
"definitions",
|
|
429
|
-
"dependentSchemas",
|
|
430
|
-
"patternProperties",
|
|
431
|
-
"properties"
|
|
432
|
-
]);
|
|
433
|
-
const SCHEMA_CHILD_KEYS = /* @__PURE__ */ new Set([
|
|
434
|
-
"additionalItems",
|
|
435
|
-
"additionalProperties",
|
|
436
|
-
"allOf",
|
|
437
|
-
"anyOf",
|
|
438
|
-
"contains",
|
|
439
|
-
"else",
|
|
440
|
-
"if",
|
|
441
|
-
"items",
|
|
442
|
-
"not",
|
|
443
|
-
"oneOf",
|
|
444
|
-
"prefixItems",
|
|
445
|
-
"propertyNames",
|
|
446
|
-
"then",
|
|
447
|
-
"unevaluatedItems",
|
|
448
|
-
"unevaluatedProperties"
|
|
449
|
-
]);
|
|
450
|
-
function cleanSchemaNode(node) {
|
|
451
|
-
if (Array.isArray(node)) {
|
|
452
|
-
let changed = false;
|
|
453
|
-
const entries = node.map((entry) => {
|
|
454
|
-
const next = cleanSchemaNode(entry);
|
|
455
|
-
changed ||= next !== entry;
|
|
456
|
-
return next;
|
|
457
|
-
});
|
|
458
|
-
return changed ? entries : node;
|
|
459
|
-
}
|
|
460
|
-
if (!isRecord(node)) return node;
|
|
461
|
-
let changed = false;
|
|
462
|
-
const cleaned = {};
|
|
463
|
-
for (const [key, value] of Object.entries(node)) {
|
|
464
|
-
if (key === "pattern") {
|
|
465
|
-
changed = true;
|
|
466
|
-
continue;
|
|
467
|
-
}
|
|
468
|
-
if (key === "maxLength" && typeof value === "number" && value >= 2e3) {
|
|
469
|
-
changed = true;
|
|
470
|
-
continue;
|
|
471
|
-
}
|
|
472
|
-
let next = value;
|
|
473
|
-
if (SCHEMA_MAP_KEYS$2.has(key) && isRecord(value)) {
|
|
474
|
-
let mapChanged = false;
|
|
475
|
-
next = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => {
|
|
476
|
-
const cleanedChild = cleanSchemaNode(childValue);
|
|
477
|
-
mapChanged ||= cleanedChild !== childValue;
|
|
478
|
-
return [childKey, cleanedChild];
|
|
479
|
-
}));
|
|
480
|
-
if (!mapChanged) next = value;
|
|
481
|
-
} else if (SCHEMA_CHILD_KEYS.has(key)) next = cleanSchemaNode(value);
|
|
482
|
-
cleaned[key] = next;
|
|
483
|
-
changed ||= next !== value;
|
|
484
|
-
}
|
|
485
|
-
return changed ? cleaned : node;
|
|
486
|
-
}
|
|
487
|
-
function collectSchemaViolations(node, path, violations) {
|
|
488
|
-
if (Array.isArray(node)) {
|
|
489
|
-
node.forEach((entry, index) => collectSchemaViolations(entry, `${path}[${index}]`, violations));
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
if (!isRecord(node)) return;
|
|
493
|
-
if ("pattern" in node) violations.push(`${path}.pattern`);
|
|
494
|
-
if (typeof node.maxLength === "number" && node.maxLength >= 2e3) violations.push(`${path}.maxLength`);
|
|
495
|
-
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);
|
|
496
|
-
else if (SCHEMA_CHILD_KEYS.has(key)) collectSchemaViolations(value, `${path}.${key}`, violations);
|
|
497
|
-
}
|
|
498
|
-
/** Removes JSON Schema constraints that llama.cpp cannot compile into GBNF. */
|
|
499
|
-
function cleanSchemaForLlamacppGbnf(schema) {
|
|
500
|
-
return cleanSchemaNode(schema);
|
|
501
|
-
}
|
|
502
|
-
/** Reports schema paths that llama.cpp cannot compile into GBNF. */
|
|
503
|
-
function findLlamacppGbnfSchemaViolations(schema, path) {
|
|
504
|
-
const violations = [];
|
|
505
|
-
collectSchemaViolations(schema, path, violations);
|
|
506
|
-
return violations;
|
|
507
|
-
}
|
|
508
|
-
//#endregion
|
|
509
|
-
//#region packages/ai/src/providers/schema-keyword-strip.ts
|
|
510
|
-
const SCHEMA_MAP_KEYS$1 = /* @__PURE__ */ new Set([
|
|
511
|
-
"$defs",
|
|
512
|
-
"definitions",
|
|
513
|
-
"dependentSchemas",
|
|
514
|
-
"dependencies",
|
|
515
|
-
"patternProperties",
|
|
516
|
-
"properties"
|
|
517
|
-
]);
|
|
518
|
-
/** Containers whose value is a single nested schema. */
|
|
519
|
-
const SCHEMA_OBJECT_KEYS$1 = /* @__PURE__ */ new Set([
|
|
520
|
-
"additionalItems",
|
|
521
|
-
"additionalProperties",
|
|
522
|
-
"contains",
|
|
523
|
-
"contentSchema",
|
|
524
|
-
"else",
|
|
525
|
-
"if",
|
|
526
|
-
"items",
|
|
527
|
-
"not",
|
|
528
|
-
"propertyNames",
|
|
529
|
-
"then",
|
|
530
|
-
"unevaluatedItems",
|
|
531
|
-
"unevaluatedProperties"
|
|
532
|
-
]);
|
|
533
|
-
/** Containers whose value is a list of nested schemas. */
|
|
534
|
-
const SCHEMA_ARRAY_KEYS$1 = /* @__PURE__ */ new Set([
|
|
535
|
-
"allOf",
|
|
536
|
-
"anyOf",
|
|
537
|
-
"items",
|
|
538
|
-
"oneOf",
|
|
539
|
-
"prefixItems"
|
|
540
|
-
]);
|
|
541
|
-
/** Recursively remove schema keywords unsupported by a target provider/tool surface. */
|
|
542
|
-
function stripUnsupportedSchemaKeywords(schema, unsupportedKeywords) {
|
|
543
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
544
|
-
if (Array.isArray(schema)) return schema.map((entry) => stripUnsupportedSchemaKeywords(entry, unsupportedKeywords));
|
|
545
|
-
const obj = schema;
|
|
546
|
-
const cleaned = {};
|
|
547
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
548
|
-
if (unsupportedKeywords.has(key)) continue;
|
|
549
|
-
if (SCHEMA_MAP_KEYS$1.has(key) && value && typeof value === "object" && !Array.isArray(value)) {
|
|
550
|
-
cleaned[key] = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => [childKey, stripUnsupportedSchemaKeywords(childValue, unsupportedKeywords)]));
|
|
551
|
-
continue;
|
|
552
|
-
}
|
|
553
|
-
if (SCHEMA_ARRAY_KEYS$1.has(key) && Array.isArray(value)) {
|
|
554
|
-
cleaned[key] = value.map((entry) => stripUnsupportedSchemaKeywords(entry, unsupportedKeywords));
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
if (SCHEMA_OBJECT_KEYS$1.has(key) && value && typeof value === "object") {
|
|
558
|
-
cleaned[key] = stripUnsupportedSchemaKeywords(value, unsupportedKeywords);
|
|
559
|
-
continue;
|
|
560
|
-
}
|
|
561
|
-
cleaned[key] = value;
|
|
562
|
-
}
|
|
563
|
-
return cleaned;
|
|
564
|
-
}
|
|
565
|
-
//#endregion
|
|
566
|
-
//#region packages/ai/src/providers/agent-tools-parameter-schema.ts
|
|
567
|
-
/**
|
|
568
|
-
* Normalizes model-facing tool parameter schemas across provider quirks.
|
|
569
|
-
* Handles local JSON Schema refs, OpenAPI nullable syntax, top-level unions,
|
|
570
|
-
* and provider-specific unsupported keyword stripping.
|
|
571
|
-
*/
|
|
572
|
-
/** Extracts the compat record whether callers pass a model (`{ compat }`) or the compat itself. */
|
|
573
|
-
function extractToolSchemaModelCompat(modelOrCompat) {
|
|
574
|
-
if (!modelOrCompat || typeof modelOrCompat !== "object") return;
|
|
575
|
-
if ("compat" in modelOrCompat) {
|
|
576
|
-
const compat = modelOrCompat.compat;
|
|
577
|
-
return compat && typeof compat === "object" ? compat : void 0;
|
|
578
|
-
}
|
|
579
|
-
return modelOrCompat;
|
|
580
|
-
}
|
|
581
|
-
/** JSON Schema keywords this model/provider rejects in tool schemas. */
|
|
582
|
-
function resolveUnsupportedToolSchemaKeywords(modelOrCompat) {
|
|
583
|
-
const keywords = extractToolSchemaModelCompat(modelOrCompat)?.unsupportedToolSchemaKeywords ?? [];
|
|
584
|
-
return new Set(normalizeStringEntries(keywords.filter((keyword) => typeof keyword === "string")));
|
|
585
|
-
}
|
|
586
|
-
/** Whether empty `items: {}` on array schemas must be omitted for this model/provider. */
|
|
587
|
-
function shouldOmitEmptyArrayItems(modelOrCompat) {
|
|
588
|
-
return extractToolSchemaModelCompat(modelOrCompat)?.omitEmptyArrayItems === true;
|
|
589
|
-
}
|
|
590
|
-
const MAX_TOOL_PARAMETER_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
|
|
591
|
-
const toolParameterSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
592
|
-
function resolveToolParameterSchemaCacheKey(options) {
|
|
593
|
-
const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
|
|
594
|
-
const normalizedModelId = normalizeLowercaseStringOrEmpty(options?.modelId);
|
|
595
|
-
const toolSchemaProfile = normalizeLowercaseStringOrEmpty(options?.modelCompat?.toolSchemaProfile);
|
|
596
|
-
const unsupportedKeywords = Array.from(resolveUnsupportedToolSchemaKeywords(options?.modelCompat)).toSorted();
|
|
597
|
-
const omitEmptyArrayItems = shouldOmitEmptyArrayItems(options?.modelCompat);
|
|
598
|
-
return JSON.stringify([
|
|
599
|
-
normalizedProvider,
|
|
600
|
-
normalizedModelId,
|
|
601
|
-
toolSchemaProfile,
|
|
602
|
-
unsupportedKeywords,
|
|
603
|
-
omitEmptyArrayItems
|
|
604
|
-
]);
|
|
605
|
-
}
|
|
606
|
-
function getCachedToolParameterSchema(schema, key) {
|
|
607
|
-
return toolParameterSchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
|
|
608
|
-
}
|
|
609
|
-
function rememberCachedToolParameterSchema(schema, key, value) {
|
|
610
|
-
const entries = toolParameterSchemaCache.get(schema) ?? [];
|
|
611
|
-
toolParameterSchemaCache.set(schema, [{
|
|
612
|
-
key,
|
|
613
|
-
value
|
|
614
|
-
}, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_TOOL_PARAMETER_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
|
|
615
|
-
return value;
|
|
616
|
-
}
|
|
617
|
-
function isGeminiModelId(modelId) {
|
|
618
|
-
return /(?:^|[/:])gemini(?:$|[-/:.])/.test(modelId);
|
|
619
|
-
}
|
|
620
|
-
function extractEnumValues(schema) {
|
|
621
|
-
if (!schema || typeof schema !== "object") return;
|
|
622
|
-
const record = schema;
|
|
623
|
-
if (Array.isArray(record.enum)) return record.enum;
|
|
624
|
-
if ("const" in record) return [record.const];
|
|
625
|
-
const variants = Array.isArray(record.anyOf) ? record.anyOf : Array.isArray(record.oneOf) ? record.oneOf : null;
|
|
626
|
-
if (variants) {
|
|
627
|
-
const values = variants.flatMap((variant) => {
|
|
628
|
-
return extractEnumValues(variant) ?? [];
|
|
629
|
-
});
|
|
630
|
-
return values.length > 0 ? values : void 0;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
function mergePropertySchemas(existing, incoming) {
|
|
634
|
-
if (!existing) return incoming;
|
|
635
|
-
if (!incoming) return existing;
|
|
636
|
-
const existingEnum = extractEnumValues(existing);
|
|
637
|
-
const incomingEnum = extractEnumValues(incoming);
|
|
638
|
-
if (existingEnum || incomingEnum) {
|
|
639
|
-
const values = uniqueValues([...existingEnum ?? [], ...incomingEnum ?? []]);
|
|
640
|
-
const merged = {};
|
|
641
|
-
for (const source of [existing, incoming]) {
|
|
642
|
-
if (!source || typeof source !== "object") continue;
|
|
643
|
-
const record = source;
|
|
644
|
-
for (const key of [
|
|
645
|
-
"title",
|
|
646
|
-
"description",
|
|
647
|
-
"default"
|
|
648
|
-
]) if (!(key in merged) && key in record) merged[key] = record[key];
|
|
649
|
-
}
|
|
650
|
-
const types = new Set(values.map((value) => typeof value));
|
|
651
|
-
if (types.size === 1) merged.type = Array.from(types)[0];
|
|
652
|
-
merged.enum = values;
|
|
653
|
-
return merged;
|
|
654
|
-
}
|
|
655
|
-
return existing;
|
|
656
|
-
}
|
|
657
|
-
function setOwnSchemaProperty(target, key, value) {
|
|
658
|
-
Object.defineProperty(target, key, {
|
|
659
|
-
value,
|
|
660
|
-
enumerable: true,
|
|
661
|
-
configurable: true,
|
|
662
|
-
writable: true
|
|
663
|
-
});
|
|
664
|
-
}
|
|
665
|
-
function hasTopLevelArrayKeyword(schemaRecord, key) {
|
|
666
|
-
return Array.isArray(schemaRecord[key]);
|
|
667
|
-
}
|
|
668
|
-
function getFlattenableVariantKey(schemaRecord) {
|
|
669
|
-
if (hasTopLevelArrayKeyword(schemaRecord, "anyOf")) return "anyOf";
|
|
670
|
-
if (hasTopLevelArrayKeyword(schemaRecord, "oneOf")) return "oneOf";
|
|
671
|
-
return null;
|
|
672
|
-
}
|
|
673
|
-
function getTopLevelConditionalKey(schemaRecord) {
|
|
674
|
-
return getFlattenableVariantKey(schemaRecord) ?? (hasTopLevelArrayKeyword(schemaRecord, "allOf") ? "allOf" : null);
|
|
675
|
-
}
|
|
676
|
-
function hasTopLevelObjectSchema(schemaRecord, conditionalKey) {
|
|
677
|
-
return schemaRecord.type === "object" && isRecord(schemaRecord.properties) && conditionalKey === null;
|
|
678
|
-
}
|
|
679
|
-
function isObjectLikeSchemaMissingType(schemaRecord, conditionalKey) {
|
|
680
|
-
return !("type" in schemaRecord) && (isRecord(schemaRecord.properties) || Array.isArray(schemaRecord.required)) && conditionalKey === null;
|
|
681
|
-
}
|
|
682
|
-
function isTypedObjectSchemaMissingValidProperties(schemaRecord, conditionalKey) {
|
|
683
|
-
return schemaRecord.type === "object" && !isRecord(schemaRecord.properties) && conditionalKey === null;
|
|
684
|
-
}
|
|
685
|
-
function isTrulyEmptySchema(schemaRecord) {
|
|
686
|
-
return Object.keys(schemaRecord).length === 0;
|
|
687
|
-
}
|
|
688
|
-
function normalizeArraySchemasMissingItems(schema) {
|
|
689
|
-
if (!isRecord(schema)) return schema;
|
|
690
|
-
let changed = false;
|
|
691
|
-
const nextSchema = { ...schema };
|
|
692
|
-
if (nextSchema.type === "array" && nextSchema.items === void 0) {
|
|
693
|
-
nextSchema.items = {};
|
|
694
|
-
changed = true;
|
|
695
|
-
}
|
|
696
|
-
const normalizeSchemaValue = (key) => {
|
|
697
|
-
if (!(key in nextSchema)) return;
|
|
698
|
-
const value = nextSchema[key];
|
|
699
|
-
if (Array.isArray(value)) {
|
|
700
|
-
const normalized = value.map(normalizeArraySchemasMissingItems);
|
|
701
|
-
if (normalized.some((entry, index) => entry !== value[index])) {
|
|
702
|
-
nextSchema[key] = normalized;
|
|
703
|
-
changed = true;
|
|
704
|
-
}
|
|
705
|
-
return;
|
|
706
|
-
}
|
|
707
|
-
const normalized = normalizeArraySchemasMissingItems(value);
|
|
708
|
-
if (normalized !== value) {
|
|
709
|
-
nextSchema[key] = normalized;
|
|
710
|
-
changed = true;
|
|
711
|
-
}
|
|
712
|
-
};
|
|
713
|
-
for (const key of [
|
|
714
|
-
"items",
|
|
715
|
-
"contains",
|
|
716
|
-
"additionalProperties",
|
|
717
|
-
"propertyNames",
|
|
718
|
-
"not",
|
|
719
|
-
"if",
|
|
720
|
-
"then",
|
|
721
|
-
"else"
|
|
722
|
-
]) normalizeSchemaValue(key);
|
|
723
|
-
for (const key of [
|
|
724
|
-
"anyOf",
|
|
725
|
-
"oneOf",
|
|
726
|
-
"allOf",
|
|
727
|
-
"prefixItems"
|
|
728
|
-
]) normalizeSchemaValue(key);
|
|
729
|
-
for (const key of [
|
|
730
|
-
"properties",
|
|
731
|
-
"patternProperties",
|
|
732
|
-
"dependentSchemas",
|
|
733
|
-
"$defs",
|
|
734
|
-
"definitions"
|
|
735
|
-
]) {
|
|
736
|
-
const value = nextSchema[key];
|
|
737
|
-
if (!isRecord(value)) continue;
|
|
738
|
-
let entriesChanged = false;
|
|
739
|
-
const normalizedEntries = Object.entries(value).map(([entryKey, entryValue]) => {
|
|
740
|
-
const normalizedEntryValue = normalizeArraySchemasMissingItems(entryValue);
|
|
741
|
-
if (normalizedEntryValue !== entryValue) entriesChanged = true;
|
|
742
|
-
return [entryKey, normalizedEntryValue];
|
|
743
|
-
});
|
|
744
|
-
if (entriesChanged) {
|
|
745
|
-
nextSchema[key] = Object.fromEntries(normalizedEntries);
|
|
746
|
-
changed = true;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
return changed ? nextSchema : schema;
|
|
750
|
-
}
|
|
751
|
-
function schemaAllowsArrayType(schema) {
|
|
752
|
-
const type = schema.type;
|
|
753
|
-
return type === "array" || Array.isArray(type) && type.includes("array");
|
|
754
|
-
}
|
|
755
|
-
const ARRAY_ITEMS_SCHEMA_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
756
|
-
"additionalProperties",
|
|
757
|
-
"contains",
|
|
758
|
-
"else",
|
|
759
|
-
"if",
|
|
760
|
-
"items",
|
|
761
|
-
"not",
|
|
762
|
-
"propertyNames",
|
|
763
|
-
"then"
|
|
764
|
-
]);
|
|
765
|
-
const ARRAY_ITEMS_SCHEMA_ARRAY_KEYS = /* @__PURE__ */ new Set([
|
|
766
|
-
"allOf",
|
|
767
|
-
"anyOf",
|
|
768
|
-
"oneOf",
|
|
769
|
-
"prefixItems"
|
|
770
|
-
]);
|
|
771
|
-
const ARRAY_ITEMS_SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
|
|
772
|
-
"$defs",
|
|
773
|
-
"definitions",
|
|
774
|
-
"dependentSchemas",
|
|
775
|
-
"patternProperties",
|
|
776
|
-
"properties"
|
|
777
|
-
]);
|
|
778
|
-
function stripEmptyArrayItemsFromArraySchemas(schema) {
|
|
779
|
-
if (Array.isArray(schema)) {
|
|
780
|
-
let changed = false;
|
|
781
|
-
const entries = schema.map((entry) => {
|
|
782
|
-
const next = stripEmptyArrayItemsFromArraySchemas(entry);
|
|
783
|
-
changed ||= next !== entry;
|
|
784
|
-
return next;
|
|
785
|
-
});
|
|
786
|
-
return changed ? entries : schema;
|
|
787
|
-
}
|
|
788
|
-
if (!isRecord(schema)) return schema;
|
|
789
|
-
let changed = false;
|
|
790
|
-
const entries = Object.entries(schema).flatMap(([key, value]) => {
|
|
791
|
-
if (key === "items" && schemaAllowsArrayType(schema) && isRecord(value) && isTrulyEmptySchema(value)) {
|
|
792
|
-
changed = true;
|
|
793
|
-
return [];
|
|
794
|
-
}
|
|
795
|
-
if (ARRAY_ITEMS_SCHEMA_OBJECT_KEYS.has(key)) {
|
|
796
|
-
const next = stripEmptyArrayItemsFromArraySchemas(value);
|
|
797
|
-
changed ||= next !== value;
|
|
798
|
-
return [[key, next]];
|
|
799
|
-
}
|
|
800
|
-
if (ARRAY_ITEMS_SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
|
|
801
|
-
const next = stripEmptyArrayItemsFromArraySchemas(value);
|
|
802
|
-
changed ||= next !== value;
|
|
803
|
-
return [[key, next]];
|
|
804
|
-
}
|
|
805
|
-
if (ARRAY_ITEMS_SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
|
|
806
|
-
let mapChanged = false;
|
|
807
|
-
const next = Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => {
|
|
808
|
-
const entryNext = stripEmptyArrayItemsFromArraySchemas(entryValue);
|
|
809
|
-
mapChanged ||= entryNext !== entryValue;
|
|
810
|
-
return [entryKey, entryNext];
|
|
811
|
-
}));
|
|
812
|
-
changed ||= mapChanged;
|
|
813
|
-
return [[key, mapChanged ? next : value]];
|
|
814
|
-
}
|
|
815
|
-
return [[key, value]];
|
|
816
|
-
});
|
|
817
|
-
return changed ? Object.fromEntries(entries) : schema;
|
|
818
|
-
}
|
|
819
|
-
function copySchemaMeta(from, to) {
|
|
820
|
-
for (const key of [
|
|
821
|
-
"title",
|
|
822
|
-
"description",
|
|
823
|
-
"default"
|
|
824
|
-
]) if (key in from && from[key] !== void 0) to[key] = from[key];
|
|
825
|
-
}
|
|
826
|
-
function extendSchemaDefs(defs, schema) {
|
|
827
|
-
const defsEntry = schema.$defs && typeof schema.$defs === "object" && !Array.isArray(schema.$defs) ? schema.$defs : void 0;
|
|
828
|
-
const legacyDefsEntry = schema.definitions && typeof schema.definitions === "object" && !Array.isArray(schema.definitions) ? schema.definitions : void 0;
|
|
829
|
-
if (!defsEntry && !legacyDefsEntry) return defs;
|
|
830
|
-
const next = defs ? {
|
|
831
|
-
$defs: new Map(defs.$defs),
|
|
832
|
-
definitions: new Map(defs.definitions)
|
|
833
|
-
} : {
|
|
834
|
-
$defs: /* @__PURE__ */ new Map(),
|
|
835
|
-
definitions: /* @__PURE__ */ new Map()
|
|
836
|
-
};
|
|
837
|
-
if (defsEntry) for (const [key, value] of Object.entries(defsEntry)) next.$defs.set(key, value);
|
|
838
|
-
if (legacyDefsEntry) for (const [key, value] of Object.entries(legacyDefsEntry)) next.definitions.set(key, value);
|
|
839
|
-
return next;
|
|
840
|
-
}
|
|
841
|
-
function decodeJsonPointerSegment(segment) {
|
|
842
|
-
return segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
843
|
-
}
|
|
844
|
-
function resolveJsonPointerPath(value, segments) {
|
|
845
|
-
let current = value;
|
|
846
|
-
for (const segment of segments) {
|
|
847
|
-
if (!current || typeof current !== "object") return;
|
|
848
|
-
const key = decodeJsonPointerSegment(segment);
|
|
849
|
-
if (Array.isArray(current)) {
|
|
850
|
-
const index = /^(?:0|[1-9]\d*)$/.test(key) ? Number(key) : -1;
|
|
851
|
-
if (index < 0 || index >= current.length) return;
|
|
852
|
-
current = current[index];
|
|
853
|
-
continue;
|
|
854
|
-
}
|
|
855
|
-
const record = current;
|
|
856
|
-
if (!Object.hasOwn(record, key)) return;
|
|
857
|
-
current = record[key];
|
|
858
|
-
}
|
|
859
|
-
return current;
|
|
860
|
-
}
|
|
861
|
-
function resolveLocalJsonPointer(rootDocument, ref) {
|
|
862
|
-
if (!ref.startsWith("#/")) return;
|
|
863
|
-
return resolveJsonPointerPath(rootDocument, ref.slice(2).split("/"));
|
|
864
|
-
}
|
|
865
|
-
const SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
|
|
866
|
-
"$defs",
|
|
867
|
-
"definitions",
|
|
868
|
-
"dependentSchemas",
|
|
869
|
-
"patternProperties",
|
|
870
|
-
"properties"
|
|
871
|
-
]);
|
|
872
|
-
const SCHEMA_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
873
|
-
"additionalProperties",
|
|
874
|
-
"contains",
|
|
875
|
-
"else",
|
|
876
|
-
"if",
|
|
877
|
-
"items",
|
|
878
|
-
"not",
|
|
879
|
-
"propertyNames",
|
|
880
|
-
"then"
|
|
881
|
-
]);
|
|
882
|
-
const SCHEMA_ARRAY_KEYS = /* @__PURE__ */ new Set([
|
|
883
|
-
"allOf",
|
|
884
|
-
"anyOf",
|
|
885
|
-
"items",
|
|
886
|
-
"oneOf",
|
|
887
|
-
"prefixItems"
|
|
888
|
-
]);
|
|
889
|
-
const SCHEMA_LITERAL_KEYS = /* @__PURE__ */ new Set([
|
|
890
|
-
"const",
|
|
891
|
-
"default",
|
|
892
|
-
"enum",
|
|
893
|
-
"examples"
|
|
894
|
-
]);
|
|
895
|
-
function tryResolveLocalRef(ref, defs, rootDocument) {
|
|
896
|
-
const match = ref.match(/^#\/(\$defs|definitions)\/([^/]+)(?:\/(.*))?$/);
|
|
897
|
-
if (match && defs) {
|
|
898
|
-
const namespace = match[1] === "$defs" ? defs.$defs : defs.definitions;
|
|
899
|
-
const name = decodeJsonPointerSegment(match[2] ?? "");
|
|
900
|
-
const resolved = name ? namespace.get(name) : void 0;
|
|
901
|
-
if (resolved !== void 0) return resolveJsonPointerPath(resolved, match[3] ? match[3].split("/") : []);
|
|
902
|
-
}
|
|
903
|
-
return resolveLocalJsonPointer(rootDocument, ref);
|
|
904
|
-
}
|
|
905
|
-
function inlineLocalSchemaRefsWithDefs(schema, defs, refStack, state, rootDocument) {
|
|
906
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
907
|
-
if (Array.isArray(schema)) return schema.map((entry) => inlineLocalSchemaRefsWithDefs(entry, defs, refStack, state, rootDocument));
|
|
908
|
-
const obj = schema;
|
|
909
|
-
const nextDefs = extendSchemaDefs(defs, obj);
|
|
910
|
-
const refValue = typeof obj.$ref === "string" ? obj.$ref : void 0;
|
|
911
|
-
if (refValue) {
|
|
912
|
-
if (refStack?.has(refValue)) return {};
|
|
913
|
-
const resolved = tryResolveLocalRef(refValue, nextDefs, rootDocument);
|
|
914
|
-
if (resolved === void 0) {
|
|
915
|
-
if (refValue.startsWith("#/")) state.unresolvedLocalRefs = true;
|
|
916
|
-
return { ...obj };
|
|
917
|
-
}
|
|
918
|
-
const nextRefStack = refStack ? new Set(refStack) : /* @__PURE__ */ new Set();
|
|
919
|
-
nextRefStack.add(refValue);
|
|
920
|
-
const inlined = inlineLocalSchemaRefsWithDefs(resolved, nextDefs, nextRefStack, state, rootDocument);
|
|
921
|
-
if (!inlined || typeof inlined !== "object" || Array.isArray(inlined)) return inlined;
|
|
922
|
-
const result = { ...inlined };
|
|
923
|
-
copySchemaMeta(obj, result);
|
|
924
|
-
if (obj.nullable === true) result.nullable = true;
|
|
925
|
-
return result;
|
|
926
|
-
}
|
|
927
|
-
const result = {};
|
|
928
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
929
|
-
if (key === "$defs" || key === "definitions" || key === "components") continue;
|
|
930
|
-
if (SCHEMA_LITERAL_KEYS.has(key)) {
|
|
931
|
-
setOwnSchemaProperty(result, key, value);
|
|
932
|
-
continue;
|
|
933
|
-
}
|
|
934
|
-
if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
|
|
935
|
-
setOwnSchemaProperty(result, key, Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [entryKey, inlineLocalSchemaRefsWithDefs(entryValue, nextDefs, refStack, state, rootDocument)])));
|
|
936
|
-
continue;
|
|
937
|
-
}
|
|
938
|
-
if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) {
|
|
939
|
-
setOwnSchemaProperty(result, key, inlineLocalSchemaRefsWithDefs(value, nextDefs, refStack, state, rootDocument));
|
|
940
|
-
continue;
|
|
941
|
-
}
|
|
942
|
-
if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
|
|
943
|
-
setOwnSchemaProperty(result, key, value.map((entry) => inlineLocalSchemaRefsWithDefs(entry, nextDefs, refStack, state, rootDocument)));
|
|
944
|
-
continue;
|
|
945
|
-
}
|
|
946
|
-
setOwnSchemaProperty(result, key, value);
|
|
947
|
-
}
|
|
948
|
-
if (state.unresolvedLocalRefs) {
|
|
949
|
-
if ("$defs" in obj) result.$defs = obj.$defs;
|
|
950
|
-
if ("definitions" in obj) result.definitions = obj.definitions;
|
|
951
|
-
if ("components" in obj) result.components = obj.components;
|
|
952
|
-
}
|
|
953
|
-
return result;
|
|
954
|
-
}
|
|
955
|
-
/** Inline local $ref pointers so providers receive self-contained tool schemas. */
|
|
956
|
-
function inlineLocalToolSchemaRefs(schema) {
|
|
957
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
958
|
-
return inlineLocalSchemaRefsWithDefs(schema, extendSchemaDefs(void 0, schema), void 0, { unresolvedLocalRefs: false }, schema);
|
|
959
|
-
}
|
|
960
|
-
const OPENAPI_SCHEMA_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
|
|
961
|
-
"discriminator",
|
|
962
|
-
"externalDocs",
|
|
963
|
-
"readOnly",
|
|
964
|
-
"writeOnly",
|
|
965
|
-
"xml",
|
|
966
|
-
"example"
|
|
967
|
-
]);
|
|
968
|
-
function appendNullSchemaType(type) {
|
|
969
|
-
if (type === "null") return type;
|
|
970
|
-
if (typeof type === "string") return [type, "null"];
|
|
971
|
-
if (Array.isArray(type)) return type.includes("null") ? type : [...type, "null"];
|
|
972
|
-
return type;
|
|
973
|
-
}
|
|
974
|
-
function isNullSchemaLike(schema) {
|
|
975
|
-
if (!isRecord(schema)) return false;
|
|
976
|
-
if (schema.type === "null") return true;
|
|
977
|
-
if (Array.isArray(schema.type) && schema.type.includes("null")) return true;
|
|
978
|
-
if ("const" in schema && schema.const === null) return true;
|
|
979
|
-
return Array.isArray(schema.enum) && schema.enum.includes(null);
|
|
980
|
-
}
|
|
981
|
-
function hasOpenApiComposition(schema) {
|
|
982
|
-
return [
|
|
983
|
-
"allOf",
|
|
984
|
-
"anyOf",
|
|
985
|
-
"oneOf"
|
|
986
|
-
].some((key) => Array.isArray(schema[key]));
|
|
987
|
-
}
|
|
988
|
-
function schemaCompositionAlreadyAllowsNull(schema) {
|
|
989
|
-
return Array.isArray(schema.anyOf) && schema.anyOf.some(isNullSchemaLike) || Array.isArray(schema.oneOf) && schema.oneOf.some(isNullSchemaLike);
|
|
990
|
-
}
|
|
991
|
-
function wrapNullableComposedSchema(schema) {
|
|
992
|
-
if (schemaCompositionAlreadyAllowsNull(schema)) return schema;
|
|
993
|
-
const wrapped = { anyOf: [schema, { type: "null" }] };
|
|
994
|
-
copySchemaMeta(schema, wrapped);
|
|
995
|
-
return wrapped;
|
|
996
|
-
}
|
|
997
|
-
function normalizeOpenApiSchemaKeywords(schema) {
|
|
998
|
-
if (Array.isArray(schema)) {
|
|
999
|
-
let changed = false;
|
|
1000
|
-
const normalized = schema.map((entry) => {
|
|
1001
|
-
const next = normalizeOpenApiSchemaKeywords(entry);
|
|
1002
|
-
changed ||= next !== entry;
|
|
1003
|
-
return next;
|
|
1004
|
-
});
|
|
1005
|
-
return changed ? normalized : schema;
|
|
1006
|
-
}
|
|
1007
|
-
if (!isRecord(schema)) return schema;
|
|
1008
|
-
let changed = false;
|
|
1009
|
-
const nullable = schema.nullable === true;
|
|
1010
|
-
const normalized = {};
|
|
1011
|
-
for (const [key, value] of Object.entries(schema)) {
|
|
1012
|
-
if (key === "nullable" || OPENAPI_SCHEMA_ANNOTATION_KEYS.has(key)) {
|
|
1013
|
-
changed = true;
|
|
1014
|
-
continue;
|
|
1015
|
-
}
|
|
1016
|
-
if (SCHEMA_LITERAL_KEYS.has(key)) {
|
|
1017
|
-
normalized[key] = value;
|
|
1018
|
-
continue;
|
|
1019
|
-
}
|
|
1020
|
-
if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
|
|
1021
|
-
let mapChanged = false;
|
|
1022
|
-
const next = Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => {
|
|
1023
|
-
const nextEntry = normalizeOpenApiSchemaKeywords(entryValue);
|
|
1024
|
-
mapChanged ||= nextEntry !== entryValue;
|
|
1025
|
-
return [entryKey, nextEntry];
|
|
1026
|
-
}));
|
|
1027
|
-
normalized[key] = mapChanged ? next : value;
|
|
1028
|
-
changed ||= mapChanged;
|
|
1029
|
-
continue;
|
|
1030
|
-
}
|
|
1031
|
-
if (key === "components") {
|
|
1032
|
-
normalized[key] = value;
|
|
1033
|
-
continue;
|
|
1034
|
-
}
|
|
1035
|
-
if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) {
|
|
1036
|
-
const next = normalizeOpenApiSchemaKeywords(value);
|
|
1037
|
-
normalized[key] = next;
|
|
1038
|
-
changed ||= next !== value;
|
|
1039
|
-
continue;
|
|
1040
|
-
}
|
|
1041
|
-
if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
|
|
1042
|
-
const next = value.map(normalizeOpenApiSchemaKeywords);
|
|
1043
|
-
normalized[key] = next;
|
|
1044
|
-
changed ||= next.some((entry, index) => entry !== value[index]);
|
|
1045
|
-
continue;
|
|
1046
|
-
}
|
|
1047
|
-
normalized[key] = value;
|
|
1048
|
-
}
|
|
1049
|
-
if (nullable) {
|
|
1050
|
-
if (hasOpenApiComposition(normalized)) return wrapNullableComposedSchema(normalized);
|
|
1051
|
-
if ("type" in normalized) {
|
|
1052
|
-
const nextType = appendNullSchemaType(normalized.type);
|
|
1053
|
-
if (nextType !== normalized.type) normalized.type = nextType;
|
|
1054
|
-
}
|
|
1055
|
-
if (Array.isArray(normalized.enum) && !normalized.enum.includes(null)) normalized.enum = [...normalized.enum, null];
|
|
1056
|
-
}
|
|
1057
|
-
return changed || nullable ? normalized : schema;
|
|
1058
|
-
}
|
|
1059
|
-
function normalizeToolParameterSchemaUncached(schema, options) {
|
|
1060
|
-
const inlinedSchema = normalizeOpenApiSchemaKeywords(inlineLocalToolSchemaRefs(schema));
|
|
1061
|
-
const schemaRecord = inlinedSchema && typeof inlinedSchema === "object" ? inlinedSchema : void 0;
|
|
1062
|
-
if (!schemaRecord) return inlinedSchema;
|
|
1063
|
-
const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
|
|
1064
|
-
const normalizedModelId = normalizeLowercaseStringOrEmpty(options?.modelId);
|
|
1065
|
-
const normalizedToolSchemaProfile = normalizeLowercaseStringOrEmpty(options?.modelCompat?.toolSchemaProfile);
|
|
1066
|
-
const isGeminiProvider = normalizedProvider.includes("google") || normalizedProvider.includes("gemini") || isGeminiModelId(normalizedModelId) || normalizedToolSchemaProfile === "gemini";
|
|
1067
|
-
const isAnthropicProvider = normalizedProvider.includes("anthropic");
|
|
1068
|
-
const unsupportedToolSchemaKeywords = resolveUnsupportedToolSchemaKeywords(options?.modelCompat);
|
|
1069
|
-
const omitEmptyArrayItems = shouldOmitEmptyArrayItems(options?.modelCompat);
|
|
1070
|
-
const isLlamacppGbnfProfile = normalizedToolSchemaProfile === "llamacpp";
|
|
1071
|
-
function applyProviderCleaning(s) {
|
|
1072
|
-
const normalizedSchema = normalizeArraySchemasMissingItems(s);
|
|
1073
|
-
let arrayItemsCompatibleSchema = omitEmptyArrayItems ? stripEmptyArrayItemsFromArraySchemas(normalizedSchema) : normalizedSchema;
|
|
1074
|
-
if (isLlamacppGbnfProfile) arrayItemsCompatibleSchema = cleanSchemaForLlamacppGbnf(arrayItemsCompatibleSchema);
|
|
1075
|
-
if (isGeminiProvider && !isAnthropicProvider) {
|
|
1076
|
-
const geminiCompatibleSchema = cleanSchemaForGemini(arrayItemsCompatibleSchema);
|
|
1077
|
-
return unsupportedToolSchemaKeywords.size > 0 ? stripUnsupportedSchemaKeywords(geminiCompatibleSchema, unsupportedToolSchemaKeywords) : geminiCompatibleSchema;
|
|
1078
|
-
}
|
|
1079
|
-
if (unsupportedToolSchemaKeywords.size > 0) return stripUnsupportedSchemaKeywords(arrayItemsCompatibleSchema, unsupportedToolSchemaKeywords);
|
|
1080
|
-
return arrayItemsCompatibleSchema;
|
|
1081
|
-
}
|
|
1082
|
-
const conditionalKey = getTopLevelConditionalKey(schemaRecord);
|
|
1083
|
-
const flattenableVariantKey = getFlattenableVariantKey(schemaRecord);
|
|
1084
|
-
if (hasTopLevelObjectSchema(schemaRecord, conditionalKey)) return applyProviderCleaning(schemaRecord);
|
|
1085
|
-
if (isObjectLikeSchemaMissingType(schemaRecord, conditionalKey)) return applyProviderCleaning({
|
|
1086
|
-
...schemaRecord,
|
|
1087
|
-
type: "object",
|
|
1088
|
-
properties: isRecord(schemaRecord.properties) ? schemaRecord.properties : {}
|
|
1089
|
-
});
|
|
1090
|
-
if (isTypedObjectSchemaMissingValidProperties(schemaRecord, conditionalKey)) return applyProviderCleaning({
|
|
1091
|
-
...schemaRecord,
|
|
1092
|
-
properties: {}
|
|
1093
|
-
});
|
|
1094
|
-
if (!flattenableVariantKey) {
|
|
1095
|
-
if (isTrulyEmptySchema(schemaRecord)) return applyProviderCleaning({
|
|
1096
|
-
type: "object",
|
|
1097
|
-
properties: {}
|
|
1098
|
-
});
|
|
1099
|
-
if (conditionalKey === "allOf") return applyProviderCleaning(inlinedSchema);
|
|
1100
|
-
return applyProviderCleaning(inlinedSchema);
|
|
1101
|
-
}
|
|
1102
|
-
const variants = schemaRecord[flattenableVariantKey];
|
|
1103
|
-
const mergedProperties = {};
|
|
1104
|
-
const requiredCounts = /* @__PURE__ */ new Map();
|
|
1105
|
-
let objectVariants = 0;
|
|
1106
|
-
for (const entry of variants) {
|
|
1107
|
-
if (!entry || typeof entry !== "object") continue;
|
|
1108
|
-
const props = entry.properties;
|
|
1109
|
-
if (!props || typeof props !== "object") continue;
|
|
1110
|
-
objectVariants += 1;
|
|
1111
|
-
for (const [key, value] of Object.entries(props)) {
|
|
1112
|
-
if (!(key in mergedProperties)) {
|
|
1113
|
-
mergedProperties[key] = value;
|
|
1114
|
-
continue;
|
|
1115
|
-
}
|
|
1116
|
-
mergedProperties[key] = mergePropertySchemas(mergedProperties[key], value);
|
|
1117
|
-
}
|
|
1118
|
-
const required = Array.isArray(entry.required) ? entry.required : [];
|
|
1119
|
-
for (const key of required) {
|
|
1120
|
-
if (typeof key !== "string") continue;
|
|
1121
|
-
requiredCounts.set(key, (requiredCounts.get(key) ?? 0) + 1);
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
const baseRequired = Array.isArray(schemaRecord.required) ? schemaRecord.required.filter((key) => typeof key === "string") : void 0;
|
|
1125
|
-
const mergedRequired = baseRequired && baseRequired.length > 0 ? baseRequired : objectVariants > 0 ? Array.from(requiredCounts.entries()).filter(([, count]) => count === objectVariants).map(([key]) => key) : void 0;
|
|
1126
|
-
const nextSchema = { ...schemaRecord };
|
|
1127
|
-
return applyProviderCleaning({
|
|
1128
|
-
type: "object",
|
|
1129
|
-
...typeof nextSchema.title === "string" ? { title: nextSchema.title } : {},
|
|
1130
|
-
...typeof nextSchema.description === "string" ? { description: nextSchema.description } : {},
|
|
1131
|
-
properties: Object.keys(mergedProperties).length > 0 ? mergedProperties : schemaRecord.properties ?? {},
|
|
1132
|
-
...mergedRequired && mergedRequired.length > 0 ? { required: mergedRequired } : {},
|
|
1133
|
-
additionalProperties: "additionalProperties" in schemaRecord ? schemaRecord.additionalProperties : true
|
|
1134
|
-
});
|
|
1135
|
-
}
|
|
1136
|
-
/** Return a provider-compatible JSON schema for a model-facing tool. */
|
|
1137
|
-
function normalizeToolParameterSchema(schema, options) {
|
|
1138
|
-
if (!schema || typeof schema !== "object") return normalizeToolParameterSchemaUncached(schema, options);
|
|
1139
|
-
const cacheKey = resolveToolParameterSchemaCacheKey(options);
|
|
1140
|
-
const cached = getCachedToolParameterSchema(schema, cacheKey);
|
|
1141
|
-
if (cached) return cached;
|
|
1142
|
-
return rememberCachedToolParameterSchema(schema, cacheKey, normalizeToolParameterSchemaUncached(schema, options));
|
|
1143
|
-
}
|
|
1144
|
-
//#endregion
|
|
1145
|
-
//#region packages/ai/src/providers/openai-tool-schema-compat.ts
|
|
1146
|
-
const OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
|
|
1147
|
-
"$defs",
|
|
1148
|
-
"definitions",
|
|
1149
|
-
"dependentSchemas",
|
|
1150
|
-
"dependencies",
|
|
1151
|
-
"patternProperties",
|
|
1152
|
-
"properties"
|
|
1153
|
-
]);
|
|
1154
|
-
const OPENAI_NULLABLE_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
|
|
1155
|
-
"default",
|
|
1156
|
-
"description",
|
|
1157
|
-
"examples",
|
|
1158
|
-
"format",
|
|
1159
|
-
"title"
|
|
1160
|
-
]);
|
|
1161
|
-
const OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS = /* @__PURE__ */ new Set([
|
|
1162
|
-
"additionalItems",
|
|
1163
|
-
"additionalProperties",
|
|
1164
|
-
"allOf",
|
|
1165
|
-
"anyOf",
|
|
1166
|
-
"contains",
|
|
1167
|
-
"contentSchema",
|
|
1168
|
-
"else",
|
|
1169
|
-
"if",
|
|
1170
|
-
"items",
|
|
1171
|
-
"not",
|
|
1172
|
-
"oneOf",
|
|
1173
|
-
"prefixItems",
|
|
1174
|
-
"propertyNames",
|
|
1175
|
-
"then",
|
|
1176
|
-
"unevaluatedItems",
|
|
1177
|
-
"unevaluatedProperties"
|
|
1178
|
-
]);
|
|
1179
|
-
function normalizeOpenAIStrictCompatSchemaMap(schema) {
|
|
1180
|
-
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
|
|
1181
|
-
let changed = false;
|
|
1182
|
-
const normalized = {};
|
|
1183
|
-
for (const [key, value] of Object.entries(schema)) {
|
|
1184
|
-
const next = normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false });
|
|
1185
|
-
normalized[key] = next;
|
|
1186
|
-
changed ||= next !== value;
|
|
1187
|
-
}
|
|
1188
|
-
return changed ? normalized : schema;
|
|
1189
|
-
}
|
|
1190
|
-
function normalizeOpenAIStrictCompatSchemaRecursive(schema, options) {
|
|
1191
|
-
if (Array.isArray(schema)) {
|
|
1192
|
-
let changed = false;
|
|
1193
|
-
const normalized = schema.map((entry) => {
|
|
1194
|
-
const next = normalizeOpenAIStrictCompatSchemaRecursive(entry, { promoteEmptyObject: false });
|
|
1195
|
-
changed ||= next !== entry;
|
|
1196
|
-
return next;
|
|
1197
|
-
});
|
|
1198
|
-
return changed ? normalized : schema;
|
|
1199
|
-
}
|
|
1200
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
1201
|
-
const record = schema;
|
|
1202
|
-
let changed = false;
|
|
1203
|
-
let hadNullType = false;
|
|
1204
|
-
const normalized = {};
|
|
1205
|
-
for (const [key, value] of Object.entries(record)) {
|
|
1206
|
-
if (value === null && OPENAI_NULLABLE_ANNOTATION_KEYS.has(key)) {
|
|
1207
|
-
changed = true;
|
|
1208
|
-
continue;
|
|
1209
|
-
}
|
|
1210
|
-
if (value === null && key === "type") {
|
|
1211
|
-
hadNullType = true;
|
|
1212
|
-
changed = true;
|
|
1213
|
-
continue;
|
|
1214
|
-
}
|
|
1215
|
-
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;
|
|
1216
|
-
normalized[key] = next;
|
|
1217
|
-
changed ||= next !== value;
|
|
1218
|
-
}
|
|
1219
|
-
if (Object.keys(normalized).length === 0) {
|
|
1220
|
-
if (!options.promoteEmptyObject) return schema;
|
|
1221
|
-
return {
|
|
1222
|
-
type: "object",
|
|
1223
|
-
properties: {},
|
|
1224
|
-
required: [],
|
|
1225
|
-
additionalProperties: false
|
|
1226
|
-
};
|
|
1227
|
-
}
|
|
1228
|
-
const hasObjectShapeHints = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) || Array.isArray(normalized.required);
|
|
1229
|
-
const hasArrayShapeHints = "items" in normalized;
|
|
1230
|
-
if (!("type" in normalized) && hasObjectShapeHints !== hasArrayShapeHints) {
|
|
1231
|
-
normalized.type = hasObjectShapeHints ? "object" : "array";
|
|
1232
|
-
changed = true;
|
|
1233
|
-
} else if (hadNullType && !("type" in normalized)) normalized.type = null;
|
|
1234
|
-
if (normalized.type === "object" && !("properties" in normalized)) {
|
|
1235
|
-
normalized.properties = {};
|
|
1236
|
-
changed = true;
|
|
1237
|
-
}
|
|
1238
|
-
const hasEmptyProperties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) && Object.keys(normalized.properties).length === 0;
|
|
1239
|
-
if (normalized.type === "object" && !Array.isArray(normalized.required) && hasEmptyProperties) {
|
|
1240
|
-
normalized.required = [];
|
|
1241
|
-
changed = true;
|
|
1242
|
-
}
|
|
1243
|
-
if (normalized.type === "object" && hasEmptyProperties && !("additionalProperties" in normalized)) {
|
|
1244
|
-
normalized.additionalProperties = false;
|
|
1245
|
-
changed = true;
|
|
1246
|
-
}
|
|
1247
|
-
return changed ? normalized : schema;
|
|
1248
|
-
}
|
|
1249
|
-
/** Repairs recoverable OpenAI tool-schema shapes before canonical normalization. */
|
|
1250
|
-
function normalizeOpenAIStrictCompatSchema(schema) {
|
|
1251
|
-
return normalizeOpenAIStrictCompatSchemaRecursive(schema, { promoteEmptyObject: true });
|
|
1252
|
-
}
|
|
1253
|
-
/** Finds schema paths that violate OpenAI strict tool-schema requirements. */
|
|
1254
|
-
function findOpenAIStrictSchemaViolations(schema, path, options) {
|
|
1255
|
-
if (Array.isArray(schema)) {
|
|
1256
|
-
if (options?.requireObjectRoot) return [`${path}.type`];
|
|
1257
|
-
return schema.flatMap((item, index) => findOpenAIStrictSchemaViolations(item, `${path}[${index}]`));
|
|
1258
|
-
}
|
|
1259
|
-
if (!schema || typeof schema !== "object") return options?.requireObjectRoot ? [`${path}.type`] : [];
|
|
1260
|
-
const record = schema;
|
|
1261
|
-
const violations = [];
|
|
1262
|
-
for (const key of [
|
|
1263
|
-
"anyOf",
|
|
1264
|
-
"oneOf",
|
|
1265
|
-
"allOf"
|
|
1266
|
-
]) if (key in record) violations.push(`${path}.${key}`);
|
|
1267
|
-
if (Array.isArray(record.type)) violations.push(`${path}.type`);
|
|
1268
|
-
const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : void 0;
|
|
1269
|
-
if (record.type === "object") {
|
|
1270
|
-
if (record.additionalProperties !== false) violations.push(`${path}.additionalProperties`);
|
|
1271
|
-
const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
|
|
1272
|
-
if (!required) violations.push(`${path}.required`);
|
|
1273
|
-
else if (properties) {
|
|
1274
|
-
const requiredSet = new Set(required);
|
|
1275
|
-
for (const key of Object.keys(properties)) if (!requiredSet.has(key)) violations.push(`${path}.required.${key}`);
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
for (const key of OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS) {
|
|
1279
|
-
const schemaMap = record[key];
|
|
1280
|
-
if (!schemaMap || typeof schemaMap !== "object" || Array.isArray(schemaMap)) continue;
|
|
1281
|
-
for (const [entryKey, value] of Object.entries(schemaMap)) violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}.${entryKey}`));
|
|
1282
|
-
}
|
|
1283
|
-
for (const key of OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS) {
|
|
1284
|
-
const value = record[key];
|
|
1285
|
-
if (value && typeof value === "object") violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}`));
|
|
1286
|
-
}
|
|
1287
|
-
return violations;
|
|
1288
|
-
}
|
|
1289
|
-
//#endregion
|
|
1290
|
-
//#region packages/ai/src/providers/openai-tool-schema.ts
|
|
1291
|
-
/**
|
|
1292
|
-
* OpenAI strict JSON-schema normalization for tool inventories and request payloads.
|
|
1293
|
-
*
|
|
1294
|
-
* Caches normalized object inputs by provider compatibility so repeated inventory builds preserve identity.
|
|
1295
|
-
*/
|
|
1296
|
-
const MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
|
|
1297
|
-
const strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
|
|
1298
|
-
function resolveToolSchemaModelCompat(compat) {
|
|
1299
|
-
if (!compat) return;
|
|
1300
|
-
const unsupportedToolSchemaKeywords = Array.isArray(compat.unsupportedToolSchemaKeywords) ? compat.unsupportedToolSchemaKeywords.filter((keyword) => typeof keyword === "string") : [];
|
|
1301
|
-
if (unsupportedToolSchemaKeywords.length === 0 && compat.omitEmptyArrayItems !== true) return;
|
|
1302
|
-
return {
|
|
1303
|
-
...unsupportedToolSchemaKeywords.length > 0 ? { unsupportedToolSchemaKeywords } : {},
|
|
1304
|
-
...compat.omitEmptyArrayItems === true ? { omitEmptyArrayItems: true } : {}
|
|
1305
|
-
};
|
|
1306
|
-
}
|
|
1307
|
-
function resolveStrictOpenAISchemaCacheKey(modelCompat) {
|
|
1308
|
-
const compat = resolveToolSchemaModelCompat(modelCompat);
|
|
1309
|
-
return JSON.stringify([[...compat?.unsupportedToolSchemaKeywords ?? []].toSorted(), shouldOmitEmptyArrayItems(compat)]);
|
|
1310
|
-
}
|
|
1311
|
-
function readCachedStrictOpenAISchema(schema, key) {
|
|
1312
|
-
return strictOpenAISchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
|
|
1313
|
-
}
|
|
1314
|
-
function rememberStrictOpenAISchema(schema, key, value) {
|
|
1315
|
-
const entries = strictOpenAISchemaCache.get(schema) ?? [];
|
|
1316
|
-
strictOpenAISchemaCache.set(schema, [{
|
|
1317
|
-
key,
|
|
1318
|
-
value
|
|
1319
|
-
}, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
|
|
1320
|
-
return value;
|
|
1321
|
-
}
|
|
1322
|
-
/** Normalizes a tool parameter schema into the OpenAI strict JSON-schema subset. */
|
|
1323
|
-
function normalizeStrictOpenAIJsonSchema(schema, modelCompat) {
|
|
1324
|
-
const schemaInput = schema ?? {};
|
|
1325
|
-
if (!schemaInput || typeof schemaInput !== "object") return normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0);
|
|
1326
|
-
const cacheKey = resolveStrictOpenAISchemaCacheKey(modelCompat);
|
|
1327
|
-
const cached = readCachedStrictOpenAISchema(schemaInput, cacheKey);
|
|
1328
|
-
if (cached !== void 0) return cached;
|
|
1329
|
-
return rememberStrictOpenAISchema(schemaInput, cacheKey, normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0));
|
|
1330
|
-
}
|
|
1331
|
-
function normalizeStrictOpenAIJsonSchemaRecursive(schema, depth) {
|
|
1332
|
-
if (Array.isArray(schema)) {
|
|
1333
|
-
let changed = false;
|
|
1334
|
-
const normalized = schema.map((entry) => {
|
|
1335
|
-
const next = normalizeStrictOpenAIJsonSchemaRecursive(entry, depth);
|
|
1336
|
-
changed ||= next !== entry;
|
|
1337
|
-
return next;
|
|
1338
|
-
});
|
|
1339
|
-
return changed ? normalized : schema;
|
|
1340
|
-
}
|
|
1341
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
1342
|
-
const record = schema;
|
|
1343
|
-
let changed = false;
|
|
1344
|
-
const normalized = {};
|
|
1345
|
-
for (const [key, value] of Object.entries(record)) {
|
|
1346
|
-
const next = normalizeStrictOpenAIJsonSchemaRecursive(value, key === "properties" ? depth : depth + 1);
|
|
1347
|
-
normalized[key] = next;
|
|
1348
|
-
changed ||= next !== value;
|
|
1349
|
-
}
|
|
1350
|
-
if (normalized.type === "object") {
|
|
1351
|
-
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : void 0;
|
|
1352
|
-
if (properties && Object.keys(properties).length === 0 && !Array.isArray(normalized.required)) {
|
|
1353
|
-
normalized.required = [];
|
|
1354
|
-
changed = true;
|
|
1355
|
-
}
|
|
1356
|
-
if (depth === 0 && !("additionalProperties" in normalized)) {
|
|
1357
|
-
normalized.additionalProperties = false;
|
|
1358
|
-
changed = true;
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
return changed ? normalized : schema;
|
|
1362
|
-
}
|
|
1363
|
-
/** Normalizes tool parameters using strict OpenAI rules only when strict mode is active. */
|
|
1364
|
-
function normalizeOpenAIStrictToolParameters(schema, strict, modelCompat) {
|
|
1365
|
-
const toolSchemaCompat = resolveToolSchemaModelCompat(modelCompat);
|
|
1366
|
-
if (!strict) return normalizeToolParameterSchema(schema ?? {}, { modelCompat: toolSchemaCompat });
|
|
1367
|
-
return normalizeStrictOpenAIJsonSchema(schema, toolSchemaCompat);
|
|
1368
|
-
}
|
|
1369
|
-
/** Returns whether a schema already satisfies OpenAI strict tool-schema constraints. */
|
|
1370
|
-
function isStrictOpenAIJsonSchemaCompatible(schema) {
|
|
1371
|
-
return isStrictOpenAIJsonSchemaCompatibleRecursive(normalizeStrictOpenAIJsonSchema(schema));
|
|
1372
|
-
}
|
|
1373
|
-
/** Returns strict-schema diagnostics for an already materialized OpenAI tool projection. */
|
|
1374
|
-
function findOpenAIStrictToolProjectionDiagnostics(projection) {
|
|
1375
|
-
return [...projection.diagnostics.map((diagnostic) => ({
|
|
1376
|
-
toolIndex: diagnostic.toolIndex,
|
|
1377
|
-
...diagnostic.toolName ? { toolName: diagnostic.toolName } : {},
|
|
1378
|
-
violations: [...diagnostic.violations]
|
|
1379
|
-
})), ...projection.tools.flatMap((tool) => {
|
|
1380
|
-
const violations = findOpenAIStrictSchemaViolations(normalizeStrictOpenAIJsonSchema(tool.parameters), `${tool.name}.parameters`);
|
|
1381
|
-
return violations.length > 0 ? [{
|
|
1382
|
-
toolIndex: tool.toolIndex,
|
|
1383
|
-
toolName: tool.name,
|
|
1384
|
-
violations
|
|
1385
|
-
}] : [];
|
|
1386
|
-
})];
|
|
1387
|
-
}
|
|
1388
|
-
function isStrictOpenAIJsonSchemaCompatibleRecursive(schema) {
|
|
1389
|
-
if (Array.isArray(schema)) return schema.every((entry) => isStrictOpenAIJsonSchemaCompatibleRecursive(entry));
|
|
1390
|
-
if (!schema || typeof schema !== "object") return true;
|
|
1391
|
-
const record = schema;
|
|
1392
|
-
if ("anyOf" in record || "oneOf" in record || "allOf" in record) return false;
|
|
1393
|
-
if (Array.isArray(record.type)) return false;
|
|
1394
|
-
if (record.type === "object" && record.additionalProperties !== false) return false;
|
|
1395
|
-
if (record.type === "object") {
|
|
1396
|
-
const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : {};
|
|
1397
|
-
const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
|
|
1398
|
-
if (!required) return false;
|
|
1399
|
-
const requiredSet = new Set(required);
|
|
1400
|
-
if (Object.keys(properties).some((key) => !requiredSet.has(key))) return false;
|
|
1401
|
-
}
|
|
1402
|
-
return Object.entries(record).every(([key, entry]) => {
|
|
1403
|
-
if (key === "properties" && entry && typeof entry === "object" && !Array.isArray(entry)) return Object.values(entry).every((value) => isStrictOpenAIJsonSchemaCompatibleRecursive(value));
|
|
1404
|
-
return isStrictOpenAIJsonSchemaCompatibleRecursive(entry);
|
|
1405
|
-
});
|
|
1406
|
-
}
|
|
1407
|
-
/** Resolves strict mode for the projected tools that will be emitted in the request payload. */
|
|
1408
|
-
function resolveOpenAIProjectedToolsStrictToolFlag(projection, strict) {
|
|
1409
|
-
if (strict !== true) return strict === false ? false : void 0;
|
|
1410
|
-
return projection.tools.every((tool) => isStrictOpenAIJsonSchemaCompatible(tool.parameters));
|
|
1411
|
-
}
|
|
1412
|
-
//#endregion
|
|
1413
59
|
//#region packages/ai/src/transports/openai-responses-replay.ts
|
|
1414
60
|
/** Resolves the assistant message id that can be replayed to OpenAI Responses. */
|
|
1415
61
|
function resolveReplayableResponsesMessageId(params) {
|
|
@@ -1439,16 +85,19 @@ function isOpenAIResponsesReplayContext(value) {
|
|
|
1439
85
|
if (!isRecord(value)) return false;
|
|
1440
86
|
return typeof value.provider === "string" && typeof value.api === "string" && typeof value.model === "string" && (value.baseUrlHash === void 0 || typeof value.baseUrlHash === "string") && (value.sessionHash === void 0 || typeof value.sessionHash === "string") && (value.authProfileHash === void 0 || typeof value.authProfileHash === "string");
|
|
1441
87
|
}
|
|
88
|
+
function isOpenAIResponsesCompactionState(state) {
|
|
89
|
+
if (typeof state.baseUrlHash !== "string" || state.v !== 1) return false;
|
|
90
|
+
if (state.type === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE) return state.data === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA;
|
|
91
|
+
if (state.type === "openai-responses-retained-compaction") return typeof state.data === "string" && state.data.length > 0 && (state.id === void 0 || typeof state.id === "string") && state.replayIndex === void 0;
|
|
92
|
+
return state.type === "openai-responses-compaction" && typeof state.data === "string" && state.data.length > 0 && (state.id === void 0 || typeof state.id === "string") && (state.replayIndex === void 0 || typeof state.replayIndex === "number" && Number.isSafeInteger(state.replayIndex) && state.replayIndex >= 0);
|
|
93
|
+
}
|
|
1442
94
|
function readOpenAIResponsesCompactionReplayState(value) {
|
|
1443
|
-
|
|
1444
|
-
const state = value;
|
|
1445
|
-
if (state.type === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE) return state.data === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA ? state : void 0;
|
|
1446
|
-
return state.type === "openai-responses-compaction" && typeof state.data === "string" && state.data.length > 0 && (state.id === void 0 || typeof state.id === "string") && (state.replayIndex === void 0 || Number.isSafeInteger(state.replayIndex) && state.replayIndex >= 0) ? state : void 0;
|
|
95
|
+
return isRecord(value) && isOpenAIResponsesReplayContext(value) && isOpenAIResponsesCompactionState(value) ? value : void 0;
|
|
1447
96
|
}
|
|
1448
97
|
function openAIResponsesReplayContextMatches(state, context) {
|
|
1449
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;
|
|
1450
99
|
}
|
|
1451
|
-
function captureOpenAIResponsesCompaction(output, item,
|
|
100
|
+
function captureOpenAIResponsesCompaction(output, item, boundary, model, captureMetadata) {
|
|
1452
101
|
const metadata = captureMetadata ?? buildOpenAIResponsesReasoningReplayMetadata(model);
|
|
1453
102
|
if (!item.encrypted_content) return;
|
|
1454
103
|
if (!metadata?.baseUrlHash) {
|
|
@@ -1456,13 +105,13 @@ function captureOpenAIResponsesCompaction(output, item, replayIndex, model, capt
|
|
|
1456
105
|
return;
|
|
1457
106
|
}
|
|
1458
107
|
const currentReplay = readOpenAIResponsesCompactionReplayState(output.providerReplay);
|
|
1459
|
-
if (currentReplay?.type === "openai-responses-compaction" && (currentReplay.replayIndex ?? -1) >
|
|
108
|
+
if (typeof boundary === "number" && currentReplay?.type === "openai-responses-compaction" && (currentReplay.replayIndex ?? -1) > boundary) return;
|
|
1460
109
|
output.providerReplay = {
|
|
1461
110
|
v: 1,
|
|
1462
|
-
type: OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE,
|
|
111
|
+
type: boundary === "retained-users" ? OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE : OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE,
|
|
1463
112
|
...item.id ? { id: item.id } : {},
|
|
1464
113
|
data: item.encrypted_content,
|
|
1465
|
-
...
|
|
114
|
+
...typeof boundary === "number" ? { replayIndex: boundary } : {},
|
|
1466
115
|
provider: metadata.provider,
|
|
1467
116
|
api: metadata.api,
|
|
1468
117
|
model: metadata.model,
|
|
@@ -1513,8 +162,8 @@ function resolveNewestOpenAIResponsesCompactionReplay(messages, model, options)
|
|
|
1513
162
|
if (openAIResponsesReplayContextMatches(replay, context)) return;
|
|
1514
163
|
continue;
|
|
1515
164
|
}
|
|
1516
|
-
if (replay?.type !== "openai-responses-compaction") {
|
|
1517
|
-
if (message.providerReplay?.type === "openai-responses-compaction") return;
|
|
165
|
+
if (replay?.type !== "openai-responses-compaction" && replay?.type !== "openai-responses-retained-compaction") {
|
|
166
|
+
if (message.providerReplay?.type === "openai-responses-compaction" || message.providerReplay?.type === "openai-responses-retained-compaction") return;
|
|
1518
167
|
continue;
|
|
1519
168
|
}
|
|
1520
169
|
if (!openAIResponsesReplayContextMatches(replay, context)) return;
|
|
@@ -1525,7 +174,10 @@ function resolveNewestOpenAIResponsesCompactionReplay(messages, model, options)
|
|
|
1525
174
|
...isSafeResponsesReplayItemId(replay.id) ? { id: replay.id } : {},
|
|
1526
175
|
encrypted_content: replay.data
|
|
1527
176
|
},
|
|
1528
|
-
|
|
177
|
+
...replay.type === "openai-responses-retained-compaction" ? { mode: "retained-users" } : {
|
|
178
|
+
mode: "compacted-prefix",
|
|
179
|
+
replayIndex: replay.replayIndex ?? 0
|
|
180
|
+
}
|
|
1529
181
|
};
|
|
1530
182
|
}
|
|
1531
183
|
}
|
|
@@ -1540,11 +192,20 @@ function buildOpenAIResponsesCompactionReplayPlan(messages, model, options) {
|
|
|
1540
192
|
preserveUnframedToolResults: false
|
|
1541
193
|
};
|
|
1542
194
|
const ownerIndex = messages.indexOf(compaction.owner);
|
|
195
|
+
const collectRetainedUserMessages = (prefix) => {
|
|
196
|
+
const previous = resolveNewestOpenAIResponsesCompactionReplay(prefix, model, options);
|
|
197
|
+
if (!previous) return prefix.filter((message) => message.role === "user");
|
|
198
|
+
const previousOwnerIndex = prefix.indexOf(previous.owner);
|
|
199
|
+
const laterUsers = prefix.slice(previousOwnerIndex + 1).filter((message) => message.role === "user");
|
|
200
|
+
return previous.mode === "retained-users" ? [...collectRetainedUserMessages(prefix.slice(0, previousOwnerIndex)), ...laterUsers] : laterUsers;
|
|
201
|
+
};
|
|
202
|
+
const retainedMessages = compaction.mode === "retained-users" ? collectRetainedUserMessages(messages.slice(0, ownerIndex)) : void 0;
|
|
1543
203
|
return {
|
|
1544
204
|
messages: [{
|
|
1545
205
|
...compaction.owner,
|
|
1546
|
-
content: compaction.owner.content.slice(compaction.replayIndex)
|
|
206
|
+
content: compaction.mode === "retained-users" ? [] : compaction.owner.content.slice(compaction.replayIndex)
|
|
1547
207
|
}, ...messages.slice(ownerIndex + 1)],
|
|
208
|
+
...retainedMessages?.length ? { retainedMessages } : {},
|
|
1548
209
|
compaction: compaction.item,
|
|
1549
210
|
preserveUnframedToolResults: true
|
|
1550
211
|
};
|
|
@@ -1732,17 +393,27 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
|
|
|
1732
393
|
authProfileId: options?.authProfileId,
|
|
1733
394
|
mode: options?.replayMode
|
|
1734
395
|
});
|
|
1735
|
-
const
|
|
396
|
+
const transformMessages = (source) => providerStyle ? transformProviderMessages(source, model, normalizeToolCallId) : transformTransportMessages(source, model, normalizeToolCallId, {
|
|
1736
397
|
normalizeSameModelToolCallIds: shouldNormalizeSameModelToolCallIds,
|
|
1737
398
|
preserveUnframedToolResults: replayPlan.preserveUnframedToolResults
|
|
1738
399
|
});
|
|
400
|
+
const transformedMessages = transformMessages(replayPlan.messages);
|
|
401
|
+
const transformedRetainedMessages = replayPlan.retainedMessages ? transformMessages(replayPlan.retainedMessages) : [];
|
|
1739
402
|
if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) messages.push(buildResponsesInputMessage(model.reasoning && (providerStyle ? model.compat?.supportsDeveloperRole !== false : options?.supportsDeveloperRole !== false) ? "developer" : "system", [{
|
|
1740
403
|
type: "input_text",
|
|
1741
404
|
text: sanitizeTransportPayloadText(stripSystemPromptCacheBoundary(context.systemPrompt))
|
|
1742
405
|
}]));
|
|
1743
|
-
|
|
406
|
+
const replayMessages = replayPlan.compaction ? [
|
|
407
|
+
...transformedRetainedMessages,
|
|
408
|
+
replayPlan.compaction,
|
|
409
|
+
...transformedMessages
|
|
410
|
+
] : transformedMessages;
|
|
1744
411
|
let msgIndex = 0;
|
|
1745
|
-
for (const msg of
|
|
412
|
+
for (const msg of replayMessages) {
|
|
413
|
+
if (!("role" in msg)) {
|
|
414
|
+
messages.push(msg);
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
1746
417
|
if (msg.role === "user") if (typeof msg.content === "string") messages.push(buildResponsesInputMessage("user", [{
|
|
1747
418
|
type: "input_text",
|
|
1748
419
|
text: sanitizeTransportPayloadText(msg.content)
|
|
@@ -1766,7 +437,14 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
|
|
|
1766
437
|
const isDifferentModel = msg.model !== model.id && msg.provider === model.provider && msg.api === model.api;
|
|
1767
438
|
for (const block of msg.content) if (block.type === "thinking") {
|
|
1768
439
|
if (shouldReplayReasoningItems && block.thinkingSignature && (providerStyle || block.thinkingSignature.startsWith("{"))) {
|
|
1769
|
-
|
|
440
|
+
let reasoningItem;
|
|
441
|
+
try {
|
|
442
|
+
reasoningItem = JSON.parse(block.thinkingSignature);
|
|
443
|
+
} catch {
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
if (!isRecord(reasoningItem) || reasoningItem.type !== "reasoning") continue;
|
|
447
|
+
const replayableReasoningItem = prepareOpenAIResponsesReasoningItemForReplay(reasoningItem, replayContext, readOpenAIResponsesReasoningReplayBlockMetadata(isRecord(block) ? block : {}), providerStyle ? { preserveUnattributedEncryptedContent: true } : void 0);
|
|
1770
448
|
if (!shouldReplayResponsesItemIds) delete replayableReasoningItem.id;
|
|
1771
449
|
if (shouldReplayResponsesItemIds && !providerStyle && model.provider === "github-copilot" && !isSafeResponsesReplayItemId(replayableReasoningItem.id)) continue;
|
|
1772
450
|
output.push(replayableReasoningItem);
|
|
@@ -1849,12 +527,15 @@ function convertProviderResponsesMessages(model, context, allowedToolCallProvide
|
|
|
1849
527
|
}
|
|
1850
528
|
//#endregion
|
|
1851
529
|
//#region packages/ai/src/transports/openai-responses-replay-internal.ts
|
|
530
|
+
function isAsyncIterable(value) {
|
|
531
|
+
return (typeof value === "object" && value !== null || typeof value === "function") && Symbol.asyncIterator in value;
|
|
532
|
+
}
|
|
1852
533
|
function isInvalidEncryptedContentError(error) {
|
|
1853
534
|
if (!error || typeof error !== "object") return false;
|
|
1854
535
|
const record = error;
|
|
1855
536
|
if (record.code === "invalid_encrypted_content" || record.code === "thinking_signature_invalid") return true;
|
|
1856
|
-
const message = typeof record.message === "string" ? record.message : "";
|
|
1857
|
-
return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || record.status === 400 && message
|
|
537
|
+
const message = typeof record.message === "string" ? record.message.toLowerCase() : "";
|
|
538
|
+
return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || (record.status === 400 || record.status == null && /(?:^|[\s(])400(?:[\s):]|$)/.test(message)) && (message.includes("could not decrypt the provided encrypted_content") || message.includes("encrypted content") && (message.includes("could not be verified") || message.includes("could not be decrypted or parsed")));
|
|
1858
539
|
}
|
|
1859
540
|
function isOrphanedFunctionCallOutputError(error) {
|
|
1860
541
|
if (!error || typeof error !== "object") return false;
|
|
@@ -1916,6 +597,7 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
|
1916
597
|
commitResponsesEncryptedContentAttempt(attempt, (checkpoint) => {
|
|
1917
598
|
if (checkpoint) params.onCompactionRejected?.(checkpoint);
|
|
1918
599
|
});
|
|
600
|
+
if (!isAsyncIterable(data)) throw new Error("OpenAI Responses streaming request returned a non-stream response");
|
|
1919
601
|
return {
|
|
1920
602
|
stream: data,
|
|
1921
603
|
response,
|
|
@@ -1933,7 +615,45 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
|
1933
615
|
payloadVariant: attempt.kind
|
|
1934
616
|
});
|
|
1935
617
|
try {
|
|
1936
|
-
|
|
618
|
+
const result = await sendAttempt(attempt);
|
|
619
|
+
return {
|
|
620
|
+
...result,
|
|
621
|
+
stream: { async *[Symbol.asyncIterator]() {
|
|
622
|
+
let rejectedEvent;
|
|
623
|
+
try {
|
|
624
|
+
for await (const event of params.wrapStream?.(result) ?? result.stream) {
|
|
625
|
+
if (isRecord(event)) {
|
|
626
|
+
const failure = event.type === "response.failed" && isRecord(event.response) ? event.response.error : event.type === "error" ? event.error ?? event : void 0;
|
|
627
|
+
if (isRecord(failure) && params.canRetryStream?.() === true && isInvalidEncryptedContentError(failure)) {
|
|
628
|
+
rejectedEvent = event;
|
|
629
|
+
const message = typeof failure.message === "string" ? failure.message : "";
|
|
630
|
+
throw Object.assign(new Error(message), {
|
|
631
|
+
code: failure.code,
|
|
632
|
+
status: failure.status
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
yield event;
|
|
637
|
+
}
|
|
638
|
+
} catch (error) {
|
|
639
|
+
const nextAttempt = params.canRetryStream?.() === true && !params.requestOptions?.signal?.aborted ? await resolveNextResponsesEncryptedContentAttempt(result.attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest }) : void 0;
|
|
640
|
+
if (!nextAttempt) {
|
|
641
|
+
if (rejectedEvent !== void 0) {
|
|
642
|
+
yield rejectedEvent;
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
throw error;
|
|
646
|
+
}
|
|
647
|
+
log.warn(`[responses] retrying streamed encrypted content provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
|
|
648
|
+
yield* (await createResponsesStreamWithEncryptedContentRetry({
|
|
649
|
+
...params,
|
|
650
|
+
request: nextAttempt.request,
|
|
651
|
+
initialAttemptKind: nextAttempt.kind,
|
|
652
|
+
initialRejectedCompaction: nextAttempt.rejectedCompaction
|
|
653
|
+
})).stream;
|
|
654
|
+
}
|
|
655
|
+
} }
|
|
656
|
+
};
|
|
1937
657
|
} catch (error) {
|
|
1938
658
|
let nextAttempt = await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
|
|
1939
659
|
if (!nextAttempt && attempt.request.previous_response_id && error && typeof error === "object" && typeof error.status === "number" && error.code === "previous_response_not_found") {
|
|
@@ -2399,20 +1119,38 @@ async function* observeResponsesStream(stream, model, requestStartedAt) {
|
|
|
2399
1119
|
}
|
|
2400
1120
|
//#endregion
|
|
2401
1121
|
//#region packages/ai/src/transports/openai-responses-stream-slots-internal.ts
|
|
2402
|
-
function
|
|
2403
|
-
const
|
|
1122
|
+
function createResponsesOutputTracker() {
|
|
1123
|
+
const outputs = /* @__PURE__ */ new Map();
|
|
2404
1124
|
const identity = (item) => {
|
|
2405
1125
|
if ((item.type === "reasoning" || item.type === "message") && item.id) return `${item.type}:${item.id}`;
|
|
2406
1126
|
return item.type === "function_call" ? `function_call:${item.call_id ?? item.id ?? ""}` : void 0;
|
|
2407
1127
|
};
|
|
1128
|
+
const get = (item, outputIndex) => {
|
|
1129
|
+
const key = identity(item);
|
|
1130
|
+
const output = (outputIndex === void 0 ? void 0 : outputs.get(outputIndex)) ?? (key === void 0 ? void 0 : outputs.get(key));
|
|
1131
|
+
if (!output || outputIndex !== void 0 && output.outputIndex !== void 0 && output.outputIndex !== outputIndex) return;
|
|
1132
|
+
if (output.type !== item.type || output.callId && item.call_id && output.callId !== item.call_id) throw new Error("Responses stream changed output item identity");
|
|
1133
|
+
return output;
|
|
1134
|
+
};
|
|
2408
1135
|
return {
|
|
2409
|
-
get
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
1136
|
+
get,
|
|
1137
|
+
set(item, contentIndex, outputIndex, completed = false) {
|
|
1138
|
+
const output = get(item, outputIndex) ?? {
|
|
1139
|
+
type: item.type,
|
|
1140
|
+
contentIndex,
|
|
1141
|
+
completed
|
|
1142
|
+
};
|
|
1143
|
+
Object.assign(output, {
|
|
1144
|
+
contentIndex,
|
|
1145
|
+
completed
|
|
1146
|
+
});
|
|
1147
|
+
if (item.call_id) output.callId = item.call_id;
|
|
1148
|
+
if (outputIndex !== void 0) {
|
|
1149
|
+
output.outputIndex = outputIndex;
|
|
1150
|
+
outputs.set(outputIndex, output);
|
|
1151
|
+
}
|
|
2414
1152
|
const key = identity(item);
|
|
2415
|
-
if (key !== void 0)
|
|
1153
|
+
if (key !== void 0) outputs.set(key, output);
|
|
2416
1154
|
}
|
|
2417
1155
|
};
|
|
2418
1156
|
}
|
|
@@ -2553,62 +1291,61 @@ function resolveCompletedResponsesToolCall(item, streamed) {
|
|
|
2553
1291
|
if (streamedName && completedName && streamedName !== completedName) throw new Error(`Responses stream changed tool-call function name from ${streamedName} to ${completedName}`);
|
|
2554
1292
|
const name = completedName ?? streamedName;
|
|
2555
1293
|
if (!name) throw new Error("Responses stream completed tool call without a function name");
|
|
2556
|
-
const argumentsValue = parseJsonObjectPreservingUnsafeIntegers(streamed?.arguments ?? item.arguments);
|
|
2557
|
-
if (!argumentsValue) throw new Error("Responses stream completed tool call with invalid JSON arguments");
|
|
2558
1294
|
return {
|
|
2559
1295
|
name,
|
|
2560
|
-
arguments:
|
|
1296
|
+
arguments: parseTerminalToolCallArguments(streamed?.arguments ?? item.arguments, "Responses stream completed tool call with invalid JSON arguments")
|
|
2561
1297
|
};
|
|
2562
1298
|
}
|
|
2563
1299
|
function createResponsesTerminalController(params) {
|
|
2564
1300
|
const { output, stream, model, options } = params;
|
|
2565
1301
|
const blocks = output.content;
|
|
2566
1302
|
const backfillReasoning = (items) => {
|
|
2567
|
-
for (const item of items) {
|
|
1303
|
+
for (const [outputIndex, item] of items.entries()) {
|
|
2568
1304
|
if (item.type !== "reasoning" || !item.encrypted_content) continue;
|
|
2569
|
-
const
|
|
2570
|
-
|
|
1305
|
+
const tracked = params.outputs.get(item, outputIndex);
|
|
1306
|
+
const block = tracked && blocks[tracked.contentIndex];
|
|
1307
|
+
if (block?.type !== "thinking" || !block.thinkingSignature) continue;
|
|
2571
1308
|
const stored = JSON.parse(block.thinkingSignature);
|
|
2572
1309
|
if (!stored.encrypted_content) block.thinkingSignature = JSON.stringify({
|
|
2573
1310
|
...stored,
|
|
2574
1311
|
encrypted_content: item.encrypted_content
|
|
2575
1312
|
});
|
|
2576
|
-
if (options?.reasoningReplayMetadata) block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY]
|
|
1313
|
+
if (options?.reasoningReplayMetadata) Object.assign(block, { [OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY]: options.reasoningReplayMetadata });
|
|
2577
1314
|
}
|
|
2578
1315
|
};
|
|
2579
|
-
const appendText = (item) => {
|
|
1316
|
+
const appendText = (item, contentIndex) => {
|
|
2580
1317
|
const text = (Array.isArray(item.content) ? item.content : []).map((part) => {
|
|
2581
1318
|
const content = part;
|
|
2582
1319
|
return content.type === "output_text" || content.type === "text" ? content.text ?? "" : content.refusal ?? "";
|
|
2583
1320
|
}).join("");
|
|
2584
|
-
const
|
|
1321
|
+
const block = contentIndex === void 0 ? void 0 : blocks[contentIndex];
|
|
1322
|
+
const started = block?.type === "text" ? block : void 0;
|
|
2585
1323
|
if (!text && !started) return;
|
|
2586
1324
|
const phase = item.phase ?? void 0;
|
|
2587
|
-
if (started) {
|
|
2588
|
-
const previousText = started.
|
|
2589
|
-
started.
|
|
2590
|
-
started.
|
|
1325
|
+
if (started && contentIndex !== void 0) {
|
|
1326
|
+
const previousText = started.text;
|
|
1327
|
+
started.text = text;
|
|
1328
|
+
started.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2591
1329
|
params.setLastTextBlock({
|
|
2592
|
-
block: started
|
|
2593
|
-
index:
|
|
1330
|
+
block: started,
|
|
1331
|
+
index: contentIndex,
|
|
2594
1332
|
phase
|
|
2595
1333
|
});
|
|
2596
|
-
params.startedTextBlocksByItemId.delete(item.id);
|
|
2597
1334
|
if (text.startsWith(previousText)) {
|
|
2598
1335
|
const delta = text.slice(previousText.length);
|
|
2599
1336
|
if (delta) stream.push({
|
|
2600
1337
|
type: "text_delta",
|
|
2601
|
-
contentIndex
|
|
1338
|
+
contentIndex,
|
|
2602
1339
|
delta
|
|
2603
1340
|
});
|
|
2604
1341
|
}
|
|
2605
1342
|
stream.push({
|
|
2606
1343
|
type: "text_end",
|
|
2607
|
-
contentIndex
|
|
1344
|
+
contentIndex,
|
|
2608
1345
|
content: text,
|
|
2609
1346
|
partial: output
|
|
2610
1347
|
});
|
|
2611
|
-
return
|
|
1348
|
+
return contentIndex;
|
|
2612
1349
|
}
|
|
2613
1350
|
const previous = params.getLastTextBlock();
|
|
2614
1351
|
const collapse = resolveResponsesMessageSnapshotCollapse({
|
|
@@ -2630,15 +1367,15 @@ function createResponsesTerminalController(params) {
|
|
|
2630
1367
|
});
|
|
2631
1368
|
return previous.index;
|
|
2632
1369
|
}
|
|
2633
|
-
const
|
|
1370
|
+
const newBlock = {
|
|
2634
1371
|
type: "text",
|
|
2635
1372
|
text,
|
|
2636
1373
|
textSignature: encodeTextSignatureV1(item.id, phase)
|
|
2637
1374
|
};
|
|
2638
|
-
blocks.push(
|
|
1375
|
+
blocks.push(newBlock);
|
|
2639
1376
|
const index = blocks.length - 1;
|
|
2640
1377
|
params.setLastTextBlock({
|
|
2641
|
-
block,
|
|
1378
|
+
block: newBlock,
|
|
2642
1379
|
index,
|
|
2643
1380
|
phase
|
|
2644
1381
|
});
|
|
@@ -2680,13 +1417,14 @@ function createResponsesTerminalController(params) {
|
|
|
2680
1417
|
};
|
|
2681
1418
|
const recoverTerminalOutput = (items, includeToolCalls) => {
|
|
2682
1419
|
let hasCompletedLaterOutput = false;
|
|
2683
|
-
for (const item of items.toReversed()) {
|
|
1420
|
+
for (const [outputIndex, item] of [...items.entries()].toReversed()) {
|
|
1421
|
+
const tracked = params.outputs.get(item, outputIndex);
|
|
2684
1422
|
if (item.type === "reasoning") {
|
|
2685
|
-
hasCompletedLaterOutput ||=
|
|
1423
|
+
hasCompletedLaterOutput ||= tracked !== void 0;
|
|
2686
1424
|
continue;
|
|
2687
1425
|
}
|
|
2688
1426
|
if (item.type !== "message" && item.type !== "function_call") continue;
|
|
2689
|
-
if (
|
|
1427
|
+
if (tracked) {
|
|
2690
1428
|
hasCompletedLaterOutput = true;
|
|
2691
1429
|
continue;
|
|
2692
1430
|
}
|
|
@@ -2695,16 +1433,18 @@ function createResponsesTerminalController(params) {
|
|
|
2695
1433
|
if (item.type === "function_call") resolveCompletedResponsesToolCall(item);
|
|
2696
1434
|
}
|
|
2697
1435
|
for (const [terminalIndex, item] of items.entries()) if (item.type === "message") {
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
1436
|
+
const tracked = params.outputs.get(item, terminalIndex);
|
|
1437
|
+
if (tracked?.completed) continue;
|
|
1438
|
+
const appendedIndex = appendText(item, tracked?.contentIndex);
|
|
1439
|
+
if (appendedIndex !== void 0) params.outputs.set(item, appendedIndex, terminalIndex, true);
|
|
2701
1440
|
} else {
|
|
2702
1441
|
params.setLastTextBlock(null);
|
|
2703
1442
|
const alreadyCapturedCompaction = item.type === "compaction" && output.providerReplay?.type === "openai-responses-compaction" && output.providerReplay.id === item.id && output.providerReplay.data === item.encrypted_content;
|
|
2704
1443
|
if (item.type === "compaction" && !alreadyCapturedCompaction) {
|
|
2705
1444
|
let replayIndex = blocks.length;
|
|
2706
|
-
for (const laterItem of items.
|
|
2707
|
-
|
|
1445
|
+
for (const [laterIndex, laterItem] of items.entries()) {
|
|
1446
|
+
if (laterIndex <= terminalIndex) continue;
|
|
1447
|
+
const laterContentIndex = params.outputs.get(laterItem, laterIndex)?.contentIndex;
|
|
2708
1448
|
if (laterContentIndex !== void 0) {
|
|
2709
1449
|
replayIndex = laterContentIndex;
|
|
2710
1450
|
break;
|
|
@@ -2712,8 +1452,8 @@ function createResponsesTerminalController(params) {
|
|
|
2712
1452
|
}
|
|
2713
1453
|
captureOpenAIResponsesCompaction(output, item, replayIndex, model, options?.reasoningReplayMetadata);
|
|
2714
1454
|
} else if (includeToolCalls && item.type === "function_call") {
|
|
2715
|
-
if (params.
|
|
2716
|
-
params.
|
|
1455
|
+
if (params.outputs.get(item, terminalIndex)) continue;
|
|
1456
|
+
params.outputs.set(item, appendToolCall(item), terminalIndex, true);
|
|
2717
1457
|
}
|
|
2718
1458
|
}
|
|
2719
1459
|
};
|
|
@@ -2763,9 +1503,7 @@ function createResponsesTerminalController(params) {
|
|
|
2763
1503
|
async function processResponsesStream(openaiStream, output, stream, model, options) {
|
|
2764
1504
|
const streamingToolCalls = createResponsesToolCallTracker();
|
|
2765
1505
|
const outputSlots = createResponsesOutputSlotTracker();
|
|
2766
|
-
const
|
|
2767
|
-
const outputItemContentIndexes = createResponsesOutputContentIndex();
|
|
2768
|
-
const startedTextBlocksByItemId = /* @__PURE__ */ new Map();
|
|
1506
|
+
const outputs = createResponsesOutputTracker();
|
|
2769
1507
|
let terminalResponse;
|
|
2770
1508
|
let lastTextBlock = null;
|
|
2771
1509
|
const blocks = output.content;
|
|
@@ -2780,11 +1518,11 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2780
1518
|
type: "thinking",
|
|
2781
1519
|
item,
|
|
2782
1520
|
block,
|
|
2783
|
-
contentIndex: blocks.length
|
|
1521
|
+
contentIndex: blocks.length,
|
|
1522
|
+
outputIndex: readResponsesOutputIndex(event)
|
|
2784
1523
|
};
|
|
2785
1524
|
blocks.push(block);
|
|
2786
|
-
|
|
2787
|
-
outputItemContentIndexes.set(item, slot.contentIndex);
|
|
1525
|
+
outputs.set(item, slot.contentIndex, slot.outputIndex);
|
|
2788
1526
|
outputSlots.register(event, slot);
|
|
2789
1527
|
stream.push({
|
|
2790
1528
|
type: "thinking_start",
|
|
@@ -2806,17 +1544,13 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2806
1544
|
item: messageItem,
|
|
2807
1545
|
block,
|
|
2808
1546
|
contentIndex: block ? blocks.length : void 0,
|
|
1547
|
+
outputIndex: readResponsesOutputIndex(event),
|
|
2809
1548
|
pendingText: collapseCandidate ? "" : null,
|
|
2810
1549
|
collapseCandidate
|
|
2811
1550
|
};
|
|
2812
1551
|
if (block) {
|
|
2813
1552
|
blocks.push(block);
|
|
2814
|
-
|
|
2815
|
-
startedTextBlocksByItemId.set(messageItem.id, {
|
|
2816
|
-
block,
|
|
2817
|
-
index: slot.contentIndex ?? blocks.length - 1,
|
|
2818
|
-
phase: messageItem.phase ?? void 0
|
|
2819
|
-
});
|
|
1553
|
+
outputs.set(messageItem, slot.contentIndex ?? blocks.length - 1, slot.outputIndex);
|
|
2820
1554
|
}
|
|
2821
1555
|
outputSlots.register(event, slot);
|
|
2822
1556
|
if (slot.contentIndex !== void 0) stream.push({
|
|
@@ -2832,9 +1566,6 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2832
1566
|
if (item.type === "message") return outputSlots.resolve(event, "text");
|
|
2833
1567
|
return readResponsesOutputIndex(event) === void 0 ? void 0 : outputSlots.get(event);
|
|
2834
1568
|
};
|
|
2835
|
-
const getOrCreateOutputSlot = (event, item) => {
|
|
2836
|
-
return resolveOutputItemSlot(event, item) ?? createOutputSlot(event, item);
|
|
2837
|
-
};
|
|
2838
1569
|
const materializeDeferredTextSlot = (slot) => {
|
|
2839
1570
|
if (slot.block || slot.pendingText === null) return;
|
|
2840
1571
|
const text = slot.pendingText;
|
|
@@ -2845,12 +1576,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2845
1576
|
};
|
|
2846
1577
|
blocks.push(slot.block);
|
|
2847
1578
|
slot.contentIndex = blocks.length - 1;
|
|
2848
|
-
|
|
2849
|
-
startedTextBlocksByItemId.set(slot.item.id, {
|
|
2850
|
-
block: slot.block,
|
|
2851
|
-
index: slot.contentIndex,
|
|
2852
|
-
phase: slot.item.phase ?? void 0
|
|
2853
|
-
});
|
|
1579
|
+
outputs.set(slot.item, slot.contentIndex, slot.outputIndex);
|
|
2854
1580
|
stream.push({
|
|
2855
1581
|
type: "text_start",
|
|
2856
1582
|
contentIndex: slot.contentIndex,
|
|
@@ -2873,9 +1599,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2873
1599
|
stream,
|
|
2874
1600
|
model,
|
|
2875
1601
|
options,
|
|
2876
|
-
|
|
2877
|
-
startedTextBlocksByItemId,
|
|
2878
|
-
outputItemContentIndexes,
|
|
1602
|
+
outputs,
|
|
2879
1603
|
getLastTextBlock: () => lastTextBlock,
|
|
2880
1604
|
setLastTextBlock: (block) => {
|
|
2881
1605
|
lastTextBlock = block;
|
|
@@ -2915,6 +1639,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2915
1639
|
block: toolCallBlock,
|
|
2916
1640
|
contentIndex,
|
|
2917
1641
|
argumentStreamReliable: true,
|
|
1642
|
+
previewSchedule: createToolArgumentPreviewSchedule(),
|
|
2918
1643
|
...readResponsesToolCallItemIdentity(item)
|
|
2919
1644
|
};
|
|
2920
1645
|
streamingToolCalls.register(event, toolCallState);
|
|
@@ -2923,7 +1648,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2923
1648
|
toolCall: toolCallState
|
|
2924
1649
|
});
|
|
2925
1650
|
output.content.push(toolCallBlock);
|
|
2926
|
-
|
|
1651
|
+
outputs.set(item, contentIndex, readResponsesOutputIndex(event));
|
|
2927
1652
|
stream.push({
|
|
2928
1653
|
type: "toolcall_start",
|
|
2929
1654
|
contentIndex,
|
|
@@ -3049,7 +1774,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3049
1774
|
const toolCall = streamingToolCalls.resolve(event);
|
|
3050
1775
|
if (toolCall) {
|
|
3051
1776
|
toolCall.block.partialJson += event.delta;
|
|
3052
|
-
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
1777
|
+
if (toolCall.previewSchedule(toolCall.block.partialJson.length)) toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
3053
1778
|
stream.push({
|
|
3054
1779
|
type: "toolcall_delta",
|
|
3055
1780
|
contentIndex: toolCall.contentIndex,
|
|
@@ -3082,13 +1807,14 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3082
1807
|
if (item.type !== "message") lastTextBlock = null;
|
|
3083
1808
|
const existingOutputSlot = resolveOutputItemSlot(event, item);
|
|
3084
1809
|
materializeDeferredTextSlots(existingOutputSlot);
|
|
3085
|
-
const outputSlot = existingOutputSlot ??
|
|
1810
|
+
const outputSlot = existingOutputSlot ?? createOutputSlot(event, item);
|
|
3086
1811
|
compactionTracker.completed(item, blocks.length);
|
|
3087
1812
|
if (item.type === "reasoning" && outputSlot?.type === "thinking") {
|
|
3088
1813
|
const summaryText = item.summary?.map((s) => s.text).join("\n\n") || "";
|
|
3089
1814
|
const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
|
|
3090
1815
|
outputSlot.block.thinking = summaryText || contentText || outputSlot.block.thinking;
|
|
3091
1816
|
outputSlot.block.thinkingSignature = JSON.stringify(item);
|
|
1817
|
+
outputs.set(item, outputSlot.contentIndex, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
|
|
3092
1818
|
if (item.encrypted_content && options?.reasoningReplayMetadata) outputSlot.block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
|
|
3093
1819
|
stream.push({
|
|
3094
1820
|
type: "thinking_end",
|
|
@@ -3120,7 +1846,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3120
1846
|
partial: output
|
|
3121
1847
|
});
|
|
3122
1848
|
lastTextBlock = outputSlot.collapseCandidate;
|
|
3123
|
-
|
|
1849
|
+
outputs.set(item, outputSlot.collapseCandidate.index, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
|
|
3124
1850
|
} else {
|
|
3125
1851
|
if (!outputSlot.block) {
|
|
3126
1852
|
outputSlot.block = {
|
|
@@ -3145,7 +1871,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3145
1871
|
index: contentIndex,
|
|
3146
1872
|
phase
|
|
3147
1873
|
};
|
|
3148
|
-
|
|
1874
|
+
outputs.set(item, contentIndex, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
|
|
3149
1875
|
stream.push({
|
|
3150
1876
|
type: "text_end",
|
|
3151
1877
|
contentIndex,
|
|
@@ -3154,7 +1880,6 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3154
1880
|
});
|
|
3155
1881
|
}
|
|
3156
1882
|
outputSlots.forget(outputSlot);
|
|
3157
|
-
startedTextBlocksByItemId.delete(item.id);
|
|
3158
1883
|
} else if (item.type === "function_call") {
|
|
3159
1884
|
const streamingToolCall = streamingToolCalls.resolve(event, readResponsesToolCallItemIdentity(item));
|
|
3160
1885
|
if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
|
|
@@ -3201,7 +1926,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3201
1926
|
toolCall,
|
|
3202
1927
|
partial: output
|
|
3203
1928
|
});
|
|
3204
|
-
|
|
1929
|
+
outputs.set(item, contentIndex, readResponsesOutputIndex(event), true);
|
|
3205
1930
|
}
|
|
3206
1931
|
} else if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
3207
1932
|
if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
|
|
@@ -3212,7 +1937,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3212
1937
|
break;
|
|
3213
1938
|
} else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
|
|
3214
1939
|
else if (event.type === "response.failed") {
|
|
3215
|
-
const failure = normalizeResponsesFailedEvent(event, model);
|
|
1940
|
+
const failure = normalizeResponsesFailedEvent(isRecord(event) ? event : {}, model);
|
|
3216
1941
|
finalizeFailedResponse(event.response, failure.responseId);
|
|
3217
1942
|
throw new ResponsesStreamFailure(failure, event.response);
|
|
3218
1943
|
}
|
|
@@ -3367,26 +2092,34 @@ async function runResponsesStreamLifecycle(params) {
|
|
|
3367
2092
|
return request;
|
|
3368
2093
|
};
|
|
3369
2094
|
const requestParams = await buildRequest("checkpoint");
|
|
3370
|
-
|
|
3371
|
-
|
|
2095
|
+
const firstEvent = createFirstStreamEventAbortController(options?.signal);
|
|
2096
|
+
firstEventAbort = firstEvent;
|
|
2097
|
+
let started = false;
|
|
2098
|
+
const { stream: hookedOpenAIStream } = await createResponsesStreamWithEncryptedContentRetry({
|
|
3372
2099
|
client,
|
|
3373
2100
|
request: requestParams,
|
|
3374
2101
|
requestOptions: {
|
|
3375
2102
|
...buildResponsesRequestOptions(options),
|
|
3376
|
-
signal:
|
|
2103
|
+
signal: firstEvent.signal
|
|
3377
2104
|
},
|
|
3378
2105
|
model,
|
|
3379
2106
|
buildFullHistoryRequest: () => buildRequest("full-history"),
|
|
3380
|
-
onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint)
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
2107
|
+
onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint),
|
|
2108
|
+
canRetryStream: () => output.content.length === 0,
|
|
2109
|
+
wrapStream: ({ stream: openaiStream, response }) => withProviderResponseHook({
|
|
2110
|
+
stream: openaiStream,
|
|
2111
|
+
signal: firstEvent.signal,
|
|
2112
|
+
abort: firstEvent.abort,
|
|
2113
|
+
hook: createOpenAIProviderAcceptanceHook(options, response, model),
|
|
2114
|
+
onReady: () => {
|
|
2115
|
+
if (!started) {
|
|
2116
|
+
started = true;
|
|
2117
|
+
stream.push({
|
|
2118
|
+
type: "start",
|
|
2119
|
+
partial: output
|
|
2120
|
+
});
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
3390
2123
|
})
|
|
3391
2124
|
});
|
|
3392
2125
|
const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
|
|
@@ -3427,4 +2160,4 @@ async function runResponsesStreamLifecycle(params) {
|
|
|
3427
2160
|
}
|
|
3428
2161
|
}
|
|
3429
2162
|
//#endregion
|
|
3430
|
-
export {
|
|
2163
|
+
export { isAzureResponsesTextDeltaEvent as A, buildResponsesInputMessage as B, summarizeResponsesTools as C, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as D, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as E, commitResponsesEncryptedContentAttempt as F, suppressOpenAIResponsesCompaction as G, createOpenAIResponsesAssistantOutput as H, createResponsesStreamWithEncryptedContentRetry as I, resolveModelPayloadDebugMode as J, resolveReplayableResponsesMessageId as K, isInvalidEncryptedContentError as L, isResponsesTextContentPartType as M, isResponsesTextDeltaEventType as N, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as O, resolveResponsesMessageSnapshotCollapse as P, resolveAzureOpenAIApiVersion as R, summarizeResponsesPayload as S, readResponsesToolCallItemIdentity as T, buildOpenAIResponsesReasoningReplayMetadata as U, convertResponsesMessages$1 as V, captureOpenAIResponsesCompaction as W, resolveModelSseDebugMode as Y, safeDebugValue as _, resolveResponsesReasoningEffort as a, summarizeOpenAITransportError as b, processResponsesStream as c, resolveResponsesTerminalStopReason as d, observeResponsesStream as f, normalizeResponsesFailedEvent as g, logResponsesFailedNoDetails as h, createResponsesAssistantOutput as i, isAzureResponsesTextDeltaEventType as j, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as k, mapResponsesTerminalUsage as l, buildResponsesFailedNoDetailsObservation as m, applyResponsesServiceTierPricing as n, runResponsesStreamLifecycle as o, ResponsesStreamFailure as p, emitModelTransportDebug as q, convertResponsesMessages as r, convertResponsesToolPayload as s, applyCommonResponsesParams as t, readResponsesReasoningTokens as u, stringifyRedactedEvent as v, createResponsesToolCallTracker as w, summarizeResponsesFailedNoDetailsObservation as x, stringifyRedactedPayload as y, resolveNextResponsesEncryptedContentAttempt as z };
|