@openclaw/ai 2026.8.1-beta.2 → 2026.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{anthropic-B6dLpq5L.mjs → anthropic-Djj7L1rx.mjs} +49 -39
- package/dist/{anthropic-compaction-replay-8lJNKXOE.mjs → anthropic-compaction-replay-CY4tkD4V.mjs} +42 -44
- package/dist/{anthropic-payload-policy-CiEuQS72.d.mts → anthropic-payload-policy-i_5_inWe.d.mts} +4 -2
- package/dist/{api-registry-k3zTz0cV.d.mts → api-registry-C9-wZd_W.d.mts} +2 -1
- package/dist/{azure-openai-responses-mxIOtUnn.mjs → azure-openai-responses-Bj3czHNa.mjs} +4 -4
- package/dist/{number-coercion-H9qHik3g.mjs → base64-CEFBpSkN.mjs} +73 -1
- package/dist/diagnostics.d.mts +2 -3
- package/dist/diagnostics.mjs +1 -1
- package/dist/{env-api-keys-DrgeBuva.mjs → env-api-keys-bktO00EJ.mjs} +2 -15
- package/dist/event-stream-C988TSLe.d.mts +1 -0
- package/dist/{event-stream-BP6AWT8j.d.mts → event-stream-UhnxHuqt.d.mts} +1 -2
- package/dist/event-stream.d.mts +2 -1
- package/dist/{google-C7h2QzDX.mjs → google-0Ca6TYbw.mjs} +4 -4
- package/dist/{google-shared-B0Qr9OR7.mjs → google-shared-DVfL9COU.mjs} +22 -8
- package/dist/{google-vertex-Bhc3TjDl.mjs → google-vertex-5dAMxprN.mjs} +4 -4
- package/dist/{host-DTqNc7ad.mjs → host-D51fmkH6.mjs} +40 -33
- package/dist/{host-vWgMMhiJ.d.mts → host-DoPJJ1KD.d.mts} +7 -7
- package/dist/index-N3zr6__t.d.mts +105 -0
- package/dist/index.d.mts +9 -10
- package/dist/index.mjs +2 -3
- package/dist/internal/anthropic.d.mts +57 -49
- package/dist/internal/anthropic.mjs +5 -5
- package/dist/internal/openai-responses-payload-policy.d.mts +3 -3
- package/dist/internal/openai-responses-payload-policy.mjs +2 -3
- package/dist/internal/openai.d.mts +65 -63
- package/dist/internal/openai.mjs +10 -8
- package/dist/internal/retry-after.d.mts +2 -3
- package/dist/internal/runtime.d.mts +53 -40
- package/dist/internal/runtime.mjs +10 -9
- package/dist/internal/shared.d.mts +37 -23
- package/dist/internal/shared.mjs +4 -4
- package/dist/{json-parse-CDnesDM_.mjs → json-parse-BuAJEbdW.mjs} +18 -2
- package/dist/{headers-DdOQtGuU.mjs → llm-request-activity-BjtkplhG.mjs} +1 -9
- package/dist/{mistral-CEWoQI_g.mjs → mistral-BCnrI-kV.mjs} +64 -53
- package/dist/{openai-chatgpt-responses-CrPmqERt.mjs → openai-chatgpt-responses-CGBGWSqr.mjs} +45 -20
- package/dist/{openai-completions-BPnt4Sml.mjs → openai-completions-BaTuwID7.mjs} +63 -258
- package/dist/{openai-completions-compat-Dt3dcawL.d.mts → openai-completions-compat-DB7FFq7k.d.mts} +3 -3
- package/dist/openai-completions-stream-Bpns6uNc.mjs +1622 -0
- package/dist/{openai-responses-DhIKtOup.mjs → openai-responses-1GBcQujk.mjs} +8 -6
- package/dist/openai-responses-compaction-window-DwydGZI8.mjs +686 -0
- package/dist/{openai-responses-contracts-XpZJxrRG.d.mts → openai-responses-contracts-DgaR3t5T.d.mts} +14 -5
- package/dist/{openai-responses-payload-policy-BSs371VM.d.mts → openai-responses-payload-policy-rLRPsSmB.d.mts} +2 -0
- package/dist/{openai-responses-prompt-observer-internal-DgNTYnRY.mjs → openai-responses-prompt-observer-internal-_nhGTn2b.mjs} +3 -3
- package/dist/{openai-responses-shared-DXIt3iY5.mjs → openai-responses-shared-zPmKnhF5.mjs} +345 -1553
- package/dist/openai-stop-reason-Drnn_6Qj.mjs +28 -0
- package/dist/openai-tool-schema-Dgl4H2MU.mjs +1695 -0
- package/dist/{provider-error-BUwEnjXq.mjs → provider-error-jZP5NMTZ.mjs} +3 -82
- package/dist/{provider-options-B96RdNpH.d.mts → provider-options-HvA_slFa.d.mts} +23 -4
- package/dist/provider-transcript-transform-C01bQ5a3.mjs +32 -0
- package/dist/provider-types.d.mts +18 -17
- package/dist/providers.d.mts +5 -6
- package/dist/providers.mjs +9 -9
- package/dist/{reasoning-tag-text-partitioner-rnPwX2pg.mjs → reasoning-tag-text-partitioner-CwzKb0bA.mjs} +4 -1
- package/dist/rolldown-runtime-BhDjJH2R.mjs +15 -0
- package/dist/{sanitize-unicode-BYqrYtC_.mjs → sanitize-unicode-DCkltN94.mjs} +1 -2
- package/dist/{simple-options-D58D5Kvw.mjs → simple-options-DKx86yX9.mjs} +42 -4
- package/dist/{anthropic-JsNA5KCu.mjs → src-Bu3FiFAG.mjs} +1 -1
- package/dist/{stream-first-event-timeout-MK28puvq.mjs → stream-first-event-timeout-DcNjoFQE.mjs} +1 -1
- package/dist/{streaming-byte-guard-BrbkbwUu.mjs → streaming-byte-guard-CC-HMn_u.mjs} +5 -6
- package/dist/string-normalization--fwJ4S2q.mjs +16 -0
- package/dist/{tool-schema-json-projection-q5d7QX5c.mjs → tool-schema-json-projection-qvTEs5Am.mjs} +17 -8
- package/dist/transport-stream-shared-CT5ycdzn.mjs +342 -0
- package/dist/transport-stream-shared-NjwWNaRY.d.mts +138 -0
- package/dist/{transport-utils-DJqkxbhC.mjs → transport-utils-BHx9z8Cl.mjs} +9 -9
- package/dist/transports.d.mts +140 -169
- package/dist/transports.mjs +269 -1262
- package/dist/types-DtGu2d3C.d.mts +1 -0
- package/dist/{types-BHNrPS1l.d.mts → types-h38Azne1.d.mts} +53 -17
- package/dist/types.d.mts +6 -5
- package/dist/types.mjs +1 -2
- package/dist/utf16-slice-qz3nsy87.mjs +84 -0
- package/dist/{validation-DT9SrFn3.d.mts → validation-C68lP2uy.d.mts} +1 -2
- package/dist/validation.d.mts +1 -1
- package/package.json +6 -6
- package/dist/anthropic-SrGtwsJu.d.mts +0 -100
- package/dist/index-BVVgDSdq.d.mts +0 -1
- package/dist/openai-responses-contracts-CyfIkQi5.mjs +0 -253
- package/dist/openai-responses-payload-policy-BDxV-W0c.mjs +0 -206
- package/dist/openai-stop-reason-BkFkqqK0.mjs +0 -563
- package/dist/openai-tool-projection-CY04OcvQ.mjs +0 -338
- package/dist/provider-transcript-transform-ePx-Bbfr.mjs +0 -155
- package/dist/record-coerce-DdXsgUd_.mjs +0 -23
- package/dist/src-D2H6yKkH.mjs +0 -2
- package/dist/stream-first-event-timeout-DvDeSucC.d.mts +0 -29
- package/dist/string-coerce-fsri9iCu.mjs +0 -34
- package/dist/types-BVVgDSdq.d.mts +0 -1
- package/dist/utf16-slice-CvGodqok.mjs +0 -29
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
import "./src-Bu3FiFAG.mjs";
|
|
2
|
+
import { n as PROVIDER_POST_DISPATCH_AMBIGUITY_ERROR_CODE } from "./types-BDdaOVi2.mjs";
|
|
3
|
+
import { c as normalizeLowercaseStringOrEmpty, o as isRecord, p as readStringValue, u as normalizeOptionalLowercaseString } from "./utf16-slice-qz3nsy87.mjs";
|
|
4
|
+
import { t as canonicalizeBase64 } from "./base64-CEFBpSkN.mjs";
|
|
5
|
+
import { n as uniqueStrings, t as normalizeStringEntries } from "./string-normalization--fwJ4S2q.mjs";
|
|
6
|
+
import { s as parsePositiveInteger } from "./transport-utils-BHx9z8Cl.mjs";
|
|
7
|
+
import { t as createSseByteGuard } from "./streaming-byte-guard-CC-HMn_u.mjs";
|
|
8
|
+
//#region packages/ai/src/providers/openai-reasoning-effort.ts
|
|
9
|
+
/**
|
|
10
|
+
* OpenAI-compatible reasoning-effort normalization. Different GPT families
|
|
11
|
+
* expose different accepted effort enums, so callers map requested values here
|
|
12
|
+
* before constructing provider payloads.
|
|
13
|
+
*/
|
|
14
|
+
const GPT_5_REASONING_EFFORTS = [
|
|
15
|
+
"minimal",
|
|
16
|
+
"low",
|
|
17
|
+
"medium",
|
|
18
|
+
"high"
|
|
19
|
+
];
|
|
20
|
+
const GPT_51_REASONING_EFFORTS = [
|
|
21
|
+
"none",
|
|
22
|
+
"low",
|
|
23
|
+
"medium",
|
|
24
|
+
"high"
|
|
25
|
+
];
|
|
26
|
+
const GPT_52_REASONING_EFFORTS = [
|
|
27
|
+
"none",
|
|
28
|
+
"low",
|
|
29
|
+
"medium",
|
|
30
|
+
"high",
|
|
31
|
+
"xhigh"
|
|
32
|
+
];
|
|
33
|
+
const GPT_56_REASONING_EFFORTS = [
|
|
34
|
+
"none",
|
|
35
|
+
"low",
|
|
36
|
+
"medium",
|
|
37
|
+
"high",
|
|
38
|
+
"xhigh",
|
|
39
|
+
"max"
|
|
40
|
+
];
|
|
41
|
+
const GPT_CODEX_REASONING_EFFORTS = [
|
|
42
|
+
"low",
|
|
43
|
+
"medium",
|
|
44
|
+
"high",
|
|
45
|
+
"xhigh"
|
|
46
|
+
];
|
|
47
|
+
const GPT_PRO_REASONING_EFFORTS = [
|
|
48
|
+
"medium",
|
|
49
|
+
"high",
|
|
50
|
+
"xhigh"
|
|
51
|
+
];
|
|
52
|
+
const GPT_5_PRO_REASONING_EFFORTS = ["high"];
|
|
53
|
+
const GPT_51_CODEX_MAX_REASONING_EFFORTS = [
|
|
54
|
+
"none",
|
|
55
|
+
"medium",
|
|
56
|
+
"high",
|
|
57
|
+
"xhigh"
|
|
58
|
+
];
|
|
59
|
+
const GPT_51_CODEX_MINI_REASONING_EFFORTS = ["medium"];
|
|
60
|
+
const GENERIC_REASONING_EFFORTS = [
|
|
61
|
+
"low",
|
|
62
|
+
"medium",
|
|
63
|
+
"high"
|
|
64
|
+
];
|
|
65
|
+
const CANONICAL_REASONING_EFFORTS = /* @__PURE__ */ new Set([
|
|
66
|
+
"none",
|
|
67
|
+
"minimal",
|
|
68
|
+
"low",
|
|
69
|
+
"medium",
|
|
70
|
+
"high",
|
|
71
|
+
"xhigh",
|
|
72
|
+
"max",
|
|
73
|
+
"off"
|
|
74
|
+
]);
|
|
75
|
+
function normalizeModelId(id) {
|
|
76
|
+
return normalizeLowercaseStringOrEmpty(id ?? "").replace(/-\d{4}-\d{2}-\d{2}$/u, "");
|
|
77
|
+
}
|
|
78
|
+
/** Return whether a model is the GPT-5.4 mini family. */
|
|
79
|
+
function isOpenAIGpt54MiniModel(model) {
|
|
80
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
81
|
+
return /^gpt-5\.4-mini(?:-|$)/u.test(id);
|
|
82
|
+
}
|
|
83
|
+
/** Return whether a model is the GPT-5.5 family. */
|
|
84
|
+
function isOpenAIGpt55Model(model) {
|
|
85
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
86
|
+
const name = normalizeModelId(typeof model.name === "string" ? model.name : void 0);
|
|
87
|
+
return /^gpt-5\.5(?:-|$)/u.test(id) || /^gpt-5\.5(?:\s|\(|-|$)/u.test(name);
|
|
88
|
+
}
|
|
89
|
+
/** Return whether a model is the GPT-5.6 family. */
|
|
90
|
+
function isOpenAIGpt56Model(model) {
|
|
91
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
92
|
+
const name = normalizeModelId(typeof model.name === "string" ? model.name : void 0);
|
|
93
|
+
return /^gpt-5\.6(?:-|$)/u.test(id) || /^gpt-5\.6(?:\s|\(|-|$)/u.test(name);
|
|
94
|
+
}
|
|
95
|
+
/** Normalize user-facing reasoning effort names to API effort names. */
|
|
96
|
+
function normalizeOpenAIReasoningEffort(effort) {
|
|
97
|
+
const trimmed = effort.trim();
|
|
98
|
+
const folded = trimmed.toLowerCase();
|
|
99
|
+
return CANONICAL_REASONING_EFFORTS.has(folded) ? folded : trimmed;
|
|
100
|
+
}
|
|
101
|
+
function readCompatReasoningEfforts(compat) {
|
|
102
|
+
if (!compat || typeof compat !== "object") return;
|
|
103
|
+
if (compat.supportsReasoningEffort === false) return [];
|
|
104
|
+
const raw = compat.supportedReasoningEfforts;
|
|
105
|
+
if (!Array.isArray(raw)) return;
|
|
106
|
+
const supported = uniqueStrings(normalizeStringEntries(raw.filter((value) => typeof value === "string")));
|
|
107
|
+
return supported.length > 0 ? supported : void 0;
|
|
108
|
+
}
|
|
109
|
+
function isDisabledReasoningEffort(effort) {
|
|
110
|
+
return effort === "none" || effort === "off";
|
|
111
|
+
}
|
|
112
|
+
/** Resolve the reasoning efforts accepted by a specific OpenAI-compatible model. */
|
|
113
|
+
function resolveOpenAISupportedReasoningEfforts(model) {
|
|
114
|
+
const compatEfforts = readCompatReasoningEfforts(model.compat);
|
|
115
|
+
if (compatEfforts) return compatEfforts;
|
|
116
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
117
|
+
if (/^gpt-5\.6(?:-|$)/u.test(id)) return GPT_56_REASONING_EFFORTS;
|
|
118
|
+
if (id === "gpt-5.1-codex-mini") return GPT_51_CODEX_MINI_REASONING_EFFORTS;
|
|
119
|
+
if (id === "gpt-5.1-codex-max") return GPT_51_CODEX_MAX_REASONING_EFFORTS;
|
|
120
|
+
if (/^gpt-5(?:\.\d+)?-codex(?:-|$)/u.test(id)) return GPT_CODEX_REASONING_EFFORTS;
|
|
121
|
+
if (id === "gpt-5-pro") return GPT_5_PRO_REASONING_EFFORTS;
|
|
122
|
+
if (/^gpt-5\.[2-9](?:\.\d+)?-pro(?:-|$)/u.test(id)) return GPT_PRO_REASONING_EFFORTS;
|
|
123
|
+
if (/^gpt-5\.[2-9](?:\.\d+)?(?:-|$)/u.test(id)) return GPT_52_REASONING_EFFORTS;
|
|
124
|
+
if (/^gpt-5\.1(?:-|$)/u.test(id)) return GPT_51_REASONING_EFFORTS;
|
|
125
|
+
if (/^gpt-5(?:-|$)/u.test(id)) return GPT_5_REASONING_EFFORTS;
|
|
126
|
+
return GENERIC_REASONING_EFFORTS;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Return whether a model accepts the temperature parameter. The GPT-5.6
|
|
130
|
+
* family rejects it with a 400; catalog compat can override per model.
|
|
131
|
+
*/
|
|
132
|
+
function supportsOpenAITemperature(model) {
|
|
133
|
+
const compat = model.compat;
|
|
134
|
+
if (compat && typeof compat === "object") {
|
|
135
|
+
const declared = compat.supportsTemperature;
|
|
136
|
+
if (typeof declared === "boolean") return declared;
|
|
137
|
+
}
|
|
138
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
139
|
+
return !/^gpt-5\.6(?:-|$)/u.test(id);
|
|
140
|
+
}
|
|
141
|
+
/** Return whether a model accepts a requested reasoning effort. */
|
|
142
|
+
function supportsOpenAIReasoningEffort(model, effort) {
|
|
143
|
+
return resolveOpenAISupportedReasoningEfforts(model).includes(normalizeOpenAIReasoningEffort(effort));
|
|
144
|
+
}
|
|
145
|
+
/** Resolve a requested reasoning effort to the closest value supported by the model. */
|
|
146
|
+
function resolveOpenAIReasoningEffortForModel(params) {
|
|
147
|
+
const requested = normalizeOpenAIReasoningEffort(params.effort);
|
|
148
|
+
const mapped = params.fallbackMap?.[requested] ?? (params.fallbackMap && CANONICAL_REASONING_EFFORTS.has(requested) ? Object.entries(params.fallbackMap).find(([effort]) => normalizeOpenAIReasoningEffort(effort) === requested)?.[1] : void 0);
|
|
149
|
+
const normalized = mapped === void 0 ? requested : mapped.trim();
|
|
150
|
+
const supported = resolveOpenAISupportedReasoningEfforts(params.model);
|
|
151
|
+
if (supported.includes(normalized)) return normalized;
|
|
152
|
+
if (requested === "off" && supported.includes("none")) return "none";
|
|
153
|
+
if (isDisabledReasoningEffort(requested) || isDisabledReasoningEffort(normalized)) return;
|
|
154
|
+
if (requested === "minimal" && supported.includes("low")) return "low";
|
|
155
|
+
if ((requested === "minimal" || requested === "low") && supported.includes("medium")) return "medium";
|
|
156
|
+
if (requested === "xhigh" && supported.includes("high")) return "high";
|
|
157
|
+
if (requested === "max" && supported.includes("xhigh")) return "xhigh";
|
|
158
|
+
return supported.find((effort) => !isDisabledReasoningEffort(normalizeOpenAIReasoningEffort(effort)));
|
|
159
|
+
}
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region packages/model-catalog-core/src/provider-id.ts
|
|
162
|
+
function normalizeProviderId(provider) {
|
|
163
|
+
return normalizeLowercaseStringOrEmpty(provider);
|
|
164
|
+
}
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region packages/ai/src/transports/openai-responses-contracts.ts
|
|
167
|
+
const DEFAULT_AZURE_OPENAI_API_VERSION = "preview";
|
|
168
|
+
const OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS = "Follow the user request.";
|
|
169
|
+
const AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS = 3e4;
|
|
170
|
+
const RESPONSE_FAILED_NO_DETAILS_MESSAGE = "Unknown error (no error details in response)";
|
|
171
|
+
const OPENAI_RESPONSES_REASONING_REPLAY_META_KEY = "__openclaw_replay";
|
|
172
|
+
const OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY = "openclawReasoningReplay";
|
|
173
|
+
const OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE = "openai-responses-compaction";
|
|
174
|
+
const OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE = "openai-responses-retained-compaction";
|
|
175
|
+
const OPENAI_RESPONSES_APIS = /* @__PURE__ */ new Set([
|
|
176
|
+
"openai-responses",
|
|
177
|
+
"azure-openai-responses",
|
|
178
|
+
"openai-chatgpt-responses",
|
|
179
|
+
"openclaw-openai-responses-transport",
|
|
180
|
+
"openclaw-openai-chatgpt-responses-transport",
|
|
181
|
+
"openclaw-azure-openai-responses-transport"
|
|
182
|
+
]);
|
|
183
|
+
var OpenAIResponsesWebSocketPreDispatchError = class extends Error {
|
|
184
|
+
constructor(cause) {
|
|
185
|
+
super("OpenAI Responses WebSocket failed before request dispatch", { cause });
|
|
186
|
+
this.name = "OpenAIResponsesWebSocketPreDispatchError";
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
var OpenAIResponsesWebSocketPostDispatchError = class extends Error {
|
|
190
|
+
constructor(cause) {
|
|
191
|
+
super("OpenAI Responses WebSocket failed after request dispatch; outcome is unknown", { cause });
|
|
192
|
+
this.code = PROVIDER_POST_DISPATCH_AMBIGUITY_ERROR_CODE;
|
|
193
|
+
this.name = "OpenAIResponsesWebSocketPostDispatchError";
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var OpenAIResponsesWebSocketServerError = class extends Error {
|
|
197
|
+
constructor(code, status, param, message, cause) {
|
|
198
|
+
super(message, { cause });
|
|
199
|
+
this.code = code;
|
|
200
|
+
this.status = status;
|
|
201
|
+
this.param = param;
|
|
202
|
+
this.name = "OpenAIResponsesWebSocketServerError";
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
var OpenAIResponsesWebSocketSafeRetryError = class extends OpenAIResponsesWebSocketServerError {};
|
|
206
|
+
function readWebSocketServerError(value) {
|
|
207
|
+
if (!isRecord(value) || value.type !== "error") return;
|
|
208
|
+
const details = isRecord(value.error) ? value.error : value;
|
|
209
|
+
if (typeof details.code !== "string" || typeof details.message !== "string") return;
|
|
210
|
+
const rawStatus = value.status ?? value.status_code;
|
|
211
|
+
return {
|
|
212
|
+
code: details.code,
|
|
213
|
+
message: details.message,
|
|
214
|
+
param: typeof details.param === "string" ? details.param : null,
|
|
215
|
+
status: typeof rawStatus === "number" ? rawStatus : void 0
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function parseOpenAIResponsesWebSocketServerError(cause) {
|
|
219
|
+
if (!isRecord(cause)) return;
|
|
220
|
+
let details = readWebSocketServerError(cause.error) ?? readWebSocketServerError(cause);
|
|
221
|
+
if (!details && typeof cause.message === "string") try {
|
|
222
|
+
details = readWebSocketServerError(JSON.parse(cause.message));
|
|
223
|
+
} catch {}
|
|
224
|
+
if (!details) return;
|
|
225
|
+
return new (details.code === "previous_response_not_found" || details.code === "websocket_connection_limit_reached" || details.code === "invalid_encrypted_content" || details.code === "thinking_signature_invalid" ? OpenAIResponsesWebSocketSafeRetryError : OpenAIResponsesWebSocketServerError)(details.code, details.status, details.param, details.message, cause);
|
|
226
|
+
}
|
|
227
|
+
const PROMPT_OBSERVER = Symbol("openaiResponsesPromptObserver");
|
|
228
|
+
const responsesPromptObserver = {
|
|
229
|
+
set(options, observer) {
|
|
230
|
+
Reflect.set(options, PROMPT_OBSERVER, observer);
|
|
231
|
+
},
|
|
232
|
+
get(options) {
|
|
233
|
+
return Reflect.get(options, PROMPT_OBSERVER);
|
|
234
|
+
},
|
|
235
|
+
copy(source, target) {
|
|
236
|
+
const observer = source && responsesPromptObserver.get(source);
|
|
237
|
+
if (observer) responsesPromptObserver.set(target, observer);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region packages/ai/src/transports/openai-responses-payload-policy.ts
|
|
242
|
+
/**
|
|
243
|
+
* OpenAI Responses payload policy.
|
|
244
|
+
* Classifies endpoint capabilities and applies store, prompt-cache,
|
|
245
|
+
* server-compaction, service-tier, and reasoning payload rules.
|
|
246
|
+
*/
|
|
247
|
+
const OPENAI_RESPONSES_PROVIDERS = /* @__PURE__ */ new Set([
|
|
248
|
+
"openai",
|
|
249
|
+
"azure-openai",
|
|
250
|
+
"azure-openai-responses"
|
|
251
|
+
]);
|
|
252
|
+
const LOCAL_ENDPOINT_HOSTS = /* @__PURE__ */ new Set([
|
|
253
|
+
"localhost",
|
|
254
|
+
"127.0.0.1",
|
|
255
|
+
"::1",
|
|
256
|
+
"[::1]"
|
|
257
|
+
]);
|
|
258
|
+
const MODELSTUDIO_NATIVE_BASE_URLS = /* @__PURE__ */ new Set([
|
|
259
|
+
"https://coding-intl.dashscope.aliyuncs.com/v1",
|
|
260
|
+
"https://coding.dashscope.aliyuncs.com/v1",
|
|
261
|
+
"https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
262
|
+
"https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
|
|
263
|
+
]);
|
|
264
|
+
const MOONSHOT_NATIVE_BASE_URLS = /* @__PURE__ */ new Set(["https://api.moonshot.ai/v1", "https://api.moonshot.cn/v1"]);
|
|
265
|
+
function normalizeComparableBaseUrl(value) {
|
|
266
|
+
const trimmed = readStringValue(value)?.trim();
|
|
267
|
+
if (!trimmed) return;
|
|
268
|
+
const parsedValue = /^[a-z0-9.[\]-]+(?::\d+)?(?:[/?#].*)?$/i.test(trimmed) ? `https://${trimmed}` : trimmed;
|
|
269
|
+
try {
|
|
270
|
+
const url = new URL(parsedValue);
|
|
271
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return;
|
|
272
|
+
url.hash = "";
|
|
273
|
+
url.search = "";
|
|
274
|
+
return url.toString().replace(/\/+$/, "").toLowerCase();
|
|
275
|
+
} catch {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function resolveUrlHostname(value) {
|
|
280
|
+
const trimmed = readStringValue(value)?.trim();
|
|
281
|
+
if (!trimmed) return;
|
|
282
|
+
try {
|
|
283
|
+
return new URL(trimmed).hostname.toLowerCase();
|
|
284
|
+
} catch {
|
|
285
|
+
try {
|
|
286
|
+
return new URL(`https://${trimmed}`).hostname.toLowerCase();
|
|
287
|
+
} catch {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function hostMatchesSuffix(host, suffix) {
|
|
293
|
+
return suffix.startsWith(".") || suffix.startsWith("-") ? host.endsWith(suffix) : host === suffix || host.endsWith(`.${suffix}`);
|
|
294
|
+
}
|
|
295
|
+
function isLocalEndpointHost(host) {
|
|
296
|
+
return LOCAL_ENDPOINT_HOSTS.has(host) || host.endsWith(".localhost") || host.endsWith(".local") || host.endsWith(".internal");
|
|
297
|
+
}
|
|
298
|
+
function resolveBundledOpenAIResponsesEndpointClass(baseUrl) {
|
|
299
|
+
const trimmed = readStringValue(baseUrl)?.trim();
|
|
300
|
+
if (!trimmed) return "default";
|
|
301
|
+
const host = resolveUrlHostname(trimmed);
|
|
302
|
+
if (!host) return "invalid";
|
|
303
|
+
const comparableBaseUrl = normalizeComparableBaseUrl(trimmed);
|
|
304
|
+
switch (host) {
|
|
305
|
+
case "api.anthropic.com": return "anthropic-public";
|
|
306
|
+
case "api.cerebras.ai": return "cerebras-native";
|
|
307
|
+
case "llm.chutes.ai": return "chutes-native";
|
|
308
|
+
case "api.deepseek.com": return "deepseek-native";
|
|
309
|
+
case "api.groq.com": return "groq-native";
|
|
310
|
+
case "api.mistral.ai": return "mistral-public";
|
|
311
|
+
case "api.openai.com": return "openai-public";
|
|
312
|
+
case "chatgpt.com": return "openai";
|
|
313
|
+
case "generativelanguage.googleapis.com": return "google-generative-ai";
|
|
314
|
+
case "aiplatform.googleapis.com": return "google-vertex";
|
|
315
|
+
case "api.x.ai": return "xai-native";
|
|
316
|
+
case "api.z.ai": return "zai-native";
|
|
317
|
+
}
|
|
318
|
+
if (hostMatchesSuffix(host, ".githubcopilot.com")) return "github-copilot-native";
|
|
319
|
+
if ([
|
|
320
|
+
".openai.azure.com",
|
|
321
|
+
".cognitiveservices.azure.com",
|
|
322
|
+
".services.ai.azure.com",
|
|
323
|
+
".api.cognitive.microsoft.com"
|
|
324
|
+
].some((suffix) => hostMatchesSuffix(host, suffix))) return "azure-openai";
|
|
325
|
+
if (hostMatchesSuffix(host, "openrouter.ai")) return "openrouter";
|
|
326
|
+
if (hostMatchesSuffix(host, "opencode.ai")) return "opencode-native";
|
|
327
|
+
if (hostMatchesSuffix(host, "-aiplatform.googleapis.com")) return "google-vertex";
|
|
328
|
+
if (comparableBaseUrl && MOONSHOT_NATIVE_BASE_URLS.has(comparableBaseUrl)) return "moonshot-native";
|
|
329
|
+
if (comparableBaseUrl && MODELSTUDIO_NATIVE_BASE_URLS.has(comparableBaseUrl)) return "modelstudio-native";
|
|
330
|
+
if (isLocalEndpointHost(host)) return "local";
|
|
331
|
+
return "custom";
|
|
332
|
+
}
|
|
333
|
+
function isOpenAIResponsesApi(api) {
|
|
334
|
+
return api !== void 0 && OPENAI_RESPONSES_APIS.has(api);
|
|
335
|
+
}
|
|
336
|
+
function readCompatPayloadBoolean(compat, key) {
|
|
337
|
+
if (!compat || typeof compat !== "object") return;
|
|
338
|
+
const value = compat[key];
|
|
339
|
+
return typeof value === "boolean" ? value : void 0;
|
|
340
|
+
}
|
|
341
|
+
function resolveOpenAIResponsesPayloadCapabilities(model) {
|
|
342
|
+
const provider = normalizeOptionalLowercaseString(model.provider);
|
|
343
|
+
const api = normalizeOptionalLowercaseString(model.api);
|
|
344
|
+
const isOpenAIProvider = provider === "openai";
|
|
345
|
+
const endpointClass = resolveBundledOpenAIResponsesEndpointClass(model.baseUrl);
|
|
346
|
+
const isResponsesApi = isOpenAIResponsesApi(api);
|
|
347
|
+
const usesConfiguredBaseUrl = endpointClass !== "default";
|
|
348
|
+
const usesKnownNativeOpenAIEndpoint = endpointClass === "openai-public" || endpointClass === "openai" || endpointClass === "azure-openai";
|
|
349
|
+
const usesKnownNativeOpenAIRoute = endpointClass === "default" ? provider === "openai" : usesKnownNativeOpenAIEndpoint;
|
|
350
|
+
const usesExplicitProxyLikeEndpoint = usesConfiguredBaseUrl && !usesKnownNativeOpenAIEndpoint;
|
|
351
|
+
const usesVerifiedInstructionsEndpoint = (endpointClass === "default" ? provider === "openai" : endpointClass === "openai-public" || endpointClass === "openai") || endpointClass === "xai-native";
|
|
352
|
+
const promptCacheKeySupport = readCompatPayloadBoolean(model.compat, "supportsPromptCacheKey");
|
|
353
|
+
const shouldStripResponsesPromptCache = promptCacheKeySupport === true ? false : promptCacheKeySupport === false ? isResponsesApi : isResponsesApi && usesExplicitProxyLikeEndpoint;
|
|
354
|
+
const supportsResponsesStoreField = readCompatPayloadBoolean(model.compat, "supportsStore") !== false && isResponsesApi;
|
|
355
|
+
return {
|
|
356
|
+
allowsOpenAIServiceTier: provider === "openai" && (api === "openai-responses" || api === "openclaw-openai-responses-transport") && endpointClass === "openai-public" || isOpenAIProvider && (api === "openai-chatgpt-responses" || api === "openclaw-openai-chatgpt-responses-transport" || api === "openai-responses" || api === "openclaw-openai-responses-transport") && endpointClass === "openai",
|
|
357
|
+
allowsResponsesStore: supportsResponsesStoreField && api !== "openai-chatgpt-responses" && api !== "openclaw-openai-chatgpt-responses-transport" && provider !== void 0 && OPENAI_RESPONSES_PROVIDERS.has(provider) && usesKnownNativeOpenAIEndpoint,
|
|
358
|
+
shouldStripResponsesPromptCache,
|
|
359
|
+
supportsResponsesStoreField,
|
|
360
|
+
usesKnownNativeOpenAIRoute,
|
|
361
|
+
usesVerifiedInstructionsEndpoint
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
function resolveOpenAIResponsesCompactThreshold(model) {
|
|
365
|
+
const contextTokens = parsePositiveInteger(model.contextTokens);
|
|
366
|
+
const contextWindow = parsePositiveInteger(model.contextWindow);
|
|
367
|
+
const effectiveBudget = contextTokens && contextWindow ? Math.min(contextTokens, contextWindow) : contextTokens || contextWindow;
|
|
368
|
+
if (effectiveBudget) return Math.max(1e3, Math.floor(effectiveBudget * .7));
|
|
369
|
+
return 8e4;
|
|
370
|
+
}
|
|
371
|
+
/** Resolve the server-compaction gate and effective threshold for a Responses route. */
|
|
372
|
+
function resolveOpenAIResponsesServerCompactionPlan(model, extraParams) {
|
|
373
|
+
const provider = normalizeOptionalLowercaseString(model.provider);
|
|
374
|
+
const allowsResponsesStore = resolveOpenAIResponsesPayloadCapabilities(model).allowsResponsesStore;
|
|
375
|
+
const configured = extraParams?.responsesServerCompaction;
|
|
376
|
+
const enabled = configured !== false && allowsResponsesStore && (configured === true || provider === "openai");
|
|
377
|
+
return {
|
|
378
|
+
enabled,
|
|
379
|
+
threshold: enabled ? parsePositiveInteger(extraParams?.responsesCompactThreshold) ?? resolveOpenAIResponsesCompactThreshold(model) : void 0
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
/** Resolve the manual Responses compact-endpoint gate for one route. */
|
|
383
|
+
function resolveOpenAIResponsesCompactEndpointPlan(model, extraParams) {
|
|
384
|
+
const configured = extraParams?.responsesCompactEndpoint;
|
|
385
|
+
const provider = typeof model.provider === "string" ? normalizeProviderId(model.provider) : "";
|
|
386
|
+
return { enabled: isOpenAIResponsesApi(normalizeOptionalLowercaseString(model.api)) && (configured === true || configured !== false && (provider === "xai" || provider === "x-ai") && resolveBundledOpenAIResponsesEndpointClass(model.baseUrl) === "xai-native") };
|
|
387
|
+
}
|
|
388
|
+
function stripDisabledOpenAIReasoningPayload(payloadObj) {
|
|
389
|
+
const reasoning = payloadObj.reasoning;
|
|
390
|
+
if (reasoning === "none") {
|
|
391
|
+
delete payloadObj.reasoning;
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
if (!reasoning || typeof reasoning !== "object" || Array.isArray(reasoning)) return;
|
|
395
|
+
if (reasoning.effort === "none") delete payloadObj.reasoning;
|
|
396
|
+
}
|
|
397
|
+
/** Strip returned-item metadata rejected by strict Responses-compatible endpoints. */
|
|
398
|
+
function stripInputItemStatuses(input) {
|
|
399
|
+
if (!Array.isArray(input)) return;
|
|
400
|
+
for (const item of input) if (item && typeof item === "object" && !Array.isArray(item)) delete item.status;
|
|
401
|
+
}
|
|
402
|
+
/** Resolve payload mutation policy for one OpenAI Responses-style model endpoint. */
|
|
403
|
+
function resolveOpenAIResponsesPayloadPolicy(model, options = {}) {
|
|
404
|
+
const capabilities = resolveOpenAIResponsesPayloadCapabilities(model);
|
|
405
|
+
const storeMode = options.storeMode ?? "provider-policy";
|
|
406
|
+
const explicitStore = storeMode === "preserve" ? void 0 : storeMode === "disable" ? capabilities.supportsResponsesStoreField ? false : void 0 : capabilities.allowsResponsesStore ? true : void 0;
|
|
407
|
+
const isResponsesApi = isOpenAIResponsesApi(normalizeOptionalLowercaseString(model.api));
|
|
408
|
+
const shouldStripDisabledReasoningPayload = isResponsesApi && (!capabilities.usesKnownNativeOpenAIRoute || !supportsOpenAIReasoningEffort(model, "none"));
|
|
409
|
+
const shouldStripInputStatus = isResponsesApi && !capabilities.usesKnownNativeOpenAIRoute;
|
|
410
|
+
const serverCompactionPlan = resolveOpenAIResponsesServerCompactionPlan(model, options.extraParams);
|
|
411
|
+
const usesInstructionsField = readCompatPayloadBoolean(model.compat, "supportsInstructions") ?? capabilities.usesVerifiedInstructionsEndpoint;
|
|
412
|
+
return {
|
|
413
|
+
allowsServiceTier: capabilities.allowsOpenAIServiceTier,
|
|
414
|
+
compactThreshold: serverCompactionPlan.threshold,
|
|
415
|
+
explicitStore,
|
|
416
|
+
shouldStripDisabledReasoningPayload,
|
|
417
|
+
shouldStripInputStatus,
|
|
418
|
+
shouldStripPromptCache: options.enablePromptCacheStripping === true && capabilities.shouldStripResponsesPromptCache,
|
|
419
|
+
shouldStripStore: explicitStore !== true && readCompatPayloadBoolean(model.compat, "supportsStore") === false && isResponsesApi,
|
|
420
|
+
useServerCompaction: options.enableServerCompaction === true && serverCompactionPlan.enabled,
|
|
421
|
+
usesInstructionsField
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
/** Mutate a Responses request payload according to the resolved endpoint policy. */
|
|
425
|
+
function applyOpenAIResponsesPayloadPolicy(payloadObj, policy) {
|
|
426
|
+
if (policy.explicitStore !== void 0) payloadObj.store = policy.explicitStore;
|
|
427
|
+
if (policy.shouldStripStore) delete payloadObj.store;
|
|
428
|
+
if (policy.shouldStripPromptCache) {
|
|
429
|
+
delete payloadObj.prompt_cache_key;
|
|
430
|
+
delete payloadObj.prompt_cache_retention;
|
|
431
|
+
}
|
|
432
|
+
if (policy.useServerCompaction && policy.compactThreshold !== void 0 && payloadObj.context_management === void 0) payloadObj.context_management = [{
|
|
433
|
+
type: "compaction",
|
|
434
|
+
compact_threshold: policy.compactThreshold
|
|
435
|
+
}];
|
|
436
|
+
if (policy.shouldStripDisabledReasoningPayload) stripDisabledOpenAIReasoningPayload(payloadObj);
|
|
437
|
+
if (policy.shouldStripInputStatus) stripInputItemStatuses(payloadObj.input);
|
|
438
|
+
}
|
|
439
|
+
//#endregion
|
|
440
|
+
//#region packages/media-core/src/inline-image-data-url.ts
|
|
441
|
+
/** Prefix used to distinguish inline data URLs from remote/local image references. */
|
|
442
|
+
const INLINE_IMAGE_DATA_URL_PREFIX = "data:";
|
|
443
|
+
const IMAGE_SIGNATURES = [
|
|
444
|
+
{
|
|
445
|
+
mime: "image/png",
|
|
446
|
+
matches: (buffer) => buffer.length >= 8 && buffer[0] === 137 && buffer[1] === 80 && buffer[2] === 78 && buffer[3] === 71 && buffer[4] === 13 && buffer[5] === 10 && buffer[6] === 26 && buffer[7] === 10
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
mime: "image/jpeg",
|
|
450
|
+
matches: (buffer) => buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
mime: "image/webp",
|
|
454
|
+
matches: (buffer) => buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WEBP"
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
mime: "image/gif",
|
|
458
|
+
matches: (buffer) => buffer.length >= 6 && (buffer.subarray(0, 6).toString("ascii") === "GIF87a" || buffer.subarray(0, 6).toString("ascii") === "GIF89a")
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
mime: "image/bmp",
|
|
462
|
+
matches: (buffer) => buffer.length >= 2 && buffer[0] === 66 && buffer[1] === 77
|
|
463
|
+
}
|
|
464
|
+
];
|
|
465
|
+
const HEIC_BRANDS = /* @__PURE__ */ new Set([
|
|
466
|
+
"heic",
|
|
467
|
+
"heix",
|
|
468
|
+
"hevc",
|
|
469
|
+
"hevx",
|
|
470
|
+
"heis",
|
|
471
|
+
"heim",
|
|
472
|
+
"hevm",
|
|
473
|
+
"hevs"
|
|
474
|
+
]);
|
|
475
|
+
const HEIF_BRANDS = /* @__PURE__ */ new Set(["mif1", "msf1"]);
|
|
476
|
+
const IMAGE_SIGNATURE_PREFIX_BASE64_CHARS = 128;
|
|
477
|
+
const INLINE_IMAGE_DATA_URL_MIMES = /* @__PURE__ */ new Set([
|
|
478
|
+
"image/png",
|
|
479
|
+
"image/jpeg",
|
|
480
|
+
"image/webp",
|
|
481
|
+
"image/gif"
|
|
482
|
+
]);
|
|
483
|
+
function startsWithDataUrl(value) {
|
|
484
|
+
return value.slice(0, 5).toLowerCase() === INLINE_IMAGE_DATA_URL_PREFIX;
|
|
485
|
+
}
|
|
486
|
+
function sniffIsoBmffImageMime(buffer) {
|
|
487
|
+
if (buffer.length < 12 || buffer.subarray(4, 8).toString("ascii") !== "ftyp") return;
|
|
488
|
+
const brands = [buffer.subarray(8, 12).toString("ascii")];
|
|
489
|
+
for (let offset = 16; offset + 4 <= buffer.length; offset += 4) brands.push(buffer.subarray(offset, offset + 4).toString("ascii"));
|
|
490
|
+
if (brands.some((brand) => HEIC_BRANDS.has(brand))) return "image/heic";
|
|
491
|
+
if (brands.some((brand) => HEIF_BRANDS.has(brand))) return "image/heif";
|
|
492
|
+
}
|
|
493
|
+
/** Sniffs supported inline image formats from decoded bytes. */
|
|
494
|
+
function sniffInlineImageMime(buffer) {
|
|
495
|
+
return IMAGE_SIGNATURES.find((signature) => signature.matches(buffer))?.mime ?? sniffIsoBmffImageMime(buffer);
|
|
496
|
+
}
|
|
497
|
+
function isImageMimeType(value) {
|
|
498
|
+
return value.trim().toLowerCase().startsWith("image/");
|
|
499
|
+
}
|
|
500
|
+
/** Canonicalizes trusted inline image base64 and rejects malformed or non-image payloads. */
|
|
501
|
+
function sanitizeInlineImageBase64(params) {
|
|
502
|
+
if (!isImageMimeType(params.mimeType)) return;
|
|
503
|
+
const canonicalPayload = canonicalizeBase64(params.base64);
|
|
504
|
+
if (!canonicalPayload) return;
|
|
505
|
+
const sniffedMimeType = sniffInlineImageMime(Buffer.from(canonicalPayload.slice(0, IMAGE_SIGNATURE_PREFIX_BASE64_CHARS), "base64"));
|
|
506
|
+
if (!sniffedMimeType) return;
|
|
507
|
+
return {
|
|
508
|
+
mimeType: sniffedMimeType,
|
|
509
|
+
base64: canonicalPayload
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
function parseInlineImageDataUrl(value) {
|
|
513
|
+
if (!startsWithDataUrl(value)) return {
|
|
514
|
+
metadata: [],
|
|
515
|
+
payload: value
|
|
516
|
+
};
|
|
517
|
+
const commaIndex = value.indexOf(",");
|
|
518
|
+
if (commaIndex < 0) return;
|
|
519
|
+
return {
|
|
520
|
+
metadata: value.slice(5, commaIndex).split(";").map((part) => part.trim()),
|
|
521
|
+
payload: value.slice(commaIndex + 1)
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
function metadataAllowsImageBase64(metadata) {
|
|
525
|
+
const [mimeType, ...options] = metadata;
|
|
526
|
+
return mimeType !== void 0 && isImageMimeType(mimeType) && options.some((part) => part.toLowerCase() === "base64");
|
|
527
|
+
}
|
|
528
|
+
function sanitizeInlineImageDataUrlWithAllowedMimes(imageUrl, allowedMimes) {
|
|
529
|
+
const parsed = parseInlineImageDataUrl(imageUrl);
|
|
530
|
+
if (!parsed) return;
|
|
531
|
+
if (parsed.metadata.length === 0) return imageUrl;
|
|
532
|
+
if (!metadataAllowsImageBase64(parsed.metadata)) return;
|
|
533
|
+
const [mimeType] = parsed.metadata;
|
|
534
|
+
const sanitized = sanitizeInlineImageBase64({
|
|
535
|
+
mimeType: mimeType ?? "",
|
|
536
|
+
base64: parsed.payload
|
|
537
|
+
});
|
|
538
|
+
if (!sanitized) return;
|
|
539
|
+
if (allowedMimes && !allowedMimes.has(sanitized.mimeType)) return;
|
|
540
|
+
return `data:${sanitized.mimeType};base64,${sanitized.base64}`;
|
|
541
|
+
}
|
|
542
|
+
/** Canonicalizes provider-safe inline image data URLs and rejects unsupported formats. */
|
|
543
|
+
function sanitizeInlineImageDataUrl(imageUrl) {
|
|
544
|
+
return sanitizeInlineImageDataUrlWithAllowedMimes(imageUrl, INLINE_IMAGE_DATA_URL_MIMES);
|
|
545
|
+
}
|
|
546
|
+
//#endregion
|
|
547
|
+
//#region packages/ai/src/transports/responses-image-payload-sanitizer.ts
|
|
548
|
+
/**
|
|
549
|
+
* Sanitizes OpenAI Responses payloads before transport. Invalid inline images
|
|
550
|
+
* are replaced with text placeholders so the request remains valid and
|
|
551
|
+
* auditable.
|
|
552
|
+
*/
|
|
553
|
+
const IMAGE_OMITTED_TEXT = "omitted image payload: invalid inline image data";
|
|
554
|
+
function invalidSnakeImage() {
|
|
555
|
+
return {
|
|
556
|
+
type: "input_text",
|
|
557
|
+
text: `[${IMAGE_OMITTED_TEXT}]`
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
function sanitizeValue(value) {
|
|
561
|
+
if (Array.isArray(value)) return value.map(sanitizeValue);
|
|
562
|
+
if (!isRecord(value)) return value;
|
|
563
|
+
if (value.type === "input_image" && typeof value.image_url === "string") {
|
|
564
|
+
const imageUrl = sanitizeInlineImageDataUrl(value.image_url);
|
|
565
|
+
return imageUrl ? {
|
|
566
|
+
...value,
|
|
567
|
+
image_url: imageUrl
|
|
568
|
+
} : invalidSnakeImage();
|
|
569
|
+
}
|
|
570
|
+
const next = {};
|
|
571
|
+
for (const [key, child] of Object.entries(value)) next[key] = sanitizeValue(child);
|
|
572
|
+
return next;
|
|
573
|
+
}
|
|
574
|
+
/** Sanitize inline image fields inside a Responses API payload. */
|
|
575
|
+
function sanitizeResponsesImagePayload(params) {
|
|
576
|
+
if (!Array.isArray(params.input)) return params;
|
|
577
|
+
return {
|
|
578
|
+
...params,
|
|
579
|
+
input: sanitizeValue(params.input)
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
//#endregion
|
|
583
|
+
//#region packages/ai/src/transports/openai-responses-compaction-window.ts
|
|
584
|
+
const COMPACTION_WINDOW_MAX_BYTES = 16 * 1024 * 1024;
|
|
585
|
+
function isOptionalCompactionString(value) {
|
|
586
|
+
return value === void 0 || typeof value === "string";
|
|
587
|
+
}
|
|
588
|
+
function isBoundedJson(value, depth = 0) {
|
|
589
|
+
if (depth > 64) return false;
|
|
590
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
591
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
592
|
+
return (Array.isArray(value) || isRecord(value)) && Object.values(value).every((child) => isBoundedJson(child, depth + 1));
|
|
593
|
+
}
|
|
594
|
+
function isInputContent(value) {
|
|
595
|
+
if (!isRecord(value)) return false;
|
|
596
|
+
const breakpoint = value.prompt_cache_breakpoint;
|
|
597
|
+
if (breakpoint !== void 0 && (!isRecord(breakpoint) || breakpoint.mode !== "explicit")) return false;
|
|
598
|
+
switch (value.type) {
|
|
599
|
+
case "input_text": return typeof value.text === "string";
|
|
600
|
+
case "input_image": return typeof value.detail === "string" && [
|
|
601
|
+
"auto",
|
|
602
|
+
"low",
|
|
603
|
+
"high",
|
|
604
|
+
"original"
|
|
605
|
+
].includes(value.detail) && (typeof value.image_url === "string" || typeof value.file_id === "string") && (value.image_url === null || isOptionalCompactionString(value.image_url)) && (value.file_id === null || isOptionalCompactionString(value.file_id));
|
|
606
|
+
case "input_file": return (value.detail === void 0 || typeof value.detail === "string" && [
|
|
607
|
+
"auto",
|
|
608
|
+
"low",
|
|
609
|
+
"high"
|
|
610
|
+
].includes(value.detail)) && [
|
|
611
|
+
value.file_data,
|
|
612
|
+
value.file_id,
|
|
613
|
+
value.file_url
|
|
614
|
+
].some((entry) => typeof entry === "string") && isOptionalCompactionString(value.file_data) && (value.file_id === null || isOptionalCompactionString(value.file_id)) && isOptionalCompactionString(value.file_url) && isOptionalCompactionString(value.filename);
|
|
615
|
+
default: return false;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
/** Validate without projecting: accepted provider fields must survive replay unchanged. */
|
|
619
|
+
function isOpenAIResponsesCompactionOutput(value, model) {
|
|
620
|
+
if (!Array.isArray(value) || value.length === 0 || !isBoundedJson(value)) return false;
|
|
621
|
+
const item = value.at(-1);
|
|
622
|
+
if (!(isRecord(item) && item.type === "compaction" && typeof item.encrypted_content === "string" && item.encrypted_content.length > 0 && isOptionalCompactionString(item.id) && isOptionalCompactionString(item.created_by) && value.slice(0, -1).every((message) => isRecord(message) && message.type === "message" && typeof message.role === "string" && [
|
|
623
|
+
"user",
|
|
624
|
+
"developer",
|
|
625
|
+
"system"
|
|
626
|
+
].includes(message.role) && isOptionalCompactionString(message.id) && (message.status === void 0 || typeof message.status === "string" && [
|
|
627
|
+
"in_progress",
|
|
628
|
+
"completed",
|
|
629
|
+
"incomplete"
|
|
630
|
+
].includes(message.status)) && Array.isArray(message.content) && message.content.every(isInputContent)))) return false;
|
|
631
|
+
const payload = sanitizeResponsesImagePayload({ input: value });
|
|
632
|
+
if (model) applyOpenAIResponsesPayloadPolicy(payload, resolveOpenAIResponsesPayloadPolicy(model));
|
|
633
|
+
return JSON.stringify(payload.input) === JSON.stringify(value);
|
|
634
|
+
}
|
|
635
|
+
/** Read the saved canonical window only when it still matches its opaque checkpoint. */
|
|
636
|
+
function readOpenAIResponsesCompactionWindow(replay, model) {
|
|
637
|
+
const window = replay.compactedWindow;
|
|
638
|
+
if (!isRecord(window) || window.state !== "ready" || typeof window.output !== "string") return;
|
|
639
|
+
if (Buffer.byteLength(window.output, "utf8") + Buffer.byteLength(replay.data, "utf8") > COMPACTION_WINDOW_MAX_BYTES) return;
|
|
640
|
+
try {
|
|
641
|
+
if (Buffer.byteLength(JSON.stringify(replay), "utf8") > COMPACTION_WINDOW_MAX_BYTES) return;
|
|
642
|
+
const output = JSON.parse(window.output);
|
|
643
|
+
if (!isOpenAIResponsesCompactionOutput(output, model)) return;
|
|
644
|
+
const item = output.at(-1);
|
|
645
|
+
return item?.type === "compaction" && item.encrypted_content === replay.data && item.id === replay.id ? output : void 0;
|
|
646
|
+
} catch {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
/** Bound success bytes while leaving body deadlines, retries, and parsing to the SDK. */
|
|
651
|
+
function createBoundedOpenAIResponsesCompactionFetch(upstreamFetch) {
|
|
652
|
+
return async (input, init) => {
|
|
653
|
+
const response = await upstreamFetch(input, init);
|
|
654
|
+
if (!response.ok || !response.body) return response;
|
|
655
|
+
const reader = response.body.getReader();
|
|
656
|
+
const guard = createSseByteGuard(reader, {
|
|
657
|
+
maxBytes: COMPACTION_WINDOW_MAX_BYTES,
|
|
658
|
+
onOverflow: () => /* @__PURE__ */ new Error("Responses compact endpoint response exceeds 16 MiB")
|
|
659
|
+
});
|
|
660
|
+
const body = new ReadableStream({
|
|
661
|
+
async pull(controller) {
|
|
662
|
+
try {
|
|
663
|
+
const chunk = await guard.read();
|
|
664
|
+
if (chunk.done) {
|
|
665
|
+
reader.releaseLock();
|
|
666
|
+
controller.close();
|
|
667
|
+
} else controller.enqueue(chunk.value);
|
|
668
|
+
} catch (error) {
|
|
669
|
+
reader.releaseLock();
|
|
670
|
+
controller.error(error);
|
|
671
|
+
}
|
|
672
|
+
},
|
|
673
|
+
cancel(reason) {
|
|
674
|
+
guard.cancel(reason);
|
|
675
|
+
reader.releaseLock();
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
return new Response(body, {
|
|
679
|
+
status: response.status,
|
|
680
|
+
statusText: response.statusText,
|
|
681
|
+
headers: response.headers
|
|
682
|
+
});
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
//#endregion
|
|
686
|
+
export { supportsOpenAITemperature as A, isOpenAIGpt54MiniModel as C, resolveOpenAIReasoningEffortForModel as D, normalizeOpenAIReasoningEffort as E, resolveOpenAISupportedReasoningEfforts as O, responsesPromptObserver as S, isOpenAIGpt56Model as T, OpenAIResponsesWebSocketPostDispatchError as _, applyOpenAIResponsesPayloadPolicy as a, RESPONSE_FAILED_NO_DETAILS_MESSAGE as b, resolveOpenAIResponsesServerCompactionPlan as c, OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS as d, OPENAI_RESPONSES_APIS as f, OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE as g, OPENAI_RESPONSES_REASONING_REPLAY_META_KEY as h, sanitizeResponsesImagePayload as i, supportsOpenAIReasoningEffort as k, AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS as l, OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY as m, isOpenAIResponsesCompactionOutput as n, resolveOpenAIResponsesCompactEndpointPlan as o, OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE as p, readOpenAIResponsesCompactionWindow as r, resolveOpenAIResponsesPayloadPolicy as s, createBoundedOpenAIResponsesCompactionFetch as t, DEFAULT_AZURE_OPENAI_API_VERSION as u, OpenAIResponsesWebSocketPreDispatchError as v, isOpenAIGpt55Model as w, parseOpenAIResponsesWebSocketServerError as x, OpenAIResponsesWebSocketSafeRetryError as y };
|