@openclaw/ai 2026.9.2 → 2026.9.3
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 +3 -2
- package/dist/anthropic-CZy5U0NY.mjs +376 -0
- package/dist/{anthropic-payload-policy-d46X2pR0.d.mts → anthropic-payload-policy-wuRCb6MH.d.mts} +16 -6
- package/dist/{anthropic-compaction-replay-DB2FGLQc.mjs → anthropic-stream-reducer-B_yo_7pf.mjs} +923 -181
- package/dist/{api-registry-DWtPjzyn.d.mts → api-registry-CB1-1oQ2.d.mts} +2 -2
- package/dist/assistant-output-iqnlJCV2.mjs +16 -0
- package/dist/assistant-text-phase-C20rxWwP.mjs +55 -0
- package/dist/{azure-openai-responses-C5bZRfAP.mjs → azure-openai-responses-Crpa40QR.mjs} +5 -5
- package/dist/{base64-CEFBpSkN.mjs → base64-D-su8YVo.mjs} +1 -27
- package/dist/{diagnostics-DfFyKeX_.mjs → diagnostics-dV98PqIy.mjs} +96 -21
- package/dist/diagnostics.d.mts +3 -1
- package/dist/diagnostics.mjs +3 -3
- package/dist/{event-stream-BhT5T1Ay.d.mts → event-stream-C1Z2piyk.d.mts} +11 -3
- package/dist/{event-stream-BgDvQeum.mjs → event-stream-D8PARQfL.mjs} +45 -1
- package/dist/event-stream-I_GlBsuZ.d.mts +1 -0
- package/dist/event-stream.d.mts +2 -2
- package/dist/event-stream.mjs +1 -1
- package/dist/{github-copilot-headers-NCJtz9i0.mjs → github-copilot-headers-B37TB3rB.mjs} +3 -10
- package/dist/github-copilot-request-facts-BTEBMeOv.mjs +16 -0
- package/dist/{google-4qeuE8iX.mjs → google-BDPriaVe.mjs} +10 -10
- package/dist/google-messages-CVn9eFpF.mjs +449 -0
- package/dist/google-shared-BedY23XS.mjs +185 -0
- package/dist/{google-vertex-O9BcnB6X.mjs → google-vertex-DMz8XQCn.mjs} +7 -6
- package/dist/{host-CEvLw30U.mjs → host-CWuF-sS3.mjs} +44 -39
- package/dist/{host-DjzGmdZ2.d.mts → host-DK3wmS3e.d.mts} +3 -3
- package/dist/host-policy-CAopLRKA.mjs +37 -0
- package/dist/{index-FnHM2FcI.d.mts → index-CQ6LTHw8.d.mts} +3 -3
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +4 -4
- package/dist/internal/anthropic.d.mts +7 -7
- package/dist/internal/anthropic.mjs +4 -4
- package/dist/internal/google-model-family.d.mts +5 -0
- package/dist/internal/google-model-family.mjs +15 -0
- package/dist/internal/openai-responses-payload-policy.d.mts +1 -1
- package/dist/internal/openai-responses-payload-policy.mjs +1 -1
- package/dist/internal/openai.d.mts +8 -103
- package/dist/internal/openai.mjs +10 -10
- package/dist/internal/retry-after.d.mts +2 -4
- package/dist/internal/retry-after.mjs +57 -8
- package/dist/internal/runtime.d.mts +7 -6
- package/dist/internal/runtime.mjs +8 -7
- package/dist/internal/shared.d.mts +14 -3
- package/dist/internal/shared.mjs +6 -4
- package/dist/internal/tool-schema.d.mts +63 -0
- package/dist/internal/tool-schema.mjs +3 -0
- package/dist/{json-parse-BuAJEbdW.mjs → json-parse-Dw_hnxsA.mjs} +1 -1
- package/dist/{mistral-Tb6oalqH.mjs → mistral--m-Jm6VZ.mjs} +13 -37
- package/dist/model-transport-url-DKocrEsb.d.mts +28 -0
- package/dist/{openai-chatgpt-responses-yUXjPNfu.mjs → openai-chatgpt-responses-nDZccFW-.mjs} +48 -38
- package/dist/openai-completions-KuoZyx0d.mjs +187 -0
- package/dist/{openai-completions-compat-CpjYUArk.d.mts → openai-completions-compat-CXn3T1we.d.mts} +26 -4
- package/dist/{openai-completions-stream-BsrBe3Gg.mjs → openai-completions-stream-BQk3SkLD.mjs} +622 -452
- package/dist/openai-prompt-cache-BI0rkM-5.mjs +220 -0
- package/dist/openai-prompt-cache-rrutvqxq.d.mts +16 -0
- package/dist/openai-provider-client-ha_WxTyj.mjs +24 -0
- package/dist/openai-reasoning-effort-BK7FbcLT.mjs +167 -0
- package/dist/{openai-responses-CCL41ALM.mjs → openai-responses-D99dOzKI.mjs} +14 -29
- package/dist/{openai-responses-compaction-window-BMVHFOtq.mjs → openai-responses-compaction-window-D5jbzCi3.mjs} +7 -170
- package/dist/{openai-responses-contracts-rF5DDRNS.d.mts → openai-responses-contracts-B55afwRo.d.mts} +3 -3
- package/dist/{openai-responses-prompt-observer-internal-D0bhBfgL.mjs → openai-responses-prompt-observer-internal-tApyTLVu.mjs} +3 -3
- package/dist/{openai-responses-shared-Bmma_3Qc.mjs → openai-responses-shared-ZyQEzS5i.mjs} +44 -115
- package/dist/openai-tool-projection-793cE3QX.d.mts +37 -0
- package/dist/{openai-tool-schema-_pTAJqKF.mjs → openai-tool-schema-CzjyYXun.mjs} +38 -556
- package/dist/openai-tool-schema-ynZBgqW-.d.mts +38 -0
- package/dist/openai-transport-params-DNasp2fU.mjs +674 -0
- package/dist/{provider-error-9TraxGvt.mjs → provider-error-C6TbKiey.mjs} +23 -6
- package/dist/{provider-options-Bcc_p-TU.d.mts → provider-options-BXr9Ec83.d.mts} +4 -39
- package/dist/{provider-transcript-transform-BaMbI1hr.mjs → provider-transcript-transform-pPmUIwKt.mjs} +1 -1
- package/dist/provider-types-CAV0Og3m.d.mts +29 -0
- package/dist/provider-types.d.mts +6 -31
- package/dist/providers.d.mts +2 -2
- package/dist/providers.mjs +11 -11
- package/dist/{reasoning-tag-text-partitioner-DLCNXki6.mjs → reasoning-tag-text-partitioner-BQBi4B9d.mjs} +19 -12
- package/dist/record-coerce-DwRYMj3t.mjs +32 -0
- package/dist/retry-after-CdCURCVg.d.mts +15 -0
- package/dist/{sanitize-unicode-D6xUvZaS.mjs → sanitize-unicode-Bb-v9meu.mjs} +1 -1
- package/dist/session-affinity-CCH7eYdB.mjs +20 -0
- package/dist/{simple-options-BjHCCh4v.mjs → simple-options-tcKOqnpF.mjs} +3 -3
- package/dist/{src-2qBGKg8O.mjs → src-B2Q_6G8V.mjs} +1 -1
- package/dist/{stream-first-event-timeout-DcNjoFQE.mjs → stream-first-event-timeout-2hfrquuz.mjs} +1 -1
- package/dist/string-coerce-fsri9iCu.mjs +34 -0
- package/dist/{string-normalization--fwJ4S2q.mjs → string-normalization-CmLIasuf.mjs} +1 -1
- package/dist/{tool-schema-json-projection-mJhXDcyz.mjs → tool-schema-json-projection-ClptDdAO.mjs} +2 -38
- package/dist/{transport-stream-shared-CZqMhfIw.mjs → transport-stream-shared-Cu3ZPhNW.mjs} +5 -5
- package/dist/{transport-stream-shared-xnaqxmbP.d.mts → transport-stream-shared-DOxpGJ-H.d.mts} +4 -4
- package/dist/transport-utils-CCooe-cr.mjs +121 -0
- package/dist/transports.d.mts +113 -41
- package/dist/transports.mjs +162 -1276
- package/dist/types-BADKjDBI.d.mts +1 -0
- package/dist/{types-CJ1-Ht7A.d.mts → types-Dy1q0CSu.d.mts} +72 -57
- package/dist/types.d.mts +5 -5
- package/dist/types.mjs +3 -3
- package/dist/utf16-slice-CvGodqok.mjs +29 -0
- package/dist/{validation-CJZtym2g.mjs → validation-BDzVDnTs.mjs} +9 -1
- package/dist/{validation-AKZBDGQd.d.mts → validation-CaFUZN9B.d.mts} +1 -1
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/package.json +13 -3
- package/dist/anthropic-BDdqdVLK.mjs +0 -886
- package/dist/event-stream-zctLx0yr.d.mts +0 -1
- package/dist/google-shared-CWeG8RIl.mjs +0 -636
- package/dist/google-thinking-level-C-V3tecN.mjs +0 -9
- package/dist/openai-completions-BIUV3RDT.mjs +0 -403
- package/dist/openai-prompt-cache-CGnVB74a.mjs +0 -21
- package/dist/openai-prompt-cache-CNoIfHYC.d.mts +0 -16
- package/dist/transport-utils-7il795_9.mjs +0 -138
- package/dist/types-3Lnm-QSJ.d.mts +0 -1
- package/dist/utf16-slice-qz3nsy87.mjs +0 -84
package/dist/transports.mjs
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
|
-
import { _ as supportsClaudeAdaptiveThinking,
|
|
2
|
-
import {
|
|
3
|
-
import { r as
|
|
4
|
-
import {
|
|
5
|
-
import { i as stableStringify } from "./provider-error-
|
|
6
|
-
import { r as
|
|
7
|
-
import { a as
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { _ as supportsClaudeAdaptiveThinking, h as resolveClaudeSonnet5ModelIdentity, m as resolveClaudeOpus5ModelIdentity } from "./src-B2Q_6G8V.mjs";
|
|
2
|
+
import { n as normalizeLowercaseStringOrEmpty, t as hasNonEmptyString } from "./string-coerce-fsri9iCu.mjs";
|
|
3
|
+
import { S as usesClaudeStreamingRefusalContract, _ as prepareClaudeNoPrefillRequestContext, h as defaultsClaudeAdaptiveThinking, m as applyClaudeRequestContract, n as getAiTransportHost, p as ANTHROPIC_CLAUDE_CODE_VERSION, r as resolveAiTransportHeaderSentinels, v as requiresClaudeAdaptiveThinking, x as usesClaudeFable5MessagesContract, y as resolveAnthropicThinkingEffort } from "./host-CWuF-sS3.mjs";
|
|
4
|
+
import { o as isRecord } from "./record-coerce-DwRYMj3t.mjs";
|
|
5
|
+
import { i as stableStringify } from "./provider-error-C6TbKiey.mjs";
|
|
6
|
+
import { a as isNativeOpenAIEndpoint, c as resolveOpenAIPromptCacheKeySupport, i as detectOpenAICompletionsCompat, l as usesNativeOpenAICodexResponsesBackend, o as isOpenAICodexResponsesModel, r as resolveOpenAIPromptCacheParams, s as resolveOpenAICompletionsCompat } from "./openai-prompt-cache-BI0rkM-5.mjs";
|
|
7
|
+
import { a as resolveModelSseDebugMode, i as resolveModelPayloadDebugMode, n as formatModelTransportDebugUrl, r as emitModelTransportDebug, t as formatModelTransportDebugBaseUrl, u as toErrorObject } from "./diagnostics-dV98PqIy.mjs";
|
|
8
|
+
import "./base64-D-su8YVo.mjs";
|
|
9
|
+
import { c as resolveModelHeaderSentinels$1, i as isCodeModeModelVisibleToolName, n as createAbortError$1, o as readResponseTextSnippet, t as MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE } from "./transport-utils-CCooe-cr.mjs";
|
|
10
|
+
import { parseRetryAfterHeadersSeconds } from "./internal/retry-after.mjs";
|
|
11
|
+
import { i as resolveProviderEndpoint, r as resolveOpenAIStrictToolSetting, s as transformTransportMessages, t as buildGuardedModelFetch } from "./host-policy-CAopLRKA.mjs";
|
|
12
|
+
import { B as logAnthropicContextEdits, C as applyAnthropicThinkingBindingControls, D as ANTHROPIC_SERVER_SIDE_FALLBACKS, F as applyAnthropicPayloadPolicyToParams, G as resolveAnthropicServerCompactionPlan, H as resolveAnthropicContextManagementBetaHeader, I as applyAnthropicRequestCacheControl, J as usesFoundryBearerAuth, K as isAnthropicOAuthApiKey, L as buildAnthropicSystemBlocks, N as applyAnthropicContextManagementToRequest, O as ANTHROPIC_SERVER_SIDE_FALLBACK_BETA, P as applyAnthropicEphemeralCacheControlMarkers, R as isAnthropicServerToolClearingEnabled, U as resolveAnthropicEphemeralCacheControl, V as resolveAnthropicCacheOptions, W as resolveAnthropicPayloadPolicy, d as convertAnthropicTools, f as buildAnthropicReplayPlan, g as normalizeAnthropicToolCallId, h as suppressAnthropicCompaction, l as buildAnthropicGenerationParams, m as resolveNewestAnthropicCompaction, p as isAnthropicReplayRejection, q as omitFoundryBearerCredentialHeaders, t as consumeAnthropicStream, u as convertAnthropicMessages, z as isDirectAnthropicModel } from "./anthropic-stream-reducer-B_yo_7pf.mjs";
|
|
11
13
|
import { t as resolveCacheRetention } from "./cache-retention-0x979a5V.mjs";
|
|
12
|
-
import { a as codeModeToolSurfaceObserver, d as stripSystemPromptCacheBoundary, m as sortPromptCacheToolsByName, o as reasoningTagTextPolicy, t as adjustMaxTokensForThinking } from "./simple-options-
|
|
13
|
-
import { a as
|
|
14
|
-
import { a as isGoogleGemini3FlashModel, c as parseRetryAfterSeconds, f as resolveModelHeaderSentinels$1, i as isCodeModeModelVisibleToolName, l as readResponseTextSnippet, m as supportsModelTools, n as createAbortError$1, o as isGoogleGemini3ProModel, p as sha256Hex, r as estimateStringChars, t as MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE, u as redactIdentifier } from "./transport-utils-7il795_9.mjs";
|
|
14
|
+
import { a as codeModeToolSurfaceObserver, d as stripSystemPromptCacheBoundary, m as sortPromptCacheToolsByName, o as reasoningTagTextPolicy, t as adjustMaxTokensForThinking } from "./simple-options-tcKOqnpF.mjs";
|
|
15
|
+
import { C as readOpenAICompletionsContentDeltas, D as throwIfModelStreamAborted, E as resolvePromptCacheKey, O as redactIdentifier, S as parseOpenAICompletionsUsage, T as resolveOpenAIClientBaseUrl, _ as createOpenAIProviderAcceptanceHook, a as enforceCodeModeResponsesToolSurface, b as log, c as readCodeModePayloadToolName, d as resolveOpenAIReasoningEffortMap, f as projectOpenAITools, g as createModelStreamCooperativeScheduler, h as GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP, i as buildOpenAISdkRequestOptions, k as sha256Hex, l as resolveCodeModeResponsesVisibleToolNames, m as reconcileOpenAIResponsesToolChoice, n as buildOpenAIClientHeaders, o as filterCodeModePayloadTools, r as buildOpenAISdkClientOptions, s as getCompat, t as assertCodeModeResponsesToolSurface, u as resolveOpenAIStrictToolFlagWithDiagnostics, v as createOpenAIResponseHook, w as readOpenAICompletionsReasoningBatch, x as measureUtf8AppendBytes, y as isOpenAICompletionsThinkingEnabled } from "./openai-transport-params-DNasp2fU.mjs";
|
|
15
16
|
import { n as getEnvApiKey } from "./env-api-keys-bktO00EJ.mjs";
|
|
16
|
-
import { S as quoteUnsafeIntegerLiterals, _ as transportAbortError, a as createWritableTransportEventStream, b as parseJsonObjectPreservingUnsafeIntegers, c as finalizeTransportStream, d as notifyProviderHttpMetadata, f as notifyProviderHttpResponse, g as sanitizeTransportPayloadText, h as sanitizeNonEmptyTransportPayloadText, i as createEmptyTransportUsage, l as mergeTransportHeaders, m as parseTerminalToolCallArguments, n as coerceTransportToolCallArguments, o as failTransportStream, p as notifyProviderStreamOpened, r as copyProviderAcceptanceObserver, s as finalizeTerminalToolCallArguments, t as assignTransportErrorDetails, u as mergeTransportMetadata, v as withProviderAcceptanceObserver, x as parseJsonPreservingUnsafeIntegers, y as withProviderResponseHook } from "./transport-stream-shared-
|
|
17
|
-
import { C as createDeepSeekTextFilter, E as tagUnresolvedTextAsCommentary, S as shouldOmitOllamaCompatResponseFormat, T as tagPendingCommentaryText, _ as hasToolCallHistory, a as buildOpenAISdkClientOptions, b as resolveOpenAICompletionsCompat, c as filterCodeModePayloadTools, d as readCodeModePayloadToolName, f as resolveCodeModeResponsesVisibleToolNames, g as convertMessages, h as resolveOpenAIReasoningEffortMap, i as buildOpenAIClientHeaders, l as getCompat, m as usesNativeOpenAICodexResponsesBackend, n as shouldEmitOpenAICompletionsReasoning, o as buildOpenAISdkRequestOptions, p as resolveOpenAIStrictToolFlagWithDiagnostics, r as assertCodeModeResponsesToolSurface, s as enforceCodeModeResponsesToolSurface, t as processCompletionsStream, u as isOpenAICodexResponsesModel, v as finalizeOpenAICompletionsToolCalls, x as resolveOpenAICompletionsResponseFormat, y as detectOpenAICompletionsCompat } from "./openai-completions-stream-BsrBe3Gg.mjs";
|
|
17
|
+
import { S as quoteUnsafeIntegerLiterals, _ as transportAbortError, a as createWritableTransportEventStream, b as parseJsonObjectPreservingUnsafeIntegers, c as finalizeTransportStream, d as notifyProviderHttpMetadata, f as notifyProviderHttpResponse, g as sanitizeTransportPayloadText, h as sanitizeNonEmptyTransportPayloadText, i as createEmptyTransportUsage, l as mergeTransportHeaders, m as parseTerminalToolCallArguments, n as coerceTransportToolCallArguments, o as failTransportStream, p as notifyProviderStreamOpened, r as copyProviderAcceptanceObserver, s as finalizeTerminalToolCallArguments, t as assignTransportErrorDetails, u as mergeTransportMetadata, v as withProviderAcceptanceObserver, x as parseJsonPreservingUnsafeIntegers, y as withProviderResponseHook } from "./transport-stream-shared-Cu3ZPhNW.mjs";
|
|
18
18
|
import { t as createDeferredEventBuffer } from "./deferred-event-buffer-DAvyP7qA.mjs";
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import { t as
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { i as
|
|
25
|
-
import {
|
|
19
|
+
import { n as providerReplayContextMatches, t as buildProviderReplayContext } from "./provider-replay-context-BuSUaAk5.mjs";
|
|
20
|
+
import { a as tagUnresolvedTextAsCommentary } from "./assistant-text-phase-C20rxWwP.mjs";
|
|
21
|
+
import { t as createAssistantOutput } from "./assistant-output-iqnlJCV2.mjs";
|
|
22
|
+
import { t as resolveOpencodeSessionHeaders } from "./session-affinity-CCH7eYdB.mjs";
|
|
23
|
+
import { c as flattenCompletionMessagesToStringContent, d as canonicalizeMaxTokensParam, f as resolveMaxTokensParam, l as stripCompletionMessagesToRoleContent, n as shouldEmitOpenAICompletionsReasoning, o as isAzureOpenAICompatibleHost, p as createDeepSeekTextFilter, r as buildOpenAICompletionsParams, s as finalizeOpenAICompletionsToolCalls, t as processCompletionsStream, u as applyCompletionsAnthropicCacheControl } from "./openai-completions-stream-BQk3SkLD.mjs";
|
|
24
|
+
import { a as googleFlashSupportsMinimalThinking, i as consumeGoogleGenerateContentStream, n as projectGoogleMessages, r as requiresGoogleToolCallId, t as convertGoogleTools } from "./google-messages-CVn9eFpF.mjs";
|
|
25
|
+
import { i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-2hfrquuz.mjs";
|
|
26
|
+
import { i as normalizeOpenAIReasoningEffort, l as supportsOpenAITemperature, o as resolveOpenAIReasoningEffortForModel } from "./openai-reasoning-effort-BK7FbcLT.mjs";
|
|
27
|
+
import { _ as OpenAIResponsesWebSocketPostDispatchError, a as applyOpenAIResponsesPayloadPolicy, c as resolveOpenAIResponsesServerCompactionPlan, d as OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS, f as OPENAI_RESPONSES_APIS, i as sanitizeResponsesImagePayload, l as AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS, n as isOpenAIResponsesCompactionOutput, o as resolveOpenAIResponsesCompactEndpointPlan, s as resolveOpenAIResponsesPayloadPolicy, t as createBoundedOpenAIResponsesCompactionFetch, v as OpenAIResponsesWebSocketPreDispatchError, x as parseOpenAIResponsesWebSocketServerError, y as OpenAIResponsesWebSocketSafeRetryError } from "./openai-responses-compaction-window-D5jbzCi3.mjs";
|
|
28
|
+
import { $ as resolveReplayableResponsesMessageId, B as resolveAzureOpenAIApiVersion, C as summarizeResponsesFailedNoDetailsObservation, G as recordResponsesInputReplay, H as buildResponsesInputMessage, J as buildOpenAIResponsesReasoningReplayMetadata, K as responsesInputFingerprint, Q as suppressOpenAIResponsesCompaction, R as createResponsesStreamWithEncryptedContentRetry, S as summarizeOpenAITransportError, T as summarizeResponsesTools, U as convertResponsesMessages, V as resolveNextResponsesEncryptedContentAttempt, W as createOpenAIResponsesAssistantOutput, X as isOpenAIResponsesReplayContext, Y as captureOpenAIResponsesCompaction, Z as resolveNewestOpenAIResponsesCompactionReplay, _ as logResponsesFailedNoDetails, b as stringifyRedactedEvent, c as convertProjectedResponsesTools, g as buildResponsesFailedNoDetailsObservation, h as ResponsesStreamFailure, m as observeResponsesStream, n as applyResponsesServiceTierPricing, q as CompactionReplayRefreshRequiredError, u as processResponsesStream, v as normalizeResponsesFailedEvent, w as summarizeResponsesPayload, x as stringifyRedactedPayload, y as safeDebugValue, z as isInvalidEncryptedContentError } from "./openai-responses-shared-ZyQEzS5i.mjs";
|
|
26
29
|
import { i as resolveAzureDeploymentNameFromMap, t as isOpenAICompatibleAzureResponsesBaseUrl } from "./azure-openai-responses-client-compat-C7K7QfUE.mjs";
|
|
27
30
|
import { n as registerSessionResourceCleanup } from "./session-resources-CkR4WWy1.mjs";
|
|
28
|
-
import { t as createResponsesPromptEgressObserver } from "./openai-responses-prompt-observer-internal-
|
|
31
|
+
import { t as createResponsesPromptEgressObserver } from "./openai-responses-prompt-observer-internal-tApyTLVu.mjs";
|
|
29
32
|
import { randomUUID } from "node:crypto";
|
|
30
33
|
import OpenAI, { AzureOpenAI } from "openai";
|
|
31
34
|
import { ResponsesWS } from "openai/resources/responses/ws.js";
|
|
@@ -78,221 +81,12 @@ function buildAnthropicBetaHeader(model, betaFeatures, params) {
|
|
|
78
81
|
if (!isDirectAnthropicModel(model)) return;
|
|
79
82
|
return params.oauth ? `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}` : betaFeatures.join(",");
|
|
80
83
|
}
|
|
81
|
-
const NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
|
|
82
|
-
async function convertContentBlocks(content, model, imageBudget) {
|
|
83
|
-
const text = extractToolResultText(content);
|
|
84
|
-
const mediaPlaceholder = describeToolResultMediaPlaceholder(content);
|
|
85
|
-
if (!(model.input.includes("image") && content.some(isImageWithMediaPayload))) return sanitizeNonEmptyTransportPayloadText(text, mediaPlaceholder ?? "(no output)");
|
|
86
|
-
const blocks = [];
|
|
87
|
-
let hasTextBlock = false;
|
|
88
|
-
for (const block of content) {
|
|
89
|
-
if (!block || typeof block !== "object") continue;
|
|
90
|
-
const record = block;
|
|
91
|
-
const blockText = extractToolResultBlockText(block);
|
|
92
|
-
if (blockText) {
|
|
93
|
-
blocks.push({
|
|
94
|
-
type: "text",
|
|
95
|
-
text: sanitizeTransportPayloadText(blockText)
|
|
96
|
-
});
|
|
97
|
-
hasTextBlock = true;
|
|
98
|
-
}
|
|
99
|
-
if (!isImageWithMediaPayload(record)) continue;
|
|
100
|
-
const [normalizedImage] = await normalizeAnthropicInlineContent([{
|
|
101
|
-
type: "image",
|
|
102
|
-
data: typeof record.data === "string" ? record.data : "",
|
|
103
|
-
mimeType: typeof record.mimeType === "string" ? record.mimeType : "image/png"
|
|
104
|
-
}], imageBudget);
|
|
105
|
-
if (normalizedImage?.type !== "image") continue;
|
|
106
|
-
blocks.push({
|
|
107
|
-
type: "image",
|
|
108
|
-
source: {
|
|
109
|
-
type: "base64",
|
|
110
|
-
media_type: resolveAnthropicImageMediaType(normalizedImage.mimeType),
|
|
111
|
-
data: normalizedImage.data
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
if (!hasTextBlock) blocks.unshift({
|
|
116
|
-
type: "text",
|
|
117
|
-
text: mediaPlaceholder ?? "(see attached image)"
|
|
118
|
-
});
|
|
119
|
-
return blocks;
|
|
120
|
-
}
|
|
121
|
-
async function convertAnthropicMessages(messages, model, isOAuthToken, options) {
|
|
122
|
-
const params = [];
|
|
123
|
-
const imageBudget = createAnthropicInlineImageBudget();
|
|
124
|
-
const allowReasoningContentReplay = options.allowReasoningContentReplay === true;
|
|
125
|
-
const replayThinkingEnabled = options.replayThinkingEnabled !== false;
|
|
126
|
-
const transformedMessages = transformTransportMessages(messages, model, normalizeAnthropicToolCallId);
|
|
127
|
-
const activeToolTurnAssistantIndex = replayThinkingEnabled ? -1 : findActiveAnthropicToolTurnAssistantIndex(transformedMessages);
|
|
128
|
-
for (let i = 0; i < transformedMessages.length; i += 1) {
|
|
129
|
-
const msg = transformedMessages[i];
|
|
130
|
-
if (!msg) continue;
|
|
131
|
-
if (msg.role === "user") {
|
|
132
|
-
if (typeof msg.content === "string") {
|
|
133
|
-
if (msg.content.trim().length > 0) {
|
|
134
|
-
const userParam = {
|
|
135
|
-
role: "user",
|
|
136
|
-
content: sanitizeTransportPayloadText(msg.content)
|
|
137
|
-
};
|
|
138
|
-
params.push(userParam);
|
|
139
|
-
}
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
const blocks = (model.input.includes("image") ? await normalizeAnthropicInlineContent(msg.content, imageBudget) : msg.content.map((item) => item.type === "image" ? {
|
|
143
|
-
type: "text",
|
|
144
|
-
text: NON_VISION_USER_IMAGE_PLACEHOLDER
|
|
145
|
-
} : item)).map((item) => item.type === "text" ? {
|
|
146
|
-
type: "text",
|
|
147
|
-
text: sanitizeTransportPayloadText(item.text)
|
|
148
|
-
} : {
|
|
149
|
-
type: "image",
|
|
150
|
-
source: {
|
|
151
|
-
type: "base64",
|
|
152
|
-
media_type: resolveAnthropicImageMediaType(item.mimeType),
|
|
153
|
-
data: item.data
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
let filteredBlocks = model.input.includes("image") ? blocks : blocks.filter((block) => block.type !== "image");
|
|
157
|
-
filteredBlocks = filteredBlocks.filter((block) => block.type !== "text" || block.text.trim().length > 0);
|
|
158
|
-
if (filteredBlocks.length === 0) continue;
|
|
159
|
-
const userParam = {
|
|
160
|
-
role: "user",
|
|
161
|
-
content: filteredBlocks
|
|
162
|
-
};
|
|
163
|
-
params.push(userParam);
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
if (msg.role === "assistant") {
|
|
167
|
-
const blocks = i === 0 && options.compaction ? [options.compaction] : [];
|
|
168
|
-
const reasoningContent = [];
|
|
169
|
-
let omittedThinking = false;
|
|
170
|
-
for (const block of msg.content) {
|
|
171
|
-
if (block.type === "text") {
|
|
172
|
-
if (block.text.trim().length > 0) blocks.push({
|
|
173
|
-
type: "text",
|
|
174
|
-
text: sanitizeTransportPayloadText(block.text)
|
|
175
|
-
});
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
if (block.type === "thinking") {
|
|
179
|
-
const thinkingSignature = block.thinkingSignature?.trim();
|
|
180
|
-
const isReasoningContent = thinkingSignature === "reasoning_content";
|
|
181
|
-
if (!replayThinkingEnabled && i !== activeToolTurnAssistantIndex && !isReasoningContent) {
|
|
182
|
-
omittedThinking = true;
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
if (block.redacted) {
|
|
186
|
-
blocks.push({
|
|
187
|
-
type: "redacted_thinking",
|
|
188
|
-
data: block.thinkingSignature
|
|
189
|
-
});
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
const hasNativeThinkingSignature = Boolean(thinkingSignature) && !isReasoningContent;
|
|
193
|
-
if (block.thinking.trim().length === 0 && !hasNativeThinkingSignature) continue;
|
|
194
|
-
if (!thinkingSignature) blocks.push({
|
|
195
|
-
type: "text",
|
|
196
|
-
text: sanitizeTransportPayloadText(block.thinking)
|
|
197
|
-
});
|
|
198
|
-
else {
|
|
199
|
-
const thinking = thinkingSignature === "reasoning_content" ? sanitizeTransportPayloadText(block.thinking) : block.thinking;
|
|
200
|
-
if (thinkingSignature === "reasoning_content") {
|
|
201
|
-
if (allowReasoningContentReplay) {
|
|
202
|
-
blocks.push({
|
|
203
|
-
type: "thinking",
|
|
204
|
-
thinking,
|
|
205
|
-
signature: thinkingSignature
|
|
206
|
-
});
|
|
207
|
-
reasoningContent.push(thinking);
|
|
208
|
-
}
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
blocks.push({
|
|
212
|
-
type: "thinking",
|
|
213
|
-
thinking,
|
|
214
|
-
signature: thinkingSignature
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
if (block.type === "toolCall") blocks.push({
|
|
220
|
-
type: "tool_use",
|
|
221
|
-
id: block.id,
|
|
222
|
-
name: isOAuthToken ? toClaudeCodeToolName(block.name) : block.name,
|
|
223
|
-
input: coerceTransportToolCallArguments(block.arguments)
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
if (blocks.length === 0 && omittedThinking) blocks.push({
|
|
227
|
-
type: "text",
|
|
228
|
-
text: ANTHROPIC_OMITTED_REASONING_TEXT
|
|
229
|
-
});
|
|
230
|
-
if (blocks.length > 0) {
|
|
231
|
-
const assistantMsg = {
|
|
232
|
-
role: "assistant",
|
|
233
|
-
content: blocks
|
|
234
|
-
};
|
|
235
|
-
if (reasoningContent.length > 0) assistantMsg.reasoning_content = reasoningContent.join("\n");
|
|
236
|
-
else if (allowReasoningContentReplay) blocks.unshift({
|
|
237
|
-
type: "thinking",
|
|
238
|
-
thinking: "",
|
|
239
|
-
signature: "reasoning_content"
|
|
240
|
-
});
|
|
241
|
-
params.push(assistantMsg);
|
|
242
|
-
}
|
|
243
|
-
continue;
|
|
244
|
-
}
|
|
245
|
-
if (msg.role === "toolResult") {
|
|
246
|
-
const toolResult = msg;
|
|
247
|
-
const toolResults = [{
|
|
248
|
-
type: "tool_result",
|
|
249
|
-
tool_use_id: toolResult.toolCallId,
|
|
250
|
-
content: await convertContentBlocks(toolResult.content, model, imageBudget),
|
|
251
|
-
is_error: toolResult.isError
|
|
252
|
-
}];
|
|
253
|
-
let j = i + 1;
|
|
254
|
-
while (j < transformedMessages.length) {
|
|
255
|
-
const nextMsg = transformedMessages.at(j);
|
|
256
|
-
if (nextMsg?.role !== "toolResult") break;
|
|
257
|
-
toolResults.push({
|
|
258
|
-
type: "tool_result",
|
|
259
|
-
tool_use_id: nextMsg.toolCallId,
|
|
260
|
-
content: await convertContentBlocks(nextMsg.content, model, imageBudget),
|
|
261
|
-
is_error: nextMsg.isError
|
|
262
|
-
});
|
|
263
|
-
j += 1;
|
|
264
|
-
}
|
|
265
|
-
i = j - 1;
|
|
266
|
-
params.push({
|
|
267
|
-
role: "user",
|
|
268
|
-
content: toolResults
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return params;
|
|
273
|
-
}
|
|
274
84
|
function ensureNonEmptyAnthropicMessages(messages) {
|
|
275
85
|
return messages.length > 0 ? messages : [{
|
|
276
86
|
role: "user",
|
|
277
87
|
content: EMPTY_ANTHROPIC_MESSAGES_FALLBACK_TEXT
|
|
278
88
|
}];
|
|
279
89
|
}
|
|
280
|
-
function convertAnthropicTools(tools, isOAuthToken) {
|
|
281
|
-
const projection = projectAnthropicTools(tools ?? [], (name) => isOAuthToken ? toClaudeCodeToolName(name) : name);
|
|
282
|
-
const converted = [];
|
|
283
|
-
for (const tool of projection.tools) converted.push({
|
|
284
|
-
name: tool.wireName,
|
|
285
|
-
description: tool.description,
|
|
286
|
-
input_schema: tool.inputSchema
|
|
287
|
-
});
|
|
288
|
-
return {
|
|
289
|
-
projection,
|
|
290
|
-
tools: converted
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
function parseAnthropicToolCallArguments(inputJson) {
|
|
294
|
-
return coerceTransportToolCallArguments(parseJsonObjectPreservingUnsafeIntegers(inputJson) ?? parseStreamingJson(inputJson));
|
|
295
|
-
}
|
|
296
90
|
const DEFAULT_ANTHROPIC_BASE_URL = "https://api.anthropic.com";
|
|
297
91
|
/** Resolve the effective Anthropic API base URL from model or environment. */
|
|
298
92
|
function resolveAnthropicBaseUrl(baseUrl) {
|
|
@@ -415,7 +209,7 @@ function createAnthropicMessagesClient(params) {
|
|
|
415
209
|
} } };
|
|
416
210
|
}
|
|
417
211
|
function formatAnthropicMessagesHttpError(response, detail) {
|
|
418
|
-
const retryAfterSeconds =
|
|
212
|
+
const retryAfterSeconds = parseRetryAfterHeadersSeconds(response.headers);
|
|
419
213
|
const retryAfterSuffix = Number.isFinite(retryAfterSeconds) ? `; Retry-After: ${Math.ceil(retryAfterSeconds ?? 0)} seconds` : "";
|
|
420
214
|
return `HTTP ${response.status}: ${detail || "Anthropic Messages request failed"}${retryAfterSuffix}`;
|
|
421
215
|
}
|
|
@@ -434,6 +228,7 @@ async function readAnthropicMessagesErrorBodySnippet(response) {
|
|
|
434
228
|
}
|
|
435
229
|
function createAnthropicTransportClient(params) {
|
|
436
230
|
const { model, context, apiKey, options } = params;
|
|
231
|
+
const optionHeaders = resolveOpencodeSessionHeaders(model, options);
|
|
437
232
|
const needsInterleavedBeta = (options?.interleavedThinking ?? true) && !supportsClaudeAdaptiveThinking(model);
|
|
438
233
|
const fetch = isKimiAnthropicProvider(model.provider) && options?.thinkingEnabled === true ? buildGuardedModelFetch(model, void 0, { sanitizeSse: false }) : buildGuardedModelFetch(model);
|
|
439
234
|
if (model.provider === "github-copilot") {
|
|
@@ -447,7 +242,7 @@ function createAnthropicTransportClient(params) {
|
|
|
447
242
|
accept: "application/json",
|
|
448
243
|
"anthropic-dangerous-direct-browser-access": "true",
|
|
449
244
|
...betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}
|
|
450
|
-
}, model.headers, getAiTransportHost().buildCopilotDynamicHeaders(context.messages),
|
|
245
|
+
}, model.headers, getAiTransportHost().buildCopilotDynamicHeaders(context.messages), optionHeaders),
|
|
451
246
|
fetch
|
|
452
247
|
}),
|
|
453
248
|
isOAuthToken: false
|
|
@@ -464,7 +259,7 @@ function createAnthropicTransportClient(params) {
|
|
|
464
259
|
accept: "application/json",
|
|
465
260
|
"anthropic-dangerous-direct-browser-access": "true",
|
|
466
261
|
...betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}
|
|
467
|
-
}, omitFoundryBearerCredentialHeaders(model.headers),
|
|
262
|
+
}, omitFoundryBearerCredentialHeaders(model.headers), optionHeaders),
|
|
468
263
|
fetch
|
|
469
264
|
}),
|
|
470
265
|
isOAuthToken: false
|
|
@@ -485,7 +280,7 @@ function createAnthropicTransportClient(params) {
|
|
|
485
280
|
...betaHeader ? { "anthropic-beta": betaHeader } : {},
|
|
486
281
|
"user-agent": `claude-cli/${ANTHROPIC_CLAUDE_CODE_VERSION}`,
|
|
487
282
|
"x-app": "cli"
|
|
488
|
-
}, model.headers,
|
|
283
|
+
}, model.headers, optionHeaders),
|
|
489
284
|
fetch
|
|
490
285
|
}),
|
|
491
286
|
isOAuthToken: true
|
|
@@ -497,7 +292,7 @@ function createAnthropicTransportClient(params) {
|
|
|
497
292
|
accept: "application/json",
|
|
498
293
|
"anthropic-dangerous-direct-browser-access": "true",
|
|
499
294
|
...betaHeader ? { "anthropic-beta": betaHeader } : {}
|
|
500
|
-
}, model.headers,
|
|
295
|
+
}, model.headers, optionHeaders);
|
|
501
296
|
return {
|
|
502
297
|
client: createAnthropicMessagesClient({
|
|
503
298
|
apiKey,
|
|
@@ -510,27 +305,21 @@ function createAnthropicTransportClient(params) {
|
|
|
510
305
|
};
|
|
511
306
|
}
|
|
512
307
|
async function buildAnthropicParams(model, context, isOAuthToken, options) {
|
|
513
|
-
const
|
|
514
|
-
const replayThinkingEnabled = mandatoryAdaptiveThinking || options?.thinkingEnabled === true;
|
|
308
|
+
const replayThinkingEnabled = requiresClaudeAdaptiveThinking(model) || options?.thinkingEnabled === true;
|
|
515
309
|
const maxTokens = resolveAnthropicMessagesMaxTokens({
|
|
516
310
|
modelContextWindow: model.contextWindow,
|
|
517
311
|
modelMaxTokens: model.maxTokens,
|
|
518
312
|
requestedMaxTokens: options?.maxTokens
|
|
519
313
|
});
|
|
520
314
|
if (maxTokens === void 0) throw new Error(`Anthropic Messages transport requires a positive maxTokens value for ${model.provider}/${model.id}`);
|
|
521
|
-
const
|
|
522
|
-
provider: model.provider,
|
|
523
|
-
api: model.api,
|
|
524
|
-
baseUrl: model.baseUrl,
|
|
525
|
-
cacheRetention: options?.cacheRetention,
|
|
526
|
-
enableCacheControl: true
|
|
527
|
-
}, model);
|
|
315
|
+
const { cacheControl, supportsCacheControlOnTools } = resolveAnthropicCacheOptions(model, options?.cacheRetention);
|
|
528
316
|
const replayPlan = buildAnthropicReplayPlan(context.messages, model, {
|
|
529
317
|
enabled: !isOAuthToken && options?.anthropicServerCompaction === true,
|
|
530
318
|
authProfileId: options?.authProfileId,
|
|
531
319
|
sessionId: options?.sessionId
|
|
532
320
|
});
|
|
533
|
-
const messages = await convertAnthropicMessages(replayPlan.messages, model, isOAuthToken, {
|
|
321
|
+
const messages = await convertAnthropicMessages(transformTransportMessages(replayPlan.messages, model, normalizeAnthropicToolCallId), model, isOAuthToken, {
|
|
322
|
+
profile: "transport",
|
|
534
323
|
allowReasoningContentReplay: supportsReasoningContentReplay(model),
|
|
535
324
|
compaction: replayPlan.compaction,
|
|
536
325
|
replayThinkingEnabled
|
|
@@ -542,54 +331,18 @@ async function buildAnthropicParams(model, context, isOAuthToken, options) {
|
|
|
542
331
|
stream: true
|
|
543
332
|
};
|
|
544
333
|
if (!isOAuthToken && useAnthropicServerSideFallback(model)) params.fallbacks = ANTHROPIC_SERVER_SIDE_FALLBACKS;
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}] : []
|
|
558
|
-
];
|
|
559
|
-
else if (context.systemPrompt) params.system = [{
|
|
560
|
-
type: "text",
|
|
561
|
-
text: sanitizeTransportPayloadText(context.systemPrompt)
|
|
562
|
-
}];
|
|
563
|
-
if (options?.temperature !== void 0 && !options.thinkingEnabled && !supportsClaudeNativeXhighEffort(model)) params.temperature = options.temperature;
|
|
564
|
-
if (options?.stop !== void 0 && options.stop.length > 0) params.stop_sequences = options.stop;
|
|
565
|
-
let toolProjection;
|
|
566
|
-
if (context.tools) {
|
|
567
|
-
const convertedTools = convertAnthropicTools(context.tools, isOAuthToken);
|
|
568
|
-
toolProjection = convertedTools.projection;
|
|
569
|
-
if (convertedTools.tools.length > 0) params.tools = convertedTools.tools;
|
|
570
|
-
}
|
|
571
|
-
if (mandatoryAdaptiveThinking || model.reasoning || supportsClaudeAdaptiveThinking(model)) {
|
|
572
|
-
if (mandatoryAdaptiveThinking || options?.thinkingEnabled) {
|
|
573
|
-
if (supportsClaudeAdaptiveThinking(model)) {
|
|
574
|
-
params.thinking = {
|
|
575
|
-
type: "adaptive",
|
|
576
|
-
display: options?.thinkingDisplay ?? "summarized"
|
|
577
|
-
};
|
|
578
|
-
const effort = options?.effort ?? (mandatoryAdaptiveThinking ? "high" : void 0);
|
|
579
|
-
if (effort) params.output_config = { effort };
|
|
580
|
-
} else params.thinking = {
|
|
581
|
-
type: "enabled",
|
|
582
|
-
budget_tokens: options?.thinkingBudgetTokens ?? 1024
|
|
583
|
-
};
|
|
584
|
-
} else if (options?.thinkingEnabled === false) params.thinking = { type: "disabled" };
|
|
585
|
-
}
|
|
586
|
-
if (options?.metadata && typeof options.metadata.user_id === "string") params.metadata = { user_id: options.metadata.user_id };
|
|
587
|
-
if (options?.toolChoice) {
|
|
588
|
-
const normalizedToolChoice = normalizeAnthropicToolChoice(replayThinkingEnabled, options.toolChoice);
|
|
589
|
-
const projectedToolChoice = toolProjection ? reconcileAnthropicToolChoice(normalizedToolChoice, toolProjection) : normalizedToolChoice;
|
|
590
|
-
if (projectedToolChoice) params.tool_choice = projectedToolChoice;
|
|
591
|
-
}
|
|
592
|
-
applyAnthropicPayloadPolicyToParams(params, payloadPolicy, /* @__PURE__ */ new Set());
|
|
334
|
+
const system = buildAnthropicSystemBlocks(context.systemPrompt, isOAuthToken, cacheControl);
|
|
335
|
+
if (system) params.system = system;
|
|
336
|
+
const convertedTools = context.tools ? convertAnthropicTools(context.tools, isOAuthToken) : void 0;
|
|
337
|
+
const toolProjection = convertedTools?.projection;
|
|
338
|
+
Object.assign(params, buildAnthropicGenerationParams({
|
|
339
|
+
model,
|
|
340
|
+
options,
|
|
341
|
+
tools: convertedTools?.tools,
|
|
342
|
+
toolProjection,
|
|
343
|
+
profile: "transport"
|
|
344
|
+
}));
|
|
345
|
+
applyAnthropicRequestCacheControl(params, cacheControl, supportsCacheControlOnTools);
|
|
593
346
|
return {
|
|
594
347
|
params,
|
|
595
348
|
toolProjection,
|
|
@@ -657,22 +410,9 @@ function createAnthropicMessagesTransportStreamFn() {
|
|
|
657
410
|
const options = rawOptions;
|
|
658
411
|
const { eventStream, stream } = createWritableTransportEventStream();
|
|
659
412
|
(async () => {
|
|
660
|
-
const output =
|
|
661
|
-
role: "assistant",
|
|
662
|
-
content: [],
|
|
663
|
-
api: "anthropic-messages",
|
|
664
|
-
provider: model.provider,
|
|
665
|
-
model: model.id,
|
|
666
|
-
usage: createEmptyTransportUsage(),
|
|
667
|
-
stopReason: "stop",
|
|
668
|
-
timestamp: Date.now()
|
|
669
|
-
};
|
|
413
|
+
const output = createAssistantOutput(model, "anthropic-messages");
|
|
670
414
|
const refusalBuffer = usesClaudeStreamingRefusalContract(model) ? createDeferredEventBuffer(stream) : void 0;
|
|
671
|
-
const eventSink = refusalBuffer ?? stream;
|
|
672
|
-
let costModel = model;
|
|
673
|
-
let messageStartPromptUsage;
|
|
674
415
|
let usedCompactionReplay = false;
|
|
675
|
-
let inputTransformations;
|
|
676
416
|
try {
|
|
677
417
|
const apiKey = options?.apiKey ?? getEnvApiKey(model.provider) ?? "";
|
|
678
418
|
if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
|
|
@@ -710,432 +450,17 @@ function createAnthropicMessagesTransportStreamFn() {
|
|
|
710
450
|
const detail = await readAnthropicMessagesErrorBodySnippet(response);
|
|
711
451
|
throw new Error(formatAnthropicMessagesHttpError(response, detail));
|
|
712
452
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
const flushPendingTextEnds = () => {
|
|
725
|
-
for (const event of pendingTextEnds) eventSink.push(event);
|
|
726
|
-
pendingTextEnds.length = 0;
|
|
727
|
-
};
|
|
728
|
-
const eventIndexKey = (eventIndex) => typeof eventIndex === "number" ? eventIndex : -1;
|
|
729
|
-
const appendReasoningContentThinkingDelta = (eventIndex, rawText) => {
|
|
730
|
-
if (typeof rawText !== "string") return false;
|
|
731
|
-
const text = sanitizeTransportPayloadText(rawText);
|
|
732
|
-
if (text.length === 0) return false;
|
|
733
|
-
const key = eventIndexKey(eventIndex);
|
|
734
|
-
let contentIndex = reasoningContentThinkingBlocks.get(key);
|
|
735
|
-
let block = contentIndex === void 0 ? void 0 : output.content[contentIndex];
|
|
736
|
-
if (!block || block.type !== "thinking") {
|
|
737
|
-
block = {
|
|
738
|
-
type: "thinking",
|
|
739
|
-
thinking: "",
|
|
740
|
-
thinkingSignature: "reasoning_content"
|
|
741
|
-
};
|
|
742
|
-
output.content.push(block);
|
|
743
|
-
contentIndex = output.content.length - 1;
|
|
744
|
-
reasoningContentThinkingBlocks.set(key, contentIndex);
|
|
745
|
-
eventSink.push({
|
|
746
|
-
type: "thinking_start",
|
|
747
|
-
contentIndex,
|
|
748
|
-
partial: output
|
|
749
|
-
});
|
|
750
|
-
}
|
|
751
|
-
if (contentIndex === void 0) return false;
|
|
752
|
-
block.thinking += text;
|
|
753
|
-
block.thinkingSignature = "reasoning_content";
|
|
754
|
-
eventSink.push({
|
|
755
|
-
type: "thinking_delta",
|
|
756
|
-
contentIndex,
|
|
757
|
-
delta: text,
|
|
758
|
-
partial: output
|
|
759
|
-
});
|
|
760
|
-
return true;
|
|
761
|
-
};
|
|
762
|
-
const appendReasoningContentTextDelta = (eventIndex, rawText) => {
|
|
763
|
-
if (typeof rawText !== "string") return false;
|
|
764
|
-
const text = sanitizeTransportPayloadText(rawText);
|
|
765
|
-
if (text.length === 0) return false;
|
|
766
|
-
const key = eventIndexKey(eventIndex);
|
|
767
|
-
let contentIndex = reasoningContentTextBlocks.get(key);
|
|
768
|
-
let block = contentIndex === void 0 ? void 0 : output.content[contentIndex];
|
|
769
|
-
if (!block || block.type !== "text") {
|
|
770
|
-
block = {
|
|
771
|
-
type: "text",
|
|
772
|
-
text: ""
|
|
773
|
-
};
|
|
774
|
-
output.content.push(block);
|
|
775
|
-
contentIndex = output.content.length - 1;
|
|
776
|
-
reasoningContentTextBlocks.set(key, contentIndex);
|
|
777
|
-
eventSink.push({
|
|
778
|
-
type: "text_start",
|
|
779
|
-
contentIndex,
|
|
780
|
-
partial: output
|
|
781
|
-
});
|
|
782
|
-
}
|
|
783
|
-
if (contentIndex === void 0) return false;
|
|
784
|
-
block.text += text;
|
|
785
|
-
eventSink.push({
|
|
786
|
-
type: "text_delta",
|
|
787
|
-
contentIndex,
|
|
788
|
-
delta: text,
|
|
789
|
-
partial: output
|
|
790
|
-
});
|
|
791
|
-
return true;
|
|
792
|
-
};
|
|
793
|
-
const finishReasoningContentSidecars = (eventIndex) => {
|
|
794
|
-
const key = eventIndexKey(eventIndex);
|
|
795
|
-
const thinkingContentIndex = reasoningContentThinkingBlocks.get(key);
|
|
796
|
-
if (thinkingContentIndex !== void 0) {
|
|
797
|
-
reasoningContentThinkingBlocks.delete(key);
|
|
798
|
-
const block = output.content[thinkingContentIndex];
|
|
799
|
-
if (block?.type === "thinking") eventSink.push({
|
|
800
|
-
type: "thinking_end",
|
|
801
|
-
contentIndex: thinkingContentIndex,
|
|
802
|
-
content: block.thinking,
|
|
803
|
-
partial: output
|
|
804
|
-
});
|
|
805
|
-
}
|
|
806
|
-
const textContentIndex = reasoningContentTextBlocks.get(key);
|
|
807
|
-
if (textContentIndex === void 0) return;
|
|
808
|
-
reasoningContentTextBlocks.delete(key);
|
|
809
|
-
const block = output.content[textContentIndex];
|
|
810
|
-
if (block?.type === "text") eventSink.push({
|
|
811
|
-
type: "text_end",
|
|
812
|
-
contentIndex: textContentIndex,
|
|
813
|
-
content: block.text,
|
|
814
|
-
partial: output
|
|
815
|
-
});
|
|
816
|
-
};
|
|
817
|
-
for await (const event of anthropicStream) {
|
|
818
|
-
inputTransformations = readAnthropicInputTransformations(event) ?? inputTransformations;
|
|
819
|
-
notifyLlmRequestActivity(transportOptions.signal);
|
|
820
|
-
if (event.type === "error") {
|
|
821
|
-
const error = event.error;
|
|
822
|
-
throw new Error(error?.message || "Anthropic Messages stream failed");
|
|
823
|
-
}
|
|
824
|
-
if (event.type === "message_start") {
|
|
825
|
-
const message = event.message;
|
|
826
|
-
const usage = message?.usage ?? {};
|
|
827
|
-
output.responseId = typeof message?.id === "string" ? message.id : void 0;
|
|
828
|
-
output.responseModel = typeof message?.model === "string" ? message.model : void 0;
|
|
829
|
-
messageStartPromptUsage = applyAnthropicMessageStartUsage(output.usage, usage);
|
|
830
|
-
calculateCost(costModel, output.usage);
|
|
831
|
-
eventSink.push({
|
|
832
|
-
type: "start",
|
|
833
|
-
partial: output
|
|
834
|
-
});
|
|
835
|
-
continue;
|
|
836
|
-
}
|
|
837
|
-
if (event.type === "message_stop") {
|
|
838
|
-
sawMessageStop = true;
|
|
839
|
-
continue;
|
|
840
|
-
}
|
|
841
|
-
if (event.type === "content_block_start") {
|
|
842
|
-
const contentBlock = event.content_block;
|
|
843
|
-
const index = typeof event.index === "number" ? event.index : -1;
|
|
844
|
-
if (transportOptions.anthropicServerCompaction === true && compactionCapture.begin(index, contentBlock, output.content.length)) continue;
|
|
845
|
-
const fallbackBoundary = refusalBuffer ? readAnthropicFallbackBoundary(contentBlock) : null;
|
|
846
|
-
if (fallbackBoundary) {
|
|
847
|
-
refusalBuffer?.discard();
|
|
848
|
-
sealedToolCalls.length = 0;
|
|
849
|
-
pendingTextEnds.length = 0;
|
|
850
|
-
blockIndexes.clear();
|
|
851
|
-
pendingThinkingSignatures.clear();
|
|
852
|
-
applyAnthropicFallbackBoundary({
|
|
853
|
-
output,
|
|
854
|
-
boundary: fallbackBoundary,
|
|
855
|
-
provider: model.provider
|
|
856
|
-
});
|
|
857
|
-
costModel = {
|
|
858
|
-
...model,
|
|
859
|
-
cost: resolveAnthropicFallbackServingModelCost({
|
|
860
|
-
requestedModelId: model.id,
|
|
861
|
-
servingModelId: fallbackBoundary.toModel,
|
|
862
|
-
requestedCost: model.cost
|
|
863
|
-
})
|
|
864
|
-
};
|
|
865
|
-
calculateCost(costModel, output.usage);
|
|
866
|
-
eventSink.push({
|
|
867
|
-
type: "start",
|
|
868
|
-
partial: output
|
|
869
|
-
});
|
|
870
|
-
for (const [i, block] of output.content.entries()) {
|
|
871
|
-
if (block.type !== "text") continue;
|
|
872
|
-
delete block.index;
|
|
873
|
-
eventSink.push({
|
|
874
|
-
type: "text_start",
|
|
875
|
-
contentIndex: i,
|
|
876
|
-
partial: output
|
|
877
|
-
});
|
|
878
|
-
if (block.text) eventSink.push({
|
|
879
|
-
type: "text_delta",
|
|
880
|
-
contentIndex: i,
|
|
881
|
-
delta: block.text,
|
|
882
|
-
partial: output
|
|
883
|
-
});
|
|
884
|
-
pendingTextEnds.push({
|
|
885
|
-
type: "text_end",
|
|
886
|
-
contentIndex: i,
|
|
887
|
-
content: block.text,
|
|
888
|
-
partial: output
|
|
889
|
-
});
|
|
890
|
-
}
|
|
891
|
-
continue;
|
|
892
|
-
}
|
|
893
|
-
pendingThinkingSignatures.delete(index);
|
|
894
|
-
if (contentBlock?.type === "text") {
|
|
895
|
-
const text = typeof contentBlock.text === "string" ? sanitizeTransportPayloadText(contentBlock.text) : "";
|
|
896
|
-
const block = {
|
|
897
|
-
type: "text",
|
|
898
|
-
text,
|
|
899
|
-
index
|
|
900
|
-
};
|
|
901
|
-
output.content.push(block);
|
|
902
|
-
const contentIndex = output.content.length - 1;
|
|
903
|
-
blockIndexes.set(index, contentIndex);
|
|
904
|
-
eventSink.push({
|
|
905
|
-
type: "text_start",
|
|
906
|
-
contentIndex,
|
|
907
|
-
partial: output
|
|
908
|
-
});
|
|
909
|
-
if (text.length > 0) eventSink.push({
|
|
910
|
-
type: "text_delta",
|
|
911
|
-
contentIndex,
|
|
912
|
-
delta: text,
|
|
913
|
-
partial: output
|
|
914
|
-
});
|
|
915
|
-
continue;
|
|
916
|
-
}
|
|
917
|
-
if (contentBlock?.type === "thinking") {
|
|
918
|
-
const thinking = typeof contentBlock.thinking === "string" ? contentBlock.thinking : "";
|
|
919
|
-
const block = {
|
|
920
|
-
type: "thinking",
|
|
921
|
-
thinking,
|
|
922
|
-
thinkingSignature: typeof contentBlock.signature === "string" ? contentBlock.signature : "",
|
|
923
|
-
index
|
|
924
|
-
};
|
|
925
|
-
output.content.push(block);
|
|
926
|
-
const contentIndex = output.content.length - 1;
|
|
927
|
-
blockIndexes.set(index, contentIndex);
|
|
928
|
-
eventSink.push({
|
|
929
|
-
type: "thinking_start",
|
|
930
|
-
contentIndex,
|
|
931
|
-
partial: output
|
|
932
|
-
});
|
|
933
|
-
if (thinking.length > 0) eventSink.push({
|
|
934
|
-
type: "thinking_delta",
|
|
935
|
-
contentIndex,
|
|
936
|
-
delta: thinking,
|
|
937
|
-
partial: output
|
|
938
|
-
});
|
|
939
|
-
continue;
|
|
940
|
-
}
|
|
941
|
-
if (contentBlock?.type === "redacted_thinking") {
|
|
942
|
-
const block = {
|
|
943
|
-
type: "thinking",
|
|
944
|
-
thinking: "[Reasoning redacted]",
|
|
945
|
-
thinkingSignature: typeof contentBlock.data === "string" ? contentBlock.data : "",
|
|
946
|
-
redacted: true,
|
|
947
|
-
index
|
|
948
|
-
};
|
|
949
|
-
output.content.push(block);
|
|
950
|
-
blockIndexes.set(index, output.content.length - 1);
|
|
951
|
-
eventSink.push({
|
|
952
|
-
type: "thinking_start",
|
|
953
|
-
contentIndex: output.content.length - 1,
|
|
954
|
-
partial: output
|
|
955
|
-
});
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
if (contentBlock?.type === "tool_use") {
|
|
959
|
-
tagPendingCommentaryText(output.content);
|
|
960
|
-
flushPendingTextEnds();
|
|
961
|
-
const block = {
|
|
962
|
-
type: "toolCall",
|
|
963
|
-
id: typeof contentBlock.id === "string" ? contentBlock.id : "",
|
|
964
|
-
name: typeof contentBlock.name === "string" ? isOAuthToken ? resolveOriginalAnthropicToolName(contentBlock.name, toolProjection) : contentBlock.name : "",
|
|
965
|
-
arguments: contentBlock.input && typeof contentBlock.input === "object" ? contentBlock.input : {},
|
|
966
|
-
partialJson: "",
|
|
967
|
-
index
|
|
968
|
-
};
|
|
969
|
-
output.content.push(block);
|
|
970
|
-
blockIndexes.set(index, output.content.length - 1);
|
|
971
|
-
toolArgumentPreviewSchedules.set(block, createToolArgumentPreviewSchedule());
|
|
972
|
-
eventSink.push({
|
|
973
|
-
type: "toolcall_start",
|
|
974
|
-
contentIndex: output.content.length - 1,
|
|
975
|
-
partial: output
|
|
976
|
-
});
|
|
977
|
-
}
|
|
978
|
-
continue;
|
|
979
|
-
}
|
|
980
|
-
if (event.type === "content_block_delta") {
|
|
981
|
-
const delta = event.delta;
|
|
982
|
-
const eventIndex = typeof event.index === "number" ? event.index : void 0;
|
|
983
|
-
if (eventIndex !== void 0 && compactionCapture.delta(eventIndex, delta)) continue;
|
|
984
|
-
let index = eventIndex === void 0 ? void 0 : blockIndexes.get(eventIndex);
|
|
985
|
-
let block = index === void 0 ? void 0 : blocks[index];
|
|
986
|
-
if (allowReasoningContentReplay) {
|
|
987
|
-
const appendedThinking = appendReasoningContentThinkingDelta(event.index, delta?.reasoning_content);
|
|
988
|
-
const hasNativeAnthropicDelta = delta?.type === "text_delta" && typeof delta.text === "string" || delta?.type === "thinking_delta" && typeof delta.thinking === "string" || delta?.type === "input_json_delta" && typeof delta.partial_json === "string" || delta?.type === "signature_delta" && typeof delta.signature === "string";
|
|
989
|
-
let appendedContent = false;
|
|
990
|
-
if (!hasNativeAnthropicDelta && typeof delta?.content === "string" && delta.content.length > 0) {
|
|
991
|
-
const text = sanitizeTransportPayloadText(delta.content);
|
|
992
|
-
if (text.length > 0) {
|
|
993
|
-
if (block?.type === "text" && index !== void 0) {
|
|
994
|
-
block.text += text;
|
|
995
|
-
eventSink.push({
|
|
996
|
-
type: "text_delta",
|
|
997
|
-
contentIndex: index,
|
|
998
|
-
delta: text,
|
|
999
|
-
partial: output
|
|
1000
|
-
});
|
|
1001
|
-
appendedContent = true;
|
|
1002
|
-
} else appendedContent = appendReasoningContentTextDelta(event.index, text);
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
if ((appendedThinking || appendedContent) && !hasNativeAnthropicDelta) continue;
|
|
1006
|
-
}
|
|
1007
|
-
if (!block && delta?.type === "text_delta" && typeof delta.text === "string") {
|
|
1008
|
-
block = {
|
|
1009
|
-
type: "text",
|
|
1010
|
-
text: "",
|
|
1011
|
-
index: typeof event.index === "number" ? event.index : blocks.length
|
|
1012
|
-
};
|
|
1013
|
-
output.content.push(block);
|
|
1014
|
-
index = output.content.length - 1;
|
|
1015
|
-
if (typeof event.index === "number") blockIndexes.set(event.index, index);
|
|
1016
|
-
eventSink.push({
|
|
1017
|
-
type: "text_start",
|
|
1018
|
-
contentIndex: index,
|
|
1019
|
-
partial: output
|
|
1020
|
-
});
|
|
1021
|
-
}
|
|
1022
|
-
if (index === void 0) continue;
|
|
1023
|
-
if (block?.type === "text" && delta?.type === "text_delta" && typeof delta.text === "string") {
|
|
1024
|
-
block.text += delta.text;
|
|
1025
|
-
eventSink.push({
|
|
1026
|
-
type: "text_delta",
|
|
1027
|
-
contentIndex: index,
|
|
1028
|
-
delta: delta.text,
|
|
1029
|
-
partial: output
|
|
1030
|
-
});
|
|
1031
|
-
continue;
|
|
1032
|
-
}
|
|
1033
|
-
if (block?.type === "thinking" && delta?.type === "thinking_delta" && typeof delta.thinking === "string") {
|
|
1034
|
-
block.thinking += delta.thinking;
|
|
1035
|
-
eventSink.push({
|
|
1036
|
-
type: "thinking_delta",
|
|
1037
|
-
contentIndex: index,
|
|
1038
|
-
delta: delta.thinking,
|
|
1039
|
-
partial: output
|
|
1040
|
-
});
|
|
1041
|
-
continue;
|
|
1042
|
-
}
|
|
1043
|
-
if (block?.type === "toolCall" && delta?.type === "input_json_delta" && typeof delta.partial_json === "string") {
|
|
1044
|
-
const partialJson = `${block.partialJson ?? ""}${delta.partial_json}`;
|
|
1045
|
-
block.partialJson = partialJson;
|
|
1046
|
-
if (toolArgumentPreviewSchedules.get(block)?.(partialJson.length)) block.arguments = parseAnthropicToolCallArguments(partialJson);
|
|
1047
|
-
eventSink.push({
|
|
1048
|
-
type: "toolcall_delta",
|
|
1049
|
-
contentIndex: index,
|
|
1050
|
-
delta: delta.partial_json,
|
|
1051
|
-
partial: output
|
|
1052
|
-
});
|
|
1053
|
-
continue;
|
|
1054
|
-
}
|
|
1055
|
-
if (block?.type === "thinking" && delta?.type === "signature_delta" && typeof delta.signature === "string") {
|
|
1056
|
-
const signatureIndex = eventIndexKey(event.index);
|
|
1057
|
-
const pendingSignature = pendingThinkingSignatures.get(signatureIndex);
|
|
1058
|
-
if (pendingSignature === void 0) {
|
|
1059
|
-
block.thinkingSignature = "";
|
|
1060
|
-
pendingThinkingSignatures.set(signatureIndex, delta.signature);
|
|
1061
|
-
} else pendingThinkingSignatures.set(signatureIndex, pendingSignature + delta.signature);
|
|
1062
|
-
}
|
|
1063
|
-
continue;
|
|
1064
|
-
}
|
|
1065
|
-
if (event.type === "content_block_stop") {
|
|
1066
|
-
const eventIndex = typeof event.index === "number" ? event.index : void 0;
|
|
1067
|
-
if (eventIndex !== void 0 && compactionCapture.complete(eventIndex)) continue;
|
|
1068
|
-
const pendingSignature = eventIndex === void 0 ? void 0 : pendingThinkingSignatures.get(eventIndex);
|
|
1069
|
-
if (eventIndex !== void 0) pendingThinkingSignatures.delete(eventIndex);
|
|
1070
|
-
const index = eventIndex === void 0 ? void 0 : blockIndexes.get(eventIndex);
|
|
1071
|
-
const block = index === void 0 ? void 0 : blocks[index];
|
|
1072
|
-
if (eventIndex === void 0 || index === void 0 || !block) {
|
|
1073
|
-
finishReasoningContentSidecars(event.index);
|
|
1074
|
-
continue;
|
|
1075
|
-
}
|
|
1076
|
-
blockIndexes.delete(eventIndex);
|
|
1077
|
-
delete block.index;
|
|
1078
|
-
if (block.type === "text") {
|
|
1079
|
-
pendingTextEnds.push({
|
|
1080
|
-
type: "text_end",
|
|
1081
|
-
contentIndex: index,
|
|
1082
|
-
content: block.text,
|
|
1083
|
-
partial: output
|
|
1084
|
-
});
|
|
1085
|
-
finishReasoningContentSidecars(event.index);
|
|
1086
|
-
continue;
|
|
1087
|
-
}
|
|
1088
|
-
if (block.type === "thinking") {
|
|
1089
|
-
if (pendingSignature !== void 0) block.thinkingSignature = pendingSignature;
|
|
1090
|
-
eventSink.push({
|
|
1091
|
-
type: "thinking_end",
|
|
1092
|
-
contentIndex: index,
|
|
1093
|
-
content: block.thinking,
|
|
1094
|
-
partial: output
|
|
1095
|
-
});
|
|
1096
|
-
finishReasoningContentSidecars(event.index);
|
|
1097
|
-
continue;
|
|
1098
|
-
}
|
|
1099
|
-
if (block.type === "toolCall") {
|
|
1100
|
-
sealedToolCalls.push({
|
|
1101
|
-
block,
|
|
1102
|
-
contentIndex: index
|
|
1103
|
-
});
|
|
1104
|
-
finishReasoningContentSidecars(event.index);
|
|
1105
|
-
}
|
|
1106
|
-
continue;
|
|
1107
|
-
}
|
|
1108
|
-
if (event.type === "message_delta") {
|
|
1109
|
-
logAnthropicContextEdits(event);
|
|
1110
|
-
const delta = event.delta;
|
|
1111
|
-
const usage = event.usage;
|
|
1112
|
-
if (delta?.stop_reason) {
|
|
1113
|
-
if (delta.stop_reason === "refusal") applyAnthropicRefusal(output, delta.stop_details, model.provider);
|
|
1114
|
-
else output.stopReason = mapAnthropicStopReason(delta.stop_reason);
|
|
1115
|
-
}
|
|
1116
|
-
applyAnthropicMessageDeltaUsage(output.usage, usage, messageStartPromptUsage);
|
|
1117
|
-
calculateCost(costModel, output.usage);
|
|
1118
|
-
if (output.stopReason === "toolUse" || output.content.some((block) => block.type === "toolCall")) tagPendingCommentaryText(output.content);
|
|
1119
|
-
flushPendingTextEnds();
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
if (isDirectAnthropicModel(model) && !sawMessageStop) throw new Error("Anthropic stream ended before message_stop");
|
|
1123
|
-
if (transportOptions.signal?.aborted) throw transportAbortError(transportOptions.signal);
|
|
1124
|
-
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
1125
|
-
if ([...blockIndexes.values()].some((index) => blocks[index]?.type === "toolCall")) throw new Error("Provider completed stream with an incomplete tool call");
|
|
1126
|
-
finalizeTerminalToolCallArguments(sealedToolCalls.map(({ block }) => block), (block) => block.partialJson && block.partialJson.length > 0 ? block.partialJson : block.arguments);
|
|
1127
|
-
for (const sealed of sealedToolCalls) {
|
|
1128
|
-
delete sealed.block.partialJson;
|
|
1129
|
-
eventSink.push({
|
|
1130
|
-
type: "toolcall_end",
|
|
1131
|
-
contentIndex: sealed.contentIndex,
|
|
1132
|
-
toolCall: sealed.block,
|
|
1133
|
-
partial: output
|
|
1134
|
-
});
|
|
1135
|
-
}
|
|
1136
|
-
refusalBuffer?.flush();
|
|
1137
|
-
if (output.stopReason === "toolUse" || output.content.some((block) => block.type === "toolCall")) tagPendingCommentaryText(output.content);
|
|
1138
|
-
flushPendingTextEnds();
|
|
453
|
+
await consumeAnthropicStream({
|
|
454
|
+
events: anthropicStream,
|
|
455
|
+
model,
|
|
456
|
+
options: transportOptions,
|
|
457
|
+
output,
|
|
458
|
+
stream,
|
|
459
|
+
refusalBuffer,
|
|
460
|
+
isOAuthToken,
|
|
461
|
+
toolProjection,
|
|
462
|
+
profile: "transport"
|
|
463
|
+
});
|
|
1139
464
|
finalizeTransportStream({
|
|
1140
465
|
stream,
|
|
1141
466
|
output
|
|
@@ -1155,71 +480,12 @@ function createAnthropicMessagesTransportStreamFn() {
|
|
|
1155
480
|
for (const block of output.content) delete block.index;
|
|
1156
481
|
}
|
|
1157
482
|
});
|
|
1158
|
-
} finally {
|
|
1159
|
-
logAnthropicThinkingDrops(inputTransformations);
|
|
1160
483
|
}
|
|
1161
484
|
})();
|
|
1162
485
|
return eventStream;
|
|
1163
486
|
};
|
|
1164
487
|
}
|
|
1165
488
|
//#endregion
|
|
1166
|
-
//#region packages/ai/src/transports/model-max-tokens-params.ts
|
|
1167
|
-
/**
|
|
1168
|
-
* Max-token parameter normalization across provider/native naming variants.
|
|
1169
|
-
* Callers canonicalize aliases before dispatch so payloads cannot carry
|
|
1170
|
-
* conflicting limits.
|
|
1171
|
-
*/
|
|
1172
|
-
const MAX_TOKENS_PARAM_KEYS = [
|
|
1173
|
-
"maxTokens",
|
|
1174
|
-
"max_completion_tokens",
|
|
1175
|
-
"max_tokens"
|
|
1176
|
-
];
|
|
1177
|
-
/** Resolve the first supported max-token parameter present in a params object. */
|
|
1178
|
-
function resolveMaxTokensParam(params) {
|
|
1179
|
-
if (!params) return;
|
|
1180
|
-
for (const key of MAX_TOKENS_PARAM_KEYS) {
|
|
1181
|
-
const resolved = asNonNegativeFiniteNumber(params[key]);
|
|
1182
|
-
if (resolved !== void 0) return resolved;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
/**
|
|
1186
|
-
* Canonicalize merged params to `maxTokens`, preserving source precedence from
|
|
1187
|
-
* left to right across the provided source objects.
|
|
1188
|
-
*/
|
|
1189
|
-
function canonicalizeMaxTokensParam(params) {
|
|
1190
|
-
let resolved;
|
|
1191
|
-
for (const source of params.sources) {
|
|
1192
|
-
const sourceValue = resolveMaxTokensParam(source);
|
|
1193
|
-
if (sourceValue !== void 0) resolved = sourceValue;
|
|
1194
|
-
}
|
|
1195
|
-
if (resolved === void 0) return;
|
|
1196
|
-
for (const key of MAX_TOKENS_PARAM_KEYS) delete params.merged[key];
|
|
1197
|
-
params.merged.maxTokens = resolved;
|
|
1198
|
-
}
|
|
1199
|
-
//#endregion
|
|
1200
|
-
//#region packages/ai/src/transports/model-transport-url.ts
|
|
1201
|
-
/**
|
|
1202
|
-
* Debug formatting helpers for model transport endpoints.
|
|
1203
|
-
* Keeps logs useful without exposing credentials, request params, or fragments.
|
|
1204
|
-
*/
|
|
1205
|
-
/** Return a sanitized URL suitable for logs and diagnostics. */
|
|
1206
|
-
function formatModelTransportDebugUrl(rawUrl) {
|
|
1207
|
-
try {
|
|
1208
|
-
const parsed = new URL(rawUrl);
|
|
1209
|
-
parsed.username = "";
|
|
1210
|
-
parsed.password = "";
|
|
1211
|
-
parsed.search = "";
|
|
1212
|
-
parsed.hash = "";
|
|
1213
|
-
return parsed.toString();
|
|
1214
|
-
} catch {
|
|
1215
|
-
return "<invalid-url>";
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
/** Format a configured base URL for debug output, or the implicit default. */
|
|
1219
|
-
function formatModelTransportDebugBaseUrl(rawUrl) {
|
|
1220
|
-
return rawUrl ? formatModelTransportDebugUrl(rawUrl) : "default";
|
|
1221
|
-
}
|
|
1222
|
-
//#endregion
|
|
1223
489
|
//#region packages/ai/src/transports/openai-compatible-conversation-turn.ts
|
|
1224
490
|
/**
|
|
1225
491
|
* OpenAI-compatible conversation turn detector.
|
|
@@ -1256,450 +522,6 @@ function hasOpenAICompatibleConversationTurn(messages) {
|
|
|
1256
522
|
});
|
|
1257
523
|
}
|
|
1258
524
|
//#endregion
|
|
1259
|
-
//#region packages/ai/src/transports/openai-completions-string-content.ts
|
|
1260
|
-
/**
|
|
1261
|
-
* OpenAI Chat Completions compatibility helpers. Some providers only accept
|
|
1262
|
-
* role/content messages with plain string content instead of text block arrays.
|
|
1263
|
-
*/
|
|
1264
|
-
function flattenStringOnlyCompletionContent(content) {
|
|
1265
|
-
if (!Array.isArray(content)) return content;
|
|
1266
|
-
const textParts = [];
|
|
1267
|
-
for (const item of content) {
|
|
1268
|
-
if (!item || typeof item !== "object" || item.type !== "text" || typeof item.text !== "string") return content;
|
|
1269
|
-
textParts.push(item.text);
|
|
1270
|
-
}
|
|
1271
|
-
return textParts.join("\n");
|
|
1272
|
-
}
|
|
1273
|
-
/** Flatten string-only text block content arrays into newline-joined strings. */
|
|
1274
|
-
function flattenCompletionMessagesToStringContent(messages) {
|
|
1275
|
-
return messages.map((message) => {
|
|
1276
|
-
if (!message || typeof message !== "object") return message;
|
|
1277
|
-
const content = message.content;
|
|
1278
|
-
const flattenedContent = flattenStringOnlyCompletionContent(content);
|
|
1279
|
-
if (flattenedContent === content) return message;
|
|
1280
|
-
return {
|
|
1281
|
-
...message,
|
|
1282
|
-
content: flattenedContent
|
|
1283
|
-
};
|
|
1284
|
-
});
|
|
1285
|
-
}
|
|
1286
|
-
/** Strip completion messages to role/content fields for strict providers. */
|
|
1287
|
-
function stripCompletionMessagesToRoleContent(messages) {
|
|
1288
|
-
return messages.map((message) => {
|
|
1289
|
-
if (!message || typeof message !== "object" || Array.isArray(message)) return message;
|
|
1290
|
-
const record = message;
|
|
1291
|
-
const stripped = {};
|
|
1292
|
-
if (Object.hasOwn(record, "role")) stripped.role = record.role;
|
|
1293
|
-
if (Object.hasOwn(record, "content")) stripped.content = record.content;
|
|
1294
|
-
return stripped;
|
|
1295
|
-
});
|
|
1296
|
-
}
|
|
1297
|
-
//#endregion
|
|
1298
|
-
//#region packages/ai/src/transports/openai-completions-host.ts
|
|
1299
|
-
/**
|
|
1300
|
-
* Chat Completions accepts Azure AI Foundry hosts in addition to traditional
|
|
1301
|
-
* Azure OpenAI hosts. Do not replace this with isTraditionalAzureOpenAIHost,
|
|
1302
|
-
* which intentionally excludes the .services.ai.azure.com Foundry suffix.
|
|
1303
|
-
*/
|
|
1304
|
-
function isAzureOpenAICompatibleHost(hostname) {
|
|
1305
|
-
return hostname.endsWith(".openai.azure.com") || hostname.endsWith(".services.ai.azure.com") || hostname.endsWith(".cognitiveservices.azure.com");
|
|
1306
|
-
}
|
|
1307
|
-
//#endregion
|
|
1308
|
-
//#region packages/ai/src/transports/openai-completions-replay.ts
|
|
1309
|
-
function isGoogleOpenAICompatModel(model) {
|
|
1310
|
-
const endpointClass = detectOpenAICompletionsCompat(model).capabilities.endpointClass;
|
|
1311
|
-
return model.provider === "google" || endpointClass === "google-generative-ai" || endpointClass === "google-vertex";
|
|
1312
|
-
}
|
|
1313
|
-
function requiresGoogleCompatToolCallThoughtSignature(model) {
|
|
1314
|
-
return isGoogleGemini3ProModel(model.id) || isGoogleGemini3FlashModel(model.id);
|
|
1315
|
-
}
|
|
1316
|
-
const GOOGLE_COMPAT_THOUGHT_SIGNATURE_ELLIPSIS_RE = /[\u2026]|\.\.\./;
|
|
1317
|
-
const GOOGLE_COMPAT_THOUGHT_SIGNATURE_BASE64_RE = /^[A-Za-z0-9+/=]+$/;
|
|
1318
|
-
function hasGoogleCompatThoughtSignatureTruncationFootprint(value) {
|
|
1319
|
-
return GOOGLE_COMPAT_THOUGHT_SIGNATURE_ELLIPSIS_RE.test(value) || GOOGLE_COMPAT_THOUGHT_SIGNATURE_BASE64_RE.test(value) && value.length % 4 !== 0;
|
|
1320
|
-
}
|
|
1321
|
-
function injectToolCallThoughtSignatures(outgoingMessages, context, model) {
|
|
1322
|
-
if (!isGoogleOpenAICompatModel(model)) return;
|
|
1323
|
-
const sigById = /* @__PURE__ */ new Map();
|
|
1324
|
-
const fallbackSig = requiresGoogleCompatToolCallThoughtSignature(model) ? GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP : void 0;
|
|
1325
|
-
for (const msg of context.messages ?? []) {
|
|
1326
|
-
if (msg.role !== "assistant") continue;
|
|
1327
|
-
const source = msg;
|
|
1328
|
-
if (!Array.isArray(source.content)) continue;
|
|
1329
|
-
for (const block of source.content) {
|
|
1330
|
-
if (block.type !== "toolCall") continue;
|
|
1331
|
-
const id = block.id;
|
|
1332
|
-
const sig = block.thoughtSignature;
|
|
1333
|
-
if (typeof id === "string" && typeof sig === "string" && sig.length > 0) {
|
|
1334
|
-
const isSameRoute = source.api === model.api && source.provider === model.provider && source.model === model.id;
|
|
1335
|
-
if (!isSameRoute && !fallbackSig) continue;
|
|
1336
|
-
sigById.set(id, isSameRoute ? sig : fallbackSig ?? sig);
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
if (sigById.size === 0 && !fallbackSig) return;
|
|
1341
|
-
for (const message of outgoingMessages) {
|
|
1342
|
-
const toolCalls = message.tool_calls;
|
|
1343
|
-
if (!Array.isArray(toolCalls)) continue;
|
|
1344
|
-
for (const toolCall of toolCalls) {
|
|
1345
|
-
const id = toolCall.id;
|
|
1346
|
-
if (typeof id !== "string") continue;
|
|
1347
|
-
let sig = sigById.get(id) ?? fallbackSig;
|
|
1348
|
-
if (typeof sig === "string" && sig.length > 0) {
|
|
1349
|
-
if (hasGoogleCompatThoughtSignatureTruncationFootprint(sig.trim())) sig = fallbackSig;
|
|
1350
|
-
}
|
|
1351
|
-
if (typeof sig !== "string" || sig.length === 0) continue;
|
|
1352
|
-
const extra = toolCall.extra_content && typeof toolCall.extra_content === "object" ? toolCall.extra_content : {};
|
|
1353
|
-
toolCall.extra_content = extra;
|
|
1354
|
-
const google = extra.google && typeof extra.google === "object" ? extra.google : {};
|
|
1355
|
-
extra.google = google;
|
|
1356
|
-
google.thought_signature = sig;
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
const COMPLETIONS_REASONING_REPLAY_FIELDS = [
|
|
1361
|
-
"reasoning_details",
|
|
1362
|
-
"reasoning_content",
|
|
1363
|
-
"reasoning",
|
|
1364
|
-
"reasoning_text"
|
|
1365
|
-
];
|
|
1366
|
-
function stripCompletionsReasoningReplayFields(record) {
|
|
1367
|
-
for (const field of COMPLETIONS_REASONING_REPLAY_FIELDS) if (field in record) delete record[field];
|
|
1368
|
-
}
|
|
1369
|
-
function sanitizeOpenRouterReasoningReplayFields(record) {
|
|
1370
|
-
const reasoningDetails = record.reasoning_details;
|
|
1371
|
-
if (typeof reasoningDetails === "string") {
|
|
1372
|
-
if (reasoningDetails.length > 0 && typeof record.reasoning !== "string") record.reasoning = reasoningDetails;
|
|
1373
|
-
delete record.reasoning_details;
|
|
1374
|
-
} else if (reasoningDetails !== void 0 && !Array.isArray(reasoningDetails)) delete record.reasoning_details;
|
|
1375
|
-
if ("reasoning" in record && (typeof record.reasoning !== "string" || record.reasoning === "")) delete record.reasoning;
|
|
1376
|
-
if ("reasoning_content" in record && (typeof record.reasoning_content !== "string" || record.reasoning_content === "")) delete record.reasoning_content;
|
|
1377
|
-
const reasoningText = record.reasoning_text;
|
|
1378
|
-
if (typeof reasoningText === "string" && reasoningText.length > 0 && typeof record.reasoning !== "string" && typeof record.reasoning_content !== "string") record.reasoning = reasoningText;
|
|
1379
|
-
if ("reasoning_text" in record) delete record.reasoning_text;
|
|
1380
|
-
}
|
|
1381
|
-
function sanitizeReasoningContentReplayFields(record) {
|
|
1382
|
-
if ("reasoning_content" in record && typeof record.reasoning_content !== "string") delete record.reasoning_content;
|
|
1383
|
-
delete record.reasoning_details;
|
|
1384
|
-
delete record.reasoning;
|
|
1385
|
-
delete record.reasoning_text;
|
|
1386
|
-
}
|
|
1387
|
-
const REASONING_CONTENT_REPLAY_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
1388
|
-
"deepseek-v4-flash",
|
|
1389
|
-
"deepseek-v4-pro",
|
|
1390
|
-
"kimi-for-coding",
|
|
1391
|
-
"kimi-k2.5",
|
|
1392
|
-
"kimi-k2.6",
|
|
1393
|
-
"kimi-k2.7-code",
|
|
1394
|
-
"kimi-k2.7-code-highspeed",
|
|
1395
|
-
"kimi-k3",
|
|
1396
|
-
"kimi-k2-thinking",
|
|
1397
|
-
"kimi-k2-thinking-turbo",
|
|
1398
|
-
"mimo-v2-pro",
|
|
1399
|
-
"mimo-v2-omni",
|
|
1400
|
-
"mimo-v2.5",
|
|
1401
|
-
"mimo-v2.5-pro",
|
|
1402
|
-
"mimo-v2.6-pro"
|
|
1403
|
-
]);
|
|
1404
|
-
const REASONING_CONTENT_REPLAY_TIER_SUFFIXES = [
|
|
1405
|
-
"-free",
|
|
1406
|
-
"-paid",
|
|
1407
|
-
"-trial"
|
|
1408
|
-
];
|
|
1409
|
-
function stripReasoningContentReplayTierSuffix(modelId) {
|
|
1410
|
-
for (const suffix of REASONING_CONTENT_REPLAY_TIER_SUFFIXES) if (modelId.length > suffix.length && modelId.endsWith(suffix)) return modelId.slice(0, -suffix.length);
|
|
1411
|
-
return modelId;
|
|
1412
|
-
}
|
|
1413
|
-
function getReasoningContentReplayModelIdCandidates(modelId) {
|
|
1414
|
-
if (typeof modelId !== "string") return [];
|
|
1415
|
-
const normalized = modelId.trim().toLowerCase();
|
|
1416
|
-
if (!normalized) return [];
|
|
1417
|
-
const parts = normalized.split("/").filter(Boolean);
|
|
1418
|
-
const finalPart = parts[parts.length - 1] ?? normalized;
|
|
1419
|
-
const candidates = [finalPart];
|
|
1420
|
-
const colonParts = finalPart.split(":").filter(Boolean);
|
|
1421
|
-
if (colonParts.length > 1) candidates.push(colonParts[0] ?? "", colonParts[colonParts.length - 1] ?? "");
|
|
1422
|
-
const baseCount = candidates.length;
|
|
1423
|
-
for (let index = 0; index < baseCount; index += 1) {
|
|
1424
|
-
const candidate = candidates[index];
|
|
1425
|
-
if (typeof candidate !== "string") continue;
|
|
1426
|
-
const stripped = stripReasoningContentReplayTierSuffix(candidate);
|
|
1427
|
-
if (stripped !== candidate) candidates.push(stripped);
|
|
1428
|
-
}
|
|
1429
|
-
return uniqueStrings(candidates.filter(Boolean));
|
|
1430
|
-
}
|
|
1431
|
-
function shouldPreserveReasoningContentReplay(model, compat) {
|
|
1432
|
-
if (compat.requiresReasoningContentOnAssistantMessages || compat.thinkingFormat === "deepseek" || compat.thinkingFormat === "zai" || shouldTrustReasoningContentReplayMetadata(model)) return true;
|
|
1433
|
-
return getReasoningContentReplayModelIdCandidates(model.id).some((modelId) => REASONING_CONTENT_REPLAY_MODEL_IDS.has(modelId));
|
|
1434
|
-
}
|
|
1435
|
-
function shouldPreserveOpenRouterReasoningReplay(model) {
|
|
1436
|
-
if (model.provider !== "openrouter") return true;
|
|
1437
|
-
const normalizedModelId = model.id.trim().toLowerCase();
|
|
1438
|
-
return !(normalizedModelId.startsWith("anthropic/") || normalizedModelId.startsWith("x-ai/"));
|
|
1439
|
-
}
|
|
1440
|
-
function shouldTrustReasoningContentReplayMetadata(model) {
|
|
1441
|
-
if (!model.reasoning) return false;
|
|
1442
|
-
if (model.provider.trim().toLowerCase() === "openai") return false;
|
|
1443
|
-
return shouldPreserveOpenRouterReasoningReplay(model);
|
|
1444
|
-
}
|
|
1445
|
-
function sanitizeCompletionsReasoningReplayFields(messages, options) {
|
|
1446
|
-
if (!Array.isArray(messages)) return;
|
|
1447
|
-
for (const msg of messages) {
|
|
1448
|
-
if (!msg || typeof msg !== "object") continue;
|
|
1449
|
-
const record = msg;
|
|
1450
|
-
if (record.role !== "assistant") continue;
|
|
1451
|
-
if (options.preserveOpenRouterReasoning) sanitizeOpenRouterReasoningReplayFields(record);
|
|
1452
|
-
else if (options.preserveReasoningContent) sanitizeReasoningContentReplayFields(record);
|
|
1453
|
-
else stripCompletionsReasoningReplayFields(record);
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
function applyCompletionsReplay(outgoingMessages, context, model, compat) {
|
|
1457
|
-
injectToolCallThoughtSignatures(outgoingMessages, context, model);
|
|
1458
|
-
sanitizeCompletionsReasoningReplayFields(outgoingMessages, {
|
|
1459
|
-
preserveOpenRouterReasoning: compat.thinkingFormat === "openrouter" && shouldPreserveOpenRouterReasoningReplay(model),
|
|
1460
|
-
preserveReasoningContent: shouldPreserveReasoningContentReplay(model, compat)
|
|
1461
|
-
});
|
|
1462
|
-
}
|
|
1463
|
-
//#endregion
|
|
1464
|
-
//#region packages/ai/src/transports/openai-completions-params.ts
|
|
1465
|
-
function isKnownOpenAICompletionsEndpoint(model) {
|
|
1466
|
-
if (!model.baseUrl.trim()) return true;
|
|
1467
|
-
const endpointClass = resolveProviderEndpoint(model).endpointClass;
|
|
1468
|
-
if (endpointClass === "openai-public" || endpointClass === "azure-openai") return true;
|
|
1469
|
-
try {
|
|
1470
|
-
return isAzureOpenAICompatibleHost(new URL(model.baseUrl).hostname.toLowerCase());
|
|
1471
|
-
} catch {
|
|
1472
|
-
return false;
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
|
-
function resolveOpenAICompletionsReasoningEffort(options) {
|
|
1476
|
-
return options?.reasoningEffort ?? options?.reasoning ?? "high";
|
|
1477
|
-
}
|
|
1478
|
-
function resolveOpenAICompletionsMaxTokens(model, options) {
|
|
1479
|
-
if (options?.maxTokens) return {
|
|
1480
|
-
maxTokens: options.maxTokens,
|
|
1481
|
-
clampToModelMaxTokens: true
|
|
1482
|
-
};
|
|
1483
|
-
const paramsMaxTokens = resolveMaxTokensParam(model.params);
|
|
1484
|
-
if (paramsMaxTokens) return {
|
|
1485
|
-
maxTokens: paramsMaxTokens,
|
|
1486
|
-
clampToModelMaxTokens: false
|
|
1487
|
-
};
|
|
1488
|
-
return {
|
|
1489
|
-
maxTokens: model.maxTokens,
|
|
1490
|
-
clampToModelMaxTokens: false
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
function resolveOpenAICompletionsModelMaxTokens(model) {
|
|
1494
|
-
return typeof model.maxTokens === "number" && Number.isFinite(model.maxTokens) && model.maxTokens > 0 ? Math.floor(model.maxTokens) : void 0;
|
|
1495
|
-
}
|
|
1496
|
-
const OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN = 1.25;
|
|
1497
|
-
const OPENAI_COMPLETIONS_IMAGE_CHAR_ESTIMATE = 8e3;
|
|
1498
|
-
function estimateOpenAICompletionsInputTokens(payload) {
|
|
1499
|
-
let adjustedChars = 0;
|
|
1500
|
-
adjustedChars += estimateOpenAICompletionsMessagesChars(payload.messages);
|
|
1501
|
-
if (Array.isArray(payload.tools) && payload.tools.length > 0) try {
|
|
1502
|
-
adjustedChars += estimateStringChars(JSON.stringify(payload.tools));
|
|
1503
|
-
} catch {
|
|
1504
|
-
adjustedChars += 1024;
|
|
1505
|
-
}
|
|
1506
|
-
if (payload.response_format !== void 0) try {
|
|
1507
|
-
adjustedChars += estimateStringChars(JSON.stringify(payload.response_format));
|
|
1508
|
-
} catch {
|
|
1509
|
-
adjustedChars += 256;
|
|
1510
|
-
}
|
|
1511
|
-
return Math.ceil(adjustedChars / 4 * OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN);
|
|
1512
|
-
}
|
|
1513
|
-
function estimateOpenAICompletionsMessagesChars(messages) {
|
|
1514
|
-
if (!Array.isArray(messages)) return 0;
|
|
1515
|
-
let adjustedChars = 0;
|
|
1516
|
-
for (const message of messages) {
|
|
1517
|
-
if (!message || typeof message !== "object") continue;
|
|
1518
|
-
const record = message;
|
|
1519
|
-
adjustedChars += estimateOpenAICompletionsContentChars(record.content);
|
|
1520
|
-
for (const field of COMPLETIONS_REASONING_REPLAY_FIELDS) adjustedChars += estimateOpenAICompletionsContentChars(record[field]);
|
|
1521
|
-
if (record.tool_calls !== void 0) try {
|
|
1522
|
-
adjustedChars += estimateStringChars(JSON.stringify(record.tool_calls));
|
|
1523
|
-
} catch {
|
|
1524
|
-
adjustedChars += 256;
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
return adjustedChars;
|
|
1528
|
-
}
|
|
1529
|
-
function estimateOpenAICompletionsContentChars(value) {
|
|
1530
|
-
if (typeof value === "string") return estimateStringChars(value);
|
|
1531
|
-
if (!Array.isArray(value)) return 0;
|
|
1532
|
-
let adjustedChars = 0;
|
|
1533
|
-
for (const block of value) {
|
|
1534
|
-
if (!block || typeof block !== "object") continue;
|
|
1535
|
-
const record = block;
|
|
1536
|
-
if (record.type === "image_url" || record.type === "input_image") {
|
|
1537
|
-
adjustedChars += OPENAI_COMPLETIONS_IMAGE_CHAR_ESTIMATE;
|
|
1538
|
-
continue;
|
|
1539
|
-
}
|
|
1540
|
-
const text = record.text;
|
|
1541
|
-
if (typeof text === "string") {
|
|
1542
|
-
adjustedChars += estimateStringChars(text);
|
|
1543
|
-
continue;
|
|
1544
|
-
}
|
|
1545
|
-
try {
|
|
1546
|
-
adjustedChars += estimateStringChars(JSON.stringify(block));
|
|
1547
|
-
} catch {
|
|
1548
|
-
adjustedChars += 256;
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
return adjustedChars;
|
|
1552
|
-
}
|
|
1553
|
-
function resolveOpenAICompletionsEffectiveContextTokens(model) {
|
|
1554
|
-
const contextTokens = model.contextTokens;
|
|
1555
|
-
if (typeof contextTokens === "number" && Number.isFinite(contextTokens) && contextTokens > 0) return contextTokens;
|
|
1556
|
-
return typeof model.contextWindow === "number" && Number.isFinite(model.contextWindow) && model.contextWindow > 0 ? model.contextWindow : void 0;
|
|
1557
|
-
}
|
|
1558
|
-
function isQwenOpenAICompletionsThinkingFormat(format) {
|
|
1559
|
-
return format === "qwen" || format === "qwen-chat-template";
|
|
1560
|
-
}
|
|
1561
|
-
function setQwenChatTemplateThinking(params, enabled) {
|
|
1562
|
-
const existing = params.chat_template_kwargs;
|
|
1563
|
-
params.chat_template_kwargs = existing && typeof existing === "object" && !Array.isArray(existing) ? {
|
|
1564
|
-
...existing,
|
|
1565
|
-
enable_thinking: enabled
|
|
1566
|
-
} : { enable_thinking: enabled };
|
|
1567
|
-
}
|
|
1568
|
-
function applyQwenOpenAICompletionsThinkingParams(params) {
|
|
1569
|
-
if (!params.modelReasoning || !isQwenOpenAICompletionsThinkingFormat(params.compatThinkingFormat)) return false;
|
|
1570
|
-
const enabled = isOpenAICompletionsThinkingEnabled(params.requestedEffort);
|
|
1571
|
-
if (params.compatThinkingFormat === "qwen-chat-template") setQwenChatTemplateThinking(params.payload, enabled);
|
|
1572
|
-
else params.payload.enable_thinking = enabled;
|
|
1573
|
-
return true;
|
|
1574
|
-
}
|
|
1575
|
-
function applyTogetherOpenAICompletionsThinkingParams(params) {
|
|
1576
|
-
if (!params.modelReasoning || params.compatThinkingFormat !== "together") return;
|
|
1577
|
-
params.payload.reasoning = { enabled: isOpenAICompletionsThinkingEnabled(params.requestedEffort) };
|
|
1578
|
-
}
|
|
1579
|
-
function convertTools(tools, compat, model) {
|
|
1580
|
-
const projection = projectOpenAITools(tools);
|
|
1581
|
-
const strict = resolveOpenAIStrictToolFlagWithDiagnostics(projection, resolveOpenAIStrictToolSetting(model, {
|
|
1582
|
-
transport: "stream",
|
|
1583
|
-
supportsStrictMode: compat?.supportsStrictMode
|
|
1584
|
-
}), {
|
|
1585
|
-
transport: "completions",
|
|
1586
|
-
model
|
|
1587
|
-
});
|
|
1588
|
-
return {
|
|
1589
|
-
projection,
|
|
1590
|
-
tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
|
|
1591
|
-
const functionTool = {
|
|
1592
|
-
name: tool.name,
|
|
1593
|
-
description: tool.description,
|
|
1594
|
-
parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, model.compat)
|
|
1595
|
-
};
|
|
1596
|
-
if (strict !== void 0) functionTool.strict = strict;
|
|
1597
|
-
return {
|
|
1598
|
-
type: "function",
|
|
1599
|
-
function: functionTool
|
|
1600
|
-
};
|
|
1601
|
-
})
|
|
1602
|
-
};
|
|
1603
|
-
}
|
|
1604
|
-
function buildOpenAICompletionsParams(model, context, options) {
|
|
1605
|
-
const compat = getCompat(model);
|
|
1606
|
-
const compatDetection = detectOpenAICompletionsCompat(model);
|
|
1607
|
-
const completionsContext = context.systemPrompt ? {
|
|
1608
|
-
...context,
|
|
1609
|
-
systemPrompt: stripSystemPromptCacheBoundary(context.systemPrompt)
|
|
1610
|
-
} : context;
|
|
1611
|
-
let messages = convertMessages(model, completionsContext, compat);
|
|
1612
|
-
applyCompletionsReplay(messages, context, model, compat);
|
|
1613
|
-
if (compat.strictMessageKeys) messages = stripCompletionMessagesToRoleContent(messages);
|
|
1614
|
-
const cacheRetention = resolveCacheRetention(options?.cacheRetention);
|
|
1615
|
-
const promptCacheKey = resolvePromptCacheKey(options, cacheRetention);
|
|
1616
|
-
const params = {
|
|
1617
|
-
model: model.id,
|
|
1618
|
-
messages: compat.requiresStringContent ? flattenCompletionMessagesToStringContent(messages) : messages,
|
|
1619
|
-
stream: true
|
|
1620
|
-
};
|
|
1621
|
-
if (compat.supportsUsageInStreaming) params.stream_options = { include_usage: true };
|
|
1622
|
-
if (compat.supportsStore) params.store = false;
|
|
1623
|
-
if (compat.supportsPromptCacheKey && promptCacheKey) {
|
|
1624
|
-
params.prompt_cache_key = promptCacheKey;
|
|
1625
|
-
if (cacheRetention === "long" && compat.supportsLongCacheRetention) params.prompt_cache_retention = "24h";
|
|
1626
|
-
}
|
|
1627
|
-
if (options?.temperature !== void 0) params.temperature = options.temperature;
|
|
1628
|
-
if (options?.topP !== void 0) params.top_p = options.topP;
|
|
1629
|
-
const responseFormat = resolveOpenAICompletionsResponseFormat(shouldOmitOllamaCompatResponseFormat({
|
|
1630
|
-
provider: model.provider,
|
|
1631
|
-
baseUrl: model.baseUrl,
|
|
1632
|
-
hasTools: () => Boolean(context.tools?.length)
|
|
1633
|
-
}) ? void 0 : options?.responseFormat, compat.supportsJsonSchemaResponseFormat);
|
|
1634
|
-
if (responseFormat !== void 0) params.response_format = responseFormat;
|
|
1635
|
-
if (options?.frequencyPenalty !== void 0) params.frequency_penalty = options.frequencyPenalty;
|
|
1636
|
-
if (options?.presencePenalty !== void 0) params.presence_penalty = options.presencePenalty;
|
|
1637
|
-
if (options?.seed !== void 0) params.seed = options.seed;
|
|
1638
|
-
if (options?.stop !== void 0 && options.stop.length > 0) params.stop = options.stop;
|
|
1639
|
-
if (supportsModelTools(model)) {
|
|
1640
|
-
if (context.tools) {
|
|
1641
|
-
const converted = convertTools(context.tools, compat, model);
|
|
1642
|
-
if (converted.tools.length > 0 || converted.projection.inputToolCount === 0 && converted.projection.diagnostics.length === 0) params.tools = converted.tools;
|
|
1643
|
-
else if (hasToolCallHistory(context.messages)) params.tools = [];
|
|
1644
|
-
if (options?.toolChoice) {
|
|
1645
|
-
const toolChoice = reconcileOpenAICompletionsToolChoice(options.toolChoice, converted.projection);
|
|
1646
|
-
if (toolChoice !== void 0) params.tool_choice = toolChoice;
|
|
1647
|
-
} else if (compatDetection.capabilities.usesExplicitProxyLikeEndpoint && Array.isArray(params.tools) && params.tools.length > 0) params.tool_choice = "auto";
|
|
1648
|
-
} else if (hasToolCallHistory(context.messages)) params.tools = [];
|
|
1649
|
-
if (compatDetection.capabilities.usesExplicitProxyLikeEndpoint && Array.isArray(params.tools) && params.tools.length === 0) {
|
|
1650
|
-
delete params.tools;
|
|
1651
|
-
delete params.tool_choice;
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
{
|
|
1655
|
-
const maxTokenBudget = resolveOpenAICompletionsMaxTokens(model, options);
|
|
1656
|
-
const effectiveMaxTokens = maxTokenBudget.maxTokens;
|
|
1657
|
-
const effectiveContextTokens = resolveOpenAICompletionsEffectiveContextTokens(model);
|
|
1658
|
-
let clampedMaxTokens = effectiveMaxTokens;
|
|
1659
|
-
const modelMaxTokens = resolveOpenAICompletionsModelMaxTokens(model);
|
|
1660
|
-
if (maxTokenBudget.clampToModelMaxTokens && clampedMaxTokens !== void 0 && modelMaxTokens !== void 0 && clampedMaxTokens > modelMaxTokens) {
|
|
1661
|
-
clampedMaxTokens = modelMaxTokens;
|
|
1662
|
-
emitModelTransportDebug(log, `[completions] clamp_max_tokens provider=${model.provider} api=${model.api} model=${model.id} requested=${effectiveMaxTokens} output=${clampedMaxTokens} modelMaxTokens=${modelMaxTokens}`);
|
|
1663
|
-
}
|
|
1664
|
-
if (compatDetection.capabilities.usesExplicitProxyLikeEndpoint && clampedMaxTokens !== void 0 && effectiveContextTokens !== void 0) {
|
|
1665
|
-
const estimatedInputTokens = estimateOpenAICompletionsInputTokens(params);
|
|
1666
|
-
const remainingBudget = Math.max(1, effectiveContextTokens - estimatedInputTokens - 1);
|
|
1667
|
-
if (clampedMaxTokens > remainingBudget) {
|
|
1668
|
-
clampedMaxTokens = remainingBudget;
|
|
1669
|
-
emitModelTransportDebug(log, `[completions] clamp_max_tokens provider=${model.provider} api=${model.api} model=${model.id} requested=${effectiveMaxTokens} output=${clampedMaxTokens} effectiveContext=${effectiveContextTokens} estimatedInput=${estimatedInputTokens}`);
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
if (clampedMaxTokens) {
|
|
1673
|
-
if (compat.maxTokensField === "max_tokens") params.max_tokens = clampedMaxTokens;
|
|
1674
|
-
else params.max_completion_tokens = clampedMaxTokens;
|
|
1675
|
-
}
|
|
1676
|
-
}
|
|
1677
|
-
const completionsReasoningEffort = resolveOpenAICompletionsReasoningEffort(options);
|
|
1678
|
-
const resolvedCompletionsReasoningEffort = completionsReasoningEffort ? resolveOpenAIReasoningEffortForModel({
|
|
1679
|
-
model,
|
|
1680
|
-
effort: completionsReasoningEffort,
|
|
1681
|
-
fallbackMap: compat.reasoningEffortMap
|
|
1682
|
-
}) : void 0;
|
|
1683
|
-
const omitChatCompletionsToolReasoningEffort = Array.isArray(params.tools) && params.tools.length > 0 && (isOpenAIGpt54MiniModel(model) || isOpenAIGpt55Model(model) && isKnownOpenAICompletionsEndpoint(model));
|
|
1684
|
-
const disableChatCompletionsToolReasoning = Array.isArray(params.tools) && params.tools.length > 0 && isOpenAIGpt56Model(model) && isKnownOpenAICompletionsEndpoint(model);
|
|
1685
|
-
const handledQwenThinkingFormat = applyQwenOpenAICompletionsThinkingParams({
|
|
1686
|
-
compatThinkingFormat: compat.thinkingFormat,
|
|
1687
|
-
modelReasoning: model.reasoning,
|
|
1688
|
-
payload: params,
|
|
1689
|
-
requestedEffort: completionsReasoningEffort
|
|
1690
|
-
});
|
|
1691
|
-
applyTogetherOpenAICompletionsThinkingParams({
|
|
1692
|
-
compatThinkingFormat: compat.thinkingFormat,
|
|
1693
|
-
modelReasoning: model.reasoning,
|
|
1694
|
-
payload: params,
|
|
1695
|
-
requestedEffort: completionsReasoningEffort
|
|
1696
|
-
});
|
|
1697
|
-
if (disableChatCompletionsToolReasoning) params.reasoning_effort = "none";
|
|
1698
|
-
else if (compat.thinkingFormat === "openrouter" && model.reasoning && resolvedCompletionsReasoningEffort) params.reasoning = { effort: resolvedCompletionsReasoningEffort };
|
|
1699
|
-
else if (resolvedCompletionsReasoningEffort && model.reasoning && compat.supportsReasoningEffort && !handledQwenThinkingFormat && !omitChatCompletionsToolReasoningEffort) params.reasoning_effort = resolvedCompletionsReasoningEffort;
|
|
1700
|
-
return params;
|
|
1701
|
-
}
|
|
1702
|
-
//#endregion
|
|
1703
525
|
//#region packages/ai/src/transports/openai-completions-transport.ts
|
|
1704
526
|
function assertOpenAICompletionsPayloadHasConversationTurn(params, model) {
|
|
1705
527
|
const messages = params.messages;
|
|
@@ -1831,7 +653,7 @@ function createOpenAICompletionsTransportStreamFn() {
|
|
|
1831
653
|
statusText: response.statusText
|
|
1832
654
|
});
|
|
1833
655
|
};
|
|
1834
|
-
const client = createOpenAICompletionsClient(model, context, apiKey, options
|
|
656
|
+
const client = createOpenAICompletionsClient(model, context, apiKey, resolveOpencodeSessionHeaders(model, options), { fetch: doneDetectingFetch });
|
|
1835
657
|
let params = buildOpenAICompletionsParams(model, context, options);
|
|
1836
658
|
const nextParams = await options?.onPayload?.(params, model);
|
|
1837
659
|
if (nextParams !== void 0) params = nextParams;
|
|
@@ -1895,26 +717,6 @@ const OPENAI_RESPONSES_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([
|
|
|
1895
717
|
"azure-openai-responses",
|
|
1896
718
|
"github-copilot"
|
|
1897
719
|
]);
|
|
1898
|
-
function convertResponsesTools(tools, model, options) {
|
|
1899
|
-
const projection = projectOpenAITools(tools);
|
|
1900
|
-
const strict = resolveOpenAIStrictToolFlagWithDiagnostics(projection, options?.strict, {
|
|
1901
|
-
transport: "responses",
|
|
1902
|
-
model
|
|
1903
|
-
});
|
|
1904
|
-
return {
|
|
1905
|
-
projection,
|
|
1906
|
-
tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
|
|
1907
|
-
const result = {
|
|
1908
|
-
type: "function",
|
|
1909
|
-
name: tool.name,
|
|
1910
|
-
description: tool.description,
|
|
1911
|
-
parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, model.compat)
|
|
1912
|
-
};
|
|
1913
|
-
if (strict !== void 0) result.strict = strict;
|
|
1914
|
-
return result;
|
|
1915
|
-
})
|
|
1916
|
-
};
|
|
1917
|
-
}
|
|
1918
720
|
function resolveOpenAIReasoningEffort(options) {
|
|
1919
721
|
return normalizeOpenAIReasoningEffort(options?.reasoningEffort ?? options?.reasoning ?? "high");
|
|
1920
722
|
}
|
|
@@ -1947,6 +749,7 @@ const OPENAI_CODEX_RESPONSES_UNSUPPORTED_PARAMS = [
|
|
|
1947
749
|
"max_output_tokens",
|
|
1948
750
|
"metadata",
|
|
1949
751
|
"prompt_cache_retention",
|
|
752
|
+
"prompt_cache_options",
|
|
1950
753
|
"service_tier",
|
|
1951
754
|
"temperature",
|
|
1952
755
|
"top_p"
|
|
@@ -1962,6 +765,7 @@ function stripOpenAICodexResponsesUnsupportedTextFields(params) {
|
|
|
1962
765
|
function sanitizeOpenAICodexResponsesParams(model, params) {
|
|
1963
766
|
if (!usesNativeOpenAICodexResponsesBackend(model)) return params;
|
|
1964
767
|
for (const key of OPENAI_CODEX_RESPONSES_UNSUPPORTED_PARAMS) delete params[key];
|
|
768
|
+
Object.assign(params, { store: false });
|
|
1965
769
|
stripOpenAICodexResponsesUnsupportedTextFields(params);
|
|
1966
770
|
return params;
|
|
1967
771
|
}
|
|
@@ -2018,14 +822,15 @@ function buildOpenAIResponsesParams(model, context, options, metadata, replayMod
|
|
|
2018
822
|
const messages = convertOpenAIResponsesMessagesForRequest(model, context, options, replayMode);
|
|
2019
823
|
ensureOpenAIResponsesNonEmptyInput(messages, context);
|
|
2020
824
|
const cacheRetention = resolveCacheRetention(options?.cacheRetention);
|
|
2021
|
-
const
|
|
825
|
+
const compat = getCompat(model);
|
|
826
|
+
const promptCacheKey = compat.supportsPromptCacheKey ? resolvePromptCacheKey(options, cacheRetention) : void 0;
|
|
2022
827
|
const instructions = resolveOpenAIResponsesInstructions(model, context, payloadPolicy.usesInstructionsField);
|
|
2023
828
|
const params = {
|
|
2024
829
|
model: model.id,
|
|
2025
830
|
input: messages,
|
|
2026
831
|
stream: true,
|
|
2027
832
|
prompt_cache_key: promptCacheKey,
|
|
2028
|
-
...
|
|
833
|
+
...resolveOpenAIPromptCacheParams(model, cacheRetention, compat),
|
|
2029
834
|
...instructions ? { instructions } : {},
|
|
2030
835
|
...metadata ? { metadata } : {}
|
|
2031
836
|
};
|
|
@@ -2039,10 +844,13 @@ function buildOpenAIResponsesParams(model, context, options, metadata, replayMod
|
|
|
2039
844
|
};
|
|
2040
845
|
if (options?.serviceTier !== void 0 && payloadPolicy.allowsServiceTier) params.service_tier = options.serviceTier;
|
|
2041
846
|
if (context.tools) {
|
|
2042
|
-
const
|
|
2043
|
-
|
|
847
|
+
const tools = context.tools;
|
|
848
|
+
const strict = resolveOpenAIStrictToolSetting(model, { transport: "stream" });
|
|
849
|
+
const projection = projectOpenAITools(tools);
|
|
850
|
+
const converted = convertProjectedResponsesTools(projection, strict, model);
|
|
851
|
+
if (converted.length > 0 || projection.inputToolCount === 0 && projection.diagnostics.length === 0) params.tools = converted;
|
|
2044
852
|
if (options?.toolChoice) {
|
|
2045
|
-
const toolChoice = reconcileOpenAIResponsesToolChoice(options.toolChoice,
|
|
853
|
+
const toolChoice = reconcileOpenAIResponsesToolChoice(options.toolChoice, projection);
|
|
2046
854
|
if (toolChoice !== void 0) params.tool_choice = toolChoice;
|
|
2047
855
|
}
|
|
2048
856
|
}
|
|
@@ -2165,6 +973,14 @@ function normalizeAssistantReplayInput(input, fromResponse = false) {
|
|
|
2165
973
|
return stableItem;
|
|
2166
974
|
});
|
|
2167
975
|
}
|
|
976
|
+
function responsesContinuationRequestFingerprint(request) {
|
|
977
|
+
const serialized = JSON.stringify(requestWithoutInput(request));
|
|
978
|
+
return sha256Hex(stableStringify(JSON.parse(serialized)));
|
|
979
|
+
}
|
|
980
|
+
function responsesContinuationPrefixFingerprint(input, output = []) {
|
|
981
|
+
const serialized = JSON.stringify([...normalizeAssistantReplayInput(input), ...normalizeAssistantReplayInput(output, true)]);
|
|
982
|
+
return sha256Hex(stableStringify(JSON.parse(serialized)));
|
|
983
|
+
}
|
|
2168
984
|
function resolveResponsesContinuationRequest(continuation, request, steering) {
|
|
2169
985
|
if (!continuation) return {
|
|
2170
986
|
request,
|
|
@@ -2227,8 +1043,9 @@ function claimOpenAIResponsesHttpContinuation(params) {
|
|
|
2227
1043
|
};
|
|
2228
1044
|
httpContinuationEntries.set(key, claimed);
|
|
2229
1045
|
try {
|
|
2230
|
-
const
|
|
2231
|
-
const
|
|
1046
|
+
const request = previous?.kind === "ready" ? params.request : params.restoreRequest?.() ?? params.request;
|
|
1047
|
+
const resolved = resolveResponsesContinuationRequest(previous?.kind === "ready" ? previous.state : void 0, request);
|
|
1048
|
+
const fullRequest = resolved.fullRequest ?? request;
|
|
2232
1049
|
return {
|
|
2233
1050
|
request: params.request.store === false ? fullRequest : resolved.request,
|
|
2234
1051
|
fullRequest,
|
|
@@ -2532,7 +1349,7 @@ function readServerEvent(message) {
|
|
|
2532
1349
|
}
|
|
2533
1350
|
function createOpenAIResponsesWebSocketStream(params) {
|
|
2534
1351
|
const connection = prepareWebSocketConnection(params.client, params.headers);
|
|
2535
|
-
|
|
1352
|
+
let fullRequest = sanitizeWebSocketRequest(params.request);
|
|
2536
1353
|
const requestModel = typeof fullRequest.model === "string" ? fullRequest.model : "";
|
|
2537
1354
|
const degradationKey = `${params.sessionId ?? ""}\0${connection.identity}\0${requestModel}`;
|
|
2538
1355
|
const degraded = degradedWebSocketConnections.get(degradationKey);
|
|
@@ -2561,10 +1378,13 @@ function createOpenAIResponsesWebSocketStream(params) {
|
|
|
2561
1378
|
if (continuation && lease.entry) {
|
|
2562
1379
|
lease.entry.continuation = void 0;
|
|
2563
1380
|
prepared = resolveResponsesContinuationRequest(continuation, fullRequest, steeringMode);
|
|
2564
|
-
} else
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
1381
|
+
} else {
|
|
1382
|
+
fullRequest = params.restoreRequest?.(fullRequest) ?? fullRequest;
|
|
1383
|
+
prepared = {
|
|
1384
|
+
request: fullRequest,
|
|
1385
|
+
continuationStatus: lease.entry ? "no_previous_response" : "socket_not_cached"
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
2568
1388
|
} catch (error) {
|
|
2569
1389
|
lease.iterator.return?.().catch(() => void 0);
|
|
2570
1390
|
lease.release({ keep: false });
|
|
@@ -2731,6 +1551,7 @@ function createOpenAIResponsesWebSocketStream(params) {
|
|
|
2731
1551
|
}
|
|
2732
1552
|
} },
|
|
2733
1553
|
request: prepared.request,
|
|
1554
|
+
fullRequest: prepared.fullRequest ?? fullRequest,
|
|
2734
1555
|
reusedConnection: lease.reusedConnection,
|
|
2735
1556
|
continuationStatus: prepared.continuationStatus,
|
|
2736
1557
|
inputReplay,
|
|
@@ -2810,6 +1631,59 @@ async function requestPreparedOpenAIResponsesCompaction(streamFn, model, context
|
|
|
2810
1631
|
}
|
|
2811
1632
|
}
|
|
2812
1633
|
//#endregion
|
|
1634
|
+
//#region packages/ai/src/transports/openai-responses-reasoning-state.ts
|
|
1635
|
+
function inputReplay(message) {
|
|
1636
|
+
const value = "openclawResponsesInputReplay" in message ? message.openclawResponsesInputReplay : void 0;
|
|
1637
|
+
return isRecord(value) ? value : void 0;
|
|
1638
|
+
}
|
|
1639
|
+
/** Save only admitted settings and hashes, never another copy of the conversation. */
|
|
1640
|
+
function recordResponsesReasoningState(message, model, identity, request, output) {
|
|
1641
|
+
if (!supportsResponsesReasoningUpdate(request) || !isRecord(request.reasoning) || !request.input || request.previous_response_id || message.providerReplay || output.some((item) => isRecord(item) && item.type === "compaction")) return;
|
|
1642
|
+
const reasoning = {
|
|
1643
|
+
...buildProviderReplayContext(model, identity),
|
|
1644
|
+
effort: request.reasoning.effort,
|
|
1645
|
+
controls: request.input.flatMap((item, index) => isConfigurationUpdate(item) ? [{
|
|
1646
|
+
index,
|
|
1647
|
+
item
|
|
1648
|
+
}] : []),
|
|
1649
|
+
inputLength: request.input.length,
|
|
1650
|
+
outputLength: output.length,
|
|
1651
|
+
prefixHash: responsesContinuationPrefixFingerprint(request.input, output),
|
|
1652
|
+
requestHash: responsesContinuationRequestFingerprint(request)
|
|
1653
|
+
};
|
|
1654
|
+
Object.assign(message, { openclawResponsesInputReplay: {
|
|
1655
|
+
...inputReplay(message),
|
|
1656
|
+
reasoning
|
|
1657
|
+
} });
|
|
1658
|
+
}
|
|
1659
|
+
/** A cold transport can replay controls, but cannot resurrect a server response handle. */
|
|
1660
|
+
function restoreResponsesReasoningState(context, model, identity, request) {
|
|
1661
|
+
const latest = context.messages.findLast((message) => message.role === "assistant");
|
|
1662
|
+
const state = latest ? inputReplay(latest)?.reasoning : void 0;
|
|
1663
|
+
if (!isRecord(state)) return request;
|
|
1664
|
+
const { effort, inputLength, outputLength, controls, prefixHash, requestHash } = state;
|
|
1665
|
+
if (!isOpenAIResponsesReplayContext(state) || !providerReplayContextMatches(state, buildProviderReplayContext(model, identity)) || latest?.providerReplay || !supportsResponsesReasoningUpdate(request) || !isRecord(request.reasoning) || !request.input || request.previous_response_id || request.input.some(isConfigurationUpdate) || typeof effort !== "string" || typeof inputLength !== "number" || !Number.isSafeInteger(inputLength) || inputLength < 0 || typeof outputLength !== "number" || !Number.isSafeInteger(outputLength) || outputLength < 0 || !Array.isArray(controls) || controls.length > inputLength || inputLength + outputLength > request.input.length + controls.length) return request;
|
|
1666
|
+
const previousInput = request.input.slice(0, inputLength - controls.length);
|
|
1667
|
+
let lastIndex = -1;
|
|
1668
|
+
for (const control of controls) {
|
|
1669
|
+
if (!isRecord(control) || typeof control.index !== "number" || !Number.isSafeInteger(control.index) || control.index <= lastIndex || control.index > previousInput.length || !isConfigurationUpdate(control.item)) return request;
|
|
1670
|
+
previousInput.splice(control.index, 0, control.item);
|
|
1671
|
+
lastIndex = control.index;
|
|
1672
|
+
}
|
|
1673
|
+
const previous = {
|
|
1674
|
+
...request,
|
|
1675
|
+
reasoning: {
|
|
1676
|
+
...request.reasoning,
|
|
1677
|
+
effort
|
|
1678
|
+
},
|
|
1679
|
+
input: previousInput
|
|
1680
|
+
};
|
|
1681
|
+
if (responsesContinuationRequestFingerprint(previous) !== requestHash) return request;
|
|
1682
|
+
const prepared = replayResponsesReasoningUpdates(previous, request, outputLength);
|
|
1683
|
+
if (responsesContinuationPrefixFingerprint((prepared.input ?? []).slice(0, inputLength + outputLength)) !== prefixHash) return request;
|
|
1684
|
+
return prepared;
|
|
1685
|
+
}
|
|
1686
|
+
//#endregion
|
|
2813
1687
|
//#region packages/ai/src/transports/openai-responses-client.ts
|
|
2814
1688
|
function resolveNativeOpenAIResponsesWebSocketMode(model, transport) {
|
|
2815
1689
|
if (transport !== "websocket" && transport !== "websocket-cached" && transport !== "auto") return;
|
|
@@ -2927,7 +1801,8 @@ function createResponsesTransportExecutor(config) {
|
|
|
2927
1801
|
apiKey,
|
|
2928
1802
|
baseUrl: model.baseUrl,
|
|
2929
1803
|
headers: buildOpenAIClientHeaders(model, context, options?.headers, turnState?.headers, sessionId),
|
|
2930
|
-
request: params
|
|
1804
|
+
request: params,
|
|
1805
|
+
restoreRequest: () => restoreResponsesReasoningState(context, model, responsesOptions, params)
|
|
2931
1806
|
});
|
|
2932
1807
|
if (continuationClaim) params = continuationClaim.fullRequest;
|
|
2933
1808
|
}
|
|
@@ -2965,7 +1840,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2965
1840
|
onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, responsesOptions, checkpoint),
|
|
2966
1841
|
canRetryStream: () => output.content.length === 0,
|
|
2967
1842
|
wrapStream: ({ stream: rawResponseStream, response, attempt }) => {
|
|
2968
|
-
|
|
1843
|
+
continuationBaseline = attempt.request.previous_response_id ? params : attempt.request;
|
|
2969
1844
|
return withProviderResponseHook({
|
|
2970
1845
|
stream: observeResponsesStream(rawResponseStream, model, requestStartedAt),
|
|
2971
1846
|
signal: firstEvent.signal,
|
|
@@ -2981,6 +1856,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2981
1856
|
return responseStream;
|
|
2982
1857
|
};
|
|
2983
1858
|
let responseStream;
|
|
1859
|
+
let websocketBaseline;
|
|
2984
1860
|
let finishWebSocket;
|
|
2985
1861
|
let transport = "sse";
|
|
2986
1862
|
const logWebSocketFallback = (reason) => emitModelTransportDebug(log, `[responses] websocket_fallback provider=${model.provider} api=${model.api} model=${model.id} reason=${reason}`);
|
|
@@ -2994,6 +1870,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
2994
1870
|
const websocket = createOpenAIResponsesWebSocketStream({
|
|
2995
1871
|
client,
|
|
2996
1872
|
request: params,
|
|
1873
|
+
restoreRequest: (request) => restoreResponsesReasoningState(context, model, responsesOptions, request),
|
|
2997
1874
|
mode: websocketMode,
|
|
2998
1875
|
sessionId: options?.sessionId,
|
|
2999
1876
|
headers: websocketHeaders,
|
|
@@ -3007,6 +1884,7 @@ function createResponsesTransportExecutor(config) {
|
|
|
3007
1884
|
}))
|
|
3008
1885
|
});
|
|
3009
1886
|
finishWebSocket = websocket.finish;
|
|
1887
|
+
websocketBaseline = websocket.fullRequest;
|
|
3010
1888
|
recordResponsesInputReplay(output, websocket.inputReplay);
|
|
3011
1889
|
observePrompt?.(websocket.request, {
|
|
3012
1890
|
egress: "responses-websocket",
|
|
@@ -3071,6 +1949,8 @@ function createResponsesTransportExecutor(config) {
|
|
|
3071
1949
|
finishWebSocket?.();
|
|
3072
1950
|
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
3073
1951
|
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
1952
|
+
const admitted = transport === "websocket" ? websocketBaseline : continuationBaseline;
|
|
1953
|
+
if (terminal && admitted && supportsNativeOpenAIResponsesEndpoint(model)) recordResponsesReasoningState(output, model, responsesOptions, admitted, terminal.output);
|
|
3074
1954
|
if (continuationClaim && continuationBaseline && terminal) continuationClaim.commit(continuationBaseline, terminal);
|
|
3075
1955
|
} catch (error) {
|
|
3076
1956
|
finishWebSocket?.({ keep: false });
|
|
@@ -3353,7 +2233,7 @@ const SIMPLE_TRANSPORT_API_ALIAS = {
|
|
|
3353
2233
|
"google-generative-ai": "openclaw-google-generative-ai-transport"
|
|
3354
2234
|
};
|
|
3355
2235
|
function createProviderOwnedGoogleTransportStreamFn(model, ctx) {
|
|
3356
|
-
|
|
2236
|
+
const streamFn = getAiTransportHost().plugin.resolveProviderStream({
|
|
3357
2237
|
provider: model.provider,
|
|
3358
2238
|
config: ctx?.cfg,
|
|
3359
2239
|
workspaceDir: ctx?.workspaceDir,
|
|
@@ -3380,6 +2260,10 @@ function createProviderOwnedGoogleTransportStreamFn(model, ctx) {
|
|
|
3380
2260
|
model
|
|
3381
2261
|
}
|
|
3382
2262
|
}) ?? void 0;
|
|
2263
|
+
return streamFn ? (requestModel, context, options) => streamFn(requestModel, context, {
|
|
2264
|
+
...options,
|
|
2265
|
+
headers: resolveOpencodeSessionHeaders(requestModel, options)
|
|
2266
|
+
}) : void 0;
|
|
3383
2267
|
}
|
|
3384
2268
|
function createSupportedTransportStreamFn(model, ctx) {
|
|
3385
2269
|
switch (model.api) {
|
|
@@ -3564,7 +2448,9 @@ function prepareProviderStreamModel(params) {
|
|
|
3564
2448
|
const streamFn = providerStreamFn ? wrapPluginProviderStream(providerStreamFn) : transportFallback && params.model.api === "google-generative-ai" ? wrapPluginProviderStream(transportFallback) : transportFallback;
|
|
3565
2449
|
if (!streamFn) return;
|
|
3566
2450
|
const api = params.apiRegistry.getApiProvider(params.model.api) ? resolveProviderStreamApi(params.model) : params.model.api;
|
|
3567
|
-
|
|
2451
|
+
const sourceApi = params.model.api;
|
|
2452
|
+
const sourceStreamFn = (runtimeModel, context, options) => streamFn(projectModel(runtimeModel, { api: sourceApi }), context, options);
|
|
2453
|
+
if (!registerCustomApi(params.apiRegistry, api, sourceStreamFn)) return;
|
|
3568
2454
|
return api === params.model.api ? params.model : projectModel(params.model, { api });
|
|
3569
2455
|
}
|
|
3570
2456
|
function prepareModelForSimpleCompletion(params) {
|
|
@@ -3589,4 +2475,4 @@ function prepareModelForSimpleCompletion(params) {
|
|
|
3589
2475
|
return applyProviderSimpleCompletionWrapper(apiRegistry, model, cfg);
|
|
3590
2476
|
}
|
|
3591
2477
|
//#endregion
|
|
3592
|
-
export { CompactionReplayRefreshRequiredError, GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP, MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE,
|
|
2478
|
+
export { CompactionReplayRefreshRequiredError, GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP, MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE, applyAnthropicContextManagementToRequest, applyAnthropicEphemeralCacheControlMarkers, applyAnthropicPayloadPolicyToParams, applyAnthropicRequestCacheControl, applyCompletionsAnthropicCacheControl, applyOpenAIResponsesPayloadPolicy, assertCodeModeResponsesToolSurface, assignTransportErrorDetails, buildAnthropicSystemBlocks, buildOpenAIClientHeaders, buildOpenAICompletionsParams, buildOpenAISdkClientOptions, buildOpenAISdkRequestOptions, buildTransportAwareSimpleStreamFn, canonicalizeMaxTokensParam, captureOpenAIResponsesCompaction, coerceTransportToolCallArguments, consumeGoogleGenerateContentStream, convertGoogleTools, copyProviderAcceptanceObserver, createAnthropicMessagesTransportStreamFn, createAzureOpenAIResponsesTransportStreamFn, createBoundaryAwareStreamFnForModel, createDeepSeekTextFilter, createEmptyTransportUsage, createModelStreamCooperativeScheduler, createOpenAICompletionsTransportStreamFn, createOpenAIProviderAcceptanceHook, createOpenAIResponseHook, createOpenAIResponsesTransportStreamFn, createOpenClawTransportStreamFnForModel, createTransportAwareStreamFnForModel, createWritableTransportEventStream, detectOpenAICompletionsCompat, emitModelTransportDebug, enforceCodeModeResponsesToolSurface, failTransportStream, filterCodeModePayloadTools, finalizeTerminalToolCallArguments, finalizeTransportStream, flattenCompletionMessagesToStringContent, formatModelTransportDebugBaseUrl, formatModelTransportDebugUrl, getCompat, googleFlashSupportsMinimalThinking, hasOpenAICompatibleConversationTurn, isAnthropicServerToolClearingEnabled, isCodeModeModelVisibleToolName, isCompactionReplayCheckpoint, isDirectAnthropicModel, isNativeOpenAIEndpoint, isOpenAICodexResponsesModel, isOpenAICompletionsThinkingEnabled, log, logAnthropicContextEdits, measureUtf8AppendBytes, mergeTransportHeaders, mergeTransportMetadata, normalizeCodexResponsesBaseUrlForOpenAISdk, notifyProviderHttpMetadata, notifyProviderHttpResponse, notifyProviderStreamOpened, parseJsonObjectPreservingUnsafeIntegers, parseJsonPreservingUnsafeIntegers, parseOpenAICompletionsUsage, parseTerminalToolCallArguments, prepareModelForSimpleCompletion, prepareTransportAwareSimpleModel, preserveCompactionReplayWindow, projectGoogleMessages, quoteUnsafeIntegerLiterals, readCodeModePayloadToolName, readOpenAICompletionsContentDeltas, readOpenAICompletionsReasoningBatch, replaceCompactionReplayOwnerContent, requestPreparedOpenAIResponsesCompaction, requiresCompactionReplayRefresh, requiresGoogleToolCallId, resolveAnthropicCacheOptions, resolveAnthropicContextManagementBetaHeader, resolveAnthropicEphemeralCacheControl, resolveAnthropicMessagesUrl, resolveAnthropicPayloadPolicy, resolveAnthropicServerCompactionPlan, resolveCodeModeResponsesVisibleToolNames, resolveCompactionReplayEligibility, resolveCompactionReplayPressure, resolveMaxTokensParam, resolveModelPayloadDebugMode, resolveModelSseDebugMode, resolveOpenAIClientBaseUrl, resolveOpenAICompletionsCompat, resolveOpenAIPromptCacheKeySupport, resolveOpenAIReasoningEffortMap, resolveOpenAIResponsesCompactEndpointPlan, resolveOpenAIResponsesPayloadPolicy, resolveOpenAIResponsesServerCompactionPlan, resolveOpenAIStrictToolFlagWithDiagnostics, resolvePromptCacheKey, resolveReplayableResponsesMessageId, resolveTransportAwareSimpleApi, sanitizeNonEmptyTransportPayloadText, sanitizeResponsesImagePayload, sanitizeTransportPayloadText, sortPromptCacheToolsByName as sortTransportToolsByName, stripCompactionReplayCheckpoint, stripCompactionReplayCheckpointInPlace, stripCompletionMessagesToRoleContent, throwIfModelStreamAborted, transportAbortError, usesNativeOpenAICodexResponsesBackend, withProviderAcceptanceObserver, withProviderResponseHook };
|