@openclaw/ai 2026.8.1-beta.3 → 2026.8.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-B8KwTtlb.mjs → anthropic-Djj7L1rx.mjs} +21 -21
- package/dist/{anthropic-compaction-replay-4Zx7-aCr.mjs → anthropic-compaction-replay-CY4tkD4V.mjs} +33 -34
- package/dist/{anthropic-payload-policy-CSx7MoKH.d.mts → anthropic-payload-policy-i_5_inWe.d.mts} +3 -2
- package/dist/{api-registry-DFxSnFqG.d.mts → api-registry-C9-wZd_W.d.mts} +2 -1
- package/dist/{azure-openai-responses-Aa4mVcYG.mjs → azure-openai-responses-Bj3czHNa.mjs} +4 -4
- package/dist/{number-coercion-H9qHik3g.mjs → base64-CEFBpSkN.mjs} +73 -1
- package/dist/diagnostics.d.mts +2 -3
- package/dist/diagnostics.mjs +1 -1
- package/dist/{env-api-keys-DrgeBuva.mjs → env-api-keys-bktO00EJ.mjs} +2 -15
- package/dist/event-stream-C988TSLe.d.mts +1 -0
- package/dist/{event-stream-D91-ohD_.d.mts → event-stream-UhnxHuqt.d.mts} +1 -2
- package/dist/event-stream.d.mts +2 -1
- package/dist/{google-yDRnipeq.mjs → google-0Ca6TYbw.mjs} +4 -4
- package/dist/{google-shared-M1dl64nz.mjs → google-shared-DVfL9COU.mjs} +14 -7
- package/dist/{google-vertex-DCJHM_a5.mjs → google-vertex-5dAMxprN.mjs} +4 -4
- package/dist/{host-DF_yxOsA.mjs → host-D51fmkH6.mjs} +4 -8
- package/dist/{host-DJq_FGcz.d.mts → host-DoPJJ1KD.d.mts} +3 -3
- package/dist/index-N3zr6__t.d.mts +105 -0
- package/dist/index.d.mts +9 -10
- package/dist/index.mjs +2 -3
- package/dist/internal/anthropic.d.mts +51 -49
- package/dist/internal/anthropic.mjs +5 -5
- package/dist/internal/openai-responses-payload-policy.d.mts +3 -3
- package/dist/internal/openai-responses-payload-policy.mjs +2 -3
- package/dist/internal/openai.d.mts +65 -63
- package/dist/internal/openai.mjs +10 -9
- package/dist/internal/retry-after.d.mts +2 -3
- package/dist/internal/runtime.d.mts +51 -40
- package/dist/internal/runtime.mjs +9 -9
- package/dist/internal/shared.d.mts +25 -25
- package/dist/internal/shared.mjs +3 -3
- package/dist/{json-parse-CDnesDM_.mjs → json-parse-BuAJEbdW.mjs} +18 -2
- package/dist/{mistral-D6hRXI7A.mjs → mistral-BCnrI-kV.mjs} +22 -25
- package/dist/{openai-chatgpt-responses-C339VIfT.mjs → openai-chatgpt-responses-CGBGWSqr.mjs} +31 -14
- package/dist/openai-completions-BaTuwID7.mjs +401 -0
- package/dist/{openai-completions-compat-B0KTleXp.d.mts → openai-completions-compat-DB7FFq7k.d.mts} +3 -3
- package/dist/openai-completions-stream-Bpns6uNc.mjs +1622 -0
- package/dist/{openai-responses-BXEcr-Tp.mjs → openai-responses-1GBcQujk.mjs} +8 -6
- package/dist/openai-responses-compaction-window-DwydGZI8.mjs +686 -0
- package/dist/{openai-responses-contracts-CD75pQ0m.d.mts → openai-responses-contracts-DgaR3t5T.d.mts} +14 -5
- package/dist/{openai-responses-payload-policy-CNGFT9zr.d.mts → openai-responses-payload-policy-rLRPsSmB.d.mts} +1 -0
- package/dist/{openai-responses-prompt-observer-internal-BG-1AsBI.mjs → openai-responses-prompt-observer-internal-_nhGTn2b.mjs} +3 -2
- package/dist/{openai-responses-shared-Cvt5MgEm.mjs → openai-responses-shared-zPmKnhF5.mjs} +315 -1468
- package/dist/openai-stop-reason-Drnn_6Qj.mjs +28 -0
- package/dist/openai-tool-schema-Dgl4H2MU.mjs +1695 -0
- package/dist/{provider-error-C8mBRJDl.mjs → provider-error-jZP5NMTZ.mjs} +3 -77
- package/dist/{provider-options-Cc5ZQ6Aa.d.mts → provider-options-HvA_slFa.d.mts} +13 -4
- package/dist/{provider-transcript-transform--gtf0ZbR.mjs → provider-transcript-transform-C01bQ5a3.mjs} +1 -1
- package/dist/provider-types.d.mts +18 -17
- package/dist/providers.d.mts +5 -6
- package/dist/providers.mjs +9 -9
- package/dist/{reasoning-tag-text-partitioner-5ygO2rZc.mjs → reasoning-tag-text-partitioner-CwzKb0bA.mjs} +1 -1
- package/dist/rolldown-runtime-BhDjJH2R.mjs +15 -0
- package/dist/{sanitize-unicode-BP7HLLZn.mjs → sanitize-unicode-DCkltN94.mjs} +1 -2
- package/dist/simple-options-DKx86yX9.mjs +155 -0
- package/dist/{anthropic-BQXQudmA.mjs → src-Bu3FiFAG.mjs} +1 -0
- package/dist/{stream-first-event-timeout-MK28puvq.mjs → stream-first-event-timeout-DcNjoFQE.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-FEr-jOoZ.mjs → tool-schema-json-projection-qvTEs5Am.mjs} +2 -2
- package/dist/{simple-options-oqsXB6U3.mjs → transport-stream-shared-CT5ycdzn.mjs} +10 -118
- package/dist/transport-stream-shared-NjwWNaRY.d.mts +138 -0
- package/dist/{transport-utils-Bv0FHkd0.mjs → transport-utils-BHx9z8Cl.mjs} +9 -9
- package/dist/transports.d.mts +127 -189
- package/dist/transports.mjs +181 -1214
- package/dist/types-DtGu2d3C.d.mts +1 -0
- package/dist/{types-DTAP49HF.d.mts → types-h38Azne1.d.mts} +38 -17
- package/dist/types.d.mts +5 -4
- package/dist/types.mjs +1 -2
- package/dist/utf16-slice-qz3nsy87.mjs +84 -0
- package/dist/{validation-DYNNrU9u.d.mts → validation-C68lP2uy.d.mts} +1 -2
- package/dist/validation.d.mts +1 -1
- package/package.json +6 -6
- package/dist/anthropic-BECQCNdF.d.mts +0 -98
- package/dist/event-stream-BVVgDSdq.d.mts +0 -1
- package/dist/headers-B_e4-1J0.mjs +0 -9
- package/dist/index-BVVgDSdq.d.mts +0 -1
- package/dist/openai-completions-D88orSJ9.mjs +0 -632
- package/dist/openai-responses-contracts-DvILoqBk.mjs +0 -247
- package/dist/openai-responses-payload-policy-BDo8CQsx.mjs +0 -208
- package/dist/openai-stop-reason-9OONKyAm.mjs +0 -579
- package/dist/openai-tool-projection-CHGLt03m.mjs +0 -426
- package/dist/provider-options-AvldWZt8.mjs +0 -21
- 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,20 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as clampThinkingLevel, r as calculateCost } from "./sanitize-unicode-
|
|
3
|
-
import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, n as getAiTransportHost } from "./host-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { n as parseStreamingJson } from "./json-parse-CDnesDM_.mjs";
|
|
1
|
+
import { c as normalizeLowercaseStringOrEmpty, d as normalizeOptionalString, o as isRecord, t as truncateUtf16Safe } from "./utf16-slice-qz3nsy87.mjs";
|
|
2
|
+
import { i as clampThinkingLevel, r as calculateCost } from "./sanitize-unicode-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-jZP5NMTZ.mjs";
|
|
5
|
+
import { r as asFiniteNumber } from "./base64-CEFBpSkN.mjs";
|
|
6
|
+
import { d as stripSystemPromptCacheBoundary, m as sortPromptCacheToolsByName } from "./simple-options-DKx86yX9.mjs";
|
|
7
|
+
import { c as transformTransportMessages } from "./tool-schema-json-projection-qvTEs5Am.mjs";
|
|
8
|
+
import { d as redactSensitiveText, u as redactIdentifier } from "./transport-utils-BHx9z8Cl.mjs";
|
|
9
|
+
import { _ as transportAbortError, g as sanitizeTransportPayloadText, h as sanitizeNonEmptyTransportPayloadText, m as parseTerminalToolCallArguments, y as withProviderResponseHook } from "./transport-stream-shared-CT5ycdzn.mjs";
|
|
10
|
+
import { r as parseStreamingJson, t as createToolArgumentPreviewSchedule } from "./json-parse-BuAJEbdW.mjs";
|
|
12
11
|
import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
|
|
13
12
|
import { t as shortHash } from "./hash-CHgqbJmD.mjs";
|
|
14
|
-
import {
|
|
15
|
-
import { a as
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
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-Dgl4H2MU.mjs";
|
|
14
|
+
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-DcNjoFQE.mjs";
|
|
15
|
+
import { t as transformProviderMessages } from "./provider-transcript-transform-C01bQ5a3.mjs";
|
|
16
|
+
import { A as supportsOpenAITemperature, D as resolveOpenAIReasoningEffortForModel, b as RESPONSE_FAILED_NO_DETAILS_MESSAGE, g as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, h as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, k as supportsOpenAIReasoningEffort, m as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, n as isOpenAIResponsesCompactionOutput, p as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, r as readOpenAIResponsesCompactionWindow } from "./openai-responses-compaction-window-DwydGZI8.mjs";
|
|
18
17
|
import { createHash, randomUUID } from "node:crypto";
|
|
19
18
|
//#region packages/ai/src/transports/model-transport-debug.ts
|
|
20
19
|
/**
|
|
@@ -57,1270 +56,6 @@ function emitModelTransportDebug(log, message) {
|
|
|
57
56
|
log.debug(message);
|
|
58
57
|
}
|
|
59
58
|
//#endregion
|
|
60
|
-
//#region packages/ai/src/providers/clean-for-gemini.ts
|
|
61
|
-
const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
62
|
-
"patternProperties",
|
|
63
|
-
"additionalProperties",
|
|
64
|
-
"$schema",
|
|
65
|
-
"$id",
|
|
66
|
-
"$ref",
|
|
67
|
-
"$defs",
|
|
68
|
-
"definitions",
|
|
69
|
-
"examples",
|
|
70
|
-
"minLength",
|
|
71
|
-
"maxLength",
|
|
72
|
-
"minimum",
|
|
73
|
-
"maximum",
|
|
74
|
-
"multipleOf",
|
|
75
|
-
"pattern",
|
|
76
|
-
"format",
|
|
77
|
-
"minItems",
|
|
78
|
-
"maxItems",
|
|
79
|
-
"uniqueItems",
|
|
80
|
-
"minProperties",
|
|
81
|
-
"maxProperties",
|
|
82
|
-
"not"
|
|
83
|
-
]);
|
|
84
|
-
const SCHEMA_META_KEYS = [
|
|
85
|
-
"description",
|
|
86
|
-
"title",
|
|
87
|
-
"default"
|
|
88
|
-
];
|
|
89
|
-
function copySchemaMeta$1(from, to) {
|
|
90
|
-
for (const key of SCHEMA_META_KEYS) if (key in from && from[key] !== void 0) to[key] = from[key];
|
|
91
|
-
}
|
|
92
|
-
function stringifyGeminiEnumValue(value) {
|
|
93
|
-
if (typeof value === "string") return value;
|
|
94
|
-
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
95
|
-
if (typeof value === "boolean") return String(value);
|
|
96
|
-
}
|
|
97
|
-
function cleanGeminiEnumValues(value) {
|
|
98
|
-
if (!Array.isArray(value)) return;
|
|
99
|
-
const values = value.flatMap((entry) => {
|
|
100
|
-
const stringified = stringifyGeminiEnumValue(entry);
|
|
101
|
-
return stringified === void 0 ? [] : [stringified];
|
|
102
|
-
});
|
|
103
|
-
const unique = [...new Set(values)];
|
|
104
|
-
return unique.length > 0 ? unique : void 0;
|
|
105
|
-
}
|
|
106
|
-
function tryFlattenLiteralAnyOf(variants) {
|
|
107
|
-
if (variants.length === 0) return null;
|
|
108
|
-
const allValues = [];
|
|
109
|
-
let commonType = null;
|
|
110
|
-
for (const variant of variants) {
|
|
111
|
-
if (!variant || typeof variant !== "object") return null;
|
|
112
|
-
const v = variant;
|
|
113
|
-
let literalValue;
|
|
114
|
-
if ("const" in v) literalValue = v.const;
|
|
115
|
-
else if (Array.isArray(v.enum) && v.enum.length === 1) literalValue = v.enum[0];
|
|
116
|
-
else return null;
|
|
117
|
-
const variantType = typeof v.type === "string" ? v.type : null;
|
|
118
|
-
if (!variantType) return null;
|
|
119
|
-
if (commonType === null) commonType = variantType;
|
|
120
|
-
else if (commonType !== variantType) return null;
|
|
121
|
-
allValues.push(literalValue);
|
|
122
|
-
}
|
|
123
|
-
if (commonType && allValues.length > 0) return {
|
|
124
|
-
type: commonType,
|
|
125
|
-
enum: allValues
|
|
126
|
-
};
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
function isNullSchema(variant) {
|
|
130
|
-
if (!variant || typeof variant !== "object" || Array.isArray(variant)) return false;
|
|
131
|
-
const record = variant;
|
|
132
|
-
if ("const" in record && record.const === null) return true;
|
|
133
|
-
if (Array.isArray(record.enum) && record.enum.length === 1) return record.enum[0] === null;
|
|
134
|
-
const typeValue = record.type;
|
|
135
|
-
if (typeValue === "null") return true;
|
|
136
|
-
if (Array.isArray(typeValue) && typeValue.length === 1 && typeValue[0] === "null") return true;
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
function stripNullVariants(variants) {
|
|
140
|
-
if (variants.length === 0) return {
|
|
141
|
-
variants,
|
|
142
|
-
stripped: false
|
|
143
|
-
};
|
|
144
|
-
const nonNull = variants.filter((variant) => !isNullSchema(variant));
|
|
145
|
-
return {
|
|
146
|
-
variants: nonNull,
|
|
147
|
-
stripped: nonNull.length !== variants.length
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
function extendSchemaDefs$1(defs, schema) {
|
|
151
|
-
const defsEntry = schema.$defs && typeof schema.$defs === "object" && !Array.isArray(schema.$defs) ? schema.$defs : void 0;
|
|
152
|
-
const legacyDefsEntry = schema.definitions && typeof schema.definitions === "object" && !Array.isArray(schema.definitions) ? schema.definitions : void 0;
|
|
153
|
-
if (!defsEntry && !legacyDefsEntry) return defs;
|
|
154
|
-
const next = defs ? new Map(defs) : /* @__PURE__ */ new Map();
|
|
155
|
-
if (defsEntry) for (const [key, value] of Object.entries(defsEntry)) next.set(key, value);
|
|
156
|
-
if (legacyDefsEntry) for (const [key, value] of Object.entries(legacyDefsEntry)) next.set(key, value);
|
|
157
|
-
return next;
|
|
158
|
-
}
|
|
159
|
-
function decodeJsonPointerSegment$1(segment) {
|
|
160
|
-
return segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
161
|
-
}
|
|
162
|
-
function tryResolveLocalRef$1(ref, defs) {
|
|
163
|
-
if (!defs) return;
|
|
164
|
-
const match = ref.match(/^#\/(?:\$defs|definitions)\/(.+)$/);
|
|
165
|
-
if (!match) return;
|
|
166
|
-
const name = decodeJsonPointerSegment$1(match[1] ?? "");
|
|
167
|
-
if (!name) return;
|
|
168
|
-
return defs.get(name);
|
|
169
|
-
}
|
|
170
|
-
function simplifyUnionVariants(params) {
|
|
171
|
-
const { obj, variants } = params;
|
|
172
|
-
const { variants: nonNullVariants, stripped } = stripNullVariants(variants);
|
|
173
|
-
const flattened = tryFlattenLiteralAnyOf(nonNullVariants);
|
|
174
|
-
if (flattened) {
|
|
175
|
-
const result = {
|
|
176
|
-
type: flattened.type,
|
|
177
|
-
enum: flattened.enum
|
|
178
|
-
};
|
|
179
|
-
copySchemaMeta$1(obj, result);
|
|
180
|
-
return {
|
|
181
|
-
kind: "simplified",
|
|
182
|
-
value: result
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
if (stripped && nonNullVariants.length === 1) {
|
|
186
|
-
const lone = nonNullVariants[0];
|
|
187
|
-
if (lone && typeof lone === "object" && !Array.isArray(lone)) {
|
|
188
|
-
const result = { ...lone };
|
|
189
|
-
copySchemaMeta$1(obj, result);
|
|
190
|
-
return {
|
|
191
|
-
kind: "simplified",
|
|
192
|
-
value: result
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
return {
|
|
196
|
-
kind: "simplified",
|
|
197
|
-
value: lone
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
kind: "variants",
|
|
202
|
-
value: stripped ? nonNullVariants : variants
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
function sanitizeRequiredFields(schema) {
|
|
206
|
-
if (!Array.isArray(schema.required)) return schema;
|
|
207
|
-
if (!schema.properties || typeof schema.properties !== "object" || Array.isArray(schema.properties)) {
|
|
208
|
-
if (schema.type === "object") delete schema.required;
|
|
209
|
-
return schema;
|
|
210
|
-
}
|
|
211
|
-
const properties = schema.properties;
|
|
212
|
-
const required = schema.required.filter((key) => typeof key === "string" && Object.hasOwn(properties, key));
|
|
213
|
-
if (required.length > 0) schema.required = required;
|
|
214
|
-
else delete schema.required;
|
|
215
|
-
return schema;
|
|
216
|
-
}
|
|
217
|
-
function cleanSchemaForGeminiWithDefs(schema, defs, refStack) {
|
|
218
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
219
|
-
if (Array.isArray(schema)) return schema.map((item) => cleanSchemaForGeminiWithDefs(item, defs, refStack));
|
|
220
|
-
const obj = schema;
|
|
221
|
-
const nextDefs = extendSchemaDefs$1(defs, obj);
|
|
222
|
-
const refValue = typeof obj.$ref === "string" ? obj.$ref : void 0;
|
|
223
|
-
if (refValue) {
|
|
224
|
-
if (refStack?.has(refValue)) return {};
|
|
225
|
-
const resolved = tryResolveLocalRef$1(refValue, nextDefs);
|
|
226
|
-
if (resolved) {
|
|
227
|
-
const nextRefStack = refStack ? new Set(refStack) : /* @__PURE__ */ new Set();
|
|
228
|
-
nextRefStack.add(refValue);
|
|
229
|
-
const cleaned = cleanSchemaForGeminiWithDefs(resolved, nextDefs, nextRefStack);
|
|
230
|
-
if (!cleaned || typeof cleaned !== "object" || Array.isArray(cleaned)) return cleaned;
|
|
231
|
-
const result = { ...cleaned };
|
|
232
|
-
copySchemaMeta$1(obj, result);
|
|
233
|
-
return result;
|
|
234
|
-
}
|
|
235
|
-
const result = {};
|
|
236
|
-
copySchemaMeta$1(obj, result);
|
|
237
|
-
return result;
|
|
238
|
-
}
|
|
239
|
-
const hasAnyOf = "anyOf" in obj && Array.isArray(obj.anyOf);
|
|
240
|
-
const hasOneOf = "oneOf" in obj && Array.isArray(obj.oneOf);
|
|
241
|
-
let cleanedAnyOf = hasAnyOf ? obj.anyOf.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack)) : void 0;
|
|
242
|
-
let cleanedOneOf = hasOneOf ? obj.oneOf.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack)) : void 0;
|
|
243
|
-
if (hasAnyOf) {
|
|
244
|
-
const simplified = simplifyUnionVariants({
|
|
245
|
-
obj,
|
|
246
|
-
variants: cleanedAnyOf ?? []
|
|
247
|
-
});
|
|
248
|
-
if (simplified.kind === "simplified") return simplified.value;
|
|
249
|
-
cleanedAnyOf = simplified.value;
|
|
250
|
-
}
|
|
251
|
-
if (hasOneOf) {
|
|
252
|
-
const simplified = simplifyUnionVariants({
|
|
253
|
-
obj,
|
|
254
|
-
variants: cleanedOneOf ?? []
|
|
255
|
-
});
|
|
256
|
-
if (simplified.kind === "simplified") return simplified.value;
|
|
257
|
-
cleanedOneOf = simplified.value;
|
|
258
|
-
}
|
|
259
|
-
const cleaned = {};
|
|
260
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
261
|
-
if (GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS.has(key)) continue;
|
|
262
|
-
if (key === "const") {
|
|
263
|
-
const enumValues = cleanGeminiEnumValues([value]);
|
|
264
|
-
if (enumValues) cleaned.enum = enumValues;
|
|
265
|
-
continue;
|
|
266
|
-
}
|
|
267
|
-
if (key === "enum") {
|
|
268
|
-
const enumValues = cleanGeminiEnumValues(value);
|
|
269
|
-
if (enumValues) cleaned.enum = enumValues;
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
if (key === "required" && Array.isArray(value) && value.length === 0) continue;
|
|
273
|
-
if (key === "type" && (hasAnyOf || hasOneOf)) continue;
|
|
274
|
-
if (key === "type" && Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
|
|
275
|
-
const types = value.filter((entry) => entry !== "null");
|
|
276
|
-
cleaned.type = types.length === 1 ? types[0] : types;
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
279
|
-
if (key === "properties") if (value && typeof value === "object" && !Array.isArray(value)) cleaned[key] = Object.fromEntries(Object.entries(value).map(([k, v]) => [k, cleanSchemaForGeminiWithDefs(v, nextDefs, refStack)]));
|
|
280
|
-
else cleaned[key] = {};
|
|
281
|
-
else if (key === "items" && value) if (Array.isArray(value)) cleaned[key] = value.map((entry) => cleanSchemaForGeminiWithDefs(entry, nextDefs, refStack));
|
|
282
|
-
else if (typeof value === "object") cleaned[key] = cleanSchemaForGeminiWithDefs(value, nextDefs, refStack);
|
|
283
|
-
else cleaned[key] = value;
|
|
284
|
-
else if (key === "anyOf" && Array.isArray(value)) cleaned[key] = cleanedAnyOf ?? value.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack));
|
|
285
|
-
else if (key === "oneOf" && Array.isArray(value)) cleaned[key] = cleanedOneOf ?? value.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack));
|
|
286
|
-
else if (key === "allOf" && Array.isArray(value)) cleaned[key] = value.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack));
|
|
287
|
-
else cleaned[key] = value;
|
|
288
|
-
}
|
|
289
|
-
if (cleaned.anyOf && Array.isArray(cleaned.anyOf)) {
|
|
290
|
-
const flattened = flattenUnionFallback(cleaned, cleaned.anyOf);
|
|
291
|
-
if (flattened) return sanitizeRequiredFields(flattened);
|
|
292
|
-
}
|
|
293
|
-
if (cleaned.oneOf && Array.isArray(cleaned.oneOf)) {
|
|
294
|
-
const flattened = flattenUnionFallback(cleaned, cleaned.oneOf);
|
|
295
|
-
if (flattened) return sanitizeRequiredFields(flattened);
|
|
296
|
-
}
|
|
297
|
-
return sanitizeRequiredFields(cleaned);
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Last-resort flattening for anyOf/oneOf arrays that could not be simplified
|
|
301
|
-
* by `simplifyUnionVariants`. Picks a representative type so the schema is
|
|
302
|
-
* accepted by Google's restricted JSON Schema validation.
|
|
303
|
-
*/
|
|
304
|
-
function flattenUnionFallback(obj, variants) {
|
|
305
|
-
const objects = variants.filter((v) => Boolean(v) && typeof v === "object");
|
|
306
|
-
if (objects.length === 0) return;
|
|
307
|
-
const types = new Set(objects.map((v) => v.type).filter(Boolean));
|
|
308
|
-
if (objects.length === 1) {
|
|
309
|
-
const merged = { ...objects[0] };
|
|
310
|
-
copySchemaMeta$1(obj, merged);
|
|
311
|
-
return merged;
|
|
312
|
-
}
|
|
313
|
-
if (types.size === 1) {
|
|
314
|
-
const merged = { type: Array.from(types)[0] };
|
|
315
|
-
copySchemaMeta$1(obj, merged);
|
|
316
|
-
return merged;
|
|
317
|
-
}
|
|
318
|
-
const first = objects[0];
|
|
319
|
-
if (first?.type) {
|
|
320
|
-
const merged = { type: first.type };
|
|
321
|
-
copySchemaMeta$1(obj, merged);
|
|
322
|
-
return merged;
|
|
323
|
-
}
|
|
324
|
-
const merged = {};
|
|
325
|
-
copySchemaMeta$1(obj, merged);
|
|
326
|
-
return merged;
|
|
327
|
-
}
|
|
328
|
-
function cleanSchemaForGemini(schema) {
|
|
329
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
330
|
-
if (Array.isArray(schema)) return schema.map(cleanSchemaForGemini);
|
|
331
|
-
return cleanSchemaForGeminiWithDefs(schema, extendSchemaDefs$1(void 0, schema), void 0);
|
|
332
|
-
}
|
|
333
|
-
//#endregion
|
|
334
|
-
//#region packages/ai/src/providers/clean-for-llamacpp-gbnf.ts
|
|
335
|
-
/** llama.cpp rejects grammar repetitions whose expanded rule count reaches 2000. */
|
|
336
|
-
const LLAMACPP_GBNF_MAX_REPETITION_THRESHOLD = 2e3;
|
|
337
|
-
const SCHEMA_MAP_KEYS$2 = /* @__PURE__ */ new Set([
|
|
338
|
-
"$defs",
|
|
339
|
-
"definitions",
|
|
340
|
-
"dependentSchemas",
|
|
341
|
-
"patternProperties",
|
|
342
|
-
"properties"
|
|
343
|
-
]);
|
|
344
|
-
const SCHEMA_CHILD_KEYS = /* @__PURE__ */ new Set([
|
|
345
|
-
"additionalItems",
|
|
346
|
-
"additionalProperties",
|
|
347
|
-
"allOf",
|
|
348
|
-
"anyOf",
|
|
349
|
-
"contains",
|
|
350
|
-
"else",
|
|
351
|
-
"if",
|
|
352
|
-
"items",
|
|
353
|
-
"not",
|
|
354
|
-
"oneOf",
|
|
355
|
-
"prefixItems",
|
|
356
|
-
"propertyNames",
|
|
357
|
-
"then",
|
|
358
|
-
"unevaluatedItems",
|
|
359
|
-
"unevaluatedProperties"
|
|
360
|
-
]);
|
|
361
|
-
function cleanSchemaNode(node) {
|
|
362
|
-
if (Array.isArray(node)) {
|
|
363
|
-
let changed = false;
|
|
364
|
-
const entries = node.map((entry) => {
|
|
365
|
-
const next = cleanSchemaNode(entry);
|
|
366
|
-
changed ||= next !== entry;
|
|
367
|
-
return next;
|
|
368
|
-
});
|
|
369
|
-
return changed ? entries : node;
|
|
370
|
-
}
|
|
371
|
-
if (!isRecord(node)) return node;
|
|
372
|
-
let changed = false;
|
|
373
|
-
const cleaned = {};
|
|
374
|
-
for (const [key, value] of Object.entries(node)) {
|
|
375
|
-
if (key === "pattern") {
|
|
376
|
-
changed = true;
|
|
377
|
-
continue;
|
|
378
|
-
}
|
|
379
|
-
if (key === "maxLength" && typeof value === "number" && value >= 2e3) {
|
|
380
|
-
changed = true;
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
let next = value;
|
|
384
|
-
if (SCHEMA_MAP_KEYS$2.has(key) && isRecord(value)) {
|
|
385
|
-
let mapChanged = false;
|
|
386
|
-
next = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => {
|
|
387
|
-
const cleanedChild = cleanSchemaNode(childValue);
|
|
388
|
-
mapChanged ||= cleanedChild !== childValue;
|
|
389
|
-
return [childKey, cleanedChild];
|
|
390
|
-
}));
|
|
391
|
-
if (!mapChanged) next = value;
|
|
392
|
-
} else if (SCHEMA_CHILD_KEYS.has(key)) next = cleanSchemaNode(value);
|
|
393
|
-
cleaned[key] = next;
|
|
394
|
-
changed ||= next !== value;
|
|
395
|
-
}
|
|
396
|
-
return changed ? cleaned : node;
|
|
397
|
-
}
|
|
398
|
-
function collectSchemaViolations(node, path, violations) {
|
|
399
|
-
if (Array.isArray(node)) {
|
|
400
|
-
node.forEach((entry, index) => collectSchemaViolations(entry, `${path}[${index}]`, violations));
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
if (!isRecord(node)) return;
|
|
404
|
-
if ("pattern" in node) violations.push(`${path}.pattern`);
|
|
405
|
-
if (typeof node.maxLength === "number" && node.maxLength >= 2e3) violations.push(`${path}.maxLength`);
|
|
406
|
-
for (const [key, value] of Object.entries(node)) if (SCHEMA_MAP_KEYS$2.has(key) && isRecord(value)) for (const [childKey, childValue] of Object.entries(value)) collectSchemaViolations(childValue, `${path}.${key}.${childKey}`, violations);
|
|
407
|
-
else if (SCHEMA_CHILD_KEYS.has(key)) collectSchemaViolations(value, `${path}.${key}`, violations);
|
|
408
|
-
}
|
|
409
|
-
/** Removes JSON Schema constraints that llama.cpp cannot compile into GBNF. */
|
|
410
|
-
function cleanSchemaForLlamacppGbnf(schema) {
|
|
411
|
-
return cleanSchemaNode(schema);
|
|
412
|
-
}
|
|
413
|
-
/** Reports schema paths that llama.cpp cannot compile into GBNF. */
|
|
414
|
-
function findLlamacppGbnfSchemaViolations(schema, path) {
|
|
415
|
-
const violations = [];
|
|
416
|
-
collectSchemaViolations(schema, path, violations);
|
|
417
|
-
return violations;
|
|
418
|
-
}
|
|
419
|
-
//#endregion
|
|
420
|
-
//#region packages/ai/src/providers/schema-keyword-strip.ts
|
|
421
|
-
const SCHEMA_MAP_KEYS$1 = /* @__PURE__ */ new Set([
|
|
422
|
-
"$defs",
|
|
423
|
-
"definitions",
|
|
424
|
-
"dependentSchemas",
|
|
425
|
-
"dependencies",
|
|
426
|
-
"patternProperties",
|
|
427
|
-
"properties"
|
|
428
|
-
]);
|
|
429
|
-
/** Containers whose value is a single nested schema. */
|
|
430
|
-
const SCHEMA_OBJECT_KEYS$1 = /* @__PURE__ */ new Set([
|
|
431
|
-
"additionalItems",
|
|
432
|
-
"additionalProperties",
|
|
433
|
-
"contains",
|
|
434
|
-
"contentSchema",
|
|
435
|
-
"else",
|
|
436
|
-
"if",
|
|
437
|
-
"items",
|
|
438
|
-
"not",
|
|
439
|
-
"propertyNames",
|
|
440
|
-
"then",
|
|
441
|
-
"unevaluatedItems",
|
|
442
|
-
"unevaluatedProperties"
|
|
443
|
-
]);
|
|
444
|
-
/** Containers whose value is a list of nested schemas. */
|
|
445
|
-
const SCHEMA_ARRAY_KEYS$1 = /* @__PURE__ */ new Set([
|
|
446
|
-
"allOf",
|
|
447
|
-
"anyOf",
|
|
448
|
-
"items",
|
|
449
|
-
"oneOf",
|
|
450
|
-
"prefixItems"
|
|
451
|
-
]);
|
|
452
|
-
/** Recursively remove schema keywords unsupported by a target provider/tool surface. */
|
|
453
|
-
function stripUnsupportedSchemaKeywords(schema, unsupportedKeywords) {
|
|
454
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
455
|
-
if (Array.isArray(schema)) return schema.map((entry) => stripUnsupportedSchemaKeywords(entry, unsupportedKeywords));
|
|
456
|
-
const obj = schema;
|
|
457
|
-
const cleaned = {};
|
|
458
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
459
|
-
if (unsupportedKeywords.has(key)) continue;
|
|
460
|
-
if (SCHEMA_MAP_KEYS$1.has(key) && value && typeof value === "object" && !Array.isArray(value)) {
|
|
461
|
-
cleaned[key] = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => [childKey, stripUnsupportedSchemaKeywords(childValue, unsupportedKeywords)]));
|
|
462
|
-
continue;
|
|
463
|
-
}
|
|
464
|
-
if (SCHEMA_ARRAY_KEYS$1.has(key) && Array.isArray(value)) {
|
|
465
|
-
cleaned[key] = value.map((entry) => stripUnsupportedSchemaKeywords(entry, unsupportedKeywords));
|
|
466
|
-
continue;
|
|
467
|
-
}
|
|
468
|
-
if (SCHEMA_OBJECT_KEYS$1.has(key) && value && typeof value === "object") {
|
|
469
|
-
cleaned[key] = stripUnsupportedSchemaKeywords(value, unsupportedKeywords);
|
|
470
|
-
continue;
|
|
471
|
-
}
|
|
472
|
-
cleaned[key] = value;
|
|
473
|
-
}
|
|
474
|
-
return cleaned;
|
|
475
|
-
}
|
|
476
|
-
//#endregion
|
|
477
|
-
//#region packages/ai/src/providers/agent-tools-parameter-schema.ts
|
|
478
|
-
/**
|
|
479
|
-
* Normalizes model-facing tool parameter schemas across provider quirks.
|
|
480
|
-
* Handles local JSON Schema refs, OpenAPI nullable syntax, top-level unions,
|
|
481
|
-
* and provider-specific unsupported keyword stripping.
|
|
482
|
-
*/
|
|
483
|
-
/** Extracts the compat record whether callers pass a model (`{ compat }`) or the compat itself. */
|
|
484
|
-
function extractToolSchemaModelCompat(modelOrCompat) {
|
|
485
|
-
if (!modelOrCompat || typeof modelOrCompat !== "object") return;
|
|
486
|
-
if ("compat" in modelOrCompat) {
|
|
487
|
-
const compat = modelOrCompat.compat;
|
|
488
|
-
return compat && typeof compat === "object" ? compat : void 0;
|
|
489
|
-
}
|
|
490
|
-
return modelOrCompat;
|
|
491
|
-
}
|
|
492
|
-
/** JSON Schema keywords this model/provider rejects in tool schemas. */
|
|
493
|
-
function resolveUnsupportedToolSchemaKeywords(modelOrCompat) {
|
|
494
|
-
const keywords = extractToolSchemaModelCompat(modelOrCompat)?.unsupportedToolSchemaKeywords ?? [];
|
|
495
|
-
return new Set(normalizeStringEntries(keywords.filter((keyword) => typeof keyword === "string")));
|
|
496
|
-
}
|
|
497
|
-
/** Whether empty `items: {}` on array schemas must be omitted for this model/provider. */
|
|
498
|
-
function shouldOmitEmptyArrayItems(modelOrCompat) {
|
|
499
|
-
return extractToolSchemaModelCompat(modelOrCompat)?.omitEmptyArrayItems === true;
|
|
500
|
-
}
|
|
501
|
-
const MAX_TOOL_PARAMETER_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
|
|
502
|
-
const toolParameterSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
503
|
-
function resolveToolParameterSchemaCacheKey(options) {
|
|
504
|
-
const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
|
|
505
|
-
const normalizedModelId = normalizeLowercaseStringOrEmpty(options?.modelId);
|
|
506
|
-
const toolSchemaProfile = normalizeLowercaseStringOrEmpty(options?.modelCompat?.toolSchemaProfile);
|
|
507
|
-
const unsupportedKeywords = Array.from(resolveUnsupportedToolSchemaKeywords(options?.modelCompat)).toSorted();
|
|
508
|
-
const omitEmptyArrayItems = shouldOmitEmptyArrayItems(options?.modelCompat);
|
|
509
|
-
return JSON.stringify([
|
|
510
|
-
normalizedProvider,
|
|
511
|
-
normalizedModelId,
|
|
512
|
-
toolSchemaProfile,
|
|
513
|
-
unsupportedKeywords,
|
|
514
|
-
omitEmptyArrayItems
|
|
515
|
-
]);
|
|
516
|
-
}
|
|
517
|
-
function getCachedToolParameterSchema(schema, key) {
|
|
518
|
-
return toolParameterSchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
|
|
519
|
-
}
|
|
520
|
-
function rememberCachedToolParameterSchema(schema, key, value) {
|
|
521
|
-
const entries = toolParameterSchemaCache.get(schema) ?? [];
|
|
522
|
-
toolParameterSchemaCache.set(schema, [{
|
|
523
|
-
key,
|
|
524
|
-
value
|
|
525
|
-
}, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_TOOL_PARAMETER_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
|
|
526
|
-
return value;
|
|
527
|
-
}
|
|
528
|
-
function isGeminiModelId(modelId) {
|
|
529
|
-
return /(?:^|[/:])gemini(?:$|[-/:.])/.test(modelId);
|
|
530
|
-
}
|
|
531
|
-
function extractEnumValues(schema) {
|
|
532
|
-
if (!schema || typeof schema !== "object") return;
|
|
533
|
-
const record = schema;
|
|
534
|
-
if (Array.isArray(record.enum)) return record.enum;
|
|
535
|
-
if ("const" in record) return [record.const];
|
|
536
|
-
const variants = Array.isArray(record.anyOf) ? record.anyOf : Array.isArray(record.oneOf) ? record.oneOf : null;
|
|
537
|
-
if (variants) {
|
|
538
|
-
const values = variants.flatMap((variant) => {
|
|
539
|
-
return extractEnumValues(variant) ?? [];
|
|
540
|
-
});
|
|
541
|
-
return values.length > 0 ? values : void 0;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
function mergePropertySchemas(existing, incoming) {
|
|
545
|
-
if (!existing) return incoming;
|
|
546
|
-
if (!incoming) return existing;
|
|
547
|
-
const existingEnum = extractEnumValues(existing);
|
|
548
|
-
const incomingEnum = extractEnumValues(incoming);
|
|
549
|
-
if (existingEnum || incomingEnum) {
|
|
550
|
-
const values = uniqueValues([...existingEnum ?? [], ...incomingEnum ?? []]);
|
|
551
|
-
const merged = {};
|
|
552
|
-
for (const source of [existing, incoming]) {
|
|
553
|
-
if (!source || typeof source !== "object") continue;
|
|
554
|
-
const record = source;
|
|
555
|
-
for (const key of [
|
|
556
|
-
"title",
|
|
557
|
-
"description",
|
|
558
|
-
"default"
|
|
559
|
-
]) if (!(key in merged) && key in record) merged[key] = record[key];
|
|
560
|
-
}
|
|
561
|
-
const types = new Set(values.map((value) => typeof value));
|
|
562
|
-
if (types.size === 1) merged.type = Array.from(types)[0];
|
|
563
|
-
merged.enum = values;
|
|
564
|
-
return merged;
|
|
565
|
-
}
|
|
566
|
-
return existing;
|
|
567
|
-
}
|
|
568
|
-
function setOwnSchemaProperty(target, key, value) {
|
|
569
|
-
Object.defineProperty(target, key, {
|
|
570
|
-
value,
|
|
571
|
-
enumerable: true,
|
|
572
|
-
configurable: true,
|
|
573
|
-
writable: true
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
function hasTopLevelArrayKeyword(schemaRecord, key) {
|
|
577
|
-
return Array.isArray(schemaRecord[key]);
|
|
578
|
-
}
|
|
579
|
-
function getFlattenableVariantKey(schemaRecord) {
|
|
580
|
-
if (hasTopLevelArrayKeyword(schemaRecord, "anyOf")) return "anyOf";
|
|
581
|
-
if (hasTopLevelArrayKeyword(schemaRecord, "oneOf")) return "oneOf";
|
|
582
|
-
return null;
|
|
583
|
-
}
|
|
584
|
-
function getTopLevelConditionalKey(schemaRecord) {
|
|
585
|
-
return getFlattenableVariantKey(schemaRecord) ?? (hasTopLevelArrayKeyword(schemaRecord, "allOf") ? "allOf" : null);
|
|
586
|
-
}
|
|
587
|
-
function hasTopLevelObjectSchema(schemaRecord, conditionalKey) {
|
|
588
|
-
return schemaRecord.type === "object" && isRecord(schemaRecord.properties) && conditionalKey === null;
|
|
589
|
-
}
|
|
590
|
-
function isObjectLikeSchemaMissingType(schemaRecord, conditionalKey) {
|
|
591
|
-
return !("type" in schemaRecord) && (isRecord(schemaRecord.properties) || Array.isArray(schemaRecord.required)) && conditionalKey === null;
|
|
592
|
-
}
|
|
593
|
-
function isTypedObjectSchemaMissingValidProperties(schemaRecord, conditionalKey) {
|
|
594
|
-
return schemaRecord.type === "object" && !isRecord(schemaRecord.properties) && conditionalKey === null;
|
|
595
|
-
}
|
|
596
|
-
function isTrulyEmptySchema(schemaRecord) {
|
|
597
|
-
return Object.keys(schemaRecord).length === 0;
|
|
598
|
-
}
|
|
599
|
-
function normalizeArraySchemasMissingItems(schema) {
|
|
600
|
-
if (!isRecord(schema)) return schema;
|
|
601
|
-
let changed = false;
|
|
602
|
-
const nextSchema = { ...schema };
|
|
603
|
-
if (nextSchema.type === "array" && nextSchema.items === void 0) {
|
|
604
|
-
nextSchema.items = {};
|
|
605
|
-
changed = true;
|
|
606
|
-
}
|
|
607
|
-
const normalizeSchemaValue = (key) => {
|
|
608
|
-
if (!(key in nextSchema)) return;
|
|
609
|
-
const value = nextSchema[key];
|
|
610
|
-
if (Array.isArray(value)) {
|
|
611
|
-
const normalized = value.map(normalizeArraySchemasMissingItems);
|
|
612
|
-
if (normalized.some((entry, index) => entry !== value[index])) {
|
|
613
|
-
nextSchema[key] = normalized;
|
|
614
|
-
changed = true;
|
|
615
|
-
}
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
const normalized = normalizeArraySchemasMissingItems(value);
|
|
619
|
-
if (normalized !== value) {
|
|
620
|
-
nextSchema[key] = normalized;
|
|
621
|
-
changed = true;
|
|
622
|
-
}
|
|
623
|
-
};
|
|
624
|
-
for (const key of [
|
|
625
|
-
"items",
|
|
626
|
-
"contains",
|
|
627
|
-
"additionalProperties",
|
|
628
|
-
"propertyNames",
|
|
629
|
-
"not",
|
|
630
|
-
"if",
|
|
631
|
-
"then",
|
|
632
|
-
"else"
|
|
633
|
-
]) normalizeSchemaValue(key);
|
|
634
|
-
for (const key of [
|
|
635
|
-
"anyOf",
|
|
636
|
-
"oneOf",
|
|
637
|
-
"allOf",
|
|
638
|
-
"prefixItems"
|
|
639
|
-
]) normalizeSchemaValue(key);
|
|
640
|
-
for (const key of [
|
|
641
|
-
"properties",
|
|
642
|
-
"patternProperties",
|
|
643
|
-
"dependentSchemas",
|
|
644
|
-
"$defs",
|
|
645
|
-
"definitions"
|
|
646
|
-
]) {
|
|
647
|
-
const value = nextSchema[key];
|
|
648
|
-
if (!isRecord(value)) continue;
|
|
649
|
-
let entriesChanged = false;
|
|
650
|
-
const normalizedEntries = Object.entries(value).map(([entryKey, entryValue]) => {
|
|
651
|
-
const normalizedEntryValue = normalizeArraySchemasMissingItems(entryValue);
|
|
652
|
-
if (normalizedEntryValue !== entryValue) entriesChanged = true;
|
|
653
|
-
return [entryKey, normalizedEntryValue];
|
|
654
|
-
});
|
|
655
|
-
if (entriesChanged) {
|
|
656
|
-
nextSchema[key] = Object.fromEntries(normalizedEntries);
|
|
657
|
-
changed = true;
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
return changed ? nextSchema : schema;
|
|
661
|
-
}
|
|
662
|
-
function schemaAllowsArrayType(schema) {
|
|
663
|
-
const type = schema.type;
|
|
664
|
-
return type === "array" || Array.isArray(type) && type.includes("array");
|
|
665
|
-
}
|
|
666
|
-
const ARRAY_ITEMS_SCHEMA_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
667
|
-
"additionalProperties",
|
|
668
|
-
"contains",
|
|
669
|
-
"else",
|
|
670
|
-
"if",
|
|
671
|
-
"items",
|
|
672
|
-
"not",
|
|
673
|
-
"propertyNames",
|
|
674
|
-
"then"
|
|
675
|
-
]);
|
|
676
|
-
const ARRAY_ITEMS_SCHEMA_ARRAY_KEYS = /* @__PURE__ */ new Set([
|
|
677
|
-
"allOf",
|
|
678
|
-
"anyOf",
|
|
679
|
-
"oneOf",
|
|
680
|
-
"prefixItems"
|
|
681
|
-
]);
|
|
682
|
-
const ARRAY_ITEMS_SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
|
|
683
|
-
"$defs",
|
|
684
|
-
"definitions",
|
|
685
|
-
"dependentSchemas",
|
|
686
|
-
"patternProperties",
|
|
687
|
-
"properties"
|
|
688
|
-
]);
|
|
689
|
-
function stripEmptyArrayItemsFromArraySchemas(schema) {
|
|
690
|
-
if (Array.isArray(schema)) {
|
|
691
|
-
let changed = false;
|
|
692
|
-
const entries = schema.map((entry) => {
|
|
693
|
-
const next = stripEmptyArrayItemsFromArraySchemas(entry);
|
|
694
|
-
changed ||= next !== entry;
|
|
695
|
-
return next;
|
|
696
|
-
});
|
|
697
|
-
return changed ? entries : schema;
|
|
698
|
-
}
|
|
699
|
-
if (!isRecord(schema)) return schema;
|
|
700
|
-
let changed = false;
|
|
701
|
-
const entries = Object.entries(schema).flatMap(([key, value]) => {
|
|
702
|
-
if (key === "items" && schemaAllowsArrayType(schema) && isRecord(value) && isTrulyEmptySchema(value)) {
|
|
703
|
-
changed = true;
|
|
704
|
-
return [];
|
|
705
|
-
}
|
|
706
|
-
if (ARRAY_ITEMS_SCHEMA_OBJECT_KEYS.has(key)) {
|
|
707
|
-
const next = stripEmptyArrayItemsFromArraySchemas(value);
|
|
708
|
-
changed ||= next !== value;
|
|
709
|
-
return [[key, next]];
|
|
710
|
-
}
|
|
711
|
-
if (ARRAY_ITEMS_SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
|
|
712
|
-
const next = stripEmptyArrayItemsFromArraySchemas(value);
|
|
713
|
-
changed ||= next !== value;
|
|
714
|
-
return [[key, next]];
|
|
715
|
-
}
|
|
716
|
-
if (ARRAY_ITEMS_SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
|
|
717
|
-
let mapChanged = false;
|
|
718
|
-
const next = Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => {
|
|
719
|
-
const entryNext = stripEmptyArrayItemsFromArraySchemas(entryValue);
|
|
720
|
-
mapChanged ||= entryNext !== entryValue;
|
|
721
|
-
return [entryKey, entryNext];
|
|
722
|
-
}));
|
|
723
|
-
changed ||= mapChanged;
|
|
724
|
-
return [[key, mapChanged ? next : value]];
|
|
725
|
-
}
|
|
726
|
-
return [[key, value]];
|
|
727
|
-
});
|
|
728
|
-
return changed ? Object.fromEntries(entries) : schema;
|
|
729
|
-
}
|
|
730
|
-
function copySchemaMeta(from, to) {
|
|
731
|
-
for (const key of [
|
|
732
|
-
"title",
|
|
733
|
-
"description",
|
|
734
|
-
"default"
|
|
735
|
-
]) if (key in from && from[key] !== void 0) to[key] = from[key];
|
|
736
|
-
}
|
|
737
|
-
function extendSchemaDefs(defs, schema) {
|
|
738
|
-
const defsEntry = schema.$defs && typeof schema.$defs === "object" && !Array.isArray(schema.$defs) ? schema.$defs : void 0;
|
|
739
|
-
const legacyDefsEntry = schema.definitions && typeof schema.definitions === "object" && !Array.isArray(schema.definitions) ? schema.definitions : void 0;
|
|
740
|
-
if (!defsEntry && !legacyDefsEntry) return defs;
|
|
741
|
-
const next = defs ? {
|
|
742
|
-
$defs: new Map(defs.$defs),
|
|
743
|
-
definitions: new Map(defs.definitions)
|
|
744
|
-
} : {
|
|
745
|
-
$defs: /* @__PURE__ */ new Map(),
|
|
746
|
-
definitions: /* @__PURE__ */ new Map()
|
|
747
|
-
};
|
|
748
|
-
if (defsEntry) for (const [key, value] of Object.entries(defsEntry)) next.$defs.set(key, value);
|
|
749
|
-
if (legacyDefsEntry) for (const [key, value] of Object.entries(legacyDefsEntry)) next.definitions.set(key, value);
|
|
750
|
-
return next;
|
|
751
|
-
}
|
|
752
|
-
function decodeJsonPointerSegment(segment) {
|
|
753
|
-
return segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
754
|
-
}
|
|
755
|
-
function resolveJsonPointerPath(value, segments) {
|
|
756
|
-
let current = value;
|
|
757
|
-
for (const segment of segments) {
|
|
758
|
-
if (!current || typeof current !== "object") return;
|
|
759
|
-
const key = decodeJsonPointerSegment(segment);
|
|
760
|
-
if (Array.isArray(current)) {
|
|
761
|
-
const index = /^(?:0|[1-9]\d*)$/.test(key) ? Number(key) : -1;
|
|
762
|
-
if (index < 0 || index >= current.length) return;
|
|
763
|
-
current = current[index];
|
|
764
|
-
continue;
|
|
765
|
-
}
|
|
766
|
-
const record = current;
|
|
767
|
-
if (!Object.hasOwn(record, key)) return;
|
|
768
|
-
current = record[key];
|
|
769
|
-
}
|
|
770
|
-
return current;
|
|
771
|
-
}
|
|
772
|
-
function resolveLocalJsonPointer(rootDocument, ref) {
|
|
773
|
-
if (!ref.startsWith("#/")) return;
|
|
774
|
-
return resolveJsonPointerPath(rootDocument, ref.slice(2).split("/"));
|
|
775
|
-
}
|
|
776
|
-
const SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
|
|
777
|
-
"$defs",
|
|
778
|
-
"definitions",
|
|
779
|
-
"dependentSchemas",
|
|
780
|
-
"patternProperties",
|
|
781
|
-
"properties"
|
|
782
|
-
]);
|
|
783
|
-
const SCHEMA_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
784
|
-
"additionalProperties",
|
|
785
|
-
"contains",
|
|
786
|
-
"else",
|
|
787
|
-
"if",
|
|
788
|
-
"items",
|
|
789
|
-
"not",
|
|
790
|
-
"propertyNames",
|
|
791
|
-
"then"
|
|
792
|
-
]);
|
|
793
|
-
const SCHEMA_ARRAY_KEYS = /* @__PURE__ */ new Set([
|
|
794
|
-
"allOf",
|
|
795
|
-
"anyOf",
|
|
796
|
-
"items",
|
|
797
|
-
"oneOf",
|
|
798
|
-
"prefixItems"
|
|
799
|
-
]);
|
|
800
|
-
const SCHEMA_LITERAL_KEYS = /* @__PURE__ */ new Set([
|
|
801
|
-
"const",
|
|
802
|
-
"default",
|
|
803
|
-
"enum",
|
|
804
|
-
"examples"
|
|
805
|
-
]);
|
|
806
|
-
function tryResolveLocalRef(ref, defs, rootDocument) {
|
|
807
|
-
const match = ref.match(/^#\/(\$defs|definitions)\/([^/]+)(?:\/(.*))?$/);
|
|
808
|
-
if (match && defs) {
|
|
809
|
-
const namespace = match[1] === "$defs" ? defs.$defs : defs.definitions;
|
|
810
|
-
const name = decodeJsonPointerSegment(match[2] ?? "");
|
|
811
|
-
const resolved = name ? namespace.get(name) : void 0;
|
|
812
|
-
if (resolved !== void 0) return resolveJsonPointerPath(resolved, match[3] ? match[3].split("/") : []);
|
|
813
|
-
}
|
|
814
|
-
return resolveLocalJsonPointer(rootDocument, ref);
|
|
815
|
-
}
|
|
816
|
-
function inlineLocalSchemaRefsWithDefs(schema, defs, refStack, state, rootDocument) {
|
|
817
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
818
|
-
if (Array.isArray(schema)) return schema.map((entry) => inlineLocalSchemaRefsWithDefs(entry, defs, refStack, state, rootDocument));
|
|
819
|
-
const obj = schema;
|
|
820
|
-
const nextDefs = extendSchemaDefs(defs, obj);
|
|
821
|
-
const refValue = typeof obj.$ref === "string" ? obj.$ref : void 0;
|
|
822
|
-
if (refValue) {
|
|
823
|
-
if (refStack?.has(refValue)) return {};
|
|
824
|
-
const resolved = tryResolveLocalRef(refValue, nextDefs, rootDocument);
|
|
825
|
-
if (resolved === void 0) {
|
|
826
|
-
if (refValue.startsWith("#/")) state.unresolvedLocalRefs = true;
|
|
827
|
-
return { ...obj };
|
|
828
|
-
}
|
|
829
|
-
const nextRefStack = refStack ? new Set(refStack) : /* @__PURE__ */ new Set();
|
|
830
|
-
nextRefStack.add(refValue);
|
|
831
|
-
const inlined = inlineLocalSchemaRefsWithDefs(resolved, nextDefs, nextRefStack, state, rootDocument);
|
|
832
|
-
if (!inlined || typeof inlined !== "object" || Array.isArray(inlined)) return inlined;
|
|
833
|
-
const result = { ...inlined };
|
|
834
|
-
copySchemaMeta(obj, result);
|
|
835
|
-
if (obj.nullable === true) result.nullable = true;
|
|
836
|
-
return result;
|
|
837
|
-
}
|
|
838
|
-
const result = {};
|
|
839
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
840
|
-
if (key === "$defs" || key === "definitions" || key === "components") continue;
|
|
841
|
-
if (SCHEMA_LITERAL_KEYS.has(key)) {
|
|
842
|
-
setOwnSchemaProperty(result, key, value);
|
|
843
|
-
continue;
|
|
844
|
-
}
|
|
845
|
-
if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
|
|
846
|
-
setOwnSchemaProperty(result, key, Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [entryKey, inlineLocalSchemaRefsWithDefs(entryValue, nextDefs, refStack, state, rootDocument)])));
|
|
847
|
-
continue;
|
|
848
|
-
}
|
|
849
|
-
if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) {
|
|
850
|
-
setOwnSchemaProperty(result, key, inlineLocalSchemaRefsWithDefs(value, nextDefs, refStack, state, rootDocument));
|
|
851
|
-
continue;
|
|
852
|
-
}
|
|
853
|
-
if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
|
|
854
|
-
setOwnSchemaProperty(result, key, value.map((entry) => inlineLocalSchemaRefsWithDefs(entry, nextDefs, refStack, state, rootDocument)));
|
|
855
|
-
continue;
|
|
856
|
-
}
|
|
857
|
-
setOwnSchemaProperty(result, key, value);
|
|
858
|
-
}
|
|
859
|
-
if (state.unresolvedLocalRefs) {
|
|
860
|
-
if ("$defs" in obj) result.$defs = obj.$defs;
|
|
861
|
-
if ("definitions" in obj) result.definitions = obj.definitions;
|
|
862
|
-
if ("components" in obj) result.components = obj.components;
|
|
863
|
-
}
|
|
864
|
-
return result;
|
|
865
|
-
}
|
|
866
|
-
/** Inline local $ref pointers so providers receive self-contained tool schemas. */
|
|
867
|
-
function inlineLocalToolSchemaRefs(schema) {
|
|
868
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
869
|
-
return inlineLocalSchemaRefsWithDefs(schema, extendSchemaDefs(void 0, schema), void 0, { unresolvedLocalRefs: false }, schema);
|
|
870
|
-
}
|
|
871
|
-
const OPENAPI_SCHEMA_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
|
|
872
|
-
"discriminator",
|
|
873
|
-
"externalDocs",
|
|
874
|
-
"readOnly",
|
|
875
|
-
"writeOnly",
|
|
876
|
-
"xml",
|
|
877
|
-
"example"
|
|
878
|
-
]);
|
|
879
|
-
function appendNullSchemaType(type) {
|
|
880
|
-
if (type === "null") return type;
|
|
881
|
-
if (typeof type === "string") return [type, "null"];
|
|
882
|
-
if (Array.isArray(type)) return type.includes("null") ? type : [...type, "null"];
|
|
883
|
-
return type;
|
|
884
|
-
}
|
|
885
|
-
function isNullSchemaLike(schema) {
|
|
886
|
-
if (!isRecord(schema)) return false;
|
|
887
|
-
if (schema.type === "null") return true;
|
|
888
|
-
if (Array.isArray(schema.type) && schema.type.includes("null")) return true;
|
|
889
|
-
if ("const" in schema && schema.const === null) return true;
|
|
890
|
-
return Array.isArray(schema.enum) && schema.enum.includes(null);
|
|
891
|
-
}
|
|
892
|
-
function hasOpenApiComposition(schema) {
|
|
893
|
-
return [
|
|
894
|
-
"allOf",
|
|
895
|
-
"anyOf",
|
|
896
|
-
"oneOf"
|
|
897
|
-
].some((key) => Array.isArray(schema[key]));
|
|
898
|
-
}
|
|
899
|
-
function schemaCompositionAlreadyAllowsNull(schema) {
|
|
900
|
-
return Array.isArray(schema.anyOf) && schema.anyOf.some(isNullSchemaLike) || Array.isArray(schema.oneOf) && schema.oneOf.some(isNullSchemaLike);
|
|
901
|
-
}
|
|
902
|
-
function wrapNullableComposedSchema(schema) {
|
|
903
|
-
if (schemaCompositionAlreadyAllowsNull(schema)) return schema;
|
|
904
|
-
const wrapped = { anyOf: [schema, { type: "null" }] };
|
|
905
|
-
copySchemaMeta(schema, wrapped);
|
|
906
|
-
return wrapped;
|
|
907
|
-
}
|
|
908
|
-
function normalizeOpenApiSchemaKeywords(schema) {
|
|
909
|
-
if (Array.isArray(schema)) {
|
|
910
|
-
let changed = false;
|
|
911
|
-
const normalized = schema.map((entry) => {
|
|
912
|
-
const next = normalizeOpenApiSchemaKeywords(entry);
|
|
913
|
-
changed ||= next !== entry;
|
|
914
|
-
return next;
|
|
915
|
-
});
|
|
916
|
-
return changed ? normalized : schema;
|
|
917
|
-
}
|
|
918
|
-
if (!isRecord(schema)) return schema;
|
|
919
|
-
let changed = false;
|
|
920
|
-
const nullable = schema.nullable === true;
|
|
921
|
-
const normalized = {};
|
|
922
|
-
for (const [key, value] of Object.entries(schema)) {
|
|
923
|
-
if (key === "nullable" || OPENAPI_SCHEMA_ANNOTATION_KEYS.has(key)) {
|
|
924
|
-
changed = true;
|
|
925
|
-
continue;
|
|
926
|
-
}
|
|
927
|
-
if (SCHEMA_LITERAL_KEYS.has(key)) {
|
|
928
|
-
normalized[key] = value;
|
|
929
|
-
continue;
|
|
930
|
-
}
|
|
931
|
-
if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
|
|
932
|
-
let mapChanged = false;
|
|
933
|
-
const next = Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => {
|
|
934
|
-
const nextEntry = normalizeOpenApiSchemaKeywords(entryValue);
|
|
935
|
-
mapChanged ||= nextEntry !== entryValue;
|
|
936
|
-
return [entryKey, nextEntry];
|
|
937
|
-
}));
|
|
938
|
-
normalized[key] = mapChanged ? next : value;
|
|
939
|
-
changed ||= mapChanged;
|
|
940
|
-
continue;
|
|
941
|
-
}
|
|
942
|
-
if (key === "components") {
|
|
943
|
-
normalized[key] = value;
|
|
944
|
-
continue;
|
|
945
|
-
}
|
|
946
|
-
if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) {
|
|
947
|
-
const next = normalizeOpenApiSchemaKeywords(value);
|
|
948
|
-
normalized[key] = next;
|
|
949
|
-
changed ||= next !== value;
|
|
950
|
-
continue;
|
|
951
|
-
}
|
|
952
|
-
if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
|
|
953
|
-
const next = value.map(normalizeOpenApiSchemaKeywords);
|
|
954
|
-
normalized[key] = next;
|
|
955
|
-
changed ||= next.some((entry, index) => entry !== value[index]);
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
normalized[key] = value;
|
|
959
|
-
}
|
|
960
|
-
if (nullable) {
|
|
961
|
-
if (hasOpenApiComposition(normalized)) return wrapNullableComposedSchema(normalized);
|
|
962
|
-
if ("type" in normalized) {
|
|
963
|
-
const nextType = appendNullSchemaType(normalized.type);
|
|
964
|
-
if (nextType !== normalized.type) normalized.type = nextType;
|
|
965
|
-
}
|
|
966
|
-
if (Array.isArray(normalized.enum) && !normalized.enum.includes(null)) normalized.enum = [...normalized.enum, null];
|
|
967
|
-
}
|
|
968
|
-
return changed || nullable ? normalized : schema;
|
|
969
|
-
}
|
|
970
|
-
function normalizeToolParameterSchemaUncached(schema, options) {
|
|
971
|
-
const inlinedSchema = normalizeOpenApiSchemaKeywords(inlineLocalToolSchemaRefs(schema));
|
|
972
|
-
const schemaRecord = inlinedSchema && typeof inlinedSchema === "object" ? inlinedSchema : void 0;
|
|
973
|
-
if (!schemaRecord) return inlinedSchema;
|
|
974
|
-
const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
|
|
975
|
-
const normalizedModelId = normalizeLowercaseStringOrEmpty(options?.modelId);
|
|
976
|
-
const normalizedToolSchemaProfile = normalizeLowercaseStringOrEmpty(options?.modelCompat?.toolSchemaProfile);
|
|
977
|
-
const isGeminiProvider = normalizedProvider.includes("google") || normalizedProvider.includes("gemini") || isGeminiModelId(normalizedModelId) || normalizedToolSchemaProfile === "gemini";
|
|
978
|
-
const isAnthropicProvider = normalizedProvider.includes("anthropic");
|
|
979
|
-
const unsupportedToolSchemaKeywords = resolveUnsupportedToolSchemaKeywords(options?.modelCompat);
|
|
980
|
-
const omitEmptyArrayItems = shouldOmitEmptyArrayItems(options?.modelCompat);
|
|
981
|
-
const isLlamacppGbnfProfile = normalizedToolSchemaProfile === "llamacpp";
|
|
982
|
-
function applyProviderCleaning(s) {
|
|
983
|
-
const normalizedSchema = normalizeArraySchemasMissingItems(s);
|
|
984
|
-
let arrayItemsCompatibleSchema = omitEmptyArrayItems ? stripEmptyArrayItemsFromArraySchemas(normalizedSchema) : normalizedSchema;
|
|
985
|
-
if (isLlamacppGbnfProfile) arrayItemsCompatibleSchema = cleanSchemaForLlamacppGbnf(arrayItemsCompatibleSchema);
|
|
986
|
-
if (isGeminiProvider && !isAnthropicProvider) {
|
|
987
|
-
const geminiCompatibleSchema = cleanSchemaForGemini(arrayItemsCompatibleSchema);
|
|
988
|
-
return unsupportedToolSchemaKeywords.size > 0 ? stripUnsupportedSchemaKeywords(geminiCompatibleSchema, unsupportedToolSchemaKeywords) : geminiCompatibleSchema;
|
|
989
|
-
}
|
|
990
|
-
if (unsupportedToolSchemaKeywords.size > 0) return stripUnsupportedSchemaKeywords(arrayItemsCompatibleSchema, unsupportedToolSchemaKeywords);
|
|
991
|
-
return arrayItemsCompatibleSchema;
|
|
992
|
-
}
|
|
993
|
-
const conditionalKey = getTopLevelConditionalKey(schemaRecord);
|
|
994
|
-
const flattenableVariantKey = getFlattenableVariantKey(schemaRecord);
|
|
995
|
-
if (hasTopLevelObjectSchema(schemaRecord, conditionalKey)) return applyProviderCleaning(schemaRecord);
|
|
996
|
-
if (isObjectLikeSchemaMissingType(schemaRecord, conditionalKey)) return applyProviderCleaning({
|
|
997
|
-
...schemaRecord,
|
|
998
|
-
type: "object",
|
|
999
|
-
properties: isRecord(schemaRecord.properties) ? schemaRecord.properties : {}
|
|
1000
|
-
});
|
|
1001
|
-
if (isTypedObjectSchemaMissingValidProperties(schemaRecord, conditionalKey)) return applyProviderCleaning({
|
|
1002
|
-
...schemaRecord,
|
|
1003
|
-
properties: {}
|
|
1004
|
-
});
|
|
1005
|
-
if (!flattenableVariantKey) {
|
|
1006
|
-
if (isTrulyEmptySchema(schemaRecord)) return applyProviderCleaning({
|
|
1007
|
-
type: "object",
|
|
1008
|
-
properties: {}
|
|
1009
|
-
});
|
|
1010
|
-
if (conditionalKey === "allOf") return applyProviderCleaning(inlinedSchema);
|
|
1011
|
-
return applyProviderCleaning(inlinedSchema);
|
|
1012
|
-
}
|
|
1013
|
-
const variants = schemaRecord[flattenableVariantKey];
|
|
1014
|
-
const mergedProperties = {};
|
|
1015
|
-
const requiredCounts = /* @__PURE__ */ new Map();
|
|
1016
|
-
let objectVariants = 0;
|
|
1017
|
-
for (const entry of variants) {
|
|
1018
|
-
if (!entry || typeof entry !== "object") continue;
|
|
1019
|
-
const props = entry.properties;
|
|
1020
|
-
if (!props || typeof props !== "object") continue;
|
|
1021
|
-
objectVariants += 1;
|
|
1022
|
-
for (const [key, value] of Object.entries(props)) {
|
|
1023
|
-
if (!(key in mergedProperties)) {
|
|
1024
|
-
mergedProperties[key] = value;
|
|
1025
|
-
continue;
|
|
1026
|
-
}
|
|
1027
|
-
mergedProperties[key] = mergePropertySchemas(mergedProperties[key], value);
|
|
1028
|
-
}
|
|
1029
|
-
const required = Array.isArray(entry.required) ? entry.required : [];
|
|
1030
|
-
for (const key of required) {
|
|
1031
|
-
if (typeof key !== "string") continue;
|
|
1032
|
-
requiredCounts.set(key, (requiredCounts.get(key) ?? 0) + 1);
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
const baseRequired = Array.isArray(schemaRecord.required) ? schemaRecord.required.filter((key) => typeof key === "string") : void 0;
|
|
1036
|
-
const mergedRequired = baseRequired && baseRequired.length > 0 ? baseRequired : objectVariants > 0 ? Array.from(requiredCounts.entries()).filter(([, count]) => count === objectVariants).map(([key]) => key) : void 0;
|
|
1037
|
-
const nextSchema = { ...schemaRecord };
|
|
1038
|
-
return applyProviderCleaning({
|
|
1039
|
-
type: "object",
|
|
1040
|
-
...typeof nextSchema.title === "string" ? { title: nextSchema.title } : {},
|
|
1041
|
-
...typeof nextSchema.description === "string" ? { description: nextSchema.description } : {},
|
|
1042
|
-
properties: Object.keys(mergedProperties).length > 0 ? mergedProperties : schemaRecord.properties ?? {},
|
|
1043
|
-
...mergedRequired && mergedRequired.length > 0 ? { required: mergedRequired } : {},
|
|
1044
|
-
additionalProperties: "additionalProperties" in schemaRecord ? schemaRecord.additionalProperties : true
|
|
1045
|
-
});
|
|
1046
|
-
}
|
|
1047
|
-
/** Return a provider-compatible JSON schema for a model-facing tool. */
|
|
1048
|
-
function normalizeToolParameterSchema(schema, options) {
|
|
1049
|
-
if (!schema || typeof schema !== "object") return normalizeToolParameterSchemaUncached(schema, options);
|
|
1050
|
-
const cacheKey = resolveToolParameterSchemaCacheKey(options);
|
|
1051
|
-
const cached = getCachedToolParameterSchema(schema, cacheKey);
|
|
1052
|
-
if (cached) return cached;
|
|
1053
|
-
return rememberCachedToolParameterSchema(schema, cacheKey, normalizeToolParameterSchemaUncached(schema, options));
|
|
1054
|
-
}
|
|
1055
|
-
//#endregion
|
|
1056
|
-
//#region packages/ai/src/providers/openai-tool-schema-compat.ts
|
|
1057
|
-
const OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
|
|
1058
|
-
"$defs",
|
|
1059
|
-
"definitions",
|
|
1060
|
-
"dependentSchemas",
|
|
1061
|
-
"dependencies",
|
|
1062
|
-
"patternProperties",
|
|
1063
|
-
"properties"
|
|
1064
|
-
]);
|
|
1065
|
-
const OPENAI_NULLABLE_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
|
|
1066
|
-
"default",
|
|
1067
|
-
"description",
|
|
1068
|
-
"examples",
|
|
1069
|
-
"format",
|
|
1070
|
-
"title"
|
|
1071
|
-
]);
|
|
1072
|
-
const OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS = /* @__PURE__ */ new Set([
|
|
1073
|
-
"additionalItems",
|
|
1074
|
-
"additionalProperties",
|
|
1075
|
-
"allOf",
|
|
1076
|
-
"anyOf",
|
|
1077
|
-
"contains",
|
|
1078
|
-
"contentSchema",
|
|
1079
|
-
"else",
|
|
1080
|
-
"if",
|
|
1081
|
-
"items",
|
|
1082
|
-
"not",
|
|
1083
|
-
"oneOf",
|
|
1084
|
-
"prefixItems",
|
|
1085
|
-
"propertyNames",
|
|
1086
|
-
"then",
|
|
1087
|
-
"unevaluatedItems",
|
|
1088
|
-
"unevaluatedProperties"
|
|
1089
|
-
]);
|
|
1090
|
-
function normalizeOpenAIStrictCompatSchemaMap(schema) {
|
|
1091
|
-
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
|
|
1092
|
-
let changed = false;
|
|
1093
|
-
const normalized = {};
|
|
1094
|
-
for (const [key, value] of Object.entries(schema)) {
|
|
1095
|
-
const next = normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false });
|
|
1096
|
-
normalized[key] = next;
|
|
1097
|
-
changed ||= next !== value;
|
|
1098
|
-
}
|
|
1099
|
-
return changed ? normalized : schema;
|
|
1100
|
-
}
|
|
1101
|
-
function normalizeOpenAIStrictCompatSchemaRecursive(schema, options) {
|
|
1102
|
-
if (Array.isArray(schema)) {
|
|
1103
|
-
let changed = false;
|
|
1104
|
-
const normalized = schema.map((entry) => {
|
|
1105
|
-
const next = normalizeOpenAIStrictCompatSchemaRecursive(entry, { promoteEmptyObject: false });
|
|
1106
|
-
changed ||= next !== entry;
|
|
1107
|
-
return next;
|
|
1108
|
-
});
|
|
1109
|
-
return changed ? normalized : schema;
|
|
1110
|
-
}
|
|
1111
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
1112
|
-
const record = schema;
|
|
1113
|
-
let changed = false;
|
|
1114
|
-
let hadNullType = false;
|
|
1115
|
-
const normalized = {};
|
|
1116
|
-
for (const [key, value] of Object.entries(record)) {
|
|
1117
|
-
if (value === null && OPENAI_NULLABLE_ANNOTATION_KEYS.has(key)) {
|
|
1118
|
-
changed = true;
|
|
1119
|
-
continue;
|
|
1120
|
-
}
|
|
1121
|
-
if (value === null && key === "type") {
|
|
1122
|
-
hadNullType = true;
|
|
1123
|
-
changed = true;
|
|
1124
|
-
continue;
|
|
1125
|
-
}
|
|
1126
|
-
const next = OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaMap(value) : OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false }) : value;
|
|
1127
|
-
normalized[key] = next;
|
|
1128
|
-
changed ||= next !== value;
|
|
1129
|
-
}
|
|
1130
|
-
if (Object.keys(normalized).length === 0) {
|
|
1131
|
-
if (!options.promoteEmptyObject) return schema;
|
|
1132
|
-
return {
|
|
1133
|
-
type: "object",
|
|
1134
|
-
properties: {},
|
|
1135
|
-
required: [],
|
|
1136
|
-
additionalProperties: false
|
|
1137
|
-
};
|
|
1138
|
-
}
|
|
1139
|
-
const hasObjectShapeHints = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) || Array.isArray(normalized.required);
|
|
1140
|
-
const hasArrayShapeHints = "items" in normalized;
|
|
1141
|
-
if (!("type" in normalized) && hasObjectShapeHints !== hasArrayShapeHints) {
|
|
1142
|
-
normalized.type = hasObjectShapeHints ? "object" : "array";
|
|
1143
|
-
changed = true;
|
|
1144
|
-
} else if (hadNullType && !("type" in normalized)) normalized.type = null;
|
|
1145
|
-
if (normalized.type === "object" && !("properties" in normalized)) {
|
|
1146
|
-
normalized.properties = {};
|
|
1147
|
-
changed = true;
|
|
1148
|
-
}
|
|
1149
|
-
const hasEmptyProperties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) && Object.keys(normalized.properties).length === 0;
|
|
1150
|
-
if (normalized.type === "object" && !Array.isArray(normalized.required) && hasEmptyProperties) {
|
|
1151
|
-
normalized.required = [];
|
|
1152
|
-
changed = true;
|
|
1153
|
-
}
|
|
1154
|
-
if (normalized.type === "object" && hasEmptyProperties && !("additionalProperties" in normalized)) {
|
|
1155
|
-
normalized.additionalProperties = false;
|
|
1156
|
-
changed = true;
|
|
1157
|
-
}
|
|
1158
|
-
return changed ? normalized : schema;
|
|
1159
|
-
}
|
|
1160
|
-
/** Repairs recoverable OpenAI tool-schema shapes before canonical normalization. */
|
|
1161
|
-
function normalizeOpenAIStrictCompatSchema(schema) {
|
|
1162
|
-
return normalizeOpenAIStrictCompatSchemaRecursive(schema, { promoteEmptyObject: true });
|
|
1163
|
-
}
|
|
1164
|
-
/** Finds schema paths that violate OpenAI strict tool-schema requirements. */
|
|
1165
|
-
function findOpenAIStrictSchemaViolations(schema, path, options) {
|
|
1166
|
-
if (Array.isArray(schema)) {
|
|
1167
|
-
if (options?.requireObjectRoot) return [`${path}.type`];
|
|
1168
|
-
return schema.flatMap((item, index) => findOpenAIStrictSchemaViolations(item, `${path}[${index}]`));
|
|
1169
|
-
}
|
|
1170
|
-
if (!schema || typeof schema !== "object") return options?.requireObjectRoot ? [`${path}.type`] : [];
|
|
1171
|
-
const record = schema;
|
|
1172
|
-
const violations = [];
|
|
1173
|
-
for (const key of [
|
|
1174
|
-
"anyOf",
|
|
1175
|
-
"oneOf",
|
|
1176
|
-
"allOf"
|
|
1177
|
-
]) if (key in record) violations.push(`${path}.${key}`);
|
|
1178
|
-
if (Array.isArray(record.type)) violations.push(`${path}.type`);
|
|
1179
|
-
const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : void 0;
|
|
1180
|
-
if (record.type === "object") {
|
|
1181
|
-
if (record.additionalProperties !== false) violations.push(`${path}.additionalProperties`);
|
|
1182
|
-
const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
|
|
1183
|
-
if (!required) violations.push(`${path}.required`);
|
|
1184
|
-
else if (properties) {
|
|
1185
|
-
const requiredSet = new Set(required);
|
|
1186
|
-
for (const key of Object.keys(properties)) if (!requiredSet.has(key)) violations.push(`${path}.required.${key}`);
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
for (const key of OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS) {
|
|
1190
|
-
const schemaMap = record[key];
|
|
1191
|
-
if (!schemaMap || typeof schemaMap !== "object" || Array.isArray(schemaMap)) continue;
|
|
1192
|
-
for (const [entryKey, value] of Object.entries(schemaMap)) violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}.${entryKey}`));
|
|
1193
|
-
}
|
|
1194
|
-
for (const key of OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS) {
|
|
1195
|
-
const value = record[key];
|
|
1196
|
-
if (value && typeof value === "object") violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}`));
|
|
1197
|
-
}
|
|
1198
|
-
return violations;
|
|
1199
|
-
}
|
|
1200
|
-
//#endregion
|
|
1201
|
-
//#region packages/ai/src/providers/openai-tool-schema.ts
|
|
1202
|
-
/**
|
|
1203
|
-
* OpenAI strict JSON-schema normalization for tool inventories and request payloads.
|
|
1204
|
-
*
|
|
1205
|
-
* Caches normalized object inputs by provider compatibility so repeated inventory builds preserve identity.
|
|
1206
|
-
*/
|
|
1207
|
-
const MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
|
|
1208
|
-
const strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
|
|
1209
|
-
function resolveToolSchemaModelCompat(compat) {
|
|
1210
|
-
if (!compat) return;
|
|
1211
|
-
const unsupportedToolSchemaKeywords = Array.isArray(compat.unsupportedToolSchemaKeywords) ? compat.unsupportedToolSchemaKeywords.filter((keyword) => typeof keyword === "string") : [];
|
|
1212
|
-
if (unsupportedToolSchemaKeywords.length === 0 && compat.omitEmptyArrayItems !== true) return;
|
|
1213
|
-
return {
|
|
1214
|
-
...unsupportedToolSchemaKeywords.length > 0 ? { unsupportedToolSchemaKeywords } : {},
|
|
1215
|
-
...compat.omitEmptyArrayItems === true ? { omitEmptyArrayItems: true } : {}
|
|
1216
|
-
};
|
|
1217
|
-
}
|
|
1218
|
-
function resolveStrictOpenAISchemaCacheKey(modelCompat) {
|
|
1219
|
-
const compat = resolveToolSchemaModelCompat(modelCompat);
|
|
1220
|
-
return JSON.stringify([[...compat?.unsupportedToolSchemaKeywords ?? []].toSorted(), shouldOmitEmptyArrayItems(compat)]);
|
|
1221
|
-
}
|
|
1222
|
-
function readCachedStrictOpenAISchema(schema, key) {
|
|
1223
|
-
return strictOpenAISchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
|
|
1224
|
-
}
|
|
1225
|
-
function rememberStrictOpenAISchema(schema, key, value) {
|
|
1226
|
-
const entries = strictOpenAISchemaCache.get(schema) ?? [];
|
|
1227
|
-
strictOpenAISchemaCache.set(schema, [{
|
|
1228
|
-
key,
|
|
1229
|
-
value
|
|
1230
|
-
}, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
|
|
1231
|
-
return value;
|
|
1232
|
-
}
|
|
1233
|
-
/** Normalizes a tool parameter schema into the OpenAI strict JSON-schema subset. */
|
|
1234
|
-
function normalizeStrictOpenAIJsonSchema(schema, modelCompat) {
|
|
1235
|
-
const schemaInput = schema ?? {};
|
|
1236
|
-
if (!schemaInput || typeof schemaInput !== "object") return normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0);
|
|
1237
|
-
const cacheKey = resolveStrictOpenAISchemaCacheKey(modelCompat);
|
|
1238
|
-
const cached = readCachedStrictOpenAISchema(schemaInput, cacheKey);
|
|
1239
|
-
if (cached !== void 0) return cached;
|
|
1240
|
-
return rememberStrictOpenAISchema(schemaInput, cacheKey, normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0));
|
|
1241
|
-
}
|
|
1242
|
-
function normalizeStrictOpenAIJsonSchemaRecursive(schema, depth) {
|
|
1243
|
-
if (Array.isArray(schema)) {
|
|
1244
|
-
let changed = false;
|
|
1245
|
-
const normalized = schema.map((entry) => {
|
|
1246
|
-
const next = normalizeStrictOpenAIJsonSchemaRecursive(entry, depth);
|
|
1247
|
-
changed ||= next !== entry;
|
|
1248
|
-
return next;
|
|
1249
|
-
});
|
|
1250
|
-
return changed ? normalized : schema;
|
|
1251
|
-
}
|
|
1252
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
1253
|
-
const record = schema;
|
|
1254
|
-
let changed = false;
|
|
1255
|
-
const normalized = {};
|
|
1256
|
-
for (const [key, value] of Object.entries(record)) {
|
|
1257
|
-
const next = normalizeStrictOpenAIJsonSchemaRecursive(value, key === "properties" ? depth : depth + 1);
|
|
1258
|
-
normalized[key] = next;
|
|
1259
|
-
changed ||= next !== value;
|
|
1260
|
-
}
|
|
1261
|
-
if (normalized.type === "object") {
|
|
1262
|
-
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : void 0;
|
|
1263
|
-
if (properties && Object.keys(properties).length === 0 && !Array.isArray(normalized.required)) {
|
|
1264
|
-
normalized.required = [];
|
|
1265
|
-
changed = true;
|
|
1266
|
-
}
|
|
1267
|
-
if (depth === 0 && !("additionalProperties" in normalized)) {
|
|
1268
|
-
normalized.additionalProperties = false;
|
|
1269
|
-
changed = true;
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
return changed ? normalized : schema;
|
|
1273
|
-
}
|
|
1274
|
-
/** Normalizes tool parameters using strict OpenAI rules only when strict mode is active. */
|
|
1275
|
-
function normalizeOpenAIStrictToolParameters(schema, strict, modelCompat) {
|
|
1276
|
-
const toolSchemaCompat = resolveToolSchemaModelCompat(modelCompat);
|
|
1277
|
-
if (!strict) return normalizeToolParameterSchema(schema ?? {}, { modelCompat: toolSchemaCompat });
|
|
1278
|
-
return normalizeStrictOpenAIJsonSchema(schema, toolSchemaCompat);
|
|
1279
|
-
}
|
|
1280
|
-
/** Returns whether a schema already satisfies OpenAI strict tool-schema constraints. */
|
|
1281
|
-
function isStrictOpenAIJsonSchemaCompatible(schema) {
|
|
1282
|
-
return isStrictOpenAIJsonSchemaCompatibleRecursive(normalizeStrictOpenAIJsonSchema(schema));
|
|
1283
|
-
}
|
|
1284
|
-
/** Returns strict-schema diagnostics for an already materialized OpenAI tool projection. */
|
|
1285
|
-
function findOpenAIStrictToolProjectionDiagnostics(projection) {
|
|
1286
|
-
return [...projection.diagnostics.map((diagnostic) => ({
|
|
1287
|
-
toolIndex: diagnostic.toolIndex,
|
|
1288
|
-
...diagnostic.toolName ? { toolName: diagnostic.toolName } : {},
|
|
1289
|
-
violations: [...diagnostic.violations]
|
|
1290
|
-
})), ...projection.tools.flatMap((tool) => {
|
|
1291
|
-
const violations = findOpenAIStrictSchemaViolations(normalizeStrictOpenAIJsonSchema(tool.parameters), `${tool.name}.parameters`);
|
|
1292
|
-
return violations.length > 0 ? [{
|
|
1293
|
-
toolIndex: tool.toolIndex,
|
|
1294
|
-
toolName: tool.name,
|
|
1295
|
-
violations
|
|
1296
|
-
}] : [];
|
|
1297
|
-
})];
|
|
1298
|
-
}
|
|
1299
|
-
function isStrictOpenAIJsonSchemaCompatibleRecursive(schema) {
|
|
1300
|
-
if (Array.isArray(schema)) return schema.every((entry) => isStrictOpenAIJsonSchemaCompatibleRecursive(entry));
|
|
1301
|
-
if (!schema || typeof schema !== "object") return true;
|
|
1302
|
-
const record = schema;
|
|
1303
|
-
if ("anyOf" in record || "oneOf" in record || "allOf" in record) return false;
|
|
1304
|
-
if (Array.isArray(record.type)) return false;
|
|
1305
|
-
if (record.type === "object" && record.additionalProperties !== false) return false;
|
|
1306
|
-
if (record.type === "object") {
|
|
1307
|
-
const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : {};
|
|
1308
|
-
const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
|
|
1309
|
-
if (!required) return false;
|
|
1310
|
-
const requiredSet = new Set(required);
|
|
1311
|
-
if (Object.keys(properties).some((key) => !requiredSet.has(key))) return false;
|
|
1312
|
-
}
|
|
1313
|
-
return Object.entries(record).every(([key, entry]) => {
|
|
1314
|
-
if (key === "properties" && entry && typeof entry === "object" && !Array.isArray(entry)) return Object.values(entry).every((value) => isStrictOpenAIJsonSchemaCompatibleRecursive(value));
|
|
1315
|
-
return isStrictOpenAIJsonSchemaCompatibleRecursive(entry);
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1318
|
-
/** Resolves strict mode for the projected tools that will be emitted in the request payload. */
|
|
1319
|
-
function resolveOpenAIProjectedToolsStrictToolFlag(projection, strict) {
|
|
1320
|
-
if (strict !== true) return strict === false ? false : void 0;
|
|
1321
|
-
return projection.tools.every((tool) => isStrictOpenAIJsonSchemaCompatible(tool.parameters));
|
|
1322
|
-
}
|
|
1323
|
-
//#endregion
|
|
1324
59
|
//#region packages/ai/src/transports/openai-responses-replay.ts
|
|
1325
60
|
/** Resolves the assistant message id that can be replayed to OpenAI Responses. */
|
|
1326
61
|
function resolveReplayableResponsesMessageId(params) {
|
|
@@ -1362,7 +97,7 @@ function readOpenAIResponsesCompactionReplayState(value) {
|
|
|
1362
97
|
function openAIResponsesReplayContextMatches(state, context) {
|
|
1363
98
|
return state.provider === context.provider && state.api === context.api && state.model === context.model && state.baseUrlHash === context.baseUrlHash && state.sessionHash === context.sessionHash && state.authProfileHash === context.authProfileHash;
|
|
1364
99
|
}
|
|
1365
|
-
function captureOpenAIResponsesCompaction(output, item, boundary, model, captureMetadata) {
|
|
100
|
+
function captureOpenAIResponsesCompaction(output, item, boundary, model, captureMetadata, compactedOutput) {
|
|
1366
101
|
const metadata = captureMetadata ?? buildOpenAIResponsesReasoningReplayMetadata(model);
|
|
1367
102
|
if (!item.encrypted_content) return;
|
|
1368
103
|
if (!metadata?.baseUrlHash) {
|
|
@@ -1371,19 +106,28 @@ function captureOpenAIResponsesCompaction(output, item, boundary, model, capture
|
|
|
1371
106
|
}
|
|
1372
107
|
const currentReplay = readOpenAIResponsesCompactionReplayState(output.providerReplay);
|
|
1373
108
|
if (typeof boundary === "number" && currentReplay?.type === "openai-responses-compaction" && (currentReplay.replayIndex ?? -1) > boundary) return;
|
|
1374
|
-
|
|
109
|
+
if (compactedOutput && !isOpenAIResponsesCompactionOutput(compactedOutput, model)) throw new Error("Responses compact endpoint checkpoint is invalid");
|
|
110
|
+
const replay = {
|
|
1375
111
|
v: 1,
|
|
1376
|
-
|
|
112
|
+
...boundary === "retained-users" ? { type: OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE } : {
|
|
113
|
+
type: OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE,
|
|
114
|
+
replayIndex: boundary
|
|
115
|
+
},
|
|
1377
116
|
...item.id ? { id: item.id } : {},
|
|
1378
117
|
data: item.encrypted_content,
|
|
1379
|
-
...typeof boundary === "number" ? { replayIndex: boundary } : {},
|
|
1380
118
|
provider: metadata.provider,
|
|
1381
119
|
api: metadata.api,
|
|
1382
120
|
model: metadata.model,
|
|
1383
121
|
baseUrlHash: metadata.baseUrlHash,
|
|
1384
122
|
...metadata.sessionHash ? { sessionHash: metadata.sessionHash } : {},
|
|
1385
|
-
...metadata.authProfileHash ? { authProfileHash: metadata.authProfileHash } : {}
|
|
123
|
+
...metadata.authProfileHash ? { authProfileHash: metadata.authProfileHash } : {},
|
|
124
|
+
...compactedOutput ? { compactedWindow: {
|
|
125
|
+
state: "ready",
|
|
126
|
+
output: JSON.stringify(compactedOutput)
|
|
127
|
+
} } : {}
|
|
1386
128
|
};
|
|
129
|
+
if (compactedOutput && !readOpenAIResponsesCompactionWindow(replay, model)) throw new Error("Responses compact endpoint checkpoint is invalid or exceeds 16 MiB");
|
|
130
|
+
output.providerReplay = replay;
|
|
1387
131
|
}
|
|
1388
132
|
function suppressOpenAIResponsesCompaction(output, model, options, rejectedCheckpoint) {
|
|
1389
133
|
const context = buildOpenAIResponsesReplayContext(model, options);
|
|
@@ -1432,6 +176,21 @@ function resolveNewestOpenAIResponsesCompactionReplay(messages, model, options)
|
|
|
1432
176
|
continue;
|
|
1433
177
|
}
|
|
1434
178
|
if (!openAIResponsesReplayContextMatches(replay, context)) return;
|
|
179
|
+
if (replay.compactedWindow !== void 0 || replay.type === "openai-responses-retained-compaction") {
|
|
180
|
+
const output = readOpenAIResponsesCompactionWindow(replay, model);
|
|
181
|
+
const item = output?.at(-1);
|
|
182
|
+
if (!output || item?.type !== "compaction") return {
|
|
183
|
+
owner: message,
|
|
184
|
+
mode: "refresh-required"
|
|
185
|
+
};
|
|
186
|
+
return {
|
|
187
|
+
owner: message,
|
|
188
|
+
mode: "complete-window",
|
|
189
|
+
output,
|
|
190
|
+
item,
|
|
191
|
+
replayIndex: replay.type === "openai-responses-retained-compaction" ? message.content.length : replay.replayIndex ?? 0
|
|
192
|
+
};
|
|
193
|
+
}
|
|
1435
194
|
return {
|
|
1436
195
|
owner: message,
|
|
1437
196
|
item: {
|
|
@@ -1439,13 +198,17 @@ function resolveNewestOpenAIResponsesCompactionReplay(messages, model, options)
|
|
|
1439
198
|
...isSafeResponsesReplayItemId(replay.id) ? { id: replay.id } : {},
|
|
1440
199
|
encrypted_content: replay.data
|
|
1441
200
|
},
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
replayIndex: replay.replayIndex ?? 0
|
|
1445
|
-
}
|
|
201
|
+
mode: "compacted-prefix",
|
|
202
|
+
replayIndex: replay.replayIndex ?? 0
|
|
1446
203
|
};
|
|
1447
204
|
}
|
|
1448
205
|
}
|
|
206
|
+
var CompactionReplayRefreshRequiredError = class extends Error {
|
|
207
|
+
constructor() {
|
|
208
|
+
super("Provider compaction checkpoint needs rebuilding. Run /compact to rebuild from saved conversation history.");
|
|
209
|
+
this.name = "CompactionReplayRefreshRequiredError";
|
|
210
|
+
}
|
|
211
|
+
};
|
|
1449
212
|
function buildOpenAIResponsesCompactionReplayPlan(messages, model, options) {
|
|
1450
213
|
if (options?.mode === "full-history") return {
|
|
1451
214
|
messages,
|
|
@@ -1456,22 +219,14 @@ function buildOpenAIResponsesCompactionReplayPlan(messages, model, options) {
|
|
|
1456
219
|
messages,
|
|
1457
220
|
preserveUnframedToolResults: false
|
|
1458
221
|
};
|
|
222
|
+
if (compaction.mode === "refresh-required") throw new CompactionReplayRefreshRequiredError();
|
|
1459
223
|
const ownerIndex = messages.indexOf(compaction.owner);
|
|
1460
|
-
const collectRetainedUserMessages = (prefix) => {
|
|
1461
|
-
const previous = resolveNewestOpenAIResponsesCompactionReplay(prefix, model, options);
|
|
1462
|
-
if (!previous) return prefix.filter((message) => message.role === "user");
|
|
1463
|
-
const previousOwnerIndex = prefix.indexOf(previous.owner);
|
|
1464
|
-
const laterUsers = prefix.slice(previousOwnerIndex + 1).filter((message) => message.role === "user");
|
|
1465
|
-
return previous.mode === "retained-users" ? [...collectRetainedUserMessages(prefix.slice(0, previousOwnerIndex)), ...laterUsers] : laterUsers;
|
|
1466
|
-
};
|
|
1467
|
-
const retainedMessages = compaction.mode === "retained-users" ? collectRetainedUserMessages(messages.slice(0, ownerIndex)) : void 0;
|
|
1468
224
|
return {
|
|
1469
225
|
messages: [{
|
|
1470
226
|
...compaction.owner,
|
|
1471
|
-
content: compaction.
|
|
227
|
+
content: compaction.owner.content.slice(compaction.replayIndex)
|
|
1472
228
|
}, ...messages.slice(ownerIndex + 1)],
|
|
1473
|
-
...
|
|
1474
|
-
compaction: compaction.item,
|
|
229
|
+
...compaction.mode === "complete-window" ? { compactedWindow: compaction.output } : { compaction: compaction.item },
|
|
1475
230
|
preserveUnframedToolResults: true
|
|
1476
231
|
};
|
|
1477
232
|
}
|
|
@@ -1663,16 +418,23 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
|
|
|
1663
418
|
preserveUnframedToolResults: replayPlan.preserveUnframedToolResults
|
|
1664
419
|
});
|
|
1665
420
|
const transformedMessages = transformMessages(replayPlan.messages);
|
|
1666
|
-
|
|
1667
|
-
if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) messages.push(buildResponsesInputMessage(model.reasoning && (providerStyle ? model.compat?.supportsDeveloperRole !== false : options?.supportsDeveloperRole !== false) ? "developer" : "system", [{
|
|
421
|
+
if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) messages.push(buildResponsesInputMessage(model.reasoning && model.compat?.supportsDeveloperRole !== false ? "developer" : "system", [{
|
|
1668
422
|
type: "input_text",
|
|
1669
423
|
text: sanitizeTransportPayloadText(stripSystemPromptCacheBoundary(context.systemPrompt))
|
|
1670
424
|
}]));
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
425
|
+
if (replayPlan.compactedWindow) messages.push(...replayPlan.compactedWindow);
|
|
426
|
+
let replayMessages = replayPlan.compaction ? [replayPlan.compaction, ...transformedMessages] : transformedMessages;
|
|
427
|
+
const isCarrier = (message) => "role" in message && message.role === "user" && message.runtimeContextCarrier === true;
|
|
428
|
+
const carriers = replayMessages.filter(isCarrier);
|
|
429
|
+
if (carriers.length > 0) {
|
|
430
|
+
const stableMessages = replayMessages.filter((message) => !isCarrier(message));
|
|
431
|
+
const insertionIndex = stableMessages.findLastIndex((message) => "role" in message ? message.role === "user" : message.type === "compaction") + 1;
|
|
432
|
+
if (insertionIndex > 0 || replayPlan.compactedWindow) replayMessages = [
|
|
433
|
+
...stableMessages.slice(0, insertionIndex),
|
|
434
|
+
...carriers,
|
|
435
|
+
...stableMessages.slice(insertionIndex)
|
|
436
|
+
];
|
|
437
|
+
}
|
|
1676
438
|
let msgIndex = 0;
|
|
1677
439
|
for (const msg of replayMessages) {
|
|
1678
440
|
if (!("role" in msg)) {
|
|
@@ -1799,8 +561,8 @@ function isInvalidEncryptedContentError(error) {
|
|
|
1799
561
|
if (!error || typeof error !== "object") return false;
|
|
1800
562
|
const record = error;
|
|
1801
563
|
if (record.code === "invalid_encrypted_content" || record.code === "thinking_signature_invalid") return true;
|
|
1802
|
-
const message = typeof record.message === "string" ? record.message : "";
|
|
1803
|
-
return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || record.status === 400 && message
|
|
564
|
+
const message = typeof record.message === "string" ? record.message.toLowerCase() : "";
|
|
565
|
+
return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || (record.status === 400 || record.status == null && /(?:^|[\s(])400(?:[\s):]|$)/.test(message)) && (message.includes("could not decrypt the provided encrypted_content") || message.includes("encrypted content") && (message.includes("could not be verified") || message.includes("could not be decrypted or parsed")));
|
|
1804
566
|
}
|
|
1805
567
|
function isOrphanedFunctionCallOutputError(error) {
|
|
1806
568
|
if (!error || typeof error !== "object") return false;
|
|
@@ -1880,7 +642,45 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
|
1880
642
|
payloadVariant: attempt.kind
|
|
1881
643
|
});
|
|
1882
644
|
try {
|
|
1883
|
-
|
|
645
|
+
const result = await sendAttempt(attempt);
|
|
646
|
+
return {
|
|
647
|
+
...result,
|
|
648
|
+
stream: { async *[Symbol.asyncIterator]() {
|
|
649
|
+
let rejectedEvent;
|
|
650
|
+
try {
|
|
651
|
+
for await (const event of params.wrapStream?.(result) ?? result.stream) {
|
|
652
|
+
if (isRecord(event)) {
|
|
653
|
+
const failure = event.type === "response.failed" && isRecord(event.response) ? event.response.error : event.type === "error" ? event.error ?? event : void 0;
|
|
654
|
+
if (isRecord(failure) && params.canRetryStream?.() === true && isInvalidEncryptedContentError(failure)) {
|
|
655
|
+
rejectedEvent = event;
|
|
656
|
+
const message = typeof failure.message === "string" ? failure.message : "";
|
|
657
|
+
throw Object.assign(new Error(message), {
|
|
658
|
+
code: failure.code,
|
|
659
|
+
status: failure.status
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
yield event;
|
|
664
|
+
}
|
|
665
|
+
} catch (error) {
|
|
666
|
+
const nextAttempt = params.canRetryStream?.() === true && !params.requestOptions?.signal?.aborted ? await resolveNextResponsesEncryptedContentAttempt(result.attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest }) : void 0;
|
|
667
|
+
if (!nextAttempt) {
|
|
668
|
+
if (rejectedEvent !== void 0) {
|
|
669
|
+
yield rejectedEvent;
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
throw error;
|
|
673
|
+
}
|
|
674
|
+
log.warn(`[responses] retrying streamed encrypted content provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
|
|
675
|
+
yield* (await createResponsesStreamWithEncryptedContentRetry({
|
|
676
|
+
...params,
|
|
677
|
+
request: nextAttempt.request,
|
|
678
|
+
initialAttemptKind: nextAttempt.kind,
|
|
679
|
+
initialRejectedCompaction: nextAttempt.rejectedCompaction
|
|
680
|
+
})).stream;
|
|
681
|
+
}
|
|
682
|
+
} }
|
|
683
|
+
};
|
|
1884
684
|
} catch (error) {
|
|
1885
685
|
let nextAttempt = await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
|
|
1886
686
|
if (!nextAttempt && attempt.request.previous_response_id && error && typeof error === "object" && typeof error.status === "number" && error.code === "previous_response_not_found") {
|
|
@@ -1952,14 +752,14 @@ function createResponsesToolCallTracker() {
|
|
|
1952
752
|
state.callId ??= identity.callId;
|
|
1953
753
|
return state;
|
|
1954
754
|
};
|
|
1955
|
-
const resolveCompatible = (candidates, identity) => {
|
|
755
|
+
const resolveCompatible = (candidates, identity, allowUnmatchedIdentity) => {
|
|
1956
756
|
const uniqueCandidates = [...new Set(candidates)];
|
|
1957
|
-
if (!identity.itemId && !identity.callId) return uniqueCandidates.length === 1 ? uniqueCandidates.at(0) : void 0;
|
|
757
|
+
if (!identity.itemId && !identity.callId) return allowUnmatchedIdentity && uniqueCandidates.length === 1 ? uniqueCandidates.at(0) : void 0;
|
|
1958
758
|
const compatible = uniqueCandidates.filter((state) => !identitiesConflict(state, identity));
|
|
1959
759
|
const matches = compatible.filter((state) => sharesIdentity(state, identity));
|
|
1960
760
|
const matched = matches.length === 1 ? matches.at(0) : void 0;
|
|
1961
761
|
if (matched) return adoptIdentity(matched, identity);
|
|
1962
|
-
const soleCompatible = uniqueCandidates.length === 1 && compatible.length === 1 && matches.length === 0 ? compatible.at(0) : void 0;
|
|
762
|
+
const soleCompatible = allowUnmatchedIdentity && uniqueCandidates.length === 1 && compatible.length === 1 && matches.length === 0 ? compatible.at(0) : void 0;
|
|
1963
763
|
return soleCompatible ? adoptIdentity(soleCompatible, identity) : void 0;
|
|
1964
764
|
};
|
|
1965
765
|
return {
|
|
@@ -1970,9 +770,10 @@ function createResponsesToolCallTracker() {
|
|
|
1970
770
|
return;
|
|
1971
771
|
}
|
|
1972
772
|
if (indexedCalls.has(outputIndex)) throw new Error(`Responses stream reused active tool-call output index ${outputIndex}`);
|
|
773
|
+
state.outputIndex = outputIndex;
|
|
1973
774
|
indexedCalls.set(outputIndex, state);
|
|
1974
775
|
},
|
|
1975
|
-
resolve(event, identity = readEventIdentity(event)) {
|
|
776
|
+
resolve(event, identity = readEventIdentity(event), allowUnmatchedIdentity = true) {
|
|
1976
777
|
const outputIndex = readOutputIndex(event);
|
|
1977
778
|
if (outputIndex !== void 0) {
|
|
1978
779
|
const indexed = indexedCalls.get(outputIndex);
|
|
@@ -1980,14 +781,15 @@ function createResponsesToolCallTracker() {
|
|
|
1980
781
|
if (indexed.callId && identity.callId && indexed.callId !== identity.callId) return;
|
|
1981
782
|
return adoptIdentity(indexed, identity);
|
|
1982
783
|
}
|
|
1983
|
-
const unindexed = resolveCompatible(unindexedCalls, identity);
|
|
784
|
+
const unindexed = resolveCompatible(unindexedCalls, identity, allowUnmatchedIdentity);
|
|
1984
785
|
if (unindexed) {
|
|
1985
786
|
unindexedCalls.delete(unindexed);
|
|
787
|
+
unindexed.outputIndex = outputIndex;
|
|
1986
788
|
indexedCalls.set(outputIndex, unindexed);
|
|
1987
789
|
}
|
|
1988
790
|
return unindexed;
|
|
1989
791
|
}
|
|
1990
|
-
return resolveCompatible([...indexedCalls.values(), ...unindexedCalls], identity);
|
|
792
|
+
return resolveCompatible([...indexedCalls.values(), ...unindexedCalls], identity, allowUnmatchedIdentity);
|
|
1991
793
|
},
|
|
1992
794
|
forget(toolCall) {
|
|
1993
795
|
for (const [outputIndex, tracked] of indexedCalls) if (tracked === toolCall) indexedCalls.delete(outputIndex);
|
|
@@ -1998,6 +800,10 @@ function createResponsesToolCallTracker() {
|
|
|
1998
800
|
},
|
|
1999
801
|
hasActive() {
|
|
2000
802
|
return indexedCalls.size > 0 || unindexedCalls.size > 0;
|
|
803
|
+
},
|
|
804
|
+
hasExactlyActive(expected) {
|
|
805
|
+
const active = /* @__PURE__ */ new Set([...indexedCalls.values(), ...unindexedCalls]);
|
|
806
|
+
return active.size === expected.length && expected.every((state) => active.has(state));
|
|
2001
807
|
}
|
|
2002
808
|
};
|
|
2003
809
|
}
|
|
@@ -2123,9 +929,10 @@ const RESPONSE_FAILED_FAILURE_FIELD_KEYS = [
|
|
|
2123
929
|
function readResponseFailedString(record, key) {
|
|
2124
930
|
return stringifyUnknown(record?.[key]);
|
|
2125
931
|
}
|
|
2126
|
-
function buildResponsesFailedEventSummary(message, responseId, observation) {
|
|
932
|
+
function buildResponsesFailedEventSummary(message, responseId, code, observation) {
|
|
2127
933
|
const summary = { message };
|
|
2128
934
|
if (responseId) summary.responseId = responseId;
|
|
935
|
+
if (code) summary.code = code;
|
|
2129
936
|
if (observation) summary.observation = observation;
|
|
2130
937
|
return summary;
|
|
2131
938
|
}
|
|
@@ -2244,11 +1051,11 @@ function normalizeResponsesFailedEvent(event, model) {
|
|
|
2244
1051
|
if (error) {
|
|
2245
1052
|
const code = readResponseFailedString(error, "code").trim();
|
|
2246
1053
|
const message = readResponseFailedString(error, "message").trim();
|
|
2247
|
-
if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId);
|
|
1054
|
+
if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId, code || void 0);
|
|
2248
1055
|
}
|
|
2249
1056
|
const incompleteReason = readResponseFailedString(isRecord(response?.incomplete_details) ? response.incomplete_details : void 0, "reason");
|
|
2250
1057
|
if (incompleteReason) return buildResponsesFailedEventSummary(`incomplete: ${incompleteReason}`, responseId);
|
|
2251
|
-
return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, buildResponsesFailedNoDetailsObservation(event, model, response));
|
|
1058
|
+
return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, void 0, buildResponsesFailedNoDetailsObservation(event, model, response));
|
|
2252
1059
|
}
|
|
2253
1060
|
var ResponsesStreamFailure = class extends Error {
|
|
2254
1061
|
constructor(failure, response) {
|
|
@@ -2256,6 +1063,7 @@ var ResponsesStreamFailure = class extends Error {
|
|
|
2256
1063
|
this.name = "ResponsesStreamFailure";
|
|
2257
1064
|
this.responseId = failure.responseId;
|
|
2258
1065
|
this.response = response;
|
|
1066
|
+
this.code = failure.code;
|
|
2259
1067
|
this.observation = failure.observation;
|
|
2260
1068
|
}
|
|
2261
1069
|
};
|
|
@@ -2346,20 +1154,39 @@ async function* observeResponsesStream(stream, model, requestStartedAt) {
|
|
|
2346
1154
|
}
|
|
2347
1155
|
//#endregion
|
|
2348
1156
|
//#region packages/ai/src/transports/openai-responses-stream-slots-internal.ts
|
|
2349
|
-
function
|
|
2350
|
-
const
|
|
1157
|
+
function createResponsesOutputTracker() {
|
|
1158
|
+
const outputs = /* @__PURE__ */ new Map();
|
|
2351
1159
|
const identity = (item) => {
|
|
2352
1160
|
if ((item.type === "reasoning" || item.type === "message") && item.id) return `${item.type}:${item.id}`;
|
|
2353
|
-
|
|
1161
|
+
const callId = item.call_id ?? item.id;
|
|
1162
|
+
return item.type === "function_call" && callId ? `function_call:${callId}` : void 0;
|
|
1163
|
+
};
|
|
1164
|
+
const get = (item, outputIndex) => {
|
|
1165
|
+
const key = identity(item);
|
|
1166
|
+
const output = (outputIndex === void 0 ? void 0 : outputs.get(outputIndex)) ?? (key === void 0 ? void 0 : outputs.get(key));
|
|
1167
|
+
if (!output || outputIndex !== void 0 && output.outputIndex !== void 0 && output.outputIndex !== outputIndex) return;
|
|
1168
|
+
if (output.type !== item.type || output.callId && item.call_id && output.callId !== item.call_id) throw new Error("Responses stream changed output item identity");
|
|
1169
|
+
return output;
|
|
2354
1170
|
};
|
|
2355
1171
|
return {
|
|
2356
|
-
get
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
1172
|
+
get,
|
|
1173
|
+
set(item, contentIndex, outputIndex, completed = false) {
|
|
1174
|
+
const output = get(item, outputIndex) ?? {
|
|
1175
|
+
type: item.type,
|
|
1176
|
+
contentIndex,
|
|
1177
|
+
completed
|
|
1178
|
+
};
|
|
1179
|
+
Object.assign(output, {
|
|
1180
|
+
contentIndex,
|
|
1181
|
+
completed
|
|
1182
|
+
});
|
|
1183
|
+
if (item.call_id) output.callId = item.call_id;
|
|
1184
|
+
if (outputIndex !== void 0) {
|
|
1185
|
+
output.outputIndex = outputIndex;
|
|
1186
|
+
outputs.set(outputIndex, output);
|
|
1187
|
+
}
|
|
2361
1188
|
const key = identity(item);
|
|
2362
|
-
if (key !== void 0)
|
|
1189
|
+
if (key !== void 0) outputs.set(key, output);
|
|
2363
1190
|
}
|
|
2364
1191
|
};
|
|
2365
1192
|
}
|
|
@@ -2419,8 +1246,11 @@ function createResponsesOutputSlotTracker() {
|
|
|
2419
1246
|
* package and managed transports from drifting on token buckets, service-tier pricing, or future
|
|
2420
1247
|
* terminal-event semantics.
|
|
2421
1248
|
*/
|
|
1249
|
+
function readReportedCount(value) {
|
|
1250
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
1251
|
+
}
|
|
2422
1252
|
function readCount(value) {
|
|
2423
|
-
return
|
|
1253
|
+
return readReportedCount(value) ?? 0;
|
|
2424
1254
|
}
|
|
2425
1255
|
/**
|
|
2426
1256
|
* Split a terminal usage payload into the priced buckets.
|
|
@@ -2438,12 +1268,21 @@ function mapResponsesTerminalUsage(usage) {
|
|
|
2438
1268
|
const input = Math.max(0, readCount(usage.input_tokens) - cacheRead - cacheWrite);
|
|
2439
1269
|
const output = readCount(usage.output_tokens);
|
|
2440
1270
|
const bucketTotal = input + output + cacheRead + cacheWrite;
|
|
1271
|
+
const totalTokens = Math.max(bucketTotal, readCount(usage.total_tokens));
|
|
1272
|
+
const reportedInput = readReportedCount(usage.input_tokens);
|
|
1273
|
+
const reportedOutput = readReportedCount(usage.output_tokens);
|
|
1274
|
+
const reportedTotal = readReportedCount(usage.total_tokens);
|
|
2441
1275
|
return {
|
|
2442
1276
|
input,
|
|
2443
1277
|
output,
|
|
2444
1278
|
cacheRead,
|
|
2445
1279
|
cacheWrite,
|
|
2446
|
-
|
|
1280
|
+
contextUsage: reportedInput !== void 0 && (reportedOutput !== void 0 || reportedTotal !== void 0 && reportedTotal >= reportedInput) && cacheRead + cacheWrite <= reportedInput ? {
|
|
1281
|
+
state: "available",
|
|
1282
|
+
promptTokens: reportedInput,
|
|
1283
|
+
totalTokens: Math.max(totalTokens, reportedInput + (reportedOutput ?? 0))
|
|
1284
|
+
} : { state: "unavailable" },
|
|
1285
|
+
totalTokens
|
|
2447
1286
|
};
|
|
2448
1287
|
}
|
|
2449
1288
|
/** Reasoning tokens are reported by the agent path only; the package path does not track them. */
|
|
@@ -2509,51 +1348,52 @@ function createResponsesTerminalController(params) {
|
|
|
2509
1348
|
const { output, stream, model, options } = params;
|
|
2510
1349
|
const blocks = output.content;
|
|
2511
1350
|
const backfillReasoning = (items) => {
|
|
2512
|
-
for (const item of items) {
|
|
1351
|
+
for (const [outputIndex, item] of items.entries()) {
|
|
2513
1352
|
if (item.type !== "reasoning" || !item.encrypted_content) continue;
|
|
2514
|
-
const
|
|
2515
|
-
|
|
1353
|
+
const tracked = params.outputs.get(item, outputIndex);
|
|
1354
|
+
const block = tracked && blocks[tracked.contentIndex];
|
|
1355
|
+
if (block?.type !== "thinking" || !block.thinkingSignature) continue;
|
|
2516
1356
|
const stored = JSON.parse(block.thinkingSignature);
|
|
2517
1357
|
if (!stored.encrypted_content) block.thinkingSignature = JSON.stringify({
|
|
2518
1358
|
...stored,
|
|
2519
1359
|
encrypted_content: item.encrypted_content
|
|
2520
1360
|
});
|
|
2521
|
-
if (options?.reasoningReplayMetadata) block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY]
|
|
1361
|
+
if (options?.reasoningReplayMetadata) Object.assign(block, { [OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY]: options.reasoningReplayMetadata });
|
|
2522
1362
|
}
|
|
2523
1363
|
};
|
|
2524
|
-
const appendText = (item) => {
|
|
1364
|
+
const appendText = (item, contentIndex) => {
|
|
2525
1365
|
const text = (Array.isArray(item.content) ? item.content : []).map((part) => {
|
|
2526
1366
|
const content = part;
|
|
2527
1367
|
return content.type === "output_text" || content.type === "text" ? content.text ?? "" : content.refusal ?? "";
|
|
2528
1368
|
}).join("");
|
|
2529
|
-
const
|
|
1369
|
+
const block = contentIndex === void 0 ? void 0 : blocks[contentIndex];
|
|
1370
|
+
const started = block?.type === "text" ? block : void 0;
|
|
2530
1371
|
if (!text && !started) return;
|
|
2531
1372
|
const phase = item.phase ?? void 0;
|
|
2532
|
-
if (started) {
|
|
2533
|
-
const previousText = started.
|
|
2534
|
-
started.
|
|
2535
|
-
started.
|
|
1373
|
+
if (started && contentIndex !== void 0) {
|
|
1374
|
+
const previousText = started.text;
|
|
1375
|
+
started.text = text;
|
|
1376
|
+
started.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2536
1377
|
params.setLastTextBlock({
|
|
2537
|
-
block: started
|
|
2538
|
-
index:
|
|
1378
|
+
block: started,
|
|
1379
|
+
index: contentIndex,
|
|
2539
1380
|
phase
|
|
2540
1381
|
});
|
|
2541
|
-
params.startedTextBlocksByItemId.delete(item.id);
|
|
2542
1382
|
if (text.startsWith(previousText)) {
|
|
2543
1383
|
const delta = text.slice(previousText.length);
|
|
2544
1384
|
if (delta) stream.push({
|
|
2545
1385
|
type: "text_delta",
|
|
2546
|
-
contentIndex
|
|
1386
|
+
contentIndex,
|
|
2547
1387
|
delta
|
|
2548
1388
|
});
|
|
2549
1389
|
}
|
|
2550
1390
|
stream.push({
|
|
2551
1391
|
type: "text_end",
|
|
2552
|
-
contentIndex
|
|
1392
|
+
contentIndex,
|
|
2553
1393
|
content: text,
|
|
2554
1394
|
partial: output
|
|
2555
1395
|
});
|
|
2556
|
-
return
|
|
1396
|
+
return contentIndex;
|
|
2557
1397
|
}
|
|
2558
1398
|
const previous = params.getLastTextBlock();
|
|
2559
1399
|
const collapse = resolveResponsesMessageSnapshotCollapse({
|
|
@@ -2575,15 +1415,15 @@ function createResponsesTerminalController(params) {
|
|
|
2575
1415
|
});
|
|
2576
1416
|
return previous.index;
|
|
2577
1417
|
}
|
|
2578
|
-
const
|
|
1418
|
+
const newBlock = {
|
|
2579
1419
|
type: "text",
|
|
2580
1420
|
text,
|
|
2581
1421
|
textSignature: encodeTextSignatureV1(item.id, phase)
|
|
2582
1422
|
};
|
|
2583
|
-
blocks.push(
|
|
1423
|
+
blocks.push(newBlock);
|
|
2584
1424
|
const index = blocks.length - 1;
|
|
2585
1425
|
params.setLastTextBlock({
|
|
2586
|
-
block,
|
|
1426
|
+
block: newBlock,
|
|
2587
1427
|
index,
|
|
2588
1428
|
phase
|
|
2589
1429
|
});
|
|
@@ -2600,65 +1440,71 @@ function createResponsesTerminalController(params) {
|
|
|
2600
1440
|
});
|
|
2601
1441
|
return index;
|
|
2602
1442
|
};
|
|
2603
|
-
const
|
|
2604
|
-
const
|
|
2605
|
-
|
|
1443
|
+
const emitToolCallCompletion = (item, outputIndex, started, validated) => {
|
|
1444
|
+
const completed = {
|
|
1445
|
+
id: resolveResponsesToolCallId(item, started?.block.id),
|
|
1446
|
+
...validated
|
|
1447
|
+
};
|
|
1448
|
+
const toolCall = started ? Object.assign(started.block, completed) : {
|
|
2606
1449
|
type: "toolCall",
|
|
2607
|
-
|
|
2608
|
-
name: validated.name,
|
|
2609
|
-
arguments: validated.arguments
|
|
1450
|
+
...completed
|
|
2610
1451
|
};
|
|
2611
|
-
|
|
2612
|
-
const contentIndex = blocks.length
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
1452
|
+
delete toolCall.partialJson;
|
|
1453
|
+
const contentIndex = started?.contentIndex ?? blocks.length;
|
|
1454
|
+
if (!started) {
|
|
1455
|
+
blocks.push(toolCall);
|
|
1456
|
+
stream.push({
|
|
1457
|
+
type: "toolcall_start",
|
|
1458
|
+
contentIndex,
|
|
1459
|
+
partial: output
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
params.outputs.set(item, contentIndex, outputIndex, true);
|
|
2618
1463
|
stream.push({
|
|
2619
1464
|
type: "toolcall_end",
|
|
2620
1465
|
contentIndex,
|
|
2621
1466
|
toolCall,
|
|
2622
1467
|
partial: output
|
|
2623
1468
|
});
|
|
2624
|
-
return contentIndex;
|
|
2625
1469
|
};
|
|
2626
|
-
const recoverTerminalOutput = (items,
|
|
1470
|
+
const recoverTerminalOutput = (items, completeToolCall) => {
|
|
2627
1471
|
let hasCompletedLaterOutput = false;
|
|
2628
|
-
for (const item of items.toReversed()) {
|
|
1472
|
+
for (const [outputIndex, item] of [...items.entries()].toReversed()) {
|
|
1473
|
+
const tracked = params.outputs.get(item, outputIndex);
|
|
2629
1474
|
if (item.type === "reasoning") {
|
|
2630
|
-
hasCompletedLaterOutput ||=
|
|
1475
|
+
hasCompletedLaterOutput ||= tracked !== void 0;
|
|
2631
1476
|
continue;
|
|
2632
1477
|
}
|
|
2633
1478
|
if (item.type !== "message" && item.type !== "function_call") continue;
|
|
2634
|
-
if (
|
|
1479
|
+
if (tracked) {
|
|
2635
1480
|
hasCompletedLaterOutput = true;
|
|
2636
1481
|
continue;
|
|
2637
1482
|
}
|
|
2638
|
-
if (item.type === "function_call" && !
|
|
1483
|
+
if (item.type === "function_call" && !completeToolCall) continue;
|
|
2639
1484
|
if (hasCompletedLaterOutput) throw new Error("Responses stream omitted an output item before completed output");
|
|
2640
|
-
if (item.type === "function_call") resolveCompletedResponsesToolCall(item);
|
|
2641
1485
|
}
|
|
2642
1486
|
for (const [terminalIndex, item] of items.entries()) if (item.type === "message") {
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
1487
|
+
const tracked = params.outputs.get(item, terminalIndex);
|
|
1488
|
+
if (tracked?.completed) continue;
|
|
1489
|
+
const appendedIndex = appendText(item, tracked?.contentIndex);
|
|
1490
|
+
if (appendedIndex !== void 0) params.outputs.set(item, appendedIndex, terminalIndex, true);
|
|
2646
1491
|
} else {
|
|
2647
1492
|
params.setLastTextBlock(null);
|
|
2648
1493
|
const alreadyCapturedCompaction = item.type === "compaction" && output.providerReplay?.type === "openai-responses-compaction" && output.providerReplay.id === item.id && output.providerReplay.data === item.encrypted_content;
|
|
2649
1494
|
if (item.type === "compaction" && !alreadyCapturedCompaction) {
|
|
2650
1495
|
let replayIndex = blocks.length;
|
|
2651
|
-
for (const laterItem of items.
|
|
2652
|
-
|
|
1496
|
+
for (const [laterIndex, laterItem] of items.entries()) {
|
|
1497
|
+
if (laterIndex <= terminalIndex) continue;
|
|
1498
|
+
const laterContentIndex = params.outputs.get(laterItem, laterIndex)?.contentIndex;
|
|
2653
1499
|
if (laterContentIndex !== void 0) {
|
|
2654
1500
|
replayIndex = laterContentIndex;
|
|
2655
1501
|
break;
|
|
2656
1502
|
}
|
|
2657
1503
|
}
|
|
2658
1504
|
captureOpenAIResponsesCompaction(output, item, replayIndex, model, options?.reasoningReplayMetadata);
|
|
2659
|
-
} else if (
|
|
2660
|
-
if (params.
|
|
2661
|
-
|
|
1505
|
+
} else if (completeToolCall && item.type === "function_call") {
|
|
1506
|
+
if (params.outputs.get(item, terminalIndex)?.completed) continue;
|
|
1507
|
+
completeToolCall(terminalIndex);
|
|
2662
1508
|
}
|
|
2663
1509
|
}
|
|
2664
1510
|
};
|
|
@@ -2685,7 +1531,6 @@ function createResponsesTerminalController(params) {
|
|
|
2685
1531
|
}
|
|
2686
1532
|
};
|
|
2687
1533
|
const finalizeResponse = (response, terminalEventType) => {
|
|
2688
|
-
params.markFinalized();
|
|
2689
1534
|
backfillReasoning(response.output ?? []);
|
|
2690
1535
|
finalizeTerminalFacts(response);
|
|
2691
1536
|
const terminal = resolveResponsesTerminalStopReason({
|
|
@@ -2700,7 +1545,8 @@ function createResponsesTerminalController(params) {
|
|
|
2700
1545
|
return {
|
|
2701
1546
|
finalizeResponse,
|
|
2702
1547
|
finalizeFailedResponse: finalizeTerminalFacts,
|
|
2703
|
-
recoverTerminalOutput
|
|
1548
|
+
recoverTerminalOutput,
|
|
1549
|
+
emitToolCallCompletion
|
|
2704
1550
|
};
|
|
2705
1551
|
}
|
|
2706
1552
|
//#endregion
|
|
@@ -2708,9 +1554,7 @@ function createResponsesTerminalController(params) {
|
|
|
2708
1554
|
async function processResponsesStream(openaiStream, output, stream, model, options) {
|
|
2709
1555
|
const streamingToolCalls = createResponsesToolCallTracker();
|
|
2710
1556
|
const outputSlots = createResponsesOutputSlotTracker();
|
|
2711
|
-
const
|
|
2712
|
-
const outputItemContentIndexes = createResponsesOutputContentIndex();
|
|
2713
|
-
const startedTextBlocksByItemId = /* @__PURE__ */ new Map();
|
|
1557
|
+
const outputs = createResponsesOutputTracker();
|
|
2714
1558
|
let terminalResponse;
|
|
2715
1559
|
let lastTextBlock = null;
|
|
2716
1560
|
const blocks = output.content;
|
|
@@ -2725,11 +1569,11 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2725
1569
|
type: "thinking",
|
|
2726
1570
|
item,
|
|
2727
1571
|
block,
|
|
2728
|
-
contentIndex: blocks.length
|
|
1572
|
+
contentIndex: blocks.length,
|
|
1573
|
+
outputIndex: readResponsesOutputIndex(event)
|
|
2729
1574
|
};
|
|
2730
1575
|
blocks.push(block);
|
|
2731
|
-
|
|
2732
|
-
outputItemContentIndexes.set(item, slot.contentIndex);
|
|
1576
|
+
outputs.set(item, slot.contentIndex, slot.outputIndex);
|
|
2733
1577
|
outputSlots.register(event, slot);
|
|
2734
1578
|
stream.push({
|
|
2735
1579
|
type: "thinking_start",
|
|
@@ -2751,17 +1595,13 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2751
1595
|
item: messageItem,
|
|
2752
1596
|
block,
|
|
2753
1597
|
contentIndex: block ? blocks.length : void 0,
|
|
1598
|
+
outputIndex: readResponsesOutputIndex(event),
|
|
2754
1599
|
pendingText: collapseCandidate ? "" : null,
|
|
2755
1600
|
collapseCandidate
|
|
2756
1601
|
};
|
|
2757
1602
|
if (block) {
|
|
2758
1603
|
blocks.push(block);
|
|
2759
|
-
|
|
2760
|
-
startedTextBlocksByItemId.set(messageItem.id, {
|
|
2761
|
-
block,
|
|
2762
|
-
index: slot.contentIndex ?? blocks.length - 1,
|
|
2763
|
-
phase: messageItem.phase ?? void 0
|
|
2764
|
-
});
|
|
1604
|
+
outputs.set(messageItem, slot.contentIndex ?? blocks.length - 1, slot.outputIndex);
|
|
2765
1605
|
}
|
|
2766
1606
|
outputSlots.register(event, slot);
|
|
2767
1607
|
if (slot.contentIndex !== void 0) stream.push({
|
|
@@ -2777,9 +1617,6 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2777
1617
|
if (item.type === "message") return outputSlots.resolve(event, "text");
|
|
2778
1618
|
return readResponsesOutputIndex(event) === void 0 ? void 0 : outputSlots.get(event);
|
|
2779
1619
|
};
|
|
2780
|
-
const getOrCreateOutputSlot = (event, item) => {
|
|
2781
|
-
return resolveOutputItemSlot(event, item) ?? createOutputSlot(event, item);
|
|
2782
|
-
};
|
|
2783
1620
|
const materializeDeferredTextSlot = (slot) => {
|
|
2784
1621
|
if (slot.block || slot.pendingText === null) return;
|
|
2785
1622
|
const text = slot.pendingText;
|
|
@@ -2790,12 +1627,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2790
1627
|
};
|
|
2791
1628
|
blocks.push(slot.block);
|
|
2792
1629
|
slot.contentIndex = blocks.length - 1;
|
|
2793
|
-
|
|
2794
|
-
startedTextBlocksByItemId.set(slot.item.id, {
|
|
2795
|
-
block: slot.block,
|
|
2796
|
-
index: slot.contentIndex,
|
|
2797
|
-
phase: slot.item.phase ?? void 0
|
|
2798
|
-
});
|
|
1630
|
+
outputs.set(slot.item, slot.contentIndex, slot.outputIndex);
|
|
2799
1631
|
stream.push({
|
|
2800
1632
|
type: "text_start",
|
|
2801
1633
|
contentIndex: slot.contentIndex,
|
|
@@ -2813,20 +1645,58 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2813
1645
|
const materializeDeferredTextSlots = (except) => {
|
|
2814
1646
|
for (const slot of outputSlots.values()) if (slot !== except && slot.type === "text") materializeDeferredTextSlot(slot);
|
|
2815
1647
|
};
|
|
2816
|
-
const
|
|
1648
|
+
const terminal = createResponsesTerminalController({
|
|
2817
1649
|
output,
|
|
2818
1650
|
stream,
|
|
2819
1651
|
model,
|
|
2820
1652
|
options,
|
|
2821
|
-
|
|
2822
|
-
startedTextBlocksByItemId,
|
|
2823
|
-
outputItemContentIndexes,
|
|
1653
|
+
outputs,
|
|
2824
1654
|
getLastTextBlock: () => lastTextBlock,
|
|
2825
1655
|
setLastTextBlock: (block) => {
|
|
2826
1656
|
lastTextBlock = block;
|
|
2827
|
-
}
|
|
2828
|
-
markFinalized: () => void 0
|
|
1657
|
+
}
|
|
2829
1658
|
});
|
|
1659
|
+
const finalizeToolCall = (item, outputIndex, streamingToolCall, validated) => {
|
|
1660
|
+
const identity = {
|
|
1661
|
+
type: item.type,
|
|
1662
|
+
id: item.id || streamingToolCall?.itemId,
|
|
1663
|
+
call_id: item.call_id || streamingToolCall?.callId
|
|
1664
|
+
};
|
|
1665
|
+
const finalOutputIndex = outputIndex ?? streamingToolCall?.outputIndex;
|
|
1666
|
+
if (finalOutputIndex === void 0 && !identity.id && !identity.call_id) {
|
|
1667
|
+
if (!streamingToolCall) throw new Error("Responses stream completed tool call without an output identity");
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
if (streamingToolCall) {
|
|
1671
|
+
streamingToolCalls.forget(streamingToolCall);
|
|
1672
|
+
for (const slot of outputSlots.values()) if (slot.type === "toolCall" && slot.toolCall === streamingToolCall) outputSlots.forget(slot);
|
|
1673
|
+
}
|
|
1674
|
+
terminal.emitToolCallCompletion(identity, finalOutputIndex, streamingToolCall, validated);
|
|
1675
|
+
};
|
|
1676
|
+
const prepareTerminalToolCalls = (items) => {
|
|
1677
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
1678
|
+
const recovered = [];
|
|
1679
|
+
const callIds = /* @__PURE__ */ new Set();
|
|
1680
|
+
const allowUnmatchedIdentity = items.filter((item, index) => item.type === "function_call" && !outputs.get(item, index)?.completed).length === 1;
|
|
1681
|
+
for (const [outputIndex, item] of items.entries()) {
|
|
1682
|
+
const tracked = outputs.get(item, outputIndex);
|
|
1683
|
+
if (item.type !== "function_call") continue;
|
|
1684
|
+
if (item.call_id && callIds.has(item.call_id)) throw new Error("Responses stream repeated a terminal tool-call identity");
|
|
1685
|
+
if (item.call_id) callIds.add(item.call_id);
|
|
1686
|
+
if (tracked?.completed) continue;
|
|
1687
|
+
const state = streamingToolCalls.resolve({ output_index: outputIndex }, readResponsesToolCallItemIdentity(item), allowUnmatchedIdentity);
|
|
1688
|
+
if (tracked && !state) throw new Error("Responses stream completed with unresolved tool calls");
|
|
1689
|
+
const validated = resolveCompletedResponsesToolCall(item, { name: state?.block.name });
|
|
1690
|
+
if (state) recovered.push(state);
|
|
1691
|
+
prepared.set(outputIndex, () => finalizeToolCall(item, outputIndex, state, validated));
|
|
1692
|
+
}
|
|
1693
|
+
if (!streamingToolCalls.hasExactlyActive(recovered)) throw new Error("Responses stream completed with unresolved tool calls");
|
|
1694
|
+
return (outputIndex) => {
|
|
1695
|
+
const complete = prepared.get(outputIndex);
|
|
1696
|
+
if (!complete) throw new Error("Responses stream completed with unresolved tool calls");
|
|
1697
|
+
complete();
|
|
1698
|
+
};
|
|
1699
|
+
};
|
|
2830
1700
|
const guardedStream = adaptResponsesStream(withFirstStreamEventTimeout(openaiStream, {
|
|
2831
1701
|
provider: model.provider,
|
|
2832
1702
|
api: model.api,
|
|
@@ -2860,6 +1730,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2860
1730
|
block: toolCallBlock,
|
|
2861
1731
|
contentIndex,
|
|
2862
1732
|
argumentStreamReliable: true,
|
|
1733
|
+
previewSchedule: createToolArgumentPreviewSchedule(),
|
|
2863
1734
|
...readResponsesToolCallItemIdentity(item)
|
|
2864
1735
|
};
|
|
2865
1736
|
streamingToolCalls.register(event, toolCallState);
|
|
@@ -2868,7 +1739,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2868
1739
|
toolCall: toolCallState
|
|
2869
1740
|
});
|
|
2870
1741
|
output.content.push(toolCallBlock);
|
|
2871
|
-
|
|
1742
|
+
outputs.set(item, contentIndex, readResponsesOutputIndex(event));
|
|
2872
1743
|
stream.push({
|
|
2873
1744
|
type: "toolcall_start",
|
|
2874
1745
|
contentIndex,
|
|
@@ -2994,7 +1865,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2994
1865
|
const toolCall = streamingToolCalls.resolve(event);
|
|
2995
1866
|
if (toolCall) {
|
|
2996
1867
|
toolCall.block.partialJson += event.delta;
|
|
2997
|
-
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
1868
|
+
if (toolCall.previewSchedule(toolCall.block.partialJson.length)) toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
2998
1869
|
stream.push({
|
|
2999
1870
|
type: "toolcall_delta",
|
|
3000
1871
|
contentIndex: toolCall.contentIndex,
|
|
@@ -3027,13 +1898,14 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3027
1898
|
if (item.type !== "message") lastTextBlock = null;
|
|
3028
1899
|
const existingOutputSlot = resolveOutputItemSlot(event, item);
|
|
3029
1900
|
materializeDeferredTextSlots(existingOutputSlot);
|
|
3030
|
-
const outputSlot = existingOutputSlot ??
|
|
1901
|
+
const outputSlot = existingOutputSlot ?? createOutputSlot(event, item);
|
|
3031
1902
|
compactionTracker.completed(item, blocks.length);
|
|
3032
1903
|
if (item.type === "reasoning" && outputSlot?.type === "thinking") {
|
|
3033
1904
|
const summaryText = item.summary?.map((s) => s.text).join("\n\n") || "";
|
|
3034
1905
|
const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
|
|
3035
1906
|
outputSlot.block.thinking = summaryText || contentText || outputSlot.block.thinking;
|
|
3036
1907
|
outputSlot.block.thinkingSignature = JSON.stringify(item);
|
|
1908
|
+
outputs.set(item, outputSlot.contentIndex, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
|
|
3037
1909
|
if (item.encrypted_content && options?.reasoningReplayMetadata) outputSlot.block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
|
|
3038
1910
|
stream.push({
|
|
3039
1911
|
type: "thinking_end",
|
|
@@ -3065,7 +1937,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3065
1937
|
partial: output
|
|
3066
1938
|
});
|
|
3067
1939
|
lastTextBlock = outputSlot.collapseCandidate;
|
|
3068
|
-
|
|
1940
|
+
outputs.set(item, outputSlot.collapseCandidate.index, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
|
|
3069
1941
|
} else {
|
|
3070
1942
|
if (!outputSlot.block) {
|
|
3071
1943
|
outputSlot.block = {
|
|
@@ -3090,7 +1962,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3090
1962
|
index: contentIndex,
|
|
3091
1963
|
phase
|
|
3092
1964
|
};
|
|
3093
|
-
|
|
1965
|
+
outputs.set(item, contentIndex, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
|
|
3094
1966
|
stream.push({
|
|
3095
1967
|
type: "text_end",
|
|
3096
1968
|
contentIndex,
|
|
@@ -3099,66 +1971,33 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
3099
1971
|
});
|
|
3100
1972
|
}
|
|
3101
1973
|
outputSlots.forget(outputSlot);
|
|
3102
|
-
startedTextBlocksByItemId.delete(item.id);
|
|
3103
1974
|
} else if (item.type === "function_call") {
|
|
1975
|
+
if (outputs.get(item, readResponsesOutputIndex(event))?.completed) continue;
|
|
3104
1976
|
const streamingToolCall = streamingToolCalls.resolve(event, readResponsesToolCallItemIdentity(item));
|
|
3105
1977
|
if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
|
|
3106
|
-
const streamedArguments = streamingToolCall?.block.partialJson ?? "";
|
|
3107
1978
|
const completedArguments = typeof item.arguments === "string" ? item.arguments : void 0;
|
|
3108
1979
|
if (streamingToolCall && !streamingToolCall.argumentStreamReliable && !completedArguments) continue;
|
|
3109
|
-
const finalArguments = completedArguments !== void 0 && (completedArguments.length > 0 || !streamedArguments) ? completedArguments : streamedArguments;
|
|
3110
1980
|
const validated = resolveCompletedResponsesToolCall(item, {
|
|
3111
1981
|
name: streamingToolCall?.block.name,
|
|
3112
|
-
arguments:
|
|
1982
|
+
arguments: completedArguments || streamingToolCall?.block.partialJson || ""
|
|
3113
1983
|
});
|
|
3114
|
-
|
|
3115
|
-
let contentIndex;
|
|
3116
|
-
if (streamingToolCall) {
|
|
3117
|
-
const block = streamingToolCall.block;
|
|
3118
|
-
block.id = resolveResponsesToolCallId(item, block.id);
|
|
3119
|
-
block.name = validated.name;
|
|
3120
|
-
block.arguments = validated.arguments;
|
|
3121
|
-
delete block.partialJson;
|
|
3122
|
-
toolCall = block;
|
|
3123
|
-
contentIndex = streamingToolCall.contentIndex;
|
|
3124
|
-
} else {
|
|
3125
|
-
toolCall = {
|
|
3126
|
-
type: "toolCall",
|
|
3127
|
-
id: resolveResponsesToolCallId(item),
|
|
3128
|
-
name: validated.name,
|
|
3129
|
-
arguments: validated.arguments
|
|
3130
|
-
};
|
|
3131
|
-
blocks.push(toolCall);
|
|
3132
|
-
contentIndex = blocks.length - 1;
|
|
3133
|
-
stream.push({
|
|
3134
|
-
type: "toolcall_start",
|
|
3135
|
-
contentIndex,
|
|
3136
|
-
partial: output
|
|
3137
|
-
});
|
|
3138
|
-
}
|
|
3139
|
-
if (streamingToolCall) {
|
|
3140
|
-
streamingToolCalls.forget(streamingToolCall);
|
|
3141
|
-
for (const slot of outputSlots.values()) if (slot.type === "toolCall" && slot.toolCall === streamingToolCall) outputSlots.forget(slot);
|
|
3142
|
-
}
|
|
3143
|
-
stream.push({
|
|
3144
|
-
type: "toolcall_end",
|
|
3145
|
-
contentIndex,
|
|
3146
|
-
toolCall,
|
|
3147
|
-
partial: output
|
|
3148
|
-
});
|
|
3149
|
-
outputItemContentIndexes.set(item, contentIndex);
|
|
1984
|
+
finalizeToolCall(item, readResponsesOutputIndex(event), streamingToolCall, validated);
|
|
3150
1985
|
}
|
|
3151
1986
|
} else if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
3152
|
-
if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
|
|
3153
|
-
finalizeResponse(event.response, event.type);
|
|
3154
|
-
if (event.type === "response.completed" || output.stopReason === "length")
|
|
1987
|
+
if (event.type === "response.incomplete" && streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
|
|
1988
|
+
terminal.finalizeResponse(event.response, event.type);
|
|
1989
|
+
if (event.type === "response.completed" || output.stopReason === "length") {
|
|
1990
|
+
const items = event.response.output ?? [];
|
|
1991
|
+
const completeToolCall = event.type === "response.completed" ? prepareTerminalToolCalls(items) : void 0;
|
|
1992
|
+
terminal.recoverTerminalOutput(items, completeToolCall);
|
|
1993
|
+
}
|
|
3155
1994
|
terminalResponse = event.type === "response.completed" ? event.response : null;
|
|
3156
1995
|
if (output.stopReason === "stop" && output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
|
|
3157
1996
|
break;
|
|
3158
1997
|
} else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
|
|
3159
1998
|
else if (event.type === "response.failed") {
|
|
3160
1999
|
const failure = normalizeResponsesFailedEvent(isRecord(event) ? event : {}, model);
|
|
3161
|
-
finalizeFailedResponse(event.response, failure.responseId);
|
|
2000
|
+
terminal.finalizeFailedResponse(event.response, failure.responseId);
|
|
3162
2001
|
throw new ResponsesStreamFailure(failure, event.response);
|
|
3163
2002
|
}
|
|
3164
2003
|
}
|
|
@@ -3312,26 +2151,34 @@ async function runResponsesStreamLifecycle(params) {
|
|
|
3312
2151
|
return request;
|
|
3313
2152
|
};
|
|
3314
2153
|
const requestParams = await buildRequest("checkpoint");
|
|
3315
|
-
|
|
3316
|
-
|
|
2154
|
+
const firstEvent = createFirstStreamEventAbortController(options?.signal);
|
|
2155
|
+
firstEventAbort = firstEvent;
|
|
2156
|
+
let started = false;
|
|
2157
|
+
const { stream: hookedOpenAIStream } = await createResponsesStreamWithEncryptedContentRetry({
|
|
3317
2158
|
client,
|
|
3318
2159
|
request: requestParams,
|
|
3319
2160
|
requestOptions: {
|
|
3320
2161
|
...buildResponsesRequestOptions(options),
|
|
3321
|
-
signal:
|
|
2162
|
+
signal: firstEvent.signal
|
|
3322
2163
|
},
|
|
3323
2164
|
model,
|
|
3324
2165
|
buildFullHistoryRequest: () => buildRequest("full-history"),
|
|
3325
|
-
onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint)
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
2166
|
+
onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint),
|
|
2167
|
+
canRetryStream: () => output.content.length === 0,
|
|
2168
|
+
wrapStream: ({ stream: openaiStream, response }) => withProviderResponseHook({
|
|
2169
|
+
stream: openaiStream,
|
|
2170
|
+
signal: firstEvent.signal,
|
|
2171
|
+
abort: firstEvent.abort,
|
|
2172
|
+
hook: createOpenAIProviderAcceptanceHook(options, response, model),
|
|
2173
|
+
onReady: () => {
|
|
2174
|
+
if (!started) {
|
|
2175
|
+
started = true;
|
|
2176
|
+
stream.push({
|
|
2177
|
+
type: "start",
|
|
2178
|
+
partial: output
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
3335
2182
|
})
|
|
3336
2183
|
});
|
|
3337
2184
|
const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
|
|
@@ -3372,4 +2219,4 @@ async function runResponsesStreamLifecycle(params) {
|
|
|
3372
2219
|
}
|
|
3373
2220
|
}
|
|
3374
2221
|
//#endregion
|
|
3375
|
-
export {
|
|
2222
|
+
export { isAzureResponsesTextDeltaEvent as A, buildResponsesInputMessage as B, summarizeResponsesTools as C, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as D, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as E, commitResponsesEncryptedContentAttempt as F, captureOpenAIResponsesCompaction as G, createOpenAIResponsesAssistantOutput as H, createResponsesStreamWithEncryptedContentRetry as I, resolveReplayableResponsesMessageId as J, resolveNewestOpenAIResponsesCompactionReplay as K, isInvalidEncryptedContentError as L, isResponsesTextContentPartType as M, isResponsesTextDeltaEventType as N, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as O, resolveResponsesMessageSnapshotCollapse as P, resolveAzureOpenAIApiVersion as R, summarizeResponsesPayload as S, readResponsesToolCallItemIdentity as T, CompactionReplayRefreshRequiredError as U, convertResponsesMessages$1 as V, buildOpenAIResponsesReasoningReplayMetadata as W, resolveModelPayloadDebugMode as X, emitModelTransportDebug as Y, resolveModelSseDebugMode as Z, safeDebugValue as _, resolveResponsesReasoningEffort as a, summarizeOpenAITransportError as b, processResponsesStream as c, resolveResponsesTerminalStopReason as d, observeResponsesStream as f, normalizeResponsesFailedEvent as g, logResponsesFailedNoDetails as h, createResponsesAssistantOutput as i, isAzureResponsesTextDeltaEventType as j, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as k, mapResponsesTerminalUsage as l, buildResponsesFailedNoDetailsObservation as m, applyResponsesServiceTierPricing as n, runResponsesStreamLifecycle as o, ResponsesStreamFailure as p, suppressOpenAIResponsesCompaction as q, convertResponsesMessages as r, convertResponsesToolPayload as s, applyCommonResponsesParams as t, readResponsesReasoningTokens as u, stringifyRedactedEvent as v, createResponsesToolCallTracker as w, summarizeResponsesFailedNoDetailsObservation as x, stringifyRedactedPayload as y, resolveNextResponsesEncryptedContentAttempt as z };
|