@openclaw/ai 2026.10.5-beta.3 → 2026.10.10-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 +11 -0
- package/dist/{anthropic-BalhAzs-.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-DkKeXXx4.mjs → anthropic-stream-reducer-CzPXOaLM.mjs} +59 -226
- 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-DfT9Ndd8.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-9SSqsJg9.mjs → google-interactions-CTEBy9od.mjs} +19 -37
- package/dist/{google-messages-DsB7fmoQ.mjs → google-messages-DfpHVTaD.mjs} +18 -6
- package/dist/{google-provider-stream-CcEI2-MC.mjs → google-provider-stream-DJ8ANfsS.mjs} +6 -6
- package/dist/{google-shared-zGR0QUyS.mjs → google-shared-VTcCJLW3.mjs} +28 -41
- package/dist/{google-vertex-Dw_abY1w.mjs → google-vertex-Bkfizj7M.mjs} +3 -3
- package/dist/{google-sYI2wnY6.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.d.mts +2 -0
- package/dist/internal/google-model-family.mjs +7 -3
- 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-BHI3uCcA.mjs → openai-chatgpt-responses-CtdnpWwe.mjs} +95 -63
- package/dist/{openai-completions-CrVgnFrV.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-Dy4CZo9Q.mjs → openai-completions-transport-DviPEqw3.mjs} +370 -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-D5oiAUOG.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-D-aDYAkJ.mjs → openai-responses-shared-Bv_1NtH9.mjs} +284 -160
- 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/{text-signature-Drb4Erb8.mjs → provider-replay-context-J6CfU3m1.mjs} +5 -14
- package/dist/{provider-transport-turn-state-BOpxgm-J.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 +34 -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-Bn1hbvK9.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/tool-schema-json-projection-B8sG1I9v.mjs +0 -180
- package/dist/types-Kdfw_04V.d.mts +0 -1
package/dist/{openai-completions-transport-Dy4CZo9Q.mjs → openai-completions-transport-DviPEqw3.mjs}
RENAMED
|
@@ -1,38 +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 {
|
|
14
|
-
import {
|
|
15
|
-
import { i as
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { C as
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import { n as
|
|
22
|
-
import {
|
|
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";
|
|
23
25
|
import { t as notifyLlmRequestActivity } from "./llm-request-activity-CfMuh5cC.mjs";
|
|
24
26
|
import { n as resolveOpencodeSessionHeaders } from "./session-affinity-DA4WHv1h.mjs";
|
|
27
|
+
import { isGoogleGemini3ThinkingLevelModel } from "./internal/google-model-family.mjs";
|
|
25
28
|
import "./types.mjs";
|
|
26
|
-
import {
|
|
27
|
-
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";
|
|
28
32
|
import { t as boundResponseBody } from "./streaming-byte-guard-DBXr1XYn.mjs";
|
|
29
|
-
import { f as withPreparedToolSchemaNormalization, r as normalizeOpenAIStrictToolParameters } from "./openai-tool-schema-
|
|
30
|
-
import { isGoogleGemini3ThinkingLevelModel } from "./internal/google-model-family.mjs";
|
|
33
|
+
import { b as prepareOpenAIFunctionTool, f as normalizeToolSchema, p as withPreparedToolSchemaNormalization, r as normalizeOpenAIStrictToolParameters } from "./openai-tool-schema-Buv0GXFb.mjs";
|
|
31
34
|
import { t as mapOpenAIStopReason } from "./openai-stop-reason-8s70vDXj.mjs";
|
|
32
|
-
import { t as createReasoningTagTextPartitioner } from "./reasoning-tag-text-partitioner-CpOy9-IQ.mjs";
|
|
33
35
|
import { i as resolveAzureDeploymentNameFromMap, t as isOpenAICompatibleAzureResponsesBaseUrl } from "./azure-openai-responses-client-compat-D0dvJMbZ.mjs";
|
|
34
|
-
import {
|
|
35
|
-
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";
|
|
36
38
|
import { randomUUID } from "node:crypto";
|
|
37
39
|
import OpenAI, { AzureOpenAI } from "openai";
|
|
38
40
|
import { ResponsesWS } from "openai/resources/responses/ws.js";
|
|
@@ -207,9 +209,21 @@ function applyCompletionsAnthropicCacheControl(payload, cacheControl = { type: "
|
|
|
207
209
|
if (shapedPayloads.has(payload)) return;
|
|
208
210
|
shapedPayloads.add(payload);
|
|
209
211
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
210
|
-
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
|
+
}
|
|
211
225
|
const blocks = messages.filter(isRecord).flatMap((message) => Array.isArray(message.content) ? message.content.filter(isRecord) : []);
|
|
212
|
-
for (const block of
|
|
226
|
+
for (const block of blocks) delete block.cache_control;
|
|
213
227
|
if (!cacheControl) return;
|
|
214
228
|
const markText = (message, splitBoundary) => {
|
|
215
229
|
if (typeof message.content === "string" && message.content) message.content = [{
|
|
@@ -237,8 +251,10 @@ function applyCompletionsAnthropicCacheControl(payload, cacheControl = { type: "
|
|
|
237
251
|
}
|
|
238
252
|
return false;
|
|
239
253
|
};
|
|
240
|
-
|
|
241
|
-
|
|
254
|
+
if (markTools && lastToolIndex >= 0) tools[lastToolIndex] = {
|
|
255
|
+
...tools[lastToolIndex],
|
|
256
|
+
cache_control: cacheControl
|
|
257
|
+
};
|
|
242
258
|
if (!markMessages) return;
|
|
243
259
|
const system = messages.find((message) => isRecord(message) && (message.role === "system" || message.role === "developer"));
|
|
244
260
|
if (isRecord(system)) markText(system, true);
|
|
@@ -451,12 +467,12 @@ function finalizeOpenAICompletionsToolCalls(output, options = {}) {
|
|
|
451
467
|
output.errorMessage = "Provider returned an incomplete or malformed tool call";
|
|
452
468
|
output.content = output.content.filter((candidate) => !isToolCall(candidate));
|
|
453
469
|
};
|
|
454
|
-
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)) {
|
|
455
471
|
rejectToolCalls();
|
|
456
472
|
return;
|
|
457
473
|
}
|
|
458
474
|
try {
|
|
459
|
-
finalizeTerminalToolCallArguments(toolCalls, (call) => call.
|
|
475
|
+
finalizeTerminalToolCallArguments(toolCalls, (call) => call.partialJson);
|
|
460
476
|
} catch {
|
|
461
477
|
rejectToolCalls();
|
|
462
478
|
return;
|
|
@@ -464,12 +480,75 @@ function finalizeOpenAICompletionsToolCalls(output, options = {}) {
|
|
|
464
480
|
for (let contentIndex = 0; contentIndex < output.content.length; contentIndex += 1) {
|
|
465
481
|
const block = output.content[contentIndex];
|
|
466
482
|
if (!block || !isToolCall(block)) continue;
|
|
467
|
-
delete block.
|
|
483
|
+
delete block.partialJson;
|
|
468
484
|
delete block.streamIndex;
|
|
469
485
|
options.onConfirmedToolCall?.(block, contentIndex);
|
|
470
486
|
}
|
|
471
487
|
}
|
|
472
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
|
|
473
552
|
//#region packages/ai/src/transports/openai-completions-host.ts
|
|
474
553
|
/**
|
|
475
554
|
* Chat Completions accepts Azure AI Foundry hosts in addition to traditional
|
|
@@ -488,6 +567,7 @@ function hasToolCallHistory(messages) {
|
|
|
488
567
|
/** Convert a normalized transcript to OpenAI Chat Completions messages. */
|
|
489
568
|
function convertMessages(model, context, compat, options = {}) {
|
|
490
569
|
const params = [];
|
|
570
|
+
const supportsTools = options.supportsTools !== false;
|
|
491
571
|
const normalizeToolCallId = (id) => {
|
|
492
572
|
if (id.includes("|")) return id.slice(0, id.indexOf("|")).replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 40);
|
|
493
573
|
if (model.provider === "openai") return id.length > 40 ? truncateUtf16Safe(id, 40) : id;
|
|
@@ -565,7 +645,10 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
565
645
|
msg.content.forEach((block) => {
|
|
566
646
|
if (block.type === "text" && block.text.trim().length > 0) assistantTexts.push(sanitizeSurrogates(block.text));
|
|
567
647
|
else if (block.type === "thinking" && block.thinking.trim().length > 0) nonEmptyThinkingBlocks.push(block);
|
|
568
|
-
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
|
+
}
|
|
569
652
|
});
|
|
570
653
|
if (nonEmptyThinkingBlocks.length > 0 && compat.requiresThinkingAsText) assistantMsg.content = [{
|
|
571
654
|
type: "text",
|
|
@@ -617,13 +700,28 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
617
700
|
const textResult = extractToolResultText(toolMsg.content);
|
|
618
701
|
const mediaPlaceholder = describeToolResultMediaPlaceholder(toolMsg.content);
|
|
619
702
|
const images = toolMsg.content.filter(isImageWithMediaPayload);
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
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
|
+
}
|
|
627
725
|
if (images.length > 0 && model.input.includes("image")) {
|
|
628
726
|
const boundedToolName = sanitizeSurrogates(truncateUtf16Safe(toolMsg.toolName ?? "", 64));
|
|
629
727
|
imageContentParts.push({
|
|
@@ -639,7 +737,7 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
639
737
|
}
|
|
640
738
|
i = j - 1;
|
|
641
739
|
if (imageContentParts.length > 0) {
|
|
642
|
-
if (compat.requiresAssistantAfterToolResult) params.push({
|
|
740
|
+
if (supportsTools && compat.requiresAssistantAfterToolResult) params.push({
|
|
643
741
|
role: "assistant",
|
|
644
742
|
content: "I have processed the tool results."
|
|
645
743
|
});
|
|
@@ -648,7 +746,7 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
648
746
|
content: imageContentParts
|
|
649
747
|
});
|
|
650
748
|
lastRole = "user";
|
|
651
|
-
} else lastRole = "toolResult";
|
|
749
|
+
} else lastRole = supportsTools ? "toolResult" : "assistant";
|
|
652
750
|
continue;
|
|
653
751
|
}
|
|
654
752
|
lastRole = msg.role;
|
|
@@ -685,7 +783,7 @@ function applyCompletionsReasoningAndRouting(params, model, reasoning, compat, m
|
|
|
685
783
|
const direct = mode === "direct";
|
|
686
784
|
const nativeEffort = compat.thinkingFormat === "openrouter" ? void 0 : reasoning.effort;
|
|
687
785
|
const enabled = reasoning.thinkingEnabled ?? false;
|
|
688
|
-
if (model.reasoning) {
|
|
786
|
+
if (model.reasoning && (!compat.thinkingOffControlUndeclared || reasoning.thinkingEnabled !== void 0 || !reasoning.thinkingExplicit)) {
|
|
689
787
|
let allowScalarEffort = true;
|
|
690
788
|
if (direct && compat.thinkingFormat === "zai") {
|
|
691
789
|
params.thinking = enabled ? {
|
|
@@ -697,9 +795,11 @@ function applyCompletionsReasoningAndRouting(params, model, reasoning, compat, m
|
|
|
697
795
|
params.enable_thinking = enabled;
|
|
698
796
|
allowScalarEffort = false;
|
|
699
797
|
} else if (compat.thinkingFormat === "qwen-chat-template") {
|
|
798
|
+
const chatTemplateReasoningEffort = enabled && reasoning.thinkingExplicit && model.compat?.supportedReasoningEfforts?.length ? reasoning.effort : void 0;
|
|
700
799
|
params.chat_template_kwargs = {
|
|
701
800
|
enable_thinking: enabled,
|
|
702
|
-
...direct ? { preserve_thinking: true } : {}
|
|
801
|
+
...direct ? { preserve_thinking: true } : {},
|
|
802
|
+
...chatTemplateReasoningEffort ? { reasoning_effort: chatTemplateReasoningEffort } : {}
|
|
703
803
|
};
|
|
704
804
|
allowScalarEffort = false;
|
|
705
805
|
} else if (compat.thinkingFormat === "together" || direct && compat.thinkingFormat === "deepseek") {
|
|
@@ -878,10 +978,6 @@ function resolveOpenAICompletionsMaxTokens(model, options) {
|
|
|
878
978
|
clampToModelMaxTokens: false
|
|
879
979
|
};
|
|
880
980
|
}
|
|
881
|
-
function resolveOpenAICompletionsModelMaxTokens(model) {
|
|
882
|
-
const maxTokens = asPositiveFiniteNumber(model.maxTokens);
|
|
883
|
-
return maxTokens === void 0 ? void 0 : Math.floor(maxTokens);
|
|
884
|
-
}
|
|
885
981
|
const OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN = 1.25;
|
|
886
982
|
const OPENAI_COMPLETIONS_IMAGE_CHAR_ESTIMATE = 8e3;
|
|
887
983
|
const MIN_USEFUL_OUTPUT_TOKENS = 16;
|
|
@@ -893,8 +989,7 @@ function estimateJsonChars(value, fallback) {
|
|
|
893
989
|
}
|
|
894
990
|
}
|
|
895
991
|
function estimateOpenAICompletionsInputTokens(payload) {
|
|
896
|
-
let adjustedChars =
|
|
897
|
-
adjustedChars += estimateOpenAICompletionsMessagesChars(payload.messages);
|
|
992
|
+
let adjustedChars = estimateOpenAICompletionsMessagesChars(payload.messages);
|
|
898
993
|
if (payload.tools?.length) adjustedChars += estimateJsonChars(payload.tools, 1024);
|
|
899
994
|
if (payload.response_format !== void 0) adjustedChars += estimateJsonChars(payload.response_format, 256);
|
|
900
995
|
return Math.ceil(adjustedChars / 4 * OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN);
|
|
@@ -944,16 +1039,8 @@ function convertTools(tools, compat, model, mode) {
|
|
|
944
1039
|
return {
|
|
945
1040
|
projection,
|
|
946
1041
|
tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
|
|
947
|
-
const
|
|
948
|
-
|
|
949
|
-
description: tool.description,
|
|
950
|
-
parameters: mode === "direct" ? tool.parameters : normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, model.compat)
|
|
951
|
-
};
|
|
952
|
-
if (strict !== void 0) functionTool.strict = strict;
|
|
953
|
-
return {
|
|
954
|
-
type: "function",
|
|
955
|
-
function: functionTool
|
|
956
|
-
};
|
|
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;
|
|
957
1044
|
})
|
|
958
1045
|
};
|
|
959
1046
|
};
|
|
@@ -962,7 +1049,22 @@ function convertTools(tools, compat, model, mode) {
|
|
|
962
1049
|
function buildOpenAICompletionsParams(model, context, options) {
|
|
963
1050
|
return buildOpenAICompletionsRequest(model, context, options, { mode: "managed" });
|
|
964
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
|
+
}
|
|
965
1066
|
function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
1067
|
+
let contextOutputCap;
|
|
966
1068
|
const resolvedPolicy = policy.mode === "direct" ? policy : {
|
|
967
1069
|
...policy,
|
|
968
1070
|
compat: getCompat(model)
|
|
@@ -980,8 +1082,10 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
980
1082
|
"qwen"
|
|
981
1083
|
].includes(model.provider));
|
|
982
1084
|
const cacheOptOutIndexes = /* @__PURE__ */ new Set();
|
|
1085
|
+
const supportsTools = policy.mode === "direct" || supportsModelTools(model);
|
|
983
1086
|
const convertedMessages = convertMessages(model, context, compat, {
|
|
984
1087
|
cacheOptOutIndexes,
|
|
1088
|
+
supportsTools,
|
|
985
1089
|
preserveSystemPromptCacheBoundary: cacheControl !== void 0 && !managedCompat?.requiresStringContent
|
|
986
1090
|
});
|
|
987
1091
|
let messages = convertedMessages;
|
|
@@ -1014,7 +1118,7 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1014
1118
|
if (policy.mode === "managed" && options?.seed !== void 0) params.seed = options.seed;
|
|
1015
1119
|
if (options?.stop !== void 0 && options.stop.length > 0) params.stop = options.stop;
|
|
1016
1120
|
let directToolProjection;
|
|
1017
|
-
if (
|
|
1121
|
+
if (supportsTools) {
|
|
1018
1122
|
if (context.tools) {
|
|
1019
1123
|
const converted = convertTools(context.tools, compat, model, policy.mode);
|
|
1020
1124
|
if (policy.mode === "direct") directToolProjection = converted.projection;
|
|
@@ -1043,7 +1147,11 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1043
1147
|
...model,
|
|
1044
1148
|
compat: model.compat ?? void 0
|
|
1045
1149
|
}, simpleReasoning)) ?? (usesBinaryOpenRouterThinking ? void 0 : "high");
|
|
1046
|
-
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
|
+
};
|
|
1047
1155
|
const { effort, thinkingEnabled } = reasoning;
|
|
1048
1156
|
{
|
|
1049
1157
|
const maxTokenBudget = policy.mode === "direct" ? {
|
|
@@ -1053,7 +1161,8 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1053
1161
|
const effectiveMaxTokens = maxTokenBudget.maxTokens;
|
|
1054
1162
|
const effectiveContextTokens = asPositiveFiniteNumber(model.contextTokens) ?? asPositiveFiniteNumber(model.contextWindow);
|
|
1055
1163
|
let clampedMaxTokens = effectiveMaxTokens;
|
|
1056
|
-
const
|
|
1164
|
+
const modelOutputLimit = asPositiveFiniteNumber(model.maxTokens);
|
|
1165
|
+
const modelMaxTokens = modelOutputLimit === void 0 ? void 0 : Math.floor(modelOutputLimit);
|
|
1057
1166
|
if (maxTokenBudget.clampToModelMaxTokens && clampedMaxTokens !== void 0 && modelMaxTokens !== void 0 && clampedMaxTokens > modelMaxTokens) {
|
|
1058
1167
|
clampedMaxTokens = modelMaxTokens;
|
|
1059
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}`);
|
|
@@ -1062,8 +1171,9 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1062
1171
|
const estimatedInputTokens = estimateOpenAICompletionsInputTokens(params);
|
|
1063
1172
|
const remainingBudget = Math.max(0, effectiveContextTokens - estimatedInputTokens - 1);
|
|
1064
1173
|
if (clampedMaxTokens > remainingBudget) {
|
|
1065
|
-
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" });
|
|
1066
1175
|
clampedMaxTokens = remainingBudget;
|
|
1176
|
+
contextOutputCap = remainingBudget;
|
|
1067
1177
|
emitModelTransportDebug(log, `[completions] clamp_max_tokens provider=${model.provider} api=${model.api} model=${model.id} requested=${effectiveMaxTokens} output=${clampedMaxTokens} effectiveContext=${effectiveContextTokens} estimatedInput=${estimatedInputTokens}`);
|
|
1068
1178
|
}
|
|
1069
1179
|
}
|
|
@@ -1082,6 +1192,11 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
|
|
|
1082
1192
|
if (isOpenAIGpt56Model(model)) params.reasoning_effort = "none";
|
|
1083
1193
|
else if (isOpenAIGpt54MiniModel(model) || isOpenAIGpt55Model(model)) delete params.reasoning_effort;
|
|
1084
1194
|
}
|
|
1195
|
+
if (contextOutputCap !== void 0) contextOutputBudgets.set(params, {
|
|
1196
|
+
model: params.model,
|
|
1197
|
+
cap: contextOutputCap,
|
|
1198
|
+
inputHash: completionsInputHash(params)
|
|
1199
|
+
});
|
|
1085
1200
|
return params;
|
|
1086
1201
|
}
|
|
1087
1202
|
//#endregion
|
|
@@ -1218,7 +1333,7 @@ function parseDeepSeekDsmlToolCallBlock(body) {
|
|
|
1218
1333
|
kind: "toolCall",
|
|
1219
1334
|
name: invokeName,
|
|
1220
1335
|
arguments: parsedArguments,
|
|
1221
|
-
|
|
1336
|
+
partialJson: JSON.stringify(parsedArguments)
|
|
1222
1337
|
});
|
|
1223
1338
|
}
|
|
1224
1339
|
return toolCalls;
|
|
@@ -1379,7 +1494,7 @@ function recoverGemmaCalls(text) {
|
|
|
1379
1494
|
kind: "toolCall",
|
|
1380
1495
|
name,
|
|
1381
1496
|
arguments: argumentsValue,
|
|
1382
|
-
|
|
1497
|
+
partialJson: JSON.stringify(argumentsValue)
|
|
1383
1498
|
});
|
|
1384
1499
|
} catch {
|
|
1385
1500
|
return;
|
|
@@ -1437,6 +1552,38 @@ function extractToolCallThoughtSignature(toolCall) {
|
|
|
1437
1552
|
const extra = tc.extra_content?.google;
|
|
1438
1553
|
return readNonEmptyStringPreservingWhitespace(extra?.thought_signature) ?? readNonEmptyStringPreservingWhitespace(tc.function?.thought_signature) ?? readNonEmptyStringPreservingWhitespace(tc.thought_signature);
|
|
1439
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
|
+
}
|
|
1440
1587
|
async function processCompletionsStream(responseStream, output, model, stream, options) {
|
|
1441
1588
|
const MAX_POST_TOOL_CALL_BUFFER_BYTES = 256e3;
|
|
1442
1589
|
const directMode = options?.mode === "direct";
|
|
@@ -1453,17 +1600,14 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1453
1600
|
let currentBlock = null;
|
|
1454
1601
|
const directContent = { block: null };
|
|
1455
1602
|
let currentTextSource;
|
|
1456
|
-
let
|
|
1457
|
-
let confirmedInterruptedTextBlock = null;
|
|
1603
|
+
let sawReasoning = false;
|
|
1458
1604
|
let pendingPostToolCallDeltas = [];
|
|
1459
1605
|
let pendingPostToolCallBytes = 0;
|
|
1460
1606
|
const toolCallBlocksByIndex = /* @__PURE__ */ new Map();
|
|
1461
1607
|
const toolCallBlocksById = /* @__PURE__ */ new Map();
|
|
1462
1608
|
const encryptedReasoning = createOpenAIEncryptedToolCallReasoningTracker();
|
|
1463
1609
|
const toolArgumentPreviewSchedules = /* @__PURE__ */ new WeakMap();
|
|
1464
|
-
const provisionalCommentaryTags = directMode ? options.provisionalCommentaryTags : /* @__PURE__ */ new Map();
|
|
1465
1610
|
const blockIndices = /* @__PURE__ */ new WeakMap();
|
|
1466
|
-
let explicitVisibleTextBlocks;
|
|
1467
1611
|
const normalizeToolCallDeltas = createOpenAICompletionsToolCallDeltaNormalizer();
|
|
1468
1612
|
let finishReason;
|
|
1469
1613
|
let sawNativeToolCallDelta = false;
|
|
@@ -1505,7 +1649,6 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1505
1649
|
text: ""
|
|
1506
1650
|
};
|
|
1507
1651
|
currentTextSource = delta.source;
|
|
1508
|
-
if (delta.source === "reasoning_detail") (explicitVisibleTextBlocks ??= /* @__PURE__ */ new Set()).add(currentBlock);
|
|
1509
1652
|
} else currentBlock = {
|
|
1510
1653
|
type: "thinking",
|
|
1511
1654
|
thinking: "",
|
|
@@ -1521,13 +1664,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1521
1664
|
});
|
|
1522
1665
|
}
|
|
1523
1666
|
if (currentBlock.type === "thinking") appendAssistantThinking(currentBlock, delta.text);
|
|
1524
|
-
else
|
|
1525
|
-
currentBlock.text += delta.text;
|
|
1526
|
-
if (pendingInterruptedTextBlock && delta.text.trim()) {
|
|
1527
|
-
confirmedInterruptedTextBlock = pendingInterruptedTextBlock;
|
|
1528
|
-
pendingInterruptedTextBlock = null;
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1667
|
+
else currentBlock.text += delta.text;
|
|
1531
1668
|
const event = {
|
|
1532
1669
|
contentIndex: blockIndex(),
|
|
1533
1670
|
delta: delta.text
|
|
@@ -1579,20 +1716,19 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1579
1716
|
currentBlock = null;
|
|
1580
1717
|
flushPendingPostToolCallDeltas();
|
|
1581
1718
|
}
|
|
1582
|
-
rememberPendingCommentaryTags(provisionalCommentaryTags, tagPendingCommentaryText(output.content));
|
|
1583
1719
|
const block = {
|
|
1584
1720
|
type: "toolCall",
|
|
1585
1721
|
id: `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`,
|
|
1586
1722
|
name: toolCall.name,
|
|
1587
1723
|
arguments: toolCall.arguments,
|
|
1588
|
-
|
|
1724
|
+
partialJson: toolCall.partialJson
|
|
1589
1725
|
};
|
|
1590
1726
|
currentBlock = block;
|
|
1591
1727
|
appendToolCallBlock(block);
|
|
1592
1728
|
pushStreamEvent({
|
|
1593
1729
|
type: "toolcall_delta",
|
|
1594
1730
|
contentIndex: blockIndices.get(block) ?? -1,
|
|
1595
|
-
delta: toolCall.
|
|
1731
|
+
delta: toolCall.partialJson,
|
|
1596
1732
|
partial: output
|
|
1597
1733
|
});
|
|
1598
1734
|
};
|
|
@@ -1623,7 +1759,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1623
1759
|
});
|
|
1624
1760
|
};
|
|
1625
1761
|
const flushReasoningTagTextPartitioner = (allowRecovery = true) => {
|
|
1626
|
-
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";
|
|
1627
1763
|
for (const delta of reasoningTagTextPartitioner.flush({ recoverUnclosed })) appendPartitionedVisibleDelta(delta);
|
|
1628
1764
|
};
|
|
1629
1765
|
const flushGemmaToolCallRecoverer = (allowRecovery = true) => {
|
|
@@ -1634,36 +1770,17 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1634
1770
|
if (currentBlock?.type !== "text" && !reasoningTagTextPartitioner.hasPending()) return;
|
|
1635
1771
|
flushReasoningTagTextPartitioner();
|
|
1636
1772
|
if (currentBlock?.type !== "text") return;
|
|
1637
|
-
if (currentTextSource !== "reasoning_detail" && currentBlock.text.trim()) pendingInterruptedTextBlock = currentBlock;
|
|
1638
1773
|
currentBlock = null;
|
|
1639
1774
|
if (directMode) directContent.block = null;
|
|
1640
1775
|
currentTextSource = void 0;
|
|
1641
1776
|
};
|
|
1642
|
-
const beginReasoning = (hasFollowingVisibleText
|
|
1643
|
-
|
|
1644
|
-
...output.openclawDelivery,
|
|
1645
|
-
textPhaseRequiresTerminal: true
|
|
1646
|
-
};
|
|
1647
|
-
if (forceStrict || reasoningTagTextPartitioner.hasPending()) reasoningTagTextPartitioner.markStrict();
|
|
1777
|
+
const beginReasoning = (hasFollowingVisibleText) => {
|
|
1778
|
+
sawReasoning = true;
|
|
1648
1779
|
if (!hasFollowingVisibleText || !reasoningTagTextPartitioner.hasPendingSyntax()) sealTextBeforeReasoning();
|
|
1649
1780
|
};
|
|
1650
|
-
const
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
model: model.id,
|
|
1654
|
-
timeoutMs: options?.firstEventTimeoutMs ?? 0,
|
|
1655
|
-
stage: "completions",
|
|
1656
|
-
abort: options?.abortFirstEventStream,
|
|
1657
|
-
onTimeout: options?.onFirstEventTimeout,
|
|
1658
|
-
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."
|
|
1659
|
-
});
|
|
1660
|
-
const events = directMode ? guardedStream : iterateModelStream(guardedStream, options?.signal);
|
|
1661
|
-
const maxUsageTokens = {
|
|
1662
|
-
prompt: 0,
|
|
1663
|
-
completion: 0,
|
|
1664
|
-
total: 0,
|
|
1665
|
-
reasoning: 0
|
|
1666
|
-
};
|
|
1781
|
+
const events = directMode ? responseStream : iterateModelStream(responseStream, options?.signal);
|
|
1782
|
+
let maxReasoningTokens = 0;
|
|
1783
|
+
let providerProcessingMs;
|
|
1667
1784
|
for await (const rawChunk of events) {
|
|
1668
1785
|
throwIfModelStreamAborted(options?.signal);
|
|
1669
1786
|
chunkPushedEvent = false;
|
|
@@ -1673,24 +1790,21 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1673
1790
|
if (typeof chunk.model === "string" && chunk.model.length > 0 && chunk.model !== model.id) output.responseModel ||= chunk.model;
|
|
1674
1791
|
const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : void 0;
|
|
1675
1792
|
const usage = chunk.usage || choice?.usage;
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
}
|
|
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" };
|
|
1690
1806
|
}
|
|
1691
|
-
if (usage) output.usage = parseOpenAICompletionsUsage(usage, model, { includeReasoningTokens: !directMode });
|
|
1692
1807
|
const rawChoiceDelta = choice?.delta ?? choice?.message;
|
|
1693
|
-
notifyLlmRequestActivity(options?.signal, Boolean(hasUsageProgress || choice?.finish_reason || rawChoiceDelta && (rawChoiceDelta.tool_calls?.length || hasOpenAICompletionsDeltaContent(rawChoiceDelta))));
|
|
1694
1808
|
if (!choice) {
|
|
1695
1809
|
emitReasoningUsageActivity(hasReasoningUsageActivity);
|
|
1696
1810
|
continue;
|
|
@@ -1715,15 +1829,12 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1715
1829
|
const lastVisibleTextIndex = contentDeltas.findLastIndex((delta) => delta.kind === "text");
|
|
1716
1830
|
const hasSameChunkVisibleText = reasoningBatch.hasVisibleText || lastVisibleTextIndex !== -1;
|
|
1717
1831
|
if (hasReasoningThinking) {
|
|
1718
|
-
beginReasoning(hasSameChunkVisibleText
|
|
1832
|
+
beginReasoning(hasSameChunkVisibleText);
|
|
1719
1833
|
appendReasoningDeltas(reasoningDeltas);
|
|
1720
1834
|
}
|
|
1721
1835
|
for (const [contentDeltaIndex, contentDelta] of contentDeltas.entries()) if (contentDelta.kind === "text") {
|
|
1722
1836
|
const parts = gemmaToolCallRecoverer?.push(contentDelta.text) ?? [contentDelta];
|
|
1723
|
-
for (const part of parts)
|
|
1724
|
-
const routedDeltas = hasReasoningThinking ? reasoningTagTextPartitioner.push(part.text) : reasoningTagTextPartitioner.pushVisible(part.text);
|
|
1725
|
-
for (const routedDelta of routedDeltas) appendPartitionedVisibleDelta(routedDelta);
|
|
1726
|
-
}
|
|
1837
|
+
for (const part of parts) for (const routedDelta of reasoningTagTextPartitioner.pushVisible(part.text)) appendPartitionedVisibleDelta(routedDelta);
|
|
1727
1838
|
} else {
|
|
1728
1839
|
beginReasoning(contentDeltaIndex < lastVisibleTextIndex);
|
|
1729
1840
|
if (emitReasoning) {
|
|
@@ -1737,7 +1848,6 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1737
1848
|
flushGemmaToolCallRecoverer(false);
|
|
1738
1849
|
sawNativeToolCallDelta = true;
|
|
1739
1850
|
flushReasoningTagTextPartitioner(false);
|
|
1740
|
-
rememberPendingCommentaryTags(provisionalCommentaryTags, tagPendingCommentaryText(output.content));
|
|
1741
1851
|
for (const toolCall of toolCallDeltas) {
|
|
1742
1852
|
const streamIndex = typeof toolCall.index === "number" ? toolCall.index : void 0;
|
|
1743
1853
|
let block = streamIndex !== void 0 ? toolCallBlocksByIndex.get(streamIndex) : void 0;
|
|
@@ -1755,7 +1865,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1755
1865
|
id: toolCall.id || "",
|
|
1756
1866
|
name: toolCall.function?.name || "",
|
|
1757
1867
|
arguments: {},
|
|
1758
|
-
|
|
1868
|
+
partialJson: "",
|
|
1759
1869
|
...initialSig ? { thoughtSignature: initialSig } : {}
|
|
1760
1870
|
};
|
|
1761
1871
|
encryptedReasoning.rememberToolCall(block.id, block);
|
|
@@ -1776,8 +1886,8 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1776
1886
|
if (deltaSig) block.thoughtSignature = deltaSig;
|
|
1777
1887
|
const toolArgumentsDelta = toolCall.function?.arguments;
|
|
1778
1888
|
if (toolArgumentsDelta) {
|
|
1779
|
-
block.
|
|
1780
|
-
if (toolArgumentPreviewSchedules.get(block)?.(block.
|
|
1889
|
+
block.partialJson += toolArgumentsDelta;
|
|
1890
|
+
if (toolArgumentPreviewSchedules.get(block)?.(block.partialJson.length)) block.arguments = parseStreamingJson(block.partialJson);
|
|
1781
1891
|
}
|
|
1782
1892
|
if (toolArgumentsDelta || directMode) pushStreamEvent({
|
|
1783
1893
|
type: "toolcall_delta",
|
|
@@ -1812,14 +1922,16 @@ async function processCompletionsStream(responseStream, output, model, stream, o
|
|
|
1812
1922
|
});
|
|
1813
1923
|
}
|
|
1814
1924
|
});
|
|
1815
|
-
|
|
1816
|
-
if (output.stopReason !== "
|
|
1817
|
-
if (output.stopReason === "error" || output.stopReason === "aborted") tagUnresolvedTextAsCommentary(output);
|
|
1818
|
-
if (output.stopReason === "toolUse") tagPendingCommentaryText(output.content);
|
|
1819
|
-
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") {
|
|
1820
1927
|
output.usage.contextUsage = { state: "unavailable" };
|
|
1821
1928
|
if (!compat.supportsUsageInStreaming) warnMissingStreamingUsage(openAIModel);
|
|
1822
1929
|
}
|
|
1930
|
+
if (providerProcessingMs !== void 0) appendAssistantMessageDiagnostic(output, {
|
|
1931
|
+
type: "provider_timing",
|
|
1932
|
+
timestamp: Date.now(),
|
|
1933
|
+
details: { processingMs: providerProcessingMs }
|
|
1934
|
+
});
|
|
1823
1935
|
}
|
|
1824
1936
|
const MAX_MISSING_USAGE_HINT_KEYS = 256;
|
|
1825
1937
|
const missingUsageHintKeys = /* @__PURE__ */ new Set();
|
|
@@ -1920,7 +2032,7 @@ function ensureOpenAIResponsesNonEmptyInput(messages, context) {
|
|
|
1920
2032
|
text: " "
|
|
1921
2033
|
}]));
|
|
1922
2034
|
}
|
|
1923
|
-
function buildOpenAIResponsesParams(model, context, options, metadata, replayMode = "checkpoint") {
|
|
2035
|
+
function buildOpenAIResponsesParams(model, context, options, metadata, replayMode = "checkpoint", retainUserProvenance = false) {
|
|
1924
2036
|
const payloadPolicy = resolveOpenAIResponsesPayloadPolicy(model, { storeMode: "transport-default" });
|
|
1925
2037
|
const policyAllowsReplayIds = payloadPolicy.explicitStore !== false && !payloadPolicy.shouldStripStore;
|
|
1926
2038
|
const replayResponsesItemIds = !usesNativeOpenAICodexResponsesBackend(model) && (options?.replayResponsesItemIds ?? policyAllowsReplayIds);
|
|
@@ -1930,7 +2042,8 @@ function buildOpenAIResponsesParams(model, context, options, metadata, replayMod
|
|
|
1930
2042
|
replayResponsesItemIds,
|
|
1931
2043
|
authProfileId: options?.authProfileId,
|
|
1932
2044
|
sessionId: options?.sessionId,
|
|
1933
|
-
replayMode
|
|
2045
|
+
replayMode,
|
|
2046
|
+
retainUserProvenance
|
|
1934
2047
|
});
|
|
1935
2048
|
ensureOpenAIResponsesNonEmptyInput(messages, context);
|
|
1936
2049
|
const cacheRetention = resolveCacheRetention(options?.cacheRetention);
|
|
@@ -1947,7 +2060,7 @@ function buildOpenAIResponsesParams(model, context, options, metadata, replayMod
|
|
|
1947
2060
|
...metadata ? { metadata } : {}
|
|
1948
2061
|
};
|
|
1949
2062
|
const effectiveMaxTokens = options?.maxTokens || model.maxTokens;
|
|
1950
|
-
if (effectiveMaxTokens) params.max_output_tokens = Math.max(effectiveMaxTokens, 16);
|
|
2063
|
+
if (effectiveMaxTokens) params.max_output_tokens = clampMaxTokensToModel(model, Math.max(effectiveMaxTokens, 16));
|
|
1951
2064
|
if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
|
|
1952
2065
|
if (options?.topP !== void 0 && (!isOpenAIGpt6Model(model) || resolveOpenAIThinkingApi(model.api) === "azure-openai-responses")) params.top_p = options.topP;
|
|
1953
2066
|
if (options?.responseFormat !== void 0) params.text = {
|
|
@@ -1992,26 +2105,31 @@ function buildOpenAIResponsesParams(model, context, options, metadata, replayMod
|
|
|
1992
2105
|
//#endregion
|
|
1993
2106
|
//#region packages/ai/src/transports/openai-responses-compact-client.ts
|
|
1994
2107
|
async function postOpenAIResponsesCompaction(params) {
|
|
1995
|
-
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
|
+
};
|
|
1996
2117
|
const response = await params.client.post("/responses/compact", {
|
|
1997
2118
|
...buildOpenAISdkRequestOptions(params.model, params.options?.signal, { timeoutMs: params.options?.timeoutMs }),
|
|
1998
|
-
body
|
|
1999
|
-
model: params.request.model,
|
|
2000
|
-
input: compactInput
|
|
2001
|
-
}
|
|
2119
|
+
body
|
|
2002
2120
|
});
|
|
2003
|
-
|
|
2004
|
-
const
|
|
2005
|
-
|
|
2006
|
-
const
|
|
2007
|
-
const
|
|
2008
|
-
|
|
2009
|
-
const usage = isRecord(response
|
|
2010
|
-
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");
|
|
2011
2129
|
return {
|
|
2012
|
-
output,
|
|
2130
|
+
output: window,
|
|
2013
2131
|
item,
|
|
2014
|
-
historyMode:
|
|
2132
|
+
historyMode: window.length > 1 ? "retained-users" : "compacted-prefix",
|
|
2015
2133
|
usage,
|
|
2016
2134
|
model: params.model,
|
|
2017
2135
|
replayMetadata: buildOpenAIResponsesReasoningReplayMetadata(params.model, {
|
|
@@ -2021,39 +2139,6 @@ async function postOpenAIResponsesCompaction(params) {
|
|
|
2021
2139
|
};
|
|
2022
2140
|
}
|
|
2023
2141
|
//#endregion
|
|
2024
|
-
//#region packages/ai/src/transports/openai-responses-compact-request.ts
|
|
2025
|
-
const COMPACT_REQUEST = Symbol("openaiResponsesCompactRequest");
|
|
2026
|
-
function claimResponsesCompactRequest(options) {
|
|
2027
|
-
const controller = options ? Reflect.get(options, COMPACT_REQUEST) : void 0;
|
|
2028
|
-
if (controller?.claimed === false) {
|
|
2029
|
-
controller.claimed = true;
|
|
2030
|
-
return controller;
|
|
2031
|
-
}
|
|
2032
|
-
}
|
|
2033
|
-
/** Run a compact-endpoint request through the session's prepared stream stack. */
|
|
2034
|
-
async function requestPreparedOpenAIResponsesCompaction(streamFn, model, context, options) {
|
|
2035
|
-
const preparedOptions = { ...options };
|
|
2036
|
-
let resolveResult;
|
|
2037
|
-
let rejectResult;
|
|
2038
|
-
const result = new Promise((resolve, reject) => {
|
|
2039
|
-
resolveResult = resolve;
|
|
2040
|
-
rejectResult = reject;
|
|
2041
|
-
});
|
|
2042
|
-
const controller = {
|
|
2043
|
-
claimed: false,
|
|
2044
|
-
resolve: resolveResult,
|
|
2045
|
-
reject: rejectResult
|
|
2046
|
-
};
|
|
2047
|
-
Reflect.set(preparedOptions, COMPACT_REQUEST, controller);
|
|
2048
|
-
const stream = await Promise.resolve(streamFn(model, context, preparedOptions));
|
|
2049
|
-
if (!controller.claimed) throw new Error("Prepared stream did not reach an OpenAI Responses transport");
|
|
2050
|
-
try {
|
|
2051
|
-
return await result;
|
|
2052
|
-
} finally {
|
|
2053
|
-
await stream.result().catch(() => void 0);
|
|
2054
|
-
}
|
|
2055
|
-
}
|
|
2056
|
-
//#endregion
|
|
2057
2142
|
//#region packages/ai/src/transports/openai-responses-reasoning-state.ts
|
|
2058
2143
|
/** Save only admitted settings and hashes, never another copy of the conversation. */
|
|
2059
2144
|
function recordResponsesReasoningState(message, model, identity, request, output) {
|
|
@@ -2314,6 +2399,16 @@ function createRecoverableResponsesWebSocketStream(params) {
|
|
|
2314
2399
|
const SESSION_WEBSOCKET_CACHE_TTL_MS = 3e5;
|
|
2315
2400
|
const SESSION_WEBSOCKET_MAX_AGE_MS = 33e5;
|
|
2316
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
|
+
}
|
|
2317
2412
|
const websocketSessionCache = /* @__PURE__ */ new Map();
|
|
2318
2413
|
const degradedWebSocketConnections = /* @__PURE__ */ new Map();
|
|
2319
2414
|
function closeWebSocketSilently(socket, reason = "done") {
|
|
@@ -2675,16 +2770,6 @@ function closeOpenAIResponsesWebSocketSessions(sessionId, owner) {
|
|
|
2675
2770
|
registerSessionResourceCleanup(closeOpenAIResponsesWebSocketSessions);
|
|
2676
2771
|
//#endregion
|
|
2677
2772
|
//#region packages/ai/src/transports/openai-responses-client.ts
|
|
2678
|
-
function resolveNativeOpenAIResponsesWebSocketMode(model, transport) {
|
|
2679
|
-
if (transport !== "websocket" && transport !== "websocket-cached" && transport !== "auto") return;
|
|
2680
|
-
if (getAiTransportHost().requiresManagedTransport(model)) return;
|
|
2681
|
-
return supportsNativeOpenAIResponsesEndpoint(model) ? transport : void 0;
|
|
2682
|
-
}
|
|
2683
|
-
function combineWebSocketTimeoutSignal(signal, model, timeoutMs) {
|
|
2684
|
-
const resolvedTimeoutMs = timeoutMs !== void 0 && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : getAiTransportHost().resolveModelRequestTimeoutMs(model);
|
|
2685
|
-
if (resolvedTimeoutMs === void 0 || !Number.isFinite(resolvedTimeoutMs)) return signal;
|
|
2686
|
-
return AbortSignal.any([signal, AbortSignal.timeout(Math.max(1, resolvedTimeoutMs))]);
|
|
2687
|
-
}
|
|
2688
2773
|
function createOpenAIResponsesClient(model, apiKey, defaultHeaders, fetchOverride) {
|
|
2689
2774
|
return new OpenAI({
|
|
2690
2775
|
apiKey,
|
|
@@ -2698,7 +2783,9 @@ function createOpenAIResponsesClient(model, apiKey, defaultHeaders, fetchOverrid
|
|
|
2698
2783
|
function createResponsesTransportExecutor(config) {
|
|
2699
2784
|
return (model, context, options) => {
|
|
2700
2785
|
const responsesOptions = options;
|
|
2786
|
+
const independent = independentResponsesRequest.has(options);
|
|
2701
2787
|
const compactRequest = claimResponsesCompactRequest(responsesOptions);
|
|
2788
|
+
const v2Compaction = compactRequest?.mode === "v2" ? createResponsesV2CompactionCollector(compactRequest.replayBudget) : void 0;
|
|
2702
2789
|
const { eventStream, stream } = createWritableTransportEventStream();
|
|
2703
2790
|
(async () => {
|
|
2704
2791
|
const output = createAssistantOutput(model, config.outputApi);
|
|
@@ -2706,9 +2793,10 @@ function createResponsesTransportExecutor(config) {
|
|
|
2706
2793
|
let continuationClaim;
|
|
2707
2794
|
const requestLifecycle = responsesRequestLifecycle.get(options);
|
|
2708
2795
|
try {
|
|
2796
|
+
if (compactRequest && requestLifecycle) throw new Error("Provider review continuation cannot replace its reviewed input with compaction");
|
|
2709
2797
|
const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
|
|
2710
|
-
const websocketMode = resolveNativeOpenAIResponsesWebSocketMode(model, responsesOptions?.transport);
|
|
2711
|
-
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);
|
|
2712
2800
|
const turnState = resolveProviderTransportTurnState(model, {
|
|
2713
2801
|
sessionId: options?.sessionId,
|
|
2714
2802
|
turnId: randomUUID(),
|
|
@@ -2720,21 +2808,26 @@ function createResponsesTransportExecutor(config) {
|
|
|
2720
2808
|
const websocketTurnHeaders = filterProviderTurnHeadersForExplicitOpencodeSession(model, options, websocketSessionPolicy?.headers);
|
|
2721
2809
|
const websocketHeaders = websocketMode ? buildOpenAIClientHeaders(model, context, options?.headers, websocketTurnHeaders, options?.sessionId, options?.cacheRetention) : void 0;
|
|
2722
2810
|
const httpHeaders = buildOpenAIClientHeaders(model, context, options?.headers, httpTurnHeaders, options?.sessionId, options?.cacheRetention);
|
|
2723
|
-
const fetchOverride = createResponsesRequestFetch(model, {
|
|
2724
|
-
compact:
|
|
2811
|
+
const fetchOverride = withOpenAIErrorResponseHook(createResponsesRequestFetch(model, {
|
|
2812
|
+
compact: compactRequest?.mode === "endpoint",
|
|
2725
2813
|
stream: config.streamRequest,
|
|
2726
2814
|
lifecycle: requestLifecycle,
|
|
2727
2815
|
onSseComment: () => notifyLlmRequestActivity(options?.signal, false)
|
|
2728
|
-
});
|
|
2816
|
+
}) ?? buildGuardedModelFetch(model), options?.onResponse, model);
|
|
2729
2817
|
const client = config.createClient(model, apiKey, httpHeaders, fetchOverride);
|
|
2730
2818
|
const nativeAstra = model.id === "gpt-6-astra" && supportsNativeOpenAIResponsesEndpoint(model);
|
|
2731
2819
|
const asyncToolExecutionEligible = nativeAstra && options?.asyncToolExecution === true && !responsesOptions?.openclawCodeModeToolSurface;
|
|
2732
2820
|
const prepareRequest = async (request) => {
|
|
2733
2821
|
let params = request;
|
|
2822
|
+
const preserveUsers = v2Compaction?.preserveUsers(request.input ?? []);
|
|
2734
2823
|
const nextParams = await options?.onPayload?.(params, model);
|
|
2735
2824
|
if (nextParams !== void 0) params = nextParams;
|
|
2825
|
+
if (preserveUsers) params = {
|
|
2826
|
+
...params,
|
|
2827
|
+
input: preserveUsers(params.input ?? [])
|
|
2828
|
+
};
|
|
2736
2829
|
params = sanitizeOpenAICodexResponsesParams(model, params);
|
|
2737
|
-
params = sanitizeResponsesImagePayload(params);
|
|
2830
|
+
params = v2Compaction ? v2Compaction.sanitizeImages(params) : sanitizeResponsesImagePayload(params);
|
|
2738
2831
|
if (responsesOptions?.openclawCodeModeToolSurface === true) {
|
|
2739
2832
|
const visibleToolNames = resolveCodeModeResponsesVisibleToolNames(context);
|
|
2740
2833
|
const allowedHostedToolTypes = responsesOptions?.openclawCodeModeAllowedHostedToolTypes;
|
|
@@ -2748,12 +2841,16 @@ function createResponsesTransportExecutor(config) {
|
|
|
2748
2841
|
async: true
|
|
2749
2842
|
} : tool);
|
|
2750
2843
|
}
|
|
2844
|
+
if (v2Compaction) {
|
|
2845
|
+
params.input = [...params.input ?? [], { type: "compaction_trigger" }];
|
|
2846
|
+
v2Compaction.assertReplayFits(params.input, model);
|
|
2847
|
+
}
|
|
2751
2848
|
return params;
|
|
2752
2849
|
};
|
|
2753
|
-
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)));
|
|
2754
2851
|
let params = await buildRequest("checkpoint");
|
|
2755
|
-
const asyncTools = asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true;
|
|
2756
|
-
if (compactRequest) {
|
|
2852
|
+
const asyncTools = !compactRequest && asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true;
|
|
2853
|
+
if (compactRequest?.mode === "endpoint") {
|
|
2757
2854
|
const compacted = await postOpenAIResponsesCompaction({
|
|
2758
2855
|
client,
|
|
2759
2856
|
model,
|
|
@@ -2763,6 +2860,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2763
2860
|
output.usage.input = compacted.usage.input_tokens;
|
|
2764
2861
|
output.usage.output = compacted.usage.output_tokens;
|
|
2765
2862
|
output.usage.totalTokens = compacted.usage.input_tokens + compacted.usage.output_tokens;
|
|
2863
|
+
output.usage.usageReport = { state: "available" };
|
|
2766
2864
|
compactRequest.resolve(compacted);
|
|
2767
2865
|
finalizeTransportStream({
|
|
2768
2866
|
stream,
|
|
@@ -2772,16 +2870,17 @@ function createResponsesTransportExecutor(config) {
|
|
|
2772
2870
|
return;
|
|
2773
2871
|
}
|
|
2774
2872
|
const sessionId = options?.sessionId;
|
|
2775
|
-
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);
|
|
2776
2875
|
continuationClaim = claimOpenAIResponsesHttpContinuation({
|
|
2777
2876
|
sessionId,
|
|
2778
2877
|
apiKey,
|
|
2779
2878
|
baseUrl: model.baseUrl,
|
|
2780
2879
|
headers: httpHeaders,
|
|
2781
2880
|
request: params,
|
|
2782
|
-
restoreRequest
|
|
2881
|
+
restoreRequest
|
|
2783
2882
|
});
|
|
2784
|
-
|
|
2883
|
+
params = continuationClaim?.fullRequest ?? restoreRequest();
|
|
2785
2884
|
}
|
|
2786
2885
|
const observePrompt = createResponsesPromptEgressObserver(responsesOptions, context.systemPrompt);
|
|
2787
2886
|
const requestStartedAt = Date.now();
|
|
@@ -2829,7 +2928,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2829
2928
|
continuationBaseline = attempt.request.previous_response_id ? params : attempt.request;
|
|
2830
2929
|
const trackedResponseStream = responseModelTracker.track(response, rawResponseStream);
|
|
2831
2930
|
return withProviderResponseHook({
|
|
2832
|
-
stream: observeResponsesStream(trackedResponseStream, model, requestStartedAt),
|
|
2931
|
+
stream: observeResponsesStream(v2Compaction ? v2Compaction.observe(trackedResponseStream) : trackedResponseStream, model, requestStartedAt, attempt.request),
|
|
2833
2932
|
signal: firstEvent.signal,
|
|
2834
2933
|
abort: firstEvent.abort,
|
|
2835
2934
|
hook: createOpenAIProviderAcceptanceHook(options, response, model),
|
|
@@ -2864,7 +2963,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2864
2963
|
signal: websocketSignal,
|
|
2865
2964
|
callerSignal: options?.signal,
|
|
2866
2965
|
degradeCooldownMs: websocketSessionPolicy?.degradeCooldownMs,
|
|
2867
|
-
onActiveResponse: nativeAstra && params.model === "gpt-6-astra" ? options?.onActiveResponse : void 0,
|
|
2966
|
+
onActiveResponse: !compactRequest && nativeAstra && params.model === "gpt-6-astra" ? options?.onActiveResponse : void 0,
|
|
2868
2967
|
steeringInput: (messages) => {
|
|
2869
2968
|
contextUsageEligible = false;
|
|
2870
2969
|
return projectResponsesSteeringInput(params, () => buildRequest("checkpoint", {
|
|
@@ -2885,7 +2984,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2885
2984
|
transport = "websocket";
|
|
2886
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))))}`);
|
|
2887
2986
|
responseStream = createRecoverableResponsesWebSocketStream({
|
|
2888
|
-
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"),
|
|
2889
2988
|
websocket,
|
|
2890
2989
|
websocketSignal,
|
|
2891
2990
|
options,
|
|
@@ -2911,7 +3010,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2911
3010
|
canRetryIdentityConflict: () => hasOnlyResponsesFunctionTools(transport === "websocket" ? websocketBaseline : continuationBaseline),
|
|
2912
3011
|
...config.pricingOptions?.(responsesOptions, model),
|
|
2913
3012
|
resolveServiceTier: (responseTier, originalTier) => responseTier ?? (requestedTier === "priority" || requestedTier === "default" ? requestedTier : originalTier),
|
|
2914
|
-
onServiceTier: (
|
|
3013
|
+
onServiceTier: (tier, response) => responsesServiceTierObserver.observe(options, requestedTier, tier, response),
|
|
2915
3014
|
firstEventTimeoutMs: getFirstStreamEventTimeoutMs(options) ?? config.firstEventTimeoutMs,
|
|
2916
3015
|
abortFirstEventStream: firstEvent.abort,
|
|
2917
3016
|
onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
|
|
@@ -2926,7 +3025,25 @@ function createResponsesTransportExecutor(config) {
|
|
|
2926
3025
|
finishWebSocket?.();
|
|
2927
3026
|
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
2928
3027
|
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
2929
|
-
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
|
+
}
|
|
2930
3047
|
if (terminal && admitted && supportsNativeOpenAIResponsesEndpoint(model)) recordResponsesReasoningState(output, model, responsesOptions, admitted, terminal.output);
|
|
2931
3048
|
if (continuationClaim && continuationBaseline && terminal) continuationClaim.commit(continuationBaseline, terminal, dispatchedPreviousResponseId);
|
|
2932
3049
|
if (terminal && admitted && contextUsageEligible) recordResponsesContextUsage(output, model, responsesOptions, admitted, terminal.output, "transport");
|
|
@@ -3158,7 +3275,7 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3158
3275
|
const { eventStream, stream } = createWritableTransportEventStream();
|
|
3159
3276
|
(async () => {
|
|
3160
3277
|
const output = createAssistantOutput(model);
|
|
3161
|
-
|
|
3278
|
+
let discardCandidate = false;
|
|
3162
3279
|
let firstEventAbort;
|
|
3163
3280
|
try {
|
|
3164
3281
|
const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
|
|
@@ -3170,10 +3287,11 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3170
3287
|
cacheRetention
|
|
3171
3288
|
} : { mode };
|
|
3172
3289
|
const { client, sawStreamDONE } = policy.mode === "direct" ? {
|
|
3173
|
-
client: createDirectCompletionsClient(model, context, apiKey,
|
|
3290
|
+
client: createDirectCompletionsClient(model, context, apiKey, options, cacheRetention === "none" ? void 0 : options?.sessionId, policy.compat),
|
|
3174
3291
|
sawStreamDONE: void 0
|
|
3175
3292
|
} : createManagedCompletionsClient(model, context, options, apiKey, cacheRetention);
|
|
3176
|
-
|
|
3293
|
+
const builtParams = buildOpenAICompletionsRequest(model, context, options, policy);
|
|
3294
|
+
let params = builtParams;
|
|
3177
3295
|
const encodeBody = prepareModelRequestBody(options);
|
|
3178
3296
|
const nextParams = await options?.onPayload?.(params, model);
|
|
3179
3297
|
if (nextParams !== void 0) params = nextParams;
|
|
@@ -3185,6 +3303,7 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3185
3303
|
}
|
|
3186
3304
|
if (getCompat(model).requiresNonEmptyUserOrAssistantMessage) assertOpenAICompletionsPayloadHasConversationTurn(params, model);
|
|
3187
3305
|
}
|
|
3306
|
+
const contextOutputBudget = resolveCompletionsContextOutputBudget(builtParams, params);
|
|
3188
3307
|
const emitReasoning = mode === "direct" ? directEmitReasoning : shouldEmitOpenAICompletionsReasoning(model, options);
|
|
3189
3308
|
firstEventAbort = createFirstStreamEventAbortController(options?.signal);
|
|
3190
3309
|
const requestOptions = mode === "direct" ? {
|
|
@@ -3214,27 +3333,42 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3214
3333
|
signal: firstEventAbort.signal,
|
|
3215
3334
|
abort: firstEventAbort.abort,
|
|
3216
3335
|
hook: createOpenAIProviderAcceptanceHook(options, response, model),
|
|
3217
|
-
onReady: () =>
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
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
|
|
3221
3358
|
});
|
|
3222
3359
|
const directEvents = mode === "direct" ? createDirectCompletionsEventStream(output, stream) : void 0;
|
|
3223
3360
|
try {
|
|
3224
|
-
await processCompletionsStream(
|
|
3361
|
+
await processCompletionsStream(buffered?.stream ?? providerStream, output, model, discardCandidate ? { push() {} } : directEvents?.stream ?? stream, {
|
|
3225
3362
|
...directEvents ? {
|
|
3226
3363
|
mode: "direct",
|
|
3227
|
-
beforeContentBlock: directEvents.beforeContentBlock
|
|
3228
|
-
provisionalCommentaryTags
|
|
3364
|
+
beforeContentBlock: directEvents.beforeContentBlock
|
|
3229
3365
|
} : { mode: "managed" },
|
|
3230
|
-
signal: options?.signal,
|
|
3366
|
+
signal: discardCandidate ? void 0 : options?.signal,
|
|
3231
3367
|
emitReasoning,
|
|
3232
3368
|
strictReasoningTags: reasoningTagTextPolicy.isStrict(options),
|
|
3233
|
-
firstEventTimeoutMs: getFirstStreamEventTimeoutMs(options),
|
|
3234
|
-
abortFirstEventStream: firstEventAbort.abort,
|
|
3235
|
-
onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
|
|
3236
3369
|
sawStreamDONE
|
|
3237
3370
|
});
|
|
3371
|
+
if (discardCandidate) throw new Error(`Context length exceeded: automatic output budget of ${contextOutputBudget} tokens exhausted before completion.`);
|
|
3238
3372
|
if (directEvents) {
|
|
3239
3373
|
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
3240
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"));
|
|
@@ -3250,6 +3384,7 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3250
3384
|
signal: options?.signal
|
|
3251
3385
|
});
|
|
3252
3386
|
} catch (error) {
|
|
3387
|
+
if (discardCandidate) output.content = [];
|
|
3253
3388
|
failTransportStream({
|
|
3254
3389
|
stream,
|
|
3255
3390
|
output,
|
|
@@ -3257,11 +3392,9 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3257
3392
|
error,
|
|
3258
3393
|
cleanup: () => {
|
|
3259
3394
|
finalizeOpenAICompletionsToolCalls(output, { allowSilentToolCallPromotion: false });
|
|
3260
|
-
clearPendingCommentaryText(provisionalCommentaryTags);
|
|
3261
|
-
tagUnresolvedTextAsCommentary(output);
|
|
3262
3395
|
if (mode === "direct") for (const block of output.content) {
|
|
3263
3396
|
delete block.index;
|
|
3264
|
-
delete block.
|
|
3397
|
+
if (block.type === "toolCall") delete block.partialJson;
|
|
3265
3398
|
delete block.streamIndex;
|
|
3266
3399
|
}
|
|
3267
3400
|
}
|
|
@@ -3272,7 +3405,7 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
|
3272
3405
|
})();
|
|
3273
3406
|
return eventStream;
|
|
3274
3407
|
}
|
|
3275
|
-
function createDirectCompletionsClient(model, context, apiKey,
|
|
3408
|
+
function createDirectCompletionsClient(model, context, apiKey, options, sessionId, compat) {
|
|
3276
3409
|
if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
|
|
3277
3410
|
const headers = { ...model.headers };
|
|
3278
3411
|
if (model.provider === "github-copilot") Object.assign(headers, buildCopilotDynamicHeaders(context.messages));
|
|
@@ -3284,7 +3417,7 @@ function createDirectCompletionsClient(model, context, apiKey, optionsHeaders, s
|
|
|
3284
3417
|
headers["x-session-affinity"] = sessionId;
|
|
3285
3418
|
}
|
|
3286
3419
|
}
|
|
3287
|
-
return createOpenAIProviderClient(model, apiKey, headers,
|
|
3420
|
+
return createOpenAIProviderClient(model, apiKey, headers, resolveProviderSimpleCompletionHeaders(model, options), options?.onResponse);
|
|
3288
3421
|
}
|
|
3289
3422
|
function createManagedCompletionsClient(model, context, options, apiKey, cacheRetention) {
|
|
3290
3423
|
const turnState = resolveProviderTransportTurnState(model, {
|
|
@@ -3296,7 +3429,7 @@ function createManagedCompletionsClient(model, context, options, apiKey, cacheRe
|
|
|
3296
3429
|
const optionHeaders = resolveOpencodeSessionHeaders(model, options);
|
|
3297
3430
|
const turnHeaders = filterProviderTurnHeadersForExplicitOpencodeSession(model, options, turnState?.headers);
|
|
3298
3431
|
const doneDetector = createSseDoneDetector();
|
|
3299
|
-
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);
|
|
3300
3433
|
const doneDetectingFetch = async (url, init) => {
|
|
3301
3434
|
const response = await baseFetch(url, init);
|
|
3302
3435
|
if (!response.body || !response.ok) return response;
|
|
@@ -3330,4 +3463,4 @@ function createManagedCompletionsClient(model, context, options, apiKey, cacheRe
|
|
|
3330
3463
|
};
|
|
3331
3464
|
}
|
|
3332
3465
|
//#endregion
|
|
3333
|
-
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 };
|