@openclaw/ai 2026.10.1 → 2026.10.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/{anthropic-BDfXKgF1.mjs → anthropic-BAHKgWam.mjs} +30 -59
- package/dist/{anthropic-payload-policy-BZUAchqb.d.mts → anthropic-payload-policy-DGblkHL5.d.mts} +19 -16
- package/dist/{anthropic-stream-reducer-DHt9uFWX.mjs → anthropic-stream-reducer-g6w1YVii.mjs} +195 -283
- package/dist/{api-registry-DcEP_o4h.d.mts → api-registry-BhXXYdRA.d.mts} +2 -2
- package/dist/assistant-message-events-CHMJgbhs.mjs +18 -0
- package/dist/{assistant-output-mJ9cL4Qg.mjs → assistant-output-CUEeSotf.mjs} +2 -2
- package/dist/{assistant-text-phase-DAv1BdTm.mjs → assistant-text-phase-BrV8KdFO.mjs} +7 -6
- package/dist/{azure-openai-responses-gn9hMf8x.mjs → azure-openai-responses-C7qBuR23.mjs} +8 -9
- package/dist/{credential-redaction-BKv49aiv.d.mts → credential-redaction-BHxruEH6.d.mts} +3 -1
- package/dist/{diagnostics-Caj-4RBA.mjs → diagnostics-tQasYct1.mjs} +10 -3
- package/dist/diagnostics.d.mts +7 -7
- package/dist/diagnostics.mjs +3 -3
- package/dist/{env-api-keys-CyX4VKGO.mjs → env-api-keys-CrxwdylR.mjs} +24 -35
- package/dist/event-stream-6UNs-AhN.d.mts +1 -0
- package/dist/{event-stream-DrRM_90c.d.mts → event-stream-BcqWLo_u.d.mts} +1 -1
- package/dist/{event-stream-C5AbCAaZ.mjs → event-stream-X2gmsUWv.mjs} +5 -8
- package/dist/event-stream.d.mts +2 -2
- package/dist/event-stream.mjs +1 -1
- package/dist/google-Boz2QcpK.mjs +20 -0
- package/dist/{google-interactions-DXu4IYGb.mjs → google-interactions-tjAb1mc5.mjs} +52 -84
- package/dist/{google-messages-Bmheetdg.mjs → google-messages-C-RZzloH.mjs} +25 -35
- package/dist/google-provider-stream-CMImyxbX.mjs +58 -0
- package/dist/{google-shared-DE_ddfsC.mjs → google-shared-OyAtMTZv.mjs} +6 -15
- package/dist/google-vertex-hCxTJea7.mjs +40 -0
- package/dist/{host-BjIYEjwT.d.mts → host-CTDz7LXD.d.mts} +6 -3
- package/dist/{host-JpNulOOs.mjs → host-JWXZWa-c.mjs} +3 -2
- package/dist/{host-policy-CC5H0iRZ.mjs → host-policy-q4Azym9F.mjs} +1 -1
- package/dist/{index-DJrNQnKw.d.mts → index-BYDvopUB.d.mts} +8 -5
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +7 -6
- package/dist/internal/anthropic.d.mts +5 -5
- package/dist/internal/anthropic.mjs +4 -4
- package/dist/internal/openai-completions-compat.d.mts +1 -1
- package/dist/internal/openai-completions-compat.mjs +1 -1
- package/dist/internal/openai-responses-payload-policy.d.mts +8 -1
- package/dist/internal/openai-responses-payload-policy.mjs +3 -3
- package/dist/internal/openai.d.mts +9 -9
- package/dist/internal/openai.mjs +9 -11
- package/dist/internal/runtime.d.mts +31 -13
- package/dist/internal/runtime.mjs +10 -13
- package/dist/internal/shared.d.mts +5 -5
- package/dist/internal/shared.mjs +6 -7
- package/dist/internal/tool-schema.mjs +2 -2
- package/dist/{llm-request-activity-D8f_oxHj.mjs → llm-request-activity-CfMuh5cC.mjs} +2 -2
- package/dist/{mistral-1Bnbneg1.mjs → mistral-DUveP4hF.mjs} +71 -146
- package/dist/{model-transport-url-C5f59L3Y.d.mts → model-transport-url-BrsjjdjR.d.mts} +5 -1
- package/dist/{number-coercion-V8-BhME4.mjs → number-coercion-C3hztWoY.mjs} +5 -4
- package/dist/{openai-chatgpt-responses-CB1JwNFF.mjs → openai-chatgpt-responses-OCwckGhY.mjs} +164 -234
- package/dist/{openai-completions-BPadHHKe.mjs → openai-completions-DOltBUe9.mjs} +7 -6
- package/dist/{openai-completions-compat-CJ0ktmGy.d.mts → openai-completions-compat-i-nLZxFy.d.mts} +10 -11
- package/dist/{openai-completions-compat-D7hWYB0G.mjs → openai-completions-compat-pg1q4uNG.mjs} +10 -6
- package/dist/{openai-completions-transport-DITBEALX.mjs → openai-completions-transport-OMrn7gnZ.mjs} +1429 -294
- package/dist/{openai-prompt-cache-Dj8qeOHT.mjs → openai-prompt-cache-Cr2xKVrS.mjs} +1 -1
- package/dist/{openai-prompt-cache-C-Q1Ksfs.d.mts → openai-prompt-cache-DIPMrMFy.d.mts} +2 -2
- package/dist/{openai-responses-1_TvcWI3.mjs → openai-responses-BSBJUA19.mjs} +9 -10
- package/dist/{openai-responses-compaction-replay-BB2SWdsx.d.mts → openai-responses-compaction-replay-B2FE4Nw8.d.mts} +4 -4
- package/dist/{openai-responses-contracts-sAvdqNjS.d.mts → openai-responses-contracts-DKqMJ1Ct.d.mts} +9 -4
- package/dist/{openai-responses-contracts-BKu8O7l4.mjs → openai-responses-contracts-DlKMMTxK.mjs} +26 -6
- package/dist/{openai-responses-compaction-window-m878aVpU.mjs → openai-responses-endpoint-CinGh4VZ.mjs} +14 -4
- package/dist/{openai-responses-prompt-observer-internal-CbH84xIS.mjs → openai-responses-request-lifecycle-D2IFiI0-.mjs} +39 -4
- package/dist/{openai-responses-shared-TCJRAoMW.mjs → openai-responses-shared-DVGhq5xF.mjs} +1036 -327
- package/dist/{openai-responses-terminal-usage-BVvyXZ8u.d.mts → openai-responses-terminal-usage-BygjiAdi.d.mts} +2 -2
- package/dist/{openai-tool-schema-DYNePiF8.mjs → openai-tool-schema-DDPXsvJP.mjs} +236 -399
- package/dist/{positive-integer-CwLi8LUL.mjs → positive-integer-CqWjqSi9.mjs} +1 -1
- package/dist/{provider-error-DQBE1bUQ.mjs → provider-error-CF9GWCs2.mjs} +5 -3
- package/dist/{provider-options-Dk4PeQV3.d.mts → provider-options-CVrXZBtA.d.mts} +3 -2
- package/dist/{provider-transport-turn-state-8c_Nj2NS.mjs → provider-transport-turn-state-LuCaTsSO.mjs} +2 -2
- package/dist/{provider-types-De8PRdR0.d.mts → provider-types-CHtRx0dI.d.mts} +3 -3
- package/dist/provider-types.d.mts +6 -6
- package/dist/providers.d.mts +2 -2
- package/dist/providers.mjs +12 -12
- package/dist/{reasoning-tag-text-partitioner-Ju9VpUGl.mjs → reasoning-tag-text-partitioner-0-Rsezog.mjs} +13 -12
- package/dist/{required-api-key-D4kn3252.mjs → required-api-key-CFJvcFy_.mjs} +1 -1
- package/dist/{simple-options-wW3117Fu.mjs → simple-options-BARFAzk9.mjs} +9 -11
- package/dist/{src-DWJq14pn.mjs → src-C_wfIUmV.mjs} +19 -4
- package/dist/{stream-CElngO8h.mjs → stream-DwrETW0_.mjs} +12 -21
- package/dist/{stream-first-event-timeout-D9ZmL_s9.mjs → stream-first-event-timeout-Dc42hKv6.mjs} +8 -21
- package/dist/{streaming-byte-guard-CC-HMn_u.mjs → streaming-byte-guard-DBXr1XYn.mjs} +16 -1
- package/dist/{string-normalization-PN10hf6d.mjs → string-normalization-I3ux50s9.mjs} +1 -1
- package/dist/{text-signature-rOn31nxc.mjs → text-signature-B_MB6U_9.mjs} +32 -5
- package/dist/{tool-schema-json-projection-Ct8SeBeJ.mjs → tool-schema-json-projection-B8sG1I9v.mjs} +29 -23
- package/dist/{transport-stream-shared-CAxkgOSj.d.mts → transport-stream-shared-BmpzDtdQ.d.mts} +4 -4
- package/dist/{transport-stream-shared-C5TAc3U_.mjs → transport-stream-shared-DH08b7Il.mjs} +8 -16
- package/dist/transports.d.mts +33 -22
- package/dist/transports.mjs +73 -1234
- package/dist/{types-DvzmWW8J.d.mts → types-Bd2T86VJ.d.mts} +5 -23
- package/dist/types-Kdfw_04V.d.mts +1 -0
- package/dist/types.d.mts +6 -6
- package/dist/types.mjs +5 -4
- package/dist/{validation-B3lQt_VE.d.mts → validation-DdGB1yy3.d.mts} +1 -1
- package/dist/{validation-DbqlIfDn.mjs → validation-opC2pjk9.mjs} +2 -3
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/package.json +4 -9
- package/dist/env-api-keys-BR0MUYYD.d.mts +0 -17
- package/dist/event-stream-DqDQWqiy.d.mts +0 -1
- package/dist/google-CyMz2jF_.mjs +0 -54
- package/dist/google-vertex-BEW0OQIA.mjs +0 -88
- package/dist/internal/env-api-keys.d.mts +0 -2
- package/dist/internal/env-api-keys.mjs +0 -2
- package/dist/openai-responses-request-lifecycle-Fsag-IGZ.mjs +0 -36
- package/dist/openai-transport-params-ildrm49s.mjs +0 -735
- package/dist/openai-web-search-tools-Cfu0uLyN.mjs +0 -14
- package/dist/provider-replay-context-ywPKKLjL.mjs +0 -25
- package/dist/types-Dlz-8qcy.d.mts +0 -1
|
@@ -1,91 +1,751 @@
|
|
|
1
|
-
import "./src-
|
|
1
|
+
import "./src-C_wfIUmV.mjs";
|
|
2
2
|
import { _ as runtimeContextContentToText, f as hasRuntimeContextMarker, p as isRuntimeContextMessage } from "./types-CQc6JNG4.mjs";
|
|
3
3
|
import { o as readProviderRefusalReview, t as appendAssistantMessageDiagnostic } from "./diagnostics-DzrF1h4J.mjs";
|
|
4
|
-
import { r as appendAssistantThinking } from "./event-stream-
|
|
5
|
-
import { o as isRecord } from "./record-coerce-CNDovvft.mjs";
|
|
6
|
-
import { a as normalizeOptionalString, c as readStringValue, o as normalizeStringifiedOptionalString } from "./string-coerce-CtgOVOSv.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import { D as
|
|
4
|
+
import { r as appendAssistantThinking } from "./event-stream-X2gmsUWv.mjs";
|
|
5
|
+
import { o as isRecord, r as asOptionalObjectRecord } from "./record-coerce-CNDovvft.mjs";
|
|
6
|
+
import { a as normalizeOptionalString, c as readStringValue, n as normalizeLowercaseStringOrEmpty, o as normalizeStringifiedOptionalString } from "./string-coerce-CtgOVOSv.mjs";
|
|
7
|
+
import { t as asFiniteNumber } from "./number-coercion-C3hztWoY.mjs";
|
|
8
|
+
import { D as applyProviderReportedUsageCost, E as headersToRecord, N as isImageWithMediaPayload, O as calculateCost, a as resolveAiTransportHeaderSentinels, k as clampThinkingLevel, r as getAiTransportHost } from "./host-JWXZWa-c.mjs";
|
|
9
|
+
import { A as MODEL_CATALOG_THINKING_LEVELS, C as normalizeOpenAIReasoningEffort, E as resolveOpenAIReasoningEffortMapping, M as resolveOpenAIThinkingApi, O as supportsOpenAIReasoningEffort, T as resolveOpenAIReasoningEffortForModel, _ as isResponsesServiceTierRejection, a as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, c as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, f as RESPONSE_FAILED_NO_DETAILS_MESSAGE, g as responsesServiceTierObserver, i as OPENAI_RESPONSES_APIS, k as supportsOpenAITemperature, o as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, p as isPreviousResponseRejection, s as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, v as nextResponsesServiceTier, w as resolveOpenAIModelReasoningEfforts } from "./openai-responses-contracts-DlKMMTxK.mjs";
|
|
9
10
|
import { n as getSessionResourceOwnerId, r as registerSessionResourceCleanup } from "./session-resources-D1wgDQ8C.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { o as
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { A as
|
|
17
|
-
import {
|
|
18
|
-
import { n as transformProviderMessages } from "./assistant-output-
|
|
19
|
-
import { t as
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
11
|
+
import { c as stableStringify, s as truncateUtf16Safe } from "./provider-error-CF9GWCs2.mjs";
|
|
12
|
+
import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-Cr2xKVrS.mjs";
|
|
13
|
+
import { _ as resolveResponsesTerminalStopReason, a as resolveModelPayloadDebugMode, d as hasOnlyResponsesFunctionTools, f as isResponsesProviderTool, g as readResponsesReasoningTokens, h as mapResponsesTerminalUsage, o as resolveModelSseDebugMode, r as emitModelTransportDebug, u as ResponsesOutputIdentityError } from "./diagnostics-tQasYct1.mjs";
|
|
14
|
+
import { i as providerReplayContextMatches, l as redactSensitiveText, n as buildProviderReplayContext, r as isProviderReplayContext, s as isCodeModeModelVisibleToolName, t as encodeTextSignatureV1 } from "./text-signature-B_MB6U_9.mjs";
|
|
15
|
+
import { c as resolveOpenAIResponsesTextFormat, i as resolveOpenAICompletionsCompat, o as usesNativeOpenAICodexResponsesBackend } from "./openai-completions-compat-pg1q4uNG.mjs";
|
|
16
|
+
import { r as resolveModelRequestTimeoutMs } from "./host-policy-q4Azym9F.mjs";
|
|
17
|
+
import { A as shortHash, C as parseJsonObjectPreservingUnsafeIntegers, E as createToolArgumentPreviewSchedule, O as parseStreamingJson, S as withProviderResponseHook, b as transportAbortError, c as failTransportStream, d as iterateModelStream, g as parseTerminalToolCallArguments, m as notifyProviderHttpResponse, t as IncompleteToolCallError, u as finalizeTransportStream, v as sanitizeTransportPayloadText } from "./transport-stream-shared-DH08b7Il.mjs";
|
|
18
|
+
import { C as stripSystemPromptCacheBoundary, D as sortPromptCacheToolsByName, d as describeToolResultMediaPlaceholder, m as extractToolResultText, s as prepareModelRequestBody } from "./simple-options-BARFAzk9.mjs";
|
|
19
|
+
import { n as transformProviderMessages } from "./assistant-output-CUEeSotf.mjs";
|
|
20
|
+
import { n as projectRuntimeToolInputSchema, t as prepareRuntimeToolInputSchema } from "./tool-schema-json-projection-B8sG1I9v.mjs";
|
|
21
|
+
import { t as notifyLlmRequestActivity } from "./llm-request-activity-CfMuh5cC.mjs";
|
|
22
|
+
import { n as resolveOpencodeSessionHeaders } from "./session-affinity-DA4WHv1h.mjs";
|
|
23
|
+
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-Dc42hKv6.mjs";
|
|
24
|
+
import { a as resolveOpenAIProjectedToolsStrictToolFlag, f as withPreparedToolSchemaNormalization, r as normalizeOpenAIStrictToolParameters, t as findOpenAIStrictToolProjectionDiagnostics } from "./openai-tool-schema-DDPXsvJP.mjs";
|
|
25
|
+
import { a as readOpenAIResponsesCompactionWindow, i as isOpenAIResponsesCompactionOutput, n as supportsNativeOpenAIResponsesEndpoint } from "./openai-responses-endpoint-CinGh4VZ.mjs";
|
|
26
|
+
import { hash, randomUUID } from "node:crypto";
|
|
27
|
+
//#region packages/normalization-core/src/node-crypto.ts
|
|
28
|
+
function sha256Hex(input) {
|
|
29
|
+
return hash("sha256", input, "hex");
|
|
30
|
+
}
|
|
31
|
+
function sha256HexPrefixCore(input, length) {
|
|
32
|
+
return sha256Hex(input).slice(0, length);
|
|
33
|
+
}
|
|
34
|
+
/** Redacts an identifier to a stable hash label, or "-" for missing values. */
|
|
35
|
+
function redactIdentifier(value, opts) {
|
|
36
|
+
const trimmed = normalizeOptionalString(value);
|
|
37
|
+
if (!trimmed) return "-";
|
|
38
|
+
const len = opts?.len ?? 12;
|
|
39
|
+
return `sha256:${sha256HexPrefixCore(trimmed, Number.isFinite(len) ? Math.max(1, Math.floor(len)) : 12)}`;
|
|
30
40
|
}
|
|
31
41
|
//#endregion
|
|
32
|
-
//#region packages/ai/src/transports/openai-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
//#region packages/ai/src/transports/openai-transport-shared.ts
|
|
43
|
+
const OPENAI_RESPONSE_MODEL_HEADER_NAMES = /* @__PURE__ */ new Set(["openai-model", "x-openai-model"]);
|
|
44
|
+
const OPENAI_RESPONSE_MODEL_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
45
|
+
"response.created",
|
|
46
|
+
"response.in_progress",
|
|
47
|
+
"response.completed",
|
|
48
|
+
"response.done",
|
|
49
|
+
"response.incomplete",
|
|
50
|
+
"response.failed"
|
|
51
|
+
]);
|
|
52
|
+
const OPENAI_DATED_MODEL_SUFFIX = /-(?:\d{8}|\d{4}-\d{2}-\d{2})$/;
|
|
53
|
+
const GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP = "skip_thought_signature_validator";
|
|
54
|
+
const log = {
|
|
55
|
+
debug(message, data) {
|
|
56
|
+
getAiTransportHost().logDebug("openai-transport", () => ({
|
|
57
|
+
message,
|
|
58
|
+
data
|
|
59
|
+
}));
|
|
60
|
+
},
|
|
61
|
+
info(message, data) {
|
|
62
|
+
getAiTransportHost().logInfo("openai-transport", message, data);
|
|
63
|
+
},
|
|
64
|
+
warn(message, data) {
|
|
65
|
+
getAiTransportHost().logWarn("openai-transport", message, data);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function splitOpenAIResponseModelHeader(value) {
|
|
69
|
+
return value ? value.split(",").map((part) => part.trim()).filter(Boolean) : [];
|
|
70
|
+
}
|
|
71
|
+
function readOpenAIResponseModelHeaders(headers) {
|
|
72
|
+
return [...OPENAI_RESPONSE_MODEL_HEADER_NAMES].flatMap((name) => splitOpenAIResponseModelHeader(headers.get(name)));
|
|
73
|
+
}
|
|
74
|
+
function readOpenAIResponseModelHeaderRecord(headers) {
|
|
75
|
+
if (!isRecord(headers)) return [];
|
|
76
|
+
return Object.entries(headers).filter(([name]) => OPENAI_RESPONSE_MODEL_HEADER_NAMES.has(name.toLowerCase())).flatMap(([, value]) => typeof value === "string" ? splitOpenAIResponseModelHeader(value) : []);
|
|
77
|
+
}
|
|
78
|
+
function readOpenAIResponseModelEvent(event) {
|
|
79
|
+
if (!isRecord(event)) return [];
|
|
80
|
+
const response = isRecord(event.response) ? event.response : void 0;
|
|
81
|
+
return [
|
|
82
|
+
...OPENAI_RESPONSE_MODEL_EVENT_TYPES.has(String(event.type)) && typeof response?.model === "string" && response.model.trim() ? [response.model.trim()] : [],
|
|
83
|
+
...readOpenAIResponseModelHeaderRecord(response?.headers),
|
|
84
|
+
...readOpenAIResponseModelHeaderRecord(event.headers)
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
function reconcileOpenAIResponseModels(current, observed) {
|
|
88
|
+
if (!current || current === observed) return observed;
|
|
89
|
+
const currentBase = current.replace(OPENAI_DATED_MODEL_SUFFIX, "");
|
|
90
|
+
const observedBase = observed.replace(OPENAI_DATED_MODEL_SUFFIX, "");
|
|
91
|
+
if (currentBase !== observedBase) return;
|
|
92
|
+
if (currentBase === current && observedBase !== observed) return observed;
|
|
93
|
+
if (observedBase === observed && currentBase !== current) return current;
|
|
94
|
+
}
|
|
95
|
+
function createResponseModelTracker(enabled = true) {
|
|
96
|
+
let responseModel;
|
|
97
|
+
const observe = (models) => {
|
|
98
|
+
for (const model of models) {
|
|
99
|
+
const reconciled = reconcileOpenAIResponseModels(responseModel, model);
|
|
100
|
+
if (!reconciled) throw new Error("Conflicting OpenAI response model attestations");
|
|
101
|
+
responseModel = reconciled;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const begin = (headers) => {
|
|
105
|
+
responseModel = void 0;
|
|
106
|
+
if (enabled && headers) observe(readOpenAIResponseModelHeaders(headers));
|
|
107
|
+
};
|
|
108
|
+
const observeEvent = (event) => {
|
|
109
|
+
if (enabled) observe(readOpenAIResponseModelEvent(event));
|
|
110
|
+
return responseModel;
|
|
111
|
+
};
|
|
112
|
+
const resolve = () => responseModel;
|
|
48
113
|
return {
|
|
49
|
-
|
|
50
|
-
|
|
114
|
+
begin,
|
|
115
|
+
observeEvent,
|
|
116
|
+
resolve,
|
|
117
|
+
track(response, stream) {
|
|
118
|
+
if (!enabled) return stream;
|
|
119
|
+
return (async function* () {
|
|
120
|
+
begin(response?.headers);
|
|
121
|
+
for await (const event of stream) {
|
|
122
|
+
observeEvent(event);
|
|
123
|
+
yield event;
|
|
124
|
+
}
|
|
125
|
+
})();
|
|
126
|
+
},
|
|
127
|
+
terminalOptions: enabled ? { resolveResponseModel: resolve } : {}
|
|
51
128
|
};
|
|
52
129
|
}
|
|
53
|
-
function
|
|
54
|
-
|
|
130
|
+
function resolveOpenAIClientBaseUrl(model, baseUrl = model.baseUrl) {
|
|
131
|
+
if (baseUrl?.trim()) return baseUrl;
|
|
132
|
+
if (model.provider.trim().toLowerCase() === "openai") return;
|
|
133
|
+
throw new Error(`Provider "${model.provider}" requires an explicit base URL before using an OpenAI-compatible API. Reload provider metadata or configure an endpoint.`);
|
|
55
134
|
}
|
|
56
|
-
|
|
57
|
-
|
|
135
|
+
const EMPTY_OPENAI_COMPLETIONS_REASONING_BATCH = {
|
|
136
|
+
deltas: [],
|
|
137
|
+
mirroredThinking: [],
|
|
138
|
+
hasThinking: false,
|
|
139
|
+
hasVisibleText: false
|
|
140
|
+
};
|
|
141
|
+
const OPENAI_COMPLETIONS_REASONING_FIELDS = [
|
|
142
|
+
"reasoning_content",
|
|
143
|
+
"reasoning",
|
|
144
|
+
"reasoning_text"
|
|
145
|
+
];
|
|
146
|
+
function appendOpenAICompletionsReasoningDelta(deltas, mirroredThinking, next) {
|
|
147
|
+
const previous = deltas[deltas.length - 1];
|
|
148
|
+
if (!previous || previous.kind !== next.kind || next.kind === "thinking" && previous.kind === "thinking" && previous.signature !== next.signature) {
|
|
149
|
+
deltas.push(next);
|
|
150
|
+
if (next.kind === "thinking") mirroredThinking.push(next.text);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
previous.text += next.text;
|
|
154
|
+
if (next.kind === "thinking") mirroredThinking[mirroredThinking.length - 1] += next.text;
|
|
155
|
+
}
|
|
156
|
+
function readOpenAICompletionsReasoningBatch(delta, visibleReasoningDetailTypes) {
|
|
157
|
+
let deltas;
|
|
158
|
+
const mirroredThinking = [];
|
|
159
|
+
const reasoningDetails = delta.reasoning_details;
|
|
160
|
+
if (Array.isArray(reasoningDetails)) for (const detail of reasoningDetails) {
|
|
161
|
+
if (!isRecord(detail)) continue;
|
|
162
|
+
if (typeof detail.text !== "string" || !detail.text) continue;
|
|
163
|
+
if (detail.type === "reasoning.text") {
|
|
164
|
+
deltas ??= [];
|
|
165
|
+
appendOpenAICompletionsReasoningDelta(deltas, mirroredThinking, {
|
|
166
|
+
kind: "thinking",
|
|
167
|
+
signature: "reasoning_details",
|
|
168
|
+
text: detail.text
|
|
169
|
+
});
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (typeof detail.type === "string" && visibleReasoningDetailTypes.has(detail.type)) {
|
|
173
|
+
deltas ??= [];
|
|
174
|
+
appendOpenAICompletionsReasoningDelta(deltas, mirroredThinking, {
|
|
175
|
+
kind: "text",
|
|
176
|
+
text: detail.text,
|
|
177
|
+
source: "reasoning_detail"
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (mirroredThinking.length === 0) for (const field of OPENAI_COMPLETIONS_REASONING_FIELDS) {
|
|
182
|
+
const value = delta[field];
|
|
183
|
+
if (typeof value === "string" && value.length > 0) {
|
|
184
|
+
deltas ??= [];
|
|
185
|
+
appendOpenAICompletionsReasoningDelta(deltas, mirroredThinking, {
|
|
186
|
+
kind: "thinking",
|
|
187
|
+
signature: field,
|
|
188
|
+
text: value
|
|
189
|
+
});
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (!deltas) return EMPTY_OPENAI_COMPLETIONS_REASONING_BATCH;
|
|
194
|
+
return {
|
|
195
|
+
deltas,
|
|
196
|
+
mirroredThinking,
|
|
197
|
+
hasThinking: mirroredThinking.length > 0,
|
|
198
|
+
hasVisibleText: mirroredThinking.length < deltas.length
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function parseOpenAICompletionsUsage(rawUsage, model, options) {
|
|
202
|
+
const cacheRead = rawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.prompt_cache_hit_tokens ?? 0;
|
|
203
|
+
const cacheWrite = rawUsage.prompt_tokens_details?.cache_write_tokens ?? rawUsage.prompt_tokens_details?.cache_creation_input_tokens ?? rawUsage.cache_creation_input_tokens ?? 0;
|
|
204
|
+
const input = Math.max(0, (rawUsage.prompt_tokens || 0) - cacheRead - cacheWrite);
|
|
205
|
+
const output = rawUsage.completion_tokens || 0;
|
|
206
|
+
const reasoningTokens = asFiniteNumber(rawUsage.completion_tokens_details?.reasoning_tokens);
|
|
207
|
+
const hasCoherentContext = [
|
|
208
|
+
rawUsage.prompt_tokens,
|
|
209
|
+
rawUsage.completion_tokens,
|
|
210
|
+
rawUsage.total_tokens,
|
|
211
|
+
cacheRead,
|
|
212
|
+
cacheWrite
|
|
213
|
+
].every((value) => typeof value === "number" && Number.isFinite(value) && value >= 0) && rawUsage.prompt_tokens >= cacheRead + cacheWrite && rawUsage.total_tokens >= rawUsage.prompt_tokens + rawUsage.completion_tokens;
|
|
214
|
+
const usage = {
|
|
215
|
+
input,
|
|
216
|
+
output,
|
|
217
|
+
cacheRead,
|
|
218
|
+
cacheWrite,
|
|
219
|
+
...options?.includeReasoningTokens !== false && reasoningTokens !== void 0 ? { reasoningTokens } : {},
|
|
220
|
+
contextUsage: hasCoherentContext ? {
|
|
221
|
+
state: "available",
|
|
222
|
+
promptTokens: rawUsage.prompt_tokens,
|
|
223
|
+
totalTokens: Math.max(input + output + cacheRead + cacheWrite, rawUsage.total_tokens)
|
|
224
|
+
} : { state: "unavailable" },
|
|
225
|
+
totalTokens: input + output + cacheRead + cacheWrite,
|
|
226
|
+
cost: {
|
|
227
|
+
input: 0,
|
|
228
|
+
output: 0,
|
|
229
|
+
cacheRead: 0,
|
|
230
|
+
cacheWrite: 0,
|
|
231
|
+
total: 0
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
calculateCost(model, usage);
|
|
235
|
+
applyProviderReportedUsageCost(usage, rawUsage.cost);
|
|
236
|
+
return usage;
|
|
58
237
|
}
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const maxTailLength = 64 - params.prefix.length;
|
|
65
|
-
const hashSuffix = `_${hash}`;
|
|
66
|
-
const tail = `${sanitizeOpenAIResponsesIdTail(rawTail).slice(0, Math.max(1, maxTailLength - hashSuffix.length)) || "id"}${hashSuffix}`.slice(0, maxTailLength);
|
|
67
|
-
return `${params.prefix}${tail}`;
|
|
238
|
+
function createOpenAIResponseHook(onResponse, response, model) {
|
|
239
|
+
return onResponse ? () => onResponse({
|
|
240
|
+
status: response.status,
|
|
241
|
+
headers: headersToRecord(response.headers)
|
|
242
|
+
}, model) : void 0;
|
|
68
243
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
prefix: "call_",
|
|
75
|
-
isValid: (value) => OPENAI_RESPONSES_CALL_ID_RE.test(value)
|
|
244
|
+
function createOpenAIProviderAcceptanceHook(options, response, model) {
|
|
245
|
+
return () => notifyProviderHttpResponse({
|
|
246
|
+
options,
|
|
247
|
+
response,
|
|
248
|
+
model
|
|
76
249
|
});
|
|
77
|
-
if (!itemId) return normalizedCallId;
|
|
78
|
-
return `${normalizedCallId}|${normalizeOpenAIResponsesIdPart({
|
|
79
|
-
value: itemId,
|
|
80
|
-
prefix: "fc_",
|
|
81
|
-
isValid: (value) => OPENAI_RESPONSES_FUNCTION_CALL_ITEM_ID_RE.test(value)
|
|
82
|
-
})}`;
|
|
83
250
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
|
|
251
|
+
/** Measure one UTF-8 append without double-counting a surrogate pair split across chunks. */
|
|
252
|
+
function measureUtf8AppendBytes(bufferEndsWithHighSurrogate, chunk) {
|
|
253
|
+
let bytes = Buffer.byteLength(chunk, "utf8");
|
|
254
|
+
if (!chunk) return {
|
|
255
|
+
bytes,
|
|
256
|
+
endsWithHighSurrogate: bufferEndsWithHighSurrogate
|
|
257
|
+
};
|
|
258
|
+
const nextCodeUnit = chunk.charCodeAt(0);
|
|
259
|
+
if (bufferEndsWithHighSurrogate && nextCodeUnit >= 56320 && nextCodeUnit <= 57343) bytes -= 2;
|
|
260
|
+
const finalCodeUnit = chunk.charCodeAt(chunk.length - 1);
|
|
261
|
+
return {
|
|
262
|
+
bytes,
|
|
263
|
+
endsWithHighSurrogate: finalCodeUnit >= 55296 && finalCodeUnit <= 56319
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function resolvePromptCacheKey(options, cacheRetention) {
|
|
267
|
+
if (cacheRetention === "none") return;
|
|
268
|
+
return clampOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId);
|
|
269
|
+
}
|
|
270
|
+
function isOpenAICompletionsThinkingEnabled(effort) {
|
|
271
|
+
const normalized = effort.trim().toLowerCase();
|
|
272
|
+
return normalized !== "off" && normalized !== "none";
|
|
273
|
+
}
|
|
274
|
+
function readOpenAICompletionsContentDeltas(content, topLevelRefusal, mirroredThinking = []) {
|
|
275
|
+
let deltas = readOpenAICompletionsContentPartDeltas(content);
|
|
276
|
+
if (mirroredThinking.length > 0) {
|
|
277
|
+
const structuredThinking = deltas.filter((delta) => delta.kind === "thinking").map((delta) => delta.text);
|
|
278
|
+
const mirrorsCombinedThinking = structuredThinking.length > 1 && mirroredThinking.includes(structuredThinking.join(""));
|
|
279
|
+
deltas = deltas.filter((delta) => delta.kind !== "thinking" || !mirrorsCombinedThinking && !mirroredThinking.includes(delta.text));
|
|
280
|
+
}
|
|
281
|
+
if (typeof topLevelRefusal !== "string" || !topLevelRefusal) return deltas;
|
|
282
|
+
const structuredRefusals = deltas.filter((delta) => delta.kind === "text" && delta.source === "refusal").map((delta) => delta.text);
|
|
283
|
+
if (structuredRefusals.some((refusal) => refusal === topLevelRefusal) || structuredRefusals.length > 1 && structuredRefusals.join("") === topLevelRefusal) return deltas;
|
|
284
|
+
return [...deltas, {
|
|
285
|
+
kind: "text",
|
|
286
|
+
text: topLevelRefusal,
|
|
287
|
+
source: "refusal"
|
|
288
|
+
}];
|
|
289
|
+
}
|
|
290
|
+
function readOpenAICompletionsContentPartDeltas(content) {
|
|
291
|
+
if (typeof content === "string") return content ? [{
|
|
292
|
+
kind: "text",
|
|
293
|
+
text: content
|
|
294
|
+
}] : [];
|
|
295
|
+
if (Array.isArray(content)) return content.flatMap(readOpenAICompletionsContentPartDeltas);
|
|
296
|
+
if (!content || typeof content !== "object") return [];
|
|
297
|
+
const record = content;
|
|
298
|
+
const type = typeof record.type === "string" ? record.type.toLowerCase() : "";
|
|
299
|
+
const extractText = (value) => {
|
|
300
|
+
if (typeof value === "string") return value;
|
|
301
|
+
if (Array.isArray(value)) return value.map(extractText).join("");
|
|
302
|
+
if (value && typeof value === "object") {
|
|
303
|
+
const nested = value;
|
|
304
|
+
return extractText(nested.text ?? nested.content ?? nested.thinking ?? nested.refusal);
|
|
305
|
+
}
|
|
306
|
+
return "";
|
|
307
|
+
};
|
|
308
|
+
const text = extractText(record.text ?? record.content ?? record.thinking ?? record.refusal);
|
|
309
|
+
if (!text) return [];
|
|
310
|
+
if (type.includes("thinking") || type.includes("reasoning")) return [{
|
|
311
|
+
kind: "thinking",
|
|
312
|
+
text
|
|
313
|
+
}];
|
|
314
|
+
if (type === "refusal") return [{
|
|
315
|
+
kind: "text",
|
|
316
|
+
text,
|
|
317
|
+
source: "refusal"
|
|
318
|
+
}];
|
|
319
|
+
if (["text", "output_text"].includes(type) || type.endsWith(".output_text")) return [{
|
|
320
|
+
kind: "text",
|
|
321
|
+
text
|
|
322
|
+
}];
|
|
323
|
+
return [];
|
|
324
|
+
}
|
|
325
|
+
//#endregion
|
|
326
|
+
//#region packages/ai/src/providers/openai-tool-projection.ts
|
|
327
|
+
function unreadableToolDiagnostic(toolIndex) {
|
|
328
|
+
return {
|
|
329
|
+
toolIndex,
|
|
330
|
+
violations: [`tool[${toolIndex}] is unreadable`]
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
/** Snapshots direct/custom tool descriptors before OpenAI payload construction. */
|
|
334
|
+
function projectOpenAITools(tools) {
|
|
335
|
+
return projectOpenAIToolDescriptors(tools);
|
|
336
|
+
}
|
|
337
|
+
/** Package-private facts are consumed before the projection or payload can escape. */
|
|
338
|
+
function prepareOpenAITools(tools) {
|
|
339
|
+
const schemas = /* @__PURE__ */ new Map();
|
|
340
|
+
return {
|
|
341
|
+
projection: projectOpenAIToolDescriptors(tools, schemas),
|
|
342
|
+
schemas
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function projectOpenAIToolDescriptors(tools, schemas) {
|
|
346
|
+
let inputToolCount;
|
|
347
|
+
try {
|
|
348
|
+
inputToolCount = tools.length;
|
|
349
|
+
} catch {
|
|
350
|
+
return {
|
|
351
|
+
inputToolCount: 0,
|
|
352
|
+
tools: [],
|
|
353
|
+
diagnostics: [unreadableToolDiagnostic(0)]
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
const projectedTools = [];
|
|
357
|
+
const diagnostics = [];
|
|
358
|
+
for (let toolIndex = 0; toolIndex < inputToolCount; toolIndex += 1) {
|
|
359
|
+
let tool;
|
|
360
|
+
let name;
|
|
361
|
+
let parameters;
|
|
362
|
+
let readPath = `tool[${toolIndex}]`;
|
|
363
|
+
try {
|
|
364
|
+
const candidate = tools[toolIndex];
|
|
365
|
+
if (!candidate) {
|
|
366
|
+
diagnostics.push(unreadableToolDiagnostic(toolIndex));
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
tool = candidate;
|
|
370
|
+
readPath += ".name";
|
|
371
|
+
const nameValue = tool.name;
|
|
372
|
+
if (typeof nameValue !== "string" || !nameValue) {
|
|
373
|
+
diagnostics.push({
|
|
374
|
+
toolIndex,
|
|
375
|
+
violations: [`${readPath} is empty`]
|
|
376
|
+
});
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
name = nameValue;
|
|
380
|
+
readPath = `${name}.parameters`;
|
|
381
|
+
parameters = tool.parameters;
|
|
382
|
+
} catch {
|
|
383
|
+
diagnostics.push({
|
|
384
|
+
toolIndex,
|
|
385
|
+
...name ? { toolName: name } : {},
|
|
386
|
+
violations: [`${readPath} is unreadable`]
|
|
387
|
+
});
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const prepared = schemas ? prepareRuntimeToolInputSchema(parameters ?? {}, `${name}.parameters`) : void 0;
|
|
391
|
+
const schemaProjection = prepared?.projection ?? projectRuntimeToolInputSchema(parameters ?? {}, `${name}.parameters`);
|
|
392
|
+
if (!isRecord(schemaProjection.schema) || schemaProjection.violations.length > 0) {
|
|
393
|
+
diagnostics.push({
|
|
394
|
+
toolIndex,
|
|
395
|
+
toolName: name,
|
|
396
|
+
violations: schemaProjection.violations.length > 0 ? schemaProjection.violations : [`${name}.parameters must be a JSON object schema`]
|
|
397
|
+
});
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (prepared?.normalization) schemas?.set(schemaProjection.schema, prepared.normalization);
|
|
401
|
+
let descriptionValue;
|
|
402
|
+
try {
|
|
403
|
+
descriptionValue = tool.description;
|
|
404
|
+
} catch {}
|
|
405
|
+
const description = typeof descriptionValue === "string" ? descriptionValue : void 0;
|
|
406
|
+
projectedTools.push({
|
|
407
|
+
toolIndex,
|
|
408
|
+
name,
|
|
409
|
+
...description !== void 0 ? { description } : {},
|
|
410
|
+
parameters: schemaProjection.schema
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
inputToolCount,
|
|
415
|
+
tools: projectedTools,
|
|
416
|
+
diagnostics
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function reconcileToolChoice(choice, projection, responses) {
|
|
420
|
+
const label = responses ? "OpenAI Responses" : "OpenAI Chat Completions";
|
|
421
|
+
if (choice === "auto") return projection.tools.length > 0 ? choice : void 0;
|
|
422
|
+
if (choice === "required") {
|
|
423
|
+
if (projection.tools.length === 0) throw new Error(`${label} tool_choice requires a tool, but no tools survived schema conversion`);
|
|
424
|
+
return choice;
|
|
425
|
+
}
|
|
426
|
+
if (choice === "none" || !isRecord(choice)) return choice;
|
|
427
|
+
const choiceType = choice.type;
|
|
428
|
+
if (!responses && choiceType === "custom") throw new Error("OpenAI Chat Completions custom tool_choice is unsupported because this adapter emits function tools only");
|
|
429
|
+
if (choiceType === "function") {
|
|
430
|
+
const functionChoice = responses ? choice : choice.function;
|
|
431
|
+
const functionName = isRecord(functionChoice) ? functionChoice.name : void 0;
|
|
432
|
+
if (typeof functionName !== "string") return choice;
|
|
433
|
+
if (!projection.tools.some((tool) => tool.name === functionName)) throw new Error(`${label} tool_choice requested unavailable tool "${functionName}" after schema conversion`);
|
|
434
|
+
return responses ? {
|
|
435
|
+
type: "function",
|
|
436
|
+
name: functionName
|
|
437
|
+
} : {
|
|
438
|
+
type: "function",
|
|
439
|
+
function: { name: functionName }
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
if (choiceType !== "allowed_tools") return choice;
|
|
443
|
+
const allowedConfig = responses ? choice : choice.allowed_tools;
|
|
444
|
+
if (!isRecord(allowedConfig)) return choice;
|
|
445
|
+
const { mode, tools } = allowedConfig;
|
|
446
|
+
if (mode !== "auto" && mode !== "required" || !Array.isArray(tools)) return choice;
|
|
447
|
+
const responseTools = [];
|
|
448
|
+
const completionTools = [];
|
|
449
|
+
for (const tool of tools) {
|
|
450
|
+
if (!isRecord(tool) || tool.type !== "function") {
|
|
451
|
+
if (responses) responseTools.push(tool);
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
const functionChoice = responses ? tool : tool.function;
|
|
455
|
+
const functionName = isRecord(functionChoice) ? functionChoice.name : void 0;
|
|
456
|
+
if (typeof functionName === "string" && projection.tools.some((projectedTool) => projectedTool.name === functionName)) {
|
|
457
|
+
if (responses) responseTools.push({
|
|
458
|
+
type: "function",
|
|
459
|
+
name: functionName
|
|
460
|
+
});
|
|
461
|
+
else completionTools.push({
|
|
462
|
+
type: "function",
|
|
463
|
+
function: { name: functionName }
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (responseTools.length === 0 && completionTools.length === 0) {
|
|
468
|
+
if (mode === "auto") return "none";
|
|
469
|
+
throw new Error(`${label} tool_choice requires a tool, but no allowed tools survived schema conversion`);
|
|
470
|
+
}
|
|
471
|
+
return responses ? {
|
|
472
|
+
type: "allowed_tools",
|
|
473
|
+
mode,
|
|
474
|
+
tools: responseTools
|
|
475
|
+
} : {
|
|
476
|
+
type: "allowed_tools",
|
|
477
|
+
allowed_tools: {
|
|
478
|
+
mode,
|
|
479
|
+
tools: completionTools
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
/** Keeps Responses tool choices aligned with surviving function schemas. */
|
|
484
|
+
function reconcileOpenAIResponsesToolChoice(choice, projection) {
|
|
485
|
+
return reconcileToolChoice(choice, projection, true);
|
|
486
|
+
}
|
|
487
|
+
/** Keeps Chat Completions tool choices aligned with surviving function schemas. */
|
|
488
|
+
function reconcileOpenAICompletionsToolChoice(choice, projection) {
|
|
489
|
+
return reconcileToolChoice(choice, projection, false);
|
|
490
|
+
}
|
|
491
|
+
/** Re-expresses an object Chat Completions tool choice in the Responses wire shape. */
|
|
492
|
+
function toOpenAIResponsesToolChoice(choice) {
|
|
493
|
+
if (choice.type === "function") return {
|
|
494
|
+
type: "function",
|
|
495
|
+
name: choice.function.name
|
|
496
|
+
};
|
|
497
|
+
return {
|
|
498
|
+
type: "allowed_tools",
|
|
499
|
+
mode: choice.allowed_tools.mode,
|
|
500
|
+
tools: choice.allowed_tools.tools.map((tool) => tool.type === "function" && isRecord(tool.function) && typeof tool.function.name === "string" ? {
|
|
501
|
+
type: "function",
|
|
502
|
+
name: tool.function.name
|
|
503
|
+
} : tool)
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
//#endregion
|
|
507
|
+
//#region packages/ai/src/transports/openai-reasoning-compat.ts
|
|
508
|
+
/** Explicit model reasoning-effort compatibility metadata. */
|
|
509
|
+
function readCompatReasoningEffortMap(compat) {
|
|
510
|
+
const rawMap = asOptionalObjectRecord(asOptionalObjectRecord(compat)?.reasoningEffortMap);
|
|
511
|
+
if (!rawMap) return {};
|
|
512
|
+
return Object.fromEntries(Object.entries(rawMap).filter((entry) => typeof entry[1] === "string"));
|
|
513
|
+
}
|
|
514
|
+
/** Resolves the reasoning effort remap for an OpenAI-compatible model. */
|
|
515
|
+
function resolveOpenAIReasoningEffortMap(model, fallbackMap = {}) {
|
|
516
|
+
return {
|
|
517
|
+
...fallbackMap,
|
|
518
|
+
...readCompatReasoningEffortMap(model.compat)
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
//#endregion
|
|
522
|
+
//#region packages/ai/src/providers/openai-request-reasoning.ts
|
|
523
|
+
/** Preserve explicit off until the selected route maps it to its native value. */
|
|
524
|
+
function resolveOpenAISimpleReasoningEffort(model, reasoning) {
|
|
525
|
+
return reasoning === void 0 ? void 0 : clampThinkingLevel(model, reasoning);
|
|
526
|
+
}
|
|
527
|
+
function resolveOpenAIRequestReasoning(model, reasoning, offDefault = "none") {
|
|
528
|
+
const requested = normalizeOpenAIReasoningEffort(reasoning ?? "off");
|
|
529
|
+
const modelLevel = MODEL_CATALOG_THINKING_LEVELS.find((candidate) => candidate === requested);
|
|
530
|
+
const modelMapped = modelLevel ? model.thinkingLevelMap?.[modelLevel] : void 0;
|
|
531
|
+
const mapped = modelMapped === null ? null : resolveOpenAIReasoningEffortMapping(requested, resolveOpenAIReasoningEffortMap(model)) ?? modelMapped;
|
|
532
|
+
const intent = mapped !== void 0 ? mapped?.trim() : reasoning === void 0 || requested === "off" && offDefault === null ? void 0 : requested;
|
|
533
|
+
const normalizedIntent = normalizeOpenAIReasoningEffort(intent ?? "off");
|
|
534
|
+
const supported = resolveOpenAIModelReasoningEfforts(model);
|
|
535
|
+
const effort = !model.reasoning || supported?.length === 0 || intent === void 0 ? void 0 : supported === void 0 ? mapped !== void 0 ? intent : requested === "off" ? "none" : requested : resolveOpenAIReasoningEffortForModel({
|
|
536
|
+
model,
|
|
537
|
+
effort: requested,
|
|
538
|
+
fallbackMap: { [requested]: intent }
|
|
539
|
+
});
|
|
540
|
+
return {
|
|
541
|
+
effort: effort === "none" && resolveOpenAIThinkingApi(model.api) === "openai-chatgpt-responses" && !supportsOpenAIReasoningEffort(model.id === "gpt-6-sol" || model.id === "gpt-6-luna" ? model : { compat: model.compat }, "none") ? void 0 : effort,
|
|
542
|
+
thinkingEnabled: intent === void 0 ? void 0 : model.reasoning && normalizedIntent !== "off" && normalizedIntent !== "none"
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
//#endregion
|
|
546
|
+
//#region packages/ai/src/transports/openai-transport-params.ts
|
|
547
|
+
const MAX_OPENAI_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS = 256;
|
|
548
|
+
const loggedOpenAIStrictToolDowngradeDiagnosticKeys = /* @__PURE__ */ new Set();
|
|
549
|
+
const OPENAI_COMPLETIONS_APIS = /* @__PURE__ */ new Set(["openai-completions", "openclaw-openai-completions-transport"]);
|
|
550
|
+
function readToolPayloadField$1(record, field) {
|
|
551
|
+
try {
|
|
552
|
+
return Object.hasOwn(record, field) ? record[field] : void 0;
|
|
553
|
+
} catch {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
function readCodeModePayloadToolName(tool) {
|
|
558
|
+
if (!isRecord(tool)) return;
|
|
559
|
+
const name = readToolPayloadField$1(tool, "name");
|
|
560
|
+
if (typeof name === "string") return name;
|
|
561
|
+
const fn = readToolPayloadField$1(tool, "function");
|
|
562
|
+
if (!isRecord(fn)) return;
|
|
563
|
+
const fnName = readToolPayloadField$1(fn, "name");
|
|
564
|
+
return typeof fnName === "string" ? fnName : void 0;
|
|
565
|
+
}
|
|
566
|
+
function readCodeModePayloadToolIdentity(tool, visibleToolNames, allowedHostedToolTypes) {
|
|
567
|
+
if (!isRecord(tool)) return;
|
|
568
|
+
const type = readToolPayloadField$1(tool, "type");
|
|
569
|
+
if (typeof type === "string" && allowedHostedToolTypes?.has(type)) {
|
|
570
|
+
try {
|
|
571
|
+
if (Object.hasOwn(tool, "name") || Object.hasOwn(tool, "function") || Object.hasOwn(tool, "functionDeclarations") || Object.hasOwn(tool, "function_declarations")) return false;
|
|
572
|
+
} catch {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
return `hosted:${type}`;
|
|
576
|
+
}
|
|
577
|
+
const name = readCodeModePayloadToolName(tool);
|
|
578
|
+
return typeof name === "string" && isCodeModeModelVisibleToolName(name, visibleToolNames) ? `client:${name}` : void 0;
|
|
579
|
+
}
|
|
580
|
+
function readCodeModePayloadToolIdentities(payload) {
|
|
581
|
+
if (!isRecord(payload)) return [];
|
|
582
|
+
const tools = readToolPayloadField$1(payload, "tools");
|
|
583
|
+
if (!Array.isArray(tools)) return [];
|
|
584
|
+
return tools.flatMap((tool) => {
|
|
585
|
+
if (!isRecord(tool)) return [];
|
|
586
|
+
const identities = [];
|
|
587
|
+
const name = readCodeModePayloadToolName(tool);
|
|
588
|
+
if (name) identities.push(`client:${name}`);
|
|
589
|
+
for (const key of ["functionDeclarations", "function_declarations"]) {
|
|
590
|
+
const declarations = readToolPayloadField$1(tool, key);
|
|
591
|
+
if (!Array.isArray(declarations)) continue;
|
|
592
|
+
for (const declaration of declarations) {
|
|
593
|
+
const declarationName = readCodeModePayloadToolName(declaration);
|
|
594
|
+
if (declarationName) identities.push(`client:${declarationName}`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
const type = readToolPayloadField$1(tool, "type");
|
|
598
|
+
if (typeof type === "string" && type !== "function") identities.push(`hosted:${type}`);
|
|
599
|
+
return identities;
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
function filterCodeModePayloadTools(payload, visibleToolNames, allowedHostedToolTypes, observer) {
|
|
603
|
+
if (!isRecord(payload)) return;
|
|
604
|
+
const tools = readToolPayloadField$1(payload, "tools");
|
|
605
|
+
if (!Array.isArray(tools)) return;
|
|
606
|
+
const beforeToolIdentities = observer ? readCodeModePayloadToolIdentities(payload) : void 0;
|
|
607
|
+
payload.tools = tools.flatMap((tool) => {
|
|
608
|
+
const identity = readCodeModePayloadToolIdentity(tool, visibleToolNames, allowedHostedToolTypes);
|
|
609
|
+
if (identity) return [tool];
|
|
610
|
+
if (identity === false) return [];
|
|
611
|
+
if (!isRecord(tool)) return [];
|
|
612
|
+
const filteredGroups = {};
|
|
613
|
+
for (const key of ["functionDeclarations", "function_declarations"]) {
|
|
614
|
+
const declarations = readToolPayloadField$1(tool, key);
|
|
615
|
+
if (!Array.isArray(declarations)) continue;
|
|
616
|
+
const filtered = declarations.filter((declaration) => {
|
|
617
|
+
const declarationName = readCodeModePayloadToolName(declaration);
|
|
618
|
+
return typeof declarationName === "string" && isCodeModeModelVisibleToolName(declarationName, visibleToolNames);
|
|
619
|
+
});
|
|
620
|
+
if (filtered.length > 0) filteredGroups[key] = filtered;
|
|
621
|
+
}
|
|
622
|
+
return Object.keys(filteredGroups).length > 0 ? [filteredGroups] : [];
|
|
623
|
+
});
|
|
624
|
+
if (beforeToolIdentities) observer?.({
|
|
625
|
+
beforeToolIdentities,
|
|
626
|
+
afterToolIdentities: readCodeModePayloadToolIdentities(payload)
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
function resolveCodeModeResponsesVisibleToolNames(context) {
|
|
630
|
+
return new Set((context.tools ?? []).map(readCodeModePayloadToolName).filter((name) => typeof name === "string"));
|
|
631
|
+
}
|
|
632
|
+
function enforceCodeModeResponsesToolSurface(payload, visibleToolNames, allowedHostedToolTypes, observer) {
|
|
633
|
+
if (!isRecord(payload)) return;
|
|
634
|
+
const tools = readToolPayloadField$1(payload, "tools");
|
|
635
|
+
if (!Array.isArray(tools)) return;
|
|
636
|
+
const beforeToolIdentities = observer ? readCodeModePayloadToolIdentities(payload) : void 0;
|
|
637
|
+
payload.tools = tools.filter((tool) => Boolean(readCodeModePayloadToolIdentity(tool, visibleToolNames, allowedHostedToolTypes)));
|
|
638
|
+
if (beforeToolIdentities) observer?.({
|
|
639
|
+
beforeToolIdentities,
|
|
640
|
+
afterToolIdentities: readCodeModePayloadToolIdentities(payload)
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
function assertCodeModeResponsesToolSurface(payload, visibleToolNames, allowedHostedToolTypes) {
|
|
644
|
+
const tools = isRecord(payload) ? readToolPayloadField$1(payload, "tools") : void 0;
|
|
645
|
+
if (!Array.isArray(tools)) throw new Error("Code mode payload tool surface violation: expected exec,wait; got no tools");
|
|
646
|
+
const identities = tools.map((tool) => readCodeModePayloadToolIdentity(tool, visibleToolNames, allowedHostedToolTypes));
|
|
647
|
+
const names = identities.flatMap((identity) => typeof identity === "string" && identity.startsWith("client:") ? [identity.slice(7)] : []).toSorted((left, right) => left.localeCompare(right));
|
|
648
|
+
if (names.length >= 2 && identities.every((identity) => typeof identity === "string") && new Set(identities).size === identities.length && names.includes("exec") && names.includes("wait")) return;
|
|
649
|
+
throw new Error(`Code mode payload tool surface violation: expected exec,wait plus direct-only tools; got ${names.length > 0 ? names.join(",") : "none"}`);
|
|
650
|
+
}
|
|
651
|
+
function resolveOpenAIStrictToolFlagWithDiagnostics(projection, strictSetting, context) {
|
|
652
|
+
const strict = resolveOpenAIProjectedToolsStrictToolFlag(projection, strictSetting);
|
|
653
|
+
if (strictSetting === true && strict === false) getAiTransportHost().logDebug("openai-transport", () => {
|
|
654
|
+
const diagnostics = findOpenAIStrictToolProjectionDiagnostics(projection);
|
|
655
|
+
const key = sha256Hex(JSON.stringify({
|
|
656
|
+
transport: context.transport,
|
|
657
|
+
provider: context.model.provider ?? null,
|
|
658
|
+
model: context.model.id ?? null,
|
|
659
|
+
diagnostics: diagnostics.map((entry) => ({
|
|
660
|
+
toolIndex: entry.toolIndex,
|
|
661
|
+
toolName: entry.toolName ?? null,
|
|
662
|
+
violations: entry.violations
|
|
663
|
+
}))
|
|
664
|
+
}));
|
|
665
|
+
if (loggedOpenAIStrictToolDowngradeDiagnosticKeys.has(key)) return null;
|
|
666
|
+
if (loggedOpenAIStrictToolDowngradeDiagnosticKeys.size >= MAX_OPENAI_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS) loggedOpenAIStrictToolDowngradeDiagnosticKeys.clear();
|
|
667
|
+
loggedOpenAIStrictToolDowngradeDiagnosticKeys.add(key);
|
|
668
|
+
const sample = diagnostics.slice(0, 5).map((entry) => ({
|
|
669
|
+
tool: entry.toolName ?? `tool[${entry.toolIndex}]`,
|
|
670
|
+
violations: entry.violations.slice(0, 8)
|
|
671
|
+
}));
|
|
672
|
+
return {
|
|
673
|
+
message: `OpenAI ${context.transport} tool schema strict mode downgraded to strict=false for ${context.model.provider ?? "unknown"}/${context.model.id ?? "unknown"} because ${diagnostics.length} tool schema(s) are not strict-compatible`,
|
|
674
|
+
data: {
|
|
675
|
+
transport: context.transport,
|
|
676
|
+
provider: context.model.provider,
|
|
677
|
+
model: context.model.id,
|
|
678
|
+
incompatibleToolCount: diagnostics.length,
|
|
679
|
+
sample
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
});
|
|
683
|
+
return strict;
|
|
684
|
+
}
|
|
685
|
+
function buildOpenAIClientHeaders(model, context, optionHeaders, turnHeaders, sessionId, cacheRetention) {
|
|
686
|
+
const providerHeaders = { ...model.headers };
|
|
687
|
+
if (model.provider === "github-copilot") Object.assign(providerHeaders, getAiTransportHost().buildCopilotDynamicHeaders(context.messages));
|
|
688
|
+
if (OPENAI_COMPLETIONS_APIS.has(model.api) && sessionId && cacheRetention !== "none") {
|
|
689
|
+
const { sessionAffinity } = resolveOpenAICompletionsCompat(model);
|
|
690
|
+
if (sessionAffinity !== "none") {
|
|
691
|
+
const affinityValue = clampOpenAIPromptCacheKey(sessionId) ?? sessionId;
|
|
692
|
+
const affinityHeaders = sessionAffinity === "openrouter" ? ["x-session-id"] : [
|
|
693
|
+
"session_id",
|
|
694
|
+
"x-client-request-id",
|
|
695
|
+
"x-session-affinity"
|
|
696
|
+
];
|
|
697
|
+
const configuredHeaders = new Set(Object.keys(providerHeaders).map((key) => key.toLowerCase()));
|
|
698
|
+
for (const name of affinityHeaders) if (!configuredHeaders.has(name)) providerHeaders[name] = affinityValue;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const callerHeaders = {
|
|
702
|
+
...optionHeaders,
|
|
703
|
+
...turnHeaders
|
|
704
|
+
};
|
|
705
|
+
const resolvedHeaders = getAiTransportHost().resolveProviderRequestHeaders({
|
|
706
|
+
provider: model.provider,
|
|
707
|
+
api: model.api,
|
|
708
|
+
baseUrl: model.baseUrl,
|
|
709
|
+
providerHeaders,
|
|
710
|
+
callerHeaders: Object.keys(callerHeaders).length > 0 ? callerHeaders : void 0,
|
|
711
|
+
precedence: "caller-wins",
|
|
712
|
+
model
|
|
713
|
+
}) ?? {};
|
|
714
|
+
const sendSessionIdHeader = (OPENAI_RESPONSES_APIS.has(model.api) && model.compat && "sendSessionIdHeader" in model.compat ? model.compat?.sendSessionIdHeader : void 0) ?? usesNativeOpenAICodexResponsesBackend(model);
|
|
715
|
+
if (sessionId && cacheRetention !== "none" && sendSessionIdHeader && !Object.keys(resolvedHeaders).some((key) => normalizeLowercaseStringOrEmpty(key) === "session_id")) resolvedHeaders.session_id = clampOpenAIPromptCacheKey(sessionId) ?? sessionId;
|
|
716
|
+
return resolveOpencodeSessionHeaders(model, {
|
|
717
|
+
sessionId,
|
|
718
|
+
headers: resolvedHeaders
|
|
719
|
+
}) ?? resolvedHeaders;
|
|
720
|
+
}
|
|
721
|
+
function buildOpenAISdkClientOptions(model) {
|
|
722
|
+
const timeout = resolveModelRequestTimeoutMs(model);
|
|
723
|
+
return {
|
|
724
|
+
...timeout === void 0 ? {} : { timeout },
|
|
725
|
+
maxRetries: 0
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
function buildOpenAISdkRequestOptions(model, signal, options) {
|
|
729
|
+
const timeout = resolveModelRequestTimeoutMs(model, options?.timeoutMs);
|
|
730
|
+
const headers = options?.stream === true && usesNativeOpenAICodexResponsesBackend(model) ? { Accept: "text/event-stream" } : void 0;
|
|
731
|
+
if (timeout === void 0 && !signal && !headers) return;
|
|
732
|
+
return {
|
|
733
|
+
...headers ? { headers } : {},
|
|
734
|
+
...signal ? { signal } : {},
|
|
735
|
+
...timeout !== void 0 ? { timeout } : {},
|
|
736
|
+
maxRetries: 0
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
function getCompat(model) {
|
|
740
|
+
const resolved = resolveOpenAICompletionsCompat(model);
|
|
741
|
+
const compat = model.compat ?? {};
|
|
742
|
+
return {
|
|
743
|
+
...resolved,
|
|
744
|
+
reasoningEffortMap: resolveOpenAIReasoningEffortMap(model, {}),
|
|
745
|
+
openRouterRouting: resolved.openRouterRouting ?? {},
|
|
746
|
+
requiresStringContent: compat.requiresStringContent ?? false,
|
|
747
|
+
strictMessageKeys: compat.strictMessageKeys === true
|
|
748
|
+
};
|
|
89
749
|
}
|
|
90
750
|
//#endregion
|
|
91
751
|
//#region packages/ai/src/transports/openai-responses-compaction-replay.ts
|
|
@@ -94,8 +754,8 @@ const OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA = "rejected";
|
|
|
94
754
|
function isOpenAIResponsesCompactionState(state) {
|
|
95
755
|
if (typeof state.baseUrlHash !== "string" || state.v !== 1) return false;
|
|
96
756
|
if (state.type === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE) return state.data === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA;
|
|
97
|
-
|
|
98
|
-
return state.type === "openai-responses-compaction" && typeof state.data === "string" && state.data.length > 0 && (state.id === void 0 || typeof state.id === "string") && (state.replayIndex === void 0 || typeof state.replayIndex === "number" && Number.isSafeInteger(state.replayIndex) && state.replayIndex >= 0);
|
|
757
|
+
const retained = state.type === OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE;
|
|
758
|
+
return (retained || 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 || !retained && typeof state.replayIndex === "number" && Number.isSafeInteger(state.replayIndex) && state.replayIndex >= 0);
|
|
99
759
|
}
|
|
100
760
|
function readOpenAIResponsesCompactionReplayState(value) {
|
|
101
761
|
return isRecord(value) && isProviderReplayContext(value) && isOpenAIResponsesCompactionState(value) ? value : void 0;
|
|
@@ -289,6 +949,50 @@ function replayResponsesReasoningUpdates(previous, request, previousOutputLength
|
|
|
289
949
|
};
|
|
290
950
|
}
|
|
291
951
|
//#endregion
|
|
952
|
+
//#region packages/ai/src/transports/openai-responses-tool-call-id-shape.ts
|
|
953
|
+
/**
|
|
954
|
+
* Pure OpenAI Responses `call_*`/`fc_*` tool-call-id shape helpers.
|
|
955
|
+
*
|
|
956
|
+
* Moved out of embedded-agent-helpers/openai.ts (the AgentMessage[]-walking
|
|
957
|
+
* caller lives in src/agents and imports from packages/ai, so the reverse
|
|
958
|
+
* import direction is not available) so the continuation transport can
|
|
959
|
+
* recognize its own cached raw ids after this same reshaping and restore
|
|
960
|
+
* them on a replayed wire request -- see openai-responses-continuation.ts.
|
|
961
|
+
*/
|
|
962
|
+
const OPENAI_RESPONSES_ID_MAX_LENGTH = 64;
|
|
963
|
+
const OPENAI_RESPONSES_CALL_ID_RE = /^call_[A-Za-z0-9_-]{1,59}$/;
|
|
964
|
+
const OPENAI_RESPONSES_FUNCTION_CALL_ITEM_ID_RE = /^fc_[A-Za-z0-9_-]{1,61}$/;
|
|
965
|
+
function splitOpenAIFunctionCallPairing(id) {
|
|
966
|
+
const separator = id.indexOf("|");
|
|
967
|
+
if (separator <= 0 || separator >= id.length - 1) return { callId: id };
|
|
968
|
+
return {
|
|
969
|
+
callId: id.slice(0, separator),
|
|
970
|
+
itemId: id.slice(separator + 1)
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
function normalizeOpenAIResponsesIdPart(value, prefix) {
|
|
974
|
+
const trimmed = value.trim();
|
|
975
|
+
if ((prefix === "call_" ? OPENAI_RESPONSES_CALL_ID_RE : OPENAI_RESPONSES_FUNCTION_CALL_ITEM_ID_RE).test(trimmed)) return trimmed;
|
|
976
|
+
const rawTail = trimmed.startsWith(prefix) ? trimmed.slice(prefix.length) : trimmed;
|
|
977
|
+
const hash = sha256Hex(trimmed || prefix).slice(0, 10);
|
|
978
|
+
const maxTailLength = 64 - prefix.length;
|
|
979
|
+
const hashSuffix = `_${hash}`;
|
|
980
|
+
return `${prefix}${`${rawTail.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "").slice(0, Math.max(1, maxTailLength - hashSuffix.length)) || "id"}${hashSuffix}`.slice(0, maxTailLength)}`;
|
|
981
|
+
}
|
|
982
|
+
/** Same shaping `normalizeOpenAIResponsesToolCallIds` applies to a replayed `call_id`/`call_id|fc_id` pair. */
|
|
983
|
+
function normalizeOpenAIResponsesFunctionCallId(id) {
|
|
984
|
+
const { callId, itemId } = splitOpenAIFunctionCallPairing(id);
|
|
985
|
+
const normalizedCallId = normalizeOpenAIResponsesIdPart(itemId ? `${callId}|${itemId}` : callId, "call_");
|
|
986
|
+
if (!itemId) return normalizedCallId;
|
|
987
|
+
return `${normalizedCallId}|${normalizeOpenAIResponsesIdPart(itemId, "fc_")}`;
|
|
988
|
+
}
|
|
989
|
+
function shouldNormalizeOpenAIResponsesToolCallId(id) {
|
|
990
|
+
const pairing = splitOpenAIFunctionCallPairing(id);
|
|
991
|
+
if (!OPENAI_RESPONSES_CALL_ID_RE.test(pairing.callId)) return true;
|
|
992
|
+
if (pairing.itemId === void 0) return false;
|
|
993
|
+
return !OPENAI_RESPONSES_FUNCTION_CALL_ITEM_ID_RE.test(pairing.itemId);
|
|
994
|
+
}
|
|
995
|
+
//#endregion
|
|
292
996
|
//#region packages/ai/src/transports/openai-responses-continuation.ts
|
|
293
997
|
const HTTP_CONTINUATION_IDLE_TTL_MS = 54e5;
|
|
294
998
|
const MAX_HTTP_CONTINUATION_READY_ENTRIES = 1e3;
|
|
@@ -351,13 +1055,9 @@ function pendingResponsesToolCalls(calls, input) {
|
|
|
351
1055
|
for (const [inputIndex, item] of input.entries()) {
|
|
352
1056
|
if (!isRecord(item) || typeof item.call_id !== "string") continue;
|
|
353
1057
|
const owner = ownerByReplayShape.get(item.call_id);
|
|
354
|
-
if (item.type === "function_call")
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
continue;
|
|
358
|
-
}
|
|
359
|
-
if (item.type !== "function_call_output") continue;
|
|
360
|
-
if (owner !== void 0 && owner !== null) lastOutputPosition.set(owner, inputIndex);
|
|
1058
|
+
if (item.type === "function_call") replayedCallIds.add(item.call_id);
|
|
1059
|
+
const positions = item.type === "function_call" ? lastCallPosition : item.type === "function_call_output" ? lastOutputPosition : void 0;
|
|
1060
|
+
if (positions && owner !== void 0 && owner !== null) positions.set(owner, inputIndex);
|
|
361
1061
|
}
|
|
362
1062
|
return calls.filter((_call, index) => {
|
|
363
1063
|
const callPosition = lastCallPosition.get(index);
|
|
@@ -516,7 +1216,7 @@ function resolveResponsesContinuationRequest(continuation, request, steering) {
|
|
|
516
1216
|
};
|
|
517
1217
|
const replayedToolRoundInput = currentInput.slice(previousInput.length, baselineLength);
|
|
518
1218
|
const replayedToolRound = normalizeAssistantReplayInput(replayedToolRoundInput);
|
|
519
|
-
const historyToolRoundUnchanged =
|
|
1219
|
+
const historyToolRoundUnchanged = [false, true].some((ignoreCachedItemIds) => jsonValuesEqual(replayedToolRound, normalizeAssistantReplayInput(continuation.lastResponseItems, true, ignoreCachedItemIds)));
|
|
520
1220
|
if (!continuationHistoryMatches(previousInput, currentInput.slice(0, previousInput.length)) || !historyToolRoundUnchanged) return {
|
|
521
1221
|
request,
|
|
522
1222
|
continuationStatus: "history_changed"
|
|
@@ -540,6 +1240,14 @@ function resolveResponsesContinuationRequest(continuation, request, steering) {
|
|
|
540
1240
|
const httpContinuationEntries = /* @__PURE__ */ new Map();
|
|
541
1241
|
const readyHttpContinuationEntries = /* @__PURE__ */ new Map();
|
|
542
1242
|
let httpContinuationRetainedBytes = 0;
|
|
1243
|
+
function createHttpContinuationTimer(key) {
|
|
1244
|
+
const timer = setTimeout(() => {
|
|
1245
|
+
const entry = httpContinuationEntries.get(key);
|
|
1246
|
+
if (entry?.kind === "ready" && entry.idleTimer === timer) deleteHttpContinuationIfOwned(key, entry);
|
|
1247
|
+
}, HTTP_CONTINUATION_IDLE_TTL_MS);
|
|
1248
|
+
timer.unref?.();
|
|
1249
|
+
return timer;
|
|
1250
|
+
}
|
|
543
1251
|
function deleteHttpContinuationIfOwned(key, entry) {
|
|
544
1252
|
if (httpContinuationEntries.get(key) !== entry) return;
|
|
545
1253
|
if (entry.kind === "ready") {
|
|
@@ -573,7 +1281,7 @@ function claimOpenAIResponsesHttpContinuation(params) {
|
|
|
573
1281
|
const key = `${getSessionResourceOwnerId(owner)}\0${params.sessionId}\0${connectionIdentity(params)}`;
|
|
574
1282
|
const previous = httpContinuationEntries.get(key);
|
|
575
1283
|
if (previous?.kind === "claimed") return;
|
|
576
|
-
if (previous
|
|
1284
|
+
if (previous) deleteHttpContinuationIfOwned(key, previous);
|
|
577
1285
|
const claimed = {
|
|
578
1286
|
kind: "claimed",
|
|
579
1287
|
sessionId: params.sessionId,
|
|
@@ -581,15 +1289,15 @@ function claimOpenAIResponsesHttpContinuation(params) {
|
|
|
581
1289
|
};
|
|
582
1290
|
httpContinuationEntries.set(key, claimed);
|
|
583
1291
|
try {
|
|
584
|
-
const request = previous
|
|
585
|
-
const resolved = resolveResponsesContinuationRequest(previous?.
|
|
1292
|
+
const request = previous ? params.request : params.restoreRequest?.() ?? params.request;
|
|
1293
|
+
const resolved = resolveResponsesContinuationRequest(previous?.state, request);
|
|
586
1294
|
const fullRequest = resolved.fullRequest ?? request;
|
|
587
1295
|
return {
|
|
588
1296
|
request: params.request.store === false ? fullRequest : resolved.request,
|
|
589
1297
|
fullRequest,
|
|
590
1298
|
commit: (effectiveRequest, response, dispatchedPreviousResponseId) => {
|
|
591
1299
|
if (httpContinuationEntries.get(key) !== claimed) return;
|
|
592
|
-
const state = recordResponsesContinuationState(previous?.
|
|
1300
|
+
const state = recordResponsesContinuationState(previous?.state, effectiveRequest, response, previous !== void 0 && dispatchedPreviousResponseId === previous.state.lastResponseId);
|
|
593
1301
|
const retainedBytes = Buffer.byteLength(JSON.stringify(state), "utf8");
|
|
594
1302
|
if (httpContinuationEntries.get(key) !== claimed) return;
|
|
595
1303
|
if (retainedBytes > MAX_HTTP_CONTINUATION_RETAINED_BYTES) {
|
|
@@ -601,10 +1309,9 @@ function claimOpenAIResponsesHttpContinuation(params) {
|
|
|
601
1309
|
...claimed,
|
|
602
1310
|
kind: "ready",
|
|
603
1311
|
state,
|
|
604
|
-
idleTimer:
|
|
1312
|
+
idleTimer: owner.runInDetachedAsyncContext(() => createHttpContinuationTimer(key)),
|
|
605
1313
|
retainedBytes
|
|
606
1314
|
};
|
|
607
|
-
ready.idleTimer.unref?.();
|
|
608
1315
|
httpContinuationRetainedBytes += retainedBytes;
|
|
609
1316
|
httpContinuationEntries.set(key, ready);
|
|
610
1317
|
readyHttpContinuationEntries.set(key, ready);
|
|
@@ -681,36 +1388,32 @@ function createResponsesInputReplay(model) {
|
|
|
681
1388
|
};
|
|
682
1389
|
}
|
|
683
1390
|
//#endregion
|
|
1391
|
+
//#region packages/ai/src/transports/openai-responses-replay.ts
|
|
1392
|
+
/** Resolves the assistant message id that can be replayed to OpenAI Responses. */
|
|
1393
|
+
function resolveReplayableResponsesMessageId(params) {
|
|
1394
|
+
if (!params.replayResponsesItemIds) return;
|
|
1395
|
+
if (!params.textSignatureId) return params.fallbackOrdinal === 0 ? params.fallbackId : `${params.fallbackId}_${params.fallbackOrdinal}`;
|
|
1396
|
+
return params.previousReplayItemWasReasoning ? params.textSignatureId : void 0;
|
|
1397
|
+
}
|
|
1398
|
+
//#endregion
|
|
684
1399
|
//#region packages/ai/src/transports/openai-responses-replay-messages-internal.ts
|
|
685
1400
|
function resolveResponsesInstructionRole(model) {
|
|
686
1401
|
const supportsDeveloperRole = !isRecord(model.compat) || model.compat.supportsDeveloperRole !== false;
|
|
687
1402
|
return model.reasoning && supportsDeveloperRole ? "developer" : "system";
|
|
688
1403
|
}
|
|
689
1404
|
function stripEncryptedReasoningContentFields(value) {
|
|
690
|
-
if (!value || typeof value !== "object") return
|
|
691
|
-
value,
|
|
692
|
-
changed: false
|
|
693
|
-
};
|
|
1405
|
+
if (!value || typeof value !== "object") return value;
|
|
694
1406
|
if (Array.isArray(value)) {
|
|
695
1407
|
let changed = false;
|
|
696
1408
|
const next = value.map((item) => {
|
|
697
1409
|
const stripped = stripEncryptedReasoningContentFields(item);
|
|
698
|
-
changed ||= stripped
|
|
699
|
-
return stripped
|
|
1410
|
+
changed ||= !Object.is(stripped, item);
|
|
1411
|
+
return stripped;
|
|
700
1412
|
});
|
|
701
|
-
return changed ?
|
|
702
|
-
value: next,
|
|
703
|
-
changed: true
|
|
704
|
-
} : {
|
|
705
|
-
value,
|
|
706
|
-
changed: false
|
|
707
|
-
};
|
|
1413
|
+
return changed ? next : value;
|
|
708
1414
|
}
|
|
709
1415
|
const source = value;
|
|
710
|
-
if (source.type === "compaction") return
|
|
711
|
-
value,
|
|
712
|
-
changed: false
|
|
713
|
-
};
|
|
1416
|
+
if (source.type === "compaction") return value;
|
|
714
1417
|
let changed = false;
|
|
715
1418
|
const next = {};
|
|
716
1419
|
for (const [key, child] of Object.entries(source)) {
|
|
@@ -719,21 +1422,13 @@ function stripEncryptedReasoningContentFields(value) {
|
|
|
719
1422
|
continue;
|
|
720
1423
|
}
|
|
721
1424
|
const stripped = stripEncryptedReasoningContentFields(child);
|
|
722
|
-
changed ||= stripped
|
|
723
|
-
next[key] = stripped
|
|
1425
|
+
changed ||= !Object.is(stripped, child);
|
|
1426
|
+
next[key] = stripped;
|
|
724
1427
|
}
|
|
725
|
-
return changed ?
|
|
726
|
-
value: next,
|
|
727
|
-
changed: true
|
|
728
|
-
} : {
|
|
729
|
-
value,
|
|
730
|
-
changed: false
|
|
731
|
-
};
|
|
1428
|
+
return changed ? next : value;
|
|
732
1429
|
}
|
|
733
1430
|
function isOpenAIResponsesReasoningReplayMetadata(value) {
|
|
734
|
-
|
|
735
|
-
const record = value;
|
|
736
|
-
return record.v === 1 && record.source === "openai-responses";
|
|
1431
|
+
return isProviderReplayContext(value) && value.v === 1 && value.source === "openai-responses";
|
|
737
1432
|
}
|
|
738
1433
|
function readOpenAIResponsesReasoningReplayBlockMetadata(block) {
|
|
739
1434
|
if (!Object.hasOwn(block, "openclawReasoningReplay")) return;
|
|
@@ -741,26 +1436,23 @@ function readOpenAIResponsesReasoningReplayBlockMetadata(block) {
|
|
|
741
1436
|
return isOpenAIResponsesReasoningReplayMetadata(value) ? value : null;
|
|
742
1437
|
}
|
|
743
1438
|
function normalizeOpenAIResponsesReasoningReplayItem(item) {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
return {
|
|
747
|
-
...record,
|
|
1439
|
+
return Array.isArray(item.summary) ? item : {
|
|
1440
|
+
...item,
|
|
748
1441
|
summary: []
|
|
749
1442
|
};
|
|
750
1443
|
}
|
|
751
1444
|
function prepareOpenAIResponsesReasoningItemForReplay(item, context, blockMetadata, options) {
|
|
752
|
-
const
|
|
753
|
-
const
|
|
754
|
-
const { [OPENAI_RESPONSES_REASONING_REPLAY_META_KEY]: rawMetadata, ...rest } = record;
|
|
1445
|
+
const hasRawMetadata = Object.hasOwn(item, OPENAI_RESPONSES_REASONING_REPLAY_META_KEY);
|
|
1446
|
+
const { [OPENAI_RESPONSES_REASONING_REPLAY_META_KEY]: rawMetadata, ...rest } = item;
|
|
755
1447
|
if (!("encrypted_content" in rest)) return normalizeOpenAIResponsesReasoningReplayItem(rest);
|
|
756
1448
|
const metadata = blockMetadata !== void 0 ? blockMetadata ?? void 0 : isOpenAIResponsesReasoningReplayMetadata(rawMetadata) ? rawMetadata : void 0;
|
|
757
1449
|
if (blockMetadata === void 0 && !hasRawMetadata && options?.preserveUnattributedEncryptedContent === true || metadata && providerReplayContextMatches(metadata, context)) return normalizeOpenAIResponsesReasoningReplayItem(rest);
|
|
758
|
-
return normalizeOpenAIResponsesReasoningReplayItem(stripEncryptedReasoningContentFields(rest)
|
|
1450
|
+
return normalizeOpenAIResponsesReasoningReplayItem(stripEncryptedReasoningContentFields(rest));
|
|
759
1451
|
}
|
|
760
|
-
function normalizeResponsesReplayItemId(id
|
|
1452
|
+
function normalizeResponsesReplayItemId(id) {
|
|
761
1453
|
if (!id) return;
|
|
762
1454
|
if (id.length <= 64) return id;
|
|
763
|
-
return
|
|
1455
|
+
return `msg_${shortHash(id)}`;
|
|
764
1456
|
}
|
|
765
1457
|
function orderResponsesAsyncToolResults(source) {
|
|
766
1458
|
const turnKey = (message) => {
|
|
@@ -898,6 +1590,7 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
|
|
|
898
1590
|
}
|
|
899
1591
|
let msgIndex = 0;
|
|
900
1592
|
const appendAssistant = createResponsesInputReplay(model);
|
|
1593
|
+
const inHistorySystemUpdates = supportsNativeOpenAIResponsesEndpoint(model);
|
|
901
1594
|
for (const msg of replayMessages) {
|
|
902
1595
|
if (!("role" in msg)) {
|
|
903
1596
|
messages.push(msg);
|
|
@@ -908,22 +1601,20 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
|
|
|
908
1601
|
text: sanitizeTransportPayloadText(runtimeContextContentToText(msg.content))
|
|
909
1602
|
}]));
|
|
910
1603
|
else if (msg.role === "user") {
|
|
911
|
-
|
|
1604
|
+
const role = msg.operatorMessage && inHistorySystemUpdates && (typeof msg.content === "string" || msg.content.every((block) => block.type === "text")) ? resolveResponsesInstructionRole(model) : "user";
|
|
1605
|
+
const content = typeof msg.content === "string" ? [{
|
|
912
1606
|
type: "input_text",
|
|
913
1607
|
text: sanitizeTransportPayloadText(msg.content)
|
|
914
|
-
}]
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
if (content.length > 0) messages.push(buildResponsesInputMessage("user", content, msg));
|
|
925
|
-
else if (providerStyle) continue;
|
|
926
|
-
}
|
|
1608
|
+
}] : msg.content.map((item) => item.type === "text" ? {
|
|
1609
|
+
type: "input_text",
|
|
1610
|
+
text: sanitizeTransportPayloadText(item.text)
|
|
1611
|
+
} : {
|
|
1612
|
+
type: "input_image",
|
|
1613
|
+
detail: "auto",
|
|
1614
|
+
image_url: `data:${item.mimeType};base64,${item.data}`
|
|
1615
|
+
}).filter((item) => providerStyle || model.input.includes("image") || item.type !== "input_image");
|
|
1616
|
+
if (content.length > 0) messages.push(buildResponsesInputMessage(role, content, msg));
|
|
1617
|
+
else if (providerStyle) continue;
|
|
927
1618
|
} else if (msg.role === "assistant") {
|
|
928
1619
|
const output = [];
|
|
929
1620
|
let textFallbackOrdinal = 0;
|
|
@@ -954,7 +1645,7 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
|
|
|
954
1645
|
previousReplayItemWasReasoning
|
|
955
1646
|
});
|
|
956
1647
|
if (!textSignature?.id) textFallbackOrdinal += 1;
|
|
957
|
-
msgId = normalizeResponsesReplayItemId(msgId
|
|
1648
|
+
msgId = normalizeResponsesReplayItemId(msgId);
|
|
958
1649
|
const messageItem = {
|
|
959
1650
|
type: "message",
|
|
960
1651
|
role: "assistant",
|
|
@@ -993,8 +1684,7 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
|
|
|
993
1684
|
if (output.length === 0 && providerStyle) continue;
|
|
994
1685
|
} else if (msg.role === "toolResult") {
|
|
995
1686
|
const textResult = extractToolResultText(msg.content);
|
|
996
|
-
const
|
|
997
|
-
const hasText = sanitizedTextResult.trim().length > 0;
|
|
1687
|
+
const hasText = textResult.trim().length > 0;
|
|
998
1688
|
const mediaPlaceholder = describeToolResultMediaPlaceholder(msg.content);
|
|
999
1689
|
const hasImages = msg.content.some(isImageWithMediaPayload);
|
|
1000
1690
|
const separatorIndex = msg.toolCallId.indexOf("|");
|
|
@@ -1004,7 +1694,7 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
|
|
|
1004
1694
|
call_id: callId,
|
|
1005
1695
|
output: hasImages && model.input.includes("image") ? [...hasText ? [{
|
|
1006
1696
|
type: "input_text",
|
|
1007
|
-
text:
|
|
1697
|
+
text: textResult
|
|
1008
1698
|
}] : mediaPlaceholder === "(see attached media)" ? [{
|
|
1009
1699
|
type: "input_text",
|
|
1010
1700
|
text: mediaPlaceholder
|
|
@@ -1012,7 +1702,7 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
|
|
|
1012
1702
|
type: "input_image",
|
|
1013
1703
|
detail: "auto",
|
|
1014
1704
|
image_url: `data:${item.mimeType};base64,${item.data}`
|
|
1015
|
-
}))] :
|
|
1705
|
+
}))] : hasText ? textResult : mediaPlaceholder ?? "(no output)"
|
|
1016
1706
|
});
|
|
1017
1707
|
}
|
|
1018
1708
|
msgIndex += 1;
|
|
@@ -1100,10 +1790,10 @@ function isProviderMessage(message) {
|
|
|
1100
1790
|
}
|
|
1101
1791
|
//#endregion
|
|
1102
1792
|
//#region packages/ai/src/transports/openai-responses-debug.ts
|
|
1103
|
-
function stringifyUnknown(value
|
|
1793
|
+
function stringifyUnknown(value) {
|
|
1104
1794
|
if (typeof value === "string") return value;
|
|
1105
1795
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1106
|
-
return
|
|
1796
|
+
return "";
|
|
1107
1797
|
}
|
|
1108
1798
|
function safeDebugValue(value) {
|
|
1109
1799
|
if (value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
|
|
@@ -1361,6 +2051,19 @@ function summarizeOpenAITransportError(error) {
|
|
|
1361
2051
|
function isAsyncIterable(value) {
|
|
1362
2052
|
return (typeof value === "object" && value !== null || typeof value === "function") && Symbol.asyncIterator in value;
|
|
1363
2053
|
}
|
|
2054
|
+
function readResponsesRecoveryEvent(event) {
|
|
2055
|
+
const record = isRecord(event) ? event : void 0;
|
|
2056
|
+
const response = isRecord(record?.response) ? record.response : void 0;
|
|
2057
|
+
return {
|
|
2058
|
+
failure: record?.type === "response.failed" ? response?.error : record?.type === "error" ? record.error ?? record : void 0,
|
|
2059
|
+
hasResponseOutput: Array.isArray(response?.output) && response.output.length > 0,
|
|
2060
|
+
isPrelude: record !== void 0 && [
|
|
2061
|
+
"response.created",
|
|
2062
|
+
"response.in_progress",
|
|
2063
|
+
"response.queued"
|
|
2064
|
+
].includes(String(record.type))
|
|
2065
|
+
};
|
|
2066
|
+
}
|
|
1364
2067
|
function isInvalidEncryptedContentError(error) {
|
|
1365
2068
|
if (!error || typeof error !== "object") return false;
|
|
1366
2069
|
const record = error;
|
|
@@ -1379,10 +2082,9 @@ function commitResponsesEncryptedContentAttempt(attempt, commit) {
|
|
|
1379
2082
|
}
|
|
1380
2083
|
function stripResponsesRequestEncryptedReasoning(request) {
|
|
1381
2084
|
const stripped = stripEncryptedReasoningContentFields(request.input);
|
|
1382
|
-
|
|
1383
|
-
return {
|
|
2085
|
+
return stripped === request.input ? request : {
|
|
1384
2086
|
...request,
|
|
1385
|
-
input: stripped
|
|
2087
|
+
input: stripped
|
|
1386
2088
|
};
|
|
1387
2089
|
}
|
|
1388
2090
|
function stripResponsesRequestCompaction(request) {
|
|
@@ -1422,16 +2124,44 @@ async function resolveNextResponsesEncryptedContentAttempt(attempt, error, optio
|
|
|
1422
2124
|
rejectedCompaction: readOpenAIResponsesCompactionRejection(attempt.request)
|
|
1423
2125
|
};
|
|
1424
2126
|
}
|
|
1425
|
-
async function
|
|
2127
|
+
async function createResponsesStreamWithRecovery(params) {
|
|
1426
2128
|
const encodeBody = params.encodeBody ?? prepareModelRequestBody(void 0);
|
|
2129
|
+
let tierCeiling;
|
|
2130
|
+
const limitTier = (request) => tierCeiling && (request.service_tier === "ultrafast" || tierCeiling === "default" && request.service_tier === "priority") ? {
|
|
2131
|
+
...request,
|
|
2132
|
+
service_tier: tierCeiling
|
|
2133
|
+
} : request;
|
|
2134
|
+
const recoverServiceTier = (attempt, error) => {
|
|
2135
|
+
if (params.requestOptions?.signal?.aborted || !supportsNativeOpenAIResponsesEndpoint(params.model)) return;
|
|
2136
|
+
const tier = attempt.request.service_tier;
|
|
2137
|
+
const next = nextResponsesServiceTier(tier, error);
|
|
2138
|
+
if (!next || tier !== "ultrafast" && tier !== "priority") return;
|
|
2139
|
+
tierCeiling = next;
|
|
2140
|
+
params.onServiceTierRejected?.(tier);
|
|
2141
|
+
log.info(`[responses] rejected ${tier} tier; retrying with ${next}`);
|
|
2142
|
+
return {
|
|
2143
|
+
...attempt,
|
|
2144
|
+
request: {
|
|
2145
|
+
...attempt.request,
|
|
2146
|
+
service_tier: next
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
};
|
|
1427
2150
|
const send = async (initialAttempt) => {
|
|
1428
2151
|
let attempt = initialAttempt;
|
|
1429
2152
|
for (;;) {
|
|
2153
|
+
const cappedRequest = limitTier(attempt.request);
|
|
2154
|
+
if (cappedRequest !== attempt.request) attempt = {
|
|
2155
|
+
kind: attempt.kind,
|
|
2156
|
+
request: cappedRequest,
|
|
2157
|
+
rejectedCompaction: attempt.rejectedCompaction
|
|
2158
|
+
};
|
|
1430
2159
|
params.observePrompt?.(attempt.request, {
|
|
1431
2160
|
egress: "responses-sdk",
|
|
1432
2161
|
payloadVariant: attempt.kind
|
|
1433
2162
|
});
|
|
1434
2163
|
const bodyOptions = await encodeBody(attempt.request);
|
|
2164
|
+
let responseAccepted = false;
|
|
1435
2165
|
try {
|
|
1436
2166
|
const { data, response } = await params.client.responses.create(attempt.request, {
|
|
1437
2167
|
...params.requestOptions,
|
|
@@ -1441,6 +2171,7 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
|
1441
2171
|
...params.requestOptions?.headers
|
|
1442
2172
|
}
|
|
1443
2173
|
}).withResponse();
|
|
2174
|
+
responseAccepted = true;
|
|
1444
2175
|
commitResponsesEncryptedContentAttempt(attempt, (checkpoint) => {
|
|
1445
2176
|
if (checkpoint) params.onCompactionRejected?.(checkpoint);
|
|
1446
2177
|
});
|
|
@@ -1451,7 +2182,7 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
|
1451
2182
|
attempt
|
|
1452
2183
|
};
|
|
1453
2184
|
} catch (error) {
|
|
1454
|
-
let nextAttempt = await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
|
|
2185
|
+
let nextAttempt = (!responseAccepted ? recoverServiceTier(attempt, error) : void 0) ?? await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
|
|
1455
2186
|
if (!nextAttempt && attempt.request.previous_response_id && error && typeof error === "object" && typeof error.status === "number" && isPreviousResponseRejection(error)) {
|
|
1456
2187
|
const request = { ...params.buildFullHistoryRequest ? await params.buildFullHistoryRequest() : attempt.request };
|
|
1457
2188
|
delete request.previous_response_id;
|
|
@@ -1461,7 +2192,7 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
|
1461
2192
|
};
|
|
1462
2193
|
}
|
|
1463
2194
|
if (!nextAttempt) throw error;
|
|
1464
|
-
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";
|
|
2195
|
+
const retryDescription = nextAttempt.request.service_tier !== attempt.request.service_tier ? "with a slower service tier" : nextAttempt.kind === "reasoning-stripped" ? "without encrypted reasoning content" : nextAttempt.kind === "compaction-stripped" ? "without encrypted compaction content" : "full history after rejected previous_response_id";
|
|
1465
2196
|
log.warn(`[responses] retrying ${retryDescription} provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
|
|
1466
2197
|
attempt = nextAttempt;
|
|
1467
2198
|
}
|
|
@@ -1474,26 +2205,42 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
|
1474
2205
|
});
|
|
1475
2206
|
return { stream: { async *[Symbol.asyncIterator]() {
|
|
1476
2207
|
let current = result;
|
|
2208
|
+
let outputObserved = false;
|
|
1477
2209
|
for (;;) {
|
|
1478
2210
|
let rejectedEvent;
|
|
2211
|
+
let sourceError;
|
|
2212
|
+
const source = current.stream;
|
|
2213
|
+
const providerStream = { async *[Symbol.asyncIterator]() {
|
|
2214
|
+
try {
|
|
2215
|
+
yield* source;
|
|
2216
|
+
} catch (error) {
|
|
2217
|
+
sourceError = error;
|
|
2218
|
+
throw error;
|
|
2219
|
+
}
|
|
2220
|
+
} };
|
|
1479
2221
|
try {
|
|
1480
|
-
for await (const event of params.wrapStream?.(
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
2222
|
+
for await (const event of params.wrapStream?.({
|
|
2223
|
+
...current,
|
|
2224
|
+
stream: providerStream
|
|
2225
|
+
}) ?? providerStream) {
|
|
2226
|
+
const { failure, hasResponseOutput, isPrelude } = readResponsesRecoveryEvent(event);
|
|
2227
|
+
outputObserved ||= hasResponseOutput;
|
|
2228
|
+
if (isRecord(failure) && params.canRetryStream?.() === true && (isInvalidEncryptedContentError(failure) || !outputObserved && isResponsesServiceTierRejection(failure))) {
|
|
2229
|
+
rejectedEvent = event;
|
|
2230
|
+
const message = typeof failure.message === "string" ? failure.message : "";
|
|
2231
|
+
throw Object.assign(new Error(message), {
|
|
2232
|
+
code: failure.code,
|
|
2233
|
+
status: failure.status,
|
|
2234
|
+
type: failure.type,
|
|
2235
|
+
param: failure.param
|
|
2236
|
+
});
|
|
1491
2237
|
}
|
|
2238
|
+
outputObserved ||= !isPrelude;
|
|
1492
2239
|
yield event;
|
|
1493
2240
|
}
|
|
1494
2241
|
return;
|
|
1495
2242
|
} catch (error) {
|
|
1496
|
-
const nextAttempt = params.canRetryStream?.() === true && !params.requestOptions?.signal?.aborted ? await resolveNextResponsesEncryptedContentAttempt(current.attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest }) : void 0;
|
|
2243
|
+
const nextAttempt = params.canRetryStream?.() === true && !params.requestOptions?.signal?.aborted ? (!outputObserved && (rejectedEvent !== void 0 || sourceError === error) ? recoverServiceTier(current.attempt, error) : void 0) ?? await resolveNextResponsesEncryptedContentAttempt(current.attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest }) : void 0;
|
|
1497
2244
|
if (!nextAttempt) {
|
|
1498
2245
|
if (rejectedEvent !== void 0) {
|
|
1499
2246
|
yield rejectedEvent;
|
|
@@ -1501,7 +2248,7 @@ async function createResponsesStreamWithEncryptedContentRetry(params) {
|
|
|
1501
2248
|
}
|
|
1502
2249
|
throw error;
|
|
1503
2250
|
}
|
|
1504
|
-
log.warn(`[responses] retrying
|
|
2251
|
+
log.warn(`[responses] retrying explicitly rejected stream provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
|
|
1505
2252
|
current = await send(nextAttempt);
|
|
1506
2253
|
}
|
|
1507
2254
|
}
|
|
@@ -1618,31 +2365,24 @@ function readResponsesOutputIndex(event) {
|
|
|
1618
2365
|
return typeof outputIndex === "number" && Number.isInteger(outputIndex) && outputIndex >= 0 ? outputIndex : void 0;
|
|
1619
2366
|
}
|
|
1620
2367
|
function createResponsesOutputSlotTracker() {
|
|
1621
|
-
const
|
|
1622
|
-
let unindexed;
|
|
2368
|
+
const slots = /* @__PURE__ */ new Map();
|
|
1623
2369
|
return {
|
|
1624
2370
|
register(event, slot) {
|
|
1625
2371
|
const outputIndex = readResponsesOutputIndex(event);
|
|
1626
|
-
if (outputIndex === void 0
|
|
1627
|
-
|
|
1628
|
-
unindexed = slot;
|
|
1629
|
-
return;
|
|
1630
|
-
}
|
|
1631
|
-
if (indexed.has(outputIndex)) throw new Error(`Responses stream reused active output index ${outputIndex}`);
|
|
1632
|
-
indexed.set(outputIndex, slot);
|
|
2372
|
+
if (slots.has(outputIndex)) throw new Error(outputIndex === void 0 ? "Responses stream added overlapping unindexed output items" : `Responses stream reused active output index ${outputIndex}`);
|
|
2373
|
+
slots.set(outputIndex, slot);
|
|
1633
2374
|
},
|
|
1634
2375
|
resolve(event, type) {
|
|
1635
2376
|
const outputIndex = readResponsesOutputIndex(event);
|
|
1636
|
-
let slot =
|
|
2377
|
+
let slot = slots.get(outputIndex);
|
|
1637
2378
|
if (outputIndex === void 0 && !slot) {
|
|
1638
|
-
const matches = [...
|
|
2379
|
+
const matches = [...slots.values()].filter((candidate) => candidate.type === type);
|
|
1639
2380
|
slot = matches.length === 1 ? matches[0] : void 0;
|
|
1640
2381
|
}
|
|
1641
2382
|
return slot?.type === type ? slot : void 0;
|
|
1642
2383
|
},
|
|
1643
2384
|
get(event) {
|
|
1644
|
-
|
|
1645
|
-
return outputIndex === void 0 ? unindexed : indexed.get(outputIndex);
|
|
2385
|
+
return slots.get(readResponsesOutputIndex(event));
|
|
1646
2386
|
},
|
|
1647
2387
|
resolveOutputItem(event, item) {
|
|
1648
2388
|
if (item.type === "reasoning") return this.resolve(event, "thinking");
|
|
@@ -1650,11 +2390,12 @@ function createResponsesOutputSlotTracker() {
|
|
|
1650
2390
|
return readResponsesOutputIndex(event) === void 0 ? void 0 : this.get(event);
|
|
1651
2391
|
},
|
|
1652
2392
|
values() {
|
|
1653
|
-
|
|
2393
|
+
const indexed = [...slots].filter(([index]) => index !== void 0).map(([, slot]) => slot);
|
|
2394
|
+
const unindexed = slots.get(void 0);
|
|
2395
|
+
return [.../* @__PURE__ */ new Set([...indexed, ...unindexed ? [unindexed] : []])];
|
|
1654
2396
|
},
|
|
1655
2397
|
forget(slot) {
|
|
1656
|
-
if (
|
|
1657
|
-
for (const [outputIndex, candidate] of indexed) if (candidate === slot) indexed.delete(outputIndex);
|
|
2398
|
+
for (const [outputIndex, candidate] of slots) if (candidate === slot) slots.delete(outputIndex);
|
|
1658
2399
|
}
|
|
1659
2400
|
};
|
|
1660
2401
|
}
|
|
@@ -1783,11 +2524,9 @@ function resolveResponsesToolCallId(item, fallbackId) {
|
|
|
1783
2524
|
const callId = typeof item.call_id === "string" ? item.call_id.trim() : "";
|
|
1784
2525
|
const itemId = typeof item.id === "string" ? item.id.trim() : "";
|
|
1785
2526
|
const [fallbackCallId, fallbackItemId = ""] = splitToolCallId(fallbackId ?? "");
|
|
1786
|
-
const resolvedCallId = callId || fallbackCallId
|
|
2527
|
+
const resolvedCallId = callId || fallbackCallId || `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`;
|
|
1787
2528
|
const resolvedItemId = itemId || fallbackItemId;
|
|
1788
|
-
|
|
1789
|
-
const generated = `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`;
|
|
1790
|
-
return resolvedItemId ? `${generated}|${resolvedItemId}` : generated;
|
|
2529
|
+
return resolvedItemId ? `${resolvedCallId}|${resolvedItemId}` : resolvedCallId;
|
|
1791
2530
|
}
|
|
1792
2531
|
function resolveCompletedResponsesToolCall(item, streamed) {
|
|
1793
2532
|
if (item.status && item.status !== "completed") throw new IncompleteToolCallError("Responses stream completed with an incomplete terminal tool call");
|
|
@@ -1822,7 +2561,8 @@ function createResponsesTerminalController(params) {
|
|
|
1822
2561
|
if (options?.reasoningReplayMetadata) Object.assign(block, { [OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY]: options.reasoningReplayMetadata });
|
|
1823
2562
|
}
|
|
1824
2563
|
};
|
|
1825
|
-
const appendText = (item,
|
|
2564
|
+
const appendText = (item, initialIndex) => {
|
|
2565
|
+
let contentIndex = initialIndex;
|
|
1826
2566
|
const text = (Array.isArray(item.content) ? item.content : []).map((part) => {
|
|
1827
2567
|
const content = part;
|
|
1828
2568
|
return content.type === "output_text" || content.type === "text" ? content.text ?? "" : content.refusal ?? "";
|
|
@@ -1848,58 +2588,47 @@ function createResponsesTerminalController(params) {
|
|
|
1848
2588
|
delta
|
|
1849
2589
|
});
|
|
1850
2590
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
const collapse = resolveResponsesMessageSnapshotCollapse({
|
|
1861
|
-
prior: previous && {
|
|
1862
|
-
text: previous.block.text,
|
|
1863
|
-
phase: previous.phase
|
|
1864
|
-
},
|
|
1865
|
-
nextText: text,
|
|
1866
|
-
nextPhase: phase
|
|
1867
|
-
});
|
|
1868
|
-
if (collapse.kind === "extend" && previous) {
|
|
1869
|
-
previous.block.text = collapse.text;
|
|
1870
|
-
previous.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
1871
|
-
stream.push({
|
|
1872
|
-
type: "text_end",
|
|
1873
|
-
contentIndex: previous.index,
|
|
1874
|
-
content: collapse.text,
|
|
1875
|
-
partial: output
|
|
2591
|
+
} else {
|
|
2592
|
+
const previous = params.getLastTextBlock();
|
|
2593
|
+
const collapse = resolveResponsesMessageSnapshotCollapse({
|
|
2594
|
+
prior: previous && {
|
|
2595
|
+
text: previous.block.text,
|
|
2596
|
+
phase: previous.phase
|
|
2597
|
+
},
|
|
2598
|
+
nextText: text,
|
|
2599
|
+
nextPhase: phase
|
|
1876
2600
|
});
|
|
1877
|
-
|
|
2601
|
+
if (collapse.kind === "extend" && previous) {
|
|
2602
|
+
previous.block.text = collapse.text;
|
|
2603
|
+
previous.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2604
|
+
contentIndex = previous.index;
|
|
2605
|
+
} else {
|
|
2606
|
+
const newBlock = {
|
|
2607
|
+
type: "text",
|
|
2608
|
+
text,
|
|
2609
|
+
textSignature: encodeTextSignatureV1(item.id, phase)
|
|
2610
|
+
};
|
|
2611
|
+
blocks.push(newBlock);
|
|
2612
|
+
contentIndex = blocks.length - 1;
|
|
2613
|
+
params.setLastTextBlock({
|
|
2614
|
+
block: newBlock,
|
|
2615
|
+
index: contentIndex,
|
|
2616
|
+
phase
|
|
2617
|
+
});
|
|
2618
|
+
stream.push({
|
|
2619
|
+
type: "text_start",
|
|
2620
|
+
contentIndex,
|
|
2621
|
+
partial: output
|
|
2622
|
+
});
|
|
2623
|
+
}
|
|
1878
2624
|
}
|
|
1879
|
-
const newBlock = {
|
|
1880
|
-
type: "text",
|
|
1881
|
-
text,
|
|
1882
|
-
textSignature: encodeTextSignatureV1(item.id, phase)
|
|
1883
|
-
};
|
|
1884
|
-
blocks.push(newBlock);
|
|
1885
|
-
const index = blocks.length - 1;
|
|
1886
|
-
params.setLastTextBlock({
|
|
1887
|
-
block: newBlock,
|
|
1888
|
-
index,
|
|
1889
|
-
phase
|
|
1890
|
-
});
|
|
1891
|
-
stream.push({
|
|
1892
|
-
type: "text_start",
|
|
1893
|
-
contentIndex: index,
|
|
1894
|
-
partial: output
|
|
1895
|
-
});
|
|
1896
2625
|
stream.push({
|
|
1897
2626
|
type: "text_end",
|
|
1898
|
-
contentIndex
|
|
2627
|
+
contentIndex,
|
|
1899
2628
|
content: text,
|
|
1900
2629
|
partial: output
|
|
1901
2630
|
});
|
|
1902
|
-
return
|
|
2631
|
+
return contentIndex;
|
|
1903
2632
|
};
|
|
1904
2633
|
const emitToolCallCompletion = (item, outputIndex, started, validated) => {
|
|
1905
2634
|
const completed = {
|
|
@@ -2043,67 +2772,52 @@ async function processResponsesStream(openaiStream, output, sink, model, options
|
|
|
2043
2772
|
let lastTextBlock = null;
|
|
2044
2773
|
const blocks = output.content;
|
|
2045
2774
|
const compactionTracker = createCompactionTracker(output, model, options);
|
|
2775
|
+
const createTextBlock = (item, text) => ({
|
|
2776
|
+
type: "text",
|
|
2777
|
+
text,
|
|
2778
|
+
...item.phase ? { textSignature: encodeTextSignatureV1(item.id, item.phase) } : {}
|
|
2779
|
+
});
|
|
2046
2780
|
const createOutputSlot = (event, item) => {
|
|
2047
|
-
|
|
2048
|
-
|
|
2781
|
+
let slot;
|
|
2782
|
+
if (item.type === "reasoning") slot = {
|
|
2783
|
+
type: "thinking",
|
|
2784
|
+
item,
|
|
2785
|
+
block: {
|
|
2049
2786
|
type: "thinking",
|
|
2050
2787
|
thinking: ""
|
|
2051
|
-
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
contentIndex: blocks.length,
|
|
2057
|
-
outputIndex: readResponsesOutputIndex(event)
|
|
2058
|
-
};
|
|
2059
|
-
blocks.push(block);
|
|
2060
|
-
outputs.set(item, slot.contentIndex, slot.outputIndex);
|
|
2061
|
-
outputSlots.register(event, slot);
|
|
2062
|
-
stream.push({
|
|
2063
|
-
type: "thinking_start",
|
|
2064
|
-
contentIndex: slot.contentIndex,
|
|
2065
|
-
partial: output
|
|
2066
|
-
});
|
|
2067
|
-
return slot;
|
|
2068
|
-
}
|
|
2069
|
-
if (item.type === "message") {
|
|
2070
|
-
const messageItem = item;
|
|
2788
|
+
},
|
|
2789
|
+
contentIndex: blocks.length,
|
|
2790
|
+
outputIndex: readResponsesOutputIndex(event)
|
|
2791
|
+
};
|
|
2792
|
+
else if (item.type === "message") {
|
|
2071
2793
|
const collapseCandidate = lastTextBlock;
|
|
2072
|
-
const block = collapseCandidate ? null :
|
|
2073
|
-
|
|
2074
|
-
text: "",
|
|
2075
|
-
...messageItem.phase ? { textSignature: encodeTextSignatureV1(messageItem.id, messageItem.phase) } : {}
|
|
2076
|
-
};
|
|
2077
|
-
const slot = {
|
|
2794
|
+
const block = collapseCandidate ? null : createTextBlock(item, "");
|
|
2795
|
+
slot = {
|
|
2078
2796
|
type: "text",
|
|
2079
|
-
item
|
|
2797
|
+
item,
|
|
2080
2798
|
block,
|
|
2081
2799
|
contentIndex: block ? blocks.length : void 0,
|
|
2082
2800
|
outputIndex: readResponsesOutputIndex(event),
|
|
2083
2801
|
pendingText: collapseCandidate ? "" : null,
|
|
2084
2802
|
collapseCandidate
|
|
2085
2803
|
};
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
outputSlots.register(event, slot);
|
|
2091
|
-
if (slot.contentIndex !== void 0) stream.push({
|
|
2092
|
-
type: "text_start",
|
|
2093
|
-
contentIndex: slot.contentIndex,
|
|
2094
|
-
partial: output
|
|
2095
|
-
});
|
|
2096
|
-
return slot;
|
|
2804
|
+
} else return;
|
|
2805
|
+
if (slot.block) {
|
|
2806
|
+
blocks.push(slot.block);
|
|
2807
|
+
outputs.set(slot.item, slot.contentIndex ?? blocks.length - 1, slot.outputIndex);
|
|
2097
2808
|
}
|
|
2809
|
+
outputSlots.register(event, slot);
|
|
2810
|
+
if (slot.contentIndex !== void 0) stream.push({
|
|
2811
|
+
type: slot.type === "thinking" ? "thinking_start" : "text_start",
|
|
2812
|
+
contentIndex: slot.contentIndex,
|
|
2813
|
+
partial: output
|
|
2814
|
+
});
|
|
2815
|
+
return slot;
|
|
2098
2816
|
};
|
|
2099
2817
|
const materializeDeferredTextSlot = (slot) => {
|
|
2100
2818
|
if (slot.block || slot.pendingText === null) return;
|
|
2101
2819
|
const text = slot.pendingText;
|
|
2102
|
-
slot.block =
|
|
2103
|
-
type: "text",
|
|
2104
|
-
text,
|
|
2105
|
-
...slot.item.phase ? { textSignature: encodeTextSignatureV1(slot.item.id, slot.item.phase) } : {}
|
|
2106
|
-
};
|
|
2820
|
+
slot.block = createTextBlock(slot.item, text);
|
|
2107
2821
|
blocks.push(slot.block);
|
|
2108
2822
|
slot.contentIndex = blocks.length - 1;
|
|
2109
2823
|
outputs.set(slot.item, slot.contentIndex, slot.outputIndex);
|
|
@@ -2263,19 +2977,17 @@ async function processResponsesStream(openaiStream, output, sink, model, options
|
|
|
2263
2977
|
if (!slot) continue;
|
|
2264
2978
|
slot.item.summary = slot.item.summary || [];
|
|
2265
2979
|
slot.item.summary.push(event.part);
|
|
2266
|
-
} else if (event.type === "response.reasoning_summary_text.delta" || event.type === "response.reasoning_summary_part.done") {
|
|
2980
|
+
} else if (event.type === "response.reasoning_summary_text.delta" || event.type === "response.reasoning_summary_part.done" || event.type === "response.reasoning_text.delta") {
|
|
2267
2981
|
const slot = outputSlots.resolve(event, "thinking");
|
|
2268
2982
|
if (!slot) continue;
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2983
|
+
const delta = event.type === "response.reasoning_summary_part.done" ? "\n\n" : event.delta;
|
|
2984
|
+
if (event.type !== "response.reasoning_text.delta") {
|
|
2985
|
+
slot.item.summary = slot.item.summary || [];
|
|
2986
|
+
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2987
|
+
if (!lastPart) continue;
|
|
2988
|
+
lastPart.text += delta;
|
|
2989
|
+
}
|
|
2274
2990
|
appendThinkingDelta(slot, delta);
|
|
2275
|
-
} else if (event.type === "response.reasoning_text.delta") {
|
|
2276
|
-
const slot = outputSlots.resolve(event, "thinking");
|
|
2277
|
-
if (!slot) continue;
|
|
2278
|
-
appendThinkingDelta(slot, event.delta);
|
|
2279
2991
|
} else if (event.type === "response.content_part.added") {
|
|
2280
2992
|
const slot = outputSlots.resolve(event, "text");
|
|
2281
2993
|
if (!slot) continue;
|
|
@@ -2311,22 +3023,19 @@ async function processResponsesStream(openaiStream, output, sink, model, options
|
|
|
2311
3023
|
lastPart.text += event.delta;
|
|
2312
3024
|
}
|
|
2313
3025
|
projectTextDelta(slot, event.delta);
|
|
2314
|
-
} else if (event.type === "response.function_call_arguments.delta") {
|
|
3026
|
+
} else if (event.type === "response.function_call_arguments.delta" || event.type === "response.function_call_arguments.done") {
|
|
2315
3027
|
const toolCall = streamingToolCalls.resolve(event);
|
|
2316
|
-
if (toolCall) {
|
|
3028
|
+
if (!toolCall) {
|
|
3029
|
+
if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
3030
|
+
continue;
|
|
3031
|
+
}
|
|
3032
|
+
let delta;
|
|
3033
|
+
if (event.type === "response.function_call_arguments.delta") {
|
|
2317
3034
|
toolCall.block.partialJson += event.delta;
|
|
2318
3035
|
toolCall.argumentsStreamed = true;
|
|
2319
3036
|
if (toolCall.previewSchedule(toolCall.block.partialJson.length)) toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
contentIndex: toolCall.contentIndex,
|
|
2323
|
-
delta: event.delta,
|
|
2324
|
-
partial: output
|
|
2325
|
-
});
|
|
2326
|
-
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
2327
|
-
} else if (event.type === "response.function_call_arguments.done") {
|
|
2328
|
-
const toolCall = streamingToolCalls.resolve(event);
|
|
2329
|
-
if (toolCall) {
|
|
3037
|
+
delta = event.delta;
|
|
3038
|
+
} else {
|
|
2330
3039
|
const previousPartialJson = toolCall.block.partialJson;
|
|
2331
3040
|
const doneArguments = typeof event.arguments === "string" ? event.arguments : void 0;
|
|
2332
3041
|
if (doneArguments !== void 0 && (doneArguments.length > 0 || previousPartialJson === "")) {
|
|
@@ -2335,16 +3044,14 @@ async function processResponsesStream(openaiStream, output, sink, model, options
|
|
|
2335
3044
|
toolCall.argumentStreamReliable = true;
|
|
2336
3045
|
toolCall.argumentsStreamed = true;
|
|
2337
3046
|
}
|
|
2338
|
-
if (doneArguments?.startsWith(previousPartialJson))
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
}
|
|
2347
|
-
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
3047
|
+
if (doneArguments?.startsWith(previousPartialJson)) delta = doneArguments.slice(previousPartialJson.length) || void 0;
|
|
3048
|
+
}
|
|
3049
|
+
if (delta !== void 0) stream.push({
|
|
3050
|
+
type: "toolcall_delta",
|
|
3051
|
+
contentIndex: toolCall.contentIndex,
|
|
3052
|
+
delta,
|
|
3053
|
+
partial: output
|
|
3054
|
+
});
|
|
2348
3055
|
} else if (event.type === "response.output_item.done") {
|
|
2349
3056
|
const item = event.item;
|
|
2350
3057
|
if (item.type !== "message") lastTextBlock = null;
|
|
@@ -2392,11 +3099,7 @@ async function processResponsesStream(openaiStream, output, sink, model, options
|
|
|
2392
3099
|
outputs.set(item, outputSlot.collapseCandidate.index, readResponsesOutputIndex(event) ?? outputSlot.outputIndex, true);
|
|
2393
3100
|
} else {
|
|
2394
3101
|
if (!outputSlot.block) {
|
|
2395
|
-
outputSlot.block =
|
|
2396
|
-
type: "text",
|
|
2397
|
-
text: "",
|
|
2398
|
-
...phase ? { textSignature: encodeTextSignatureV1(item.id, phase) } : {}
|
|
2399
|
-
};
|
|
3102
|
+
outputSlot.block = createTextBlock(item, "");
|
|
2400
3103
|
blocks.push(outputSlot.block);
|
|
2401
3104
|
outputSlot.contentIndex = blocks.length - 1;
|
|
2402
3105
|
stream.push({
|
|
@@ -2588,7 +3291,7 @@ async function runResponsesStreamLifecycle(params) {
|
|
|
2588
3291
|
let started = false;
|
|
2589
3292
|
let admittedRequest;
|
|
2590
3293
|
let requestedTier;
|
|
2591
|
-
const { stream: hookedOpenAIStream } = await
|
|
3294
|
+
const { stream: hookedOpenAIStream } = await createResponsesStreamWithRecovery({
|
|
2592
3295
|
client,
|
|
2593
3296
|
request: requestParams,
|
|
2594
3297
|
requestOptions: {
|
|
@@ -2601,6 +3304,7 @@ async function runResponsesStreamLifecycle(params) {
|
|
|
2601
3304
|
buildFullHistoryRequest: () => buildRequest("full-history"),
|
|
2602
3305
|
onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint),
|
|
2603
3306
|
canRetryStream: () => output.content.length === 0,
|
|
3307
|
+
onServiceTierRejected: (tier) => responsesServiceTierObserver.reject(options, tier),
|
|
2604
3308
|
wrapStream: ({ stream: openaiStream, response, attempt }) => {
|
|
2605
3309
|
requestedTier = attempt.request.service_tier;
|
|
2606
3310
|
admittedRequest = attempt.kind === "initial" ? attempt.request : void 0;
|
|
@@ -2623,14 +3327,19 @@ async function runResponsesStreamLifecycle(params) {
|
|
|
2623
3327
|
});
|
|
2624
3328
|
const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
|
|
2625
3329
|
const onFirstEventTimeout = getFirstStreamEventTimeoutHandler(options);
|
|
3330
|
+
const processStreamOptions = params.processStreamOptions || firstEventTimeoutMs !== void 0 || onFirstEventTimeout !== void 0 ? {
|
|
3331
|
+
...params.processStreamOptions,
|
|
3332
|
+
firstEventTimeoutMs: params.processStreamOptions?.firstEventTimeoutMs ?? firstEventTimeoutMs,
|
|
3333
|
+
abortFirstEventStream: params.processStreamOptions?.abortFirstEventStream ?? firstEventAbort.abort,
|
|
3334
|
+
onFirstEventTimeout: params.processStreamOptions?.onFirstEventTimeout ?? onFirstEventTimeout,
|
|
3335
|
+
signal: params.processStreamOptions?.signal ?? options?.signal
|
|
3336
|
+
} : void 0;
|
|
2626
3337
|
const terminal = await processResponsesStream(hookedOpenAIStream, output, stream, model, {
|
|
2627
|
-
...
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
signal: params.processStreamOptions?.signal ?? options?.signal
|
|
2633
|
-
} : void 0,
|
|
3338
|
+
...processStreamOptions,
|
|
3339
|
+
resolveServiceTier: (responseTier, originalTier) => {
|
|
3340
|
+
const tier = requestedTier === "priority" || requestedTier === "default" ? requestedTier : originalTier;
|
|
3341
|
+
return processStreamOptions?.resolveServiceTier ? processStreamOptions.resolveServiceTier(responseTier, tier) : responseTier ?? tier;
|
|
3342
|
+
},
|
|
2634
3343
|
onServiceTier: (responseTier) => responsesServiceTierObserver.observe(options, requestedTier, responseTier),
|
|
2635
3344
|
canRetryIdentityConflict: () => hasOnlyResponsesFunctionTools(admittedRequest),
|
|
2636
3345
|
reasoningReplayMetadata: buildOpenAIResponsesReasoningReplayMetadata(model, {
|
|
@@ -2671,4 +3380,4 @@ async function runResponsesStreamLifecycle(params) {
|
|
|
2671
3380
|
}
|
|
2672
3381
|
}
|
|
2673
3382
|
//#endregion
|
|
2674
|
-
export {
|
|
3383
|
+
export { replayResponsesReasoningUpdates as $, summarizeResponsesPayload as A, measureUtf8AppendBytes as At, responsesInputFingerprint as B, readResponsesRecoveryEvent as C, toOpenAIResponsesToolChoice as Ct, logResponsesFailedNoDetails as D, createResponseModelTracker as Dt, ResponsesStreamFailure as E, createOpenAIResponseHook as Et, convertProviderResponsesMessages as F, resolvePromptCacheKey as Ft, responsesContinuationRequestFingerprint as G, recordResponsesContinuationState as H, convertResponsesMessages as I, redactIdentifier as It, OPENAI_RESPONSES_ID_MAX_LENGTH as J, OPENAI_RESPONSES_CALL_ID_RE as K, resolveReplayableResponsesMessageId as L, sha256Hex as Lt, resolveResponsesContextUsageBoundary as M, readOpenAICompletionsContentDeltas as Mt, bindResponsesInputMessage as N, readOpenAICompletionsReasoningBatch as Nt, safeDebugValue as O, isOpenAICompletionsThinkingEnabled as Ot, buildResponsesInputMessage as P, resolveOpenAIClientBaseUrl as Pt, isConfigurationUpdate as Q, readResponsesInputReplayState as R, isInvalidEncryptedContentError as S, reconcileOpenAIResponsesToolChoice as St, resolveNextResponsesEncryptedContentAttempt as T, createOpenAIProviderAcceptanceHook as Tt, resolveResponsesContinuationRequest as U, claimOpenAIResponsesHttpContinuation as V, responsesContinuationPrefixFingerprint as W, shouldNormalizeOpenAIResponsesToolCallId as X, normalizeOpenAIResponsesFunctionCallId as Y, splitOpenAIFunctionCallPairing as Z, isResponsesTextContentPartType as _, resolveOpenAISimpleReasoningEffort as _t, prepareResponsesTools as a, suppressOpenAIResponsesCompaction as at, commitResponsesEncryptedContentAttempt as b, projectOpenAITools as bt, observeResponsesStream as c, buildOpenAISdkClientOptions as ct, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as d, filterCodeModePayloadTools as dt, supportsResponsesReasoningUpdate as et, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as f, getCompat as ft, isAzureResponsesTextDeltaEventType as g, resolveOpenAIRequestReasoning as gt, isAzureResponsesTextDeltaEvent as h, resolveOpenAIStrictToolFlagWithDiagnostics as ht, convertResponsesToolPayload as i, resolveNewestOpenAIResponsesCompactionReplay as it, recordResponsesContextUsage as j, parseOpenAICompletionsUsage as jt, summarizeOpenAITransportError as k, log as kt, createResponsesToolCallTracker as l, buildOpenAISdkRequestOptions as lt, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as m, resolveCodeModeResponsesVisibleToolNames as mt, applyResponsesServiceTierPricing as n, buildOpenAIResponsesReasoningReplayMetadata as nt, readOpenAIMisalignmentReview as o, assertCodeModeResponsesToolSurface as ot, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as p, readCodeModePayloadToolName as pt, OPENAI_RESPONSES_FUNCTION_CALL_ITEM_ID_RE as q, runResponsesStreamLifecycle as r, captureOpenAIResponsesCompaction as rt, processResponsesStream as s, buildOpenAIClientHeaders as st, applyCommonResponsesParams as t, CompactionReplayRefreshRequiredError as tt, readResponsesToolCallItemIdentity as u, enforceCodeModeResponsesToolSurface as ut, isResponsesTextDeltaEventType as v, resolveOpenAIReasoningEffortMap as vt, resolveAzureOpenAIApiVersion as w, GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP as wt, createResponsesStreamWithRecovery as x, reconcileOpenAICompletionsToolChoice as xt, resolveResponsesMessageSnapshotCollapse as y, prepareOpenAITools as yt, recordResponsesInputReplay as z };
|