@openclaw/ai 2026.8.1-beta.1 → 2026.8.1-beta.3
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-CE-7SkF6.mjs → anthropic-B8KwTtlb.mjs} +62 -37
- package/dist/{anthropic-SrGtwsJu.d.mts → anthropic-BECQCNdF.d.mts} +0 -2
- package/dist/{src-QkygScBs.mjs → anthropic-BQXQudmA.mjs} +0 -2
- package/dist/{anthropic-usage-Ma4iX6uG.mjs → anthropic-compaction-replay-4Zx7-aCr.mjs} +225 -103
- package/dist/anthropic-payload-policy-CSx7MoKH.d.mts +50 -0
- package/dist/{api-registry-EpJoVwM1.d.mts → api-registry-DFxSnFqG.d.mts} +1 -1
- package/dist/{azure-openai-responses-Cc_kasye.mjs → azure-openai-responses-Aa4mVcYG.mjs} +23 -29
- package/dist/diagnostics.d.mts +24 -1
- package/dist/diagnostics.mjs +2 -1
- package/dist/event-stream-BVVgDSdq.d.mts +1 -0
- package/dist/{event-stream-DRmDMRHH.d.mts → event-stream-D91-ohD_.d.mts} +3 -1
- package/dist/{event-stream-CEV9t6da.mjs → event-stream-uSMZJ3FA.mjs} +16 -3
- package/dist/event-stream.d.mts +1 -1
- package/dist/event-stream.mjs +1 -1
- package/dist/{google-shared-Cq2UKx1l.mjs → google-shared-M1dl64nz.mjs} +17 -19
- package/dist/google-thinking-level-C-V3tecN.mjs +9 -0
- package/dist/{google-vertex-CusxWzvE.mjs → google-vertex-DCJHM_a5.mjs} +5 -4
- package/dist/{google-CGQu21aw.mjs → google-yDRnipeq.mjs} +4 -4
- package/dist/host-DF_yxOsA.mjs +477 -0
- package/dist/{host-Dn4_SZI2.d.mts → host-DJq_FGcz.d.mts} +13 -8
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +7 -5
- package/dist/internal/anthropic.d.mts +21 -7
- package/dist/internal/anthropic.mjs +5 -5
- package/dist/internal/openai-responses-payload-policy.d.mts +3 -0
- package/dist/internal/openai-responses-payload-policy.mjs +3 -0
- package/dist/internal/openai.d.mts +6 -6
- package/dist/internal/openai.mjs +9 -7
- package/dist/internal/runtime.d.mts +19 -5
- package/dist/internal/runtime.mjs +85 -72
- package/dist/internal/shared.d.mts +17 -8
- package/dist/internal/shared.mjs +4 -5
- package/dist/{json-parse-BvXNt1-7.mjs → json-parse-CDnesDM_.mjs} +4 -6
- package/dist/{mistral-Dx6VzNjf.mjs → mistral-D6hRXI7A.mjs} +67 -72
- package/dist/{number-coercion-1Miyb5MO.mjs → number-coercion-H9qHik3g.mjs} +7 -2
- package/dist/openai-chatgpt-jwt-KWcgd0d_.mjs +19 -0
- package/dist/{openai-chatgpt-responses-SC9m0FSf.mjs → openai-chatgpt-responses-C339VIfT.mjs} +235 -146
- package/dist/{openai-completions-BaIpl93j.mjs → openai-completions-D88orSJ9.mjs} +88 -67
- package/dist/openai-completions-compat-B0KTleXp.d.mts +43 -0
- package/dist/{openai-responses-Bdx3V_Yu.mjs → openai-responses-BXEcr-Tp.mjs} +17 -24
- package/dist/openai-responses-contracts-CD75pQ0m.d.mts +68 -0
- package/dist/openai-responses-contracts-DvILoqBk.mjs +247 -0
- package/dist/openai-responses-payload-policy-BDo8CQsx.mjs +208 -0
- package/dist/openai-responses-payload-policy-CNGFT9zr.d.mts +41 -0
- package/dist/{openai-responses-prompt-observer-internal-DDZPxRfr.mjs → openai-responses-prompt-observer-internal-BG-1AsBI.mjs} +2 -3
- package/dist/{openai-responses-stream-internal-Bl8YyVtF.mjs → openai-responses-shared-Cvt5MgEm.mjs} +1287 -1039
- package/dist/{openai-reasoning-compat-DKebnIBL.mjs → openai-stop-reason-9OONKyAm.mjs} +222 -180
- package/dist/{openai-transport-shared-Cipt7egQ.mjs → openai-tool-projection-CHGLt03m.mjs} +239 -128
- package/dist/provider-error-C8mBRJDl.mjs +424 -0
- package/dist/provider-error-CzNw4BWX.d.mts +12 -0
- package/dist/provider-options-AvldWZt8.mjs +21 -0
- package/dist/{provider-options-C5kYML7i.d.mts → provider-options-Cc5ZQ6Aa.d.mts} +19 -3
- package/dist/provider-transcript-transform--gtf0ZbR.mjs +32 -0
- package/dist/provider-types.d.mts +31 -0
- package/dist/provider-types.mjs +8 -0
- package/dist/providers.d.mts +1 -1
- package/dist/providers.mjs +17 -19
- package/dist/{reasoning-tag-text-partitioner-CGDyLWUR.mjs → reasoning-tag-text-partitioner-5ygO2rZc.mjs} +17 -8
- package/dist/record-coerce-DdXsgUd_.mjs +23 -0
- package/dist/{model-utils-Dau5dlgm.mjs → sanitize-unicode-BP7HLLZn.mjs} +28 -2
- package/dist/session-resources-CkR4WWy1.mjs +21 -0
- package/dist/simple-options-oqsXB6U3.mjs +450 -0
- package/dist/src-D2H6yKkH.mjs +2 -0
- package/dist/{stream-first-event-timeout-BIBomOGq.mjs → stream-first-event-timeout-MK28puvq.mjs} +2 -2
- package/dist/string-coerce-fsri9iCu.mjs +34 -0
- package/dist/{tool-schema-json-projection-B1b-XCn5.mjs → tool-schema-json-projection-FEr-jOoZ.mjs} +20 -13
- package/dist/transport-utils-Bv0FHkd0.mjs +138 -0
- package/dist/transports.d.mts +199 -209
- package/dist/transports.mjs +1842 -1364
- package/dist/types-BDdaOVi2.mjs +6 -0
- package/dist/{types-CH7ReIcU.d.mts → types-DTAP49HF.d.mts} +35 -2
- package/dist/types.d.mts +5 -5
- package/dist/types.mjs +6 -4
- package/dist/utf16-slice-CvGodqok.mjs +29 -0
- package/dist/{validation-DAa_yFOM.mjs → validation-B61OhAio.mjs} +6 -6
- package/dist/{validation-CcPcuEbR.d.mts → validation-DYNNrU9u.d.mts} +1 -1
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/package.json +15 -1
- package/dist/host-Bl7Kgddo.mjs +0 -407
- package/dist/openai-chatgpt-jwt-DhAAzLkj.mjs +0 -39
- package/dist/openai-responses-contracts-BBKBfAqR.d.mts +0 -116
- package/dist/openai-responses-shared-CCyMvg7M.mjs +0 -403
- package/dist/provider-error-DI0Ts28U.mjs +0 -47
- package/dist/sanitize-unicode-DT5o51ur.mjs +0 -26
- package/dist/tool-result-text-Dvkp2Dus.mjs +0 -274
- package/dist/transform-messages-DfjpNXNQ.mjs +0 -2
- package/dist/transport-stream-shared-CPNv7A3r.mjs +0 -297
package/dist/{openai-responses-stream-internal-Bl8YyVtF.mjs → openai-responses-shared-Cvt5MgEm.mjs}
RENAMED
|
@@ -1,128 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { a as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { a as
|
|
1
|
+
import { a as normalizeOptionalString, n as normalizeLowercaseStringOrEmpty } from "./string-coerce-fsri9iCu.mjs";
|
|
2
|
+
import { i as clampThinkingLevel, r as calculateCost } from "./sanitize-unicode-BP7HLLZn.mjs";
|
|
3
|
+
import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, n as getAiTransportHost } from "./host-DF_yxOsA.mjs";
|
|
4
|
+
import { a as isRecord } from "./record-coerce-DdXsgUd_.mjs";
|
|
5
|
+
import { t as truncateUtf16Safe } from "./utf16-slice-CvGodqok.mjs";
|
|
6
|
+
import { n as projectProviderError } from "./provider-error-C8mBRJDl.mjs";
|
|
7
|
+
import { t as asFiniteNumber } from "./number-coercion-H9qHik3g.mjs";
|
|
8
|
+
import { C as normalizeStringEntries, S as supportsOpenAITemperature, T as uniqueValues, a as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, c as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, f as RESPONSE_FAILED_NO_DETAILS_MESSAGE, o as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, s as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, x as supportsOpenAIReasoningEffort, y as resolveOpenAIReasoningEffortForModel } from "./openai-responses-contracts-DvILoqBk.mjs";
|
|
9
|
+
import { C as withProviderResponseHook, P as sortPromptCacheToolsByName, b as sanitizeTransportPayloadText, j as stripSystemPromptCacheBoundary, v as parseTerminalToolCallArguments, x as transportAbortError, y as sanitizeNonEmptyTransportPayloadText } from "./simple-options-oqsXB6U3.mjs";
|
|
10
|
+
import { c as transformTransportMessages } from "./tool-schema-json-projection-FEr-jOoZ.mjs";
|
|
11
|
+
import { n as parseStreamingJson } from "./json-parse-CDnesDM_.mjs";
|
|
12
|
+
import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
|
|
9
13
|
import { t as shortHash } from "./hash-CHgqbJmD.mjs";
|
|
10
|
-
import {
|
|
11
|
-
|
|
14
|
+
import { l as redactIdentifier, u as redactSensitiveText } from "./transport-utils-Bv0FHkd0.mjs";
|
|
15
|
+
import { a as createModelStreamCooperativeScheduler, l as log, o as createOpenAIProviderAcceptanceHook, t as projectOpenAITools } from "./openai-tool-projection-CHGLt03m.mjs";
|
|
16
|
+
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-MK28puvq.mjs";
|
|
17
|
+
import { t as transformProviderMessages } from "./provider-transcript-transform--gtf0ZbR.mjs";
|
|
18
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
19
|
+
//#region packages/ai/src/transports/model-transport-debug.ts
|
|
12
20
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
21
|
+
* Environment-driven debug controls for model transport logging.
|
|
22
|
+
*
|
|
23
|
+
* Model adapters share these helpers so payload, SSE, and transport diagnostics
|
|
24
|
+
* interpret OpenClaw debug environment variables consistently.
|
|
15
25
|
*/
|
|
16
|
-
const MAX_SAFE_INTEGER_ABS_STR = String(Number.MAX_SAFE_INTEGER);
|
|
17
|
-
function isAsciiDigit(ch) {
|
|
18
|
-
return ch !== void 0 && ch >= "0" && ch <= "9";
|
|
19
|
-
}
|
|
20
|
-
function parseJsonNumberToken(input, start) {
|
|
21
|
-
let idx = start;
|
|
22
|
-
if (input[idx] === "-") idx += 1;
|
|
23
|
-
if (idx >= input.length) return null;
|
|
24
|
-
if (input[idx] === "0") idx += 1;
|
|
25
|
-
else if (isAsciiDigit(input[idx]) && input[idx] !== "0") while (isAsciiDigit(input[idx])) idx += 1;
|
|
26
|
-
else return null;
|
|
27
|
-
let isInteger = true;
|
|
28
|
-
if (input[idx] === ".") {
|
|
29
|
-
isInteger = false;
|
|
30
|
-
idx += 1;
|
|
31
|
-
if (!isAsciiDigit(input[idx])) return null;
|
|
32
|
-
while (isAsciiDigit(input[idx])) idx += 1;
|
|
33
|
-
}
|
|
34
|
-
if (input[idx] === "e" || input[idx] === "E") {
|
|
35
|
-
isInteger = false;
|
|
36
|
-
idx += 1;
|
|
37
|
-
if (input[idx] === "+" || input[idx] === "-") idx += 1;
|
|
38
|
-
if (!isAsciiDigit(input[idx])) return null;
|
|
39
|
-
while (isAsciiDigit(input[idx])) idx += 1;
|
|
40
|
-
}
|
|
41
|
-
return {
|
|
42
|
-
token: input.slice(start, idx),
|
|
43
|
-
end: idx,
|
|
44
|
-
isInteger
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function isUnsafeIntegerLiteral(token) {
|
|
48
|
-
const digits = token[0] === "-" ? token.slice(1) : token;
|
|
49
|
-
if (digits.length < MAX_SAFE_INTEGER_ABS_STR.length) return false;
|
|
50
|
-
if (digits.length > MAX_SAFE_INTEGER_ABS_STR.length) return true;
|
|
51
|
-
return digits > MAX_SAFE_INTEGER_ABS_STR;
|
|
52
|
-
}
|
|
53
|
-
/** Quotes integer literals above Number.MAX_SAFE_INTEGER before JSON.parse. */
|
|
54
|
-
function quoteUnsafeIntegerLiterals(input) {
|
|
55
|
-
let out = "";
|
|
56
|
-
let inString = false;
|
|
57
|
-
let escaped = false;
|
|
58
|
-
let idx = 0;
|
|
59
|
-
while (idx < input.length) {
|
|
60
|
-
const ch = input[idx] ?? "";
|
|
61
|
-
if (inString) {
|
|
62
|
-
out += ch;
|
|
63
|
-
if (escaped) escaped = false;
|
|
64
|
-
else if (ch === "\\") escaped = true;
|
|
65
|
-
else if (ch === "\"") inString = false;
|
|
66
|
-
idx += 1;
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (ch === "\"") {
|
|
70
|
-
inString = true;
|
|
71
|
-
out += ch;
|
|
72
|
-
idx += 1;
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (ch === "-" || isAsciiDigit(ch)) {
|
|
76
|
-
const parsed = parseJsonNumberToken(input, idx);
|
|
77
|
-
if (parsed) {
|
|
78
|
-
if (parsed.isInteger && isUnsafeIntegerLiteral(parsed.token)) out += `"${parsed.token}"`;
|
|
79
|
-
else out += parsed.token;
|
|
80
|
-
idx = parsed.end;
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
out += ch;
|
|
85
|
-
idx += 1;
|
|
86
|
-
}
|
|
87
|
-
return out;
|
|
88
|
-
}
|
|
89
|
-
/** Parses JSON while preserving unsafe integer literals as strings. */
|
|
90
|
-
function parseJsonPreservingUnsafeIntegers(input) {
|
|
91
|
-
return JSON.parse(quoteUnsafeIntegerLiterals(input));
|
|
92
|
-
}
|
|
93
|
-
/** Parses or accepts an object while preserving unsafe integer literals in string input. */
|
|
94
|
-
function parseJsonObjectPreservingUnsafeIntegers(value) {
|
|
95
|
-
if (typeof value === "string") {
|
|
96
|
-
try {
|
|
97
|
-
const parsed = parseJsonPreservingUnsafeIntegers(value);
|
|
98
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
|
|
99
|
-
} catch {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
if (value && typeof value === "object" && !Array.isArray(value)) return value;
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
//#endregion
|
|
108
|
-
//#region packages/ai/src/transports/model-transport-debug.ts
|
|
109
|
-
function normalizeEnv(value) {
|
|
110
|
-
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
111
|
-
}
|
|
112
26
|
function isTruthyEnv(value) {
|
|
113
|
-
const normalized =
|
|
27
|
+
const normalized = normalizeLowercaseStringOrEmpty(value);
|
|
114
28
|
return normalized.length > 0 && normalized !== "0" && normalized !== "false" && normalized !== "off" && normalized !== "no";
|
|
115
29
|
}
|
|
116
30
|
/** Resolves model payload debug verbosity from `OPENCLAW_DEBUG_MODEL_PAYLOAD`. */
|
|
117
31
|
function resolveModelPayloadDebugMode(env = process.env) {
|
|
118
|
-
const normalized =
|
|
32
|
+
const normalized = normalizeLowercaseStringOrEmpty(env.OPENCLAW_DEBUG_MODEL_PAYLOAD);
|
|
119
33
|
if (normalized === "tools" || normalized === "full-redacted") return normalized;
|
|
120
34
|
if (normalized === "summary") return "summary";
|
|
121
35
|
return "off";
|
|
122
36
|
}
|
|
123
37
|
/** Resolves SSE stream debug verbosity from `OPENCLAW_DEBUG_SSE`. */
|
|
124
38
|
function resolveModelSseDebugMode(env = process.env) {
|
|
125
|
-
const normalized =
|
|
39
|
+
const normalized = normalizeLowercaseStringOrEmpty(env.OPENCLAW_DEBUG_SSE);
|
|
126
40
|
if (normalized === "peek") return "peek";
|
|
127
41
|
if (normalized === "events" || isTruthyEnv(normalized)) return "events";
|
|
128
42
|
return "off";
|
|
@@ -143,173 +57,6 @@ function emitModelTransportDebug(log, message) {
|
|
|
143
57
|
log.debug(message);
|
|
144
58
|
}
|
|
145
59
|
//#endregion
|
|
146
|
-
//#region packages/normalization-core/src/string-normalization.ts
|
|
147
|
-
/** Coerces entries to strings, trims them, and drops empty results. */
|
|
148
|
-
function normalizeStringEntries(list) {
|
|
149
|
-
return (list ?? []).map((entry) => normalizeOptionalString(String(entry)) ?? "").filter(Boolean);
|
|
150
|
-
}
|
|
151
|
-
/** Returns first-seen unique values while preserving insertion order. */
|
|
152
|
-
function uniqueValues(values) {
|
|
153
|
-
return [...new Set(values)];
|
|
154
|
-
}
|
|
155
|
-
/** Returns first-seen unique strings while preserving insertion order. */
|
|
156
|
-
function uniqueStrings(values) {
|
|
157
|
-
return uniqueValues(values);
|
|
158
|
-
}
|
|
159
|
-
//#endregion
|
|
160
|
-
//#region packages/ai/src/providers/openai-reasoning-effort.ts
|
|
161
|
-
/**
|
|
162
|
-
* OpenAI-compatible reasoning-effort normalization. Different GPT families
|
|
163
|
-
* expose different accepted effort enums, so callers map requested values here
|
|
164
|
-
* before constructing provider payloads.
|
|
165
|
-
*/
|
|
166
|
-
const GPT_5_REASONING_EFFORTS = [
|
|
167
|
-
"minimal",
|
|
168
|
-
"low",
|
|
169
|
-
"medium",
|
|
170
|
-
"high"
|
|
171
|
-
];
|
|
172
|
-
const GPT_51_REASONING_EFFORTS = [
|
|
173
|
-
"none",
|
|
174
|
-
"low",
|
|
175
|
-
"medium",
|
|
176
|
-
"high"
|
|
177
|
-
];
|
|
178
|
-
const GPT_52_REASONING_EFFORTS = [
|
|
179
|
-
"none",
|
|
180
|
-
"low",
|
|
181
|
-
"medium",
|
|
182
|
-
"high",
|
|
183
|
-
"xhigh"
|
|
184
|
-
];
|
|
185
|
-
const GPT_56_REASONING_EFFORTS = [
|
|
186
|
-
"none",
|
|
187
|
-
"low",
|
|
188
|
-
"medium",
|
|
189
|
-
"high",
|
|
190
|
-
"xhigh",
|
|
191
|
-
"max"
|
|
192
|
-
];
|
|
193
|
-
const GPT_CODEX_REASONING_EFFORTS = [
|
|
194
|
-
"low",
|
|
195
|
-
"medium",
|
|
196
|
-
"high",
|
|
197
|
-
"xhigh"
|
|
198
|
-
];
|
|
199
|
-
const GPT_PRO_REASONING_EFFORTS = [
|
|
200
|
-
"medium",
|
|
201
|
-
"high",
|
|
202
|
-
"xhigh"
|
|
203
|
-
];
|
|
204
|
-
const GPT_5_PRO_REASONING_EFFORTS = ["high"];
|
|
205
|
-
const GPT_51_CODEX_MAX_REASONING_EFFORTS = [
|
|
206
|
-
"none",
|
|
207
|
-
"medium",
|
|
208
|
-
"high",
|
|
209
|
-
"xhigh"
|
|
210
|
-
];
|
|
211
|
-
const GPT_51_CODEX_MINI_REASONING_EFFORTS = ["medium"];
|
|
212
|
-
const GENERIC_REASONING_EFFORTS = [
|
|
213
|
-
"low",
|
|
214
|
-
"medium",
|
|
215
|
-
"high"
|
|
216
|
-
];
|
|
217
|
-
const CANONICAL_REASONING_EFFORTS = /* @__PURE__ */ new Set([
|
|
218
|
-
"none",
|
|
219
|
-
"minimal",
|
|
220
|
-
"low",
|
|
221
|
-
"medium",
|
|
222
|
-
"high",
|
|
223
|
-
"xhigh",
|
|
224
|
-
"max",
|
|
225
|
-
"off"
|
|
226
|
-
]);
|
|
227
|
-
function normalizeModelId(id) {
|
|
228
|
-
return normalizeLowercaseStringOrEmpty(id ?? "").replace(/-\d{4}-\d{2}-\d{2}$/u, "");
|
|
229
|
-
}
|
|
230
|
-
/** Return whether a model is the GPT-5.4 mini family. */
|
|
231
|
-
function isOpenAIGpt54MiniModel(model) {
|
|
232
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
233
|
-
return /^gpt-5\.4-mini(?:-|$)/u.test(id);
|
|
234
|
-
}
|
|
235
|
-
/** Return whether a model is the GPT-5.5 family. */
|
|
236
|
-
function isOpenAIGpt55Model(model) {
|
|
237
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
238
|
-
const name = normalizeModelId(typeof model.name === "string" ? model.name : void 0);
|
|
239
|
-
return /^gpt-5\.5(?:-|$)/u.test(id) || /^gpt-5\.5(?:\s|\(|-|$)/u.test(name);
|
|
240
|
-
}
|
|
241
|
-
/** Return whether a model is the GPT-5.6 family. */
|
|
242
|
-
function isOpenAIGpt56Model(model) {
|
|
243
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
244
|
-
const name = normalizeModelId(typeof model.name === "string" ? model.name : void 0);
|
|
245
|
-
return /^gpt-5\.6(?:-|$)/u.test(id) || /^gpt-5\.6(?:\s|\(|-|$)/u.test(name);
|
|
246
|
-
}
|
|
247
|
-
/** Normalize user-facing reasoning effort names to API effort names. */
|
|
248
|
-
function normalizeOpenAIReasoningEffort(effort) {
|
|
249
|
-
const trimmed = effort.trim();
|
|
250
|
-
const folded = trimmed.toLowerCase();
|
|
251
|
-
return CANONICAL_REASONING_EFFORTS.has(folded) ? folded : trimmed;
|
|
252
|
-
}
|
|
253
|
-
function readCompatReasoningEfforts(compat) {
|
|
254
|
-
if (!compat || typeof compat !== "object") return;
|
|
255
|
-
if (compat.supportsReasoningEffort === false) return [];
|
|
256
|
-
const raw = compat.supportedReasoningEfforts;
|
|
257
|
-
if (!Array.isArray(raw)) return;
|
|
258
|
-
const supported = uniqueStrings(normalizeStringEntries(raw.filter((value) => typeof value === "string")));
|
|
259
|
-
return supported.length > 0 ? supported : void 0;
|
|
260
|
-
}
|
|
261
|
-
function isDisabledReasoningEffort(effort) {
|
|
262
|
-
return effort === "none" || effort === "off";
|
|
263
|
-
}
|
|
264
|
-
/** Resolve the reasoning efforts accepted by a specific OpenAI-compatible model. */
|
|
265
|
-
function resolveOpenAISupportedReasoningEfforts(model) {
|
|
266
|
-
const compatEfforts = readCompatReasoningEfforts(model.compat);
|
|
267
|
-
if (compatEfforts) return compatEfforts;
|
|
268
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
269
|
-
if (/^gpt-5\.6(?:-|$)/u.test(id)) return GPT_56_REASONING_EFFORTS;
|
|
270
|
-
if (id === "gpt-5.1-codex-mini") return GPT_51_CODEX_MINI_REASONING_EFFORTS;
|
|
271
|
-
if (id === "gpt-5.1-codex-max") return GPT_51_CODEX_MAX_REASONING_EFFORTS;
|
|
272
|
-
if (/^gpt-5(?:\.\d+)?-codex(?:-|$)/u.test(id)) return GPT_CODEX_REASONING_EFFORTS;
|
|
273
|
-
if (id === "gpt-5-pro") return GPT_5_PRO_REASONING_EFFORTS;
|
|
274
|
-
if (/^gpt-5\.[2-9](?:\.\d+)?-pro(?:-|$)/u.test(id)) return GPT_PRO_REASONING_EFFORTS;
|
|
275
|
-
if (/^gpt-5\.[2-9](?:\.\d+)?(?:-|$)/u.test(id)) return GPT_52_REASONING_EFFORTS;
|
|
276
|
-
if (/^gpt-5\.1(?:-|$)/u.test(id)) return GPT_51_REASONING_EFFORTS;
|
|
277
|
-
if (/^gpt-5(?:-|$)/u.test(id)) return GPT_5_REASONING_EFFORTS;
|
|
278
|
-
return GENERIC_REASONING_EFFORTS;
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Return whether a model accepts the temperature parameter. The GPT-5.6
|
|
282
|
-
* family rejects it with a 400; catalog compat can override per model.
|
|
283
|
-
*/
|
|
284
|
-
function supportsOpenAITemperature(model) {
|
|
285
|
-
const compat = model.compat;
|
|
286
|
-
if (compat && typeof compat === "object") {
|
|
287
|
-
const declared = compat.supportsTemperature;
|
|
288
|
-
if (typeof declared === "boolean") return declared;
|
|
289
|
-
}
|
|
290
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
291
|
-
return !/^gpt-5\.6(?:-|$)/u.test(id);
|
|
292
|
-
}
|
|
293
|
-
/** Return whether a model accepts a requested reasoning effort. */
|
|
294
|
-
function supportsOpenAIReasoningEffort(model, effort) {
|
|
295
|
-
return resolveOpenAISupportedReasoningEfforts(model).includes(normalizeOpenAIReasoningEffort(effort));
|
|
296
|
-
}
|
|
297
|
-
/** Resolve a requested reasoning effort to the closest value supported by the model. */
|
|
298
|
-
function resolveOpenAIReasoningEffortForModel(params) {
|
|
299
|
-
const requested = normalizeOpenAIReasoningEffort(params.effort);
|
|
300
|
-
const mapped = params.fallbackMap?.[requested] ?? (params.fallbackMap && CANONICAL_REASONING_EFFORTS.has(requested) ? Object.entries(params.fallbackMap).find(([effort]) => normalizeOpenAIReasoningEffort(effort) === requested)?.[1] : void 0);
|
|
301
|
-
const normalized = mapped === void 0 ? requested : mapped.trim();
|
|
302
|
-
const supported = resolveOpenAISupportedReasoningEfforts(params.model);
|
|
303
|
-
if (supported.includes(normalized)) return normalized;
|
|
304
|
-
if (requested === "off" && supported.includes("none")) return "none";
|
|
305
|
-
if (isDisabledReasoningEffort(requested) || isDisabledReasoningEffort(normalized)) return;
|
|
306
|
-
if (requested === "minimal" && supported.includes("low")) return "low";
|
|
307
|
-
if ((requested === "minimal" || requested === "low") && supported.includes("medium")) return "medium";
|
|
308
|
-
if (requested === "xhigh" && supported.includes("high")) return "high";
|
|
309
|
-
if (requested === "max" && supported.includes("xhigh")) return "xhigh";
|
|
310
|
-
return supported.find((effort) => !isDisabledReasoningEffort(normalizeOpenAIReasoningEffort(effort)));
|
|
311
|
-
}
|
|
312
|
-
//#endregion
|
|
313
60
|
//#region packages/ai/src/providers/clean-for-gemini.ts
|
|
314
61
|
const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
315
62
|
"patternProperties",
|
|
@@ -431,8 +178,8 @@ function simplifyUnionVariants(params) {
|
|
|
431
178
|
};
|
|
432
179
|
copySchemaMeta$1(obj, result);
|
|
433
180
|
return {
|
|
434
|
-
|
|
435
|
-
|
|
181
|
+
kind: "simplified",
|
|
182
|
+
value: result
|
|
436
183
|
};
|
|
437
184
|
}
|
|
438
185
|
if (stripped && nonNullVariants.length === 1) {
|
|
@@ -441,16 +188,19 @@ function simplifyUnionVariants(params) {
|
|
|
441
188
|
const result = { ...lone };
|
|
442
189
|
copySchemaMeta$1(obj, result);
|
|
443
190
|
return {
|
|
444
|
-
|
|
445
|
-
|
|
191
|
+
kind: "simplified",
|
|
192
|
+
value: result
|
|
446
193
|
};
|
|
447
194
|
}
|
|
448
195
|
return {
|
|
449
|
-
|
|
450
|
-
|
|
196
|
+
kind: "simplified",
|
|
197
|
+
value: lone
|
|
451
198
|
};
|
|
452
199
|
}
|
|
453
|
-
return {
|
|
200
|
+
return {
|
|
201
|
+
kind: "variants",
|
|
202
|
+
value: stripped ? nonNullVariants : variants
|
|
203
|
+
};
|
|
454
204
|
}
|
|
455
205
|
function sanitizeRequiredFields(schema) {
|
|
456
206
|
if (!Array.isArray(schema.required)) return schema;
|
|
@@ -495,16 +245,16 @@ function cleanSchemaForGeminiWithDefs(schema, defs, refStack) {
|
|
|
495
245
|
obj,
|
|
496
246
|
variants: cleanedAnyOf ?? []
|
|
497
247
|
});
|
|
498
|
-
|
|
499
|
-
|
|
248
|
+
if (simplified.kind === "simplified") return simplified.value;
|
|
249
|
+
cleanedAnyOf = simplified.value;
|
|
500
250
|
}
|
|
501
251
|
if (hasOneOf) {
|
|
502
252
|
const simplified = simplifyUnionVariants({
|
|
503
253
|
obj,
|
|
504
254
|
variants: cleanedOneOf ?? []
|
|
505
255
|
});
|
|
506
|
-
|
|
507
|
-
|
|
256
|
+
if (simplified.kind === "simplified") return simplified.value;
|
|
257
|
+
cleanedOneOf = simplified.value;
|
|
508
258
|
}
|
|
509
259
|
const cleaned = {};
|
|
510
260
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -608,9 +358,6 @@ const SCHEMA_CHILD_KEYS = /* @__PURE__ */ new Set([
|
|
|
608
358
|
"unevaluatedItems",
|
|
609
359
|
"unevaluatedProperties"
|
|
610
360
|
]);
|
|
611
|
-
function isSchemaRecord(value) {
|
|
612
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
613
|
-
}
|
|
614
361
|
function cleanSchemaNode(node) {
|
|
615
362
|
if (Array.isArray(node)) {
|
|
616
363
|
let changed = false;
|
|
@@ -621,7 +368,7 @@ function cleanSchemaNode(node) {
|
|
|
621
368
|
});
|
|
622
369
|
return changed ? entries : node;
|
|
623
370
|
}
|
|
624
|
-
if (!
|
|
371
|
+
if (!isRecord(node)) return node;
|
|
625
372
|
let changed = false;
|
|
626
373
|
const cleaned = {};
|
|
627
374
|
for (const [key, value] of Object.entries(node)) {
|
|
@@ -634,7 +381,7 @@ function cleanSchemaNode(node) {
|
|
|
634
381
|
continue;
|
|
635
382
|
}
|
|
636
383
|
let next = value;
|
|
637
|
-
if (SCHEMA_MAP_KEYS$2.has(key) &&
|
|
384
|
+
if (SCHEMA_MAP_KEYS$2.has(key) && isRecord(value)) {
|
|
638
385
|
let mapChanged = false;
|
|
639
386
|
next = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => {
|
|
640
387
|
const cleanedChild = cleanSchemaNode(childValue);
|
|
@@ -653,10 +400,10 @@ function collectSchemaViolations(node, path, violations) {
|
|
|
653
400
|
node.forEach((entry, index) => collectSchemaViolations(entry, `${path}[${index}]`, violations));
|
|
654
401
|
return;
|
|
655
402
|
}
|
|
656
|
-
if (!
|
|
403
|
+
if (!isRecord(node)) return;
|
|
657
404
|
if ("pattern" in node) violations.push(`${path}.pattern`);
|
|
658
405
|
if (typeof node.maxLength === "number" && node.maxLength >= 2e3) violations.push(`${path}.maxLength`);
|
|
659
|
-
for (const [key, value] of Object.entries(node)) if (SCHEMA_MAP_KEYS$2.has(key) &&
|
|
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);
|
|
660
407
|
else if (SCHEMA_CHILD_KEYS.has(key)) collectSchemaViolations(value, `${path}.${key}`, violations);
|
|
661
408
|
}
|
|
662
409
|
/** Removes JSON Schema constraints that llama.cpp cannot compile into GBNF. */
|
|
@@ -1458,7 +1205,7 @@ function findOpenAIStrictSchemaViolations(schema, path, options) {
|
|
|
1458
1205
|
* Caches normalized object inputs by provider compatibility so repeated inventory builds preserve identity.
|
|
1459
1206
|
*/
|
|
1460
1207
|
const MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
|
|
1461
|
-
|
|
1208
|
+
const strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
|
|
1462
1209
|
function resolveToolSchemaModelCompat(compat) {
|
|
1463
1210
|
if (!compat) return;
|
|
1464
1211
|
const unsupportedToolSchemaKeywords = Array.isArray(compat.unsupportedToolSchemaKeywords) ? compat.unsupportedToolSchemaKeywords.filter((keyword) => typeof keyword === "string") : [];
|
|
@@ -1483,9 +1230,6 @@ function rememberStrictOpenAISchema(schema, key, value) {
|
|
|
1483
1230
|
}, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
|
|
1484
1231
|
return value;
|
|
1485
1232
|
}
|
|
1486
|
-
function clearOpenAIToolSchemaCacheForTest() {
|
|
1487
|
-
strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
|
|
1488
|
-
}
|
|
1489
1233
|
/** Normalizes a tool parameter schema into the OpenAI strict JSON-schema subset. */
|
|
1490
1234
|
function normalizeStrictOpenAIJsonSchema(schema, modelCompat) {
|
|
1491
1235
|
const schemaInput = schema ?? {};
|
|
@@ -1584,337 +1328,197 @@ function resolveReplayableResponsesMessageId(params) {
|
|
|
1584
1328
|
if (!params.textSignatureId) return params.fallbackOrdinal === 0 ? params.fallbackId : `${params.fallbackId}_${params.fallbackOrdinal}`;
|
|
1585
1329
|
return params.previousReplayItemWasReasoning ? params.textSignatureId : void 0;
|
|
1586
1330
|
}
|
|
1587
|
-
const OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS = "Follow the user request.";
|
|
1588
|
-
const AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS = 3e4;
|
|
1589
|
-
const RESPONSE_FAILED_NO_DETAILS_MESSAGE = "Unknown error (no error details in response)";
|
|
1590
|
-
const OPENAI_RESPONSES_REASONING_REPLAY_META_KEY = "__openclaw_replay";
|
|
1591
|
-
const OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY = "openclawReasoningReplay";
|
|
1592
|
-
const PROMPT_OBSERVER = Symbol("openaiResponsesPromptObserver");
|
|
1593
|
-
const responsesPromptObserver = {
|
|
1594
|
-
set(options, observer) {
|
|
1595
|
-
Reflect.set(options, PROMPT_OBSERVER, observer);
|
|
1596
|
-
},
|
|
1597
|
-
get(options) {
|
|
1598
|
-
return Reflect.get(options, PROMPT_OBSERVER);
|
|
1599
|
-
},
|
|
1600
|
-
copy(source, target) {
|
|
1601
|
-
const observer = source && responsesPromptObserver.get(source);
|
|
1602
|
-
if (observer) responsesPromptObserver.set(target, observer);
|
|
1603
|
-
}
|
|
1604
|
-
};
|
|
1605
1331
|
//#endregion
|
|
1606
|
-
//#region packages/ai/src/transports/openai-responses-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1332
|
+
//#region packages/ai/src/transports/openai-responses-compaction-replay.ts
|
|
1333
|
+
const OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE = "openai-responses-compaction-suppression";
|
|
1334
|
+
const OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA = "rejected";
|
|
1335
|
+
function hashOptionalReplayContextValue(value) {
|
|
1336
|
+
const normalized = value?.trim();
|
|
1337
|
+
return normalized ? shortHash(normalized) : void 0;
|
|
1611
1338
|
}
|
|
1612
|
-
function
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1339
|
+
function buildOpenAIResponsesReplayContext(model, options) {
|
|
1340
|
+
return {
|
|
1341
|
+
provider: model.provider,
|
|
1342
|
+
api: model.api,
|
|
1343
|
+
model: model.id,
|
|
1344
|
+
baseUrlHash: hashOptionalReplayContextValue(model.baseUrl),
|
|
1345
|
+
sessionHash: hashOptionalReplayContextValue(options?.sessionId),
|
|
1346
|
+
authProfileHash: hashOptionalReplayContextValue(options?.authProfileId)
|
|
1347
|
+
};
|
|
1618
1348
|
}
|
|
1619
|
-
function
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
usage.cost.input *= multiplier;
|
|
1623
|
-
usage.cost.output *= multiplier;
|
|
1624
|
-
usage.cost.cacheRead *= multiplier;
|
|
1625
|
-
usage.cost.cacheWrite *= multiplier;
|
|
1626
|
-
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
1349
|
+
function isOpenAIResponsesReplayContext(value) {
|
|
1350
|
+
if (!isRecord(value)) return false;
|
|
1351
|
+
return typeof value.provider === "string" && typeof value.api === "string" && typeof value.model === "string" && (value.baseUrlHash === void 0 || typeof value.baseUrlHash === "string") && (value.sessionHash === void 0 || typeof value.sessionHash === "string") && (value.authProfileHash === void 0 || typeof value.authProfileHash === "string");
|
|
1627
1352
|
}
|
|
1628
|
-
function
|
|
1629
|
-
if (typeof
|
|
1630
|
-
if (
|
|
1631
|
-
if (
|
|
1632
|
-
|
|
1633
|
-
return Array.isArray(value) ? "array" : typeof value;
|
|
1353
|
+
function isOpenAIResponsesCompactionState(state) {
|
|
1354
|
+
if (typeof state.baseUrlHash !== "string" || state.v !== 1) return false;
|
|
1355
|
+
if (state.type === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE) return state.data === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA;
|
|
1356
|
+
if (state.type === "openai-responses-retained-compaction") return typeof state.data === "string" && state.data.length > 0 && (state.id === void 0 || typeof state.id === "string") && state.replayIndex === void 0;
|
|
1357
|
+
return state.type === "openai-responses-compaction" && typeof state.data === "string" && state.data.length > 0 && (state.id === void 0 || typeof state.id === "string") && (state.replayIndex === void 0 || typeof state.replayIndex === "number" && Number.isSafeInteger(state.replayIndex) && state.replayIndex >= 0);
|
|
1634
1358
|
}
|
|
1635
|
-
function
|
|
1636
|
-
|
|
1637
|
-
if (Array.isArray(input)) return input.reduce((total, item) => total + responseInputTextChars(item), 0);
|
|
1638
|
-
if (!input || typeof input !== "object") return 0;
|
|
1639
|
-
const record = input;
|
|
1640
|
-
let total = 0;
|
|
1641
|
-
if (typeof record.text === "string") total += record.text.length;
|
|
1642
|
-
if (typeof record.content === "string") total += record.content.length;
|
|
1643
|
-
else if (Array.isArray(record.content)) total += responseInputTextChars(record.content);
|
|
1644
|
-
return total;
|
|
1359
|
+
function readOpenAIResponsesCompactionReplayState(value) {
|
|
1360
|
+
return isRecord(value) && isOpenAIResponsesReplayContext(value) && isOpenAIResponsesCompactionState(value) ? value : void 0;
|
|
1645
1361
|
}
|
|
1646
|
-
function
|
|
1647
|
-
|
|
1648
|
-
const roles = /* @__PURE__ */ new Set();
|
|
1649
|
-
for (const item of input) if (item && typeof item === "object") {
|
|
1650
|
-
const role = item.role;
|
|
1651
|
-
if (typeof role === "string" && role.trim()) roles.add(role.trim());
|
|
1652
|
-
}
|
|
1653
|
-
return [...roles].toSorted().join(",");
|
|
1362
|
+
function openAIResponsesReplayContextMatches(state, context) {
|
|
1363
|
+
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;
|
|
1654
1364
|
}
|
|
1655
|
-
function
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1365
|
+
function captureOpenAIResponsesCompaction(output, item, boundary, model, captureMetadata) {
|
|
1366
|
+
const metadata = captureMetadata ?? buildOpenAIResponsesReasoningReplayMetadata(model);
|
|
1367
|
+
if (!item.encrypted_content) return;
|
|
1368
|
+
if (!metadata?.baseUrlHash) {
|
|
1369
|
+
log.debug("[responses] skipping compaction capture: missing base URL hash");
|
|
1659
1370
|
return;
|
|
1660
1371
|
}
|
|
1372
|
+
const currentReplay = readOpenAIResponsesCompactionReplayState(output.providerReplay);
|
|
1373
|
+
if (typeof boundary === "number" && currentReplay?.type === "openai-responses-compaction" && (currentReplay.replayIndex ?? -1) > boundary) return;
|
|
1374
|
+
output.providerReplay = {
|
|
1375
|
+
v: 1,
|
|
1376
|
+
type: boundary === "retained-users" ? OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE : OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE,
|
|
1377
|
+
...item.id ? { id: item.id } : {},
|
|
1378
|
+
data: item.encrypted_content,
|
|
1379
|
+
...typeof boundary === "number" ? { replayIndex: boundary } : {},
|
|
1380
|
+
provider: metadata.provider,
|
|
1381
|
+
api: metadata.api,
|
|
1382
|
+
model: metadata.model,
|
|
1383
|
+
baseUrlHash: metadata.baseUrlHash,
|
|
1384
|
+
...metadata.sessionHash ? { sessionHash: metadata.sessionHash } : {},
|
|
1385
|
+
...metadata.authProfileHash ? { authProfileHash: metadata.authProfileHash } : {}
|
|
1386
|
+
};
|
|
1661
1387
|
}
|
|
1662
|
-
function
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
return typeof type === "string" && type !== "function" ? type : "";
|
|
1674
|
-
}
|
|
1675
|
-
function summarizeResponsesTools(tools) {
|
|
1676
|
-
if (!Array.isArray(tools)) return "count=0";
|
|
1677
|
-
const names = tools.map(readResponsesToolDisplayName).filter(Boolean);
|
|
1678
|
-
const mode = resolveModelPayloadDebugMode();
|
|
1679
|
-
const maxNames = mode === "tools" || mode === "full-redacted" ? names.length : 12;
|
|
1680
|
-
const label = maxNames >= names.length ? "names" : "sample";
|
|
1681
|
-
const shown = names.slice(0, maxNames).join(",");
|
|
1682
|
-
return `count=${tools.length}${shown ? ` ${label}=${shown}` : ""}`;
|
|
1388
|
+
function suppressOpenAIResponsesCompaction(output, model, options, rejectedCheckpoint) {
|
|
1389
|
+
const context = buildOpenAIResponsesReplayContext(model, options);
|
|
1390
|
+
if (!context.baseUrlHash) return;
|
|
1391
|
+
output.providerReplay = {
|
|
1392
|
+
v: 1,
|
|
1393
|
+
type: OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE,
|
|
1394
|
+
data: OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA,
|
|
1395
|
+
...context,
|
|
1396
|
+
baseUrlHash: context.baseUrlHash
|
|
1397
|
+
};
|
|
1398
|
+
if (rejectedCheckpoint) options?.onCompactionRejected?.(rejectedCheckpoint);
|
|
1683
1399
|
}
|
|
1684
|
-
function
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1400
|
+
function createCompactionTracker(output, model, options) {
|
|
1401
|
+
const replayIndexes = /* @__PURE__ */ new Map();
|
|
1402
|
+
return {
|
|
1403
|
+
added(item, replayIndex) {
|
|
1404
|
+
if (item.type === "compaction" && item.id) replayIndexes.set(item.id, replayIndex);
|
|
1405
|
+
},
|
|
1406
|
+
completed(item, fallbackReplayIndex) {
|
|
1407
|
+
if (item.type !== "compaction" || !item.encrypted_content) return;
|
|
1408
|
+
captureOpenAIResponsesCompaction(output, {
|
|
1409
|
+
type: "compaction",
|
|
1410
|
+
...item.id ? { id: item.id } : {},
|
|
1411
|
+
encrypted_content: item.encrypted_content
|
|
1412
|
+
}, (item.id ? replayIndexes.get(item.id) : void 0) ?? fallbackReplayIndex, model, options?.reasoningReplayMetadata);
|
|
1413
|
+
if (item.id) replayIndexes.delete(item.id);
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1693
1416
|
}
|
|
1694
|
-
function
|
|
1695
|
-
|
|
1696
|
-
return redacted.length > 2e3 ? `${truncateUtf16Safe(redacted, 2e3)}…<truncated>` : redacted;
|
|
1417
|
+
function isSafeResponsesReplayItemId(id) {
|
|
1418
|
+
return typeof id === "string" && id.length > 0 && id.length <= 64;
|
|
1697
1419
|
}
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1420
|
+
function resolveNewestOpenAIResponsesCompactionReplay(messages, model, options) {
|
|
1421
|
+
const context = buildOpenAIResponsesReplayContext(model, options);
|
|
1422
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
1423
|
+
const message = messages[index];
|
|
1424
|
+
if (message?.role !== "assistant") continue;
|
|
1425
|
+
const replay = readOpenAIResponsesCompactionReplayState(message.providerReplay);
|
|
1426
|
+
if (replay?.type === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE) {
|
|
1427
|
+
if (openAIResponsesReplayContextMatches(replay, context)) return;
|
|
1428
|
+
continue;
|
|
1429
|
+
}
|
|
1430
|
+
if (replay?.type !== "openai-responses-compaction" && replay?.type !== "openai-responses-retained-compaction") {
|
|
1431
|
+
if (message.providerReplay?.type === "openai-responses-compaction" || message.providerReplay?.type === "openai-responses-retained-compaction") return;
|
|
1432
|
+
continue;
|
|
1433
|
+
}
|
|
1434
|
+
if (!openAIResponsesReplayContextMatches(replay, context)) return;
|
|
1435
|
+
return {
|
|
1436
|
+
owner: message,
|
|
1437
|
+
item: {
|
|
1438
|
+
type: "compaction",
|
|
1439
|
+
...isSafeResponsesReplayItemId(replay.id) ? { id: replay.id } : {},
|
|
1440
|
+
encrypted_content: replay.data
|
|
1441
|
+
},
|
|
1442
|
+
...replay.type === "openai-responses-retained-compaction" ? { mode: "retained-users" } : {
|
|
1443
|
+
mode: "compacted-prefix",
|
|
1444
|
+
replayIndex: replay.replayIndex ?? 0
|
|
1445
|
+
}
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1709
1448
|
}
|
|
1710
|
-
function
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1449
|
+
function buildOpenAIResponsesCompactionReplayPlan(messages, model, options) {
|
|
1450
|
+
if (options?.mode === "full-history") return {
|
|
1451
|
+
messages,
|
|
1452
|
+
preserveUnframedToolResults: false
|
|
1453
|
+
};
|
|
1454
|
+
const compaction = resolveNewestOpenAIResponsesCompactionReplay(messages, model, options);
|
|
1455
|
+
if (!compaction) return {
|
|
1456
|
+
messages,
|
|
1457
|
+
preserveUnframedToolResults: false
|
|
1458
|
+
};
|
|
1459
|
+
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
|
+
return {
|
|
1469
|
+
messages: [{
|
|
1470
|
+
...compaction.owner,
|
|
1471
|
+
content: compaction.mode === "retained-users" ? [] : compaction.owner.content.slice(compaction.replayIndex)
|
|
1472
|
+
}, ...messages.slice(ownerIndex + 1)],
|
|
1473
|
+
...retainedMessages?.length ? { retainedMessages } : {},
|
|
1474
|
+
compaction: compaction.item,
|
|
1475
|
+
preserveUnframedToolResults: true
|
|
1476
|
+
};
|
|
1715
1477
|
}
|
|
1716
|
-
function
|
|
1717
|
-
|
|
1718
|
-
|
|
1478
|
+
function buildOpenAIResponsesReasoningReplayMetadata(model, options) {
|
|
1479
|
+
return {
|
|
1480
|
+
v: 1,
|
|
1481
|
+
source: "openai-responses",
|
|
1482
|
+
...buildOpenAIResponsesReplayContext(model, options)
|
|
1483
|
+
};
|
|
1719
1484
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
if (seen.has(value)) return out;
|
|
1728
|
-
seen.add(value);
|
|
1485
|
+
//#endregion
|
|
1486
|
+
//#region packages/ai/src/transports/openai-responses-replay-messages-internal.ts
|
|
1487
|
+
function stripEncryptedReasoningContentFields(value) {
|
|
1488
|
+
if (!value || typeof value !== "object") return {
|
|
1489
|
+
value,
|
|
1490
|
+
changed: false
|
|
1491
|
+
};
|
|
1729
1492
|
if (Array.isArray(value)) {
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
const
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
});
|
|
1744
|
-
}
|
|
1745
|
-
return out;
|
|
1493
|
+
let changed = false;
|
|
1494
|
+
const next = value.map((item) => {
|
|
1495
|
+
const stripped = stripEncryptedReasoningContentFields(item);
|
|
1496
|
+
changed ||= stripped.changed;
|
|
1497
|
+
return stripped.value;
|
|
1498
|
+
});
|
|
1499
|
+
return changed ? {
|
|
1500
|
+
value: next,
|
|
1501
|
+
changed: true
|
|
1502
|
+
} : {
|
|
1503
|
+
value,
|
|
1504
|
+
changed: false
|
|
1505
|
+
};
|
|
1746
1506
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1507
|
+
const source = value;
|
|
1508
|
+
if (source.type === "compaction") return {
|
|
1509
|
+
value,
|
|
1510
|
+
changed: false
|
|
1511
|
+
};
|
|
1512
|
+
let changed = false;
|
|
1513
|
+
const next = {};
|
|
1514
|
+
for (const [key, child] of Object.entries(source)) {
|
|
1515
|
+
if (key === "encrypted_content") {
|
|
1516
|
+
changed = true;
|
|
1753
1517
|
continue;
|
|
1754
1518
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
identifierKey: isResponseFailedIdentifierKey(key) ? key : void 0,
|
|
1759
|
-
out,
|
|
1760
|
-
seen
|
|
1761
|
-
});
|
|
1762
|
-
}
|
|
1763
|
-
return out;
|
|
1764
|
-
}
|
|
1765
|
-
function redactResponseFailedDiagnosticValue(value, opts = {}) {
|
|
1766
|
-
const key = opts.key ?? "";
|
|
1767
|
-
const depth = opts.depth ?? 0;
|
|
1768
|
-
if (typeof value === "string" || typeof value === "number") return key && isResponseFailedIdentifierKey(key) ? redactIdentifier(String(value), { len: 12 }) : value;
|
|
1769
|
-
if (depth > 6 || !value || typeof value !== "object") return value;
|
|
1770
|
-
const seen = opts.seen ?? /* @__PURE__ */ new WeakSet();
|
|
1771
|
-
if (seen.has(value)) return "<circular>";
|
|
1772
|
-
seen.add(value);
|
|
1773
|
-
if (Array.isArray(value)) return value.slice(0, 16).map((item) => redactResponseFailedDiagnosticValue(item, {
|
|
1774
|
-
key,
|
|
1775
|
-
depth: depth + 1,
|
|
1776
|
-
seen
|
|
1777
|
-
}));
|
|
1778
|
-
const out = {};
|
|
1779
|
-
for (const [childKey, child] of Object.entries(value)) out[childKey] = redactResponseFailedDiagnosticValue(child, {
|
|
1780
|
-
key: childKey,
|
|
1781
|
-
depth: depth + 1,
|
|
1782
|
-
seen
|
|
1783
|
-
});
|
|
1784
|
-
return out;
|
|
1785
|
-
}
|
|
1786
|
-
function buildResponsesFailedFailureFields(response) {
|
|
1787
|
-
if (!response) return {};
|
|
1788
|
-
const fields = {};
|
|
1789
|
-
for (const key of RESPONSE_FAILED_FAILURE_FIELD_KEYS) if (response[key] !== void 0 && response[key] !== null) fields[key] = response[key];
|
|
1790
|
-
return fields;
|
|
1791
|
-
}
|
|
1792
|
-
function buildResponsesFailedNoDetailsObservation(event, model, response = isRecord(event.response) ? event.response : void 0) {
|
|
1793
|
-
const failureFields = redactResponseFailedDiagnosticValue(buildResponsesFailedFailureFields(response));
|
|
1794
|
-
const metadataKeys = isRecord(response?.metadata) ? Object.keys(response.metadata).toSorted() : [];
|
|
1795
|
-
const responsePreview = {
|
|
1796
|
-
id: readResponseFailedString(response, "id"),
|
|
1797
|
-
status: readResponseFailedString(response, "status"),
|
|
1798
|
-
model: readResponseFailedString(response, "model"),
|
|
1799
|
-
object: readResponseFailedString(response, "object"),
|
|
1800
|
-
failureFields,
|
|
1801
|
-
metadataKeys
|
|
1802
|
-
};
|
|
1803
|
-
return {
|
|
1804
|
-
event: "openai_responses_response_failed_without_details",
|
|
1805
|
-
provider: model.provider,
|
|
1806
|
-
api: model.api,
|
|
1807
|
-
transportModel: model.id,
|
|
1808
|
-
providerRuntimeFailureKind: "no_error_details",
|
|
1809
|
-
responseId: responsePreview.id,
|
|
1810
|
-
responseStatus: responsePreview.status,
|
|
1811
|
-
responseModel: responsePreview.model,
|
|
1812
|
-
responseObject: responsePreview.object,
|
|
1813
|
-
metadataKeys,
|
|
1814
|
-
requestIdHashes: collectResponseFailedIdentifierHashes(event),
|
|
1815
|
-
failureFieldsPreview: stringifyRedactedEvent(failureFields),
|
|
1816
|
-
responsePreview: stringifyRedactedEvent(responsePreview)
|
|
1817
|
-
};
|
|
1818
|
-
}
|
|
1819
|
-
function summarizeResponsesFailedNoDetailsObservation(observation) {
|
|
1820
|
-
const requestIds = observation.requestIdHashes.join(",");
|
|
1821
|
-
const metadataKeys = observation.metadataKeys.join(",");
|
|
1822
|
-
return `responseId=${safeDebugValue(observation.responseId || void 0)} responseStatus=${safeDebugValue(observation.responseStatus || void 0)} responseModel=${safeDebugValue(observation.responseModel || void 0)} requestIds=${requestIds || "none"} metadataKeys=${metadataKeys || "none"} failureFields=${observation.failureFieldsPreview}`;
|
|
1823
|
-
}
|
|
1824
|
-
function normalizeResponsesFailedEvent(event, model) {
|
|
1825
|
-
const response = isRecord(event.response) ? event.response : void 0;
|
|
1826
|
-
const responseId = readResponseFailedString(response, "id") || void 0;
|
|
1827
|
-
const error = isRecord(response?.error) ? response.error : void 0;
|
|
1828
|
-
if (error) {
|
|
1829
|
-
const code = readResponseFailedString(error, "code").trim();
|
|
1830
|
-
const message = readResponseFailedString(error, "message").trim();
|
|
1831
|
-
if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId);
|
|
1832
|
-
}
|
|
1833
|
-
const incompleteReason = readResponseFailedString(isRecord(response?.incomplete_details) ? response.incomplete_details : void 0, "reason");
|
|
1834
|
-
if (incompleteReason) return buildResponsesFailedEventSummary(`incomplete: ${incompleteReason}`, responseId);
|
|
1835
|
-
return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, buildResponsesFailedNoDetailsObservation(event, model, response));
|
|
1836
|
-
}
|
|
1837
|
-
function logResponsesFailedNoDetails(observation) {
|
|
1838
|
-
log.warn(`[responses] response.failed missing error details provider=${observation.provider} api=${observation.api} model=${observation.transportModel} ` + summarizeResponsesFailedNoDetailsObservation(observation), observation);
|
|
1839
|
-
}
|
|
1840
|
-
function summarizeResponsesPayload(params) {
|
|
1841
|
-
if (!params || typeof params !== "object") return "payload=non-object";
|
|
1842
|
-
const record = params;
|
|
1843
|
-
const input = record.input;
|
|
1844
|
-
const reasoning = record.reasoning && typeof record.reasoning === "object" ? record.reasoning : void 0;
|
|
1845
|
-
const text = record.text && typeof record.text === "object" ? record.text : void 0;
|
|
1846
|
-
const parts = [
|
|
1847
|
-
`fields=${Object.keys(record).toSorted().join(",")}`,
|
|
1848
|
-
`model=${safeDebugValue(record.model)}`,
|
|
1849
|
-
`stream=${safeDebugValue(record.stream)}`,
|
|
1850
|
-
`inputItems=${Array.isArray(input) ? input.length : typeof input}`,
|
|
1851
|
-
`inputRoles=${responseInputRoles(input) || "none"}`,
|
|
1852
|
-
`inputTextChars=${responseInputTextChars(input)}`,
|
|
1853
|
-
`tools=${summarizeResponsesTools(record.tools)}`,
|
|
1854
|
-
`reasoningEffort=${safeDebugValue(reasoning?.effort)}`,
|
|
1855
|
-
`reasoningSummary=${safeDebugValue(reasoning?.summary)}`,
|
|
1856
|
-
`textVerbosity=${safeDebugValue(text?.verbosity)}`,
|
|
1857
|
-
`serviceTier=${safeDebugValue(record.service_tier)}`,
|
|
1858
|
-
`store=${safeDebugValue(record.store)}`,
|
|
1859
|
-
`promptCacheKey=${record.prompt_cache_key === void 0 ? "absent" : "present"}`,
|
|
1860
|
-
`metadataKeys=${record.metadata && typeof record.metadata === "object" ? Object.keys(record.metadata).toSorted().join(",") : "none"}`
|
|
1861
|
-
];
|
|
1862
|
-
if (resolveModelPayloadDebugMode() === "full-redacted") parts.push(`payload=${stringifyRedactedPayload(record)}`);
|
|
1863
|
-
return parts.join(" ");
|
|
1864
|
-
}
|
|
1865
|
-
function summarizeOpenAITransportError(error) {
|
|
1866
|
-
if (!error || typeof error !== "object") return `type=${typeof error} message=${safeDebugValue(error)}`;
|
|
1867
|
-
const record = error;
|
|
1868
|
-
const cause = record.cause && typeof record.cause === "object" ? record.cause : void 0;
|
|
1869
|
-
return [
|
|
1870
|
-
`name=${safeDebugValue(record.name)}`,
|
|
1871
|
-
`status=${safeDebugValue(record.status)}`,
|
|
1872
|
-
`code=${safeDebugValue(record.code)}`,
|
|
1873
|
-
`type=${safeDebugValue(record.type)}`,
|
|
1874
|
-
`causeName=${safeDebugValue(cause?.name)}`,
|
|
1875
|
-
`causeCode=${safeDebugValue(cause?.code)}`,
|
|
1876
|
-
`message=${error instanceof Error ? error.message : safeDebugValue(error)}`
|
|
1877
|
-
].join(" ");
|
|
1878
|
-
}
|
|
1879
|
-
//#endregion
|
|
1880
|
-
//#region packages/ai/src/transports/openai-responses-replay-internal.ts
|
|
1881
|
-
function isInvalidEncryptedContentError(error) {
|
|
1882
|
-
if (!error || typeof error !== "object") return false;
|
|
1883
|
-
const record = error;
|
|
1884
|
-
if (record.code === "invalid_encrypted_content" || record.code === "thinking_signature_invalid") return true;
|
|
1885
|
-
const message = typeof record.message === "string" ? record.message : "";
|
|
1886
|
-
return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || record.status === 400 && message.toLowerCase().includes("could not decrypt the provided encrypted_content");
|
|
1887
|
-
}
|
|
1888
|
-
function stripEncryptedContentFields(value) {
|
|
1889
|
-
if (!value || typeof value !== "object") return {
|
|
1890
|
-
value,
|
|
1891
|
-
changed: false
|
|
1892
|
-
};
|
|
1893
|
-
if (Array.isArray(value)) {
|
|
1894
|
-
let changed = false;
|
|
1895
|
-
const next = value.map((item) => {
|
|
1896
|
-
const stripped = stripEncryptedContentFields(item);
|
|
1897
|
-
changed ||= stripped.changed;
|
|
1898
|
-
return stripped.value;
|
|
1899
|
-
});
|
|
1900
|
-
return changed ? {
|
|
1901
|
-
value: next,
|
|
1902
|
-
changed: true
|
|
1903
|
-
} : {
|
|
1904
|
-
value,
|
|
1905
|
-
changed: false
|
|
1906
|
-
};
|
|
1907
|
-
}
|
|
1908
|
-
let changed = false;
|
|
1909
|
-
const next = {};
|
|
1910
|
-
for (const [key, child] of Object.entries(value)) {
|
|
1911
|
-
if (key === "encrypted_content") {
|
|
1912
|
-
changed = true;
|
|
1913
|
-
continue;
|
|
1914
|
-
}
|
|
1915
|
-
const stripped = stripEncryptedContentFields(child);
|
|
1916
|
-
changed ||= stripped.changed;
|
|
1917
|
-
next[key] = stripped.value;
|
|
1519
|
+
const stripped = stripEncryptedReasoningContentFields(child);
|
|
1520
|
+
changed ||= stripped.changed;
|
|
1521
|
+
next[key] = stripped.value;
|
|
1918
1522
|
}
|
|
1919
1523
|
return changed ? {
|
|
1920
1524
|
value: next,
|
|
@@ -1924,54 +1528,15 @@ function stripEncryptedContentFields(value) {
|
|
|
1924
1528
|
changed: false
|
|
1925
1529
|
};
|
|
1926
1530
|
}
|
|
1927
|
-
function stripResponsesRequestEncryptedContent(params) {
|
|
1928
|
-
const stripped = stripEncryptedContentFields(params.input);
|
|
1929
|
-
if (!stripped.changed) return params;
|
|
1930
|
-
return {
|
|
1931
|
-
...params,
|
|
1932
|
-
input: stripped.value
|
|
1933
|
-
};
|
|
1934
|
-
}
|
|
1935
|
-
function hashOptionalReplayContextValue(value) {
|
|
1936
|
-
const normalized = value?.trim();
|
|
1937
|
-
return normalized ? shortHash(normalized) : void 0;
|
|
1938
|
-
}
|
|
1939
|
-
function buildOpenAIResponsesReplayContext(model, options) {
|
|
1940
|
-
return {
|
|
1941
|
-
provider: model.provider,
|
|
1942
|
-
api: model.api,
|
|
1943
|
-
model: model.id,
|
|
1944
|
-
baseUrlHash: hashOptionalReplayContextValue(model.baseUrl),
|
|
1945
|
-
sessionHash: hashOptionalReplayContextValue(options?.sessionId),
|
|
1946
|
-
authProfileHash: hashOptionalReplayContextValue(options?.authProfileId)
|
|
1947
|
-
};
|
|
1948
|
-
}
|
|
1949
|
-
function buildOpenAIResponsesReasoningReplayMetadata(model, options) {
|
|
1950
|
-
return {
|
|
1951
|
-
v: 1,
|
|
1952
|
-
source: "openai-responses",
|
|
1953
|
-
...buildOpenAIResponsesReplayContext(model, options)
|
|
1954
|
-
};
|
|
1955
|
-
}
|
|
1956
|
-
function tagOpenAIResponsesReasoningReplayItem(item, model, options) {
|
|
1957
|
-
if (!("encrypted_content" in item)) return item;
|
|
1958
|
-
return {
|
|
1959
|
-
...item,
|
|
1960
|
-
[OPENAI_RESPONSES_REASONING_REPLAY_META_KEY]: buildOpenAIResponsesReasoningReplayMetadata(model, options)
|
|
1961
|
-
};
|
|
1962
|
-
}
|
|
1963
1531
|
function isOpenAIResponsesReasoningReplayMetadata(value) {
|
|
1964
|
-
if (!value
|
|
1532
|
+
if (!isOpenAIResponsesReplayContext(value)) return false;
|
|
1965
1533
|
const record = value;
|
|
1966
|
-
return record.v === 1 && record.source === "openai-responses"
|
|
1967
|
-
}
|
|
1968
|
-
function encryptedReasoningReplayMetadataMatches(metadata, context) {
|
|
1969
|
-
if (!metadata) return false;
|
|
1970
|
-
return metadata.provider === context.provider && metadata.api === context.api && metadata.model === context.model && metadata.baseUrlHash === context.baseUrlHash && metadata.sessionHash === context.sessionHash && metadata.authProfileHash === context.authProfileHash;
|
|
1534
|
+
return record.v === 1 && record.source === "openai-responses";
|
|
1971
1535
|
}
|
|
1972
1536
|
function readOpenAIResponsesReasoningReplayBlockMetadata(block) {
|
|
1537
|
+
if (!Object.hasOwn(block, "openclawReasoningReplay")) return;
|
|
1973
1538
|
const value = block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY];
|
|
1974
|
-
return isOpenAIResponsesReasoningReplayMetadata(value) ? value :
|
|
1539
|
+
return isOpenAIResponsesReasoningReplayMetadata(value) ? value : null;
|
|
1975
1540
|
}
|
|
1976
1541
|
function normalizeOpenAIResponsesReasoningReplayItem(item) {
|
|
1977
1542
|
const record = item;
|
|
@@ -1981,49 +1546,20 @@ function normalizeOpenAIResponsesReasoningReplayItem(item) {
|
|
|
1981
1546
|
summary: []
|
|
1982
1547
|
};
|
|
1983
1548
|
}
|
|
1984
|
-
function prepareOpenAIResponsesReasoningItemForReplay(item, context, blockMetadata) {
|
|
1985
|
-
const
|
|
1549
|
+
function prepareOpenAIResponsesReasoningItemForReplay(item, context, blockMetadata, options) {
|
|
1550
|
+
const record = item;
|
|
1551
|
+
const hasRawMetadata = Object.hasOwn(record, OPENAI_RESPONSES_REASONING_REPLAY_META_KEY);
|
|
1552
|
+
const { [OPENAI_RESPONSES_REASONING_REPLAY_META_KEY]: rawMetadata, ...rest } = record;
|
|
1986
1553
|
if (!("encrypted_content" in rest)) return normalizeOpenAIResponsesReasoningReplayItem(rest);
|
|
1987
|
-
|
|
1988
|
-
return normalizeOpenAIResponsesReasoningReplayItem(
|
|
1989
|
-
|
|
1990
|
-
async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
1991
|
-
try {
|
|
1992
|
-
params.observePrompt?.(params.request, {
|
|
1993
|
-
egress: "responses-sdk",
|
|
1994
|
-
payloadVariant: "initial"
|
|
1995
|
-
});
|
|
1996
|
-
const { data, response } = await params.client.responses.create(params.request, params.requestOptions).withResponse();
|
|
1997
|
-
return {
|
|
1998
|
-
stream: data,
|
|
1999
|
-
response
|
|
2000
|
-
};
|
|
2001
|
-
} catch (error) {
|
|
2002
|
-
const retryRequest = stripResponsesRequestEncryptedContent(params.request);
|
|
2003
|
-
if (!isInvalidEncryptedContentError(error) || retryRequest === params.request) throw error;
|
|
2004
|
-
log.warn(`[responses] retrying without encrypted reasoning content provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
|
|
2005
|
-
params.observePrompt?.(retryRequest, {
|
|
2006
|
-
egress: "responses-sdk",
|
|
2007
|
-
payloadVariant: "encrypted-content-retry"
|
|
2008
|
-
});
|
|
2009
|
-
const { data, response } = await params.client.responses.create(retryRequest, params.requestOptions).withResponse();
|
|
2010
|
-
return {
|
|
2011
|
-
stream: data,
|
|
2012
|
-
response
|
|
2013
|
-
};
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
function resolveAzureOpenAIApiVersion(env = process.env) {
|
|
2017
|
-
return env.AZURE_OPENAI_API_VERSION?.trim() || "preview";
|
|
1554
|
+
const metadata = blockMetadata !== void 0 ? blockMetadata ?? void 0 : isOpenAIResponsesReasoningReplayMetadata(rawMetadata) ? rawMetadata : void 0;
|
|
1555
|
+
if (blockMetadata === void 0 && !hasRawMetadata && options?.preserveUnattributedEncryptedContent === true || metadata && openAIResponsesReplayContextMatches(metadata, context)) return normalizeOpenAIResponsesReasoningReplayItem(rest);
|
|
1556
|
+
return normalizeOpenAIResponsesReasoningReplayItem(stripEncryptedReasoningContentFields(rest).value);
|
|
2018
1557
|
}
|
|
2019
1558
|
function normalizeResponsesReplayItemId(id, prefix) {
|
|
2020
1559
|
if (!id) return;
|
|
2021
1560
|
if (id.length <= 64) return id;
|
|
2022
1561
|
return `${prefix}_${shortHash(id)}`;
|
|
2023
1562
|
}
|
|
2024
|
-
function isSafeResponsesReplayItemId(id) {
|
|
2025
|
-
return typeof id === "string" && id.length > 0 && id.length <= 64;
|
|
2026
|
-
}
|
|
2027
1563
|
function encodeTextSignatureV1(id, phase) {
|
|
2028
1564
|
return JSON.stringify({
|
|
2029
1565
|
v: 1,
|
|
@@ -2031,7 +1567,7 @@ function encodeTextSignatureV1(id, phase) {
|
|
|
2031
1567
|
...phase ? { phase } : {}
|
|
2032
1568
|
});
|
|
2033
1569
|
}
|
|
2034
|
-
function
|
|
1570
|
+
function parseOpenAIResponsesTextSignature(signature) {
|
|
2035
1571
|
if (!signature) return;
|
|
2036
1572
|
if (signature.startsWith("{")) try {
|
|
2037
1573
|
const parsed = JSON.parse(signature);
|
|
@@ -2054,8 +1590,34 @@ function buildResponsesInputMessage(role, content) {
|
|
|
2054
1590
|
content
|
|
2055
1591
|
};
|
|
2056
1592
|
}
|
|
2057
|
-
function
|
|
1593
|
+
function createOpenAIResponsesAssistantOutput(model, api = model.api) {
|
|
1594
|
+
return {
|
|
1595
|
+
role: "assistant",
|
|
1596
|
+
content: [],
|
|
1597
|
+
api,
|
|
1598
|
+
provider: model.provider,
|
|
1599
|
+
model: model.id,
|
|
1600
|
+
usage: {
|
|
1601
|
+
input: 0,
|
|
1602
|
+
output: 0,
|
|
1603
|
+
cacheRead: 0,
|
|
1604
|
+
cacheWrite: 0,
|
|
1605
|
+
totalTokens: 0,
|
|
1606
|
+
cost: {
|
|
1607
|
+
input: 0,
|
|
1608
|
+
output: 0,
|
|
1609
|
+
cacheRead: 0,
|
|
1610
|
+
cacheWrite: 0,
|
|
1611
|
+
total: 0
|
|
1612
|
+
}
|
|
1613
|
+
},
|
|
1614
|
+
stopReason: "stop",
|
|
1615
|
+
timestamp: Date.now()
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
function convertResponsesMessagesWithStyle(model, context, allowedToolCallProviders, options, conversionStyle) {
|
|
2058
1619
|
const messages = [];
|
|
1620
|
+
const providerStyle = conversionStyle === "provider";
|
|
2059
1621
|
const shouldReplayReasoningItems = options?.replayReasoningItems ?? true;
|
|
2060
1622
|
const shouldReplayResponsesItemIds = options?.replayResponsesItemIds ?? true;
|
|
2061
1623
|
const replayContext = buildOpenAIResponsesReplayContext(model, {
|
|
@@ -2063,7 +1625,10 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2063
1625
|
authProfileId: options?.authProfileId
|
|
2064
1626
|
});
|
|
2065
1627
|
const shouldNormalizeSameModelToolCallIds = model.provider === "github-copilot";
|
|
2066
|
-
const sanitizeIdPart = (part) =>
|
|
1628
|
+
const sanitizeIdPart = (part) => {
|
|
1629
|
+
const sanitized = part.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1630
|
+
return providerStyle ? sanitized : sanitized.replace(/_+$/, "");
|
|
1631
|
+
};
|
|
2067
1632
|
const normalizeIdPart = (part) => {
|
|
2068
1633
|
const sanitized = sanitizeIdPart(part);
|
|
2069
1634
|
return (sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized).replace(/_+$/, "");
|
|
@@ -2084,17 +1649,36 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2084
1649
|
const callId = id.slice(0, separatorIndex);
|
|
2085
1650
|
const itemId = id.slice(separatorIndex + 1);
|
|
2086
1651
|
const normalizedCallId = normalizeIdPart(callId);
|
|
2087
|
-
let normalizedItemId = source.provider !== model.provider || source.api !== model.api ? buildForeignResponsesItemId(itemId) : model.provider === "github-copilot" ? buildSameProviderCopilotResponsesItemId(itemId) : normalizeIdPart(itemId);
|
|
1652
|
+
let normalizedItemId = source.provider !== model.provider || source.api !== model.api ? buildForeignResponsesItemId(itemId) : model.provider === "github-copilot" ? providerStyle ? normalizeIdPart(itemId) : buildSameProviderCopilotResponsesItemId(itemId) : normalizeIdPart(itemId);
|
|
2088
1653
|
if (!normalizedItemId.startsWith("fc_")) normalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`);
|
|
2089
1654
|
return `${normalizedCallId}|${normalizedItemId}`;
|
|
2090
1655
|
};
|
|
2091
|
-
const
|
|
2092
|
-
|
|
1656
|
+
const replayPlan = buildOpenAIResponsesCompactionReplayPlan(context.messages, model, {
|
|
1657
|
+
sessionId: options?.sessionId,
|
|
1658
|
+
authProfileId: options?.authProfileId,
|
|
1659
|
+
mode: options?.replayMode
|
|
1660
|
+
});
|
|
1661
|
+
const transformMessages = (source) => providerStyle ? transformProviderMessages(source, model, normalizeToolCallId) : transformTransportMessages(source, model, normalizeToolCallId, {
|
|
1662
|
+
normalizeSameModelToolCallIds: shouldNormalizeSameModelToolCallIds,
|
|
1663
|
+
preserveUnframedToolResults: replayPlan.preserveUnframedToolResults
|
|
1664
|
+
});
|
|
1665
|
+
const transformedMessages = transformMessages(replayPlan.messages);
|
|
1666
|
+
const transformedRetainedMessages = replayPlan.retainedMessages ? transformMessages(replayPlan.retainedMessages) : [];
|
|
1667
|
+
if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) messages.push(buildResponsesInputMessage(model.reasoning && (providerStyle ? model.compat?.supportsDeveloperRole !== false : options?.supportsDeveloperRole !== false) ? "developer" : "system", [{
|
|
2093
1668
|
type: "input_text",
|
|
2094
1669
|
text: sanitizeTransportPayloadText(stripSystemPromptCacheBoundary(context.systemPrompt))
|
|
2095
1670
|
}]));
|
|
1671
|
+
const replayMessages = replayPlan.compaction ? [
|
|
1672
|
+
...transformedRetainedMessages,
|
|
1673
|
+
replayPlan.compaction,
|
|
1674
|
+
...transformedMessages
|
|
1675
|
+
] : transformedMessages;
|
|
2096
1676
|
let msgIndex = 0;
|
|
2097
|
-
for (const msg of
|
|
1677
|
+
for (const msg of replayMessages) {
|
|
1678
|
+
if (!("role" in msg)) {
|
|
1679
|
+
messages.push(msg);
|
|
1680
|
+
continue;
|
|
1681
|
+
}
|
|
2098
1682
|
if (msg.role === "user") if (typeof msg.content === "string") messages.push(buildResponsesInputMessage("user", [{
|
|
2099
1683
|
type: "input_text",
|
|
2100
1684
|
text: sanitizeTransportPayloadText(msg.content)
|
|
@@ -2107,8 +1691,9 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2107
1691
|
type: "input_image",
|
|
2108
1692
|
detail: "auto",
|
|
2109
1693
|
image_url: `data:${item.mimeType};base64,${item.data}`
|
|
2110
|
-
}).filter((item) => model.input.includes("image") || item.type !== "input_image");
|
|
1694
|
+
}).filter((item) => providerStyle || model.input.includes("image") || item.type !== "input_image");
|
|
2111
1695
|
if (content.length > 0) messages.push(buildResponsesInputMessage("user", content));
|
|
1696
|
+
else if (providerStyle) continue;
|
|
2112
1697
|
}
|
|
2113
1698
|
else if (msg.role === "assistant") {
|
|
2114
1699
|
const output = [];
|
|
@@ -2116,15 +1701,22 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2116
1701
|
let previousReplayItemWasReasoning = false;
|
|
2117
1702
|
const isDifferentModel = msg.model !== model.id && msg.provider === model.provider && msg.api === model.api;
|
|
2118
1703
|
for (const block of msg.content) if (block.type === "thinking") {
|
|
2119
|
-
if (shouldReplayReasoningItems && block.thinkingSignature && block.thinkingSignature.startsWith("{")) {
|
|
2120
|
-
|
|
1704
|
+
if (shouldReplayReasoningItems && block.thinkingSignature && (providerStyle || block.thinkingSignature.startsWith("{"))) {
|
|
1705
|
+
let reasoningItem;
|
|
1706
|
+
try {
|
|
1707
|
+
reasoningItem = JSON.parse(block.thinkingSignature);
|
|
1708
|
+
} catch {
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1711
|
+
if (!isRecord(reasoningItem) || reasoningItem.type !== "reasoning") continue;
|
|
1712
|
+
const replayableReasoningItem = prepareOpenAIResponsesReasoningItemForReplay(reasoningItem, replayContext, readOpenAIResponsesReasoningReplayBlockMetadata(isRecord(block) ? block : {}), providerStyle ? { preserveUnattributedEncryptedContent: true } : void 0);
|
|
2121
1713
|
if (!shouldReplayResponsesItemIds) delete replayableReasoningItem.id;
|
|
2122
|
-
if (shouldReplayResponsesItemIds && model.provider === "github-copilot" && !isSafeResponsesReplayItemId(replayableReasoningItem.id)) continue;
|
|
1714
|
+
if (shouldReplayResponsesItemIds && !providerStyle && model.provider === "github-copilot" && !isSafeResponsesReplayItemId(replayableReasoningItem.id)) continue;
|
|
2123
1715
|
output.push(replayableReasoningItem);
|
|
2124
1716
|
previousReplayItemWasReasoning = true;
|
|
2125
1717
|
}
|
|
2126
1718
|
} else if (block.type === "text") {
|
|
2127
|
-
const textSignature =
|
|
1719
|
+
const textSignature = parseOpenAIResponsesTextSignature(block.textSignature);
|
|
2128
1720
|
let msgId = resolveReplayableResponsesMessageId({
|
|
2129
1721
|
replayResponsesItemIds: shouldReplayResponsesItemIds,
|
|
2130
1722
|
textSignatureId: textSignature?.id,
|
|
@@ -2158,11 +1750,12 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2158
1750
|
...itemId ? { id: itemId } : {},
|
|
2159
1751
|
call_id: callId,
|
|
2160
1752
|
name: block.name,
|
|
2161
|
-
arguments: typeof block.arguments === "string" ? block.arguments : JSON.stringify(block.arguments ?? {})
|
|
1753
|
+
arguments: providerStyle ? JSON.stringify(block.arguments) : typeof block.arguments === "string" ? block.arguments : JSON.stringify(block.arguments ?? {})
|
|
2162
1754
|
});
|
|
2163
1755
|
previousReplayItemWasReasoning = false;
|
|
2164
1756
|
}
|
|
2165
1757
|
if (output.length > 0) messages.push(...output);
|
|
1758
|
+
else if (providerStyle) continue;
|
|
2166
1759
|
} else if (msg.role === "toolResult") {
|
|
2167
1760
|
const textResult = extractToolResultText(msg.content);
|
|
2168
1761
|
const sanitizedTextResult = sanitizeTransportPayloadText(textResult);
|
|
@@ -2191,6 +1784,123 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2191
1784
|
}
|
|
2192
1785
|
return messages;
|
|
2193
1786
|
}
|
|
1787
|
+
function convertResponsesMessages$1(model, context, allowedToolCallProviders, options) {
|
|
1788
|
+
return convertResponsesMessagesWithStyle(model, context, allowedToolCallProviders, options, "transport");
|
|
1789
|
+
}
|
|
1790
|
+
function convertProviderResponsesMessages(model, context, allowedToolCallProviders, options) {
|
|
1791
|
+
return convertResponsesMessagesWithStyle(model, context, allowedToolCallProviders, options, "provider");
|
|
1792
|
+
}
|
|
1793
|
+
//#endregion
|
|
1794
|
+
//#region packages/ai/src/transports/openai-responses-replay-internal.ts
|
|
1795
|
+
function isAsyncIterable(value) {
|
|
1796
|
+
return (typeof value === "object" && value !== null || typeof value === "function") && Symbol.asyncIterator in value;
|
|
1797
|
+
}
|
|
1798
|
+
function isInvalidEncryptedContentError(error) {
|
|
1799
|
+
if (!error || typeof error !== "object") return false;
|
|
1800
|
+
const record = error;
|
|
1801
|
+
if (record.code === "invalid_encrypted_content" || record.code === "thinking_signature_invalid") return true;
|
|
1802
|
+
const message = typeof record.message === "string" ? record.message : "";
|
|
1803
|
+
return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || record.status === 400 && message.toLowerCase().includes("could not decrypt the provided encrypted_content");
|
|
1804
|
+
}
|
|
1805
|
+
function isOrphanedFunctionCallOutputError(error) {
|
|
1806
|
+
if (!error || typeof error !== "object") return false;
|
|
1807
|
+
const record = error;
|
|
1808
|
+
const message = typeof record.message === "string" ? record.message : "";
|
|
1809
|
+
return /No tool call found for function call output with call_id [A-Za-z0-9_-]+/.test(message);
|
|
1810
|
+
}
|
|
1811
|
+
function commitResponsesEncryptedContentAttempt(attempt, commit) {
|
|
1812
|
+
if (attempt.kind === "compaction-stripped") commit(attempt.rejectedCompaction);
|
|
1813
|
+
}
|
|
1814
|
+
function stripResponsesRequestEncryptedReasoning(request) {
|
|
1815
|
+
const stripped = stripEncryptedReasoningContentFields(request.input);
|
|
1816
|
+
if (!stripped.changed) return request;
|
|
1817
|
+
return {
|
|
1818
|
+
...request,
|
|
1819
|
+
input: stripped.value
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
function stripResponsesRequestCompaction(request) {
|
|
1823
|
+
if (!Array.isArray(request.input)) return request;
|
|
1824
|
+
const input = request.input.filter((item) => !(item !== null && typeof item === "object" && item.type === "compaction"));
|
|
1825
|
+
return input.length === request.input.length ? request : {
|
|
1826
|
+
...request,
|
|
1827
|
+
input
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
function readOpenAIResponsesCompactionRejection(request) {
|
|
1831
|
+
if (!Array.isArray(request.input)) return;
|
|
1832
|
+
const item = request.input.find((candidate) => candidate !== null && typeof candidate === "object" && candidate.type === "compaction" && typeof candidate.encrypted_content === "string");
|
|
1833
|
+
return item ? {
|
|
1834
|
+
data: item.encrypted_content,
|
|
1835
|
+
...typeof item.id === "string" ? { id: item.id } : {}
|
|
1836
|
+
} : void 0;
|
|
1837
|
+
}
|
|
1838
|
+
async function resolveNextResponsesEncryptedContentAttempt(attempt, error, options) {
|
|
1839
|
+
const orphanedFunctionOutput = isOrphanedFunctionCallOutputError(error);
|
|
1840
|
+
if (!isInvalidEncryptedContentError(error) && !orphanedFunctionOutput || attempt.kind === "compaction-stripped") return;
|
|
1841
|
+
if (!orphanedFunctionOutput && (attempt.kind === "initial" || attempt.kind === "continuation-rejected")) {
|
|
1842
|
+
const reasoningStripped = stripResponsesRequestEncryptedReasoning(attempt.request);
|
|
1843
|
+
if (reasoningStripped !== attempt.request) return {
|
|
1844
|
+
kind: "reasoning-stripped",
|
|
1845
|
+
request: reasoningStripped
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1848
|
+
const locallyStripped = stripResponsesRequestCompaction(attempt.request);
|
|
1849
|
+
if (locallyStripped === attempt.request) return;
|
|
1850
|
+
let compactionStripped = options?.buildFullHistoryRequest ? await options.buildFullHistoryRequest() : locallyStripped;
|
|
1851
|
+
compactionStripped = stripResponsesRequestCompaction(compactionStripped);
|
|
1852
|
+
if (attempt.kind === "reasoning-stripped") compactionStripped = stripResponsesRequestEncryptedReasoning(compactionStripped);
|
|
1853
|
+
return {
|
|
1854
|
+
kind: "compaction-stripped",
|
|
1855
|
+
request: compactionStripped,
|
|
1856
|
+
rejectedCompaction: readOpenAIResponsesCompactionRejection(attempt.request)
|
|
1857
|
+
};
|
|
1858
|
+
}
|
|
1859
|
+
async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
1860
|
+
const sendAttempt = async (attempt) => {
|
|
1861
|
+
const { data, response } = await params.client.responses.create(attempt.request, params.requestOptions).withResponse();
|
|
1862
|
+
commitResponsesEncryptedContentAttempt(attempt, (checkpoint) => {
|
|
1863
|
+
if (checkpoint) params.onCompactionRejected?.(checkpoint);
|
|
1864
|
+
});
|
|
1865
|
+
if (!isAsyncIterable(data)) throw new Error("OpenAI Responses streaming request returned a non-stream response");
|
|
1866
|
+
return {
|
|
1867
|
+
stream: data,
|
|
1868
|
+
response,
|
|
1869
|
+
attempt
|
|
1870
|
+
};
|
|
1871
|
+
};
|
|
1872
|
+
let attempt = {
|
|
1873
|
+
kind: params.initialAttemptKind ?? "initial",
|
|
1874
|
+
request: params.request,
|
|
1875
|
+
...params.initialRejectedCompaction ? { rejectedCompaction: params.initialRejectedCompaction } : {}
|
|
1876
|
+
};
|
|
1877
|
+
while (true) {
|
|
1878
|
+
params.observePrompt?.(attempt.request, {
|
|
1879
|
+
egress: "responses-sdk",
|
|
1880
|
+
payloadVariant: attempt.kind
|
|
1881
|
+
});
|
|
1882
|
+
try {
|
|
1883
|
+
return await sendAttempt(attempt);
|
|
1884
|
+
} catch (error) {
|
|
1885
|
+
let nextAttempt = await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
|
|
1886
|
+
if (!nextAttempt && attempt.request.previous_response_id && error && typeof error === "object" && typeof error.status === "number" && error.code === "previous_response_not_found") {
|
|
1887
|
+
const request = { ...params.buildFullHistoryRequest ? await params.buildFullHistoryRequest() : attempt.request };
|
|
1888
|
+
delete request.previous_response_id;
|
|
1889
|
+
nextAttempt = {
|
|
1890
|
+
kind: "continuation-rejected",
|
|
1891
|
+
request
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
if (!nextAttempt) throw error;
|
|
1895
|
+
const retryDescription = nextAttempt.kind === "reasoning-stripped" ? "without encrypted reasoning content" : nextAttempt.kind === "compaction-stripped" ? "without encrypted compaction content" : "full history after rejected previous_response_id";
|
|
1896
|
+
log.warn(`[responses] retrying ${retryDescription} provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
|
|
1897
|
+
attempt = nextAttempt;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
function resolveAzureOpenAIApiVersion(env = process.env) {
|
|
1902
|
+
return env.AZURE_OPENAI_API_VERSION?.trim() || "preview";
|
|
1903
|
+
}
|
|
2194
1904
|
//#endregion
|
|
2195
1905
|
//#region packages/ai/src/providers/openai-responses-stream-compat.ts
|
|
2196
1906
|
const OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE = "output_text";
|
|
@@ -2220,19 +1930,16 @@ function resolveResponsesMessageSnapshotCollapse(params) {
|
|
|
2220
1930
|
}
|
|
2221
1931
|
//#endregion
|
|
2222
1932
|
//#region packages/ai/src/providers/openai-responses-tool-call-tracker.ts
|
|
2223
|
-
function readIdentityValue(value) {
|
|
2224
|
-
return (typeof value === "string" ? value.trim() : "") || void 0;
|
|
2225
|
-
}
|
|
2226
1933
|
function readOutputIndex(event) {
|
|
2227
1934
|
return typeof event.output_index === "number" && Number.isInteger(event.output_index) && event.output_index >= 0 ? event.output_index : void 0;
|
|
2228
1935
|
}
|
|
2229
1936
|
function readEventIdentity(event) {
|
|
2230
|
-
return { itemId:
|
|
1937
|
+
return { itemId: normalizeOptionalString(event.item_id) };
|
|
2231
1938
|
}
|
|
2232
1939
|
function readResponsesToolCallItemIdentity(item) {
|
|
2233
1940
|
return {
|
|
2234
|
-
itemId:
|
|
2235
|
-
callId:
|
|
1941
|
+
itemId: normalizeOptionalString(item.id),
|
|
1942
|
+
callId: normalizeOptionalString(item.call_id)
|
|
2236
1943
|
};
|
|
2237
1944
|
}
|
|
2238
1945
|
function createResponsesToolCallTracker() {
|
|
@@ -2295,6 +2002,308 @@ function createResponsesToolCallTracker() {
|
|
|
2295
2002
|
};
|
|
2296
2003
|
}
|
|
2297
2004
|
//#endregion
|
|
2005
|
+
//#region packages/ai/src/transports/openai-responses-debug.ts
|
|
2006
|
+
function stringifyUnknown(value, fallback = "") {
|
|
2007
|
+
if (typeof value === "string") return value;
|
|
2008
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
2009
|
+
return fallback;
|
|
2010
|
+
}
|
|
2011
|
+
function safeDebugValue(value) {
|
|
2012
|
+
if (typeof value === "string") return value;
|
|
2013
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
2014
|
+
if (value === null) return "null";
|
|
2015
|
+
if (value === void 0) return "undefined";
|
|
2016
|
+
return Array.isArray(value) ? "array" : typeof value;
|
|
2017
|
+
}
|
|
2018
|
+
function responseInputTextChars(input) {
|
|
2019
|
+
if (typeof input === "string") return input.length;
|
|
2020
|
+
if (Array.isArray(input)) return input.reduce((total, item) => total + responseInputTextChars(item), 0);
|
|
2021
|
+
if (!input || typeof input !== "object") return 0;
|
|
2022
|
+
const record = input;
|
|
2023
|
+
let total = 0;
|
|
2024
|
+
if (typeof record.text === "string") total += record.text.length;
|
|
2025
|
+
if (typeof record.content === "string") total += record.content.length;
|
|
2026
|
+
else if (Array.isArray(record.content)) total += responseInputTextChars(record.content);
|
|
2027
|
+
return total;
|
|
2028
|
+
}
|
|
2029
|
+
function responseInputRoles(input) {
|
|
2030
|
+
if (!Array.isArray(input)) return "";
|
|
2031
|
+
const roles = /* @__PURE__ */ new Set();
|
|
2032
|
+
for (const item of input) if (item && typeof item === "object") {
|
|
2033
|
+
const role = item.role;
|
|
2034
|
+
if (typeof role === "string" && role.trim()) roles.add(role.trim());
|
|
2035
|
+
}
|
|
2036
|
+
return [...roles].toSorted().join(",");
|
|
2037
|
+
}
|
|
2038
|
+
function responseInputItemShape(input) {
|
|
2039
|
+
if (!Array.isArray(input)) return "none";
|
|
2040
|
+
return input.map((item) => {
|
|
2041
|
+
if (!isRecord(item) || typeof item.type !== "string") return "unknown";
|
|
2042
|
+
if (item.type === "message" && typeof item.role === "string") return `message:${item.role}`;
|
|
2043
|
+
return item.type;
|
|
2044
|
+
}).join(",") || "none";
|
|
2045
|
+
}
|
|
2046
|
+
function hashOpaqueResponsesValue(value) {
|
|
2047
|
+
return createHash("sha256").update(value).digest("hex");
|
|
2048
|
+
}
|
|
2049
|
+
function summarizeResponsesCompactionItems(input) {
|
|
2050
|
+
if (!Array.isArray(input)) return [
|
|
2051
|
+
"compactionItems=0",
|
|
2052
|
+
"compactionIdHashes=none",
|
|
2053
|
+
"compactionPayloadHashes=none",
|
|
2054
|
+
"compactionInputIndexes=none"
|
|
2055
|
+
];
|
|
2056
|
+
const compactions = input.flatMap((item, inputIndex) => {
|
|
2057
|
+
if (!isRecord(item) || item.type !== "compaction") return [];
|
|
2058
|
+
return [{
|
|
2059
|
+
idHash: typeof item.id === "string" ? hashOpaqueResponsesValue(item.id) : void 0,
|
|
2060
|
+
inputIndex,
|
|
2061
|
+
payloadHash: typeof item.encrypted_content === "string" ? hashOpaqueResponsesValue(item.encrypted_content) : void 0
|
|
2062
|
+
}];
|
|
2063
|
+
});
|
|
2064
|
+
return [
|
|
2065
|
+
`compactionItems=${compactions.length}`,
|
|
2066
|
+
`compactionIdHashes=${compactions.flatMap((item) => item.idHash ?? []).join(",") || "none"}`,
|
|
2067
|
+
`compactionPayloadHashes=${compactions.flatMap((item) => item.payloadHash ?? []).join(",") || "none"}`,
|
|
2068
|
+
`compactionInputIndexes=${compactions.map((item) => item.inputIndex).join(",") || "none"}`
|
|
2069
|
+
];
|
|
2070
|
+
}
|
|
2071
|
+
function readToolPayloadField(record, field) {
|
|
2072
|
+
try {
|
|
2073
|
+
return record[field];
|
|
2074
|
+
} catch {
|
|
2075
|
+
return;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
function readResponsesToolDisplayName(tool) {
|
|
2079
|
+
if (!tool || typeof tool !== "object") return "";
|
|
2080
|
+
const record = tool;
|
|
2081
|
+
const name = readToolPayloadField(record, "name");
|
|
2082
|
+
if (typeof name === "string") return name;
|
|
2083
|
+
const fn = readToolPayloadField(record, "function");
|
|
2084
|
+
if (fn && typeof fn === "object") {
|
|
2085
|
+
const fnName = readToolPayloadField(fn, "name");
|
|
2086
|
+
if (typeof fnName === "string") return fnName;
|
|
2087
|
+
}
|
|
2088
|
+
const type = readToolPayloadField(record, "type");
|
|
2089
|
+
return typeof type === "string" && type !== "function" ? type : "";
|
|
2090
|
+
}
|
|
2091
|
+
function summarizeResponsesTools(tools) {
|
|
2092
|
+
if (!Array.isArray(tools)) return "count=0";
|
|
2093
|
+
const names = tools.map(readResponsesToolDisplayName).filter(Boolean);
|
|
2094
|
+
const mode = resolveModelPayloadDebugMode();
|
|
2095
|
+
const maxNames = mode === "tools" || mode === "full-redacted" ? names.length : 12;
|
|
2096
|
+
const label = maxNames >= names.length ? "names" : "sample";
|
|
2097
|
+
const shown = names.slice(0, maxNames).join(",");
|
|
2098
|
+
return `count=${tools.length}${shown ? ` ${label}=${shown}` : ""}`;
|
|
2099
|
+
}
|
|
2100
|
+
function stringifyRedactedPayload(value) {
|
|
2101
|
+
try {
|
|
2102
|
+
const encoded = JSON.stringify(value, (key, child) => key === "encrypted_content" ? "<opaque data omitted>" : child);
|
|
2103
|
+
if (!encoded) return "<empty>";
|
|
2104
|
+
const redacted = redactSensitiveText(encoded, { mode: "tools" });
|
|
2105
|
+
return redacted.length > 8e3 ? `${truncateUtf16Safe(redacted, 8e3)}…<truncated>` : redacted;
|
|
2106
|
+
} catch {
|
|
2107
|
+
return "<unserializable>";
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
function stringifyRedactedEvent(value) {
|
|
2111
|
+
const redacted = stringifyRedactedPayload(value);
|
|
2112
|
+
return redacted.length > 2e3 ? `${truncateUtf16Safe(redacted, 2e3)}…<truncated>` : redacted;
|
|
2113
|
+
}
|
|
2114
|
+
const RESPONSE_FAILED_FAILURE_FIELD_KEYS = [
|
|
2115
|
+
"error",
|
|
2116
|
+
"incomplete_details",
|
|
2117
|
+
"status_details",
|
|
2118
|
+
"failure_reason",
|
|
2119
|
+
"last_error",
|
|
2120
|
+
"provider_error",
|
|
2121
|
+
"error_details"
|
|
2122
|
+
];
|
|
2123
|
+
function readResponseFailedString(record, key) {
|
|
2124
|
+
return stringifyUnknown(record?.[key]);
|
|
2125
|
+
}
|
|
2126
|
+
function buildResponsesFailedEventSummary(message, responseId, observation) {
|
|
2127
|
+
const summary = { message };
|
|
2128
|
+
if (responseId) summary.responseId = responseId;
|
|
2129
|
+
if (observation) summary.observation = observation;
|
|
2130
|
+
return summary;
|
|
2131
|
+
}
|
|
2132
|
+
function isResponseFailedIdentifierKey(key) {
|
|
2133
|
+
const normalized = key.replace(/[-_\s]/g, "").toLowerCase();
|
|
2134
|
+
return normalized === "requestid" || normalized === "xrequestid" || normalized === "providerrequestid" || normalized === "providerresponseid" || normalized === "litellmrequestid" || normalized.includes("request") && normalized.endsWith("id") || normalized.includes("provider") && normalized.endsWith("id");
|
|
2135
|
+
}
|
|
2136
|
+
function collectResponseFailedIdentifierHashes(value, opts = {}) {
|
|
2137
|
+
const path = opts.path ?? "";
|
|
2138
|
+
const depth = opts.depth ?? 0;
|
|
2139
|
+
const identifierKey = opts.identifierKey ?? "";
|
|
2140
|
+
const out = opts.out ?? [];
|
|
2141
|
+
const seen = opts.seen ?? /* @__PURE__ */ new WeakSet();
|
|
2142
|
+
if (out.length >= 12 || depth > 4 || !value || typeof value !== "object") return out;
|
|
2143
|
+
if (seen.has(value)) return out;
|
|
2144
|
+
seen.add(value);
|
|
2145
|
+
if (Array.isArray(value)) {
|
|
2146
|
+
for (const [index, item] of value.entries()) {
|
|
2147
|
+
if (index >= 8 || out.length >= 12) break;
|
|
2148
|
+
const itemString = typeof item === "string" || typeof item === "number" ? String(item).trim() : "";
|
|
2149
|
+
if (identifierKey && isResponseFailedIdentifierKey(identifierKey) && itemString) {
|
|
2150
|
+
out.push(`${path}[${index}]=${redactIdentifier(itemString, { len: 12 })}`);
|
|
2151
|
+
continue;
|
|
2152
|
+
}
|
|
2153
|
+
collectResponseFailedIdentifierHashes(item, {
|
|
2154
|
+
path: `${path}[${index}]`,
|
|
2155
|
+
depth: depth + 1,
|
|
2156
|
+
identifierKey,
|
|
2157
|
+
out,
|
|
2158
|
+
seen
|
|
2159
|
+
});
|
|
2160
|
+
}
|
|
2161
|
+
return out;
|
|
2162
|
+
}
|
|
2163
|
+
for (const [key, child] of Object.entries(value)) {
|
|
2164
|
+
if (out.length >= 12) break;
|
|
2165
|
+
const childPath = path ? `${path}.${key}` : key;
|
|
2166
|
+
const childString = typeof child === "string" || typeof child === "number" ? String(child).trim() : "";
|
|
2167
|
+
if (isResponseFailedIdentifierKey(key) && childString) {
|
|
2168
|
+
out.push(`${childPath}=${redactIdentifier(childString, { len: 12 })}`);
|
|
2169
|
+
continue;
|
|
2170
|
+
}
|
|
2171
|
+
collectResponseFailedIdentifierHashes(child, {
|
|
2172
|
+
path: childPath,
|
|
2173
|
+
depth: depth + 1,
|
|
2174
|
+
identifierKey: isResponseFailedIdentifierKey(key) ? key : void 0,
|
|
2175
|
+
out,
|
|
2176
|
+
seen
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
return out;
|
|
2180
|
+
}
|
|
2181
|
+
function redactResponseFailedDiagnosticValue(value, opts = {}) {
|
|
2182
|
+
const key = opts.key ?? "";
|
|
2183
|
+
const depth = opts.depth ?? 0;
|
|
2184
|
+
if (typeof value === "string" || typeof value === "number") return key && isResponseFailedIdentifierKey(key) ? redactIdentifier(String(value), { len: 12 }) : value;
|
|
2185
|
+
if (depth > 6 || !value || typeof value !== "object") return value;
|
|
2186
|
+
const seen = opts.seen ?? /* @__PURE__ */ new WeakSet();
|
|
2187
|
+
if (seen.has(value)) return "<circular>";
|
|
2188
|
+
seen.add(value);
|
|
2189
|
+
if (Array.isArray(value)) return value.slice(0, 16).map((item) => redactResponseFailedDiagnosticValue(item, {
|
|
2190
|
+
key,
|
|
2191
|
+
depth: depth + 1,
|
|
2192
|
+
seen
|
|
2193
|
+
}));
|
|
2194
|
+
const out = {};
|
|
2195
|
+
for (const [childKey, child] of Object.entries(value)) out[childKey] = redactResponseFailedDiagnosticValue(child, {
|
|
2196
|
+
key: childKey,
|
|
2197
|
+
depth: depth + 1,
|
|
2198
|
+
seen
|
|
2199
|
+
});
|
|
2200
|
+
return out;
|
|
2201
|
+
}
|
|
2202
|
+
function buildResponsesFailedFailureFields(response) {
|
|
2203
|
+
if (!response) return {};
|
|
2204
|
+
const fields = {};
|
|
2205
|
+
for (const key of RESPONSE_FAILED_FAILURE_FIELD_KEYS) if (response[key] !== void 0 && response[key] !== null) fields[key] = response[key];
|
|
2206
|
+
return fields;
|
|
2207
|
+
}
|
|
2208
|
+
function buildResponsesFailedNoDetailsObservation(event, model, response = isRecord(event.response) ? event.response : void 0) {
|
|
2209
|
+
const failureFields = redactResponseFailedDiagnosticValue(buildResponsesFailedFailureFields(response));
|
|
2210
|
+
const metadataKeys = isRecord(response?.metadata) ? Object.keys(response.metadata).toSorted() : [];
|
|
2211
|
+
const responsePreview = {
|
|
2212
|
+
id: readResponseFailedString(response, "id"),
|
|
2213
|
+
status: readResponseFailedString(response, "status"),
|
|
2214
|
+
model: readResponseFailedString(response, "model"),
|
|
2215
|
+
object: readResponseFailedString(response, "object"),
|
|
2216
|
+
failureFields,
|
|
2217
|
+
metadataKeys
|
|
2218
|
+
};
|
|
2219
|
+
return {
|
|
2220
|
+
event: "openai_responses_response_failed_without_details",
|
|
2221
|
+
provider: model.provider,
|
|
2222
|
+
api: model.api,
|
|
2223
|
+
transportModel: model.id,
|
|
2224
|
+
providerRuntimeFailureKind: "no_error_details",
|
|
2225
|
+
responseId: responsePreview.id,
|
|
2226
|
+
responseStatus: responsePreview.status,
|
|
2227
|
+
responseModel: responsePreview.model,
|
|
2228
|
+
responseObject: responsePreview.object,
|
|
2229
|
+
metadataKeys,
|
|
2230
|
+
requestIdHashes: collectResponseFailedIdentifierHashes(event),
|
|
2231
|
+
failureFieldsPreview: stringifyRedactedEvent(failureFields),
|
|
2232
|
+
responsePreview: stringifyRedactedEvent(responsePreview)
|
|
2233
|
+
};
|
|
2234
|
+
}
|
|
2235
|
+
function summarizeResponsesFailedNoDetailsObservation(observation) {
|
|
2236
|
+
const requestIds = observation.requestIdHashes.join(",");
|
|
2237
|
+
const metadataKeys = observation.metadataKeys.join(",");
|
|
2238
|
+
return `responseId=${safeDebugValue(observation.responseId || void 0)} responseStatus=${safeDebugValue(observation.responseStatus || void 0)} responseModel=${safeDebugValue(observation.responseModel || void 0)} requestIds=${requestIds || "none"} metadataKeys=${metadataKeys || "none"} failureFields=${observation.failureFieldsPreview}`;
|
|
2239
|
+
}
|
|
2240
|
+
function normalizeResponsesFailedEvent(event, model) {
|
|
2241
|
+
const response = isRecord(event.response) ? event.response : void 0;
|
|
2242
|
+
const responseId = readResponseFailedString(response, "id") || void 0;
|
|
2243
|
+
const error = isRecord(response?.error) ? response.error : void 0;
|
|
2244
|
+
if (error) {
|
|
2245
|
+
const code = readResponseFailedString(error, "code").trim();
|
|
2246
|
+
const message = readResponseFailedString(error, "message").trim();
|
|
2247
|
+
if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId);
|
|
2248
|
+
}
|
|
2249
|
+
const incompleteReason = readResponseFailedString(isRecord(response?.incomplete_details) ? response.incomplete_details : void 0, "reason");
|
|
2250
|
+
if (incompleteReason) return buildResponsesFailedEventSummary(`incomplete: ${incompleteReason}`, responseId);
|
|
2251
|
+
return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, buildResponsesFailedNoDetailsObservation(event, model, response));
|
|
2252
|
+
}
|
|
2253
|
+
var ResponsesStreamFailure = class extends Error {
|
|
2254
|
+
constructor(failure, response) {
|
|
2255
|
+
super(failure.message);
|
|
2256
|
+
this.name = "ResponsesStreamFailure";
|
|
2257
|
+
this.responseId = failure.responseId;
|
|
2258
|
+
this.response = response;
|
|
2259
|
+
this.observation = failure.observation;
|
|
2260
|
+
}
|
|
2261
|
+
};
|
|
2262
|
+
function logResponsesFailedNoDetails(observation) {
|
|
2263
|
+
log.warn(`[responses] response.failed missing error details provider=${observation.provider} api=${observation.api} model=${observation.transportModel} ` + summarizeResponsesFailedNoDetailsObservation(observation), observation);
|
|
2264
|
+
}
|
|
2265
|
+
function summarizeResponsesPayload(params) {
|
|
2266
|
+
if (!params || typeof params !== "object") return "payload=non-object";
|
|
2267
|
+
const record = params;
|
|
2268
|
+
const input = record.input;
|
|
2269
|
+
const reasoning = record.reasoning && typeof record.reasoning === "object" ? record.reasoning : void 0;
|
|
2270
|
+
const text = record.text && typeof record.text === "object" ? record.text : void 0;
|
|
2271
|
+
const parts = [
|
|
2272
|
+
`fields=${Object.keys(record).toSorted().join(",")}`,
|
|
2273
|
+
`model=${safeDebugValue(record.model)}`,
|
|
2274
|
+
`stream=${safeDebugValue(record.stream)}`,
|
|
2275
|
+
`inputItems=${Array.isArray(input) ? input.length : typeof input}`,
|
|
2276
|
+
`inputItemShape=${responseInputItemShape(input)}`,
|
|
2277
|
+
`inputRoles=${responseInputRoles(input) || "none"}`,
|
|
2278
|
+
`inputTextChars=${responseInputTextChars(input)}`,
|
|
2279
|
+
`tools=${summarizeResponsesTools(record.tools)}`,
|
|
2280
|
+
`reasoningEffort=${safeDebugValue(reasoning?.effort)}`,
|
|
2281
|
+
`reasoningSummary=${safeDebugValue(reasoning?.summary)}`,
|
|
2282
|
+
`textVerbosity=${safeDebugValue(text?.verbosity)}`,
|
|
2283
|
+
`serviceTier=${safeDebugValue(record.service_tier)}`,
|
|
2284
|
+
...summarizeResponsesCompactionItems(input),
|
|
2285
|
+
`store=${safeDebugValue(record.store)}`,
|
|
2286
|
+
`promptCacheKey=${record.prompt_cache_key === void 0 ? "absent" : "present"}`,
|
|
2287
|
+
`metadataKeys=${record.metadata && typeof record.metadata === "object" ? Object.keys(record.metadata).toSorted().join(",") : "none"}`
|
|
2288
|
+
];
|
|
2289
|
+
if (resolveModelPayloadDebugMode() === "full-redacted") parts.push(`payload=${stringifyRedactedPayload(record)}`);
|
|
2290
|
+
return parts.join(" ");
|
|
2291
|
+
}
|
|
2292
|
+
function summarizeOpenAITransportError(error) {
|
|
2293
|
+
if (!error || typeof error !== "object") return `type=${typeof error} message=${safeDebugValue(error)}`;
|
|
2294
|
+
const record = error;
|
|
2295
|
+
const cause = record.cause && typeof record.cause === "object" ? record.cause : void 0;
|
|
2296
|
+
return [
|
|
2297
|
+
`name=${safeDebugValue(record.name)}`,
|
|
2298
|
+
`status=${safeDebugValue(record.status)}`,
|
|
2299
|
+
`code=${safeDebugValue(record.code)}`,
|
|
2300
|
+
`type=${safeDebugValue(record.type)}`,
|
|
2301
|
+
`causeName=${safeDebugValue(cause?.name)}`,
|
|
2302
|
+
`causeCode=${safeDebugValue(cause?.code)}`,
|
|
2303
|
+
`message=${error instanceof Error ? error.message : safeDebugValue(error)}`
|
|
2304
|
+
].join(" ");
|
|
2305
|
+
}
|
|
2306
|
+
//#endregion
|
|
2298
2307
|
//#region packages/ai/src/transports/openai-responses-stream-observer-internal.ts
|
|
2299
2308
|
const STRING_DELTA_EVENTS = /* @__PURE__ */ new Set([
|
|
2300
2309
|
"response.function_call_arguments.delta",
|
|
@@ -2316,7 +2325,7 @@ async function* adaptResponsesStream(stream, signal) {
|
|
|
2316
2325
|
await scheduler.afterEvent();
|
|
2317
2326
|
}
|
|
2318
2327
|
}
|
|
2319
|
-
async function* observeResponsesStream(stream, model) {
|
|
2328
|
+
async function* observeResponsesStream(stream, model, requestStartedAt) {
|
|
2320
2329
|
const startedAt = Date.now();
|
|
2321
2330
|
const eventTypes = /* @__PURE__ */ new Map();
|
|
2322
2331
|
const debugMode = resolveModelSseDebugMode();
|
|
@@ -2326,7 +2335,7 @@ async function* observeResponsesStream(stream, model) {
|
|
|
2326
2335
|
const type = isRecord(event) && typeof event.type === "string" ? event.type : "unknown";
|
|
2327
2336
|
eventCount += 1;
|
|
2328
2337
|
eventTypes.set(type, (eventTypes.get(type) ?? 0) + 1);
|
|
2329
|
-
if (eventCount === 1) emitModelTransportDebug(log, `[responses] first_event provider=${model.provider} api=${model.api} model=${model.id} elapsedMs=${Date.now() - startedAt} type=${type}`);
|
|
2338
|
+
if (eventCount === 1) emitModelTransportDebug(log, `[responses] first_event provider=${model.provider} api=${model.api} model=${model.id} elapsedMs=${Date.now() - (requestStartedAt ?? startedAt)} headersToEventMs=${Date.now() - startedAt} type=${type}`);
|
|
2330
2339
|
if (debugMode === "peek" && eventCount <= 5) emitModelTransportDebug(log, `[responses] event_peek provider=${model.provider} api=${model.api} model=${model.id} index=${eventCount} type=${type} event=${stringifyRedactedEvent(event)}`);
|
|
2331
2340
|
yield event;
|
|
2332
2341
|
}
|
|
@@ -2337,6 +2346,23 @@ async function* observeResponsesStream(stream, model) {
|
|
|
2337
2346
|
}
|
|
2338
2347
|
//#endregion
|
|
2339
2348
|
//#region packages/ai/src/transports/openai-responses-stream-slots-internal.ts
|
|
2349
|
+
function createResponsesOutputContentIndex() {
|
|
2350
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
2351
|
+
const identity = (item) => {
|
|
2352
|
+
if ((item.type === "reasoning" || item.type === "message") && item.id) return `${item.type}:${item.id}`;
|
|
2353
|
+
return item.type === "function_call" ? `function_call:${item.call_id ?? item.id ?? ""}` : void 0;
|
|
2354
|
+
};
|
|
2355
|
+
return {
|
|
2356
|
+
get(item) {
|
|
2357
|
+
const key = identity(item);
|
|
2358
|
+
return key === void 0 ? void 0 : indexes.get(key);
|
|
2359
|
+
},
|
|
2360
|
+
set(item, contentIndex) {
|
|
2361
|
+
const key = identity(item);
|
|
2362
|
+
if (key !== void 0) indexes.set(key, contentIndex);
|
|
2363
|
+
}
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2340
2366
|
function appendResponsesPendingTextDelta(slot, delta, materialize) {
|
|
2341
2367
|
slot.pendingText = `${slot.pendingText ?? ""}${delta}`;
|
|
2342
2368
|
const priorText = slot.collapseCandidate?.block.text ?? "";
|
|
@@ -2385,6 +2411,14 @@ function createResponsesOutputSlotTracker() {
|
|
|
2385
2411
|
}
|
|
2386
2412
|
//#endregion
|
|
2387
2413
|
//#region packages/ai/src/providers/openai-responses-terminal-usage.ts
|
|
2414
|
+
/**
|
|
2415
|
+
* Canonical mapping for terminal OpenAI Responses events.
|
|
2416
|
+
*
|
|
2417
|
+
* `response.completed`, `response.incomplete`, and `response.failed` are terminal and can carry
|
|
2418
|
+
* usage, so every Responses path finalizes through the helpers here. Keeping one owner prevents
|
|
2419
|
+
* package and managed transports from drifting on token buckets, service-tier pricing, or future
|
|
2420
|
+
* terminal-event semantics.
|
|
2421
|
+
*/
|
|
2388
2422
|
function readCount(value) {
|
|
2389
2423
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2390
2424
|
}
|
|
@@ -2414,8 +2448,7 @@ function mapResponsesTerminalUsage(usage) {
|
|
|
2414
2448
|
}
|
|
2415
2449
|
/** Reasoning tokens are reported by the agent path only; the package path does not track them. */
|
|
2416
2450
|
function readResponsesReasoningTokens(usage) {
|
|
2417
|
-
|
|
2418
|
-
return typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) ? reasoningTokens : void 0;
|
|
2451
|
+
return asFiniteNumber(usage?.output_tokens_details?.reasoning_tokens);
|
|
2419
2452
|
}
|
|
2420
2453
|
function mapResponsesTerminalStopReason(status) {
|
|
2421
2454
|
if (!status) return "stop";
|
|
@@ -2467,11 +2500,9 @@ function resolveCompletedResponsesToolCall(item, streamed) {
|
|
|
2467
2500
|
if (streamedName && completedName && streamedName !== completedName) throw new Error(`Responses stream changed tool-call function name from ${streamedName} to ${completedName}`);
|
|
2468
2501
|
const name = completedName ?? streamedName;
|
|
2469
2502
|
if (!name) throw new Error("Responses stream completed tool call without a function name");
|
|
2470
|
-
const argumentsValue = parseJsonObjectPreservingUnsafeIntegers(streamed?.arguments ?? item.arguments);
|
|
2471
|
-
if (!argumentsValue) throw new Error("Responses stream completed tool call with invalid JSON arguments");
|
|
2472
2503
|
return {
|
|
2473
2504
|
name,
|
|
2474
|
-
arguments:
|
|
2505
|
+
arguments: parseTerminalToolCallArguments(streamed?.arguments ?? item.arguments, "Responses stream completed tool call with invalid JSON arguments")
|
|
2475
2506
|
};
|
|
2476
2507
|
}
|
|
2477
2508
|
function createResponsesTerminalController(params) {
|
|
@@ -2522,7 +2553,7 @@ function createResponsesTerminalController(params) {
|
|
|
2522
2553
|
content: text,
|
|
2523
2554
|
partial: output
|
|
2524
2555
|
});
|
|
2525
|
-
return;
|
|
2556
|
+
return started.index;
|
|
2526
2557
|
}
|
|
2527
2558
|
const previous = params.getLastTextBlock();
|
|
2528
2559
|
const collapse = resolveResponsesMessageSnapshotCollapse({
|
|
@@ -2542,7 +2573,7 @@ function createResponsesTerminalController(params) {
|
|
|
2542
2573
|
content: collapse.text,
|
|
2543
2574
|
partial: output
|
|
2544
2575
|
});
|
|
2545
|
-
return;
|
|
2576
|
+
return previous.index;
|
|
2546
2577
|
}
|
|
2547
2578
|
const block = {
|
|
2548
2579
|
type: "text",
|
|
@@ -2567,6 +2598,7 @@ function createResponsesTerminalController(params) {
|
|
|
2567
2598
|
content: text,
|
|
2568
2599
|
partial: output
|
|
2569
2600
|
});
|
|
2601
|
+
return index;
|
|
2570
2602
|
};
|
|
2571
2603
|
const appendToolCall = (item) => {
|
|
2572
2604
|
const validated = resolveCompletedResponsesToolCall(item);
|
|
@@ -2589,17 +2621,17 @@ function createResponsesTerminalController(params) {
|
|
|
2589
2621
|
toolCall,
|
|
2590
2622
|
partial: output
|
|
2591
2623
|
});
|
|
2624
|
+
return contentIndex;
|
|
2592
2625
|
};
|
|
2593
2626
|
const recoverTerminalOutput = (items, includeToolCalls) => {
|
|
2594
2627
|
let hasCompletedLaterOutput = false;
|
|
2595
2628
|
for (const item of items.toReversed()) {
|
|
2596
2629
|
if (item.type === "reasoning") {
|
|
2597
|
-
hasCompletedLaterOutput ||= params.
|
|
2630
|
+
hasCompletedLaterOutput ||= params.outputItemContentIndexes.get(item) !== void 0;
|
|
2598
2631
|
continue;
|
|
2599
2632
|
}
|
|
2600
2633
|
if (item.type !== "message" && item.type !== "function_call") continue;
|
|
2601
|
-
|
|
2602
|
-
if (params.completedOutputItemIdentities.has(identity) || item.type === "message" && params.startedTextBlocksByItemId.has(item.id)) {
|
|
2634
|
+
if (params.outputItemContentIndexes.get(item) !== void 0 || item.type === "message" && params.startedTextBlocksByItemId.has(item.id)) {
|
|
2603
2635
|
hasCompletedLaterOutput = true;
|
|
2604
2636
|
continue;
|
|
2605
2637
|
}
|
|
@@ -2607,25 +2639,32 @@ function createResponsesTerminalController(params) {
|
|
|
2607
2639
|
if (hasCompletedLaterOutput) throw new Error("Responses stream omitted an output item before completed output");
|
|
2608
2640
|
if (item.type === "function_call") resolveCompletedResponsesToolCall(item);
|
|
2609
2641
|
}
|
|
2610
|
-
for (const item of items) if (item.type === "message") {
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
params.completedOutputItemIdentities.add(identity);
|
|
2642
|
+
for (const [terminalIndex, item] of items.entries()) if (item.type === "message") {
|
|
2643
|
+
if (params.outputItemContentIndexes.get(item) !== void 0 && !params.startedTextBlocksByItemId.has(item.id)) continue;
|
|
2644
|
+
const appendedIndex = appendText(item);
|
|
2645
|
+
if (appendedIndex !== void 0) params.outputItemContentIndexes.set(item, appendedIndex);
|
|
2615
2646
|
} else {
|
|
2616
2647
|
params.setLastTextBlock(null);
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2648
|
+
const alreadyCapturedCompaction = item.type === "compaction" && output.providerReplay?.type === "openai-responses-compaction" && output.providerReplay.id === item.id && output.providerReplay.data === item.encrypted_content;
|
|
2649
|
+
if (item.type === "compaction" && !alreadyCapturedCompaction) {
|
|
2650
|
+
let replayIndex = blocks.length;
|
|
2651
|
+
for (const laterItem of items.slice(terminalIndex + 1)) {
|
|
2652
|
+
const laterContentIndex = params.outputItemContentIndexes.get(laterItem);
|
|
2653
|
+
if (laterContentIndex !== void 0) {
|
|
2654
|
+
replayIndex = laterContentIndex;
|
|
2655
|
+
break;
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
captureOpenAIResponsesCompaction(output, item, replayIndex, model, options?.reasoningReplayMetadata);
|
|
2659
|
+
} else if (includeToolCalls && item.type === "function_call") {
|
|
2660
|
+
if (params.outputItemContentIndexes.get(item) !== void 0) continue;
|
|
2661
|
+
params.outputItemContentIndexes.set(item, appendToolCall(item));
|
|
2622
2662
|
}
|
|
2623
2663
|
}
|
|
2624
2664
|
};
|
|
2625
|
-
const
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
output.responseId = response.id || output.responseId;
|
|
2665
|
+
const finalizeTerminalFacts = (response, responseId = response.id) => {
|
|
2666
|
+
output.responseId = responseId || output.responseId;
|
|
2667
|
+
output.responseModel = response.model?.trim() || void 0;
|
|
2629
2668
|
const usage = mapResponsesTerminalUsage(response.usage);
|
|
2630
2669
|
const reasoningTokens = readResponsesReasoningTokens(response.usage);
|
|
2631
2670
|
if (usage) output.usage = {
|
|
@@ -2644,6 +2683,11 @@ function createResponsesTerminalController(params) {
|
|
|
2644
2683
|
const tier = options.resolveServiceTier ? options.resolveServiceTier(response.service_tier, options.serviceTier) : response.service_tier ?? options.serviceTier;
|
|
2645
2684
|
options.applyServiceTierPricing(output.usage, tier);
|
|
2646
2685
|
}
|
|
2686
|
+
};
|
|
2687
|
+
const finalizeResponse = (response, terminalEventType) => {
|
|
2688
|
+
params.markFinalized();
|
|
2689
|
+
backfillReasoning(response.output ?? []);
|
|
2690
|
+
finalizeTerminalFacts(response);
|
|
2647
2691
|
const terminal = resolveResponsesTerminalStopReason({
|
|
2648
2692
|
status: response.status,
|
|
2649
2693
|
terminalEventType,
|
|
@@ -2655,30 +2699,22 @@ function createResponsesTerminalController(params) {
|
|
|
2655
2699
|
};
|
|
2656
2700
|
return {
|
|
2657
2701
|
finalizeResponse,
|
|
2702
|
+
finalizeFailedResponse: finalizeTerminalFacts,
|
|
2658
2703
|
recoverTerminalOutput
|
|
2659
2704
|
};
|
|
2660
2705
|
}
|
|
2661
2706
|
//#endregion
|
|
2662
2707
|
//#region packages/ai/src/transports/openai-responses-stream-internal.ts
|
|
2663
|
-
var ResponsesStreamFailure = class extends Error {
|
|
2664
|
-
constructor(failure, response) {
|
|
2665
|
-
super(failure.message);
|
|
2666
|
-
this.name = "ResponsesStreamFailure";
|
|
2667
|
-
this.responseId = failure.responseId;
|
|
2668
|
-
this.response = response;
|
|
2669
|
-
this.observation = failure.observation;
|
|
2670
|
-
}
|
|
2671
|
-
};
|
|
2672
2708
|
async function processResponsesStream(openaiStream, output, stream, model, options) {
|
|
2673
2709
|
const streamingToolCalls = createResponsesToolCallTracker();
|
|
2674
2710
|
const outputSlots = createResponsesOutputSlotTracker();
|
|
2675
2711
|
const reasoningBlocksById = /* @__PURE__ */ new Map();
|
|
2676
|
-
const
|
|
2712
|
+
const outputItemContentIndexes = createResponsesOutputContentIndex();
|
|
2677
2713
|
const startedTextBlocksByItemId = /* @__PURE__ */ new Map();
|
|
2678
|
-
let
|
|
2714
|
+
let terminalResponse;
|
|
2679
2715
|
let lastTextBlock = null;
|
|
2680
2716
|
const blocks = output.content;
|
|
2681
|
-
const
|
|
2717
|
+
const compactionTracker = createCompactionTracker(output, model, options);
|
|
2682
2718
|
const createOutputSlot = (event, item) => {
|
|
2683
2719
|
if (item.type === "reasoning") {
|
|
2684
2720
|
const block = {
|
|
@@ -2693,6 +2729,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2693
2729
|
};
|
|
2694
2730
|
blocks.push(block);
|
|
2695
2731
|
reasoningBlocksById.set(item.id, block);
|
|
2732
|
+
outputItemContentIndexes.set(item, slot.contentIndex);
|
|
2696
2733
|
outputSlots.register(event, slot);
|
|
2697
2734
|
stream.push({
|
|
2698
2735
|
type: "thinking_start",
|
|
@@ -2719,6 +2756,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2719
2756
|
};
|
|
2720
2757
|
if (block) {
|
|
2721
2758
|
blocks.push(block);
|
|
2759
|
+
outputItemContentIndexes.set(messageItem, slot.contentIndex ?? blocks.length - 1);
|
|
2722
2760
|
startedTextBlocksByItemId.set(messageItem.id, {
|
|
2723
2761
|
block,
|
|
2724
2762
|
index: slot.contentIndex ?? blocks.length - 1,
|
|
@@ -2751,7 +2789,8 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2751
2789
|
...slot.item.phase ? { textSignature: encodeTextSignatureV1(slot.item.id, slot.item.phase) } : {}
|
|
2752
2790
|
};
|
|
2753
2791
|
blocks.push(slot.block);
|
|
2754
|
-
slot.contentIndex =
|
|
2792
|
+
slot.contentIndex = blocks.length - 1;
|
|
2793
|
+
outputItemContentIndexes.set(slot.item, slot.contentIndex);
|
|
2755
2794
|
startedTextBlocksByItemId.set(slot.item.id, {
|
|
2756
2795
|
block: slot.block,
|
|
2757
2796
|
index: slot.contentIndex,
|
|
@@ -2774,21 +2813,19 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2774
2813
|
const materializeDeferredTextSlots = (except) => {
|
|
2775
2814
|
for (const slot of outputSlots.values()) if (slot !== except && slot.type === "text") materializeDeferredTextSlot(slot);
|
|
2776
2815
|
};
|
|
2777
|
-
const { finalizeResponse, recoverTerminalOutput } = createResponsesTerminalController({
|
|
2816
|
+
const { finalizeResponse, finalizeFailedResponse, recoverTerminalOutput } = createResponsesTerminalController({
|
|
2778
2817
|
output,
|
|
2779
2818
|
stream,
|
|
2780
2819
|
model,
|
|
2781
2820
|
options,
|
|
2782
2821
|
reasoningBlocksById,
|
|
2783
|
-
completedOutputItemIdentities,
|
|
2784
2822
|
startedTextBlocksByItemId,
|
|
2823
|
+
outputItemContentIndexes,
|
|
2785
2824
|
getLastTextBlock: () => lastTextBlock,
|
|
2786
2825
|
setLastTextBlock: (block) => {
|
|
2787
2826
|
lastTextBlock = block;
|
|
2788
2827
|
},
|
|
2789
|
-
markFinalized: () =>
|
|
2790
|
-
terminalResponseEvent = "finalized";
|
|
2791
|
-
}
|
|
2828
|
+
markFinalized: () => void 0
|
|
2792
2829
|
});
|
|
2793
2830
|
const guardedStream = adaptResponsesStream(withFirstStreamEventTimeout(openaiStream, {
|
|
2794
2831
|
provider: model.provider,
|
|
@@ -2801,327 +2838,538 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2801
2838
|
hint: "The provider may be stalled while parsing the tool payload; retry with a smaller tool surface or enable OPENCLAW_DEBUG_MODEL_PAYLOAD=tools to inspect exposed tools."
|
|
2802
2839
|
}), options?.signal);
|
|
2803
2840
|
try {
|
|
2804
|
-
for await (const event of guardedStream)
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
contentIndex
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
partial: output
|
|
2855
|
-
});
|
|
2856
|
-
} else if (event.type === "response.reasoning_summary_part.done") {
|
|
2857
|
-
const slot = outputSlots.resolve(event, "thinking");
|
|
2858
|
-
if (!slot) continue;
|
|
2859
|
-
slot.item.summary = slot.item.summary || [];
|
|
2860
|
-
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2861
|
-
if (!lastPart) continue;
|
|
2862
|
-
slot.block.thinking += "\n\n";
|
|
2863
|
-
lastPart.text += "\n\n";
|
|
2864
|
-
stream.push({
|
|
2865
|
-
type: "thinking_delta",
|
|
2866
|
-
contentIndex: slot.contentIndex,
|
|
2867
|
-
delta: "\n\n",
|
|
2868
|
-
partial: output
|
|
2869
|
-
});
|
|
2870
|
-
} else if (event.type === "response.reasoning_text.delta") {
|
|
2871
|
-
const slot = outputSlots.resolve(event, "thinking");
|
|
2872
|
-
if (!slot) continue;
|
|
2873
|
-
slot.block.thinking += event.delta;
|
|
2874
|
-
stream.push({
|
|
2875
|
-
type: "thinking_delta",
|
|
2876
|
-
contentIndex: slot.contentIndex,
|
|
2877
|
-
delta: event.delta,
|
|
2878
|
-
partial: output
|
|
2879
|
-
});
|
|
2880
|
-
} else if (event.type === "response.content_part.added") {
|
|
2881
|
-
const slot = outputSlots.resolve(event, "text");
|
|
2882
|
-
if (!slot) continue;
|
|
2883
|
-
slot.item.content = slot.item.content || [];
|
|
2884
|
-
if (event.part.type === "output_text" || event.part.type === "text" || event.part.type === "refusal") slot.item.content.push(event.part);
|
|
2885
|
-
} else if (event.type === "response.output_text.delta") {
|
|
2886
|
-
const slot = outputSlots.resolve(event, "text");
|
|
2887
|
-
if (!slot) continue;
|
|
2888
|
-
slot.item.content ||= [];
|
|
2889
|
-
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2890
|
-
if (!isResponsesTextContentPartType(lastPart?.type)) {
|
|
2891
|
-
lastPart = {
|
|
2892
|
-
type: "output_text",
|
|
2893
|
-
text: "",
|
|
2894
|
-
annotations: []
|
|
2895
|
-
};
|
|
2896
|
-
slot.item.content.push(lastPart);
|
|
2897
|
-
}
|
|
2898
|
-
lastPart.text += event.delta;
|
|
2899
|
-
if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
|
|
2900
|
-
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2901
|
-
slot.block.text += event.delta;
|
|
2841
|
+
for await (const event of guardedStream) {
|
|
2842
|
+
notifyLlmRequestActivity(options?.signal);
|
|
2843
|
+
if (event.type === "response.created") output.responseId = event.response.id;
|
|
2844
|
+
else if (event.type === "response.output_item.added") {
|
|
2845
|
+
materializeDeferredTextSlots();
|
|
2846
|
+
const item = event.item;
|
|
2847
|
+
compactionTracker.added(item, blocks.length);
|
|
2848
|
+
if (item.type !== "message") lastTextBlock = null;
|
|
2849
|
+
if (item.type === "reasoning" || item.type === "message") createOutputSlot(event, item);
|
|
2850
|
+
else if (item.type === "function_call") {
|
|
2851
|
+
const toolCallBlock = {
|
|
2852
|
+
type: "toolCall",
|
|
2853
|
+
id: resolveResponsesToolCallId(item),
|
|
2854
|
+
name: typeof item.name === "string" ? item.name.trim() : "",
|
|
2855
|
+
arguments: {},
|
|
2856
|
+
partialJson: item.arguments || ""
|
|
2857
|
+
};
|
|
2858
|
+
const contentIndex = output.content.length;
|
|
2859
|
+
const toolCallState = {
|
|
2860
|
+
block: toolCallBlock,
|
|
2861
|
+
contentIndex,
|
|
2862
|
+
argumentStreamReliable: true,
|
|
2863
|
+
...readResponsesToolCallItemIdentity(item)
|
|
2864
|
+
};
|
|
2865
|
+
streamingToolCalls.register(event, toolCallState);
|
|
2866
|
+
if (readResponsesOutputIndex(event) !== void 0) outputSlots.register(event, {
|
|
2867
|
+
type: "toolCall",
|
|
2868
|
+
toolCall: toolCallState
|
|
2869
|
+
});
|
|
2870
|
+
output.content.push(toolCallBlock);
|
|
2871
|
+
outputItemContentIndexes.set(item, contentIndex);
|
|
2872
|
+
stream.push({
|
|
2873
|
+
type: "toolcall_start",
|
|
2874
|
+
contentIndex,
|
|
2875
|
+
partial: output
|
|
2876
|
+
});
|
|
2877
|
+
}
|
|
2878
|
+
} else if (event.type === "response.reasoning_summary_part.added") {
|
|
2879
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2880
|
+
if (!slot) continue;
|
|
2881
|
+
slot.item.summary = slot.item.summary || [];
|
|
2882
|
+
slot.item.summary.push(event.part);
|
|
2883
|
+
} else if (event.type === "response.reasoning_summary_text.delta") {
|
|
2884
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2885
|
+
if (!slot) continue;
|
|
2886
|
+
slot.item.summary = slot.item.summary || [];
|
|
2887
|
+
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2888
|
+
if (!lastPart) continue;
|
|
2889
|
+
slot.block.thinking += event.delta;
|
|
2890
|
+
lastPart.text += event.delta;
|
|
2902
2891
|
stream.push({
|
|
2903
|
-
type: "
|
|
2892
|
+
type: "thinking_delta",
|
|
2904
2893
|
contentIndex: slot.contentIndex,
|
|
2905
|
-
delta: event.delta
|
|
2894
|
+
delta: event.delta,
|
|
2895
|
+
partial: output
|
|
2906
2896
|
});
|
|
2907
|
-
}
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
lastPart
|
|
2915
|
-
type: "text",
|
|
2916
|
-
text: ""
|
|
2917
|
-
};
|
|
2918
|
-
slot.item.content.push(lastPart);
|
|
2919
|
-
}
|
|
2920
|
-
lastPart.text += event.delta;
|
|
2921
|
-
if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
|
|
2922
|
-
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2923
|
-
slot.block.text += event.delta;
|
|
2897
|
+
} else if (event.type === "response.reasoning_summary_part.done") {
|
|
2898
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2899
|
+
if (!slot) continue;
|
|
2900
|
+
slot.item.summary = slot.item.summary || [];
|
|
2901
|
+
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2902
|
+
if (!lastPart) continue;
|
|
2903
|
+
slot.block.thinking += "\n\n";
|
|
2904
|
+
lastPart.text += "\n\n";
|
|
2924
2905
|
stream.push({
|
|
2925
|
-
type: "
|
|
2906
|
+
type: "thinking_delta",
|
|
2926
2907
|
contentIndex: slot.contentIndex,
|
|
2927
|
-
delta:
|
|
2908
|
+
delta: "\n\n",
|
|
2909
|
+
partial: output
|
|
2928
2910
|
});
|
|
2929
|
-
}
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
slot.item.content ||= [];
|
|
2934
|
-
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2935
|
-
if (lastPart?.type !== "refusal") {
|
|
2936
|
-
lastPart = {
|
|
2937
|
-
type: "refusal",
|
|
2938
|
-
refusal: ""
|
|
2939
|
-
};
|
|
2940
|
-
slot.item.content.push(lastPart);
|
|
2941
|
-
}
|
|
2942
|
-
lastPart.refusal += event.delta;
|
|
2943
|
-
if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
|
|
2944
|
-
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2945
|
-
slot.block.text += event.delta;
|
|
2911
|
+
} else if (event.type === "response.reasoning_text.delta") {
|
|
2912
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2913
|
+
if (!slot) continue;
|
|
2914
|
+
slot.block.thinking += event.delta;
|
|
2946
2915
|
stream.push({
|
|
2947
|
-
type: "
|
|
2916
|
+
type: "thinking_delta",
|
|
2948
2917
|
contentIndex: slot.contentIndex,
|
|
2949
|
-
delta: event.delta
|
|
2950
|
-
});
|
|
2951
|
-
}
|
|
2952
|
-
} else if (event.type === "response.function_call_arguments.delta") {
|
|
2953
|
-
const toolCall = streamingToolCalls.resolve(event);
|
|
2954
|
-
if (toolCall) {
|
|
2955
|
-
toolCall.block.partialJson += event.delta;
|
|
2956
|
-
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
2957
|
-
stream.push({
|
|
2958
|
-
type: "toolcall_delta",
|
|
2959
|
-
contentIndex: toolCall.contentIndex,
|
|
2960
2918
|
delta: event.delta,
|
|
2961
2919
|
partial: output
|
|
2962
2920
|
});
|
|
2963
|
-
} else if (
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2921
|
+
} else if (event.type === "response.content_part.added") {
|
|
2922
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2923
|
+
if (!slot) continue;
|
|
2924
|
+
slot.item.content = slot.item.content || [];
|
|
2925
|
+
if (event.part.type === "output_text" || event.part.type === "text" || event.part.type === "refusal") slot.item.content.push(event.part);
|
|
2926
|
+
} else if (event.type === "response.output_text.delta") {
|
|
2927
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2928
|
+
if (!slot) continue;
|
|
2929
|
+
slot.item.content ||= [];
|
|
2930
|
+
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2931
|
+
if (!isResponsesTextContentPartType(lastPart?.type)) {
|
|
2932
|
+
lastPart = {
|
|
2933
|
+
type: "output_text",
|
|
2934
|
+
text: "",
|
|
2935
|
+
annotations: []
|
|
2936
|
+
};
|
|
2937
|
+
slot.item.content.push(lastPart);
|
|
2938
|
+
}
|
|
2939
|
+
lastPart.text += event.delta;
|
|
2940
|
+
if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
|
|
2941
|
+
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2942
|
+
slot.block.text += event.delta;
|
|
2943
|
+
stream.push({
|
|
2944
|
+
type: "text_delta",
|
|
2945
|
+
contentIndex: slot.contentIndex,
|
|
2946
|
+
delta: event.delta
|
|
2947
|
+
});
|
|
2948
|
+
}
|
|
2949
|
+
} else if (isAzureResponsesTextDeltaEvent(event)) {
|
|
2950
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2951
|
+
if (!slot) continue;
|
|
2952
|
+
slot.item.content = slot.item.content || [];
|
|
2953
|
+
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2954
|
+
if (lastPart?.type !== "text") {
|
|
2955
|
+
lastPart = {
|
|
2956
|
+
type: "text",
|
|
2957
|
+
text: ""
|
|
2958
|
+
};
|
|
2959
|
+
slot.item.content.push(lastPart);
|
|
2960
|
+
}
|
|
2961
|
+
lastPart.text += event.delta;
|
|
2962
|
+
if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
|
|
2963
|
+
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2964
|
+
slot.block.text += event.delta;
|
|
2965
|
+
stream.push({
|
|
2966
|
+
type: "text_delta",
|
|
2967
|
+
contentIndex: slot.contentIndex,
|
|
2968
|
+
delta: event.delta
|
|
2969
|
+
});
|
|
2970
|
+
}
|
|
2971
|
+
} else if (event.type === "response.refusal.delta") {
|
|
2972
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2973
|
+
if (!slot) continue;
|
|
2974
|
+
slot.item.content ||= [];
|
|
2975
|
+
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2976
|
+
if (lastPart?.type !== "refusal") {
|
|
2977
|
+
lastPart = {
|
|
2978
|
+
type: "refusal",
|
|
2979
|
+
refusal: ""
|
|
2980
|
+
};
|
|
2981
|
+
slot.item.content.push(lastPart);
|
|
2982
|
+
}
|
|
2983
|
+
lastPart.refusal += event.delta;
|
|
2984
|
+
if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
|
|
2985
|
+
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2986
|
+
slot.block.text += event.delta;
|
|
2987
|
+
stream.push({
|
|
2988
|
+
type: "text_delta",
|
|
2989
|
+
contentIndex: slot.contentIndex,
|
|
2990
|
+
delta: event.delta
|
|
2991
|
+
});
|
|
2973
2992
|
}
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2993
|
+
} else if (event.type === "response.function_call_arguments.delta") {
|
|
2994
|
+
const toolCall = streamingToolCalls.resolve(event);
|
|
2995
|
+
if (toolCall) {
|
|
2996
|
+
toolCall.block.partialJson += event.delta;
|
|
2997
|
+
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
2998
|
+
stream.push({
|
|
2977
2999
|
type: "toolcall_delta",
|
|
2978
3000
|
contentIndex: toolCall.contentIndex,
|
|
2979
|
-
delta,
|
|
3001
|
+
delta: event.delta,
|
|
2980
3002
|
partial: output
|
|
2981
3003
|
});
|
|
2982
|
-
}
|
|
2983
|
-
} else if (
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
} else if (
|
|
3004
|
-
const
|
|
3005
|
-
|
|
3006
|
-
const
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
if (collapse.kind === "extend" && outputSlot.collapseCandidate) {
|
|
3017
|
-
outputSlot.collapseCandidate.block.text = collapse.text;
|
|
3018
|
-
outputSlot.collapseCandidate.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
3004
|
+
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
3005
|
+
} else if (event.type === "response.function_call_arguments.done") {
|
|
3006
|
+
const toolCall = streamingToolCalls.resolve(event);
|
|
3007
|
+
if (toolCall) {
|
|
3008
|
+
const previousPartialJson = toolCall.block.partialJson;
|
|
3009
|
+
const doneArguments = typeof event.arguments === "string" ? event.arguments : void 0;
|
|
3010
|
+
if (doneArguments !== void 0 && (doneArguments.length > 0 || previousPartialJson === "")) {
|
|
3011
|
+
toolCall.block.partialJson = doneArguments;
|
|
3012
|
+
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
3013
|
+
toolCall.argumentStreamReliable = true;
|
|
3014
|
+
}
|
|
3015
|
+
if (doneArguments?.startsWith(previousPartialJson)) {
|
|
3016
|
+
const delta = doneArguments.slice(previousPartialJson.length);
|
|
3017
|
+
if (delta.length > 0) stream.push({
|
|
3018
|
+
type: "toolcall_delta",
|
|
3019
|
+
contentIndex: toolCall.contentIndex,
|
|
3020
|
+
delta,
|
|
3021
|
+
partial: output
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
3025
|
+
} else if (event.type === "response.output_item.done") {
|
|
3026
|
+
const item = event.item;
|
|
3027
|
+
if (item.type !== "message") lastTextBlock = null;
|
|
3028
|
+
const existingOutputSlot = resolveOutputItemSlot(event, item);
|
|
3029
|
+
materializeDeferredTextSlots(existingOutputSlot);
|
|
3030
|
+
const outputSlot = existingOutputSlot ?? getOrCreateOutputSlot(event, item);
|
|
3031
|
+
compactionTracker.completed(item, blocks.length);
|
|
3032
|
+
if (item.type === "reasoning" && outputSlot?.type === "thinking") {
|
|
3033
|
+
const summaryText = item.summary?.map((s) => s.text).join("\n\n") || "";
|
|
3034
|
+
const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
|
|
3035
|
+
outputSlot.block.thinking = summaryText || contentText || outputSlot.block.thinking;
|
|
3036
|
+
outputSlot.block.thinkingSignature = JSON.stringify(item);
|
|
3037
|
+
if (item.encrypted_content && options?.reasoningReplayMetadata) outputSlot.block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
|
|
3019
3038
|
stream.push({
|
|
3020
|
-
type: "
|
|
3021
|
-
contentIndex: outputSlot.
|
|
3022
|
-
content:
|
|
3039
|
+
type: "thinking_end",
|
|
3040
|
+
contentIndex: outputSlot.contentIndex,
|
|
3041
|
+
content: outputSlot.block.thinking,
|
|
3023
3042
|
partial: output
|
|
3024
3043
|
});
|
|
3025
|
-
|
|
3026
|
-
} else {
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3044
|
+
outputSlots.forget(outputSlot);
|
|
3045
|
+
} else if (item.type === "message" && outputSlot?.type === "text" && (outputSlot.block || outputSlot.pendingText !== null)) {
|
|
3046
|
+
const streamedText = outputSlot.pendingText ?? outputSlot.block?.text ?? "";
|
|
3047
|
+
const finalText = item.content == null ? streamedText : item.content.map((c) => c.type === "output_text" || c.type === "text" ? c.text : c.refusal).join("");
|
|
3048
|
+
const phase = item.phase ?? void 0;
|
|
3049
|
+
const collapse = outputSlot.pendingText !== null ? resolveResponsesMessageSnapshotCollapse({
|
|
3050
|
+
prior: outputSlot.collapseCandidate && {
|
|
3051
|
+
text: outputSlot.collapseCandidate.block.text,
|
|
3052
|
+
phase: outputSlot.collapseCandidate.phase
|
|
3053
|
+
},
|
|
3054
|
+
nextText: finalText,
|
|
3055
|
+
nextPhase: phase
|
|
3056
|
+
}) : { kind: "keep" };
|
|
3057
|
+
outputSlot.pendingText = null;
|
|
3058
|
+
if (collapse.kind === "extend" && outputSlot.collapseCandidate) {
|
|
3059
|
+
outputSlot.collapseCandidate.block.text = collapse.text;
|
|
3060
|
+
outputSlot.collapseCandidate.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
3061
|
+
stream.push({
|
|
3062
|
+
type: "text_end",
|
|
3063
|
+
contentIndex: outputSlot.collapseCandidate.index,
|
|
3064
|
+
content: collapse.text,
|
|
3065
|
+
partial: output
|
|
3066
|
+
});
|
|
3067
|
+
lastTextBlock = outputSlot.collapseCandidate;
|
|
3068
|
+
outputItemContentIndexes.set(item, outputSlot.collapseCandidate.index);
|
|
3069
|
+
} else {
|
|
3070
|
+
if (!outputSlot.block) {
|
|
3071
|
+
outputSlot.block = {
|
|
3072
|
+
type: "text",
|
|
3073
|
+
text: "",
|
|
3074
|
+
...phase ? { textSignature: encodeTextSignatureV1(item.id, phase) } : {}
|
|
3075
|
+
};
|
|
3076
|
+
blocks.push(outputSlot.block);
|
|
3077
|
+
outputSlot.contentIndex = blocks.length - 1;
|
|
3078
|
+
stream.push({
|
|
3079
|
+
type: "text_start",
|
|
3080
|
+
contentIndex: outputSlot.contentIndex,
|
|
3081
|
+
partial: output
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3084
|
+
outputSlot.block.text = finalText;
|
|
3085
|
+
outputSlot.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
3086
|
+
const contentIndex = outputSlot.contentIndex;
|
|
3087
|
+
if (contentIndex === void 0) throw new Error("Responses stream finalized text without a content index");
|
|
3088
|
+
lastTextBlock = {
|
|
3089
|
+
block: outputSlot.block,
|
|
3090
|
+
index: contentIndex,
|
|
3091
|
+
phase
|
|
3032
3092
|
};
|
|
3033
|
-
|
|
3034
|
-
outputSlot.contentIndex = blockIndex();
|
|
3093
|
+
outputItemContentIndexes.set(item, contentIndex);
|
|
3035
3094
|
stream.push({
|
|
3036
|
-
type: "
|
|
3037
|
-
contentIndex
|
|
3095
|
+
type: "text_end",
|
|
3096
|
+
contentIndex,
|
|
3097
|
+
content: outputSlot.block.text,
|
|
3038
3098
|
partial: output
|
|
3039
3099
|
});
|
|
3040
3100
|
}
|
|
3041
|
-
outputSlot
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
content: outputSlot.block.text,
|
|
3054
|
-
partial: output
|
|
3101
|
+
outputSlots.forget(outputSlot);
|
|
3102
|
+
startedTextBlocksByItemId.delete(item.id);
|
|
3103
|
+
} else if (item.type === "function_call") {
|
|
3104
|
+
const streamingToolCall = streamingToolCalls.resolve(event, readResponsesToolCallItemIdentity(item));
|
|
3105
|
+
if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
|
|
3106
|
+
const streamedArguments = streamingToolCall?.block.partialJson ?? "";
|
|
3107
|
+
const completedArguments = typeof item.arguments === "string" ? item.arguments : void 0;
|
|
3108
|
+
if (streamingToolCall && !streamingToolCall.argumentStreamReliable && !completedArguments) continue;
|
|
3109
|
+
const finalArguments = completedArguments !== void 0 && (completedArguments.length > 0 || !streamedArguments) ? completedArguments : streamedArguments;
|
|
3110
|
+
const validated = resolveCompletedResponsesToolCall(item, {
|
|
3111
|
+
name: streamingToolCall?.block.name,
|
|
3112
|
+
arguments: finalArguments
|
|
3055
3113
|
});
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
type
|
|
3084
|
-
|
|
3085
|
-
name: validated.name,
|
|
3086
|
-
arguments: validated.arguments
|
|
3087
|
-
};
|
|
3088
|
-
blocks.push(toolCall);
|
|
3089
|
-
contentIndex = blockIndex();
|
|
3114
|
+
let toolCall;
|
|
3115
|
+
let contentIndex;
|
|
3116
|
+
if (streamingToolCall) {
|
|
3117
|
+
const block = streamingToolCall.block;
|
|
3118
|
+
block.id = resolveResponsesToolCallId(item, block.id);
|
|
3119
|
+
block.name = validated.name;
|
|
3120
|
+
block.arguments = validated.arguments;
|
|
3121
|
+
delete block.partialJson;
|
|
3122
|
+
toolCall = block;
|
|
3123
|
+
contentIndex = streamingToolCall.contentIndex;
|
|
3124
|
+
} else {
|
|
3125
|
+
toolCall = {
|
|
3126
|
+
type: "toolCall",
|
|
3127
|
+
id: resolveResponsesToolCallId(item),
|
|
3128
|
+
name: validated.name,
|
|
3129
|
+
arguments: validated.arguments
|
|
3130
|
+
};
|
|
3131
|
+
blocks.push(toolCall);
|
|
3132
|
+
contentIndex = blocks.length - 1;
|
|
3133
|
+
stream.push({
|
|
3134
|
+
type: "toolcall_start",
|
|
3135
|
+
contentIndex,
|
|
3136
|
+
partial: output
|
|
3137
|
+
});
|
|
3138
|
+
}
|
|
3139
|
+
if (streamingToolCall) {
|
|
3140
|
+
streamingToolCalls.forget(streamingToolCall);
|
|
3141
|
+
for (const slot of outputSlots.values()) if (slot.type === "toolCall" && slot.toolCall === streamingToolCall) outputSlots.forget(slot);
|
|
3142
|
+
}
|
|
3090
3143
|
stream.push({
|
|
3091
|
-
type: "
|
|
3144
|
+
type: "toolcall_end",
|
|
3092
3145
|
contentIndex,
|
|
3146
|
+
toolCall,
|
|
3093
3147
|
partial: output
|
|
3094
3148
|
});
|
|
3149
|
+
outputItemContentIndexes.set(item, contentIndex);
|
|
3095
3150
|
}
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
});
|
|
3106
|
-
|
|
3151
|
+
} else if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
3152
|
+
if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
|
|
3153
|
+
finalizeResponse(event.response, event.type);
|
|
3154
|
+
if (event.type === "response.completed" || output.stopReason === "length") recoverTerminalOutput(event.response.output ?? [], event.type === "response.completed");
|
|
3155
|
+
terminalResponse = event.type === "response.completed" ? event.response : null;
|
|
3156
|
+
if (output.stopReason === "stop" && output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
|
|
3157
|
+
break;
|
|
3158
|
+
} else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
|
|
3159
|
+
else if (event.type === "response.failed") {
|
|
3160
|
+
const failure = normalizeResponsesFailedEvent(isRecord(event) ? event : {}, model);
|
|
3161
|
+
finalizeFailedResponse(event.response, failure.responseId);
|
|
3162
|
+
throw new ResponsesStreamFailure(failure, event.response);
|
|
3107
3163
|
}
|
|
3108
|
-
} else if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
3109
|
-
if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
|
|
3110
|
-
finalizeResponse(event.response, event.type);
|
|
3111
|
-
if (event.type === "response.completed" || output.stopReason === "length") recoverTerminalOutput(event.response.output ?? [], event.type === "response.completed");
|
|
3112
|
-
if (output.stopReason === "stop" && output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
|
|
3113
|
-
break;
|
|
3114
|
-
} else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
|
|
3115
|
-
else if (event.type === "response.failed") {
|
|
3116
|
-
const failure = normalizeResponsesFailedEvent(event, model);
|
|
3117
|
-
if (failure.responseId) output.responseId = failure.responseId;
|
|
3118
|
-
throw new ResponsesStreamFailure(failure, event.response);
|
|
3119
3164
|
}
|
|
3165
|
+
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
3120
3166
|
if (streamingToolCalls.hasActive()) throw new Error("Responses stream ended with unresolved tool calls");
|
|
3121
|
-
if (
|
|
3167
|
+
if (terminalResponse === void 0) throw new Error("OpenAI Responses stream ended before a terminal response event");
|
|
3168
|
+
return terminalResponse ?? void 0;
|
|
3122
3169
|
} finally {
|
|
3123
3170
|
for (const block of output.content) delete block.partialJson;
|
|
3124
3171
|
}
|
|
3125
3172
|
}
|
|
3126
3173
|
//#endregion
|
|
3127
|
-
|
|
3174
|
+
//#region packages/ai/src/providers/openai-responses-tools.ts
|
|
3175
|
+
const LOG_SUBSYSTEM = "llm/openai-responses";
|
|
3176
|
+
const MAX_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS = 64;
|
|
3177
|
+
const loggedStrictToolDowngradeDiagnosticKeys = /* @__PURE__ */ new Set();
|
|
3178
|
+
/** Converts and returns the projection used to reconcile tool choices. */
|
|
3179
|
+
function convertResponsesToolPayload(tools, options) {
|
|
3180
|
+
const projection = projectOpenAITools(tools);
|
|
3181
|
+
const strict = resolveResponsesStrictToolFlag(projection, resolveResponsesStrictToolSetting(options), options?.model);
|
|
3182
|
+
return {
|
|
3183
|
+
projection,
|
|
3184
|
+
tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
|
|
3185
|
+
const result = {
|
|
3186
|
+
type: "function",
|
|
3187
|
+
name: tool.name,
|
|
3188
|
+
description: tool.description,
|
|
3189
|
+
parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, options?.model?.compat)
|
|
3190
|
+
};
|
|
3191
|
+
if (strict !== void 0) result.strict = strict;
|
|
3192
|
+
return result;
|
|
3193
|
+
})
|
|
3194
|
+
};
|
|
3195
|
+
}
|
|
3196
|
+
function resolveResponsesStrictToolSetting(options) {
|
|
3197
|
+
if (options?.strict !== void 0) return options.strict;
|
|
3198
|
+
if (options?.model) return getAiTransportHost().resolveOpenAIStrictToolSetting(options.model, {
|
|
3199
|
+
transport: "stream",
|
|
3200
|
+
supportsStrictMode: options.supportsStrictMode
|
|
3201
|
+
});
|
|
3202
|
+
return false;
|
|
3203
|
+
}
|
|
3204
|
+
function resolveResponsesStrictToolFlag(projection, strictSetting, model) {
|
|
3205
|
+
const strict = resolveOpenAIProjectedToolsStrictToolFlag(projection, strictSetting);
|
|
3206
|
+
if (strictSetting === true && strict === false && model) getAiTransportHost().logDebug(LOG_SUBSYSTEM, () => {
|
|
3207
|
+
const diagnostics = findOpenAIStrictToolProjectionDiagnostics(projection);
|
|
3208
|
+
if (!shouldLogStrictToolDowngradeDiagnostic(diagnostics, model)) return null;
|
|
3209
|
+
const sample = diagnostics.slice(0, 5).map((entry) => ({
|
|
3210
|
+
tool: entry.toolName ?? `tool[${entry.toolIndex}]`,
|
|
3211
|
+
violations: entry.violations.slice(0, 8)
|
|
3212
|
+
}));
|
|
3213
|
+
return {
|
|
3214
|
+
message: `OpenAI responses tool schema strict mode downgraded to strict=false for ${model.provider ?? "unknown"}/${model.id ?? "unknown"} because ${diagnostics.length} tool schema(s) are not strict-compatible`,
|
|
3215
|
+
data: {
|
|
3216
|
+
provider: model.provider,
|
|
3217
|
+
model: model.id,
|
|
3218
|
+
incompatibleToolCount: diagnostics.length,
|
|
3219
|
+
sample
|
|
3220
|
+
}
|
|
3221
|
+
};
|
|
3222
|
+
});
|
|
3223
|
+
return strict;
|
|
3224
|
+
}
|
|
3225
|
+
function shouldLogStrictToolDowngradeDiagnostic(diagnostics, model) {
|
|
3226
|
+
const key = createHash("sha256").update(JSON.stringify({
|
|
3227
|
+
provider: model.provider,
|
|
3228
|
+
model: model.id,
|
|
3229
|
+
diagnostics: diagnostics.map((entry) => ({
|
|
3230
|
+
toolIndex: entry.toolIndex,
|
|
3231
|
+
toolName: entry.toolName ?? null,
|
|
3232
|
+
violations: entry.violations
|
|
3233
|
+
}))
|
|
3234
|
+
})).digest("hex");
|
|
3235
|
+
if (loggedStrictToolDowngradeDiagnosticKeys.has(key)) return false;
|
|
3236
|
+
if (loggedStrictToolDowngradeDiagnosticKeys.size >= MAX_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS) loggedStrictToolDowngradeDiagnosticKeys.clear();
|
|
3237
|
+
loggedStrictToolDowngradeDiagnosticKeys.add(key);
|
|
3238
|
+
return true;
|
|
3239
|
+
}
|
|
3240
|
+
//#endregion
|
|
3241
|
+
//#region packages/ai/src/providers/openai-responses-shared.ts
|
|
3242
|
+
function isResponsesReasoningEffort(effort) {
|
|
3243
|
+
return effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max";
|
|
3244
|
+
}
|
|
3245
|
+
function convertResponsesMessages(model, context, allowedToolCallProviders, options) {
|
|
3246
|
+
return convertProviderResponsesMessages(model, context, allowedToolCallProviders, options);
|
|
3247
|
+
}
|
|
3248
|
+
const createResponsesAssistantOutput = createOpenAIResponsesAssistantOutput;
|
|
3249
|
+
function applyResponsesServiceTierPricing(usage, serviceTier, model) {
|
|
3250
|
+
let multiplier = 1;
|
|
3251
|
+
if (serviceTier === "flex") multiplier = .5;
|
|
3252
|
+
else if (serviceTier === "priority") multiplier = model.id === "gpt-5.5" ? 2.5 : 2;
|
|
3253
|
+
if (multiplier === 1) return;
|
|
3254
|
+
usage.cost.input *= multiplier;
|
|
3255
|
+
usage.cost.output *= multiplier;
|
|
3256
|
+
usage.cost.cacheRead *= multiplier;
|
|
3257
|
+
usage.cost.cacheWrite *= multiplier;
|
|
3258
|
+
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
3259
|
+
}
|
|
3260
|
+
function resolveResponsesReasoningEffort(model, reasoning) {
|
|
3261
|
+
const clampedReasoning = reasoning ? clampThinkingLevel(model, reasoning) : void 0;
|
|
3262
|
+
if (!clampedReasoning || clampedReasoning === "off") return;
|
|
3263
|
+
if (clampedReasoning === "max") return supportsOpenAIReasoningEffort(model, "max") ? "max" : "xhigh";
|
|
3264
|
+
if (clampedReasoning === "minimal" && model.provider === "openai" && supportsOpenAIReasoningEffort(model, "max")) {
|
|
3265
|
+
const effort = resolveOpenAIReasoningEffortForModel({
|
|
3266
|
+
model,
|
|
3267
|
+
effort: "minimal"
|
|
3268
|
+
});
|
|
3269
|
+
return isResponsesReasoningEffort(effort) ? effort : void 0;
|
|
3270
|
+
}
|
|
3271
|
+
return clampedReasoning;
|
|
3272
|
+
}
|
|
3273
|
+
function applyCommonResponsesParams(params, model, context, options, config) {
|
|
3274
|
+
if (options?.maxTokens) params.max_output_tokens = Math.max(options.maxTokens, 16);
|
|
3275
|
+
if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
|
|
3276
|
+
if (context.tools) {
|
|
3277
|
+
const converted = convertResponsesToolPayload(context.tools, { model });
|
|
3278
|
+
if (converted.tools.length > 0) params.tools = converted.tools;
|
|
3279
|
+
}
|
|
3280
|
+
if (!model.reasoning) return;
|
|
3281
|
+
if (options?.reasoningEffort || options?.reasoningSummary) {
|
|
3282
|
+
params.reasoning = {
|
|
3283
|
+
effort: options?.reasoningEffort ? model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort : "medium",
|
|
3284
|
+
summary: options?.reasoningSummary || "auto"
|
|
3285
|
+
};
|
|
3286
|
+
params.include = ["reasoning.encrypted_content"];
|
|
3287
|
+
} else if ((config?.setDefaultReasoningOff ?? true) && model.thinkingLevelMap?.off !== null) params.reasoning = { effort: model.thinkingLevelMap?.off ?? "none" };
|
|
3288
|
+
}
|
|
3289
|
+
function buildResponsesRequestOptions(options) {
|
|
3290
|
+
return {
|
|
3291
|
+
...options?.signal ? { signal: options.signal } : {},
|
|
3292
|
+
...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},
|
|
3293
|
+
maxRetries: options?.maxRetries ?? 0
|
|
3294
|
+
};
|
|
3295
|
+
}
|
|
3296
|
+
function cleanStreamingScratchBuffers(output) {
|
|
3297
|
+
for (const block of output.content) {
|
|
3298
|
+
delete block.index;
|
|
3299
|
+
delete block.partialJson;
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
async function runResponsesStreamLifecycle(params) {
|
|
3303
|
+
const { stream, output, options } = params;
|
|
3304
|
+
let firstEventAbort;
|
|
3305
|
+
try {
|
|
3306
|
+
const model = params.resolveRequestModel?.(params.model) ?? params.model;
|
|
3307
|
+
const client = params.createClient(model);
|
|
3308
|
+
const buildRequest = async (replayMode) => {
|
|
3309
|
+
let request = params.buildParams(model, replayMode);
|
|
3310
|
+
const nextRequest = await options?.onPayload?.(request, model);
|
|
3311
|
+
if (nextRequest !== void 0) request = nextRequest;
|
|
3312
|
+
return request;
|
|
3313
|
+
};
|
|
3314
|
+
const requestParams = await buildRequest("checkpoint");
|
|
3315
|
+
firstEventAbort = createFirstStreamEventAbortController(options?.signal);
|
|
3316
|
+
const { stream: openaiStream, response } = await createResponsesStreamWithEncryptedContentRetry({
|
|
3317
|
+
client,
|
|
3318
|
+
request: requestParams,
|
|
3319
|
+
requestOptions: {
|
|
3320
|
+
...buildResponsesRequestOptions(options),
|
|
3321
|
+
signal: firstEventAbort.signal
|
|
3322
|
+
},
|
|
3323
|
+
model,
|
|
3324
|
+
buildFullHistoryRequest: () => buildRequest("full-history"),
|
|
3325
|
+
onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint)
|
|
3326
|
+
});
|
|
3327
|
+
const hookedOpenAIStream = withProviderResponseHook({
|
|
3328
|
+
stream: openaiStream,
|
|
3329
|
+
signal: firstEventAbort.signal,
|
|
3330
|
+
abort: firstEventAbort.abort,
|
|
3331
|
+
hook: createOpenAIProviderAcceptanceHook(options, response, model),
|
|
3332
|
+
onReady: () => stream.push({
|
|
3333
|
+
type: "start",
|
|
3334
|
+
partial: output
|
|
3335
|
+
})
|
|
3336
|
+
});
|
|
3337
|
+
const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
|
|
3338
|
+
const onFirstEventTimeout = getFirstStreamEventTimeoutHandler(options);
|
|
3339
|
+
await processResponsesStream(hookedOpenAIStream, output, stream, model, {
|
|
3340
|
+
...params.processStreamOptions || firstEventTimeoutMs !== void 0 || onFirstEventTimeout !== void 0 ? {
|
|
3341
|
+
...params.processStreamOptions,
|
|
3342
|
+
firstEventTimeoutMs: params.processStreamOptions?.firstEventTimeoutMs ?? firstEventTimeoutMs,
|
|
3343
|
+
abortFirstEventStream: params.processStreamOptions?.abortFirstEventStream ?? firstEventAbort.abort,
|
|
3344
|
+
onFirstEventTimeout: params.processStreamOptions?.onFirstEventTimeout ?? onFirstEventTimeout,
|
|
3345
|
+
signal: params.processStreamOptions?.signal ?? options?.signal
|
|
3346
|
+
} : void 0,
|
|
3347
|
+
reasoningReplayMetadata: buildOpenAIResponsesReasoningReplayMetadata(model, {
|
|
3348
|
+
sessionId: options?.sessionId,
|
|
3349
|
+
authProfileId: options?.authProfileId
|
|
3350
|
+
})
|
|
3351
|
+
});
|
|
3352
|
+
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
3353
|
+
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
3354
|
+
stream.push({
|
|
3355
|
+
type: "done",
|
|
3356
|
+
reason: output.stopReason,
|
|
3357
|
+
message: output
|
|
3358
|
+
});
|
|
3359
|
+
stream.end();
|
|
3360
|
+
} catch (error) {
|
|
3361
|
+
cleanStreamingScratchBuffers(output);
|
|
3362
|
+
const terminal = projectProviderError(error, options?.signal);
|
|
3363
|
+
Object.assign(output, terminal);
|
|
3364
|
+
stream.push({
|
|
3365
|
+
type: "error",
|
|
3366
|
+
reason: terminal.stopReason,
|
|
3367
|
+
error: output
|
|
3368
|
+
});
|
|
3369
|
+
stream.end();
|
|
3370
|
+
} finally {
|
|
3371
|
+
firstEventAbort?.dispose();
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
//#endregion
|
|
3375
|
+
export { normalizeOpenAIStrictCompatSchema as $, isAzureResponsesTextDeltaEvent as A, buildResponsesInputMessage as B, summarizeResponsesTools as C, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as D, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as E, commitResponsesEncryptedContentAttempt as F, suppressOpenAIResponsesCompaction as G, createOpenAIResponsesAssistantOutput as H, createResponsesStreamWithEncryptedContentRetry as I, isStrictOpenAIJsonSchemaCompatible as J, resolveReplayableResponsesMessageId as K, isInvalidEncryptedContentError as L, isResponsesTextContentPartType as M, isResponsesTextDeltaEventType as N, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as O, resolveResponsesMessageSnapshotCollapse as P, findOpenAIStrictSchemaViolations as Q, resolveAzureOpenAIApiVersion as R, summarizeResponsesPayload as S, readResponsesToolCallItemIdentity as T, buildOpenAIResponsesReasoningReplayMetadata as U, convertResponsesMessages$1 as V, captureOpenAIResponsesCompaction as W, normalizeStrictOpenAIJsonSchema as X, normalizeOpenAIStrictToolParameters as Y, resolveOpenAIProjectedToolsStrictToolFlag as Z, safeDebugValue as _, resolveResponsesReasoningEffort as a, LLAMACPP_GBNF_MAX_REPETITION_THRESHOLD as at, summarizeOpenAITransportError as b, processResponsesStream as c, GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS as ct, resolveResponsesTerminalStopReason as d, resolveModelPayloadDebugMode as dt, extractToolSchemaModelCompat as et, observeResponsesStream as f, resolveModelSseDebugMode as ft, normalizeResponsesFailedEvent as g, logResponsesFailedNoDetails as h, createResponsesAssistantOutput as i, stripUnsupportedSchemaKeywords as it, isAzureResponsesTextDeltaEventType as j, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as k, mapResponsesTerminalUsage as l, cleanSchemaForGemini as lt, buildResponsesFailedNoDetailsObservation as m, applyResponsesServiceTierPricing as n, resolveUnsupportedToolSchemaKeywords as nt, runResponsesStreamLifecycle as o, cleanSchemaForLlamacppGbnf as ot, ResponsesStreamFailure as p, findOpenAIStrictToolProjectionDiagnostics as q, convertResponsesMessages as r, shouldOmitEmptyArrayItems as rt, convertResponsesToolPayload as s, findLlamacppGbnfSchemaViolations as st, applyCommonResponsesParams as t, normalizeToolParameterSchema as tt, readResponsesReasoningTokens as u, emitModelTransportDebug as ut, stringifyRedactedEvent as v, createResponsesToolCallTracker as w, summarizeResponsesFailedNoDetailsObservation as x, stringifyRedactedPayload as y, resolveNextResponsesEncryptedContentAttempt as z };
|