@openclaw/ai 2026.10.5 → 2026.10.10-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/{anthropic-DIIiiz99.mjs → anthropic-D6spfBri.mjs} +16 -18
- package/dist/{anthropic-payload-policy-DGblkHL5.d.mts → anthropic-payload-policy-Cr8xjazC.d.mts} +6 -3
- package/dist/{anthropic-stream-reducer-DfMVFm-r.mjs → anthropic-stream-reducer-CzPXOaLM.mjs} +55 -227
- package/dist/anthropic-tool-projection-BdAS3rtJ.mjs +165 -0
- package/dist/anthropic-tool-projection-DKH-aEWU.d.mts +51 -0
- package/dist/{api-registry-BhXXYdRA.d.mts → api-registry-gDt0faai.d.mts} +2 -2
- package/dist/{assistant-output-BuhRpLeD.mjs → assistant-output-6iFA1nbC.mjs} +2 -2
- package/dist/{azure-openai-responses-DGQnXRMs.mjs → azure-openai-responses-0TqHwnlD.mjs} +8 -8
- package/dist/{cloudflare-5qSGvIUH.mjs → cloudflare-Dttf8jKq.mjs} +1 -1
- package/dist/{credential-redaction-BHxruEH6.d.mts → credential-redaction-XvsPf7Yi.d.mts} +1 -0
- package/dist/{diagnostics-tQasYct1.mjs → diagnostics-Cv7cW3pS.mjs} +3 -3
- package/dist/diagnostics.d.mts +6 -6
- package/dist/diagnostics.mjs +2 -2
- package/dist/{env-api-keys-CrxwdylR.mjs → env-api-keys-Xd8dm_aV.mjs} +10 -34
- package/dist/event-stream-CDpFza-M.d.mts +1 -0
- package/dist/{event-stream-BcqWLo_u.d.mts → event-stream-CzpE1g_o.d.mts} +1 -1
- package/dist/event-stream.d.mts +2 -2
- package/dist/{github-copilot-request-facts-DEE6gcB9.mjs → github-copilot-request-facts-F-EmvkpW.mjs} +1 -1
- package/dist/{google-interactions-zIz70M2e.mjs → google-interactions-DVQ7AaSF.mjs} +29 -50
- package/dist/{google-messages-CNbUJK5E.mjs → google-messages-DfpHVTaD.mjs} +15 -5
- package/dist/{google-provider-stream-Cn0XF1MG.mjs → google-provider-stream-DJ8ANfsS.mjs} +6 -6
- package/dist/{google-shared-BPnWP4tT.mjs → google-shared-VTcCJLW3.mjs} +21 -29
- package/dist/{google-vertex-XQ7OQtaM.mjs → google-vertex-Bkfizj7M.mjs} +3 -3
- package/dist/{google-BlbTC1Xp.mjs → google-zWpkDSeN.mjs} +4 -4
- package/dist/{host-Bf3NjYNj.mjs → host-B2gk-d1H.mjs} +5 -11
- package/dist/{host-CTDz7LXD.d.mts → host-jJOffdlW.d.mts} +4 -6
- package/dist/{host-policy-BzZluO6_.mjs → host-policy-mpqGhbeM.mjs} +1 -1
- package/dist/{index-BYDvopUB.d.mts → index-DSprYWaz.d.mts} +7 -5
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +6 -6
- package/dist/internal/anthropic.d.mts +7 -53
- package/dist/internal/anthropic.mjs +6 -5
- package/dist/internal/google-model-family.mjs +1 -1
- 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 +3 -3
- package/dist/internal/openai-responses-payload-policy.mjs +3 -3
- package/dist/internal/openai.d.mts +17 -26
- package/dist/internal/openai.mjs +10 -10
- package/dist/internal/retry-after.d.mts +1 -1
- package/dist/internal/retry-after.mjs +80 -55
- package/dist/internal/runtime.d.mts +9 -31
- package/dist/internal/runtime.mjs +10 -116
- package/dist/internal/shared.d.mts +9 -7
- package/dist/internal/shared.mjs +8 -6
- package/dist/internal/tool-schema.d.mts +83 -5
- package/dist/internal/tool-schema.mjs +4 -3
- package/dist/{mistral-dCDCR5ur.mjs → mistral-CATJrwne.mjs} +32 -35
- package/dist/model-request-body-BD5vy4rP.d.mts +17 -0
- package/dist/{number-coercion-C3hztWoY.mjs → number-coercion-37gmNkuA.mjs} +1 -1
- package/dist/{openai-chatgpt-responses-D8-q7cgy.mjs → openai-chatgpt-responses-CtdnpWwe.mjs} +95 -63
- package/dist/{openai-completions-CMN24pza.mjs → openai-completions-B6sET3oI.mjs} +10 -8
- package/dist/{openai-completions-compat-i-nLZxFy.d.mts → openai-completions-compat-1gsjP-KO.d.mts} +6 -3
- package/dist/{openai-completions-compat-CYX18uDk.mjs → openai-completions-compat-CFhQ3UVU.mjs} +7 -2
- package/dist/{openai-completions-transport-DuXQOxrH.mjs → openai-completions-transport-DviPEqw3.mjs} +369 -237
- package/dist/{openai-prompt-cache-r93BJhjm.mjs → openai-prompt-cache-DJ_P143P.mjs} +1 -1
- package/dist/{openai-prompt-cache-DIPMrMFy.d.mts → openai-prompt-cache-DgjD-UL5.d.mts} +2 -2
- package/dist/{openai-responses-BMxoJdTC.mjs → openai-responses-BXsJK-mD.mjs} +13 -15
- package/dist/{openai-responses-compaction-replay-B2FE4Nw8.d.mts → openai-responses-compaction-replay-Cvnl_nCq.d.mts} +5 -5
- package/dist/{openai-responses-contracts-DlKMMTxK.mjs → openai-responses-contracts-Bx-16mnf.mjs} +45 -6
- package/dist/{openai-responses-contracts-DKqMJ1Ct.d.mts → openai-responses-contracts-CQ4_AWjL.d.mts} +20 -8
- package/dist/{openai-responses-endpoint-CinGh4VZ.mjs → openai-responses-endpoint-D4v-eeYy.mjs} +55 -22
- package/dist/{openai-responses-payload-policy-C7GsA1y0.d.mts → openai-responses-payload-policy-BzM52TTH.d.mts} +9 -3
- package/dist/openai-responses-request-lifecycle-CTdAb2v1.mjs +246 -0
- package/dist/{openai-responses-shared-afo9-s16.mjs → openai-responses-shared-Bv_1NtH9.mjs} +284 -173
- package/dist/{openai-responses-terminal-usage-BygjiAdi.d.mts → openai-responses-terminal-usage-CpVjkqn-.d.mts} +2 -2
- package/dist/{openai-tool-schema-DDPXsvJP.mjs → openai-tool-schema-Buv0GXFb.mjs} +170 -237
- package/dist/overflow-DJHXTNBQ.mjs +117 -0
- package/dist/{positive-integer-CqWjqSi9.mjs → positive-integer-Bb4Evc7L.mjs} +1 -1
- package/dist/prompt-cache-stability-D_MeCQFI.mjs +32 -0
- package/dist/{provider-error-xumb1V3F.d.mts → provider-error-CnaWYTRY.d.mts} +1 -0
- package/dist/{provider-error-CF9GWCs2.mjs → provider-error-qtZD2inE.mjs} +75 -13
- package/dist/{provider-options-CVrXZBtA.d.mts → provider-options-DeYeaflL.d.mts} +52 -6
- package/dist/{transport-utils-34BQoXq3.mjs → provider-replay-context-J6CfU3m1.mjs} +28 -5
- package/dist/{provider-transport-turn-state-BYrELw8H.mjs → provider-transport-turn-state-Jxppzuc2.mjs} +5 -5
- package/dist/{provider-types-CHtRx0dI.d.mts → provider-types-ODq57rG_.d.mts} +3 -3
- package/dist/provider-types.d.mts +6 -6
- package/dist/providers.d.mts +2 -2
- package/dist/providers.mjs +11 -11
- package/dist/{reasoning-tag-text-partitioner-CpOy9-IQ.mjs → reasoning-tag-text-partitioner-DzlRubwU.mjs} +134 -47
- package/dist/{required-api-key-CFJvcFy_.mjs → required-api-key-D088S4Cd.mjs} +1 -1
- package/dist/{retry-after-CdCURCVg.d.mts → retry-after-sw-XX8aC.d.mts} +1 -1
- package/dist/sanitize-unicode-CRGuMONI.mjs +8 -0
- package/dist/sanitize-unicode-ZqVLLEKC.d.mts +27 -0
- package/dist/{session-resources-D1wgDQ8C.mjs → session-resources-vKvGIE3J.mjs} +1 -10
- package/dist/{simple-options-BAu4B54D.mjs → simple-options-BYgC6kse.mjs} +68 -79
- package/dist/{src-C44MKrW5.mjs → src-CyA0zJnt.mjs} +6 -2
- package/dist/{stream-Dd8DwRFL.mjs → stream-DLBirT0e.mjs} +8 -47
- package/dist/{stream-first-event-timeout-Dc42hKv6.mjs → stream-first-event-timeout-D_TfJHRJ.mjs} +1 -1
- package/dist/{string-coerce-CtgOVOSv.mjs → string-coerce-Cj8sqWHx.mjs} +26 -1
- package/dist/tool-schema-json-projection-B0hHDV7N.mjs +492 -0
- package/dist/{transport-stream-shared-BmpzDtdQ.d.mts → transport-stream-shared-8ru8eX4s.d.mts} +5 -5
- package/dist/{transport-stream-shared-CWGOuLcA.mjs → transport-stream-shared-CzQlAzJH.mjs} +27 -75
- package/dist/transports.d.mts +33 -28
- package/dist/transports.mjs +42 -48
- package/dist/{types-CQc6JNG4.mjs → types-BXd0kI8-.mjs} +1 -1
- package/dist/types-CBJthzJX.d.mts +1 -0
- package/dist/{types-Bd2T86VJ.d.mts → types-CVYzKrMl.d.mts} +20 -3
- package/dist/types.d.mts +6 -6
- package/dist/types.mjs +4 -4
- package/dist/{validation-ZX_sPVV0.mjs → validation-9FSkE8T-.mjs} +22 -3
- package/dist/{validation-DdGB1yy3.d.mts → validation-BQ5u20Ru.d.mts} +1 -1
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/package.json +3 -3
- package/dist/assistant-text-phase-mvdMcrY-.mjs +0 -50
- package/dist/event-stream-6UNs-AhN.d.mts +0 -1
- package/dist/expect-lbe3Hgrh.mjs +0 -8
- package/dist/json-schema-Bp07Qui3.mjs +0 -22
- package/dist/openai-responses-request-lifecycle-NSIJo9jY.mjs +0 -67
- package/dist/openai-tool-projection-793cE3QX.d.mts +0 -37
- package/dist/openai-tool-schema-a5ysBBga.d.mts +0 -32
- package/dist/rolldown-runtime-BhDjJH2R.mjs +0 -15
- package/dist/sanitize-unicode-CjDG6jJx.d.mts +0 -5
- package/dist/string-normalization-I3ux50s9.mjs +0 -28
- package/dist/text-signature-CUXnvk_c.mjs +0 -34
- package/dist/tool-schema-json-projection-B8sG1I9v.mjs +0 -180
- package/dist/types-Kdfw_04V.d.mts +0 -1
package/dist/{openai-completions-transport-DuXQOxrH.mjs → openai-completions-transport-DviPEqw3.mjs}
RENAMED
|
@@ -1,39 +1,40 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as createReasoningTagTextPartitioner } from "./reasoning-tag-text-partitioner-DzlRubwU.mjs";
|
|
2
|
+
import { _ as runtimeContextContentToText, f as hasRuntimeContextMarker, p as isRuntimeContextMessage } from "./types-BXd0kI8-.mjs";
|
|
3
|
+
import { t as appendAssistantMessageDiagnostic } from "./diagnostics-DzrF1h4J.mjs";
|
|
2
4
|
import { r as appendAssistantThinking } from "./event-stream-X2gmsUWv.mjs";
|
|
3
5
|
import { i as asOptionalRecord, o as isRecord, r as asOptionalObjectRecord } from "./record-coerce-CNDovvft.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { n as asNonNegativeFiniteNumber, r as asPositiveFiniteNumber } from "./number-coercion-
|
|
6
|
-
import { N as isImageWithMediaPayload, a as resolveAiTransportHeaderSentinels, r as getAiTransportHost } from "./host-
|
|
7
|
-
import {
|
|
8
|
-
import { r as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { r as
|
|
12
|
-
import { d as
|
|
13
|
-
import { c as
|
|
14
|
-
import {
|
|
15
|
-
import { i as
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { C as
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import { n as transformProviderMessages, t as createAssistantOutput } from "./assistant-output-
|
|
23
|
-
import { a as tagUnresolvedTextAsCommentary, i as tagPendingCommentaryText, n as rememberPendingCommentaryTags, r as tagInterruptedTextPhases, t as clearPendingCommentaryText } from "./assistant-text-phase-mvdMcrY-.mjs";
|
|
6
|
+
import { c as readNonEmptyStringPreservingWhitespace, t as hasNonEmptyString } from "./string-coerce-Cj8sqWHx.mjs";
|
|
7
|
+
import { n as asNonNegativeFiniteNumber, r as asPositiveFiniteNumber } from "./number-coercion-37gmNkuA.mjs";
|
|
8
|
+
import { N as isImageWithMediaPayload, a as resolveAiTransportHeaderSentinels, r as getAiTransportHost } from "./host-B2gk-d1H.mjs";
|
|
9
|
+
import { A as supportsOpenAITemperature, C as isOpenAIGpt6Model, L as resolveOpenAIThinkingApi, M as uniqueStrings, S as isOpenAIGpt56Model, _ as responsesServiceTierObserver, b as isOpenAIGpt54MiniModel, d as OpenAIResponsesWebSocketSafeRetryError, h as parseOpenAIResponsesWebSocketServerError, l as OpenAIResponsesWebSocketPostDispatchError, r as OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS, t as AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS, u as OpenAIResponsesWebSocketPreDispatchError, v as isResponsesServiceTierRejection, x as isOpenAIGpt55Model, y as nextResponsesServiceTier } from "./openai-responses-contracts-Bx-16mnf.mjs";
|
|
10
|
+
import { n as getSessionResourceOwnerId, r as registerSessionResourceCleanup } from "./session-resources-vKvGIE3J.mjs";
|
|
11
|
+
import { c as stableStringify, s as truncateUtf16Safe } from "./provider-error-qtZD2inE.mjs";
|
|
12
|
+
import { r as resolveOpenAIPromptCacheParams } from "./openai-prompt-cache-DJ_P143P.mjs";
|
|
13
|
+
import { d as hasOnlyResponsesFunctionTools, i as emitModelTransportError, r as emitModelTransportDebug, t as formatModelTransportDebugBaseUrl } from "./diagnostics-Cv7cW3pS.mjs";
|
|
14
|
+
import { a as estimateStringChars, d as supportsModelTools, n as isProviderReplayContext, r as providerReplayContextMatches, t as buildProviderReplayContext } from "./provider-replay-context-J6CfU3m1.mjs";
|
|
15
|
+
import { c as resolveOpenAIResponsesTextFormat, i as resolveOpenAICompletionsCompat, l as shouldOmitOllamaCompatResponseFormat, n as isNativeOpenAIEndpoint, o as usesNativeOpenAICodexResponsesBackend, r as isOpenAICodexResponsesModel, s as resolveOpenAICompletionsResponseFormat, t as detectOpenAICompletionsCompat } from "./openai-completions-compat-CFhQ3UVU.mjs";
|
|
16
|
+
import { i as resolveProviderEndpoint, t as buildGuardedModelFetch } from "./host-policy-mpqGhbeM.mjs";
|
|
17
|
+
import { i as resolveCacheRetention, r as buildCopilotDynamicHeaders } from "./cloudflare-Dttf8jKq.mjs";
|
|
18
|
+
import { t as sanitizeSurrogates } from "./sanitize-unicode-CRGuMONI.mjs";
|
|
19
|
+
import { r as sortPromptCacheToolsByName } from "./prompt-cache-stability-D_MeCQFI.mjs";
|
|
20
|
+
import { C as splitSystemPromptRelocatableBoundary, S as splitSystemPromptCacheBoundary, T as stripSystemPromptRelocatableBoundary, f as extractToolResultText, g as reasoningTagTextPolicy, h as preparedRequestSuffix, l as describeToolResultMediaPlaceholder, m as codeModeToolSurfaceObserver, r as clampMaxTokensToModel, s as prepareModelRequestBody, w as stripSystemPromptCacheBoundary } from "./simple-options-BYgC6kse.mjs";
|
|
21
|
+
import { A as shortHash, E as createToolArgumentPreviewSchedule, M as racePromiseWithAbortSignal, O as parseStreamingJson, S as withProviderResponseHook, b as transportAbortError, c as failTransportStream, d as iterateModelStream, h as notifyProviderStreamOpened, l as finalizeTerminalToolCallArguments, s as createWritableTransportEventStream, u as finalizeTransportStream, v as sanitizeTransportPayloadText, y as throwIfModelStreamAborted } from "./transport-stream-shared-CzQlAzJH.mjs";
|
|
22
|
+
import { C as redactIdentifier, w as sha256Hex } from "./tool-schema-json-projection-B0hHDV7N.mjs";
|
|
23
|
+
import { n as getEnvApiKey } from "./env-api-keys-Xd8dm_aV.mjs";
|
|
24
|
+
import { n as transformProviderMessages, t as createAssistantOutput } from "./assistant-output-6iFA1nbC.mjs";
|
|
24
25
|
import { t as notifyLlmRequestActivity } from "./llm-request-activity-CfMuh5cC.mjs";
|
|
25
26
|
import { n as resolveOpencodeSessionHeaders } from "./session-affinity-DA4WHv1h.mjs";
|
|
26
27
|
import { isGoogleGemini3ThinkingLevelModel } from "./internal/google-model-family.mjs";
|
|
27
28
|
import "./types.mjs";
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
29
|
+
import { $ as isConfigurationUpdate, A as summarizeResponsesPayload, At as log, B as recordResponsesInputReplay, C as readResponsesRecoveryEvent, Ct as reconcileOpenAIResponsesToolChoice, D as logResponsesFailedNoDetails, E as ResponsesStreamFailure, Et as createOpenAIProviderAcceptanceHook, Ft as resolveOpenAIClientBaseUrl, G as responsesContinuationPrefixFingerprint, H as claimOpenAIResponsesHttpContinuation, I as convertResponsesMessages, It as resolvePromptCacheKey, K as responsesContinuationRequestFingerprint, Lt as withOpenAIErrorResponseHook, Mt as parseOpenAICompletionsUsage, Nt as readOpenAICompletionsContentDeltas, O as safeDebugValue, Ot as createResponseModelTracker, P as buildResponsesInputMessage, Pt as readOpenAICompletionsReasoningBatch, S as isInvalidEncryptedContentError, St as reconcileOpenAICompletionsToolChoice, T as resolveNextResponsesEncryptedContentAttempt, Tt as GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP, U as recordResponsesContinuationState, V as responsesInputFingerprint, W as resolveResponsesContinuationRequest, _t as resolveOpenAIRequestReasoning, a as prepareResponsesTools, bt as prepareOpenAITools, c as observeResponsesStream, ct as buildOpenAIClientHeaders, dt as enforceCodeModeResponsesToolSurface, et as replayResponsesReasoningUpdates, gt as resolveOpenAIStrictToolFlagWithDiagnostics, ht as resolveCodeModeResponsesVisibleToolNames, j as recordResponsesContextUsage, jt as measureUtf8AppendBytes, k as summarizeOpenAITransportError, kt as isOpenAICompletionsThinkingEnabled, lt as buildOpenAISdkClientOptions, n as applyResponsesServiceTierPricing, ot as suppressOpenAIResponsesCompaction, pt as getCompat, rt as buildOpenAIResponsesReasoningReplayMetadata, s as processResponsesStream, st as assertCodeModeResponsesToolSurface, tt as supportsResponsesReasoningUpdate, ut as buildOpenAISdkRequestOptions, vt as resolveOpenAISimpleReasoningEffort, w as resolveAzureOpenAIApiVersion, wt as toOpenAIResponsesToolChoice, x as createResponsesStreamWithRecovery, xt as projectOpenAITools, z as readResponsesInputReplayState } from "./openai-responses-shared-Bv_1NtH9.mjs";
|
|
30
|
+
import { i as createOpenAIProviderClient, n as resolveProviderSimpleCompletionHeaders, r as resolveProviderTransportTurnState, t as filterProviderTurnHeadersForExplicitOpencodeSession } from "./provider-transport-turn-state-Jxppzuc2.mjs";
|
|
31
|
+
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-D_TfJHRJ.mjs";
|
|
30
32
|
import { t as boundResponseBody } from "./streaming-byte-guard-DBXr1XYn.mjs";
|
|
31
|
-
import { f as withPreparedToolSchemaNormalization, r as normalizeOpenAIStrictToolParameters } from "./openai-tool-schema-
|
|
33
|
+
import { b as prepareOpenAIFunctionTool, f as normalizeToolSchema, p as withPreparedToolSchemaNormalization, r as normalizeOpenAIStrictToolParameters } from "./openai-tool-schema-Buv0GXFb.mjs";
|
|
32
34
|
import { t as mapOpenAIStopReason } from "./openai-stop-reason-8s70vDXj.mjs";
|
|
33
|
-
import { t as createReasoningTagTextPartitioner } from "./reasoning-tag-text-partitioner-CpOy9-IQ.mjs";
|
|
34
35
|
import { i as resolveAzureDeploymentNameFromMap, t as isOpenAICompatibleAzureResponsesBaseUrl } from "./azure-openai-responses-client-compat-D0dvJMbZ.mjs";
|
|
35
|
-
import {
|
|
36
|
-
import { n as
|
|
36
|
+
import { a as isOpenAIResponsesCompactionOutput, c as applyOpenAIResponsesPayloadPolicy, d as resolveOpenAIResponsesPayloadPolicy, i as getOpenAIResponsesCompactionOutputError, n as supportsNativeOpenAIResponsesEndpoint, r as createBoundedOpenAIResponsesCompactionFetch, s as sanitizeResponsesImagePayload, t as isOfficialOpenAIResponsesBaseUrl } from "./openai-responses-endpoint-D4v-eeYy.mjs";
|
|
37
|
+
import { a as createResponsesV2CompactionCollector, i as createResponsesPromptEgressObserver, n as responsesRequestLifecycle, o as claimResponsesCompactRequest, r as withResponsesRequestAcceptance, t as independentResponsesRequest } from "./openai-responses-request-lifecycle-CTdAb2v1.mjs";
|
|
37
38
|
import { randomUUID } from "node:crypto";
|
|
38
39
|
import OpenAI, { AzureOpenAI } from "openai";
|
|
39
40
|
import { ResponsesWS } from "openai/resources/responses/ws.js";
|
|
@@ -208,9 +209,21 @@ function applyCompletionsAnthropicCacheControl(payload, cacheControl = { type: "
|
|
|
208
209
|
if (shapedPayloads.has(payload)) return;
|
|
209
210
|
shapedPayloads.add(payload);
|
|
210
211
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
211
|
-
const tools = Array.isArray(payload.tools) ? payload.tools
|
|
212
|
+
const tools = Array.isArray(payload.tools) ? payload.tools : [];
|
|
213
|
+
let lastToolIndex = -1;
|
|
214
|
+
for (let index = 0; index < tools.length; index++) {
|
|
215
|
+
const tool = tools[index];
|
|
216
|
+
if (isRecord(tool)) {
|
|
217
|
+
lastToolIndex = index;
|
|
218
|
+
if (Object.hasOwn(tool, "cache_control")) {
|
|
219
|
+
const unmarked = { ...tool };
|
|
220
|
+
delete unmarked.cache_control;
|
|
221
|
+
tools[index] = unmarked;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
212
225
|
const blocks = messages.filter(isRecord).flatMap((message) => Array.isArray(message.content) ? message.content.filter(isRecord) : []);
|
|
213
|
-
for (const block of
|
|
226
|
+
for (const block of blocks) delete block.cache_control;
|
|
214
227
|
if (!cacheControl) return;
|
|
215
228
|
const markText = (message, splitBoundary) => {
|
|
216
229
|
if (typeof message.content === "string" && message.content) message.content = [{
|
|
@@ -238,8 +251,10 @@ function applyCompletionsAnthropicCacheControl(payload, cacheControl = { type: "
|
|
|
238
251
|
}
|
|
239
252
|
return false;
|
|
240
253
|
};
|
|
241
|
-
|
|
242
|
-
|
|
254
|
+
if (markTools && lastToolIndex >= 0) tools[lastToolIndex] = {
|
|
255
|
+
...tools[lastToolIndex],
|
|
256
|
+
cache_control: cacheControl
|
|
257
|
+
};
|
|
243
258
|
if (!markMessages) return;
|
|
244
259
|
const system = messages.find((message) => isRecord(message) && (message.role === "system" || message.role === "developer"));
|
|
245
260
|
if (isRecord(system)) markText(system, true);
|
|
@@ -452,12 +467,12 @@ function finalizeOpenAICompletionsToolCalls(output, options = {}) {
|
|
|
452
467
|
output.errorMessage = "Provider returned an incomplete or malformed tool call";
|
|
453
468
|
output.content = output.content.filter((candidate) => !isToolCall(candidate));
|
|
454
469
|
};
|
|
455
|
-
if (toolCalls.some((call) => typeof call.name !== "string" || call.name.trim().length === 0 || typeof call.
|
|
470
|
+
if (toolCalls.some((call) => typeof call.name !== "string" || call.name.trim().length === 0 || typeof call.partialJson !== "string" || call.partialJson.trim().length === 0)) {
|
|
456
471
|
rejectToolCalls();
|
|
457
472
|
return;
|
|
458
473
|
}
|
|
459
474
|
try {
|
|
460
|
-
finalizeTerminalToolCallArguments(toolCalls, (call) => call.
|
|
475
|
+
finalizeTerminalToolCallArguments(toolCalls, (call) => call.partialJson);
|
|
461
476
|
} catch {
|
|
462
477
|
rejectToolCalls();
|
|
463
478
|
return;
|
|
@@ -465,12 +480,75 @@ function finalizeOpenAICompletionsToolCalls(output, options = {}) {
|
|
|
465
480
|
for (let contentIndex = 0; contentIndex < output.content.length; contentIndex += 1) {
|
|
466
481
|
const block = output.content[contentIndex];
|
|
467
482
|
if (!block || !isToolCall(block)) continue;
|
|
468
|
-
delete block.
|
|
483
|
+
delete block.partialJson;
|
|
469
484
|
delete block.streamIndex;
|
|
470
485
|
options.onConfirmedToolCall?.(block, contentIndex);
|
|
471
486
|
}
|
|
472
487
|
}
|
|
473
488
|
//#endregion
|
|
489
|
+
//#region packages/ai/src/transports/openai-completions-context-budget-buffer.ts
|
|
490
|
+
const MAX_CONTEXT_BUDGET_BUFFER_CHUNKS = 8192;
|
|
491
|
+
const MAX_CONTEXT_BUDGET_BUFFER_BYTES = 4194304;
|
|
492
|
+
async function bufferContextLimitedCompletions(source, signal) {
|
|
493
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
494
|
+
const chunks = [];
|
|
495
|
+
let bufferedBytes = 0;
|
|
496
|
+
let overflow;
|
|
497
|
+
let finished = false;
|
|
498
|
+
let failed = false;
|
|
499
|
+
let sourceError;
|
|
500
|
+
let finishReason;
|
|
501
|
+
try {
|
|
502
|
+
for (;;) {
|
|
503
|
+
const next = await iterator.next();
|
|
504
|
+
if (next.done) {
|
|
505
|
+
finished = true;
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
const chunk = next.value;
|
|
509
|
+
const chunkBytes = Buffer.byteLength(JSON.stringify(chunk) ?? "", "utf8");
|
|
510
|
+
if (chunks.length >= MAX_CONTEXT_BUDGET_BUFFER_CHUNKS || bufferedBytes + chunkBytes > MAX_CONTEXT_BUDGET_BUFFER_BYTES) {
|
|
511
|
+
overflow = next;
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
chunks.push(chunk);
|
|
515
|
+
bufferedBytes += chunkBytes;
|
|
516
|
+
const chunkFinishReason = chunk?.choices?.[0]?.finish_reason;
|
|
517
|
+
if (chunkFinishReason) finishReason = chunkFinishReason;
|
|
518
|
+
signal?.throwIfAborted();
|
|
519
|
+
}
|
|
520
|
+
} catch (error) {
|
|
521
|
+
failed = true;
|
|
522
|
+
sourceError = error;
|
|
523
|
+
iterator.return?.().catch(() => void 0);
|
|
524
|
+
}
|
|
525
|
+
return {
|
|
526
|
+
bounded: overflow === void 0,
|
|
527
|
+
failed,
|
|
528
|
+
finishReason,
|
|
529
|
+
stream: { async *[Symbol.asyncIterator]() {
|
|
530
|
+
try {
|
|
531
|
+
yield* chunks;
|
|
532
|
+
if (failed) throw sourceError;
|
|
533
|
+
if (overflow !== void 0) {
|
|
534
|
+
yield overflow.value;
|
|
535
|
+
for (;;) {
|
|
536
|
+
const next = await iterator.next();
|
|
537
|
+
if (next.done) {
|
|
538
|
+
finished = true;
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
yield next.value;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
} finally {
|
|
545
|
+
chunks.length = 0;
|
|
546
|
+
if (!finished && !failed) iterator.return?.().catch(() => void 0);
|
|
547
|
+
}
|
|
548
|
+
} }
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
//#endregion
|
|
474
552
|
//#region packages/ai/src/transports/openai-completions-host.ts
|
|
475
553
|
/**
|
|
476
554
|
* Chat Completions accepts Azure AI Foundry hosts in addition to traditional
|
|
@@ -489,6 +567,7 @@ function hasToolCallHistory(messages) {
|
|
|
489
567
|
/** Convert a normalized transcript to OpenAI Chat Completions messages. */
|
|
490
568
|
function convertMessages(model, context, compat, options = {}) {
|
|
491
569
|
const params = [];
|
|
570
|
+
const supportsTools = options.supportsTools !== false;
|
|
492
571
|
const normalizeToolCallId = (id) => {
|
|
493
572
|
if (id.includes("|")) return id.slice(0, id.indexOf("|")).replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 40);
|
|
494
573
|
if (model.provider === "openai") return id.length > 40 ? truncateUtf16Safe(id, 40) : id;
|
|
@@ -566,7 +645,10 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
566
645
|
msg.content.forEach((block) => {
|
|
567
646
|
if (block.type === "text" && block.text.trim().length > 0) assistantTexts.push(sanitizeSurrogates(block.text));
|
|
568
647
|
else if (block.type === "thinking" && block.thinking.trim().length > 0) nonEmptyThinkingBlocks.push(block);
|
|
569
|
-
else if (block.type === "toolCall")
|
|
648
|
+
else if (block.type === "toolCall") {
|
|
649
|
+
if (supportsTools) toolCalls.push(block);
|
|
650
|
+
else assistantTexts.push(sanitizeSurrogates(`[tool call id=${block.id} name=${block.name}] ${JSON.stringify(block.arguments)}`));
|
|
651
|
+
}
|
|
570
652
|
});
|
|
571
653
|
if (nonEmptyThinkingBlocks.length > 0 && compat.requiresThinkingAsText) assistantMsg.content = [{
|
|
572
654
|
type: "text",
|
|
@@ -618,13 +700,28 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
618
700
|
const textResult = extractToolResultText(toolMsg.content);
|
|
619
701
|
const mediaPlaceholder = describeToolResultMediaPlaceholder(toolMsg.content);
|
|
620
702
|
const images = toolMsg.content.filter(isImageWithMediaPayload);
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
703
|
+
const content = textResult.trim() ? textResult : mediaPlaceholder ?? "(no output)";
|
|
704
|
+
if (supportsTools) {
|
|
705
|
+
const toolResultMsg = {
|
|
706
|
+
role: "tool",
|
|
707
|
+
content,
|
|
708
|
+
tool_call_id: preparedRequestSuffix.has(context) ? preparedRequestSuffix.toolCallId(context, toolMsg.toolCallId, normalizeToolCallId(toolMsg.toolCallId)) : toolMsg.toolCallId
|
|
709
|
+
};
|
|
710
|
+
if (compat.requiresToolResultName && toolMsg.toolName) toolResultMsg.name = toolMsg.toolName;
|
|
711
|
+
params.push(toolResultMsg);
|
|
712
|
+
} else {
|
|
713
|
+
const text = sanitizeSurrogates(`[tool result id=${toolMsg.toolCallId} name=${toolMsg.toolName}] ${content}`);
|
|
714
|
+
const previous = params.at(-1);
|
|
715
|
+
if (previous?.role !== "assistant") params.push({
|
|
716
|
+
role: "assistant",
|
|
717
|
+
content: text
|
|
718
|
+
});
|
|
719
|
+
else if (Array.isArray(previous.content)) previous.content.push({
|
|
720
|
+
type: "text",
|
|
721
|
+
text
|
|
722
|
+
});
|
|
723
|
+
else previous.content = previous.content ? `${previous.content}\n${text}` : text;
|
|
724
|
+
}
|
|
628
725
|
if (images.length > 0 && model.input.includes("image")) {
|
|
629
726
|
const boundedToolName = sanitizeSurrogates(truncateUtf16Safe(toolMsg.toolName ?? "", 64));
|
|
630
727
|
imageContentParts.push({
|
|
@@ -640,7 +737,7 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
640
737
|
}
|
|
641
738
|
i = j - 1;
|
|
642
739
|
if (imageContentParts.length > 0) {
|
|
643
|
-
if (compat.requiresAssistantAfterToolResult) params.push({
|
|
740
|
+
if (supportsTools && compat.requiresAssistantAfterToolResult) params.push({
|
|
644
741
|
role: "assistant",
|
|
645
742
|
content: "I have processed the tool results."
|
|
646
743
|
});
|
|
@@ -649,7 +746,7 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
649
746
|
content: imageContentParts
|
|
650
747
|
});
|
|
651
748
|
lastRole = "user";
|
|
652
|
-
} else lastRole = "toolResult";
|
|
749
|
+
} else lastRole = supportsTools ? "toolResult" : "assistant";
|
|
653
750
|
continue;
|
|
654
751
|
}
|
|
655
752
|
lastRole = msg.role;
|
|
@@ -686,7 +783,7 @@ function applyCompletionsReasoningAndRouting(params, model, reasoning, compat, m
|
|
|
686
783
|
const direct = mode === "direct";
|
|
687
784
|
const nativeEffort = compat.thinkingFormat === "openrouter" ? void 0 : reasoning.effort;
|
|
688
785
|
const enabled = reasoning.thinkingEnabled ?? false;
|
|
689
|
-
if (model.reasoning) {
|
|
786
|
+
if (model.reasoning && (!compat.thinkingOffControlUndeclared || reasoning.thinkingEnabled !== void 0 || !reasoning.thinkingExplicit)) {
|
|
690
787
|
let allowScalarEffort = true;
|
|
691
788
|
if (direct && compat.thinkingFormat === "zai") {
|
|
692
789
|
params.thinking = enabled ? {
|
|
@@ -698,9 +795,11 @@ function applyCompletionsReasoningAndRouting(params, model, reasoning, compat, m
|
|
|
698
795
|
params.enable_thinking = enabled;
|
|
699
796
|
allowScalarEffort = false;
|
|
700
797
|
} else if (compat.thinkingFormat === "qwen-chat-template") {
|
|
798
|
+
const chatTemplateReasoningEffort = enabled && reasoning.thinkingExplicit && model.compat?.supportedReasoningEfforts?.length ? reasoning.effort : void 0;
|
|
701
799
|
params.chat_template_kwargs = {
|
|
702
800
|
enable_thinking: enabled,
|
|
703
|
-
...direct ? { preserve_thinking: true } : {}
|
|
801
|
+
...direct ? { preserve_thinking: true } : {},
|
|
802
|
+
...chatTemplateReasoningEffort ? { reasoning_effort: chatTemplateReasoningEffort } : {}
|
|
704
803
|
};
|
|
705
804
|
allowScalarEffort = false;
|
|
706
805
|
} else if (compat.thinkingFormat === "together" || direct && compat.thinkingFormat === "deepseek") {
|
|
@@ -879,10 +978,6 @@ function resolveOpenAICompletionsMaxTokens(model, options) {
|
|
|
879
978
|
clampToModelMaxTokens: false
|
|
880
979
|
};
|
|
881
980
|
}
|
|
882
|
-
function resolveOpenAICompletionsModelMaxTokens(model) {
|
|
883
|
-
const maxTokens = asPositiveFiniteNumber(model.maxTokens);
|
|
884
|
-
return maxTokens === void 0 ? void 0 : Math.floor(maxTokens);
|
|
885
|
-
}
|
|
886
981
|
const OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN = 1.25;
|
|
887
982
|
const OPENAI_COMPLETIONS_IMAGE_CHAR_ESTIMATE = 8e3;
|
|
888
983
|
const MIN_USEFUL_OUTPUT_TOKENS = 16;
|
|
@@ -894,8 +989,7 @@ function estimateJsonChars(value, fallback) {
|
|
|
894
989
|
}
|
|
895
990
|
}
|
|
896
991
|
function estimateOpenAICompletionsInputTokens(payload) {
|
|
897
|
-
let adjustedChars =
|
|
898
|
-
adjustedChars += estimateOpenAICompletionsMessagesChars(payload.messages);
|
|
992
|
+
let adjustedChars = estimateOpenAICompletionsMessagesChars(payload.messages);
|
|
899
993
|
if (payload.tools?.length) adjustedChars += estimateJsonChars(payload.tools, 1024);
|
|
900
994
|
if (payload.response_format !== void 0) adjustedChars += estimateJsonChars(payload.response_format, 256);
|
|
901
995
|
return Math.ceil(adjustedChars / 4 * OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN);
|
|
@@ -945,16 +1039,8 @@ function convertTools(tools, compat, model, mode) {
|
|
|
945
1039
|
return {
|
|
946
1040
|
projection,
|
|
947
1041
|
tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
|
|
948
|
-
const
|
|
949
|
-
|
|
950
|
-
description: tool.description,
|
|
951
|
-
parameters: mode === "direct" ? tool.parameters : normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, model.compat)
|
|
952
|
-
};
|
|
953
|
-
if (strict !== void 0) functionTool.strict = strict;
|
|
954
|
-
return {
|
|
955
|
-
type: "function",
|
|
956
|
-
function: functionTool
|
|
957
|
-
};
|
|
1042
|
+
const parameters = compat.requiresTypedUnionBranches ? normalizeToolSchema(tool.parameters, "moonshot") : tool.parameters;
|
|
1043
|
+
return prepareOpenAIFunctionTool(tool.name, tool.description, mode === "direct" ? parameters : normalizeOpenAIStrictToolParameters(parameters, strict === true, model.compat), strict).completions;
|
|
958
1044
|
})
|
|
959
1045
|
};
|
|
960
1046
|
};
|
|
@@ -963,7 +1049,22 @@ function convertTools(tools, compat, model, mode) {
|
|
|
963
1049
|
function buildOpenAICompletionsParams(model, context, options) {
|
|
964
1050
|
return buildOpenAICompletionsRequest(model, context, options, { mode: "managed" });
|
|
965
1051
|
}
|
|
1052
|
+
const contextOutputBudgets = /* @__PURE__ */ new WeakMap();
|
|
1053
|
+
function completionsInputHash(payload) {
|
|
1054
|
+
return shortHash(JSON.stringify([
|
|
1055
|
+
payload.messages,
|
|
1056
|
+
payload.tools,
|
|
1057
|
+
payload.response_format
|
|
1058
|
+
]));
|
|
1059
|
+
}
|
|
1060
|
+
function resolveCompletionsContextOutputBudget(request, payload) {
|
|
1061
|
+
const budget = contextOutputBudgets.get(request);
|
|
1062
|
+
const limits = [payload.max_tokens, payload.max_completion_tokens].filter((value) => value !== void 0);
|
|
1063
|
+
if (!budget || payload.model !== budget.model || !Array.isArray(payload.messages) || payload.tools !== void 0 && !Array.isArray(payload.tools) || limits.length === 0 || limits.some((value) => value !== budget.cap) || completionsInputHash(payload) !== budget.inputHash) return;
|
|
1064
|
+
return budget.cap;
|
|
1065
|
+
}
|
|
966
1066
|
function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
1067
|
+
let contextOutputCap;
|
|
967
1068
|
const resolvedPolicy = policy.mode === "direct" ? policy : {
|
|
968
1069
|
...policy,
|
|
969
1070
|
compat: getCompat(model)
|
|
@@ -981,8 +1082,10 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
981
1082
|
"qwen"
|
|
982
1083
|
].includes(model.provider));
|
|
983
1084
|
const cacheOptOutIndexes = /* @__PURE__ */ new Set();
|
|
1085
|
+
const supportsTools = policy.mode === "direct" || supportsModelTools(model);
|
|
984
1086
|
const convertedMessages = convertMessages(model, context, compat, {
|
|
985
1087
|
cacheOptOutIndexes,
|
|
1088
|
+
supportsTools,
|
|
986
1089
|
preserveSystemPromptCacheBoundary: cacheControl !== void 0 && !managedCompat?.requiresStringContent
|
|
987
1090
|
});
|
|
988
1091
|
let messages = convertedMessages;
|
|
@@ -1015,7 +1118,7 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1015
1118
|
if (policy.mode === "managed" && options?.seed !== void 0) params.seed = options.seed;
|
|
1016
1119
|
if (options?.stop !== void 0 && options.stop.length > 0) params.stop = options.stop;
|
|
1017
1120
|
let directToolProjection;
|
|
1018
|
-
if (
|
|
1121
|
+
if (supportsTools) {
|
|
1019
1122
|
if (context.tools) {
|
|
1020
1123
|
const converted = convertTools(context.tools, compat, model, policy.mode);
|
|
1021
1124
|
if (policy.mode === "direct") directToolProjection = converted.projection;
|
|
@@ -1044,7 +1147,11 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1044
1147
|
...model,
|
|
1045
1148
|
compat: model.compat ?? void 0
|
|
1046
1149
|
}, simpleReasoning)) ?? (usesBinaryOpenRouterThinking ? void 0 : "high");
|
|
1047
|
-
const
|
|
1150
|
+
const thinkingExplicit = options?.openclawThinkingExplicit ?? (options?.reasoningEffort !== void 0 || options?.reasoning !== void 0);
|
|
1151
|
+
const reasoning = {
|
|
1152
|
+
...resolveOpenAIRequestReasoning(model, requestedEffort, compat.reasoningEffortForOff),
|
|
1153
|
+
thinkingExplicit
|
|
1154
|
+
};
|
|
1048
1155
|
const { effort, thinkingEnabled } = reasoning;
|
|
1049
1156
|
{
|
|
1050
1157
|
const maxTokenBudget = policy.mode === "direct" ? {
|
|
@@ -1054,7 +1161,8 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1054
1161
|
const effectiveMaxTokens = maxTokenBudget.maxTokens;
|
|
1055
1162
|
const effectiveContextTokens = asPositiveFiniteNumber(model.contextTokens) ?? asPositiveFiniteNumber(model.contextWindow);
|
|
1056
1163
|
let clampedMaxTokens = effectiveMaxTokens;
|
|
1057
|
-
const
|
|
1164
|
+
const modelOutputLimit = asPositiveFiniteNumber(model.maxTokens);
|
|
1165
|
+
const modelMaxTokens = modelOutputLimit === void 0 ? void 0 : Math.floor(modelOutputLimit);
|
|
1058
1166
|
if (maxTokenBudget.clampToModelMaxTokens && clampedMaxTokens !== void 0 && modelMaxTokens !== void 0 && clampedMaxTokens > modelMaxTokens) {
|
|
1059
1167
|
clampedMaxTokens = modelMaxTokens;
|
|
1060
1168
|
if (policy.mode === "managed") emitModelTransportDebug(log, `[completions] clamp_max_tokens provider=${model.provider} api=${model.api} model=${model.id} requested=${effectiveMaxTokens} output=${clampedMaxTokens} modelMaxTokens=${modelMaxTokens}`);
|
|
@@ -1063,8 +1171,9 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1063
1171
|
const estimatedInputTokens = estimateOpenAICompletionsInputTokens(params);
|
|
1064
1172
|
const remainingBudget = Math.max(0, effectiveContextTokens - estimatedInputTokens - 1);
|
|
1065
1173
|
if (clampedMaxTokens > remainingBudget) {
|
|
1066
|
-
if (remainingBudget < MIN_USEFUL_OUTPUT_TOKENS) throw Object.assign(/* @__PURE__ */ new Error(`Context window exceeded: estimated input ${estimatedInputTokens} leaves only ${remainingBudget} output tokens within the ${effectiveContextTokens}-token context.`), { code: "context_length_exceeded" });
|
|
1174
|
+
if (remainingBudget < (params.tools?.length && params.tool_choice !== "none" ? Math.max(MIN_USEFUL_OUTPUT_TOKENS, Math.min(2048, Math.ceil((modelMaxTokens ?? 0) / 8))) : MIN_USEFUL_OUTPUT_TOKENS)) throw Object.assign(/* @__PURE__ */ new Error(`Context window exceeded: estimated input ${estimatedInputTokens} leaves only ${remainingBudget} output tokens within the ${effectiveContextTokens}-token context.`), { code: "context_length_exceeded" });
|
|
1067
1175
|
clampedMaxTokens = remainingBudget;
|
|
1176
|
+
contextOutputCap = remainingBudget;
|
|
1068
1177
|
emitModelTransportDebug(log, `[completions] clamp_max_tokens provider=${model.provider} api=${model.api} model=${model.id} requested=${effectiveMaxTokens} output=${clampedMaxTokens} effectiveContext=${effectiveContextTokens} estimatedInput=${estimatedInputTokens}`);
|
|
1069
1178
|
}
|
|
1070
1179
|
}
|
|
@@ -1083,6 +1192,11 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1083
1192
|
if (isOpenAIGpt56Model(model)) params.reasoning_effort = "none";
|
|
1084
1193
|
else if (isOpenAIGpt54MiniModel(model) || isOpenAIGpt55Model(model)) delete params.reasoning_effort;
|
|
1085
1194
|
}
|
|
1195
|
+
if (contextOutputCap !== void 0) contextOutputBudgets.set(params, {
|
|
1196
|
+
model: params.model,
|
|
1197
|
+
cap: contextOutputCap,
|
|
1198
|
+
inputHash: completionsInputHash(params)
|
|
1199
|
+
});
|
|
1086
1200
|
return params;
|
|
1087
1201
|
}
|
|
1088
1202
|
//#endregion
|
|
@@ -1219,7 +1333,7 @@ function parseDeepSeekDsmlToolCallBlock(body) {
|
|
|
1219
1333
|
kind: "toolCall",
|
|
1220
1334
|
name: invokeName,
|
|
1221
1335
|
arguments: parsedArguments,
|
|
1222
|
-
|
|
1336
|
+
partialJson: JSON.stringify(parsedArguments)
|
|
1223
1337
|
});
|
|
1224
1338
|
}
|
|
1225
1339
|
return toolCalls;
|
|
@@ -1380,7 +1494,7 @@ function recoverGemmaCalls(text) {
|
|
|
1380
1494
|
kind: "toolCall",
|
|
1381
1495
|
name,
|
|
1382
1496
|
arguments: argumentsValue,
|
|
1383
|
-
|
|
1497
|
+
partialJson: JSON.stringify(argumentsValue)
|
|
1384
1498
|
});
|
|
1385
1499
|
} catch {
|
|
1386
1500
|
return;
|
|
@@ -1438,6 +1552,38 @@ function extractToolCallThoughtSignature(toolCall) {
|
|
|
1438
1552
|
const extra = tc.extra_content?.google;
|
|
1439
1553
|
return readNonEmptyStringPreservingWhitespace(extra?.thought_signature) ?? readNonEmptyStringPreservingWhitespace(tc.function?.thought_signature) ?? readNonEmptyStringPreservingWhitespace(tc.thought_signature);
|
|
1440
1554
|
}
|
|
1555
|
+
async function* observeOpenAICompletionsProgress(responseStream, signal) {
|
|
1556
|
+
const maxUsageTokens = {
|
|
1557
|
+
prompt: 0,
|
|
1558
|
+
completion: 0,
|
|
1559
|
+
total: 0,
|
|
1560
|
+
reasoning: 0
|
|
1561
|
+
};
|
|
1562
|
+
for await (const rawChunk of responseStream) {
|
|
1563
|
+
throwIfModelStreamAborted(signal);
|
|
1564
|
+
if (rawChunk && typeof rawChunk === "object") {
|
|
1565
|
+
const chunk = rawChunk;
|
|
1566
|
+
const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : void 0;
|
|
1567
|
+
const usage = chunk.usage || choice?.usage;
|
|
1568
|
+
let hasUsageProgress = false;
|
|
1569
|
+
for (const [counter, reported] of [
|
|
1570
|
+
["prompt", usage?.prompt_tokens],
|
|
1571
|
+
["completion", usage?.completion_tokens],
|
|
1572
|
+
["total", usage?.total_tokens],
|
|
1573
|
+
["reasoning", usage?.completion_tokens_details?.reasoning_tokens]
|
|
1574
|
+
]) {
|
|
1575
|
+
const tokens = asPositiveFiniteNumber(reported) ?? 0;
|
|
1576
|
+
if (tokens > maxUsageTokens[counter]) {
|
|
1577
|
+
maxUsageTokens[counter] = tokens;
|
|
1578
|
+
hasUsageProgress = true;
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
const rawChoiceDelta = choice?.delta ?? choice?.message;
|
|
1582
|
+
notifyLlmRequestActivity(signal, Boolean(hasUsageProgress || choice?.finish_reason || rawChoiceDelta && (rawChoiceDelta.tool_calls?.length || hasOpenAICompletionsDeltaContent(rawChoiceDelta))));
|
|
1583
|
+
}
|
|
1584
|
+
yield rawChunk;
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1441
1587
|
async function processCompletionsStream(responseStream, output, model, stream, options) {
|
|
1442
1588
|
const MAX_POST_TOOL_CALL_BUFFER_BYTES = 256e3;
|
|
1443
1589
|
const directMode = options?.mode === "direct";
|
|
@@ -1454,17 +1600,14 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1454
1600
|
let currentBlock = null;
|
|
1455
1601
|
const directContent = { block: null };
|
|
1456
1602
|
let currentTextSource;
|
|
1457
|
-
let
|
|
1458
|
-
let confirmedInterruptedTextBlock = null;
|
|
1603
|
+
let sawReasoning = false;
|
|
1459
1604
|
let pendingPostToolCallDeltas = [];
|
|
1460
1605
|
let pendingPostToolCallBytes = 0;
|
|
1461
1606
|
const toolCallBlocksByIndex = /* @__PURE__ */ new Map();
|
|
1462
1607
|
const toolCallBlocksById = /* @__PURE__ */ new Map();
|
|
1463
1608
|
const encryptedReasoning = createOpenAIEncryptedToolCallReasoningTracker();
|
|
1464
1609
|
const toolArgumentPreviewSchedules = /* @__PURE__ */ new WeakMap();
|
|
1465
|
-
const provisionalCommentaryTags = directMode ? options.provisionalCommentaryTags : /* @__PURE__ */ new Map();
|
|
1466
1610
|
const blockIndices = /* @__PURE__ */ new WeakMap();
|
|
1467
|
-
let explicitVisibleTextBlocks;
|
|
1468
1611
|
const normalizeToolCallDeltas = createOpenAICompletionsToolCallDeltaNormalizer();
|
|
1469
1612
|
let finishReason;
|
|
1470
1613
|
let sawNativeToolCallDelta = false;
|
|
@@ -1472,7 +1615,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1472
1615
|
let chunkPushedEvent = false;
|
|
1473
1616
|
const pushStreamEvent = (event) => {
|
|
1474
1617
|
chunkPushedEvent = true;
|
|
1475
|
-
stream.push(
|
|
1618
|
+
stream.push(event);
|
|
1476
1619
|
};
|
|
1477
1620
|
const appendToolCallBlock = (block) => {
|
|
1478
1621
|
output.content.push(block);
|
|
@@ -1506,7 +1649,6 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1506
1649
|
text: ""
|
|
1507
1650
|
};
|
|
1508
1651
|
currentTextSource = delta.source;
|
|
1509
|
-
if (delta.source === "reasoning_detail") (explicitVisibleTextBlocks ??= /* @__PURE__ */ new Set()).add(currentBlock);
|
|
1510
1652
|
} else currentBlock = {
|
|
1511
1653
|
type: "thinking",
|
|
1512
1654
|
thinking: "",
|
|
@@ -1522,13 +1664,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1522
1664
|
});
|
|
1523
1665
|
}
|
|
1524
1666
|
if (currentBlock.type === "thinking") appendAssistantThinking(currentBlock, delta.text);
|
|
1525
|
-
else
|
|
1526
|
-
currentBlock.text += delta.text;
|
|
1527
|
-
if (pendingInterruptedTextBlock && delta.text.trim()) {
|
|
1528
|
-
confirmedInterruptedTextBlock = pendingInterruptedTextBlock;
|
|
1529
|
-
pendingInterruptedTextBlock = null;
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1667
|
+
else currentBlock.text += delta.text;
|
|
1532
1668
|
const event = {
|
|
1533
1669
|
contentIndex: blockIndex(),
|
|
1534
1670
|
delta: delta.text
|
|
@@ -1580,20 +1716,19 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1580
1716
|
currentBlock = null;
|
|
1581
1717
|
flushPendingPostToolCallDeltas();
|
|
1582
1718
|
}
|
|
1583
|
-
rememberPendingCommentaryTags(provisionalCommentaryTags, tagPendingCommentaryText(output.content));
|
|
1584
1719
|
const block = {
|
|
1585
1720
|
type: "toolCall",
|
|
1586
1721
|
id: `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`,
|
|
1587
1722
|
name: toolCall.name,
|
|
1588
1723
|
arguments: toolCall.arguments,
|
|
1589
|
-
|
|
1724
|
+
partialJson: toolCall.partialJson
|
|
1590
1725
|
};
|
|
1591
1726
|
currentBlock = block;
|
|
1592
1727
|
appendToolCallBlock(block);
|
|
1593
1728
|
pushStreamEvent({
|
|
1594
1729
|
type: "toolcall_delta",
|
|
1595
1730
|
contentIndex: blockIndices.get(block) ?? -1,
|
|
1596
|
-
delta: toolCall.
|
|
1731
|
+
delta: toolCall.partialJson,
|
|
1597
1732
|
partial: output
|
|
1598
1733
|
});
|
|
1599
1734
|
};
|
|
@@ -1624,7 +1759,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1624
1759
|
});
|
|
1625
1760
|
};
|
|
1626
1761
|
const flushReasoningTagTextPartitioner = (allowRecovery = true) => {
|
|
1627
|
-
const recoverUnclosed = allowRecovery && output.stopReason !== "length" && output.stopReason !== "error" && output.stopReason !== "aborted";
|
|
1762
|
+
const recoverUnclosed = allowRecovery && !sawReasoning && output.stopReason !== "length" && output.stopReason !== "error" && output.stopReason !== "aborted";
|
|
1628
1763
|
for (const delta of reasoningTagTextPartitioner.flush({ recoverUnclosed })) appendPartitionedVisibleDelta(delta);
|
|
1629
1764
|
};
|
|
1630
1765
|
const flushGemmaToolCallRecoverer = (allowRecovery = true) => {
|
|
@@ -1635,36 +1770,17 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1635
1770
|
if (currentBlock?.type !== "text" && !reasoningTagTextPartitioner.hasPending()) return;
|
|
1636
1771
|
flushReasoningTagTextPartitioner();
|
|
1637
1772
|
if (currentBlock?.type !== "text") return;
|
|
1638
|
-
if (currentTextSource !== "reasoning_detail" && currentBlock.text.trim()) pendingInterruptedTextBlock = currentBlock;
|
|
1639
1773
|
currentBlock = null;
|
|
1640
1774
|
if (directMode) directContent.block = null;
|
|
1641
1775
|
currentTextSource = void 0;
|
|
1642
1776
|
};
|
|
1643
|
-
const beginReasoning = (hasFollowingVisibleText
|
|
1644
|
-
|
|
1645
|
-
...output.openclawDelivery,
|
|
1646
|
-
textPhaseRequiresTerminal: true
|
|
1647
|
-
};
|
|
1648
|
-
if (forceStrict || reasoningTagTextPartitioner.hasPending()) reasoningTagTextPartitioner.markStrict();
|
|
1777
|
+
const beginReasoning = (hasFollowingVisibleText) => {
|
|
1778
|
+
sawReasoning = true;
|
|
1649
1779
|
if (!hasFollowingVisibleText || !reasoningTagTextPartitioner.hasPendingSyntax()) sealTextBeforeReasoning();
|
|
1650
1780
|
};
|
|
1651
|
-
const
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
model: model.id,
|
|
1655
|
-
timeoutMs: options?.firstEventTimeoutMs ?? 0,
|
|
1656
|
-
stage: "completions",
|
|
1657
|
-
abort: options?.abortFirstEventStream,
|
|
1658
|
-
onTimeout: options?.onFirstEventTimeout,
|
|
1659
|
-
hint: "The provider may be stalled while parsing the tool payload; retry with a smaller tool surface or enable OPENCLAW_DEBUG_MODEL_PAYLOAD=tools to inspect exposed tools."
|
|
1660
|
-
});
|
|
1661
|
-
const events = directMode ? guardedStream : iterateModelStream(guardedStream, options?.signal);
|
|
1662
|
-
const maxUsageTokens = {
|
|
1663
|
-
prompt: 0,
|
|
1664
|
-
completion: 0,
|
|
1665
|
-
total: 0,
|
|
1666
|
-
reasoning: 0
|
|
1667
|
-
};
|
|
1781
|
+
const events = directMode ? responseStream : iterateModelStream(responseStream, options?.signal);
|
|
1782
|
+
let maxReasoningTokens = 0;
|
|
1783
|
+
let providerProcessingMs;
|
|
1668
1784
|
for await (const rawChunk of events) {
|
|
1669
1785
|
throwIfModelStreamAborted(options?.signal);
|
|
1670
1786
|
chunkPushedEvent = false;
|
|
@@ -1674,24 +1790,21 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1674
1790
|
if (typeof chunk.model === "string" && chunk.model.length > 0 && chunk.model !== model.id) output.responseModel ||= chunk.model;
|
|
1675
1791
|
const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : void 0;
|
|
1676
1792
|
const usage = chunk.usage || choice?.usage;
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
}
|
|
1793
|
+
if (chunk.timings !== void 0 && (choice?.finish_reason || Array.isArray(chunk.choices) && chunk.choices.length === 0 && chunk.usage)) {
|
|
1794
|
+
const promptMs = asNonNegativeFiniteNumber(chunk.timings?.prompt_ms);
|
|
1795
|
+
const predictedMs = asNonNegativeFiniteNumber(chunk.timings?.predicted_ms);
|
|
1796
|
+
providerProcessingMs = promptMs !== void 0 && predictedMs !== void 0 ? asNonNegativeFiniteNumber(promptMs + predictedMs) : void 0;
|
|
1797
|
+
}
|
|
1798
|
+
const reasoningTokens = asPositiveFiniteNumber(usage?.completion_tokens_details?.reasoning_tokens) ?? 0;
|
|
1799
|
+
const hasReasoningUsageActivity = reasoningTokens > maxReasoningTokens;
|
|
1800
|
+
maxReasoningTokens = Math.max(maxReasoningTokens, reasoningTokens);
|
|
1801
|
+
if (usage) {
|
|
1802
|
+
output.usage = parseOpenAICompletionsUsage(usage, model, { includeReasoningTokens: !directMode });
|
|
1803
|
+
const terminalUsage = Boolean(finishReason || choice?.finish_reason || chunk.choices?.length === 0);
|
|
1804
|
+
const completeCounts = [usage.prompt_tokens, usage.completion_tokens].every((value) => typeof value === "number" && Number.isFinite(value) && value >= 0);
|
|
1805
|
+
output.usage.usageReport = { state: terminalUsage && completeCounts ? "available" : "unavailable" };
|
|
1691
1806
|
}
|
|
1692
|
-
if (usage) output.usage = parseOpenAICompletionsUsage(usage, model, { includeReasoningTokens: !directMode });
|
|
1693
1807
|
const rawChoiceDelta = choice?.delta ?? choice?.message;
|
|
1694
|
-
notifyLlmRequestActivity(options?.signal, Boolean(hasUsageProgress || choice?.finish_reason || rawChoiceDelta && (rawChoiceDelta.tool_calls?.length || hasOpenAICompletionsDeltaContent(rawChoiceDelta))));
|
|
1695
1808
|
if (!choice) {
|
|
1696
1809
|
emitReasoningUsageActivity(hasReasoningUsageActivity);
|
|
1697
1810
|
continue;
|
|
@@ -1716,15 +1829,12 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1716
1829
|
const lastVisibleTextIndex = contentDeltas.findLastIndex((delta) => delta.kind === "text");
|
|
1717
1830
|
const hasSameChunkVisibleText = reasoningBatch.hasVisibleText || lastVisibleTextIndex !== -1;
|
|
1718
1831
|
if (hasReasoningThinking) {
|
|
1719
|
-
beginReasoning(hasSameChunkVisibleText
|
|
1832
|
+
beginReasoning(hasSameChunkVisibleText);
|
|
1720
1833
|
appendReasoningDeltas(reasoningDeltas);
|
|
1721
1834
|
}
|
|
1722
1835
|
for (const [contentDeltaIndex, contentDelta] of contentDeltas.entries()) if (contentDelta.kind === "text") {
|
|
1723
1836
|
const parts = gemmaToolCallRecoverer?.push(contentDelta.text) ?? [contentDelta];
|
|
1724
|
-
for (const part of parts)
|
|
1725
|
-
const routedDeltas = hasReasoningThinking ? reasoningTagTextPartitioner.push(part.text) : reasoningTagTextPartitioner.pushVisible(part.text);
|
|
1726
|
-
for (const routedDelta of routedDeltas) appendPartitionedVisibleDelta(routedDelta);
|
|
1727
|
-
}
|
|
1837
|
+
for (const part of parts) for (const routedDelta of reasoningTagTextPartitioner.pushVisible(part.text)) appendPartitionedVisibleDelta(routedDelta);
|
|
1728
1838
|
} else {
|
|
1729
1839
|
beginReasoning(contentDeltaIndex < lastVisibleTextIndex);
|
|
1730
1840
|
if (emitReasoning) {
|
|
@@ -1738,7 +1848,6 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1738
1848
|
flushGemmaToolCallRecoverer(false);
|
|
1739
1849
|
sawNativeToolCallDelta = true;
|
|
1740
1850
|
flushReasoningTagTextPartitioner(false);
|
|
1741
|
-
rememberPendingCommentaryTags(provisionalCommentaryTags, tagPendingCommentaryText(output.content));
|
|
1742
1851
|
for (const toolCall of toolCallDeltas) {
|
|
1743
1852
|
const streamIndex = typeof toolCall.index === "number" ? toolCall.index : void 0;
|
|
1744
1853
|
let block = streamIndex !== void 0 ? toolCallBlocksByIndex.get(streamIndex) : void 0;
|
|
@@ -1756,7 +1865,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1756
1865
|
id: toolCall.id || "",
|
|
1757
1866
|
name: toolCall.function?.name || "",
|
|
1758
1867
|
arguments: {},
|
|
1759
|
-
|
|
1868
|
+
partialJson: "",
|
|
1760
1869
|
...initialSig ? { thoughtSignature: initialSig } : {}
|
|
1761
1870
|
};
|
|
1762
1871
|
encryptedReasoning.rememberToolCall(block.id, block);
|
|
@@ -1777,8 +1886,8 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1777
1886
|
if (deltaSig) block.thoughtSignature = deltaSig;
|
|
1778
1887
|
const toolArgumentsDelta = toolCall.function?.arguments;
|
|
1779
1888
|
if (toolArgumentsDelta) {
|
|
1780
|
-
block.
|
|
1781
|
-
if (toolArgumentPreviewSchedules.get(block)?.(block.
|
|
1889
|
+
block.partialJson += toolArgumentsDelta;
|
|
1890
|
+
if (toolArgumentPreviewSchedules.get(block)?.(block.partialJson.length)) block.arguments = parseStreamingJson(block.partialJson);
|
|
1782
1891
|
}
|
|
1783
1892
|
if (toolArgumentsDelta || directMode) pushStreamEvent({
|
|
1784
1893
|
type: "toolcall_delta",
|
|
@@ -1813,14 +1922,16 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1813
1922
|
});
|
|
1814
1923
|
}
|
|
1815
1924
|
});
|
|
1816
|
-
|
|
1817
|
-
if (output.stopReason !== "
|
|
1818
|
-
if (output.stopReason === "error" || output.stopReason === "aborted") tagUnresolvedTextAsCommentary(output);
|
|
1819
|
-
if (output.stopReason === "toolUse") tagPendingCommentaryText(output.content);
|
|
1820
|
-
if (!output.usage.contextUsage && !options?.signal?.aborted && output.stopReason !== "error" && output.stopReason !== "aborted") {
|
|
1925
|
+
output.usage.usageReport ??= { state: "unavailable" };
|
|
1926
|
+
if ((!output.usage.contextUsage || output.usage.usageReport.state === "unavailable") && !options?.signal?.aborted && output.stopReason !== "error" && output.stopReason !== "aborted") {
|
|
1821
1927
|
output.usage.contextUsage = { state: "unavailable" };
|
|
1822
1928
|
if (!compat.supportsUsageInStreaming) warnMissingStreamingUsage(openAIModel);
|
|
1823
1929
|
}
|
|
1930
|
+
if (providerProcessingMs !== void 0) appendAssistantMessageDiagnostic(output, {
|
|
1931
|
+
type: "provider_timing",
|
|
1932
|
+
timestamp: Date.now(),
|
|
1933
|
+
details: { processingMs: providerProcessingMs }
|
|
1934
|
+
});
|
|
1824
1935
|
}
|
|
1825
1936
|
const MAX_MISSING_USAGE_HINT_KEYS = 256;
|
|
1826
1937
|
const missingUsageHintKeys = /* @__PURE__ */ new Set();
|
|
@@ -1921,7 +2032,7 @@ function ensureOpenAIResponsesNonEmptyInput(messages, context) {
|
|
|
1921
2032
|
text: " "
|
|
1922
2033
|
}]));
|
|
1923
2034
|
}
|
|
1924
|
-
function buildOpenAIResponsesParams(model, context, options, metadata, replayMode = "checkpoint") {
|
|
2035
|
+
function buildOpenAIResponsesParams(model, context, options, metadata, replayMode = "checkpoint", retainUserProvenance = false) {
|
|
1925
2036
|
const payloadPolicy = resolveOpenAIResponsesPayloadPolicy(model, { storeMode: "transport-default" });
|
|
1926
2037
|
const policyAllowsReplayIds = payloadPolicy.explicitStore !== false && !payloadPolicy.shouldStripStore;
|
|
1927
2038
|
const replayResponsesItemIds = !usesNativeOpenAICodexResponsesBackend(model) && (options?.replayResponsesItemIds ?? policyAllowsReplayIds);
|
|
@@ -1931,7 +2042,8 @@ function buildOpenAIResponsesParams(model, context, options, metadata, replayMod
|
|
|
1931
2042
|
replayResponsesItemIds,
|
|
1932
2043
|
authProfileId: options?.authProfileId,
|
|
1933
2044
|
sessionId: options?.sessionId,
|
|
1934
|
-
replayMode
|
|
2045
|
+
replayMode,
|
|
2046
|
+
retainUserProvenance
|
|
1935
2047
|
});
|
|
1936
2048
|
ensureOpenAIResponsesNonEmptyInput(messages, context);
|
|
1937
2049
|
const cacheRetention = resolveCacheRetention(options?.cacheRetention);
|
|
@@ -1993,26 +2105,31 @@ function buildOpenAIResponsesParams(model, context, options, metadata, replayMod
|
|
|
1993
2105
|
//#endregion
|
|
1994
2106
|
//#region packages/ai/src/transports/openai-responses-compact-client.ts
|
|
1995
2107
|
async function postOpenAIResponsesCompaction(params) {
|
|
1996
|
-
const
|
|
2108
|
+
const instructions = typeof params.request.instructions === "string" && params.request.instructions.length > 0 ? params.request.instructions : void 0;
|
|
2109
|
+
const body = instructions && !supportsNativeOpenAIResponsesEndpoint(params.model) ? {
|
|
2110
|
+
model: params.request.model,
|
|
2111
|
+
input: [buildOpenAIResponsesCompactSystemMessage(params.model, instructions), ...params.request.input ?? []]
|
|
2112
|
+
} : {
|
|
2113
|
+
model: params.request.model,
|
|
2114
|
+
input: params.request.input,
|
|
2115
|
+
...instructions ? { instructions } : {}
|
|
2116
|
+
};
|
|
1997
2117
|
const response = await params.client.post("/responses/compact", {
|
|
1998
2118
|
...buildOpenAISdkRequestOptions(params.model, params.options?.signal, { timeoutMs: params.options?.timeoutMs }),
|
|
1999
|
-
body
|
|
2000
|
-
model: params.request.model,
|
|
2001
|
-
input: compactInput
|
|
2002
|
-
}
|
|
2119
|
+
body
|
|
2003
2120
|
});
|
|
2004
|
-
|
|
2005
|
-
const
|
|
2006
|
-
|
|
2007
|
-
const
|
|
2008
|
-
const
|
|
2009
|
-
|
|
2010
|
-
const usage = isRecord(response
|
|
2011
|
-
if (!
|
|
2121
|
+
if (!isRecord(response) || response.object !== "response.compaction") throw new Error("Responses compact endpoint must return a response.compaction object");
|
|
2122
|
+
const output = response.output;
|
|
2123
|
+
if (!isOpenAIResponsesCompactionOutput(output, params.model)) throw new Error(`Responses compact endpoint: ${getOpenAIResponsesCompactionOutputError(output, params.model)}`);
|
|
2124
|
+
const window = output;
|
|
2125
|
+
const item = window.at(-1);
|
|
2126
|
+
if (window.length > 1 && !supportsNativeOpenAIResponsesEndpoint(params.model)) throw new Error("Responses compact endpoint: retained messages require native OpenAI");
|
|
2127
|
+
const usage = isRecord(response.usage) ? response.usage : void 0;
|
|
2128
|
+
if (!usage || typeof usage.input_tokens !== "number" || typeof usage.output_tokens !== "number") throw new Error("Responses compact endpoint: usage must include input_tokens and output_tokens");
|
|
2012
2129
|
return {
|
|
2013
|
-
output,
|
|
2130
|
+
output: window,
|
|
2014
2131
|
item,
|
|
2015
|
-
historyMode:
|
|
2132
|
+
historyMode: window.length > 1 ? "retained-users" : "compacted-prefix",
|
|
2016
2133
|
usage,
|
|
2017
2134
|
model: params.model,
|
|
2018
2135
|
replayMetadata: buildOpenAIResponsesReasoningReplayMetadata(params.model, {
|
|
@@ -2022,39 +2139,6 @@ async function postOpenAIResponsesCompaction(params) {
|
|
|
2022
2139
|
};
|
|
2023
2140
|
}
|
|
2024
2141
|
//#endregion
|
|
2025
|
-
//#region packages/ai/src/transports/openai-responses-compact-request.ts
|
|
2026
|
-
const COMPACT_REQUEST = Symbol("openaiResponsesCompactRequest");
|
|
2027
|
-
function claimResponsesCompactRequest(options) {
|
|
2028
|
-
const controller = options ? Reflect.get(options, COMPACT_REQUEST) : void 0;
|
|
2029
|
-
if (controller?.claimed === false) {
|
|
2030
|
-
controller.claimed = true;
|
|
2031
|
-
return controller;
|
|
2032
|
-
}
|
|
2033
|
-
}
|
|
2034
|
-
/** Run a compact-endpoint request through the session's prepared stream stack. */
|
|
2035
|
-
async function requestPreparedOpenAIResponsesCompaction(streamFn, model, context, options) {
|
|
2036
|
-
const preparedOptions = { ...options };
|
|
2037
|
-
let resolveResult;
|
|
2038
|
-
let rejectResult;
|
|
2039
|
-
const result = new Promise((resolve, reject) => {
|
|
2040
|
-
resolveResult = resolve;
|
|
2041
|
-
rejectResult = reject;
|
|
2042
|
-
});
|
|
2043
|
-
const controller = {
|
|
2044
|
-
claimed: false,
|
|
2045
|
-
resolve: resolveResult,
|
|
2046
|
-
reject: rejectResult
|
|
2047
|
-
};
|
|
2048
|
-
Reflect.set(preparedOptions, COMPACT_REQUEST, controller);
|
|
2049
|
-
const stream = await Promise.resolve(streamFn(model, context, preparedOptions));
|
|
2050
|
-
if (!controller.claimed) throw new Error("Prepared stream did not reach an OpenAI Responses transport");
|
|
2051
|
-
try {
|
|
2052
|
-
return await result;
|
|
2053
|
-
} finally {
|
|
2054
|
-
await stream.result().catch(() => void 0);
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
//#endregion
|
|
2058
2142
|
//#region packages/ai/src/transports/openai-responses-reasoning-state.ts
|
|
2059
2143
|
/** Save only admitted settings and hashes, never another copy of the conversation. */
|
|
2060
2144
|
function recordResponsesReasoningState(message, model, identity, request, output) {
|
|
@@ -2315,6 +2399,16 @@ function createRecoverableResponsesWebSocketStream(params) {
|
|
|
2315
2399
|
const SESSION_WEBSOCKET_CACHE_TTL_MS = 3e5;
|
|
2316
2400
|
const SESSION_WEBSOCKET_MAX_AGE_MS = 33e5;
|
|
2317
2401
|
const WEBSOCKET_OPEN_STATE = 1;
|
|
2402
|
+
function resolveNativeOpenAIResponsesWebSocketMode(model, transport) {
|
|
2403
|
+
if (transport !== "websocket" && transport !== "websocket-cached" && transport !== "auto") return;
|
|
2404
|
+
if (getAiTransportHost().requiresManagedTransport(model)) return;
|
|
2405
|
+
return supportsNativeOpenAIResponsesEndpoint(model) ? transport : void 0;
|
|
2406
|
+
}
|
|
2407
|
+
function combineWebSocketTimeoutSignal(signal, model, timeoutMs) {
|
|
2408
|
+
const resolvedTimeoutMs = timeoutMs !== void 0 && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : getAiTransportHost().resolveModelRequestTimeoutMs(model);
|
|
2409
|
+
if (resolvedTimeoutMs === void 0 || !Number.isFinite(resolvedTimeoutMs)) return signal;
|
|
2410
|
+
return AbortSignal.any([signal, AbortSignal.timeout(Math.max(1, resolvedTimeoutMs))]);
|
|
2411
|
+
}
|
|
2318
2412
|
const websocketSessionCache = /* @__PURE__ */ new Map();
|
|
2319
2413
|
const degradedWebSocketConnections = /* @__PURE__ */ new Map();
|
|
2320
2414
|
function closeWebSocketSilently(socket, reason = "done") {
|
|
@@ -2676,16 +2770,6 @@ function closeOpenAIResponsesWebSocketSessions(sessionId, owner) {
|
|
|
2676
2770
|
registerSessionResourceCleanup(closeOpenAIResponsesWebSocketSessions);
|
|
2677
2771
|
//#endregion
|
|
2678
2772
|
//#region packages/ai/src/transports/openai-responses-client.ts
|
|
2679
|
-
function resolveNativeOpenAIResponsesWebSocketMode(model, transport) {
|
|
2680
|
-
if (transport !== "websocket" && transport !== "websocket-cached" && transport !== "auto") return;
|
|
2681
|
-
if (getAiTransportHost().requiresManagedTransport(model)) return;
|
|
2682
|
-
return supportsNativeOpenAIResponsesEndpoint(model) ? transport : void 0;
|
|
2683
|
-
}
|
|
2684
|
-
function combineWebSocketTimeoutSignal(signal, model, timeoutMs) {
|
|
2685
|
-
const resolvedTimeoutMs = timeoutMs !== void 0 && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : getAiTransportHost().resolveModelRequestTimeoutMs(model);
|
|
2686
|
-
if (resolvedTimeoutMs === void 0 || !Number.isFinite(resolvedTimeoutMs)) return signal;
|
|
2687
|
-
return AbortSignal.any([signal, AbortSignal.timeout(Math.max(1, resolvedTimeoutMs))]);
|
|
2688
|
-
}
|
|
2689
2773
|
function createOpenAIResponsesClient(model, apiKey, defaultHeaders, fetchOverride) {
|
|
2690
2774
|
return new OpenAI({
|
|
2691
2775
|
apiKey,
|
|
@@ -2699,7 +2783,9 @@ function createOpenAIResponsesClient(model, apiKey, defaultHeaders, fetchOverrid
|
|
|
2699
2783
|
function createResponsesTransportExecutor(config) {
|
|
2700
2784
|
return (model, context, options) => {
|
|
2701
2785
|
const responsesOptions = options;
|
|
2786
|
+
const independent = independentResponsesRequest.has(options);
|
|
2702
2787
|
const compactRequest = claimResponsesCompactRequest(responsesOptions);
|
|
2788
|
+
const v2Compaction = compactRequest?.mode === "v2" ? createResponsesV2CompactionCollector(compactRequest.replayBudget) : void 0;
|
|
2703
2789
|
const { eventStream, stream } = createWritableTransportEventStream();
|
|
2704
2790
|
(async () => {
|
|
2705
2791
|
const output = createAssistantOutput(model, config.outputApi);
|
|
@@ -2707,9 +2793,10 @@ function createResponsesTransportExecutor(config) {
|
|
|
2707
2793
|
let continuationClaim;
|
|
2708
2794
|
const requestLifecycle = responsesRequestLifecycle.get(options);
|
|
2709
2795
|
try {
|
|
2796
|
+
if (compactRequest && requestLifecycle) throw new Error("Provider review continuation cannot replace its reviewed input with compaction");
|
|
2710
2797
|
const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
|
|
2711
|
-
const websocketMode = resolveNativeOpenAIResponsesWebSocketMode(model, responsesOptions?.transport);
|
|
2712
|
-
const encodeBody = prepareModelRequestBody(websocketMode || compactRequest ? void 0 : options);
|
|
2798
|
+
const websocketMode = independent ? void 0 : resolveNativeOpenAIResponsesWebSocketMode(model, responsesOptions?.transport);
|
|
2799
|
+
const encodeBody = prepareModelRequestBody(websocketMode || compactRequest?.mode === "endpoint" ? void 0 : options);
|
|
2713
2800
|
const turnState = resolveProviderTransportTurnState(model, {
|
|
2714
2801
|
sessionId: options?.sessionId,
|
|
2715
2802
|
turnId: randomUUID(),
|
|
@@ -2721,21 +2808,26 @@ function createResponsesTransportExecutor(config) {
|
|
|
2721
2808
|
const websocketTurnHeaders = filterProviderTurnHeadersForExplicitOpencodeSession(model, options, websocketSessionPolicy?.headers);
|
|
2722
2809
|
const websocketHeaders = websocketMode ? buildOpenAIClientHeaders(model, context, options?.headers, websocketTurnHeaders, options?.sessionId, options?.cacheRetention) : void 0;
|
|
2723
2810
|
const httpHeaders = buildOpenAIClientHeaders(model, context, options?.headers, httpTurnHeaders, options?.sessionId, options?.cacheRetention);
|
|
2724
|
-
const fetchOverride = createResponsesRequestFetch(model, {
|
|
2725
|
-
compact:
|
|
2811
|
+
const fetchOverride = withOpenAIErrorResponseHook(createResponsesRequestFetch(model, {
|
|
2812
|
+
compact: compactRequest?.mode === "endpoint",
|
|
2726
2813
|
stream: config.streamRequest,
|
|
2727
2814
|
lifecycle: requestLifecycle,
|
|
2728
2815
|
onSseComment: () => notifyLlmRequestActivity(options?.signal, false)
|
|
2729
|
-
});
|
|
2816
|
+
}) ?? buildGuardedModelFetch(model), options?.onResponse, model);
|
|
2730
2817
|
const client = config.createClient(model, apiKey, httpHeaders, fetchOverride);
|
|
2731
2818
|
const nativeAstra = model.id === "gpt-6-astra" && supportsNativeOpenAIResponsesEndpoint(model);
|
|
2732
2819
|
const asyncToolExecutionEligible = nativeAstra && options?.asyncToolExecution === true && !responsesOptions?.openclawCodeModeToolSurface;
|
|
2733
2820
|
const prepareRequest = async (request) => {
|
|
2734
2821
|
let params = request;
|
|
2822
|
+
const preserveUsers = v2Compaction?.preserveUsers(request.input ?? []);
|
|
2735
2823
|
const nextParams = await options?.onPayload?.(params, model);
|
|
2736
2824
|
if (nextParams !== void 0) params = nextParams;
|
|
2825
|
+
if (preserveUsers) params = {
|
|
2826
|
+
...params,
|
|
2827
|
+
input: preserveUsers(params.input ?? [])
|
|
2828
|
+
};
|
|
2737
2829
|
params = sanitizeOpenAICodexResponsesParams(model, params);
|
|
2738
|
-
params = sanitizeResponsesImagePayload(params);
|
|
2830
|
+
params = v2Compaction ? v2Compaction.sanitizeImages(params) : sanitizeResponsesImagePayload(params);
|
|
2739
2831
|
if (responsesOptions?.openclawCodeModeToolSurface === true) {
|
|
2740
2832
|
const visibleToolNames = resolveCodeModeResponsesVisibleToolNames(context);
|
|
2741
2833
|
const allowedHostedToolTypes = responsesOptions?.openclawCodeModeAllowedHostedToolTypes;
|
|
@@ -2749,12 +2841,16 @@ function createResponsesTransportExecutor(config) {
|
|
|
2749
2841
|
async: true
|
|
2750
2842
|
} : tool);
|
|
2751
2843
|
}
|
|
2844
|
+
if (v2Compaction) {
|
|
2845
|
+
params.input = [...params.input ?? [], { type: "compaction_trigger" }];
|
|
2846
|
+
v2Compaction.assertReplayFits(params.input, model);
|
|
2847
|
+
}
|
|
2752
2848
|
return params;
|
|
2753
2849
|
};
|
|
2754
|
-
const buildRequest = (replayMode, requestContext = context) => prepareRequest(config.buildRequest(model, requestContext, responsesOptions, turnState?.metadata, replayMode));
|
|
2850
|
+
const buildRequest = (replayMode, requestContext = context) => prepareRequest(config.buildRequest(model, requestContext, responsesOptions, turnState?.metadata, replayMode, Boolean(v2Compaction)));
|
|
2755
2851
|
let params = await buildRequest("checkpoint");
|
|
2756
|
-
const asyncTools = asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true;
|
|
2757
|
-
if (compactRequest) {
|
|
2852
|
+
const asyncTools = !compactRequest && asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true;
|
|
2853
|
+
if (compactRequest?.mode === "endpoint") {
|
|
2758
2854
|
const compacted = await postOpenAIResponsesCompaction({
|
|
2759
2855
|
client,
|
|
2760
2856
|
model,
|
|
@@ -2764,6 +2860,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2764
2860
|
output.usage.input = compacted.usage.input_tokens;
|
|
2765
2861
|
output.usage.output = compacted.usage.output_tokens;
|
|
2766
2862
|
output.usage.totalTokens = compacted.usage.input_tokens + compacted.usage.output_tokens;
|
|
2863
|
+
output.usage.usageReport = { state: "available" };
|
|
2767
2864
|
compactRequest.resolve(compacted);
|
|
2768
2865
|
finalizeTransportStream({
|
|
2769
2866
|
stream,
|
|
@@ -2773,16 +2870,17 @@ function createResponsesTransportExecutor(config) {
|
|
|
2773
2870
|
return;
|
|
2774
2871
|
}
|
|
2775
2872
|
const sessionId = options?.sessionId;
|
|
2776
|
-
if (config.httpContinuation && !websocketMode && !getAiTransportHost().requiresManagedTransport(model) && (supportsNativeOpenAIResponsesEndpoint(model) || resolveOpenAIResponsesPayloadPolicy(model).explicitContinuationOptIn) && sessionId && (params.store === true || supportsResponsesReasoningUpdate(params)) && !params.previous_response_id) {
|
|
2873
|
+
if (config.httpContinuation && !compactRequest && !independent && !websocketMode && !getAiTransportHost().requiresManagedTransport(model) && (supportsNativeOpenAIResponsesEndpoint(model) || resolveOpenAIResponsesPayloadPolicy(model).explicitContinuationOptIn) && sessionId && (params.store === true || supportsResponsesReasoningUpdate(params)) && !params.previous_response_id) {
|
|
2874
|
+
const restoreRequest = () => restoreResponsesReasoningState(context, model, responsesOptions, params);
|
|
2777
2875
|
continuationClaim = claimOpenAIResponsesHttpContinuation({
|
|
2778
2876
|
sessionId,
|
|
2779
2877
|
apiKey,
|
|
2780
2878
|
baseUrl: model.baseUrl,
|
|
2781
2879
|
headers: httpHeaders,
|
|
2782
2880
|
request: params,
|
|
2783
|
-
restoreRequest
|
|
2881
|
+
restoreRequest
|
|
2784
2882
|
});
|
|
2785
|
-
|
|
2883
|
+
params = continuationClaim?.fullRequest ?? restoreRequest();
|
|
2786
2884
|
}
|
|
2787
2885
|
const observePrompt = createResponsesPromptEgressObserver(responsesOptions, context.systemPrompt);
|
|
2788
2886
|
const requestStartedAt = Date.now();
|
|
@@ -2830,7 +2928,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2830
2928
|
continuationBaseline = attempt.request.previous_response_id ? params : attempt.request;
|
|
2831
2929
|
const trackedResponseStream = responseModelTracker.track(response, rawResponseStream);
|
|
2832
2930
|
return withProviderResponseHook({
|
|
2833
|
-
stream: observeResponsesStream(trackedResponseStream, model, requestStartedAt),
|
|
2931
|
+
stream: observeResponsesStream(v2Compaction ? v2Compaction.observe(trackedResponseStream) : trackedResponseStream, model, requestStartedAt, attempt.request),
|
|
2834
2932
|
signal: firstEvent.signal,
|
|
2835
2933
|
abort: firstEvent.abort,
|
|
2836
2934
|
hook: createOpenAIProviderAcceptanceHook(options, response, model),
|
|
@@ -2865,7 +2963,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2865
2963
|
signal: websocketSignal,
|
|
2866
2964
|
callerSignal: options?.signal,
|
|
2867
2965
|
degradeCooldownMs: websocketSessionPolicy?.degradeCooldownMs,
|
|
2868
|
-
onActiveResponse: nativeAstra && params.model === "gpt-6-astra" ? options?.onActiveResponse : void 0,
|
|
2966
|
+
onActiveResponse: !compactRequest && nativeAstra && params.model === "gpt-6-astra" ? options?.onActiveResponse : void 0,
|
|
2869
2967
|
steeringInput: (messages) => {
|
|
2870
2968
|
contextUsageEligible = false;
|
|
2871
2969
|
return projectResponsesSteeringInput(params, () => buildRequest("checkpoint", {
|
|
@@ -2886,7 +2984,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2886
2984
|
transport = "websocket";
|
|
2887
2985
|
emitModelTransportDebug(log, `[responses] websocket_selected provider=${model.provider} api=${model.api} model=${model.id} mode=${websocketMode} reused=${websocket.reusedConnection} continuation=${websocket.continuationStatus === "continued"} continuationStatus=${websocket.continuationStatus} sessionIdHash=${redactIdentifier(options?.sessionId)} headersHash=${redactIdentifier(JSON.stringify(Object.entries(websocketHeaders ?? {}).toSorted(([a], [b]) => a.localeCompare(b))))}`);
|
|
2888
2986
|
responseStream = createRecoverableResponsesWebSocketStream({
|
|
2889
|
-
trackedWebSocketStream: responseModelTracker.track(void 0, websocket.stream),
|
|
2987
|
+
trackedWebSocketStream: observeResponsesStream(v2Compaction ? v2Compaction.observe(responseModelTracker.track(void 0, websocket.stream)) : responseModelTracker.track(void 0, websocket.stream), model, requestStartedAt, websocket.request, "websocket"),
|
|
2890
2988
|
websocket,
|
|
2891
2989
|
websocketSignal,
|
|
2892
2990
|
options,
|
|
@@ -2912,7 +3010,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2912
3010
|
canRetryIdentityConflict: () => hasOnlyResponsesFunctionTools(transport === "websocket" ? websocketBaseline : continuationBaseline),
|
|
2913
3011
|
...config.pricingOptions?.(responsesOptions, model),
|
|
2914
3012
|
resolveServiceTier: (responseTier, originalTier) => responseTier ?? (requestedTier === "priority" || requestedTier === "default" ? requestedTier : originalTier),
|
|
2915
|
-
onServiceTier: (
|
|
3013
|
+
onServiceTier: (tier, response) => responsesServiceTierObserver.observe(options, requestedTier, tier, response),
|
|
2916
3014
|
firstEventTimeoutMs: getFirstStreamEventTimeoutMs(options) ?? config.firstEventTimeoutMs,
|
|
2917
3015
|
abortFirstEventStream: firstEvent.abort,
|
|
2918
3016
|
onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
|
|
@@ -2927,7 +3025,25 @@ function createResponsesTransportExecutor(config) {
|
|
|
2927
3025
|
finishWebSocket?.();
|
|
2928
3026
|
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
2929
3027
|
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
2930
|
-
const admitted = transport === "websocket" ? websocketBaseline : continuationBaseline;
|
|
3028
|
+
const admitted = !independent && (transport === "websocket" ? websocketBaseline : continuationBaseline);
|
|
3029
|
+
if (v2Compaction && compactRequest) {
|
|
3030
|
+
const compacted = v2Compaction.finish({
|
|
3031
|
+
terminal,
|
|
3032
|
+
input: params.input ?? [],
|
|
3033
|
+
model,
|
|
3034
|
+
options: responsesOptions
|
|
3035
|
+
});
|
|
3036
|
+
compactRequest.resolve({
|
|
3037
|
+
...compacted,
|
|
3038
|
+
modelUsage: output.usage
|
|
3039
|
+
});
|
|
3040
|
+
finalizeTransportStream({
|
|
3041
|
+
stream,
|
|
3042
|
+
output,
|
|
3043
|
+
signal: options?.signal
|
|
3044
|
+
});
|
|
3045
|
+
return;
|
|
3046
|
+
}
|
|
2931
3047
|
if (terminal && admitted && supportsNativeOpenAIResponsesEndpoint(model)) recordResponsesReasoningState(output, model, responsesOptions, admitted, terminal.output);
|
|
2932
3048
|
if (continuationClaim && continuationBaseline && terminal) continuationClaim.commit(continuationBaseline, terminal, dispatchedPreviousResponseId);
|
|
2933
3049
|
if (terminal && admitted && contextUsageEligible) recordResponsesContextUsage(output, model, responsesOptions, admitted, terminal.output, "transport");
|
|
@@ -3159,7 +3275,7 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3159
3275
|
const { eventStream, stream } = createWritableTransportEventStream();
|
|
3160
3276
|
(async () => {
|
|
3161
3277
|
const output = createAssistantOutput(model);
|
|
3162
|
-
|
|
3278
|
+
let discardCandidate = false;
|
|
3163
3279
|
let firstEventAbort;
|
|
3164
3280
|
try {
|
|
3165
3281
|
const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
|
|
@@ -3171,10 +3287,11 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3171
3287
|
cacheRetention
|
|
3172
3288
|
} : { mode };
|
|
3173
3289
|
const { client, sawStreamDONE } = policy.mode === "direct" ? {
|
|
3174
|
-
client: createDirectCompletionsClient(model, context, apiKey,
|
|
3290
|
+
client: createDirectCompletionsClient(model, context, apiKey, options, cacheRetention === "none" ? void 0 : options?.sessionId, policy.compat),
|
|
3175
3291
|
sawStreamDONE: void 0
|
|
3176
3292
|
} : createManagedCompletionsClient(model, context, options, apiKey, cacheRetention);
|
|
3177
|
-
|
|
3293
|
+
const builtParams = buildOpenAICompletionsRequest(model, context, options, policy);
|
|
3294
|
+
let params = builtParams;
|
|
3178
3295
|
const encodeBody = prepareModelRequestBody(options);
|
|
3179
3296
|
const nextParams = await options?.onPayload?.(params, model);
|
|
3180
3297
|
if (nextParams !== void 0) params = nextParams;
|
|
@@ -3186,6 +3303,7 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3186
3303
|
}
|
|
3187
3304
|
if (getCompat(model).requiresNonEmptyUserOrAssistantMessage) assertOpenAICompletionsPayloadHasConversationTurn(params, model);
|
|
3188
3305
|
}
|
|
3306
|
+
const contextOutputBudget = resolveCompletionsContextOutputBudget(builtParams, params);
|
|
3189
3307
|
const emitReasoning = mode === "direct" ? directEmitReasoning : shouldEmitOpenAICompletionsReasoning(model, options);
|
|
3190
3308
|
firstEventAbort = createFirstStreamEventAbortController(options?.signal);
|
|
3191
3309
|
const requestOptions = mode === "direct" ? {
|
|
@@ -3215,27 +3333,42 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3215
3333
|
signal: firstEventAbort.signal,
|
|
3216
3334
|
abort: firstEventAbort.abort,
|
|
3217
3335
|
hook: createOpenAIProviderAcceptanceHook(options, response, model),
|
|
3218
|
-
onReady: () =>
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3336
|
+
onReady: () => {
|
|
3337
|
+
if (contextOutputBudget === void 0) stream.push({
|
|
3338
|
+
type: "start",
|
|
3339
|
+
partial: output
|
|
3340
|
+
});
|
|
3341
|
+
}
|
|
3342
|
+
});
|
|
3343
|
+
const providerStream = observeOpenAICompletionsProgress(withFirstStreamEventTimeout(hookedResponseStream, {
|
|
3344
|
+
provider: model.provider,
|
|
3345
|
+
api: model.api,
|
|
3346
|
+
model: model.id,
|
|
3347
|
+
timeoutMs: getFirstStreamEventTimeoutMs(options) ?? 0,
|
|
3348
|
+
stage: "completions",
|
|
3349
|
+
abort: firstEventAbort.abort,
|
|
3350
|
+
onTimeout: getFirstStreamEventTimeoutHandler(options),
|
|
3351
|
+
hint: "The provider may be stalled while parsing the tool payload; retry with a smaller tool surface or enable OPENCLAW_DEBUG_MODEL_PAYLOAD=tools to inspect exposed tools."
|
|
3352
|
+
}), options?.signal);
|
|
3353
|
+
const buffered = contextOutputBudget === void 0 ? void 0 : await bufferContextLimitedCompletions(providerStream, options?.signal);
|
|
3354
|
+
discardCandidate = Boolean(buffered?.bounded && (buffered.failed || buffered.finishReason === "length"));
|
|
3355
|
+
if (buffered && !discardCandidate) stream.push({
|
|
3356
|
+
type: "start",
|
|
3357
|
+
partial: output
|
|
3222
3358
|
});
|
|
3223
3359
|
const directEvents = mode === "direct" ? createDirectCompletionsEventStream(output, stream) : void 0;
|
|
3224
3360
|
try {
|
|
3225
|
-
await processCompletionsStream(
|
|
3361
|
+
await processCompletionsStream(buffered?.stream ?? providerStream, output, model, discardCandidate ? { push() {} } : directEvents?.stream ?? stream, {
|
|
3226
3362
|
...directEvents ? {
|
|
3227
3363
|
mode: "direct",
|
|
3228
|
-
beforeContentBlock: directEvents.beforeContentBlock
|
|
3229
|
-
provisionalCommentaryTags
|
|
3364
|
+
beforeContentBlock: directEvents.beforeContentBlock
|
|
3230
3365
|
} : { mode: "managed" },
|
|
3231
|
-
signal: options?.signal,
|
|
3366
|
+
signal: discardCandidate ? void 0 : options?.signal,
|
|
3232
3367
|
emitReasoning,
|
|
3233
3368
|
strictReasoningTags: reasoningTagTextPolicy.isStrict(options),
|
|
3234
|
-
firstEventTimeoutMs: getFirstStreamEventTimeoutMs(options),
|
|
3235
|
-
abortFirstEventStream: firstEventAbort.abort,
|
|
3236
|
-
onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
|
|
3237
3369
|
sawStreamDONE
|
|
3238
3370
|
});
|
|
3371
|
+
if (discardCandidate) throw new Error(`Context length exceeded: automatic output budget of ${contextOutputBudget} tokens exhausted before completion.`);
|
|
3239
3372
|
if (directEvents) {
|
|
3240
3373
|
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
3241
3374
|
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage || (output.stopReason === "aborted" ? "Request was aborted" : "Provider returned an invalid tool call"));
|
|
@@ -3251,6 +3384,7 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3251
3384
|
signal: options?.signal
|
|
3252
3385
|
});
|
|
3253
3386
|
} catch (error) {
|
|
3387
|
+
if (discardCandidate) output.content = [];
|
|
3254
3388
|
failTransportStream({
|
|
3255
3389
|
stream,
|
|
3256
3390
|
output,
|
|
@@ -3258,11 +3392,9 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3258
3392
|
error,
|
|
3259
3393
|
cleanup: () => {
|
|
3260
3394
|
finalizeOpenAICompletionsToolCalls(output, { allowSilentToolCallPromotion: false });
|
|
3261
|
-
clearPendingCommentaryText(provisionalCommentaryTags);
|
|
3262
|
-
tagUnresolvedTextAsCommentary(output);
|
|
3263
3395
|
if (mode === "direct") for (const block of output.content) {
|
|
3264
3396
|
delete block.index;
|
|
3265
|
-
delete block.
|
|
3397
|
+
if (block.type === "toolCall") delete block.partialJson;
|
|
3266
3398
|
delete block.streamIndex;
|
|
3267
3399
|
}
|
|
3268
3400
|
}
|
|
@@ -3273,7 +3405,7 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3273
3405
|
})();
|
|
3274
3406
|
return eventStream;
|
|
3275
3407
|
}
|
|
3276
|
-
function createDirectCompletionsClient(model, context, apiKey,
|
|
3408
|
+
function createDirectCompletionsClient(model, context, apiKey, options, sessionId, compat) {
|
|
3277
3409
|
if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
|
|
3278
3410
|
const headers = { ...model.headers };
|
|
3279
3411
|
if (model.provider === "github-copilot") Object.assign(headers, buildCopilotDynamicHeaders(context.messages));
|
|
@@ -3285,7 +3417,7 @@ function createDirectCompletionsClient(model, context, apiKey, optionsHeaders, s
|
|
|
3285
3417
|
headers["x-session-affinity"] = sessionId;
|
|
3286
3418
|
}
|
|
3287
3419
|
}
|
|
3288
|
-
return createOpenAIProviderClient(model, apiKey, headers,
|
|
3420
|
+
return createOpenAIProviderClient(model, apiKey, headers, resolveProviderSimpleCompletionHeaders(model, options), options?.onResponse);
|
|
3289
3421
|
}
|
|
3290
3422
|
function createManagedCompletionsClient(model, context, options, apiKey, cacheRetention) {
|
|
3291
3423
|
const turnState = resolveProviderTransportTurnState(model, {
|
|
@@ -3297,7 +3429,7 @@ function createManagedCompletionsClient(model, context, options, apiKey, cacheRe
|
|
|
3297
3429
|
const optionHeaders = resolveOpencodeSessionHeaders(model, options);
|
|
3298
3430
|
const turnHeaders = filterProviderTurnHeadersForExplicitOpencodeSession(model, options, turnState?.headers);
|
|
3299
3431
|
const doneDetector = createSseDoneDetector();
|
|
3300
|
-
const baseFetch = buildGuardedModelFetch(model, void 0, { onSseComment: () => notifyLlmRequestActivity(options?.signal, false) });
|
|
3432
|
+
const baseFetch = withOpenAIErrorResponseHook(buildGuardedModelFetch(model, void 0, { onSseComment: () => notifyLlmRequestActivity(options?.signal, false) }), options?.onResponse, model);
|
|
3301
3433
|
const doneDetectingFetch = async (url, init) => {
|
|
3302
3434
|
const response = await baseFetch(url, init);
|
|
3303
3435
|
if (!response.body || !response.ok) return response;
|
|
@@ -3331,4 +3463,4 @@ function createManagedCompletionsClient(model, context, options, apiKey, cacheRe
|
|
|
3331
3463
|
};
|
|
3332
3464
|
}
|
|
3333
3465
|
//#endregion
|
|
3334
|
-
export {
|
|
3466
|
+
export { hasResponsesWebSearchTool as a, flattenCompletionMessagesToStringContent as c, hasOpenAICompatibleConversationTurn as d, canonicalizeMaxTokensParam as f, createOpenAIResponsesTransportStreamFn as i, stripCompletionMessagesToRoleContent as l, createDeepSeekTextFilter as m, streamOpenAICompletionsRequest as n, buildOpenAICompletionsParams as o, resolveMaxTokensParam as p, createAzureOpenAIResponsesTransportStreamFn as r, convertMessages as s, createOpenAICompletionsTransportStreamFn as t, applyCompletionsAnthropicCacheControl as u };
|