@openclaw/ai 2026.7.2-beta.7 → 2026.8.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{anthropic-CH4UUnZr.mjs → anthropic-B6dLpq5L.mjs} +55 -203
- package/dist/{src-QkygScBs.mjs → anthropic-JsNA5KCu.mjs} +0 -1
- package/dist/anthropic-compaction-replay-8lJNKXOE.mjs +840 -0
- package/dist/anthropic-payload-policy-CiEuQS72.d.mts +49 -0
- package/dist/{api-registry-DlMgPR39.d.mts → api-registry-k3zTz0cV.d.mts} +1 -1
- package/dist/{azure-openai-responses-CImcwB83.mjs → azure-openai-responses-mxIOtUnn.mjs} +23 -29
- package/dist/diagnostics.d.mts +24 -1
- package/dist/diagnostics.mjs +2 -1
- package/dist/{event-stream-YjaPW20U.d.mts → event-stream-BP6AWT8j.d.mts} +4 -1
- package/dist/{event-stream-D8n2uFee.mjs → event-stream-uSMZJ3FA.mjs} +26 -5
- package/dist/event-stream.d.mts +1 -1
- package/dist/event-stream.mjs +1 -1
- package/dist/{google-CtSg0iTS.mjs → google-C7h2QzDX.mjs} +5 -5
- package/dist/{google-shared-DNBz5rcD.mjs → google-shared-B0Qr9OR7.mjs} +146 -89
- package/dist/google-thinking-level-C-V3tecN.mjs +9 -0
- package/dist/{google-vertex-31f1uS9L.mjs → google-vertex-Bhc3TjDl.mjs} +11 -7
- package/dist/{llm-request-activity-BjtkplhG.mjs → headers-DdOQtGuU.mjs} +9 -1
- package/dist/host-DTqNc7ad.mjs +466 -0
- package/dist/{host-B9GUmcra.d.mts → host-vWgMMhiJ.d.mts} +9 -4
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +7 -5
- package/dist/internal/anthropic.d.mts +29 -5
- 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 +8 -7
- package/dist/internal/runtime.d.mts +17 -5
- package/dist/internal/runtime.mjs +85 -73
- package/dist/internal/shared.d.mts +1 -6
- package/dist/internal/shared.mjs +3 -5
- package/dist/{json-parse-BvXNt1-7.mjs → json-parse-CDnesDM_.mjs} +4 -6
- package/dist/{mistral-CWmpvWYh.mjs → mistral-CEWoQI_g.mjs} +45 -48
- package/dist/number-coercion-H9qHik3g.mjs +71 -0
- package/dist/openai-chatgpt-jwt-KWcgd0d_.mjs +19 -0
- package/dist/{openai-chatgpt-responses-B84Ibtrd.mjs → openai-chatgpt-responses-CrPmqERt.mjs} +284 -240
- package/dist/{openai-completions-DsOxhOD1.mjs → openai-completions-BPnt4Sml.mjs} +65 -99
- package/dist/{openai-completions-compat-DBWjXoMZ.d.mts → openai-completions-compat-Dt3dcawL.d.mts} +2 -2
- package/dist/{openai-responses-BT7A3sLu.mjs → openai-responses-DhIKtOup.mjs} +18 -41
- package/dist/openai-responses-contracts-CyfIkQi5.mjs +253 -0
- package/dist/openai-responses-contracts-XpZJxrRG.d.mts +68 -0
- package/dist/openai-responses-payload-policy-BDxV-W0c.mjs +206 -0
- package/dist/openai-responses-payload-policy-BSs371VM.d.mts +40 -0
- package/dist/openai-responses-prompt-observer-internal-DgNTYnRY.mjs +46 -0
- package/dist/{openai-responses-stream-internal-Cw5txaGW.mjs → openai-responses-shared-DXIt3iY5.mjs} +1406 -940
- package/dist/{openai-reasoning-compat-YgeLncHw.mjs → openai-stop-reason-BkFkqqK0.mjs} +204 -37
- package/dist/openai-tool-projection-CY04OcvQ.mjs +338 -0
- package/dist/provider-error-BUwEnjXq.mjs +429 -0
- package/dist/provider-error-CzNw4BWX.d.mts +12 -0
- package/dist/{provider-options-D8bB3z9b.d.mts → provider-options-B96RdNpH.d.mts} +9 -3
- package/dist/provider-transcript-transform-ePx-Bbfr.mjs +155 -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-rnPwX2pg.mjs} +14 -8
- package/dist/record-coerce-DdXsgUd_.mjs +23 -0
- package/dist/sanitize-unicode-BYqrYtC_.mjs +90 -0
- package/dist/session-resources-CkR4WWy1.mjs +21 -0
- package/dist/simple-options-D58D5Kvw.mjs +117 -0
- package/dist/src-D2H6yKkH.mjs +2 -0
- package/dist/{stream-first-event-timeout-BBys9hSb.mjs → stream-first-event-timeout-MK28puvq.mjs} +2 -2
- package/dist/string-coerce-fsri9iCu.mjs +34 -0
- package/dist/{tool-schema-json-projection-BwNu3nDi.mjs → tool-schema-json-projection-q5d7QX5c.mjs} +32 -7
- package/dist/transport-utils-DJqkxbhC.mjs +138 -0
- package/dist/transports.d.mts +166 -241
- package/dist/transports.mjs +1979 -1825
- package/dist/types-BDdaOVi2.mjs +6 -0
- package/dist/{types-bzp5k29J.d.mts → types-BHNrPS1l.d.mts} +23 -1
- package/dist/types.d.mts +4 -4
- 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-B-j7cOYp.d.mts → validation-DT9SrFn3.d.mts} +1 -1
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/package.json +15 -1
- package/dist/anthropic-usage-DWU-x8MI.mjs +0 -459
- package/dist/error-coercion-DgxlWC0n.mjs +0 -15
- package/dist/headers-B_e4-1J0.mjs +0 -9
- package/dist/host-Dog2WQiR.mjs +0 -369
- package/dist/number-coercion-DvG7SNMg.mjs +0 -129
- package/dist/openai-chatgpt-jwt-DhAAzLkj.mjs +0 -39
- package/dist/openai-responses-shared-pXl6Wd8S.mjs +0 -392
- package/dist/openai-tool-projection-OhX64DoP.mjs +0 -215
- package/dist/provider-error-CAEvRjry.mjs +0 -47
- package/dist/sanitize-unicode-DT5o51ur.mjs +0 -26
- package/dist/simple-options-9lhRrN73.mjs +0 -50
- package/dist/tool-result-text-CTpIRbYd.mjs +0 -225
- package/dist/transform-messages-C8mBqZxF.mjs +0 -2
- package/dist/transport-stream-shared-D81p90xq.mjs +0 -297
package/dist/{openai-responses-stream-internal-Cw5txaGW.mjs → openai-responses-shared-DXIt3iY5.mjs}
RENAMED
|
@@ -1,31 +1,134 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { a as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { n as
|
|
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-BYqrYtC_.mjs";
|
|
3
|
+
import { a as describeToolResultMediaPlaceholder, l as isImageWithMediaPayload, n as getAiTransportHost, s as extractToolResultText } from "./host-DTqNc7ad.mjs";
|
|
4
|
+
import { a as isRecord, n as asNullableRecord } from "./record-coerce-DdXsgUd_.mjs";
|
|
5
|
+
import { t as truncateUtf16Safe } from "./utf16-slice-CvGodqok.mjs";
|
|
6
|
+
import { n as projectProviderError } from "./provider-error-BUwEnjXq.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, 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-CyfIkQi5.mjs";
|
|
9
|
+
import { f as sortPromptCacheToolsByName, l as stripSystemPromptCacheBoundary } from "./simple-options-D58D5Kvw.mjs";
|
|
10
|
+
import { c as transformTransportMessages } from "./tool-schema-json-projection-q5d7QX5c.mjs";
|
|
11
|
+
import { n as parseStreamingJson } from "./json-parse-CDnesDM_.mjs";
|
|
12
|
+
import { n as notifyLlmRequestActivity } from "./headers-DdOQtGuU.mjs";
|
|
9
13
|
import { t as shortHash } from "./hash-CHgqbJmD.mjs";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
import { d as sanitizeTransportPayloadText, f as transportAbortError, p as withProviderResponseHook, t as transformProviderMessages, u as sanitizeNonEmptyTransportPayloadText } from "./provider-transcript-transform-ePx-Bbfr.mjs";
|
|
15
|
+
import { l as redactIdentifier, u as redactSensitiveText } from "./transport-utils-DJqkxbhC.mjs";
|
|
16
|
+
import { a as createModelStreamCooperativeScheduler, c as log, o as createOpenAIResponseHook, t as projectOpenAITools } from "./openai-tool-projection-CY04OcvQ.mjs";
|
|
17
|
+
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-MK28puvq.mjs";
|
|
18
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
19
|
+
//#region packages/ai/src/transports/json-unsafe-integers.ts
|
|
20
|
+
/**
|
|
21
|
+
* JSON parsing helpers that preserve integer literals larger than
|
|
22
|
+
* Number.MAX_SAFE_INTEGER as strings before JSON.parse can round them.
|
|
23
|
+
*/
|
|
24
|
+
const MAX_SAFE_INTEGER_ABS_STR = String(Number.MAX_SAFE_INTEGER);
|
|
25
|
+
function isAsciiDigit(ch) {
|
|
26
|
+
return ch !== void 0 && ch >= "0" && ch <= "9";
|
|
27
|
+
}
|
|
28
|
+
function parseJsonNumberToken(input, start) {
|
|
29
|
+
let idx = start;
|
|
30
|
+
if (input[idx] === "-") idx += 1;
|
|
31
|
+
if (idx >= input.length) return null;
|
|
32
|
+
if (input[idx] === "0") idx += 1;
|
|
33
|
+
else if (isAsciiDigit(input[idx]) && input[idx] !== "0") while (isAsciiDigit(input[idx])) idx += 1;
|
|
34
|
+
else return null;
|
|
35
|
+
let isInteger = true;
|
|
36
|
+
if (input[idx] === ".") {
|
|
37
|
+
isInteger = false;
|
|
38
|
+
idx += 1;
|
|
39
|
+
if (!isAsciiDigit(input[idx])) return null;
|
|
40
|
+
while (isAsciiDigit(input[idx])) idx += 1;
|
|
41
|
+
}
|
|
42
|
+
if (input[idx] === "e" || input[idx] === "E") {
|
|
43
|
+
isInteger = false;
|
|
44
|
+
idx += 1;
|
|
45
|
+
if (input[idx] === "+" || input[idx] === "-") idx += 1;
|
|
46
|
+
if (!isAsciiDigit(input[idx])) return null;
|
|
47
|
+
while (isAsciiDigit(input[idx])) idx += 1;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
token: input.slice(start, idx),
|
|
51
|
+
end: idx,
|
|
52
|
+
isInteger
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function isUnsafeIntegerLiteral(token) {
|
|
56
|
+
const digits = token[0] === "-" ? token.slice(1) : token;
|
|
57
|
+
if (digits.length < MAX_SAFE_INTEGER_ABS_STR.length) return false;
|
|
58
|
+
if (digits.length > MAX_SAFE_INTEGER_ABS_STR.length) return true;
|
|
59
|
+
return digits > MAX_SAFE_INTEGER_ABS_STR;
|
|
60
|
+
}
|
|
61
|
+
/** Quotes integer literals above Number.MAX_SAFE_INTEGER before JSON.parse. */
|
|
62
|
+
function quoteUnsafeIntegerLiterals(input) {
|
|
63
|
+
let out = "";
|
|
64
|
+
let inString = false;
|
|
65
|
+
let escaped = false;
|
|
66
|
+
let idx = 0;
|
|
67
|
+
while (idx < input.length) {
|
|
68
|
+
const ch = input[idx] ?? "";
|
|
69
|
+
if (inString) {
|
|
70
|
+
out += ch;
|
|
71
|
+
if (escaped) escaped = false;
|
|
72
|
+
else if (ch === "\\") escaped = true;
|
|
73
|
+
else if (ch === "\"") inString = false;
|
|
74
|
+
idx += 1;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (ch === "\"") {
|
|
78
|
+
inString = true;
|
|
79
|
+
out += ch;
|
|
80
|
+
idx += 1;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (ch === "-" || isAsciiDigit(ch)) {
|
|
84
|
+
const parsed = parseJsonNumberToken(input, idx);
|
|
85
|
+
if (parsed) {
|
|
86
|
+
if (parsed.isInteger && isUnsafeIntegerLiteral(parsed.token)) out += `"${parsed.token}"`;
|
|
87
|
+
else out += parsed.token;
|
|
88
|
+
idx = parsed.end;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
out += ch;
|
|
93
|
+
idx += 1;
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
14
96
|
}
|
|
97
|
+
/** Parses JSON while preserving unsafe integer literals as strings. */
|
|
98
|
+
function parseJsonPreservingUnsafeIntegers(input) {
|
|
99
|
+
return JSON.parse(quoteUnsafeIntegerLiterals(input));
|
|
100
|
+
}
|
|
101
|
+
/** Parses or accepts an object while preserving unsafe integer literals in string input. */
|
|
102
|
+
function parseJsonObjectPreservingUnsafeIntegers(value) {
|
|
103
|
+
if (typeof value === "string") try {
|
|
104
|
+
return asNullableRecord(parseJsonPreservingUnsafeIntegers(value));
|
|
105
|
+
} catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return asNullableRecord(value);
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region packages/ai/src/transports/model-transport-debug.ts
|
|
112
|
+
/**
|
|
113
|
+
* Environment-driven debug controls for model transport logging.
|
|
114
|
+
*
|
|
115
|
+
* Model adapters share these helpers so payload, SSE, and transport diagnostics
|
|
116
|
+
* interpret OpenClaw debug environment variables consistently.
|
|
117
|
+
*/
|
|
15
118
|
function isTruthyEnv(value) {
|
|
16
|
-
const normalized =
|
|
119
|
+
const normalized = normalizeLowercaseStringOrEmpty(value);
|
|
17
120
|
return normalized.length > 0 && normalized !== "0" && normalized !== "false" && normalized !== "off" && normalized !== "no";
|
|
18
121
|
}
|
|
19
122
|
/** Resolves model payload debug verbosity from `OPENCLAW_DEBUG_MODEL_PAYLOAD`. */
|
|
20
123
|
function resolveModelPayloadDebugMode(env = process.env) {
|
|
21
|
-
const normalized =
|
|
124
|
+
const normalized = normalizeLowercaseStringOrEmpty(env.OPENCLAW_DEBUG_MODEL_PAYLOAD);
|
|
22
125
|
if (normalized === "tools" || normalized === "full-redacted") return normalized;
|
|
23
126
|
if (normalized === "summary") return "summary";
|
|
24
127
|
return "off";
|
|
25
128
|
}
|
|
26
129
|
/** Resolves SSE stream debug verbosity from `OPENCLAW_DEBUG_SSE`. */
|
|
27
130
|
function resolveModelSseDebugMode(env = process.env) {
|
|
28
|
-
const normalized =
|
|
131
|
+
const normalized = normalizeLowercaseStringOrEmpty(env.OPENCLAW_DEBUG_SSE);
|
|
29
132
|
if (normalized === "peek") return "peek";
|
|
30
133
|
if (normalized === "events" || isTruthyEnv(normalized)) return "events";
|
|
31
134
|
return "off";
|
|
@@ -46,173 +149,6 @@ function emitModelTransportDebug(log, message) {
|
|
|
46
149
|
log.debug(message);
|
|
47
150
|
}
|
|
48
151
|
//#endregion
|
|
49
|
-
//#region packages/normalization-core/src/string-normalization.ts
|
|
50
|
-
/** Coerces entries to strings, trims them, and drops empty results. */
|
|
51
|
-
function normalizeStringEntries(list) {
|
|
52
|
-
return (list ?? []).map((entry) => normalizeOptionalString(String(entry)) ?? "").filter(Boolean);
|
|
53
|
-
}
|
|
54
|
-
/** Returns first-seen unique values while preserving insertion order. */
|
|
55
|
-
function uniqueValues(values) {
|
|
56
|
-
return [...new Set(values)];
|
|
57
|
-
}
|
|
58
|
-
/** Returns first-seen unique strings while preserving insertion order. */
|
|
59
|
-
function uniqueStrings(values) {
|
|
60
|
-
return uniqueValues(values);
|
|
61
|
-
}
|
|
62
|
-
//#endregion
|
|
63
|
-
//#region packages/ai/src/providers/openai-reasoning-effort.ts
|
|
64
|
-
/**
|
|
65
|
-
* OpenAI-compatible reasoning-effort normalization. Different GPT families
|
|
66
|
-
* expose different accepted effort enums, so callers map requested values here
|
|
67
|
-
* before constructing provider payloads.
|
|
68
|
-
*/
|
|
69
|
-
const GPT_5_REASONING_EFFORTS = [
|
|
70
|
-
"minimal",
|
|
71
|
-
"low",
|
|
72
|
-
"medium",
|
|
73
|
-
"high"
|
|
74
|
-
];
|
|
75
|
-
const GPT_51_REASONING_EFFORTS = [
|
|
76
|
-
"none",
|
|
77
|
-
"low",
|
|
78
|
-
"medium",
|
|
79
|
-
"high"
|
|
80
|
-
];
|
|
81
|
-
const GPT_52_REASONING_EFFORTS = [
|
|
82
|
-
"none",
|
|
83
|
-
"low",
|
|
84
|
-
"medium",
|
|
85
|
-
"high",
|
|
86
|
-
"xhigh"
|
|
87
|
-
];
|
|
88
|
-
const GPT_56_REASONING_EFFORTS = [
|
|
89
|
-
"none",
|
|
90
|
-
"low",
|
|
91
|
-
"medium",
|
|
92
|
-
"high",
|
|
93
|
-
"xhigh",
|
|
94
|
-
"max"
|
|
95
|
-
];
|
|
96
|
-
const GPT_CODEX_REASONING_EFFORTS = [
|
|
97
|
-
"low",
|
|
98
|
-
"medium",
|
|
99
|
-
"high",
|
|
100
|
-
"xhigh"
|
|
101
|
-
];
|
|
102
|
-
const GPT_PRO_REASONING_EFFORTS = [
|
|
103
|
-
"medium",
|
|
104
|
-
"high",
|
|
105
|
-
"xhigh"
|
|
106
|
-
];
|
|
107
|
-
const GPT_5_PRO_REASONING_EFFORTS = ["high"];
|
|
108
|
-
const GPT_51_CODEX_MAX_REASONING_EFFORTS = [
|
|
109
|
-
"none",
|
|
110
|
-
"medium",
|
|
111
|
-
"high",
|
|
112
|
-
"xhigh"
|
|
113
|
-
];
|
|
114
|
-
const GPT_51_CODEX_MINI_REASONING_EFFORTS = ["medium"];
|
|
115
|
-
const GENERIC_REASONING_EFFORTS = [
|
|
116
|
-
"low",
|
|
117
|
-
"medium",
|
|
118
|
-
"high"
|
|
119
|
-
];
|
|
120
|
-
const CANONICAL_REASONING_EFFORTS = /* @__PURE__ */ new Set([
|
|
121
|
-
"none",
|
|
122
|
-
"minimal",
|
|
123
|
-
"low",
|
|
124
|
-
"medium",
|
|
125
|
-
"high",
|
|
126
|
-
"xhigh",
|
|
127
|
-
"max",
|
|
128
|
-
"off"
|
|
129
|
-
]);
|
|
130
|
-
function normalizeModelId(id) {
|
|
131
|
-
return normalizeLowercaseStringOrEmpty(id ?? "").replace(/-\d{4}-\d{2}-\d{2}$/u, "");
|
|
132
|
-
}
|
|
133
|
-
/** Return whether a model is the GPT-5.4 mini family. */
|
|
134
|
-
function isOpenAIGpt54MiniModel(model) {
|
|
135
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
136
|
-
return /^gpt-5\.4-mini(?:-|$)/u.test(id);
|
|
137
|
-
}
|
|
138
|
-
/** Return whether a model is the GPT-5.5 family. */
|
|
139
|
-
function isOpenAIGpt55Model(model) {
|
|
140
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
141
|
-
const name = normalizeModelId(typeof model.name === "string" ? model.name : void 0);
|
|
142
|
-
return /^gpt-5\.5(?:-|$)/u.test(id) || /^gpt-5\.5(?:\s|\(|-|$)/u.test(name);
|
|
143
|
-
}
|
|
144
|
-
/** Return whether a model is the GPT-5.6 family. */
|
|
145
|
-
function isOpenAIGpt56Model(model) {
|
|
146
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
147
|
-
const name = normalizeModelId(typeof model.name === "string" ? model.name : void 0);
|
|
148
|
-
return /^gpt-5\.6(?:-|$)/u.test(id) || /^gpt-5\.6(?:\s|\(|-|$)/u.test(name);
|
|
149
|
-
}
|
|
150
|
-
/** Normalize user-facing reasoning effort names to API effort names. */
|
|
151
|
-
function normalizeOpenAIReasoningEffort(effort) {
|
|
152
|
-
const trimmed = effort.trim();
|
|
153
|
-
const folded = trimmed.toLowerCase();
|
|
154
|
-
return CANONICAL_REASONING_EFFORTS.has(folded) ? folded : trimmed;
|
|
155
|
-
}
|
|
156
|
-
function readCompatReasoningEfforts(compat) {
|
|
157
|
-
if (!compat || typeof compat !== "object") return;
|
|
158
|
-
if (compat.supportsReasoningEffort === false) return [];
|
|
159
|
-
const raw = compat.supportedReasoningEfforts;
|
|
160
|
-
if (!Array.isArray(raw)) return;
|
|
161
|
-
const supported = uniqueStrings(normalizeStringEntries(raw.filter((value) => typeof value === "string")));
|
|
162
|
-
return supported.length > 0 ? supported : void 0;
|
|
163
|
-
}
|
|
164
|
-
function isDisabledReasoningEffort(effort) {
|
|
165
|
-
return effort === "none" || effort === "off";
|
|
166
|
-
}
|
|
167
|
-
/** Resolve the reasoning efforts accepted by a specific OpenAI-compatible model. */
|
|
168
|
-
function resolveOpenAISupportedReasoningEfforts(model) {
|
|
169
|
-
const compatEfforts = readCompatReasoningEfforts(model.compat);
|
|
170
|
-
if (compatEfforts) return compatEfforts;
|
|
171
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
172
|
-
if (/^gpt-5\.6(?:-|$)/u.test(id)) return GPT_56_REASONING_EFFORTS;
|
|
173
|
-
if (id === "gpt-5.1-codex-mini") return GPT_51_CODEX_MINI_REASONING_EFFORTS;
|
|
174
|
-
if (id === "gpt-5.1-codex-max") return GPT_51_CODEX_MAX_REASONING_EFFORTS;
|
|
175
|
-
if (/^gpt-5(?:\.\d+)?-codex(?:-|$)/u.test(id)) return GPT_CODEX_REASONING_EFFORTS;
|
|
176
|
-
if (id === "gpt-5-pro") return GPT_5_PRO_REASONING_EFFORTS;
|
|
177
|
-
if (/^gpt-5\.[2-9](?:\.\d+)?-pro(?:-|$)/u.test(id)) return GPT_PRO_REASONING_EFFORTS;
|
|
178
|
-
if (/^gpt-5\.[2-9](?:\.\d+)?(?:-|$)/u.test(id)) return GPT_52_REASONING_EFFORTS;
|
|
179
|
-
if (/^gpt-5\.1(?:-|$)/u.test(id)) return GPT_51_REASONING_EFFORTS;
|
|
180
|
-
if (/^gpt-5(?:-|$)/u.test(id)) return GPT_5_REASONING_EFFORTS;
|
|
181
|
-
return GENERIC_REASONING_EFFORTS;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Return whether a model accepts the temperature parameter. The GPT-5.6
|
|
185
|
-
* family rejects it with a 400; catalog compat can override per model.
|
|
186
|
-
*/
|
|
187
|
-
function supportsOpenAITemperature(model) {
|
|
188
|
-
const compat = model.compat;
|
|
189
|
-
if (compat && typeof compat === "object") {
|
|
190
|
-
const declared = compat.supportsTemperature;
|
|
191
|
-
if (typeof declared === "boolean") return declared;
|
|
192
|
-
}
|
|
193
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
194
|
-
return !/^gpt-5\.6(?:-|$)/u.test(id);
|
|
195
|
-
}
|
|
196
|
-
/** Return whether a model accepts a requested reasoning effort. */
|
|
197
|
-
function supportsOpenAIReasoningEffort(model, effort) {
|
|
198
|
-
return resolveOpenAISupportedReasoningEfforts(model).includes(normalizeOpenAIReasoningEffort(effort));
|
|
199
|
-
}
|
|
200
|
-
/** Resolve a requested reasoning effort to the closest value supported by the model. */
|
|
201
|
-
function resolveOpenAIReasoningEffortForModel(params) {
|
|
202
|
-
const requested = normalizeOpenAIReasoningEffort(params.effort);
|
|
203
|
-
const mapped = params.fallbackMap?.[requested] ?? (params.fallbackMap && CANONICAL_REASONING_EFFORTS.has(requested) ? Object.entries(params.fallbackMap).find(([effort]) => normalizeOpenAIReasoningEffort(effort) === requested)?.[1] : void 0);
|
|
204
|
-
const normalized = mapped === void 0 ? requested : mapped.trim();
|
|
205
|
-
const supported = resolveOpenAISupportedReasoningEfforts(params.model);
|
|
206
|
-
if (supported.includes(normalized)) return normalized;
|
|
207
|
-
if (requested === "off" && supported.includes("none")) return "none";
|
|
208
|
-
if (isDisabledReasoningEffort(requested) || isDisabledReasoningEffort(normalized)) return;
|
|
209
|
-
if (requested === "minimal" && supported.includes("low")) return "low";
|
|
210
|
-
if ((requested === "minimal" || requested === "low") && supported.includes("medium")) return "medium";
|
|
211
|
-
if (requested === "xhigh" && supported.includes("high")) return "high";
|
|
212
|
-
if (requested === "max" && supported.includes("xhigh")) return "xhigh";
|
|
213
|
-
return supported.find((effort) => !isDisabledReasoningEffort(normalizeOpenAIReasoningEffort(effort)));
|
|
214
|
-
}
|
|
215
|
-
//#endregion
|
|
216
152
|
//#region packages/ai/src/providers/clean-for-gemini.ts
|
|
217
153
|
const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
218
154
|
"patternProperties",
|
|
@@ -511,9 +447,6 @@ const SCHEMA_CHILD_KEYS = /* @__PURE__ */ new Set([
|
|
|
511
447
|
"unevaluatedItems",
|
|
512
448
|
"unevaluatedProperties"
|
|
513
449
|
]);
|
|
514
|
-
function isSchemaRecord(value) {
|
|
515
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
516
|
-
}
|
|
517
450
|
function cleanSchemaNode(node) {
|
|
518
451
|
if (Array.isArray(node)) {
|
|
519
452
|
let changed = false;
|
|
@@ -524,7 +457,7 @@ function cleanSchemaNode(node) {
|
|
|
524
457
|
});
|
|
525
458
|
return changed ? entries : node;
|
|
526
459
|
}
|
|
527
|
-
if (!
|
|
460
|
+
if (!isRecord(node)) return node;
|
|
528
461
|
let changed = false;
|
|
529
462
|
const cleaned = {};
|
|
530
463
|
for (const [key, value] of Object.entries(node)) {
|
|
@@ -537,7 +470,7 @@ function cleanSchemaNode(node) {
|
|
|
537
470
|
continue;
|
|
538
471
|
}
|
|
539
472
|
let next = value;
|
|
540
|
-
if (SCHEMA_MAP_KEYS$2.has(key) &&
|
|
473
|
+
if (SCHEMA_MAP_KEYS$2.has(key) && isRecord(value)) {
|
|
541
474
|
let mapChanged = false;
|
|
542
475
|
next = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => {
|
|
543
476
|
const cleanedChild = cleanSchemaNode(childValue);
|
|
@@ -556,10 +489,10 @@ function collectSchemaViolations(node, path, violations) {
|
|
|
556
489
|
node.forEach((entry, index) => collectSchemaViolations(entry, `${path}[${index}]`, violations));
|
|
557
490
|
return;
|
|
558
491
|
}
|
|
559
|
-
if (!
|
|
492
|
+
if (!isRecord(node)) return;
|
|
560
493
|
if ("pattern" in node) violations.push(`${path}.pattern`);
|
|
561
494
|
if (typeof node.maxLength === "number" && node.maxLength >= 2e3) violations.push(`${path}.maxLength`);
|
|
562
|
-
for (const [key, value] of Object.entries(node)) if (SCHEMA_MAP_KEYS$2.has(key) &&
|
|
495
|
+
for (const [key, value] of Object.entries(node)) if (SCHEMA_MAP_KEYS$2.has(key) && isRecord(value)) for (const [childKey, childValue] of Object.entries(value)) collectSchemaViolations(childValue, `${path}.${key}.${childKey}`, violations);
|
|
563
496
|
else if (SCHEMA_CHILD_KEYS.has(key)) collectSchemaViolations(value, `${path}.${key}`, violations);
|
|
564
497
|
}
|
|
565
498
|
/** Removes JSON Schema constraints that llama.cpp cannot compile into GBNF. */
|
|
@@ -1361,7 +1294,7 @@ function findOpenAIStrictSchemaViolations(schema, path, options) {
|
|
|
1361
1294
|
* Caches normalized object inputs by provider compatibility so repeated inventory builds preserve identity.
|
|
1362
1295
|
*/
|
|
1363
1296
|
const MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
|
|
1364
|
-
|
|
1297
|
+
const strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
|
|
1365
1298
|
function resolveToolSchemaModelCompat(compat) {
|
|
1366
1299
|
if (!compat) return;
|
|
1367
1300
|
const unsupportedToolSchemaKeywords = Array.isArray(compat.unsupportedToolSchemaKeywords) ? compat.unsupportedToolSchemaKeywords.filter((keyword) => typeof keyword === "string") : [];
|
|
@@ -1386,9 +1319,6 @@ function rememberStrictOpenAISchema(schema, key, value) {
|
|
|
1386
1319
|
}, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
|
|
1387
1320
|
return value;
|
|
1388
1321
|
}
|
|
1389
|
-
function clearOpenAIToolSchemaCacheForTest() {
|
|
1390
|
-
strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
|
|
1391
|
-
}
|
|
1392
1322
|
/** Normalizes a tool parameter schema into the OpenAI strict JSON-schema subset. */
|
|
1393
1323
|
function normalizeStrictOpenAIJsonSchema(schema, modelCompat) {
|
|
1394
1324
|
const schemaInput = schema ?? {};
|
|
@@ -1480,49 +1410,6 @@ function resolveOpenAIProjectedToolsStrictToolFlag(projection, strict) {
|
|
|
1480
1410
|
return projection.tools.every((tool) => isStrictOpenAIJsonSchemaCompatible(tool.parameters));
|
|
1481
1411
|
}
|
|
1482
1412
|
//#endregion
|
|
1483
|
-
//#region packages/ai/src/transports/openai-transport-shared.ts
|
|
1484
|
-
/** Shared options, usage shape, cache identity, ordering, and stream scheduling for OpenAI APIs. */
|
|
1485
|
-
const MODEL_STREAM_COOPERATIVE_YIELD_INTERVAL_MS = 12;
|
|
1486
|
-
const MODEL_STREAM_COOPERATIVE_YIELD_MAX_EVENTS = 64;
|
|
1487
|
-
const GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP = "skip_thought_signature_validator";
|
|
1488
|
-
const log = {
|
|
1489
|
-
debug(message, data) {
|
|
1490
|
-
getAiTransportHost().logDebug("openai-transport", () => ({
|
|
1491
|
-
message,
|
|
1492
|
-
data
|
|
1493
|
-
}));
|
|
1494
|
-
},
|
|
1495
|
-
info(message, data) {
|
|
1496
|
-
getAiTransportHost().logInfo("openai-transport", message, data);
|
|
1497
|
-
},
|
|
1498
|
-
warn(message, data) {
|
|
1499
|
-
getAiTransportHost().logWarn("openai-transport", message, data);
|
|
1500
|
-
}
|
|
1501
|
-
};
|
|
1502
|
-
function throwIfModelStreamAborted(signal) {
|
|
1503
|
-
if (signal?.aborted) throw transportAbortError(signal);
|
|
1504
|
-
}
|
|
1505
|
-
function createModelStreamCooperativeScheduler(signal) {
|
|
1506
|
-
let lastYieldedAt = Date.now();
|
|
1507
|
-
let eventsSinceYield = 0;
|
|
1508
|
-
return { async afterEvent() {
|
|
1509
|
-
throwIfModelStreamAborted(signal);
|
|
1510
|
-
eventsSinceYield += 1;
|
|
1511
|
-
const now = Date.now();
|
|
1512
|
-
if (eventsSinceYield < MODEL_STREAM_COOPERATIVE_YIELD_MAX_EVENTS && now - lastYieldedAt < MODEL_STREAM_COOPERATIVE_YIELD_INTERVAL_MS) return;
|
|
1513
|
-
eventsSinceYield = 0;
|
|
1514
|
-
lastYieldedAt = now;
|
|
1515
|
-
await new Promise((resolve) => {
|
|
1516
|
-
setTimeout(resolve, 0);
|
|
1517
|
-
});
|
|
1518
|
-
throwIfModelStreamAborted(signal);
|
|
1519
|
-
} };
|
|
1520
|
-
}
|
|
1521
|
-
function resolvePromptCacheKey(options, cacheRetention) {
|
|
1522
|
-
if (cacheRetention === "none") return;
|
|
1523
|
-
return clampOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId);
|
|
1524
|
-
}
|
|
1525
|
-
//#endregion
|
|
1526
1413
|
//#region packages/ai/src/transports/openai-responses-replay.ts
|
|
1527
1414
|
/** Resolves the assistant message id that can be replayed to OpenAI Responses. */
|
|
1528
1415
|
function resolveReplayableResponsesMessageId(params) {
|
|
@@ -1530,324 +1417,182 @@ function resolveReplayableResponsesMessageId(params) {
|
|
|
1530
1417
|
if (!params.textSignatureId) return params.fallbackOrdinal === 0 ? params.fallbackId : `${params.fallbackId}_${params.fallbackOrdinal}`;
|
|
1531
1418
|
return params.previousReplayItemWasReasoning ? params.textSignatureId : void 0;
|
|
1532
1419
|
}
|
|
1533
|
-
const OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS = "Follow the user request.";
|
|
1534
|
-
const AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS = 3e4;
|
|
1535
|
-
const RESPONSE_FAILED_NO_DETAILS_MESSAGE = "Unknown error (no error details in response)";
|
|
1536
|
-
const OPENAI_RESPONSES_REASONING_REPLAY_META_KEY = "__openclaw_replay";
|
|
1537
|
-
const OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY = "openclawReasoningReplay";
|
|
1538
1420
|
//#endregion
|
|
1539
|
-
//#region packages/ai/src/transports/openai-responses-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
function getServiceTierCostMultiplier(serviceTier) {
|
|
1546
|
-
switch (serviceTier) {
|
|
1547
|
-
case "flex": return .5;
|
|
1548
|
-
case "priority": return 2;
|
|
1549
|
-
default: return 1;
|
|
1550
|
-
}
|
|
1421
|
+
//#region packages/ai/src/transports/openai-responses-compaction-replay.ts
|
|
1422
|
+
const OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE = "openai-responses-compaction-suppression";
|
|
1423
|
+
const OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA = "rejected";
|
|
1424
|
+
function hashOptionalReplayContextValue(value) {
|
|
1425
|
+
const normalized = value?.trim();
|
|
1426
|
+
return normalized ? shortHash(normalized) : void 0;
|
|
1551
1427
|
}
|
|
1552
|
-
function
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1428
|
+
function buildOpenAIResponsesReplayContext(model, options) {
|
|
1429
|
+
return {
|
|
1430
|
+
provider: model.provider,
|
|
1431
|
+
api: model.api,
|
|
1432
|
+
model: model.id,
|
|
1433
|
+
baseUrlHash: hashOptionalReplayContextValue(model.baseUrl),
|
|
1434
|
+
sessionHash: hashOptionalReplayContextValue(options?.sessionId),
|
|
1435
|
+
authProfileHash: hashOptionalReplayContextValue(options?.authProfileId)
|
|
1436
|
+
};
|
|
1560
1437
|
}
|
|
1561
|
-
function
|
|
1562
|
-
if (
|
|
1563
|
-
|
|
1564
|
-
if (value === null) return "null";
|
|
1565
|
-
if (value === void 0) return "undefined";
|
|
1566
|
-
return Array.isArray(value) ? "array" : typeof value;
|
|
1438
|
+
function isOpenAIResponsesReplayContext(value) {
|
|
1439
|
+
if (!isRecord(value)) return false;
|
|
1440
|
+
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");
|
|
1567
1441
|
}
|
|
1568
|
-
function
|
|
1569
|
-
if (typeof
|
|
1570
|
-
|
|
1571
|
-
if (
|
|
1572
|
-
|
|
1573
|
-
let total = 0;
|
|
1574
|
-
if (typeof record.text === "string") total += record.text.length;
|
|
1575
|
-
if (typeof record.content === "string") total += record.content.length;
|
|
1576
|
-
else if (Array.isArray(record.content)) total += responseInputTextChars(record.content);
|
|
1577
|
-
return total;
|
|
1442
|
+
function readOpenAIResponsesCompactionReplayState(value) {
|
|
1443
|
+
if (!isOpenAIResponsesReplayContext(value) || typeof value.baseUrlHash !== "string" || value.v !== 1) return;
|
|
1444
|
+
const state = value;
|
|
1445
|
+
if (state.type === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE) return state.data === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA ? state : void 0;
|
|
1446
|
+
return state.type === "openai-responses-compaction" && typeof state.data === "string" && state.data.length > 0 && (state.id === void 0 || typeof state.id === "string") && (state.replayIndex === void 0 || Number.isSafeInteger(state.replayIndex) && state.replayIndex >= 0) ? state : void 0;
|
|
1578
1447
|
}
|
|
1579
|
-
function
|
|
1580
|
-
|
|
1581
|
-
const roles = /* @__PURE__ */ new Set();
|
|
1582
|
-
for (const item of input) if (item && typeof item === "object") {
|
|
1583
|
-
const role = item.role;
|
|
1584
|
-
if (typeof role === "string" && role.trim()) roles.add(role.trim());
|
|
1585
|
-
}
|
|
1586
|
-
return [...roles].toSorted().join(",");
|
|
1448
|
+
function openAIResponsesReplayContextMatches(state, context) {
|
|
1449
|
+
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;
|
|
1587
1450
|
}
|
|
1588
|
-
function
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1451
|
+
function captureOpenAIResponsesCompaction(output, item, replayIndex, model, captureMetadata) {
|
|
1452
|
+
const metadata = captureMetadata ?? buildOpenAIResponsesReasoningReplayMetadata(model);
|
|
1453
|
+
if (!item.encrypted_content) return;
|
|
1454
|
+
if (!metadata?.baseUrlHash) {
|
|
1455
|
+
log.debug("[responses] skipping compaction capture: missing base URL hash");
|
|
1592
1456
|
return;
|
|
1593
1457
|
}
|
|
1458
|
+
const currentReplay = readOpenAIResponsesCompactionReplayState(output.providerReplay);
|
|
1459
|
+
if (currentReplay?.type === "openai-responses-compaction" && (currentReplay.replayIndex ?? -1) > (replayIndex ?? Number.MAX_SAFE_INTEGER)) return;
|
|
1460
|
+
output.providerReplay = {
|
|
1461
|
+
v: 1,
|
|
1462
|
+
type: OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE,
|
|
1463
|
+
...item.id ? { id: item.id } : {},
|
|
1464
|
+
data: item.encrypted_content,
|
|
1465
|
+
...replayIndex === void 0 ? {} : { replayIndex },
|
|
1466
|
+
provider: metadata.provider,
|
|
1467
|
+
api: metadata.api,
|
|
1468
|
+
model: metadata.model,
|
|
1469
|
+
baseUrlHash: metadata.baseUrlHash,
|
|
1470
|
+
...metadata.sessionHash ? { sessionHash: metadata.sessionHash } : {},
|
|
1471
|
+
...metadata.authProfileHash ? { authProfileHash: metadata.authProfileHash } : {}
|
|
1472
|
+
};
|
|
1594
1473
|
}
|
|
1595
|
-
function
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
return typeof type === "string" && type !== "function" ? type : "";
|
|
1607
|
-
}
|
|
1608
|
-
function summarizeResponsesTools(tools) {
|
|
1609
|
-
if (!Array.isArray(tools)) return "count=0";
|
|
1610
|
-
const names = tools.map(readResponsesToolDisplayName).filter(Boolean);
|
|
1611
|
-
const mode = resolveModelPayloadDebugMode();
|
|
1612
|
-
const maxNames = mode === "tools" || mode === "full-redacted" ? names.length : 12;
|
|
1613
|
-
const label = maxNames >= names.length ? "names" : "sample";
|
|
1614
|
-
const shown = names.slice(0, maxNames).join(",");
|
|
1615
|
-
return `count=${tools.length}${shown ? ` ${label}=${shown}` : ""}`;
|
|
1474
|
+
function suppressOpenAIResponsesCompaction(output, model, options, rejectedCheckpoint) {
|
|
1475
|
+
const context = buildOpenAIResponsesReplayContext(model, options);
|
|
1476
|
+
if (!context.baseUrlHash) return;
|
|
1477
|
+
output.providerReplay = {
|
|
1478
|
+
v: 1,
|
|
1479
|
+
type: OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE,
|
|
1480
|
+
data: OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA,
|
|
1481
|
+
...context,
|
|
1482
|
+
baseUrlHash: context.baseUrlHash
|
|
1483
|
+
};
|
|
1484
|
+
if (rejectedCheckpoint) options?.onCompactionRejected?.(rejectedCheckpoint);
|
|
1616
1485
|
}
|
|
1617
|
-
function
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1486
|
+
function createCompactionTracker(output, model, options) {
|
|
1487
|
+
const replayIndexes = /* @__PURE__ */ new Map();
|
|
1488
|
+
return {
|
|
1489
|
+
added(item, replayIndex) {
|
|
1490
|
+
if (item.type === "compaction" && item.id) replayIndexes.set(item.id, replayIndex);
|
|
1491
|
+
},
|
|
1492
|
+
completed(item, fallbackReplayIndex) {
|
|
1493
|
+
if (item.type !== "compaction" || !item.encrypted_content) return;
|
|
1494
|
+
captureOpenAIResponsesCompaction(output, {
|
|
1495
|
+
type: "compaction",
|
|
1496
|
+
...item.id ? { id: item.id } : {},
|
|
1497
|
+
encrypted_content: item.encrypted_content
|
|
1498
|
+
}, (item.id ? replayIndexes.get(item.id) : void 0) ?? fallbackReplayIndex, model, options?.reasoningReplayMetadata);
|
|
1499
|
+
if (item.id) replayIndexes.delete(item.id);
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1626
1502
|
}
|
|
1627
|
-
function
|
|
1628
|
-
|
|
1629
|
-
return redacted.length > 2e3 ? `${truncateUtf16Safe(redacted, 2e3)}…<truncated>` : redacted;
|
|
1503
|
+
function isSafeResponsesReplayItemId(id) {
|
|
1504
|
+
return typeof id === "string" && id.length > 0 && id.length <= 64;
|
|
1630
1505
|
}
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1506
|
+
function resolveNewestOpenAIResponsesCompactionReplay(messages, model, options) {
|
|
1507
|
+
const context = buildOpenAIResponsesReplayContext(model, options);
|
|
1508
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
1509
|
+
const message = messages[index];
|
|
1510
|
+
if (message?.role !== "assistant") continue;
|
|
1511
|
+
const replay = readOpenAIResponsesCompactionReplayState(message.providerReplay);
|
|
1512
|
+
if (replay?.type === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE) {
|
|
1513
|
+
if (openAIResponsesReplayContextMatches(replay, context)) return;
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1516
|
+
if (replay?.type !== "openai-responses-compaction") {
|
|
1517
|
+
if (message.providerReplay?.type === "openai-responses-compaction") return;
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
if (!openAIResponsesReplayContextMatches(replay, context)) return;
|
|
1521
|
+
return {
|
|
1522
|
+
owner: message,
|
|
1523
|
+
item: {
|
|
1524
|
+
type: "compaction",
|
|
1525
|
+
...isSafeResponsesReplayItemId(replay.id) ? { id: replay.id } : {},
|
|
1526
|
+
encrypted_content: replay.data
|
|
1527
|
+
},
|
|
1528
|
+
replayIndex: replay.replayIndex ?? 0
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1642
1531
|
}
|
|
1643
|
-
function
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1532
|
+
function buildOpenAIResponsesCompactionReplayPlan(messages, model, options) {
|
|
1533
|
+
if (options?.mode === "full-history") return {
|
|
1534
|
+
messages,
|
|
1535
|
+
preserveUnframedToolResults: false
|
|
1536
|
+
};
|
|
1537
|
+
const compaction = resolveNewestOpenAIResponsesCompactionReplay(messages, model, options);
|
|
1538
|
+
if (!compaction) return {
|
|
1539
|
+
messages,
|
|
1540
|
+
preserveUnframedToolResults: false
|
|
1541
|
+
};
|
|
1542
|
+
const ownerIndex = messages.indexOf(compaction.owner);
|
|
1543
|
+
return {
|
|
1544
|
+
messages: [{
|
|
1545
|
+
...compaction.owner,
|
|
1546
|
+
content: compaction.owner.content.slice(compaction.replayIndex)
|
|
1547
|
+
}, ...messages.slice(ownerIndex + 1)],
|
|
1548
|
+
compaction: compaction.item,
|
|
1549
|
+
preserveUnframedToolResults: true
|
|
1550
|
+
};
|
|
1648
1551
|
}
|
|
1649
|
-
function
|
|
1650
|
-
|
|
1651
|
-
|
|
1552
|
+
function buildOpenAIResponsesReasoningReplayMetadata(model, options) {
|
|
1553
|
+
return {
|
|
1554
|
+
v: 1,
|
|
1555
|
+
source: "openai-responses",
|
|
1556
|
+
...buildOpenAIResponsesReplayContext(model, options)
|
|
1557
|
+
};
|
|
1652
1558
|
}
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
if (seen.has(value)) return out;
|
|
1661
|
-
seen.add(value);
|
|
1559
|
+
//#endregion
|
|
1560
|
+
//#region packages/ai/src/transports/openai-responses-replay-messages-internal.ts
|
|
1561
|
+
function stripEncryptedReasoningContentFields(value) {
|
|
1562
|
+
if (!value || typeof value !== "object") return {
|
|
1563
|
+
value,
|
|
1564
|
+
changed: false
|
|
1565
|
+
};
|
|
1662
1566
|
if (Array.isArray(value)) {
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
const
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
});
|
|
1677
|
-
}
|
|
1678
|
-
return out;
|
|
1567
|
+
let changed = false;
|
|
1568
|
+
const next = value.map((item) => {
|
|
1569
|
+
const stripped = stripEncryptedReasoningContentFields(item);
|
|
1570
|
+
changed ||= stripped.changed;
|
|
1571
|
+
return stripped.value;
|
|
1572
|
+
});
|
|
1573
|
+
return changed ? {
|
|
1574
|
+
value: next,
|
|
1575
|
+
changed: true
|
|
1576
|
+
} : {
|
|
1577
|
+
value,
|
|
1578
|
+
changed: false
|
|
1579
|
+
};
|
|
1679
1580
|
}
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1581
|
+
const source = value;
|
|
1582
|
+
if (source.type === "compaction") return {
|
|
1583
|
+
value,
|
|
1584
|
+
changed: false
|
|
1585
|
+
};
|
|
1586
|
+
let changed = false;
|
|
1587
|
+
const next = {};
|
|
1588
|
+
for (const [key, child] of Object.entries(source)) {
|
|
1589
|
+
if (key === "encrypted_content") {
|
|
1590
|
+
changed = true;
|
|
1686
1591
|
continue;
|
|
1687
1592
|
}
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
identifierKey: isResponseFailedIdentifierKey(key) ? key : void 0,
|
|
1692
|
-
out,
|
|
1693
|
-
seen
|
|
1694
|
-
});
|
|
1695
|
-
}
|
|
1696
|
-
return out;
|
|
1697
|
-
}
|
|
1698
|
-
function redactResponseFailedDiagnosticValue(value, opts = {}) {
|
|
1699
|
-
const key = opts.key ?? "";
|
|
1700
|
-
const depth = opts.depth ?? 0;
|
|
1701
|
-
if (typeof value === "string" || typeof value === "number") return key && isResponseFailedIdentifierKey(key) ? redactIdentifier(String(value), { len: 12 }) : value;
|
|
1702
|
-
if (depth > 6 || !value || typeof value !== "object") return value;
|
|
1703
|
-
const seen = opts.seen ?? /* @__PURE__ */ new WeakSet();
|
|
1704
|
-
if (seen.has(value)) return "<circular>";
|
|
1705
|
-
seen.add(value);
|
|
1706
|
-
if (Array.isArray(value)) return value.slice(0, 16).map((item) => redactResponseFailedDiagnosticValue(item, {
|
|
1707
|
-
key,
|
|
1708
|
-
depth: depth + 1,
|
|
1709
|
-
seen
|
|
1710
|
-
}));
|
|
1711
|
-
const out = {};
|
|
1712
|
-
for (const [childKey, child] of Object.entries(value)) out[childKey] = redactResponseFailedDiagnosticValue(child, {
|
|
1713
|
-
key: childKey,
|
|
1714
|
-
depth: depth + 1,
|
|
1715
|
-
seen
|
|
1716
|
-
});
|
|
1717
|
-
return out;
|
|
1718
|
-
}
|
|
1719
|
-
function buildResponsesFailedFailureFields(response) {
|
|
1720
|
-
if (!response) return {};
|
|
1721
|
-
const fields = {};
|
|
1722
|
-
for (const key of RESPONSE_FAILED_FAILURE_FIELD_KEYS) if (response[key] !== void 0 && response[key] !== null) fields[key] = response[key];
|
|
1723
|
-
return fields;
|
|
1724
|
-
}
|
|
1725
|
-
function buildResponsesFailedNoDetailsObservation(event, model, response = isRecord(event.response) ? event.response : void 0) {
|
|
1726
|
-
const failureFields = redactResponseFailedDiagnosticValue(buildResponsesFailedFailureFields(response));
|
|
1727
|
-
const metadataKeys = isRecord(response?.metadata) ? Object.keys(response.metadata).toSorted() : [];
|
|
1728
|
-
const responsePreview = {
|
|
1729
|
-
id: readResponseFailedString(response, "id"),
|
|
1730
|
-
status: readResponseFailedString(response, "status"),
|
|
1731
|
-
model: readResponseFailedString(response, "model"),
|
|
1732
|
-
object: readResponseFailedString(response, "object"),
|
|
1733
|
-
failureFields,
|
|
1734
|
-
metadataKeys
|
|
1735
|
-
};
|
|
1736
|
-
return {
|
|
1737
|
-
event: "openai_responses_response_failed_without_details",
|
|
1738
|
-
provider: model.provider,
|
|
1739
|
-
api: model.api,
|
|
1740
|
-
transportModel: model.id,
|
|
1741
|
-
providerRuntimeFailureKind: "no_error_details",
|
|
1742
|
-
responseId: responsePreview.id,
|
|
1743
|
-
responseStatus: responsePreview.status,
|
|
1744
|
-
responseModel: responsePreview.model,
|
|
1745
|
-
responseObject: responsePreview.object,
|
|
1746
|
-
metadataKeys,
|
|
1747
|
-
requestIdHashes: collectResponseFailedIdentifierHashes(event),
|
|
1748
|
-
failureFieldsPreview: stringifyRedactedEvent(failureFields),
|
|
1749
|
-
responsePreview: stringifyRedactedEvent(responsePreview)
|
|
1750
|
-
};
|
|
1751
|
-
}
|
|
1752
|
-
function summarizeResponsesFailedNoDetailsObservation(observation) {
|
|
1753
|
-
const requestIds = observation.requestIdHashes.join(",");
|
|
1754
|
-
const metadataKeys = observation.metadataKeys.join(",");
|
|
1755
|
-
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}`;
|
|
1756
|
-
}
|
|
1757
|
-
function normalizeResponsesFailedEvent(event, model) {
|
|
1758
|
-
const response = isRecord(event.response) ? event.response : void 0;
|
|
1759
|
-
const responseId = readResponseFailedString(response, "id") || void 0;
|
|
1760
|
-
const error = isRecord(response?.error) ? response.error : void 0;
|
|
1761
|
-
if (error) {
|
|
1762
|
-
const code = readResponseFailedString(error, "code").trim();
|
|
1763
|
-
const message = readResponseFailedString(error, "message").trim();
|
|
1764
|
-
if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId);
|
|
1765
|
-
}
|
|
1766
|
-
const incompleteReason = readResponseFailedString(isRecord(response?.incomplete_details) ? response.incomplete_details : void 0, "reason");
|
|
1767
|
-
if (incompleteReason) return buildResponsesFailedEventSummary(`incomplete: ${incompleteReason}`, responseId);
|
|
1768
|
-
return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, buildResponsesFailedNoDetailsObservation(event, model, response));
|
|
1769
|
-
}
|
|
1770
|
-
function logResponsesFailedNoDetails(observation) {
|
|
1771
|
-
log.warn(`[responses] response.failed missing error details provider=${observation.provider} api=${observation.api} model=${observation.transportModel} ` + summarizeResponsesFailedNoDetailsObservation(observation), observation);
|
|
1772
|
-
}
|
|
1773
|
-
function summarizeResponsesPayload(params) {
|
|
1774
|
-
if (!params || typeof params !== "object") return "payload=non-object";
|
|
1775
|
-
const record = params;
|
|
1776
|
-
const input = record.input;
|
|
1777
|
-
const reasoning = record.reasoning && typeof record.reasoning === "object" ? record.reasoning : void 0;
|
|
1778
|
-
const text = record.text && typeof record.text === "object" ? record.text : void 0;
|
|
1779
|
-
const parts = [
|
|
1780
|
-
`fields=${Object.keys(record).toSorted().join(",")}`,
|
|
1781
|
-
`model=${safeDebugValue(record.model)}`,
|
|
1782
|
-
`stream=${safeDebugValue(record.stream)}`,
|
|
1783
|
-
`inputItems=${Array.isArray(input) ? input.length : typeof input}`,
|
|
1784
|
-
`inputRoles=${responseInputRoles(input) || "none"}`,
|
|
1785
|
-
`inputTextChars=${responseInputTextChars(input)}`,
|
|
1786
|
-
`tools=${summarizeResponsesTools(record.tools)}`,
|
|
1787
|
-
`reasoningEffort=${safeDebugValue(reasoning?.effort)}`,
|
|
1788
|
-
`reasoningSummary=${safeDebugValue(reasoning?.summary)}`,
|
|
1789
|
-
`textVerbosity=${safeDebugValue(text?.verbosity)}`,
|
|
1790
|
-
`serviceTier=${safeDebugValue(record.service_tier)}`,
|
|
1791
|
-
`store=${safeDebugValue(record.store)}`,
|
|
1792
|
-
`promptCacheKey=${record.prompt_cache_key === void 0 ? "absent" : "present"}`,
|
|
1793
|
-
`metadataKeys=${record.metadata && typeof record.metadata === "object" ? Object.keys(record.metadata).toSorted().join(",") : "none"}`
|
|
1794
|
-
];
|
|
1795
|
-
if (resolveModelPayloadDebugMode() === "full-redacted") parts.push(`payload=${stringifyRedactedPayload(record)}`);
|
|
1796
|
-
return parts.join(" ");
|
|
1797
|
-
}
|
|
1798
|
-
function summarizeOpenAITransportError(error) {
|
|
1799
|
-
if (!error || typeof error !== "object") return `type=${typeof error} message=${safeDebugValue(error)}`;
|
|
1800
|
-
const record = error;
|
|
1801
|
-
const cause = record.cause && typeof record.cause === "object" ? record.cause : void 0;
|
|
1802
|
-
return [
|
|
1803
|
-
`name=${safeDebugValue(record.name)}`,
|
|
1804
|
-
`status=${safeDebugValue(record.status)}`,
|
|
1805
|
-
`code=${safeDebugValue(record.code)}`,
|
|
1806
|
-
`type=${safeDebugValue(record.type)}`,
|
|
1807
|
-
`causeName=${safeDebugValue(cause?.name)}`,
|
|
1808
|
-
`causeCode=${safeDebugValue(cause?.code)}`,
|
|
1809
|
-
`message=${error instanceof Error ? error.message : safeDebugValue(error)}`
|
|
1810
|
-
].join(" ");
|
|
1811
|
-
}
|
|
1812
|
-
//#endregion
|
|
1813
|
-
//#region packages/ai/src/transports/openai-responses-replay-internal.ts
|
|
1814
|
-
function isInvalidEncryptedContentError(error) {
|
|
1815
|
-
if (!error || typeof error !== "object") return false;
|
|
1816
|
-
const record = error;
|
|
1817
|
-
if (record.code === "invalid_encrypted_content" || record.code === "thinking_signature_invalid") return true;
|
|
1818
|
-
const message = typeof record.message === "string" ? record.message : "";
|
|
1819
|
-
return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || record.status === 400 && message.toLowerCase().includes("could not decrypt the provided encrypted_content");
|
|
1820
|
-
}
|
|
1821
|
-
function stripEncryptedContentFields(value) {
|
|
1822
|
-
if (!value || typeof value !== "object") return {
|
|
1823
|
-
value,
|
|
1824
|
-
changed: false
|
|
1825
|
-
};
|
|
1826
|
-
if (Array.isArray(value)) {
|
|
1827
|
-
let changed = false;
|
|
1828
|
-
const next = value.map((item) => {
|
|
1829
|
-
const stripped = stripEncryptedContentFields(item);
|
|
1830
|
-
changed ||= stripped.changed;
|
|
1831
|
-
return stripped.value;
|
|
1832
|
-
});
|
|
1833
|
-
return changed ? {
|
|
1834
|
-
value: next,
|
|
1835
|
-
changed: true
|
|
1836
|
-
} : {
|
|
1837
|
-
value,
|
|
1838
|
-
changed: false
|
|
1839
|
-
};
|
|
1840
|
-
}
|
|
1841
|
-
let changed = false;
|
|
1842
|
-
const next = {};
|
|
1843
|
-
for (const [key, child] of Object.entries(value)) {
|
|
1844
|
-
if (key === "encrypted_content") {
|
|
1845
|
-
changed = true;
|
|
1846
|
-
continue;
|
|
1847
|
-
}
|
|
1848
|
-
const stripped = stripEncryptedContentFields(child);
|
|
1849
|
-
changed ||= stripped.changed;
|
|
1850
|
-
next[key] = stripped.value;
|
|
1593
|
+
const stripped = stripEncryptedReasoningContentFields(child);
|
|
1594
|
+
changed ||= stripped.changed;
|
|
1595
|
+
next[key] = stripped.value;
|
|
1851
1596
|
}
|
|
1852
1597
|
return changed ? {
|
|
1853
1598
|
value: next,
|
|
@@ -1857,54 +1602,15 @@ function stripEncryptedContentFields(value) {
|
|
|
1857
1602
|
changed: false
|
|
1858
1603
|
};
|
|
1859
1604
|
}
|
|
1860
|
-
function stripResponsesRequestEncryptedContent(params) {
|
|
1861
|
-
const stripped = stripEncryptedContentFields(params.input);
|
|
1862
|
-
if (!stripped.changed) return params;
|
|
1863
|
-
return {
|
|
1864
|
-
...params,
|
|
1865
|
-
input: stripped.value
|
|
1866
|
-
};
|
|
1867
|
-
}
|
|
1868
|
-
function hashOptionalReplayContextValue(value) {
|
|
1869
|
-
const normalized = value?.trim();
|
|
1870
|
-
return normalized ? shortHash(normalized) : void 0;
|
|
1871
|
-
}
|
|
1872
|
-
function buildOpenAIResponsesReplayContext(model, options) {
|
|
1873
|
-
return {
|
|
1874
|
-
provider: model.provider,
|
|
1875
|
-
api: model.api,
|
|
1876
|
-
model: model.id,
|
|
1877
|
-
baseUrlHash: hashOptionalReplayContextValue(model.baseUrl),
|
|
1878
|
-
sessionHash: hashOptionalReplayContextValue(options?.sessionId),
|
|
1879
|
-
authProfileHash: hashOptionalReplayContextValue(options?.authProfileId)
|
|
1880
|
-
};
|
|
1881
|
-
}
|
|
1882
|
-
function buildOpenAIResponsesReasoningReplayMetadata(model, options) {
|
|
1883
|
-
return {
|
|
1884
|
-
v: 1,
|
|
1885
|
-
source: "openai-responses",
|
|
1886
|
-
...buildOpenAIResponsesReplayContext(model, options)
|
|
1887
|
-
};
|
|
1888
|
-
}
|
|
1889
|
-
function tagOpenAIResponsesReasoningReplayItem(item, model, options) {
|
|
1890
|
-
if (!("encrypted_content" in item)) return item;
|
|
1891
|
-
return {
|
|
1892
|
-
...item,
|
|
1893
|
-
[OPENAI_RESPONSES_REASONING_REPLAY_META_KEY]: buildOpenAIResponsesReasoningReplayMetadata(model, options)
|
|
1894
|
-
};
|
|
1895
|
-
}
|
|
1896
1605
|
function isOpenAIResponsesReasoningReplayMetadata(value) {
|
|
1897
|
-
if (!value
|
|
1606
|
+
if (!isOpenAIResponsesReplayContext(value)) return false;
|
|
1898
1607
|
const record = value;
|
|
1899
|
-
return record.v === 1 && record.source === "openai-responses"
|
|
1900
|
-
}
|
|
1901
|
-
function encryptedReasoningReplayMetadataMatches(metadata, context) {
|
|
1902
|
-
if (!metadata) return false;
|
|
1903
|
-
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;
|
|
1608
|
+
return record.v === 1 && record.source === "openai-responses";
|
|
1904
1609
|
}
|
|
1905
1610
|
function readOpenAIResponsesReasoningReplayBlockMetadata(block) {
|
|
1611
|
+
if (!Object.hasOwn(block, "openclawReasoningReplay")) return;
|
|
1906
1612
|
const value = block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY];
|
|
1907
|
-
return isOpenAIResponsesReasoningReplayMetadata(value) ? value :
|
|
1613
|
+
return isOpenAIResponsesReasoningReplayMetadata(value) ? value : null;
|
|
1908
1614
|
}
|
|
1909
1615
|
function normalizeOpenAIResponsesReasoningReplayItem(item) {
|
|
1910
1616
|
const record = item;
|
|
@@ -1914,33 +1620,20 @@ function normalizeOpenAIResponsesReasoningReplayItem(item) {
|
|
|
1914
1620
|
summary: []
|
|
1915
1621
|
};
|
|
1916
1622
|
}
|
|
1917
|
-
function prepareOpenAIResponsesReasoningItemForReplay(item, context, blockMetadata) {
|
|
1918
|
-
const
|
|
1623
|
+
function prepareOpenAIResponsesReasoningItemForReplay(item, context, blockMetadata, options) {
|
|
1624
|
+
const record = item;
|
|
1625
|
+
const hasRawMetadata = Object.hasOwn(record, OPENAI_RESPONSES_REASONING_REPLAY_META_KEY);
|
|
1626
|
+
const { [OPENAI_RESPONSES_REASONING_REPLAY_META_KEY]: rawMetadata, ...rest } = record;
|
|
1919
1627
|
if (!("encrypted_content" in rest)) return normalizeOpenAIResponsesReasoningReplayItem(rest);
|
|
1920
|
-
|
|
1921
|
-
return normalizeOpenAIResponsesReasoningReplayItem(
|
|
1922
|
-
|
|
1923
|
-
async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
1924
|
-
try {
|
|
1925
|
-
return await params.client.responses.create(params.request, params.requestOptions);
|
|
1926
|
-
} catch (error) {
|
|
1927
|
-
const retryRequest = stripResponsesRequestEncryptedContent(params.request);
|
|
1928
|
-
if (!isInvalidEncryptedContentError(error) || retryRequest === params.request) throw error;
|
|
1929
|
-
log.warn(`[responses] retrying without encrypted reasoning content provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
|
|
1930
|
-
return await params.client.responses.create(retryRequest, params.requestOptions);
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
function resolveAzureOpenAIApiVersion(env = process.env) {
|
|
1934
|
-
return env.AZURE_OPENAI_API_VERSION?.trim() || "preview";
|
|
1628
|
+
const metadata = blockMetadata !== void 0 ? blockMetadata ?? void 0 : isOpenAIResponsesReasoningReplayMetadata(rawMetadata) ? rawMetadata : void 0;
|
|
1629
|
+
if (blockMetadata === void 0 && !hasRawMetadata && options?.preserveUnattributedEncryptedContent === true || metadata && openAIResponsesReplayContextMatches(metadata, context)) return normalizeOpenAIResponsesReasoningReplayItem(rest);
|
|
1630
|
+
return normalizeOpenAIResponsesReasoningReplayItem(stripEncryptedReasoningContentFields(rest).value);
|
|
1935
1631
|
}
|
|
1936
1632
|
function normalizeResponsesReplayItemId(id, prefix) {
|
|
1937
1633
|
if (!id) return;
|
|
1938
1634
|
if (id.length <= 64) return id;
|
|
1939
1635
|
return `${prefix}_${shortHash(id)}`;
|
|
1940
1636
|
}
|
|
1941
|
-
function isSafeResponsesReplayItemId(id) {
|
|
1942
|
-
return typeof id === "string" && id.length > 0 && id.length <= 64;
|
|
1943
|
-
}
|
|
1944
1637
|
function encodeTextSignatureV1(id, phase) {
|
|
1945
1638
|
return JSON.stringify({
|
|
1946
1639
|
v: 1,
|
|
@@ -1948,7 +1641,7 @@ function encodeTextSignatureV1(id, phase) {
|
|
|
1948
1641
|
...phase ? { phase } : {}
|
|
1949
1642
|
});
|
|
1950
1643
|
}
|
|
1951
|
-
function
|
|
1644
|
+
function parseOpenAIResponsesTextSignature(signature) {
|
|
1952
1645
|
if (!signature) return;
|
|
1953
1646
|
if (signature.startsWith("{")) try {
|
|
1954
1647
|
const parsed = JSON.parse(signature);
|
|
@@ -1971,8 +1664,34 @@ function buildResponsesInputMessage(role, content) {
|
|
|
1971
1664
|
content
|
|
1972
1665
|
};
|
|
1973
1666
|
}
|
|
1974
|
-
function
|
|
1667
|
+
function createOpenAIResponsesAssistantOutput(model, api = model.api) {
|
|
1668
|
+
return {
|
|
1669
|
+
role: "assistant",
|
|
1670
|
+
content: [],
|
|
1671
|
+
api,
|
|
1672
|
+
provider: model.provider,
|
|
1673
|
+
model: model.id,
|
|
1674
|
+
usage: {
|
|
1675
|
+
input: 0,
|
|
1676
|
+
output: 0,
|
|
1677
|
+
cacheRead: 0,
|
|
1678
|
+
cacheWrite: 0,
|
|
1679
|
+
totalTokens: 0,
|
|
1680
|
+
cost: {
|
|
1681
|
+
input: 0,
|
|
1682
|
+
output: 0,
|
|
1683
|
+
cacheRead: 0,
|
|
1684
|
+
cacheWrite: 0,
|
|
1685
|
+
total: 0
|
|
1686
|
+
}
|
|
1687
|
+
},
|
|
1688
|
+
stopReason: "stop",
|
|
1689
|
+
timestamp: Date.now()
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1692
|
+
function convertResponsesMessagesWithStyle(model, context, allowedToolCallProviders, options, conversionStyle) {
|
|
1975
1693
|
const messages = [];
|
|
1694
|
+
const providerStyle = conversionStyle === "provider";
|
|
1976
1695
|
const shouldReplayReasoningItems = options?.replayReasoningItems ?? true;
|
|
1977
1696
|
const shouldReplayResponsesItemIds = options?.replayResponsesItemIds ?? true;
|
|
1978
1697
|
const replayContext = buildOpenAIResponsesReplayContext(model, {
|
|
@@ -1980,7 +1699,10 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
1980
1699
|
authProfileId: options?.authProfileId
|
|
1981
1700
|
});
|
|
1982
1701
|
const shouldNormalizeSameModelToolCallIds = model.provider === "github-copilot";
|
|
1983
|
-
const sanitizeIdPart = (part) =>
|
|
1702
|
+
const sanitizeIdPart = (part) => {
|
|
1703
|
+
const sanitized = part.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1704
|
+
return providerStyle ? sanitized : sanitized.replace(/_+$/, "");
|
|
1705
|
+
};
|
|
1984
1706
|
const normalizeIdPart = (part) => {
|
|
1985
1707
|
const sanitized = sanitizeIdPart(part);
|
|
1986
1708
|
return (sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized).replace(/_+$/, "");
|
|
@@ -2001,15 +1723,24 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2001
1723
|
const callId = id.slice(0, separatorIndex);
|
|
2002
1724
|
const itemId = id.slice(separatorIndex + 1);
|
|
2003
1725
|
const normalizedCallId = normalizeIdPart(callId);
|
|
2004
|
-
let normalizedItemId = source.provider !== model.provider || source.api !== model.api ? buildForeignResponsesItemId(itemId) : model.provider === "github-copilot" ? buildSameProviderCopilotResponsesItemId(itemId) : normalizeIdPart(itemId);
|
|
1726
|
+
let normalizedItemId = source.provider !== model.provider || source.api !== model.api ? buildForeignResponsesItemId(itemId) : model.provider === "github-copilot" ? providerStyle ? normalizeIdPart(itemId) : buildSameProviderCopilotResponsesItemId(itemId) : normalizeIdPart(itemId);
|
|
2005
1727
|
if (!normalizedItemId.startsWith("fc_")) normalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`);
|
|
2006
1728
|
return `${normalizedCallId}|${normalizedItemId}`;
|
|
2007
1729
|
};
|
|
2008
|
-
const
|
|
2009
|
-
|
|
1730
|
+
const replayPlan = buildOpenAIResponsesCompactionReplayPlan(context.messages, model, {
|
|
1731
|
+
sessionId: options?.sessionId,
|
|
1732
|
+
authProfileId: options?.authProfileId,
|
|
1733
|
+
mode: options?.replayMode
|
|
1734
|
+
});
|
|
1735
|
+
const transformedMessages = providerStyle ? transformProviderMessages(replayPlan.messages, model, normalizeToolCallId) : transformTransportMessages(replayPlan.messages, model, normalizeToolCallId, {
|
|
1736
|
+
normalizeSameModelToolCallIds: shouldNormalizeSameModelToolCallIds,
|
|
1737
|
+
preserveUnframedToolResults: replayPlan.preserveUnframedToolResults
|
|
1738
|
+
});
|
|
1739
|
+
if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) messages.push(buildResponsesInputMessage(model.reasoning && (providerStyle ? model.compat?.supportsDeveloperRole !== false : options?.supportsDeveloperRole !== false) ? "developer" : "system", [{
|
|
2010
1740
|
type: "input_text",
|
|
2011
1741
|
text: sanitizeTransportPayloadText(stripSystemPromptCacheBoundary(context.systemPrompt))
|
|
2012
1742
|
}]));
|
|
1743
|
+
if (replayPlan.compaction) messages.push(replayPlan.compaction);
|
|
2013
1744
|
let msgIndex = 0;
|
|
2014
1745
|
for (const msg of transformedMessages) {
|
|
2015
1746
|
if (msg.role === "user") if (typeof msg.content === "string") messages.push(buildResponsesInputMessage("user", [{
|
|
@@ -2024,8 +1755,9 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2024
1755
|
type: "input_image",
|
|
2025
1756
|
detail: "auto",
|
|
2026
1757
|
image_url: `data:${item.mimeType};base64,${item.data}`
|
|
2027
|
-
}).filter((item) => model.input.includes("image") || item.type !== "input_image");
|
|
1758
|
+
}).filter((item) => providerStyle || model.input.includes("image") || item.type !== "input_image");
|
|
2028
1759
|
if (content.length > 0) messages.push(buildResponsesInputMessage("user", content));
|
|
1760
|
+
else if (providerStyle) continue;
|
|
2029
1761
|
}
|
|
2030
1762
|
else if (msg.role === "assistant") {
|
|
2031
1763
|
const output = [];
|
|
@@ -2033,15 +1765,15 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2033
1765
|
let previousReplayItemWasReasoning = false;
|
|
2034
1766
|
const isDifferentModel = msg.model !== model.id && msg.provider === model.provider && msg.api === model.api;
|
|
2035
1767
|
for (const block of msg.content) if (block.type === "thinking") {
|
|
2036
|
-
if (shouldReplayReasoningItems && block.thinkingSignature && block.thinkingSignature.startsWith("{")) {
|
|
2037
|
-
const replayableReasoningItem = prepareOpenAIResponsesReasoningItemForReplay(JSON.parse(block.thinkingSignature), replayContext, readOpenAIResponsesReasoningReplayBlockMetadata(block));
|
|
1768
|
+
if (shouldReplayReasoningItems && block.thinkingSignature && (providerStyle || block.thinkingSignature.startsWith("{"))) {
|
|
1769
|
+
const replayableReasoningItem = prepareOpenAIResponsesReasoningItemForReplay(JSON.parse(block.thinkingSignature), replayContext, readOpenAIResponsesReasoningReplayBlockMetadata(block), providerStyle ? { preserveUnattributedEncryptedContent: true } : void 0);
|
|
2038
1770
|
if (!shouldReplayResponsesItemIds) delete replayableReasoningItem.id;
|
|
2039
|
-
if (shouldReplayResponsesItemIds && model.provider === "github-copilot" && !isSafeResponsesReplayItemId(replayableReasoningItem.id)) continue;
|
|
1771
|
+
if (shouldReplayResponsesItemIds && !providerStyle && model.provider === "github-copilot" && !isSafeResponsesReplayItemId(replayableReasoningItem.id)) continue;
|
|
2040
1772
|
output.push(replayableReasoningItem);
|
|
2041
1773
|
previousReplayItemWasReasoning = true;
|
|
2042
1774
|
}
|
|
2043
1775
|
} else if (block.type === "text") {
|
|
2044
|
-
const textSignature =
|
|
1776
|
+
const textSignature = parseOpenAIResponsesTextSignature(block.textSignature);
|
|
2045
1777
|
let msgId = resolveReplayableResponsesMessageId({
|
|
2046
1778
|
replayResponsesItemIds: shouldReplayResponsesItemIds,
|
|
2047
1779
|
textSignatureId: textSignature?.id,
|
|
@@ -2075,11 +1807,12 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2075
1807
|
...itemId ? { id: itemId } : {},
|
|
2076
1808
|
call_id: callId,
|
|
2077
1809
|
name: block.name,
|
|
2078
|
-
arguments: typeof block.arguments === "string" ? block.arguments : JSON.stringify(block.arguments ?? {})
|
|
1810
|
+
arguments: providerStyle ? JSON.stringify(block.arguments) : typeof block.arguments === "string" ? block.arguments : JSON.stringify(block.arguments ?? {})
|
|
2079
1811
|
});
|
|
2080
1812
|
previousReplayItemWasReasoning = false;
|
|
2081
1813
|
}
|
|
2082
1814
|
if (output.length > 0) messages.push(...output);
|
|
1815
|
+
else if (providerStyle) continue;
|
|
2083
1816
|
} else if (msg.role === "toolResult") {
|
|
2084
1817
|
const textResult = extractToolResultText(msg.content);
|
|
2085
1818
|
const sanitizedTextResult = sanitizeTransportPayloadText(textResult);
|
|
@@ -2108,6 +1841,119 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
|
|
|
2108
1841
|
}
|
|
2109
1842
|
return messages;
|
|
2110
1843
|
}
|
|
1844
|
+
function convertResponsesMessages$1(model, context, allowedToolCallProviders, options) {
|
|
1845
|
+
return convertResponsesMessagesWithStyle(model, context, allowedToolCallProviders, options, "transport");
|
|
1846
|
+
}
|
|
1847
|
+
function convertProviderResponsesMessages(model, context, allowedToolCallProviders, options) {
|
|
1848
|
+
return convertResponsesMessagesWithStyle(model, context, allowedToolCallProviders, options, "provider");
|
|
1849
|
+
}
|
|
1850
|
+
//#endregion
|
|
1851
|
+
//#region packages/ai/src/transports/openai-responses-replay-internal.ts
|
|
1852
|
+
function isInvalidEncryptedContentError(error) {
|
|
1853
|
+
if (!error || typeof error !== "object") return false;
|
|
1854
|
+
const record = error;
|
|
1855
|
+
if (record.code === "invalid_encrypted_content" || record.code === "thinking_signature_invalid") return true;
|
|
1856
|
+
const message = typeof record.message === "string" ? record.message : "";
|
|
1857
|
+
return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || record.status === 400 && message.toLowerCase().includes("could not decrypt the provided encrypted_content");
|
|
1858
|
+
}
|
|
1859
|
+
function isOrphanedFunctionCallOutputError(error) {
|
|
1860
|
+
if (!error || typeof error !== "object") return false;
|
|
1861
|
+
const record = error;
|
|
1862
|
+
const message = typeof record.message === "string" ? record.message : "";
|
|
1863
|
+
return /No tool call found for function call output with call_id [A-Za-z0-9_-]+/.test(message);
|
|
1864
|
+
}
|
|
1865
|
+
function commitResponsesEncryptedContentAttempt(attempt, commit) {
|
|
1866
|
+
if (attempt.kind === "compaction-stripped") commit(attempt.rejectedCompaction);
|
|
1867
|
+
}
|
|
1868
|
+
function stripResponsesRequestEncryptedReasoning(request) {
|
|
1869
|
+
const stripped = stripEncryptedReasoningContentFields(request.input);
|
|
1870
|
+
if (!stripped.changed) return request;
|
|
1871
|
+
return {
|
|
1872
|
+
...request,
|
|
1873
|
+
input: stripped.value
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
function stripResponsesRequestCompaction(request) {
|
|
1877
|
+
if (!Array.isArray(request.input)) return request;
|
|
1878
|
+
const input = request.input.filter((item) => !(item !== null && typeof item === "object" && item.type === "compaction"));
|
|
1879
|
+
return input.length === request.input.length ? request : {
|
|
1880
|
+
...request,
|
|
1881
|
+
input
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
function readOpenAIResponsesCompactionRejection(request) {
|
|
1885
|
+
if (!Array.isArray(request.input)) return;
|
|
1886
|
+
const item = request.input.find((candidate) => candidate !== null && typeof candidate === "object" && candidate.type === "compaction" && typeof candidate.encrypted_content === "string");
|
|
1887
|
+
return item ? {
|
|
1888
|
+
data: item.encrypted_content,
|
|
1889
|
+
...typeof item.id === "string" ? { id: item.id } : {}
|
|
1890
|
+
} : void 0;
|
|
1891
|
+
}
|
|
1892
|
+
async function resolveNextResponsesEncryptedContentAttempt(attempt, error, options) {
|
|
1893
|
+
const orphanedFunctionOutput = isOrphanedFunctionCallOutputError(error);
|
|
1894
|
+
if (!isInvalidEncryptedContentError(error) && !orphanedFunctionOutput || attempt.kind === "compaction-stripped") return;
|
|
1895
|
+
if (!orphanedFunctionOutput && (attempt.kind === "initial" || attempt.kind === "continuation-rejected")) {
|
|
1896
|
+
const reasoningStripped = stripResponsesRequestEncryptedReasoning(attempt.request);
|
|
1897
|
+
if (reasoningStripped !== attempt.request) return {
|
|
1898
|
+
kind: "reasoning-stripped",
|
|
1899
|
+
request: reasoningStripped
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
const locallyStripped = stripResponsesRequestCompaction(attempt.request);
|
|
1903
|
+
if (locallyStripped === attempt.request) return;
|
|
1904
|
+
let compactionStripped = options?.buildFullHistoryRequest ? await options.buildFullHistoryRequest() : locallyStripped;
|
|
1905
|
+
compactionStripped = stripResponsesRequestCompaction(compactionStripped);
|
|
1906
|
+
if (attempt.kind === "reasoning-stripped") compactionStripped = stripResponsesRequestEncryptedReasoning(compactionStripped);
|
|
1907
|
+
return {
|
|
1908
|
+
kind: "compaction-stripped",
|
|
1909
|
+
request: compactionStripped,
|
|
1910
|
+
rejectedCompaction: readOpenAIResponsesCompactionRejection(attempt.request)
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
1914
|
+
const sendAttempt = async (attempt) => {
|
|
1915
|
+
const { data, response } = await params.client.responses.create(attempt.request, params.requestOptions).withResponse();
|
|
1916
|
+
commitResponsesEncryptedContentAttempt(attempt, (checkpoint) => {
|
|
1917
|
+
if (checkpoint) params.onCompactionRejected?.(checkpoint);
|
|
1918
|
+
});
|
|
1919
|
+
return {
|
|
1920
|
+
stream: data,
|
|
1921
|
+
response,
|
|
1922
|
+
attempt
|
|
1923
|
+
};
|
|
1924
|
+
};
|
|
1925
|
+
let attempt = {
|
|
1926
|
+
kind: params.initialAttemptKind ?? "initial",
|
|
1927
|
+
request: params.request,
|
|
1928
|
+
...params.initialRejectedCompaction ? { rejectedCompaction: params.initialRejectedCompaction } : {}
|
|
1929
|
+
};
|
|
1930
|
+
while (true) {
|
|
1931
|
+
params.observePrompt?.(attempt.request, {
|
|
1932
|
+
egress: "responses-sdk",
|
|
1933
|
+
payloadVariant: attempt.kind
|
|
1934
|
+
});
|
|
1935
|
+
try {
|
|
1936
|
+
return await sendAttempt(attempt);
|
|
1937
|
+
} catch (error) {
|
|
1938
|
+
let nextAttempt = await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
|
|
1939
|
+
if (!nextAttempt && attempt.request.previous_response_id && error && typeof error === "object" && typeof error.status === "number" && error.code === "previous_response_not_found") {
|
|
1940
|
+
const request = { ...params.buildFullHistoryRequest ? await params.buildFullHistoryRequest() : attempt.request };
|
|
1941
|
+
delete request.previous_response_id;
|
|
1942
|
+
nextAttempt = {
|
|
1943
|
+
kind: "continuation-rejected",
|
|
1944
|
+
request
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1947
|
+
if (!nextAttempt) throw error;
|
|
1948
|
+
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";
|
|
1949
|
+
log.warn(`[responses] retrying ${retryDescription} provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
|
|
1950
|
+
attempt = nextAttempt;
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
function resolveAzureOpenAIApiVersion(env = process.env) {
|
|
1955
|
+
return env.AZURE_OPENAI_API_VERSION?.trim() || "preview";
|
|
1956
|
+
}
|
|
2111
1957
|
//#endregion
|
|
2112
1958
|
//#region packages/ai/src/providers/openai-responses-stream-compat.ts
|
|
2113
1959
|
const OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE = "output_text";
|
|
@@ -2137,19 +1983,16 @@ function resolveResponsesMessageSnapshotCollapse(params) {
|
|
|
2137
1983
|
}
|
|
2138
1984
|
//#endregion
|
|
2139
1985
|
//#region packages/ai/src/providers/openai-responses-tool-call-tracker.ts
|
|
2140
|
-
function readIdentityValue(value) {
|
|
2141
|
-
return (typeof value === "string" ? value.trim() : "") || void 0;
|
|
2142
|
-
}
|
|
2143
1986
|
function readOutputIndex(event) {
|
|
2144
1987
|
return typeof event.output_index === "number" && Number.isInteger(event.output_index) && event.output_index >= 0 ? event.output_index : void 0;
|
|
2145
1988
|
}
|
|
2146
1989
|
function readEventIdentity(event) {
|
|
2147
|
-
return { itemId:
|
|
1990
|
+
return { itemId: normalizeOptionalString(event.item_id) };
|
|
2148
1991
|
}
|
|
2149
1992
|
function readResponsesToolCallItemIdentity(item) {
|
|
2150
1993
|
return {
|
|
2151
|
-
itemId:
|
|
2152
|
-
callId:
|
|
1994
|
+
itemId: normalizeOptionalString(item.id),
|
|
1995
|
+
callId: normalizeOptionalString(item.call_id)
|
|
2153
1996
|
};
|
|
2154
1997
|
}
|
|
2155
1998
|
function createResponsesToolCallTracker() {
|
|
@@ -2212,6 +2055,308 @@ function createResponsesToolCallTracker() {
|
|
|
2212
2055
|
};
|
|
2213
2056
|
}
|
|
2214
2057
|
//#endregion
|
|
2058
|
+
//#region packages/ai/src/transports/openai-responses-debug.ts
|
|
2059
|
+
function stringifyUnknown(value, fallback = "") {
|
|
2060
|
+
if (typeof value === "string") return value;
|
|
2061
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
2062
|
+
return fallback;
|
|
2063
|
+
}
|
|
2064
|
+
function safeDebugValue(value) {
|
|
2065
|
+
if (typeof value === "string") return value;
|
|
2066
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
2067
|
+
if (value === null) return "null";
|
|
2068
|
+
if (value === void 0) return "undefined";
|
|
2069
|
+
return Array.isArray(value) ? "array" : typeof value;
|
|
2070
|
+
}
|
|
2071
|
+
function responseInputTextChars(input) {
|
|
2072
|
+
if (typeof input === "string") return input.length;
|
|
2073
|
+
if (Array.isArray(input)) return input.reduce((total, item) => total + responseInputTextChars(item), 0);
|
|
2074
|
+
if (!input || typeof input !== "object") return 0;
|
|
2075
|
+
const record = input;
|
|
2076
|
+
let total = 0;
|
|
2077
|
+
if (typeof record.text === "string") total += record.text.length;
|
|
2078
|
+
if (typeof record.content === "string") total += record.content.length;
|
|
2079
|
+
else if (Array.isArray(record.content)) total += responseInputTextChars(record.content);
|
|
2080
|
+
return total;
|
|
2081
|
+
}
|
|
2082
|
+
function responseInputRoles(input) {
|
|
2083
|
+
if (!Array.isArray(input)) return "";
|
|
2084
|
+
const roles = /* @__PURE__ */ new Set();
|
|
2085
|
+
for (const item of input) if (item && typeof item === "object") {
|
|
2086
|
+
const role = item.role;
|
|
2087
|
+
if (typeof role === "string" && role.trim()) roles.add(role.trim());
|
|
2088
|
+
}
|
|
2089
|
+
return [...roles].toSorted().join(",");
|
|
2090
|
+
}
|
|
2091
|
+
function responseInputItemShape(input) {
|
|
2092
|
+
if (!Array.isArray(input)) return "none";
|
|
2093
|
+
return input.map((item) => {
|
|
2094
|
+
if (!isRecord(item) || typeof item.type !== "string") return "unknown";
|
|
2095
|
+
if (item.type === "message" && typeof item.role === "string") return `message:${item.role}`;
|
|
2096
|
+
return item.type;
|
|
2097
|
+
}).join(",") || "none";
|
|
2098
|
+
}
|
|
2099
|
+
function hashOpaqueResponsesValue(value) {
|
|
2100
|
+
return createHash("sha256").update(value).digest("hex");
|
|
2101
|
+
}
|
|
2102
|
+
function summarizeResponsesCompactionItems(input) {
|
|
2103
|
+
if (!Array.isArray(input)) return [
|
|
2104
|
+
"compactionItems=0",
|
|
2105
|
+
"compactionIdHashes=none",
|
|
2106
|
+
"compactionPayloadHashes=none",
|
|
2107
|
+
"compactionInputIndexes=none"
|
|
2108
|
+
];
|
|
2109
|
+
const compactions = input.flatMap((item, inputIndex) => {
|
|
2110
|
+
if (!isRecord(item) || item.type !== "compaction") return [];
|
|
2111
|
+
return [{
|
|
2112
|
+
idHash: typeof item.id === "string" ? hashOpaqueResponsesValue(item.id) : void 0,
|
|
2113
|
+
inputIndex,
|
|
2114
|
+
payloadHash: typeof item.encrypted_content === "string" ? hashOpaqueResponsesValue(item.encrypted_content) : void 0
|
|
2115
|
+
}];
|
|
2116
|
+
});
|
|
2117
|
+
return [
|
|
2118
|
+
`compactionItems=${compactions.length}`,
|
|
2119
|
+
`compactionIdHashes=${compactions.flatMap((item) => item.idHash ?? []).join(",") || "none"}`,
|
|
2120
|
+
`compactionPayloadHashes=${compactions.flatMap((item) => item.payloadHash ?? []).join(",") || "none"}`,
|
|
2121
|
+
`compactionInputIndexes=${compactions.map((item) => item.inputIndex).join(",") || "none"}`
|
|
2122
|
+
];
|
|
2123
|
+
}
|
|
2124
|
+
function readToolPayloadField(record, field) {
|
|
2125
|
+
try {
|
|
2126
|
+
return record[field];
|
|
2127
|
+
} catch {
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
function readResponsesToolDisplayName(tool) {
|
|
2132
|
+
if (!tool || typeof tool !== "object") return "";
|
|
2133
|
+
const record = tool;
|
|
2134
|
+
const name = readToolPayloadField(record, "name");
|
|
2135
|
+
if (typeof name === "string") return name;
|
|
2136
|
+
const fn = readToolPayloadField(record, "function");
|
|
2137
|
+
if (fn && typeof fn === "object") {
|
|
2138
|
+
const fnName = readToolPayloadField(fn, "name");
|
|
2139
|
+
if (typeof fnName === "string") return fnName;
|
|
2140
|
+
}
|
|
2141
|
+
const type = readToolPayloadField(record, "type");
|
|
2142
|
+
return typeof type === "string" && type !== "function" ? type : "";
|
|
2143
|
+
}
|
|
2144
|
+
function summarizeResponsesTools(tools) {
|
|
2145
|
+
if (!Array.isArray(tools)) return "count=0";
|
|
2146
|
+
const names = tools.map(readResponsesToolDisplayName).filter(Boolean);
|
|
2147
|
+
const mode = resolveModelPayloadDebugMode();
|
|
2148
|
+
const maxNames = mode === "tools" || mode === "full-redacted" ? names.length : 12;
|
|
2149
|
+
const label = maxNames >= names.length ? "names" : "sample";
|
|
2150
|
+
const shown = names.slice(0, maxNames).join(",");
|
|
2151
|
+
return `count=${tools.length}${shown ? ` ${label}=${shown}` : ""}`;
|
|
2152
|
+
}
|
|
2153
|
+
function stringifyRedactedPayload(value) {
|
|
2154
|
+
try {
|
|
2155
|
+
const encoded = JSON.stringify(value, (key, child) => key === "encrypted_content" ? "<opaque data omitted>" : child);
|
|
2156
|
+
if (!encoded) return "<empty>";
|
|
2157
|
+
const redacted = redactSensitiveText(encoded, { mode: "tools" });
|
|
2158
|
+
return redacted.length > 8e3 ? `${truncateUtf16Safe(redacted, 8e3)}…<truncated>` : redacted;
|
|
2159
|
+
} catch {
|
|
2160
|
+
return "<unserializable>";
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
function stringifyRedactedEvent(value) {
|
|
2164
|
+
const redacted = stringifyRedactedPayload(value);
|
|
2165
|
+
return redacted.length > 2e3 ? `${truncateUtf16Safe(redacted, 2e3)}…<truncated>` : redacted;
|
|
2166
|
+
}
|
|
2167
|
+
const RESPONSE_FAILED_FAILURE_FIELD_KEYS = [
|
|
2168
|
+
"error",
|
|
2169
|
+
"incomplete_details",
|
|
2170
|
+
"status_details",
|
|
2171
|
+
"failure_reason",
|
|
2172
|
+
"last_error",
|
|
2173
|
+
"provider_error",
|
|
2174
|
+
"error_details"
|
|
2175
|
+
];
|
|
2176
|
+
function readResponseFailedString(record, key) {
|
|
2177
|
+
return stringifyUnknown(record?.[key]);
|
|
2178
|
+
}
|
|
2179
|
+
function buildResponsesFailedEventSummary(message, responseId, observation) {
|
|
2180
|
+
const summary = { message };
|
|
2181
|
+
if (responseId) summary.responseId = responseId;
|
|
2182
|
+
if (observation) summary.observation = observation;
|
|
2183
|
+
return summary;
|
|
2184
|
+
}
|
|
2185
|
+
function isResponseFailedIdentifierKey(key) {
|
|
2186
|
+
const normalized = key.replace(/[-_\s]/g, "").toLowerCase();
|
|
2187
|
+
return normalized === "requestid" || normalized === "xrequestid" || normalized === "providerrequestid" || normalized === "providerresponseid" || normalized === "litellmrequestid" || normalized.includes("request") && normalized.endsWith("id") || normalized.includes("provider") && normalized.endsWith("id");
|
|
2188
|
+
}
|
|
2189
|
+
function collectResponseFailedIdentifierHashes(value, opts = {}) {
|
|
2190
|
+
const path = opts.path ?? "";
|
|
2191
|
+
const depth = opts.depth ?? 0;
|
|
2192
|
+
const identifierKey = opts.identifierKey ?? "";
|
|
2193
|
+
const out = opts.out ?? [];
|
|
2194
|
+
const seen = opts.seen ?? /* @__PURE__ */ new WeakSet();
|
|
2195
|
+
if (out.length >= 12 || depth > 4 || !value || typeof value !== "object") return out;
|
|
2196
|
+
if (seen.has(value)) return out;
|
|
2197
|
+
seen.add(value);
|
|
2198
|
+
if (Array.isArray(value)) {
|
|
2199
|
+
for (const [index, item] of value.entries()) {
|
|
2200
|
+
if (index >= 8 || out.length >= 12) break;
|
|
2201
|
+
const itemString = typeof item === "string" || typeof item === "number" ? String(item).trim() : "";
|
|
2202
|
+
if (identifierKey && isResponseFailedIdentifierKey(identifierKey) && itemString) {
|
|
2203
|
+
out.push(`${path}[${index}]=${redactIdentifier(itemString, { len: 12 })}`);
|
|
2204
|
+
continue;
|
|
2205
|
+
}
|
|
2206
|
+
collectResponseFailedIdentifierHashes(item, {
|
|
2207
|
+
path: `${path}[${index}]`,
|
|
2208
|
+
depth: depth + 1,
|
|
2209
|
+
identifierKey,
|
|
2210
|
+
out,
|
|
2211
|
+
seen
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
return out;
|
|
2215
|
+
}
|
|
2216
|
+
for (const [key, child] of Object.entries(value)) {
|
|
2217
|
+
if (out.length >= 12) break;
|
|
2218
|
+
const childPath = path ? `${path}.${key}` : key;
|
|
2219
|
+
const childString = typeof child === "string" || typeof child === "number" ? String(child).trim() : "";
|
|
2220
|
+
if (isResponseFailedIdentifierKey(key) && childString) {
|
|
2221
|
+
out.push(`${childPath}=${redactIdentifier(childString, { len: 12 })}`);
|
|
2222
|
+
continue;
|
|
2223
|
+
}
|
|
2224
|
+
collectResponseFailedIdentifierHashes(child, {
|
|
2225
|
+
path: childPath,
|
|
2226
|
+
depth: depth + 1,
|
|
2227
|
+
identifierKey: isResponseFailedIdentifierKey(key) ? key : void 0,
|
|
2228
|
+
out,
|
|
2229
|
+
seen
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
return out;
|
|
2233
|
+
}
|
|
2234
|
+
function redactResponseFailedDiagnosticValue(value, opts = {}) {
|
|
2235
|
+
const key = opts.key ?? "";
|
|
2236
|
+
const depth = opts.depth ?? 0;
|
|
2237
|
+
if (typeof value === "string" || typeof value === "number") return key && isResponseFailedIdentifierKey(key) ? redactIdentifier(String(value), { len: 12 }) : value;
|
|
2238
|
+
if (depth > 6 || !value || typeof value !== "object") return value;
|
|
2239
|
+
const seen = opts.seen ?? /* @__PURE__ */ new WeakSet();
|
|
2240
|
+
if (seen.has(value)) return "<circular>";
|
|
2241
|
+
seen.add(value);
|
|
2242
|
+
if (Array.isArray(value)) return value.slice(0, 16).map((item) => redactResponseFailedDiagnosticValue(item, {
|
|
2243
|
+
key,
|
|
2244
|
+
depth: depth + 1,
|
|
2245
|
+
seen
|
|
2246
|
+
}));
|
|
2247
|
+
const out = {};
|
|
2248
|
+
for (const [childKey, child] of Object.entries(value)) out[childKey] = redactResponseFailedDiagnosticValue(child, {
|
|
2249
|
+
key: childKey,
|
|
2250
|
+
depth: depth + 1,
|
|
2251
|
+
seen
|
|
2252
|
+
});
|
|
2253
|
+
return out;
|
|
2254
|
+
}
|
|
2255
|
+
function buildResponsesFailedFailureFields(response) {
|
|
2256
|
+
if (!response) return {};
|
|
2257
|
+
const fields = {};
|
|
2258
|
+
for (const key of RESPONSE_FAILED_FAILURE_FIELD_KEYS) if (response[key] !== void 0 && response[key] !== null) fields[key] = response[key];
|
|
2259
|
+
return fields;
|
|
2260
|
+
}
|
|
2261
|
+
function buildResponsesFailedNoDetailsObservation(event, model, response = isRecord(event.response) ? event.response : void 0) {
|
|
2262
|
+
const failureFields = redactResponseFailedDiagnosticValue(buildResponsesFailedFailureFields(response));
|
|
2263
|
+
const metadataKeys = isRecord(response?.metadata) ? Object.keys(response.metadata).toSorted() : [];
|
|
2264
|
+
const responsePreview = {
|
|
2265
|
+
id: readResponseFailedString(response, "id"),
|
|
2266
|
+
status: readResponseFailedString(response, "status"),
|
|
2267
|
+
model: readResponseFailedString(response, "model"),
|
|
2268
|
+
object: readResponseFailedString(response, "object"),
|
|
2269
|
+
failureFields,
|
|
2270
|
+
metadataKeys
|
|
2271
|
+
};
|
|
2272
|
+
return {
|
|
2273
|
+
event: "openai_responses_response_failed_without_details",
|
|
2274
|
+
provider: model.provider,
|
|
2275
|
+
api: model.api,
|
|
2276
|
+
transportModel: model.id,
|
|
2277
|
+
providerRuntimeFailureKind: "no_error_details",
|
|
2278
|
+
responseId: responsePreview.id,
|
|
2279
|
+
responseStatus: responsePreview.status,
|
|
2280
|
+
responseModel: responsePreview.model,
|
|
2281
|
+
responseObject: responsePreview.object,
|
|
2282
|
+
metadataKeys,
|
|
2283
|
+
requestIdHashes: collectResponseFailedIdentifierHashes(event),
|
|
2284
|
+
failureFieldsPreview: stringifyRedactedEvent(failureFields),
|
|
2285
|
+
responsePreview: stringifyRedactedEvent(responsePreview)
|
|
2286
|
+
};
|
|
2287
|
+
}
|
|
2288
|
+
function summarizeResponsesFailedNoDetailsObservation(observation) {
|
|
2289
|
+
const requestIds = observation.requestIdHashes.join(",");
|
|
2290
|
+
const metadataKeys = observation.metadataKeys.join(",");
|
|
2291
|
+
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}`;
|
|
2292
|
+
}
|
|
2293
|
+
function normalizeResponsesFailedEvent(event, model) {
|
|
2294
|
+
const response = isRecord(event.response) ? event.response : void 0;
|
|
2295
|
+
const responseId = readResponseFailedString(response, "id") || void 0;
|
|
2296
|
+
const error = isRecord(response?.error) ? response.error : void 0;
|
|
2297
|
+
if (error) {
|
|
2298
|
+
const code = readResponseFailedString(error, "code").trim();
|
|
2299
|
+
const message = readResponseFailedString(error, "message").trim();
|
|
2300
|
+
if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId);
|
|
2301
|
+
}
|
|
2302
|
+
const incompleteReason = readResponseFailedString(isRecord(response?.incomplete_details) ? response.incomplete_details : void 0, "reason");
|
|
2303
|
+
if (incompleteReason) return buildResponsesFailedEventSummary(`incomplete: ${incompleteReason}`, responseId);
|
|
2304
|
+
return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, buildResponsesFailedNoDetailsObservation(event, model, response));
|
|
2305
|
+
}
|
|
2306
|
+
var ResponsesStreamFailure = class extends Error {
|
|
2307
|
+
constructor(failure, response) {
|
|
2308
|
+
super(failure.message);
|
|
2309
|
+
this.name = "ResponsesStreamFailure";
|
|
2310
|
+
this.responseId = failure.responseId;
|
|
2311
|
+
this.response = response;
|
|
2312
|
+
this.observation = failure.observation;
|
|
2313
|
+
}
|
|
2314
|
+
};
|
|
2315
|
+
function logResponsesFailedNoDetails(observation) {
|
|
2316
|
+
log.warn(`[responses] response.failed missing error details provider=${observation.provider} api=${observation.api} model=${observation.transportModel} ` + summarizeResponsesFailedNoDetailsObservation(observation), observation);
|
|
2317
|
+
}
|
|
2318
|
+
function summarizeResponsesPayload(params) {
|
|
2319
|
+
if (!params || typeof params !== "object") return "payload=non-object";
|
|
2320
|
+
const record = params;
|
|
2321
|
+
const input = record.input;
|
|
2322
|
+
const reasoning = record.reasoning && typeof record.reasoning === "object" ? record.reasoning : void 0;
|
|
2323
|
+
const text = record.text && typeof record.text === "object" ? record.text : void 0;
|
|
2324
|
+
const parts = [
|
|
2325
|
+
`fields=${Object.keys(record).toSorted().join(",")}`,
|
|
2326
|
+
`model=${safeDebugValue(record.model)}`,
|
|
2327
|
+
`stream=${safeDebugValue(record.stream)}`,
|
|
2328
|
+
`inputItems=${Array.isArray(input) ? input.length : typeof input}`,
|
|
2329
|
+
`inputItemShape=${responseInputItemShape(input)}`,
|
|
2330
|
+
`inputRoles=${responseInputRoles(input) || "none"}`,
|
|
2331
|
+
`inputTextChars=${responseInputTextChars(input)}`,
|
|
2332
|
+
`tools=${summarizeResponsesTools(record.tools)}`,
|
|
2333
|
+
`reasoningEffort=${safeDebugValue(reasoning?.effort)}`,
|
|
2334
|
+
`reasoningSummary=${safeDebugValue(reasoning?.summary)}`,
|
|
2335
|
+
`textVerbosity=${safeDebugValue(text?.verbosity)}`,
|
|
2336
|
+
`serviceTier=${safeDebugValue(record.service_tier)}`,
|
|
2337
|
+
...summarizeResponsesCompactionItems(input),
|
|
2338
|
+
`store=${safeDebugValue(record.store)}`,
|
|
2339
|
+
`promptCacheKey=${record.prompt_cache_key === void 0 ? "absent" : "present"}`,
|
|
2340
|
+
`metadataKeys=${record.metadata && typeof record.metadata === "object" ? Object.keys(record.metadata).toSorted().join(",") : "none"}`
|
|
2341
|
+
];
|
|
2342
|
+
if (resolveModelPayloadDebugMode() === "full-redacted") parts.push(`payload=${stringifyRedactedPayload(record)}`);
|
|
2343
|
+
return parts.join(" ");
|
|
2344
|
+
}
|
|
2345
|
+
function summarizeOpenAITransportError(error) {
|
|
2346
|
+
if (!error || typeof error !== "object") return `type=${typeof error} message=${safeDebugValue(error)}`;
|
|
2347
|
+
const record = error;
|
|
2348
|
+
const cause = record.cause && typeof record.cause === "object" ? record.cause : void 0;
|
|
2349
|
+
return [
|
|
2350
|
+
`name=${safeDebugValue(record.name)}`,
|
|
2351
|
+
`status=${safeDebugValue(record.status)}`,
|
|
2352
|
+
`code=${safeDebugValue(record.code)}`,
|
|
2353
|
+
`type=${safeDebugValue(record.type)}`,
|
|
2354
|
+
`causeName=${safeDebugValue(cause?.name)}`,
|
|
2355
|
+
`causeCode=${safeDebugValue(cause?.code)}`,
|
|
2356
|
+
`message=${error instanceof Error ? error.message : safeDebugValue(error)}`
|
|
2357
|
+
].join(" ");
|
|
2358
|
+
}
|
|
2359
|
+
//#endregion
|
|
2215
2360
|
//#region packages/ai/src/transports/openai-responses-stream-observer-internal.ts
|
|
2216
2361
|
const STRING_DELTA_EVENTS = /* @__PURE__ */ new Set([
|
|
2217
2362
|
"response.function_call_arguments.delta",
|
|
@@ -2233,7 +2378,7 @@ async function* adaptResponsesStream(stream, signal) {
|
|
|
2233
2378
|
await scheduler.afterEvent();
|
|
2234
2379
|
}
|
|
2235
2380
|
}
|
|
2236
|
-
async function* observeResponsesStream(stream, model) {
|
|
2381
|
+
async function* observeResponsesStream(stream, model, requestStartedAt) {
|
|
2237
2382
|
const startedAt = Date.now();
|
|
2238
2383
|
const eventTypes = /* @__PURE__ */ new Map();
|
|
2239
2384
|
const debugMode = resolveModelSseDebugMode();
|
|
@@ -2243,7 +2388,7 @@ async function* observeResponsesStream(stream, model) {
|
|
|
2243
2388
|
const type = isRecord(event) && typeof event.type === "string" ? event.type : "unknown";
|
|
2244
2389
|
eventCount += 1;
|
|
2245
2390
|
eventTypes.set(type, (eventTypes.get(type) ?? 0) + 1);
|
|
2246
|
-
if (eventCount === 1) emitModelTransportDebug(log, `[responses] first_event provider=${model.provider} api=${model.api} model=${model.id} elapsedMs=${Date.now() - startedAt} type=${type}`);
|
|
2391
|
+
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}`);
|
|
2247
2392
|
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)}`);
|
|
2248
2393
|
yield event;
|
|
2249
2394
|
}
|
|
@@ -2254,6 +2399,29 @@ async function* observeResponsesStream(stream, model) {
|
|
|
2254
2399
|
}
|
|
2255
2400
|
//#endregion
|
|
2256
2401
|
//#region packages/ai/src/transports/openai-responses-stream-slots-internal.ts
|
|
2402
|
+
function createResponsesOutputContentIndex() {
|
|
2403
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
2404
|
+
const identity = (item) => {
|
|
2405
|
+
if ((item.type === "reasoning" || item.type === "message") && item.id) return `${item.type}:${item.id}`;
|
|
2406
|
+
return item.type === "function_call" ? `function_call:${item.call_id ?? item.id ?? ""}` : void 0;
|
|
2407
|
+
};
|
|
2408
|
+
return {
|
|
2409
|
+
get(item) {
|
|
2410
|
+
const key = identity(item);
|
|
2411
|
+
return key === void 0 ? void 0 : indexes.get(key);
|
|
2412
|
+
},
|
|
2413
|
+
set(item, contentIndex) {
|
|
2414
|
+
const key = identity(item);
|
|
2415
|
+
if (key !== void 0) indexes.set(key, contentIndex);
|
|
2416
|
+
}
|
|
2417
|
+
};
|
|
2418
|
+
}
|
|
2419
|
+
function appendResponsesPendingTextDelta(slot, delta, materialize) {
|
|
2420
|
+
slot.pendingText = `${slot.pendingText ?? ""}${delta}`;
|
|
2421
|
+
const priorText = slot.collapseCandidate?.block.text ?? "";
|
|
2422
|
+
if (priorText.startsWith(slot.pendingText) || slot.pendingText.startsWith(priorText)) return;
|
|
2423
|
+
materialize(slot);
|
|
2424
|
+
}
|
|
2257
2425
|
function readResponsesOutputIndex(event) {
|
|
2258
2426
|
const outputIndex = event.output_index;
|
|
2259
2427
|
return typeof outputIndex === "number" && Number.isInteger(outputIndex) && outputIndex >= 0 ? outputIndex : void 0;
|
|
@@ -2296,6 +2464,14 @@ function createResponsesOutputSlotTracker() {
|
|
|
2296
2464
|
}
|
|
2297
2465
|
//#endregion
|
|
2298
2466
|
//#region packages/ai/src/providers/openai-responses-terminal-usage.ts
|
|
2467
|
+
/**
|
|
2468
|
+
* Canonical mapping for terminal OpenAI Responses events.
|
|
2469
|
+
*
|
|
2470
|
+
* `response.completed`, `response.incomplete`, and `response.failed` are terminal and can carry
|
|
2471
|
+
* usage, so every Responses path finalizes through the helpers here. Keeping one owner prevents
|
|
2472
|
+
* package and managed transports from drifting on token buckets, service-tier pricing, or future
|
|
2473
|
+
* terminal-event semantics.
|
|
2474
|
+
*/
|
|
2299
2475
|
function readCount(value) {
|
|
2300
2476
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2301
2477
|
}
|
|
@@ -2325,8 +2501,7 @@ function mapResponsesTerminalUsage(usage) {
|
|
|
2325
2501
|
}
|
|
2326
2502
|
/** Reasoning tokens are reported by the agent path only; the package path does not track them. */
|
|
2327
2503
|
function readResponsesReasoningTokens(usage) {
|
|
2328
|
-
|
|
2329
|
-
return typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) ? reasoningTokens : void 0;
|
|
2504
|
+
return asFiniteNumber(usage?.output_tokens_details?.reasoning_tokens);
|
|
2330
2505
|
}
|
|
2331
2506
|
function mapResponsesTerminalStopReason(status) {
|
|
2332
2507
|
if (!status) return "stop";
|
|
@@ -2371,13 +2546,19 @@ function resolveResponsesToolCallId(item, fallbackId) {
|
|
|
2371
2546
|
const generated = `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`;
|
|
2372
2547
|
return resolvedItemId ? `${generated}|${resolvedItemId}` : generated;
|
|
2373
2548
|
}
|
|
2374
|
-
function
|
|
2375
|
-
|
|
2376
|
-
const
|
|
2549
|
+
function resolveCompletedResponsesToolCall(item, streamed) {
|
|
2550
|
+
if (item.status && item.status !== "completed") throw new Error("Responses stream completed with an incomplete terminal tool call");
|
|
2551
|
+
const streamedName = streamed?.name?.trim() || void 0;
|
|
2552
|
+
const completedName = typeof item.name === "string" ? item.name.trim() || void 0 : void 0;
|
|
2377
2553
|
if (streamedName && completedName && streamedName !== completedName) throw new Error(`Responses stream changed tool-call function name from ${streamedName} to ${completedName}`);
|
|
2378
2554
|
const name = completedName ?? streamedName;
|
|
2379
2555
|
if (!name) throw new Error("Responses stream completed tool call without a function name");
|
|
2380
|
-
|
|
2556
|
+
const argumentsValue = parseJsonObjectPreservingUnsafeIntegers(streamed?.arguments ?? item.arguments);
|
|
2557
|
+
if (!argumentsValue) throw new Error("Responses stream completed tool call with invalid JSON arguments");
|
|
2558
|
+
return {
|
|
2559
|
+
name,
|
|
2560
|
+
arguments: argumentsValue
|
|
2561
|
+
};
|
|
2381
2562
|
}
|
|
2382
2563
|
function createResponsesTerminalController(params) {
|
|
2383
2564
|
const { output, stream, model, options } = params;
|
|
@@ -2400,8 +2581,35 @@ function createResponsesTerminalController(params) {
|
|
|
2400
2581
|
const content = part;
|
|
2401
2582
|
return content.type === "output_text" || content.type === "text" ? content.text ?? "" : content.refusal ?? "";
|
|
2402
2583
|
}).join("");
|
|
2403
|
-
|
|
2584
|
+
const started = params.startedTextBlocksByItemId.get(item.id);
|
|
2585
|
+
if (!text && !started) return;
|
|
2404
2586
|
const phase = item.phase ?? void 0;
|
|
2587
|
+
if (started) {
|
|
2588
|
+
const previousText = started.block.text;
|
|
2589
|
+
started.block.text = text;
|
|
2590
|
+
started.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2591
|
+
params.setLastTextBlock({
|
|
2592
|
+
block: started.block,
|
|
2593
|
+
index: started.index,
|
|
2594
|
+
phase
|
|
2595
|
+
});
|
|
2596
|
+
params.startedTextBlocksByItemId.delete(item.id);
|
|
2597
|
+
if (text.startsWith(previousText)) {
|
|
2598
|
+
const delta = text.slice(previousText.length);
|
|
2599
|
+
if (delta) stream.push({
|
|
2600
|
+
type: "text_delta",
|
|
2601
|
+
contentIndex: started.index,
|
|
2602
|
+
delta
|
|
2603
|
+
});
|
|
2604
|
+
}
|
|
2605
|
+
stream.push({
|
|
2606
|
+
type: "text_end",
|
|
2607
|
+
contentIndex: started.index,
|
|
2608
|
+
content: text,
|
|
2609
|
+
partial: output
|
|
2610
|
+
});
|
|
2611
|
+
return started.index;
|
|
2612
|
+
}
|
|
2405
2613
|
const previous = params.getLastTextBlock();
|
|
2406
2614
|
const collapse = resolveResponsesMessageSnapshotCollapse({
|
|
2407
2615
|
prior: previous && {
|
|
@@ -2420,7 +2628,7 @@ function createResponsesTerminalController(params) {
|
|
|
2420
2628
|
content: collapse.text,
|
|
2421
2629
|
partial: output
|
|
2422
2630
|
});
|
|
2423
|
-
return;
|
|
2631
|
+
return previous.index;
|
|
2424
2632
|
}
|
|
2425
2633
|
const block = {
|
|
2426
2634
|
type: "text",
|
|
@@ -2445,13 +2653,15 @@ function createResponsesTerminalController(params) {
|
|
|
2445
2653
|
content: text,
|
|
2446
2654
|
partial: output
|
|
2447
2655
|
});
|
|
2656
|
+
return index;
|
|
2448
2657
|
};
|
|
2449
2658
|
const appendToolCall = (item) => {
|
|
2659
|
+
const validated = resolveCompletedResponsesToolCall(item);
|
|
2450
2660
|
const toolCall = {
|
|
2451
2661
|
type: "toolCall",
|
|
2452
2662
|
id: resolveResponsesToolCallId(item),
|
|
2453
|
-
name:
|
|
2454
|
-
arguments:
|
|
2663
|
+
name: validated.name,
|
|
2664
|
+
arguments: validated.arguments
|
|
2455
2665
|
};
|
|
2456
2666
|
blocks.push(toolCall);
|
|
2457
2667
|
const contentIndex = blocks.length - 1;
|
|
@@ -2466,19 +2676,50 @@ function createResponsesTerminalController(params) {
|
|
|
2466
2676
|
toolCall,
|
|
2467
2677
|
partial: output
|
|
2468
2678
|
});
|
|
2679
|
+
return contentIndex;
|
|
2469
2680
|
};
|
|
2470
2681
|
const recoverTerminalOutput = (items, includeToolCalls) => {
|
|
2471
|
-
|
|
2472
|
-
for (const item of items
|
|
2473
|
-
|
|
2682
|
+
let hasCompletedLaterOutput = false;
|
|
2683
|
+
for (const item of items.toReversed()) {
|
|
2684
|
+
if (item.type === "reasoning") {
|
|
2685
|
+
hasCompletedLaterOutput ||= params.outputItemContentIndexes.get(item) !== void 0;
|
|
2686
|
+
continue;
|
|
2687
|
+
}
|
|
2688
|
+
if (item.type !== "message" && item.type !== "function_call") continue;
|
|
2689
|
+
if (params.outputItemContentIndexes.get(item) !== void 0 || item.type === "message" && params.startedTextBlocksByItemId.has(item.id)) {
|
|
2690
|
+
hasCompletedLaterOutput = true;
|
|
2691
|
+
continue;
|
|
2692
|
+
}
|
|
2693
|
+
if (item.type === "function_call" && !includeToolCalls) continue;
|
|
2694
|
+
if (hasCompletedLaterOutput) throw new Error("Responses stream omitted an output item before completed output");
|
|
2695
|
+
if (item.type === "function_call") resolveCompletedResponsesToolCall(item);
|
|
2696
|
+
}
|
|
2697
|
+
for (const [terminalIndex, item] of items.entries()) if (item.type === "message") {
|
|
2698
|
+
if (params.outputItemContentIndexes.get(item) !== void 0 && !params.startedTextBlocksByItemId.has(item.id)) continue;
|
|
2699
|
+
const appendedIndex = appendText(item);
|
|
2700
|
+
if (appendedIndex !== void 0) params.outputItemContentIndexes.set(item, appendedIndex);
|
|
2701
|
+
} else {
|
|
2474
2702
|
params.setLastTextBlock(null);
|
|
2475
|
-
|
|
2703
|
+
const alreadyCapturedCompaction = item.type === "compaction" && output.providerReplay?.type === "openai-responses-compaction" && output.providerReplay.id === item.id && output.providerReplay.data === item.encrypted_content;
|
|
2704
|
+
if (item.type === "compaction" && !alreadyCapturedCompaction) {
|
|
2705
|
+
let replayIndex = blocks.length;
|
|
2706
|
+
for (const laterItem of items.slice(terminalIndex + 1)) {
|
|
2707
|
+
const laterContentIndex = params.outputItemContentIndexes.get(laterItem);
|
|
2708
|
+
if (laterContentIndex !== void 0) {
|
|
2709
|
+
replayIndex = laterContentIndex;
|
|
2710
|
+
break;
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
captureOpenAIResponsesCompaction(output, item, replayIndex, model, options?.reasoningReplayMetadata);
|
|
2714
|
+
} else if (includeToolCalls && item.type === "function_call") {
|
|
2715
|
+
if (params.outputItemContentIndexes.get(item) !== void 0) continue;
|
|
2716
|
+
params.outputItemContentIndexes.set(item, appendToolCall(item));
|
|
2717
|
+
}
|
|
2476
2718
|
}
|
|
2477
2719
|
};
|
|
2478
|
-
const
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
output.responseId = response.id || output.responseId;
|
|
2720
|
+
const finalizeTerminalFacts = (response, responseId = response.id) => {
|
|
2721
|
+
output.responseId = responseId || output.responseId;
|
|
2722
|
+
output.responseModel = response.model?.trim() || void 0;
|
|
2482
2723
|
const usage = mapResponsesTerminalUsage(response.usage);
|
|
2483
2724
|
const reasoningTokens = readResponsesReasoningTokens(response.usage);
|
|
2484
2725
|
if (usage) output.usage = {
|
|
@@ -2497,6 +2738,11 @@ function createResponsesTerminalController(params) {
|
|
|
2497
2738
|
const tier = options.resolveServiceTier ? options.resolveServiceTier(response.service_tier, options.serviceTier) : response.service_tier ?? options.serviceTier;
|
|
2498
2739
|
options.applyServiceTierPricing(output.usage, tier);
|
|
2499
2740
|
}
|
|
2741
|
+
};
|
|
2742
|
+
const finalizeResponse = (response, terminalEventType) => {
|
|
2743
|
+
params.markFinalized();
|
|
2744
|
+
backfillReasoning(response.output ?? []);
|
|
2745
|
+
finalizeTerminalFacts(response);
|
|
2500
2746
|
const terminal = resolveResponsesTerminalStopReason({
|
|
2501
2747
|
status: response.status,
|
|
2502
2748
|
terminalEventType,
|
|
@@ -2508,28 +2754,22 @@ function createResponsesTerminalController(params) {
|
|
|
2508
2754
|
};
|
|
2509
2755
|
return {
|
|
2510
2756
|
finalizeResponse,
|
|
2757
|
+
finalizeFailedResponse: finalizeTerminalFacts,
|
|
2511
2758
|
recoverTerminalOutput
|
|
2512
2759
|
};
|
|
2513
2760
|
}
|
|
2514
2761
|
//#endregion
|
|
2515
2762
|
//#region packages/ai/src/transports/openai-responses-stream-internal.ts
|
|
2516
|
-
var ResponsesStreamFailure = class extends Error {
|
|
2517
|
-
constructor(failure, response) {
|
|
2518
|
-
super(failure.message);
|
|
2519
|
-
this.name = "ResponsesStreamFailure";
|
|
2520
|
-
this.responseId = failure.responseId;
|
|
2521
|
-
this.response = response;
|
|
2522
|
-
this.observation = failure.observation;
|
|
2523
|
-
}
|
|
2524
|
-
};
|
|
2525
2763
|
async function processResponsesStream(openaiStream, output, stream, model, options) {
|
|
2526
2764
|
const streamingToolCalls = createResponsesToolCallTracker();
|
|
2527
2765
|
const outputSlots = createResponsesOutputSlotTracker();
|
|
2528
2766
|
const reasoningBlocksById = /* @__PURE__ */ new Map();
|
|
2529
|
-
|
|
2767
|
+
const outputItemContentIndexes = createResponsesOutputContentIndex();
|
|
2768
|
+
const startedTextBlocksByItemId = /* @__PURE__ */ new Map();
|
|
2769
|
+
let terminalResponse;
|
|
2530
2770
|
let lastTextBlock = null;
|
|
2531
2771
|
const blocks = output.content;
|
|
2532
|
-
const
|
|
2772
|
+
const compactionTracker = createCompactionTracker(output, model, options);
|
|
2533
2773
|
const createOutputSlot = (event, item) => {
|
|
2534
2774
|
if (item.type === "reasoning") {
|
|
2535
2775
|
const block = {
|
|
@@ -2543,6 +2783,8 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2543
2783
|
contentIndex: blocks.length
|
|
2544
2784
|
};
|
|
2545
2785
|
blocks.push(block);
|
|
2786
|
+
reasoningBlocksById.set(item.id, block);
|
|
2787
|
+
outputItemContentIndexes.set(item, slot.contentIndex);
|
|
2546
2788
|
outputSlots.register(event, slot);
|
|
2547
2789
|
stream.push({
|
|
2548
2790
|
type: "thinking_start",
|
|
@@ -2567,7 +2809,15 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2567
2809
|
pendingText: collapseCandidate ? "" : null,
|
|
2568
2810
|
collapseCandidate
|
|
2569
2811
|
};
|
|
2570
|
-
if (block)
|
|
2812
|
+
if (block) {
|
|
2813
|
+
blocks.push(block);
|
|
2814
|
+
outputItemContentIndexes.set(messageItem, slot.contentIndex ?? blocks.length - 1);
|
|
2815
|
+
startedTextBlocksByItemId.set(messageItem.id, {
|
|
2816
|
+
block,
|
|
2817
|
+
index: slot.contentIndex ?? blocks.length - 1,
|
|
2818
|
+
phase: messageItem.phase ?? void 0
|
|
2819
|
+
});
|
|
2820
|
+
}
|
|
2571
2821
|
outputSlots.register(event, slot);
|
|
2572
2822
|
if (slot.contentIndex !== void 0) stream.push({
|
|
2573
2823
|
type: "text_start",
|
|
@@ -2594,7 +2844,13 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2594
2844
|
...slot.item.phase ? { textSignature: encodeTextSignatureV1(slot.item.id, slot.item.phase) } : {}
|
|
2595
2845
|
};
|
|
2596
2846
|
blocks.push(slot.block);
|
|
2597
|
-
slot.contentIndex =
|
|
2847
|
+
slot.contentIndex = blocks.length - 1;
|
|
2848
|
+
outputItemContentIndexes.set(slot.item, slot.contentIndex);
|
|
2849
|
+
startedTextBlocksByItemId.set(slot.item.id, {
|
|
2850
|
+
block: slot.block,
|
|
2851
|
+
index: slot.contentIndex,
|
|
2852
|
+
phase: slot.item.phase ?? void 0
|
|
2853
|
+
});
|
|
2598
2854
|
stream.push({
|
|
2599
2855
|
type: "text_start",
|
|
2600
2856
|
contentIndex: slot.contentIndex,
|
|
@@ -2612,25 +2868,19 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2612
2868
|
const materializeDeferredTextSlots = (except) => {
|
|
2613
2869
|
for (const slot of outputSlots.values()) if (slot !== except && slot.type === "text") materializeDeferredTextSlot(slot);
|
|
2614
2870
|
};
|
|
2615
|
-
const
|
|
2616
|
-
slot.pendingText = `${slot.pendingText ?? ""}${delta}`;
|
|
2617
|
-
const priorText = slot.collapseCandidate?.block.text ?? "";
|
|
2618
|
-
if (priorText.startsWith(slot.pendingText) || slot.pendingText.startsWith(priorText)) return;
|
|
2619
|
-
materializeDeferredTextSlot(slot);
|
|
2620
|
-
};
|
|
2621
|
-
const { finalizeResponse, recoverTerminalOutput } = createResponsesTerminalController({
|
|
2871
|
+
const { finalizeResponse, finalizeFailedResponse, recoverTerminalOutput } = createResponsesTerminalController({
|
|
2622
2872
|
output,
|
|
2623
2873
|
stream,
|
|
2624
2874
|
model,
|
|
2625
2875
|
options,
|
|
2626
2876
|
reasoningBlocksById,
|
|
2877
|
+
startedTextBlocksByItemId,
|
|
2878
|
+
outputItemContentIndexes,
|
|
2627
2879
|
getLastTextBlock: () => lastTextBlock,
|
|
2628
2880
|
setLastTextBlock: (block) => {
|
|
2629
2881
|
lastTextBlock = block;
|
|
2630
2882
|
},
|
|
2631
|
-
markFinalized: () =>
|
|
2632
|
-
terminalResponseEvent = "finalized";
|
|
2633
|
-
}
|
|
2883
|
+
markFinalized: () => void 0
|
|
2634
2884
|
});
|
|
2635
2885
|
const guardedStream = adaptResponsesStream(withFirstStreamEventTimeout(openaiStream, {
|
|
2636
2886
|
provider: model.provider,
|
|
@@ -2643,322 +2893,538 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
|
|
|
2643
2893
|
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."
|
|
2644
2894
|
}), options?.signal);
|
|
2645
2895
|
try {
|
|
2646
|
-
for await (const event of guardedStream)
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
contentIndex
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
partial: output
|
|
2697
|
-
});
|
|
2698
|
-
} else if (event.type === "response.reasoning_summary_part.done") {
|
|
2699
|
-
const slot = outputSlots.resolve(event, "thinking");
|
|
2700
|
-
if (!slot) continue;
|
|
2701
|
-
slot.item.summary = slot.item.summary || [];
|
|
2702
|
-
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2703
|
-
if (!lastPart) continue;
|
|
2704
|
-
slot.block.thinking += "\n\n";
|
|
2705
|
-
lastPart.text += "\n\n";
|
|
2706
|
-
stream.push({
|
|
2707
|
-
type: "thinking_delta",
|
|
2708
|
-
contentIndex: slot.contentIndex,
|
|
2709
|
-
delta: "\n\n",
|
|
2710
|
-
partial: output
|
|
2711
|
-
});
|
|
2712
|
-
} else if (event.type === "response.reasoning_text.delta") {
|
|
2713
|
-
const slot = outputSlots.resolve(event, "thinking");
|
|
2714
|
-
if (!slot) continue;
|
|
2715
|
-
slot.block.thinking += event.delta;
|
|
2716
|
-
stream.push({
|
|
2717
|
-
type: "thinking_delta",
|
|
2718
|
-
contentIndex: slot.contentIndex,
|
|
2719
|
-
delta: event.delta,
|
|
2720
|
-
partial: output
|
|
2721
|
-
});
|
|
2722
|
-
} else if (event.type === "response.content_part.added") {
|
|
2723
|
-
const slot = outputSlots.resolve(event, "text");
|
|
2724
|
-
if (!slot) continue;
|
|
2725
|
-
slot.item.content = slot.item.content || [];
|
|
2726
|
-
if (event.part.type === "output_text" || event.part.type === "text" || event.part.type === "refusal") slot.item.content.push(event.part);
|
|
2727
|
-
} else if (event.type === "response.output_text.delta") {
|
|
2728
|
-
const slot = outputSlots.resolve(event, "text");
|
|
2729
|
-
if (!slot) continue;
|
|
2730
|
-
slot.item.content ||= [];
|
|
2731
|
-
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2732
|
-
if (!isResponsesTextContentPartType(lastPart?.type)) {
|
|
2733
|
-
lastPart = {
|
|
2734
|
-
type: "output_text",
|
|
2735
|
-
text: "",
|
|
2736
|
-
annotations: []
|
|
2737
|
-
};
|
|
2738
|
-
slot.item.content.push(lastPart);
|
|
2739
|
-
}
|
|
2740
|
-
lastPart.text += event.delta;
|
|
2741
|
-
if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
|
|
2742
|
-
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2743
|
-
slot.block.text += event.delta;
|
|
2896
|
+
for await (const event of guardedStream) {
|
|
2897
|
+
notifyLlmRequestActivity(options?.signal);
|
|
2898
|
+
if (event.type === "response.created") output.responseId = event.response.id;
|
|
2899
|
+
else if (event.type === "response.output_item.added") {
|
|
2900
|
+
materializeDeferredTextSlots();
|
|
2901
|
+
const item = event.item;
|
|
2902
|
+
compactionTracker.added(item, blocks.length);
|
|
2903
|
+
if (item.type !== "message") lastTextBlock = null;
|
|
2904
|
+
if (item.type === "reasoning" || item.type === "message") createOutputSlot(event, item);
|
|
2905
|
+
else if (item.type === "function_call") {
|
|
2906
|
+
const toolCallBlock = {
|
|
2907
|
+
type: "toolCall",
|
|
2908
|
+
id: resolveResponsesToolCallId(item),
|
|
2909
|
+
name: typeof item.name === "string" ? item.name.trim() : "",
|
|
2910
|
+
arguments: {},
|
|
2911
|
+
partialJson: item.arguments || ""
|
|
2912
|
+
};
|
|
2913
|
+
const contentIndex = output.content.length;
|
|
2914
|
+
const toolCallState = {
|
|
2915
|
+
block: toolCallBlock,
|
|
2916
|
+
contentIndex,
|
|
2917
|
+
argumentStreamReliable: true,
|
|
2918
|
+
...readResponsesToolCallItemIdentity(item)
|
|
2919
|
+
};
|
|
2920
|
+
streamingToolCalls.register(event, toolCallState);
|
|
2921
|
+
if (readResponsesOutputIndex(event) !== void 0) outputSlots.register(event, {
|
|
2922
|
+
type: "toolCall",
|
|
2923
|
+
toolCall: toolCallState
|
|
2924
|
+
});
|
|
2925
|
+
output.content.push(toolCallBlock);
|
|
2926
|
+
outputItemContentIndexes.set(item, contentIndex);
|
|
2927
|
+
stream.push({
|
|
2928
|
+
type: "toolcall_start",
|
|
2929
|
+
contentIndex,
|
|
2930
|
+
partial: output
|
|
2931
|
+
});
|
|
2932
|
+
}
|
|
2933
|
+
} else if (event.type === "response.reasoning_summary_part.added") {
|
|
2934
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2935
|
+
if (!slot) continue;
|
|
2936
|
+
slot.item.summary = slot.item.summary || [];
|
|
2937
|
+
slot.item.summary.push(event.part);
|
|
2938
|
+
} else if (event.type === "response.reasoning_summary_text.delta") {
|
|
2939
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2940
|
+
if (!slot) continue;
|
|
2941
|
+
slot.item.summary = slot.item.summary || [];
|
|
2942
|
+
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2943
|
+
if (!lastPart) continue;
|
|
2944
|
+
slot.block.thinking += event.delta;
|
|
2945
|
+
lastPart.text += event.delta;
|
|
2744
2946
|
stream.push({
|
|
2745
|
-
type: "
|
|
2947
|
+
type: "thinking_delta",
|
|
2746
2948
|
contentIndex: slot.contentIndex,
|
|
2747
|
-
delta: event.delta
|
|
2949
|
+
delta: event.delta,
|
|
2950
|
+
partial: output
|
|
2748
2951
|
});
|
|
2749
|
-
}
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
lastPart
|
|
2757
|
-
type: "text",
|
|
2758
|
-
text: ""
|
|
2759
|
-
};
|
|
2760
|
-
slot.item.content.push(lastPart);
|
|
2761
|
-
}
|
|
2762
|
-
lastPart.text += event.delta;
|
|
2763
|
-
if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
|
|
2764
|
-
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2765
|
-
slot.block.text += event.delta;
|
|
2952
|
+
} else if (event.type === "response.reasoning_summary_part.done") {
|
|
2953
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2954
|
+
if (!slot) continue;
|
|
2955
|
+
slot.item.summary = slot.item.summary || [];
|
|
2956
|
+
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2957
|
+
if (!lastPart) continue;
|
|
2958
|
+
slot.block.thinking += "\n\n";
|
|
2959
|
+
lastPart.text += "\n\n";
|
|
2766
2960
|
stream.push({
|
|
2767
|
-
type: "
|
|
2961
|
+
type: "thinking_delta",
|
|
2768
2962
|
contentIndex: slot.contentIndex,
|
|
2769
|
-
delta:
|
|
2963
|
+
delta: "\n\n",
|
|
2964
|
+
partial: output
|
|
2770
2965
|
});
|
|
2771
|
-
}
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
slot.item.content ||= [];
|
|
2776
|
-
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2777
|
-
if (lastPart?.type !== "refusal") {
|
|
2778
|
-
lastPart = {
|
|
2779
|
-
type: "refusal",
|
|
2780
|
-
refusal: ""
|
|
2781
|
-
};
|
|
2782
|
-
slot.item.content.push(lastPart);
|
|
2783
|
-
}
|
|
2784
|
-
lastPart.refusal += event.delta;
|
|
2785
|
-
if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
|
|
2786
|
-
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2787
|
-
slot.block.text += event.delta;
|
|
2966
|
+
} else if (event.type === "response.reasoning_text.delta") {
|
|
2967
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2968
|
+
if (!slot) continue;
|
|
2969
|
+
slot.block.thinking += event.delta;
|
|
2788
2970
|
stream.push({
|
|
2789
|
-
type: "
|
|
2971
|
+
type: "thinking_delta",
|
|
2790
2972
|
contentIndex: slot.contentIndex,
|
|
2791
|
-
delta: event.delta
|
|
2792
|
-
});
|
|
2793
|
-
}
|
|
2794
|
-
} else if (event.type === "response.function_call_arguments.delta") {
|
|
2795
|
-
const toolCall = streamingToolCalls.resolve(event);
|
|
2796
|
-
if (toolCall) {
|
|
2797
|
-
toolCall.block.partialJson += event.delta;
|
|
2798
|
-
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
2799
|
-
stream.push({
|
|
2800
|
-
type: "toolcall_delta",
|
|
2801
|
-
contentIndex: toolCall.contentIndex,
|
|
2802
2973
|
delta: event.delta,
|
|
2803
2974
|
partial: output
|
|
2804
2975
|
});
|
|
2805
|
-
} else if (
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2976
|
+
} else if (event.type === "response.content_part.added") {
|
|
2977
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2978
|
+
if (!slot) continue;
|
|
2979
|
+
slot.item.content = slot.item.content || [];
|
|
2980
|
+
if (event.part.type === "output_text" || event.part.type === "text" || event.part.type === "refusal") slot.item.content.push(event.part);
|
|
2981
|
+
} else if (event.type === "response.output_text.delta") {
|
|
2982
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2983
|
+
if (!slot) continue;
|
|
2984
|
+
slot.item.content ||= [];
|
|
2985
|
+
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2986
|
+
if (!isResponsesTextContentPartType(lastPart?.type)) {
|
|
2987
|
+
lastPart = {
|
|
2988
|
+
type: "output_text",
|
|
2989
|
+
text: "",
|
|
2990
|
+
annotations: []
|
|
2991
|
+
};
|
|
2992
|
+
slot.item.content.push(lastPart);
|
|
2993
|
+
}
|
|
2994
|
+
lastPart.text += event.delta;
|
|
2995
|
+
if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
|
|
2996
|
+
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2997
|
+
slot.block.text += event.delta;
|
|
2998
|
+
stream.push({
|
|
2999
|
+
type: "text_delta",
|
|
3000
|
+
contentIndex: slot.contentIndex,
|
|
3001
|
+
delta: event.delta
|
|
3002
|
+
});
|
|
3003
|
+
}
|
|
3004
|
+
} else if (isAzureResponsesTextDeltaEvent(event)) {
|
|
3005
|
+
const slot = outputSlots.resolve(event, "text");
|
|
3006
|
+
if (!slot) continue;
|
|
3007
|
+
slot.item.content = slot.item.content || [];
|
|
3008
|
+
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
3009
|
+
if (lastPart?.type !== "text") {
|
|
3010
|
+
lastPart = {
|
|
3011
|
+
type: "text",
|
|
3012
|
+
text: ""
|
|
3013
|
+
};
|
|
3014
|
+
slot.item.content.push(lastPart);
|
|
3015
|
+
}
|
|
3016
|
+
lastPart.text += event.delta;
|
|
3017
|
+
if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
|
|
3018
|
+
else if (slot.block && slot.contentIndex !== void 0) {
|
|
3019
|
+
slot.block.text += event.delta;
|
|
3020
|
+
stream.push({
|
|
3021
|
+
type: "text_delta",
|
|
3022
|
+
contentIndex: slot.contentIndex,
|
|
3023
|
+
delta: event.delta
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3026
|
+
} else if (event.type === "response.refusal.delta") {
|
|
3027
|
+
const slot = outputSlots.resolve(event, "text");
|
|
3028
|
+
if (!slot) continue;
|
|
3029
|
+
slot.item.content ||= [];
|
|
3030
|
+
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
3031
|
+
if (lastPart?.type !== "refusal") {
|
|
3032
|
+
lastPart = {
|
|
3033
|
+
type: "refusal",
|
|
3034
|
+
refusal: ""
|
|
3035
|
+
};
|
|
3036
|
+
slot.item.content.push(lastPart);
|
|
3037
|
+
}
|
|
3038
|
+
lastPart.refusal += event.delta;
|
|
3039
|
+
if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
|
|
3040
|
+
else if (slot.block && slot.contentIndex !== void 0) {
|
|
3041
|
+
slot.block.text += event.delta;
|
|
3042
|
+
stream.push({
|
|
3043
|
+
type: "text_delta",
|
|
3044
|
+
contentIndex: slot.contentIndex,
|
|
3045
|
+
delta: event.delta
|
|
3046
|
+
});
|
|
2815
3047
|
}
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
3048
|
+
} else if (event.type === "response.function_call_arguments.delta") {
|
|
3049
|
+
const toolCall = streamingToolCalls.resolve(event);
|
|
3050
|
+
if (toolCall) {
|
|
3051
|
+
toolCall.block.partialJson += event.delta;
|
|
3052
|
+
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
3053
|
+
stream.push({
|
|
2819
3054
|
type: "toolcall_delta",
|
|
2820
3055
|
contentIndex: toolCall.contentIndex,
|
|
2821
|
-
delta,
|
|
3056
|
+
delta: event.delta,
|
|
2822
3057
|
partial: output
|
|
2823
3058
|
});
|
|
2824
|
-
}
|
|
2825
|
-
} else if (
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
});
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
const
|
|
2849
|
-
|
|
2850
|
-
const
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
outputSlot.pendingText = null;
|
|
2859
|
-
if (collapse.kind === "extend" && outputSlot.collapseCandidate) {
|
|
2860
|
-
outputSlot.collapseCandidate.block.text = collapse.text;
|
|
2861
|
-
outputSlot.collapseCandidate.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
3059
|
+
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
3060
|
+
} else if (event.type === "response.function_call_arguments.done") {
|
|
3061
|
+
const toolCall = streamingToolCalls.resolve(event);
|
|
3062
|
+
if (toolCall) {
|
|
3063
|
+
const previousPartialJson = toolCall.block.partialJson;
|
|
3064
|
+
const doneArguments = typeof event.arguments === "string" ? event.arguments : void 0;
|
|
3065
|
+
if (doneArguments !== void 0 && (doneArguments.length > 0 || previousPartialJson === "")) {
|
|
3066
|
+
toolCall.block.partialJson = doneArguments;
|
|
3067
|
+
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
3068
|
+
toolCall.argumentStreamReliable = true;
|
|
3069
|
+
}
|
|
3070
|
+
if (doneArguments?.startsWith(previousPartialJson)) {
|
|
3071
|
+
const delta = doneArguments.slice(previousPartialJson.length);
|
|
3072
|
+
if (delta.length > 0) stream.push({
|
|
3073
|
+
type: "toolcall_delta",
|
|
3074
|
+
contentIndex: toolCall.contentIndex,
|
|
3075
|
+
delta,
|
|
3076
|
+
partial: output
|
|
3077
|
+
});
|
|
3078
|
+
}
|
|
3079
|
+
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
3080
|
+
} else if (event.type === "response.output_item.done") {
|
|
3081
|
+
const item = event.item;
|
|
3082
|
+
if (item.type !== "message") lastTextBlock = null;
|
|
3083
|
+
const existingOutputSlot = resolveOutputItemSlot(event, item);
|
|
3084
|
+
materializeDeferredTextSlots(existingOutputSlot);
|
|
3085
|
+
const outputSlot = existingOutputSlot ?? getOrCreateOutputSlot(event, item);
|
|
3086
|
+
compactionTracker.completed(item, blocks.length);
|
|
3087
|
+
if (item.type === "reasoning" && outputSlot?.type === "thinking") {
|
|
3088
|
+
const summaryText = item.summary?.map((s) => s.text).join("\n\n") || "";
|
|
3089
|
+
const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
|
|
3090
|
+
outputSlot.block.thinking = summaryText || contentText || outputSlot.block.thinking;
|
|
3091
|
+
outputSlot.block.thinkingSignature = JSON.stringify(item);
|
|
3092
|
+
if (item.encrypted_content && options?.reasoningReplayMetadata) outputSlot.block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
|
|
2862
3093
|
stream.push({
|
|
2863
|
-
type: "
|
|
2864
|
-
contentIndex: outputSlot.
|
|
2865
|
-
content:
|
|
3094
|
+
type: "thinking_end",
|
|
3095
|
+
contentIndex: outputSlot.contentIndex,
|
|
3096
|
+
content: outputSlot.block.thinking,
|
|
2866
3097
|
partial: output
|
|
2867
3098
|
});
|
|
2868
|
-
|
|
2869
|
-
} else {
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
3099
|
+
outputSlots.forget(outputSlot);
|
|
3100
|
+
} else if (item.type === "message" && outputSlot?.type === "text" && (outputSlot.block || outputSlot.pendingText !== null)) {
|
|
3101
|
+
const streamedText = outputSlot.pendingText ?? outputSlot.block?.text ?? "";
|
|
3102
|
+
const finalText = item.content == null ? streamedText : item.content.map((c) => c.type === "output_text" || c.type === "text" ? c.text : c.refusal).join("");
|
|
3103
|
+
const phase = item.phase ?? void 0;
|
|
3104
|
+
const collapse = outputSlot.pendingText !== null ? resolveResponsesMessageSnapshotCollapse({
|
|
3105
|
+
prior: outputSlot.collapseCandidate && {
|
|
3106
|
+
text: outputSlot.collapseCandidate.block.text,
|
|
3107
|
+
phase: outputSlot.collapseCandidate.phase
|
|
3108
|
+
},
|
|
3109
|
+
nextText: finalText,
|
|
3110
|
+
nextPhase: phase
|
|
3111
|
+
}) : { kind: "keep" };
|
|
3112
|
+
outputSlot.pendingText = null;
|
|
3113
|
+
if (collapse.kind === "extend" && outputSlot.collapseCandidate) {
|
|
3114
|
+
outputSlot.collapseCandidate.block.text = collapse.text;
|
|
3115
|
+
outputSlot.collapseCandidate.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
3116
|
+
stream.push({
|
|
3117
|
+
type: "text_end",
|
|
3118
|
+
contentIndex: outputSlot.collapseCandidate.index,
|
|
3119
|
+
content: collapse.text,
|
|
3120
|
+
partial: output
|
|
3121
|
+
});
|
|
3122
|
+
lastTextBlock = outputSlot.collapseCandidate;
|
|
3123
|
+
outputItemContentIndexes.set(item, outputSlot.collapseCandidate.index);
|
|
3124
|
+
} else {
|
|
3125
|
+
if (!outputSlot.block) {
|
|
3126
|
+
outputSlot.block = {
|
|
3127
|
+
type: "text",
|
|
3128
|
+
text: "",
|
|
3129
|
+
...phase ? { textSignature: encodeTextSignatureV1(item.id, phase) } : {}
|
|
3130
|
+
};
|
|
3131
|
+
blocks.push(outputSlot.block);
|
|
3132
|
+
outputSlot.contentIndex = blocks.length - 1;
|
|
3133
|
+
stream.push({
|
|
3134
|
+
type: "text_start",
|
|
3135
|
+
contentIndex: outputSlot.contentIndex,
|
|
3136
|
+
partial: output
|
|
3137
|
+
});
|
|
3138
|
+
}
|
|
3139
|
+
outputSlot.block.text = finalText;
|
|
3140
|
+
outputSlot.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
3141
|
+
const contentIndex = outputSlot.contentIndex;
|
|
3142
|
+
if (contentIndex === void 0) throw new Error("Responses stream finalized text without a content index");
|
|
3143
|
+
lastTextBlock = {
|
|
3144
|
+
block: outputSlot.block,
|
|
3145
|
+
index: contentIndex,
|
|
3146
|
+
phase
|
|
2875
3147
|
};
|
|
2876
|
-
|
|
2877
|
-
outputSlot.contentIndex = blockIndex();
|
|
3148
|
+
outputItemContentIndexes.set(item, contentIndex);
|
|
2878
3149
|
stream.push({
|
|
2879
|
-
type: "
|
|
2880
|
-
contentIndex
|
|
3150
|
+
type: "text_end",
|
|
3151
|
+
contentIndex,
|
|
3152
|
+
content: outputSlot.block.text,
|
|
2881
3153
|
partial: output
|
|
2882
3154
|
});
|
|
2883
3155
|
}
|
|
2884
|
-
outputSlot
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
content: outputSlot.block.text,
|
|
2897
|
-
partial: output
|
|
3156
|
+
outputSlots.forget(outputSlot);
|
|
3157
|
+
startedTextBlocksByItemId.delete(item.id);
|
|
3158
|
+
} else if (item.type === "function_call") {
|
|
3159
|
+
const streamingToolCall = streamingToolCalls.resolve(event, readResponsesToolCallItemIdentity(item));
|
|
3160
|
+
if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
|
|
3161
|
+
const streamedArguments = streamingToolCall?.block.partialJson ?? "";
|
|
3162
|
+
const completedArguments = typeof item.arguments === "string" ? item.arguments : void 0;
|
|
3163
|
+
if (streamingToolCall && !streamingToolCall.argumentStreamReliable && !completedArguments) continue;
|
|
3164
|
+
const finalArguments = completedArguments !== void 0 && (completedArguments.length > 0 || !streamedArguments) ? completedArguments : streamedArguments;
|
|
3165
|
+
const validated = resolveCompletedResponsesToolCall(item, {
|
|
3166
|
+
name: streamingToolCall?.block.name,
|
|
3167
|
+
arguments: finalArguments
|
|
2898
3168
|
});
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
3169
|
+
let toolCall;
|
|
3170
|
+
let contentIndex;
|
|
3171
|
+
if (streamingToolCall) {
|
|
3172
|
+
const block = streamingToolCall.block;
|
|
3173
|
+
block.id = resolveResponsesToolCallId(item, block.id);
|
|
3174
|
+
block.name = validated.name;
|
|
3175
|
+
block.arguments = validated.arguments;
|
|
3176
|
+
delete block.partialJson;
|
|
3177
|
+
toolCall = block;
|
|
3178
|
+
contentIndex = streamingToolCall.contentIndex;
|
|
3179
|
+
} else {
|
|
3180
|
+
toolCall = {
|
|
3181
|
+
type: "toolCall",
|
|
3182
|
+
id: resolveResponsesToolCallId(item),
|
|
3183
|
+
name: validated.name,
|
|
3184
|
+
arguments: validated.arguments
|
|
3185
|
+
};
|
|
3186
|
+
blocks.push(toolCall);
|
|
3187
|
+
contentIndex = blocks.length - 1;
|
|
3188
|
+
stream.push({
|
|
3189
|
+
type: "toolcall_start",
|
|
3190
|
+
contentIndex,
|
|
3191
|
+
partial: output
|
|
3192
|
+
});
|
|
3193
|
+
}
|
|
3194
|
+
if (streamingToolCall) {
|
|
3195
|
+
streamingToolCalls.forget(streamingToolCall);
|
|
3196
|
+
for (const slot of outputSlots.values()) if (slot.type === "toolCall" && slot.toolCall === streamingToolCall) outputSlots.forget(slot);
|
|
3197
|
+
}
|
|
2928
3198
|
stream.push({
|
|
2929
|
-
type: "
|
|
3199
|
+
type: "toolcall_end",
|
|
2930
3200
|
contentIndex,
|
|
3201
|
+
toolCall,
|
|
2931
3202
|
partial: output
|
|
2932
3203
|
});
|
|
3204
|
+
outputItemContentIndexes.set(item, contentIndex);
|
|
2933
3205
|
}
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
3206
|
+
} else if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
3207
|
+
if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
|
|
3208
|
+
finalizeResponse(event.response, event.type);
|
|
3209
|
+
if (event.type === "response.completed" || output.stopReason === "length") recoverTerminalOutput(event.response.output ?? [], event.type === "response.completed");
|
|
3210
|
+
terminalResponse = event.type === "response.completed" ? event.response : null;
|
|
3211
|
+
if (output.stopReason === "stop" && output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
|
|
3212
|
+
break;
|
|
3213
|
+
} else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
|
|
3214
|
+
else if (event.type === "response.failed") {
|
|
3215
|
+
const failure = normalizeResponsesFailedEvent(event, model);
|
|
3216
|
+
finalizeFailedResponse(event.response, failure.responseId);
|
|
3217
|
+
throw new ResponsesStreamFailure(failure, event.response);
|
|
2944
3218
|
}
|
|
2945
|
-
} else if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
2946
|
-
if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
|
|
2947
|
-
finalizeResponse(event.response, event.type);
|
|
2948
|
-
if (event.type === "response.completed" || output.stopReason === "length") recoverTerminalOutput(event.response.output ?? [], event.type === "response.completed");
|
|
2949
|
-
if (output.stopReason === "stop" && output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
|
|
2950
|
-
break;
|
|
2951
|
-
} else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
|
|
2952
|
-
else if (event.type === "response.failed") {
|
|
2953
|
-
const failure = normalizeResponsesFailedEvent(event, model);
|
|
2954
|
-
if (failure.responseId) output.responseId = failure.responseId;
|
|
2955
|
-
throw new ResponsesStreamFailure(failure, event.response);
|
|
2956
3219
|
}
|
|
3220
|
+
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
2957
3221
|
if (streamingToolCalls.hasActive()) throw new Error("Responses stream ended with unresolved tool calls");
|
|
2958
|
-
if (
|
|
3222
|
+
if (terminalResponse === void 0) throw new Error("OpenAI Responses stream ended before a terminal response event");
|
|
3223
|
+
return terminalResponse ?? void 0;
|
|
2959
3224
|
} finally {
|
|
2960
3225
|
for (const block of output.content) delete block.partialJson;
|
|
2961
3226
|
}
|
|
2962
3227
|
}
|
|
2963
3228
|
//#endregion
|
|
2964
|
-
|
|
3229
|
+
//#region packages/ai/src/providers/openai-responses-tools.ts
|
|
3230
|
+
const LOG_SUBSYSTEM = "llm/openai-responses";
|
|
3231
|
+
const MAX_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS = 64;
|
|
3232
|
+
const loggedStrictToolDowngradeDiagnosticKeys = /* @__PURE__ */ new Set();
|
|
3233
|
+
/** Converts and returns the projection used to reconcile tool choices. */
|
|
3234
|
+
function convertResponsesToolPayload(tools, options) {
|
|
3235
|
+
const projection = projectOpenAITools(tools);
|
|
3236
|
+
const strict = resolveResponsesStrictToolFlag(projection, resolveResponsesStrictToolSetting(options), options?.model);
|
|
3237
|
+
return {
|
|
3238
|
+
projection,
|
|
3239
|
+
tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
|
|
3240
|
+
const result = {
|
|
3241
|
+
type: "function",
|
|
3242
|
+
name: tool.name,
|
|
3243
|
+
description: tool.description,
|
|
3244
|
+
parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, options?.model?.compat)
|
|
3245
|
+
};
|
|
3246
|
+
if (strict !== void 0) result.strict = strict;
|
|
3247
|
+
return result;
|
|
3248
|
+
})
|
|
3249
|
+
};
|
|
3250
|
+
}
|
|
3251
|
+
function resolveResponsesStrictToolSetting(options) {
|
|
3252
|
+
if (options?.strict !== void 0) return options.strict;
|
|
3253
|
+
if (options?.model) return getAiTransportHost().resolveOpenAIStrictToolSetting(options.model, {
|
|
3254
|
+
transport: "stream",
|
|
3255
|
+
supportsStrictMode: options.supportsStrictMode
|
|
3256
|
+
});
|
|
3257
|
+
return false;
|
|
3258
|
+
}
|
|
3259
|
+
function resolveResponsesStrictToolFlag(projection, strictSetting, model) {
|
|
3260
|
+
const strict = resolveOpenAIProjectedToolsStrictToolFlag(projection, strictSetting);
|
|
3261
|
+
if (strictSetting === true && strict === false && model) getAiTransportHost().logDebug(LOG_SUBSYSTEM, () => {
|
|
3262
|
+
const diagnostics = findOpenAIStrictToolProjectionDiagnostics(projection);
|
|
3263
|
+
if (!shouldLogStrictToolDowngradeDiagnostic(diagnostics, model)) return null;
|
|
3264
|
+
const sample = diagnostics.slice(0, 5).map((entry) => ({
|
|
3265
|
+
tool: entry.toolName ?? `tool[${entry.toolIndex}]`,
|
|
3266
|
+
violations: entry.violations.slice(0, 8)
|
|
3267
|
+
}));
|
|
3268
|
+
return {
|
|
3269
|
+
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`,
|
|
3270
|
+
data: {
|
|
3271
|
+
provider: model.provider,
|
|
3272
|
+
model: model.id,
|
|
3273
|
+
incompatibleToolCount: diagnostics.length,
|
|
3274
|
+
sample
|
|
3275
|
+
}
|
|
3276
|
+
};
|
|
3277
|
+
});
|
|
3278
|
+
return strict;
|
|
3279
|
+
}
|
|
3280
|
+
function shouldLogStrictToolDowngradeDiagnostic(diagnostics, model) {
|
|
3281
|
+
const key = createHash("sha256").update(JSON.stringify({
|
|
3282
|
+
provider: model.provider,
|
|
3283
|
+
model: model.id,
|
|
3284
|
+
diagnostics: diagnostics.map((entry) => ({
|
|
3285
|
+
toolIndex: entry.toolIndex,
|
|
3286
|
+
toolName: entry.toolName ?? null,
|
|
3287
|
+
violations: entry.violations
|
|
3288
|
+
}))
|
|
3289
|
+
})).digest("hex");
|
|
3290
|
+
if (loggedStrictToolDowngradeDiagnosticKeys.has(key)) return false;
|
|
3291
|
+
if (loggedStrictToolDowngradeDiagnosticKeys.size >= MAX_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS) loggedStrictToolDowngradeDiagnosticKeys.clear();
|
|
3292
|
+
loggedStrictToolDowngradeDiagnosticKeys.add(key);
|
|
3293
|
+
return true;
|
|
3294
|
+
}
|
|
3295
|
+
//#endregion
|
|
3296
|
+
//#region packages/ai/src/providers/openai-responses-shared.ts
|
|
3297
|
+
function isResponsesReasoningEffort(effort) {
|
|
3298
|
+
return effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max";
|
|
3299
|
+
}
|
|
3300
|
+
function convertResponsesMessages(model, context, allowedToolCallProviders, options) {
|
|
3301
|
+
return convertProviderResponsesMessages(model, context, allowedToolCallProviders, options);
|
|
3302
|
+
}
|
|
3303
|
+
const createResponsesAssistantOutput = createOpenAIResponsesAssistantOutput;
|
|
3304
|
+
function applyResponsesServiceTierPricing(usage, serviceTier, model) {
|
|
3305
|
+
let multiplier = 1;
|
|
3306
|
+
if (serviceTier === "flex") multiplier = .5;
|
|
3307
|
+
else if (serviceTier === "priority") multiplier = model.id === "gpt-5.5" ? 2.5 : 2;
|
|
3308
|
+
if (multiplier === 1) return;
|
|
3309
|
+
usage.cost.input *= multiplier;
|
|
3310
|
+
usage.cost.output *= multiplier;
|
|
3311
|
+
usage.cost.cacheRead *= multiplier;
|
|
3312
|
+
usage.cost.cacheWrite *= multiplier;
|
|
3313
|
+
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
3314
|
+
}
|
|
3315
|
+
function resolveResponsesReasoningEffort(model, reasoning) {
|
|
3316
|
+
const clampedReasoning = reasoning ? clampThinkingLevel(model, reasoning) : void 0;
|
|
3317
|
+
if (!clampedReasoning || clampedReasoning === "off") return;
|
|
3318
|
+
if (clampedReasoning === "max") return supportsOpenAIReasoningEffort(model, "max") ? "max" : "xhigh";
|
|
3319
|
+
if (clampedReasoning === "minimal" && model.provider === "openai" && supportsOpenAIReasoningEffort(model, "max")) {
|
|
3320
|
+
const effort = resolveOpenAIReasoningEffortForModel({
|
|
3321
|
+
model,
|
|
3322
|
+
effort: "minimal"
|
|
3323
|
+
});
|
|
3324
|
+
return isResponsesReasoningEffort(effort) ? effort : void 0;
|
|
3325
|
+
}
|
|
3326
|
+
return clampedReasoning;
|
|
3327
|
+
}
|
|
3328
|
+
function applyCommonResponsesParams(params, model, context, options, config) {
|
|
3329
|
+
if (options?.maxTokens) params.max_output_tokens = Math.max(options.maxTokens, 16);
|
|
3330
|
+
if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
|
|
3331
|
+
if (context.tools) {
|
|
3332
|
+
const converted = convertResponsesToolPayload(context.tools, { model });
|
|
3333
|
+
if (converted.tools.length > 0) params.tools = converted.tools;
|
|
3334
|
+
}
|
|
3335
|
+
if (!model.reasoning) return;
|
|
3336
|
+
if (options?.reasoningEffort || options?.reasoningSummary) {
|
|
3337
|
+
params.reasoning = {
|
|
3338
|
+
effort: options?.reasoningEffort ? model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort : "medium",
|
|
3339
|
+
summary: options?.reasoningSummary || "auto"
|
|
3340
|
+
};
|
|
3341
|
+
params.include = ["reasoning.encrypted_content"];
|
|
3342
|
+
} else if ((config?.setDefaultReasoningOff ?? true) && model.thinkingLevelMap?.off !== null) params.reasoning = { effort: model.thinkingLevelMap?.off ?? "none" };
|
|
3343
|
+
}
|
|
3344
|
+
function buildResponsesRequestOptions(options) {
|
|
3345
|
+
return {
|
|
3346
|
+
...options?.signal ? { signal: options.signal } : {},
|
|
3347
|
+
...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},
|
|
3348
|
+
maxRetries: options?.maxRetries ?? 0
|
|
3349
|
+
};
|
|
3350
|
+
}
|
|
3351
|
+
function cleanStreamingScratchBuffers(output) {
|
|
3352
|
+
for (const block of output.content) {
|
|
3353
|
+
delete block.index;
|
|
3354
|
+
delete block.partialJson;
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
async function runResponsesStreamLifecycle(params) {
|
|
3358
|
+
const { stream, output, options } = params;
|
|
3359
|
+
let firstEventAbort;
|
|
3360
|
+
try {
|
|
3361
|
+
const model = params.resolveRequestModel?.(params.model) ?? params.model;
|
|
3362
|
+
const client = params.createClient(model);
|
|
3363
|
+
const buildRequest = async (replayMode) => {
|
|
3364
|
+
let request = params.buildParams(model, replayMode);
|
|
3365
|
+
const nextRequest = await options?.onPayload?.(request, model);
|
|
3366
|
+
if (nextRequest !== void 0) request = nextRequest;
|
|
3367
|
+
return request;
|
|
3368
|
+
};
|
|
3369
|
+
const requestParams = await buildRequest("checkpoint");
|
|
3370
|
+
firstEventAbort = createFirstStreamEventAbortController(options?.signal);
|
|
3371
|
+
const { stream: openaiStream, response } = await createResponsesStreamWithEncryptedContentRetry({
|
|
3372
|
+
client,
|
|
3373
|
+
request: requestParams,
|
|
3374
|
+
requestOptions: {
|
|
3375
|
+
...buildResponsesRequestOptions(options),
|
|
3376
|
+
signal: firstEventAbort.signal
|
|
3377
|
+
},
|
|
3378
|
+
model,
|
|
3379
|
+
buildFullHistoryRequest: () => buildRequest("full-history"),
|
|
3380
|
+
onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint)
|
|
3381
|
+
});
|
|
3382
|
+
const hookedOpenAIStream = withProviderResponseHook({
|
|
3383
|
+
stream: openaiStream,
|
|
3384
|
+
signal: firstEventAbort.signal,
|
|
3385
|
+
abort: firstEventAbort.abort,
|
|
3386
|
+
hook: createOpenAIResponseHook(options?.onResponse, response, model),
|
|
3387
|
+
onReady: () => stream.push({
|
|
3388
|
+
type: "start",
|
|
3389
|
+
partial: output
|
|
3390
|
+
})
|
|
3391
|
+
});
|
|
3392
|
+
const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
|
|
3393
|
+
const onFirstEventTimeout = getFirstStreamEventTimeoutHandler(options);
|
|
3394
|
+
await processResponsesStream(hookedOpenAIStream, output, stream, model, {
|
|
3395
|
+
...params.processStreamOptions || firstEventTimeoutMs !== void 0 || onFirstEventTimeout !== void 0 ? {
|
|
3396
|
+
...params.processStreamOptions,
|
|
3397
|
+
firstEventTimeoutMs: params.processStreamOptions?.firstEventTimeoutMs ?? firstEventTimeoutMs,
|
|
3398
|
+
abortFirstEventStream: params.processStreamOptions?.abortFirstEventStream ?? firstEventAbort.abort,
|
|
3399
|
+
onFirstEventTimeout: params.processStreamOptions?.onFirstEventTimeout ?? onFirstEventTimeout,
|
|
3400
|
+
signal: params.processStreamOptions?.signal ?? options?.signal
|
|
3401
|
+
} : void 0,
|
|
3402
|
+
reasoningReplayMetadata: buildOpenAIResponsesReasoningReplayMetadata(model, {
|
|
3403
|
+
sessionId: options?.sessionId,
|
|
3404
|
+
authProfileId: options?.authProfileId
|
|
3405
|
+
})
|
|
3406
|
+
});
|
|
3407
|
+
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
3408
|
+
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
3409
|
+
stream.push({
|
|
3410
|
+
type: "done",
|
|
3411
|
+
reason: output.stopReason,
|
|
3412
|
+
message: output
|
|
3413
|
+
});
|
|
3414
|
+
stream.end();
|
|
3415
|
+
} catch (error) {
|
|
3416
|
+
cleanStreamingScratchBuffers(output);
|
|
3417
|
+
const terminal = projectProviderError(error, options?.signal);
|
|
3418
|
+
Object.assign(output, terminal);
|
|
3419
|
+
stream.push({
|
|
3420
|
+
type: "error",
|
|
3421
|
+
reason: terminal.stopReason,
|
|
3422
|
+
error: output
|
|
3423
|
+
});
|
|
3424
|
+
stream.end();
|
|
3425
|
+
} finally {
|
|
3426
|
+
firstEventAbort?.dispose();
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
//#endregion
|
|
3430
|
+
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, quoteUnsafeIntegerLiterals as ht, 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, parseJsonPreservingUnsafeIntegers as mt, applyResponsesServiceTierPricing as n, resolveUnsupportedToolSchemaKeywords as nt, runResponsesStreamLifecycle as o, cleanSchemaForLlamacppGbnf as ot, ResponsesStreamFailure as p, parseJsonObjectPreservingUnsafeIntegers as pt, 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 };
|