@openclaw/ai 2026.9.1 → 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.
Files changed (111) hide show
  1. package/README.md +3 -2
  2. package/dist/anthropic-CZy5U0NY.mjs +376 -0
  3. package/dist/anthropic-payload-policy-wuRCb6MH.d.mts +85 -0
  4. package/dist/anthropic-stream-reducer-B_yo_7pf.mjs +1669 -0
  5. package/dist/{api-registry-Cs6HGNqY.d.mts → api-registry-CB1-1oQ2.d.mts} +2 -2
  6. package/dist/assistant-output-iqnlJCV2.mjs +16 -0
  7. package/dist/assistant-text-phase-C20rxWwP.mjs +55 -0
  8. package/dist/{azure-openai-responses-CN4Fy5zV.mjs → azure-openai-responses-Crpa40QR.mjs} +5 -5
  9. package/dist/{base64-CEFBpSkN.mjs → base64-D-su8YVo.mjs} +1 -27
  10. package/dist/{diagnostics-KhXK-QJI.mjs → diagnostics-dV98PqIy.mjs} +96 -21
  11. package/dist/diagnostics.d.mts +3 -1
  12. package/dist/diagnostics.mjs +3 -3
  13. package/dist/{event-stream-vK_7r3bj.d.mts → event-stream-C1Z2piyk.d.mts} +11 -3
  14. package/dist/{event-stream-uSMZJ3FA.mjs → event-stream-D8PARQfL.mjs} +48 -10
  15. package/dist/event-stream-I_GlBsuZ.d.mts +1 -0
  16. package/dist/event-stream.d.mts +2 -2
  17. package/dist/event-stream.mjs +1 -1
  18. package/dist/{github-copilot-headers-NCJtz9i0.mjs → github-copilot-headers-B37TB3rB.mjs} +3 -10
  19. package/dist/github-copilot-request-facts-BTEBMeOv.mjs +16 -0
  20. package/dist/{google-CC-nrwXg.mjs → google-BDPriaVe.mjs} +10 -10
  21. package/dist/google-messages-CVn9eFpF.mjs +449 -0
  22. package/dist/google-shared-BedY23XS.mjs +185 -0
  23. package/dist/{google-vertex-DCr0pyzQ.mjs → google-vertex-DMz8XQCn.mjs} +7 -6
  24. package/dist/{host-BIaiBURL.mjs → host-CWuF-sS3.mjs} +84 -34
  25. package/dist/{host-BztR4tQj.d.mts → host-DK3wmS3e.d.mts} +3 -3
  26. package/dist/host-policy-CAopLRKA.mjs +37 -0
  27. package/dist/{index-AfaxKT8w.d.mts → index-CQ6LTHw8.d.mts} +11 -5
  28. package/dist/index.d.mts +7 -7
  29. package/dist/index.mjs +5 -5
  30. package/dist/internal/anthropic.d.mts +14 -11
  31. package/dist/internal/anthropic.mjs +5 -5
  32. package/dist/internal/google-model-family.d.mts +5 -0
  33. package/dist/internal/google-model-family.mjs +15 -0
  34. package/dist/internal/openai-responses-payload-policy.d.mts +1 -1
  35. package/dist/internal/openai-responses-payload-policy.mjs +1 -1
  36. package/dist/internal/openai.d.mts +8 -103
  37. package/dist/internal/openai.mjs +10 -10
  38. package/dist/internal/retry-after.d.mts +2 -4
  39. package/dist/internal/retry-after.mjs +57 -8
  40. package/dist/internal/runtime.d.mts +7 -6
  41. package/dist/internal/runtime.mjs +8 -7
  42. package/dist/internal/shared.d.mts +14 -3
  43. package/dist/internal/shared.mjs +6 -4
  44. package/dist/internal/tool-schema.d.mts +63 -0
  45. package/dist/internal/tool-schema.mjs +3 -0
  46. package/dist/{json-parse-BuAJEbdW.mjs → json-parse-Dw_hnxsA.mjs} +1 -1
  47. package/dist/{mistral-B7etBd_H.mjs → mistral--m-Jm6VZ.mjs} +16 -38
  48. package/dist/model-transport-url-DKocrEsb.d.mts +28 -0
  49. package/dist/{openai-chatgpt-responses-BAJ4gq3i.mjs → openai-chatgpt-responses-nDZccFW-.mjs} +62 -54
  50. package/dist/openai-completions-KuoZyx0d.mjs +187 -0
  51. package/dist/{openai-completions-compat-4IjSBpr6.d.mts → openai-completions-compat-CXn3T1we.d.mts} +26 -4
  52. package/dist/{openai-completions-stream-DZjwK8vp.mjs → openai-completions-stream-BQk3SkLD.mjs} +621 -451
  53. package/dist/openai-prompt-cache-BI0rkM-5.mjs +220 -0
  54. package/dist/openai-prompt-cache-rrutvqxq.d.mts +16 -0
  55. package/dist/openai-provider-client-ha_WxTyj.mjs +24 -0
  56. package/dist/openai-reasoning-effort-BK7FbcLT.mjs +167 -0
  57. package/dist/{openai-responses-BEUlxfDu.mjs → openai-responses-D99dOzKI.mjs} +14 -32
  58. package/dist/{openai-responses-compaction-window-DO7yV7az.mjs → openai-responses-compaction-window-D5jbzCi3.mjs} +7 -159
  59. package/dist/{openai-responses-contracts-bPzSN_Ba.d.mts → openai-responses-contracts-B55afwRo.d.mts} +12 -4
  60. package/dist/{openai-responses-prompt-observer-internal-C7x4IK7r.mjs → openai-responses-prompt-observer-internal-tApyTLVu.mjs} +3 -3
  61. package/dist/{openai-responses-shared-DiAdpNAM.mjs → openai-responses-shared-ZyQEzS5i.mjs} +217 -212
  62. package/dist/openai-tool-projection-793cE3QX.d.mts +37 -0
  63. package/dist/{openai-tool-schema-BMiHFH36.mjs → openai-tool-schema-CzjyYXun.mjs} +53 -583
  64. package/dist/openai-tool-schema-ynZBgqW-.d.mts +38 -0
  65. package/dist/openai-transport-params-DNasp2fU.mjs +674 -0
  66. package/dist/{provider-error-B6EGq6gg.mjs → provider-error-C6TbKiey.mjs} +29 -13
  67. package/dist/{provider-options-CxFPtvh7.d.mts → provider-options-BXr9Ec83.d.mts} +19 -42
  68. package/dist/provider-replay-context-BuSUaAk5.mjs +21 -0
  69. package/dist/{provider-transcript-transform-WvJmFUAf.mjs → provider-transcript-transform-pPmUIwKt.mjs} +1 -1
  70. package/dist/provider-types-CAV0Og3m.d.mts +29 -0
  71. package/dist/provider-types.d.mts +6 -31
  72. package/dist/providers.d.mts +2 -2
  73. package/dist/providers.mjs +11 -11
  74. package/dist/{reasoning-tag-text-partitioner-C-4uedDb.mjs → reasoning-tag-text-partitioner-BQBi4B9d.mjs} +90 -35
  75. package/dist/record-coerce-DwRYMj3t.mjs +32 -0
  76. package/dist/retry-after-CdCURCVg.d.mts +15 -0
  77. package/dist/{sanitize-unicode-S6binQG-.mjs → sanitize-unicode-Bb-v9meu.mjs} +1 -1
  78. package/dist/session-affinity-CCH7eYdB.mjs +20 -0
  79. package/dist/{simple-options-0PLDyJ-d.mjs → simple-options-tcKOqnpF.mjs} +3 -3
  80. package/dist/{src-C8U7lkoa.mjs → src-B2Q_6G8V.mjs} +10 -2
  81. package/dist/{stream-first-event-timeout-DcNjoFQE.mjs → stream-first-event-timeout-2hfrquuz.mjs} +1 -1
  82. package/dist/string-coerce-fsri9iCu.mjs +34 -0
  83. package/dist/{string-normalization--fwJ4S2q.mjs → string-normalization-CmLIasuf.mjs} +1 -1
  84. package/dist/{tool-schema-json-projection-BtZiml7r.mjs → tool-schema-json-projection-ClptDdAO.mjs} +2 -38
  85. package/dist/{transport-stream-shared-CytPVLIg.mjs → transport-stream-shared-Cu3ZPhNW.mjs} +5 -5
  86. package/dist/{transport-stream-shared-BrvFTkoO.d.mts → transport-stream-shared-DOxpGJ-H.d.mts} +4 -4
  87. package/dist/transport-utils-CCooe-cr.mjs +121 -0
  88. package/dist/transports.d.mts +114 -41
  89. package/dist/transports.mjs +796 -1596
  90. package/dist/types-BADKjDBI.d.mts +1 -0
  91. package/dist/{types-DbrhszyQ.d.mts → types-Dy1q0CSu.d.mts} +101 -64
  92. package/dist/types.d.mts +6 -6
  93. package/dist/types.mjs +4 -4
  94. package/dist/utf16-slice-CvGodqok.mjs +29 -0
  95. package/dist/{validation-CJZtym2g.mjs → validation-BDzVDnTs.mjs} +9 -1
  96. package/dist/{validation-BOwtcl9X.d.mts → validation-CaFUZN9B.d.mts} +1 -1
  97. package/dist/validation.d.mts +1 -1
  98. package/dist/validation.mjs +1 -1
  99. package/package.json +14 -4
  100. package/dist/anthropic-compaction-replay-OMJZ0uyo.mjs +0 -838
  101. package/dist/anthropic-hk7F7ptG.mjs +0 -883
  102. package/dist/anthropic-payload-policy-DBT1itQ-.d.mts +0 -51
  103. package/dist/event-stream-DeDhbCc5.d.mts +0 -1
  104. package/dist/google-shared-CjPY0hZM.mjs +0 -634
  105. package/dist/google-thinking-level-C-V3tecN.mjs +0 -9
  106. package/dist/openai-completions-D0QZ0AyB.mjs +0 -403
  107. package/dist/openai-prompt-cache-2uo_1OR1.d.mts +0 -7
  108. package/dist/openai-prompt-cache-mZTCdRPo.mjs +0 -12
  109. package/dist/transport-utils-CtuS1Upe.mjs +0 -138
  110. package/dist/types-B5EFUmXs.d.mts +0 -1
  111. package/dist/utf16-slice-qz3nsy87.mjs +0 -84
@@ -1,30 +1,34 @@
1
- import { g as supportsClaudeAdaptiveThinking, m as resolveClaudeSonnet5ModelIdentity, p as resolveClaudeOpus5ModelIdentity, y as supportsClaudeNativeXhighEffort } from "./src-C8U7lkoa.mjs";
2
- import { c as normalizeLowercaseStringOrEmpty, o as isRecord, s as hasNonEmptyString } from "./utf16-slice-qz3nsy87.mjs";
3
- import { r as calculateCost } from "./sanitize-unicode-S6binQG-.mjs";
4
- import { S as usesClaudeStreamingRefusalContract, _ as prepareClaudeNoPrefillRequestContext, a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, f as ANTHROPIC_CLAUDE_CODE_BILLING_SYSTEM_BLOCK, g as mapAnthropicStopReason, h as defaultsClaudeAdaptiveThinking, m as applyClaudeRequestContract, n as getAiTransportHost, p as ANTHROPIC_CLAUDE_CODE_VERSION, r as resolveAiTransportHeaderSentinels, s as extractToolResultBlockText, v as requiresClaudeAdaptiveThinking, x as usesClaudeFable5MessagesContract, y as resolveAnthropicThinkingEffort } from "./host-BIaiBURL.mjs";
5
- import { i as stableStringify } from "./provider-error-B6EGq6gg.mjs";
6
- import { r as toErrorObject } from "./diagnostics-KhXK-QJI.mjs";
7
- import { a as asNonNegativeFiniteNumber } from "./base64-CEFBpSkN.mjs";
8
- import { n as uniqueStrings } from "./string-normalization--fwJ4S2q.mjs";
9
- import { A as applyAnthropicCacheControlToMessages, C as applyAnthropicFallbackBoundary, D as createAnthropicInlineImageBudget, E as applyAnthropicRefusal, F as resolveAnthropicServerCompactionPlan, I as isAnthropicOAuthApiKey, L as omitFoundryBearerCredentialHeaders, M as applyAnthropicPayloadPolicyToParams, N as resolveAnthropicEphemeralCacheControl, O as normalizeAnthropicInlineContent, P as resolveAnthropicPayloadPolicy, R as usesFoundryBearerAuth, T as resolveAnthropicFallbackServingModelCost, _ as toClaudeCodeToolName, a as suppressAnthropicCompaction, b as ANTHROPIC_SERVER_SIDE_FALLBACKS, f as normalizeAnthropicToolCallId, g as resolveOriginalAnthropicToolName, h as reconcileAnthropicToolChoice, i as resolveNewestAnthropicCompaction, j as applyAnthropicEphemeralCacheControlMarkers, k as resolveAnthropicImageMediaType, m as projectAnthropicTools, n as createCompactionCapture, o as applyAnthropicMessageDeltaUsage, p as normalizeAnthropicToolChoice, r as isAnthropicReplayRejection, s as applyAnthropicMessageStartUsage, t as buildAnthropicReplayPlan, v as ANTHROPIC_OMITTED_REASONING_TEXT, w as readAnthropicFallbackBoundary, x as ANTHROPIC_SERVER_SIDE_FALLBACK_BETA, y as findActiveAnthropicToolTurnAssistantIndex } from "./anthropic-compaction-replay-OMJZ0uyo.mjs";
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";
10
13
  import { t as resolveCacheRetention } from "./cache-retention-0x979a5V.mjs";
11
- import { a as codeModeToolSurfaceObserver, d as stripSystemPromptCacheBoundary, m as sortPromptCacheToolsByName, o as reasoningTagTextPolicy, t as adjustMaxTokensForThinking } from "./simple-options-0PLDyJ-d.mjs";
12
- import { a as resolveProviderEndpoint, c as transformTransportMessages, i as resolveOpenAIStrictToolSetting, n as buildGuardedModelFetch } from "./tool-schema-json-projection-BtZiml7r.mjs";
13
- 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-CtuS1Upe.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";
14
16
  import { n as getEnvApiKey } from "./env-api-keys-bktO00EJ.mjs";
15
- 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-CytPVLIg.mjs";
16
- 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-DZjwK8vp.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";
17
18
  import { t as createDeferredEventBuffer } from "./deferred-event-buffer-DAvyP7qA.mjs";
18
- import { r as parseStreamingJson, t as createToolArgumentPreviewSchedule } from "./json-parse-BuAJEbdW.mjs";
19
- import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
20
- import { t as googleFlashSupportsMinimalThinking } from "./google-thinking-level-C-V3tecN.mjs";
21
- import { B as buildResponsesInputMessage, C as summarizeResponsesTools, G as captureOpenAIResponsesCompaction, H as createOpenAIResponsesAssistantOutput, I as createResponsesStreamWithEncryptedContentRetry, J as resolveReplayableResponsesMessageId, K as resolveNewestOpenAIResponsesCompactionReplay, L as isInvalidEncryptedContentError, R as resolveAzureOpenAIApiVersion, S as summarizeResponsesPayload, U as CompactionReplayRefreshRequiredError, V as convertResponsesMessages, W as buildOpenAIResponsesReasoningReplayMetadata, X as resolveModelPayloadDebugMode, Y as emitModelTransportDebug, Z as resolveModelSseDebugMode, _ as safeDebugValue, b as summarizeOpenAITransportError, c as processResponsesStream, f as observeResponsesStream, g as normalizeResponsesFailedEvent, h as logResponsesFailedNoDetails, m as buildResponsesFailedNoDetailsObservation, n as applyResponsesServiceTierPricing, p as ResponsesStreamFailure, q as suppressOpenAIResponsesCompaction, v as stringifyRedactedEvent, x as summarizeResponsesFailedNoDetailsObservation, y as stringifyRedactedPayload, z as resolveNextResponsesEncryptedContentAttempt } from "./openai-responses-shared-DiAdpNAM.mjs";
22
- import { A as readOpenAICompletionsReasoningBatch, C as createOpenAIProviderAcceptanceHook, D as measureUtf8AppendBytes, E as log, M as resolvePromptCacheKey, N as throwIfModelStreamAborted, O as parseOpenAICompletionsUsage, S as createModelStreamCooperativeScheduler, T as isOpenAICompletionsThinkingEnabled, b as reconcileOpenAIResponsesToolChoice, j as resolveOpenAIClientBaseUrl, k as readOpenAICompletionsContentDeltas, r as normalizeOpenAIStrictToolParameters, v as projectOpenAITools, w as createOpenAIResponseHook, x as GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP, y as reconcileOpenAICompletionsToolChoice } from "./openai-tool-schema-BMiHFH36.mjs";
23
- import { i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-DcNjoFQE.mjs";
24
- import { C as isOpenAIGpt54MiniModel, D as resolveOpenAIReasoningEffortForModel, E as normalizeOpenAIReasoningEffort, T as isOpenAIGpt56Model, _ 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, w as isOpenAIGpt55Model, x as parseOpenAIResponsesWebSocketServerError, y as OpenAIResponsesWebSocketSafeRetryError } from "./openai-responses-compaction-window-DO7yV7az.mjs";
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";
25
29
  import { i as resolveAzureDeploymentNameFromMap, t as isOpenAICompatibleAzureResponsesBaseUrl } from "./azure-openai-responses-client-compat-C7K7QfUE.mjs";
26
30
  import { n as registerSessionResourceCleanup } from "./session-resources-CkR4WWy1.mjs";
27
- import { t as createResponsesPromptEgressObserver } from "./openai-responses-prompt-observer-internal-C7x4IK7r.mjs";
31
+ import { t as createResponsesPromptEgressObserver } from "./openai-responses-prompt-observer-internal-tApyTLVu.mjs";
28
32
  import { randomUUID } from "node:crypto";
29
33
  import OpenAI, { AzureOpenAI } from "openai";
30
34
  import { ResponsesWS } from "openai/resources/responses/ws.js";
@@ -59,11 +63,6 @@ function resolveAnthropicMessagesMaxTokens(params) {
59
63
  const contextWindow = resolvePositiveAnthropicTokenLimit(params.modelContextWindow);
60
64
  return contextWindow === void 0 ? ANTHROPIC_MESSAGES_DEFAULT_MAX_TOKENS : Math.max(1, Math.min(ANTHROPIC_MESSAGES_DEFAULT_MAX_TOKENS, Math.floor(contextWindow / ANTHROPIC_MESSAGES_FALLBACK_CONTEXT_DIVISOR)));
61
65
  }
62
- function isDirectAnthropicModel(model) {
63
- if (normalizeLowercaseStringOrEmpty(model.provider) !== "anthropic") return false;
64
- const endpointClass = resolveProviderEndpoint(model).endpointClass;
65
- return endpointClass === "default" || endpointClass === "anthropic-public";
66
- }
67
66
  function isKimiAnthropicProvider(provider) {
68
67
  return /^kimi(?:-|$)/.test(normalizeLowercaseStringOrEmpty(provider ?? ""));
69
68
  }
@@ -82,224 +81,12 @@ function buildAnthropicBetaHeader(model, betaFeatures, params) {
82
81
  if (!isDirectAnthropicModel(model)) return;
83
82
  return params.oauth ? `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}` : betaFeatures.join(",");
84
83
  }
85
- const NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
86
- async function convertContentBlocks(content, model, imageBudget) {
87
- const text = extractToolResultText(content);
88
- const mediaPlaceholder = describeToolResultMediaPlaceholder(content);
89
- if (!(model.input.includes("image") && content.some(isImageWithMediaPayload))) return sanitizeNonEmptyTransportPayloadText(text, mediaPlaceholder ?? "(no output)");
90
- const blocks = [];
91
- let hasTextBlock = false;
92
- for (const block of content) {
93
- if (!block || typeof block !== "object") continue;
94
- const record = block;
95
- const blockText = extractToolResultBlockText(block);
96
- if (blockText) {
97
- blocks.push({
98
- type: "text",
99
- text: sanitizeTransportPayloadText(blockText)
100
- });
101
- hasTextBlock = true;
102
- }
103
- if (!isImageWithMediaPayload(record)) continue;
104
- const [normalizedImage] = await normalizeAnthropicInlineContent([{
105
- type: "image",
106
- data: typeof record.data === "string" ? record.data : "",
107
- mimeType: typeof record.mimeType === "string" ? record.mimeType : "image/png"
108
- }], imageBudget);
109
- if (normalizedImage?.type !== "image") continue;
110
- blocks.push({
111
- type: "image",
112
- source: {
113
- type: "base64",
114
- media_type: resolveAnthropicImageMediaType(normalizedImage.mimeType),
115
- data: normalizedImage.data
116
- }
117
- });
118
- }
119
- if (!hasTextBlock) blocks.unshift({
120
- type: "text",
121
- text: mediaPlaceholder ?? "(see attached image)"
122
- });
123
- return blocks;
124
- }
125
- async function convertAnthropicMessages(messages, model, isOAuthToken, options) {
126
- const params = [];
127
- const imageBudget = createAnthropicInlineImageBudget();
128
- const allowReasoningContentReplay = options.allowReasoningContentReplay === true;
129
- const replayThinkingEnabled = options.replayThinkingEnabled !== false;
130
- const transformedMessages = transformTransportMessages(messages, model, normalizeAnthropicToolCallId);
131
- const activeToolTurnAssistantIndex = replayThinkingEnabled ? -1 : findActiveAnthropicToolTurnAssistantIndex(transformedMessages);
132
- for (let i = 0; i < transformedMessages.length; i += 1) {
133
- const msg = transformedMessages[i];
134
- if (!msg) continue;
135
- if (msg.role === "user") {
136
- const isRuntimeContextCarrier = msg.runtimeContextCarrier === true;
137
- if (typeof msg.content === "string") {
138
- if (msg.content.trim().length > 0) {
139
- const userParam = {
140
- role: "user",
141
- content: sanitizeTransportPayloadText(msg.content)
142
- };
143
- if (isRuntimeContextCarrier) options.cacheBreakpointOptOutMessageIndexes.add(params.length);
144
- params.push(userParam);
145
- }
146
- continue;
147
- }
148
- const blocks = (model.input.includes("image") ? await normalizeAnthropicInlineContent(msg.content, imageBudget) : msg.content.map((item) => item.type === "image" ? {
149
- type: "text",
150
- text: NON_VISION_USER_IMAGE_PLACEHOLDER
151
- } : item)).map((item) => item.type === "text" ? {
152
- type: "text",
153
- text: sanitizeTransportPayloadText(item.text)
154
- } : {
155
- type: "image",
156
- source: {
157
- type: "base64",
158
- media_type: resolveAnthropicImageMediaType(item.mimeType),
159
- data: item.data
160
- }
161
- });
162
- let filteredBlocks = model.input.includes("image") ? blocks : blocks.filter((block) => block.type !== "image");
163
- filteredBlocks = filteredBlocks.filter((block) => block.type !== "text" || block.text.trim().length > 0);
164
- if (filteredBlocks.length === 0) continue;
165
- const userParam = {
166
- role: "user",
167
- content: filteredBlocks
168
- };
169
- if (isRuntimeContextCarrier) options.cacheBreakpointOptOutMessageIndexes.add(params.length);
170
- params.push(userParam);
171
- continue;
172
- }
173
- if (msg.role === "assistant") {
174
- const blocks = i === 0 && options.compaction ? [options.compaction] : [];
175
- const reasoningContent = [];
176
- let omittedThinking = false;
177
- for (const block of msg.content) {
178
- if (block.type === "text") {
179
- if (block.text.trim().length > 0) blocks.push({
180
- type: "text",
181
- text: sanitizeTransportPayloadText(block.text)
182
- });
183
- continue;
184
- }
185
- if (block.type === "thinking") {
186
- const thinkingSignature = block.thinkingSignature?.trim();
187
- const isReasoningContent = thinkingSignature === "reasoning_content";
188
- if (!replayThinkingEnabled && i !== activeToolTurnAssistantIndex && !isReasoningContent) {
189
- omittedThinking = true;
190
- continue;
191
- }
192
- if (block.redacted) {
193
- blocks.push({
194
- type: "redacted_thinking",
195
- data: block.thinkingSignature
196
- });
197
- continue;
198
- }
199
- const hasNativeThinkingSignature = Boolean(thinkingSignature) && !isReasoningContent;
200
- if (block.thinking.trim().length === 0 && !hasNativeThinkingSignature) continue;
201
- if (!thinkingSignature) blocks.push({
202
- type: "text",
203
- text: sanitizeTransportPayloadText(block.thinking)
204
- });
205
- else {
206
- const thinking = thinkingSignature === "reasoning_content" ? sanitizeTransportPayloadText(block.thinking) : block.thinking;
207
- if (thinkingSignature === "reasoning_content") {
208
- if (allowReasoningContentReplay) {
209
- blocks.push({
210
- type: "thinking",
211
- thinking,
212
- signature: thinkingSignature
213
- });
214
- reasoningContent.push(thinking);
215
- }
216
- continue;
217
- }
218
- blocks.push({
219
- type: "thinking",
220
- thinking,
221
- signature: thinkingSignature
222
- });
223
- }
224
- continue;
225
- }
226
- if (block.type === "toolCall") blocks.push({
227
- type: "tool_use",
228
- id: block.id,
229
- name: isOAuthToken ? toClaudeCodeToolName(block.name) : block.name,
230
- input: coerceTransportToolCallArguments(block.arguments)
231
- });
232
- }
233
- if (blocks.length === 0 && omittedThinking) blocks.push({
234
- type: "text",
235
- text: ANTHROPIC_OMITTED_REASONING_TEXT
236
- });
237
- if (blocks.length > 0) {
238
- const assistantMsg = {
239
- role: "assistant",
240
- content: blocks
241
- };
242
- if (reasoningContent.length > 0) assistantMsg.reasoning_content = reasoningContent.join("\n");
243
- else if (allowReasoningContentReplay) blocks.unshift({
244
- type: "thinking",
245
- thinking: "",
246
- signature: "reasoning_content"
247
- });
248
- params.push(assistantMsg);
249
- }
250
- continue;
251
- }
252
- if (msg.role === "toolResult") {
253
- const toolResult = msg;
254
- const toolResults = [{
255
- type: "tool_result",
256
- tool_use_id: toolResult.toolCallId,
257
- content: await convertContentBlocks(toolResult.content, model, imageBudget),
258
- is_error: toolResult.isError
259
- }];
260
- let j = i + 1;
261
- while (j < transformedMessages.length) {
262
- const nextMsg = transformedMessages.at(j);
263
- if (nextMsg?.role !== "toolResult") break;
264
- toolResults.push({
265
- type: "tool_result",
266
- tool_use_id: nextMsg.toolCallId,
267
- content: await convertContentBlocks(nextMsg.content, model, imageBudget),
268
- is_error: nextMsg.isError
269
- });
270
- j += 1;
271
- }
272
- i = j - 1;
273
- params.push({
274
- role: "user",
275
- content: toolResults
276
- });
277
- }
278
- }
279
- return params;
280
- }
281
84
  function ensureNonEmptyAnthropicMessages(messages) {
282
85
  return messages.length > 0 ? messages : [{
283
86
  role: "user",
284
87
  content: EMPTY_ANTHROPIC_MESSAGES_FALLBACK_TEXT
285
88
  }];
286
89
  }
287
- function convertAnthropicTools(tools, isOAuthToken) {
288
- const projection = projectAnthropicTools(tools ?? [], (name) => isOAuthToken ? toClaudeCodeToolName(name) : name);
289
- const converted = [];
290
- for (const tool of projection.tools) converted.push({
291
- name: tool.wireName,
292
- description: tool.description,
293
- input_schema: tool.inputSchema
294
- });
295
- return {
296
- projection,
297
- tools: converted
298
- };
299
- }
300
- function parseAnthropicToolCallArguments(inputJson) {
301
- return coerceTransportToolCallArguments(parseJsonObjectPreservingUnsafeIntegers(inputJson) ?? parseStreamingJson(inputJson));
302
- }
303
90
  const DEFAULT_ANTHROPIC_BASE_URL = "https://api.anthropic.com";
304
91
  /** Resolve the effective Anthropic API base URL from model or environment. */
305
92
  function resolveAnthropicBaseUrl(baseUrl) {
@@ -402,12 +189,13 @@ async function* parseAnthropicSseBody(body, signal) {
402
189
  function createAnthropicMessagesClient(params) {
403
190
  const url = resolveAnthropicMessagesUrl(params.baseURL);
404
191
  return { messages: { async stream(body, options) {
405
- const headers = mergeTransportHeaders({
192
+ const headers = new Headers(mergeTransportHeaders({
406
193
  "content-type": "application/json",
407
194
  "anthropic-version": "2023-06-01",
408
195
  ...params.apiKey ? { "x-api-key": params.apiKey } : {},
409
196
  ...params.authToken ? { authorization: `Bearer ${params.authToken}` } : {}
410
- }, params.defaultHeaders);
197
+ }, params.defaultHeaders));
198
+ for (const [name, value] of Object.entries(options?.headers ?? {})) headers.set(name, value);
411
199
  const response = await params.fetch(url, {
412
200
  method: "POST",
413
201
  headers,
@@ -421,7 +209,7 @@ function createAnthropicMessagesClient(params) {
421
209
  } } };
422
210
  }
423
211
  function formatAnthropicMessagesHttpError(response, detail) {
424
- const retryAfterSeconds = parseRetryAfterSeconds(response.headers);
212
+ const retryAfterSeconds = parseRetryAfterHeadersSeconds(response.headers);
425
213
  const retryAfterSuffix = Number.isFinite(retryAfterSeconds) ? `; Retry-After: ${Math.ceil(retryAfterSeconds ?? 0)} seconds` : "";
426
214
  return `HTTP ${response.status}: ${detail || "Anthropic Messages request failed"}${retryAfterSuffix}`;
427
215
  }
@@ -440,6 +228,7 @@ async function readAnthropicMessagesErrorBodySnippet(response) {
440
228
  }
441
229
  function createAnthropicTransportClient(params) {
442
230
  const { model, context, apiKey, options } = params;
231
+ const optionHeaders = resolveOpencodeSessionHeaders(model, options);
443
232
  const needsInterleavedBeta = (options?.interleavedThinking ?? true) && !supportsClaudeAdaptiveThinking(model);
444
233
  const fetch = isKimiAnthropicProvider(model.provider) && options?.thinkingEnabled === true ? buildGuardedModelFetch(model, void 0, { sanitizeSse: false }) : buildGuardedModelFetch(model);
445
234
  if (model.provider === "github-copilot") {
@@ -453,7 +242,7 @@ function createAnthropicTransportClient(params) {
453
242
  accept: "application/json",
454
243
  "anthropic-dangerous-direct-browser-access": "true",
455
244
  ...betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}
456
- }, model.headers, getAiTransportHost().buildCopilotDynamicHeaders(context.messages), options?.headers),
245
+ }, model.headers, getAiTransportHost().buildCopilotDynamicHeaders(context.messages), optionHeaders),
457
246
  fetch
458
247
  }),
459
248
  isOAuthToken: false
@@ -470,7 +259,7 @@ function createAnthropicTransportClient(params) {
470
259
  accept: "application/json",
471
260
  "anthropic-dangerous-direct-browser-access": "true",
472
261
  ...betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}
473
- }, omitFoundryBearerCredentialHeaders(model.headers), options?.headers),
262
+ }, omitFoundryBearerCredentialHeaders(model.headers), optionHeaders),
474
263
  fetch
475
264
  }),
476
265
  isOAuthToken: false
@@ -491,7 +280,7 @@ function createAnthropicTransportClient(params) {
491
280
  ...betaHeader ? { "anthropic-beta": betaHeader } : {},
492
281
  "user-agent": `claude-cli/${ANTHROPIC_CLAUDE_CODE_VERSION}`,
493
282
  "x-app": "cli"
494
- }, model.headers, options?.headers),
283
+ }, model.headers, optionHeaders),
495
284
  fetch
496
285
  }),
497
286
  isOAuthToken: true
@@ -499,45 +288,39 @@ function createAnthropicTransportClient(params) {
499
288
  }
500
289
  if (useAnthropicServerSideFallback(model)) betaFeatures.push(ANTHROPIC_SERVER_SIDE_FALLBACK_BETA);
501
290
  const betaHeader = buildAnthropicBetaHeader(model, betaFeatures, { oauth: false });
291
+ const defaultHeaders = mergeTransportHeaders({
292
+ accept: "application/json",
293
+ "anthropic-dangerous-direct-browser-access": "true",
294
+ ...betaHeader ? { "anthropic-beta": betaHeader } : {}
295
+ }, model.headers, optionHeaders);
502
296
  return {
503
297
  client: createAnthropicMessagesClient({
504
298
  apiKey,
505
299
  baseURL: model.baseUrl,
506
- defaultHeaders: mergeTransportHeaders({
507
- accept: "application/json",
508
- "anthropic-dangerous-direct-browser-access": "true",
509
- ...betaHeader ? { "anthropic-beta": betaHeader } : {}
510
- }, model.headers, options?.headers),
300
+ defaultHeaders,
511
301
  fetch
512
302
  }),
513
- isOAuthToken: false
303
+ isOAuthToken: false,
304
+ directApiKeyBetaHeader: isDirectAnthropicModel(model) ? new Headers(defaultHeaders).get("anthropic-beta") ?? "" : void 0
514
305
  };
515
306
  }
516
307
  async function buildAnthropicParams(model, context, isOAuthToken, options) {
517
- const mandatoryAdaptiveThinking = requiresClaudeAdaptiveThinking(model);
518
- const replayThinkingEnabled = mandatoryAdaptiveThinking || options?.thinkingEnabled === true;
308
+ const replayThinkingEnabled = requiresClaudeAdaptiveThinking(model) || options?.thinkingEnabled === true;
519
309
  const maxTokens = resolveAnthropicMessagesMaxTokens({
520
310
  modelContextWindow: model.contextWindow,
521
311
  modelMaxTokens: model.maxTokens,
522
312
  requestedMaxTokens: options?.maxTokens
523
313
  });
524
314
  if (maxTokens === void 0) throw new Error(`Anthropic Messages transport requires a positive maxTokens value for ${model.provider}/${model.id}`);
525
- const payloadPolicy = resolveAnthropicPayloadPolicy({
526
- provider: model.provider,
527
- api: model.api,
528
- baseUrl: model.baseUrl,
529
- cacheRetention: options?.cacheRetention,
530
- enableCacheControl: true
531
- }, model);
532
- const cacheBreakpointOptOutMessageIndexes = /* @__PURE__ */ new Set();
315
+ const { cacheControl, supportsCacheControlOnTools } = resolveAnthropicCacheOptions(model, options?.cacheRetention);
533
316
  const replayPlan = buildAnthropicReplayPlan(context.messages, model, {
534
317
  enabled: !isOAuthToken && options?.anthropicServerCompaction === true,
535
318
  authProfileId: options?.authProfileId,
536
319
  sessionId: options?.sessionId
537
320
  });
538
- const messages = await convertAnthropicMessages(replayPlan.messages, model, isOAuthToken, {
321
+ const messages = await convertAnthropicMessages(transformTransportMessages(replayPlan.messages, model, normalizeAnthropicToolCallId), model, isOAuthToken, {
322
+ profile: "transport",
539
323
  allowReasoningContentReplay: supportsReasoningContentReplay(model),
540
- cacheBreakpointOptOutMessageIndexes,
541
324
  compaction: replayPlan.compaction,
542
325
  replayThinkingEnabled
543
326
  });
@@ -548,54 +331,18 @@ async function buildAnthropicParams(model, context, isOAuthToken, options) {
548
331
  stream: true
549
332
  };
550
333
  if (!isOAuthToken && useAnthropicServerSideFallback(model)) params.fallbacks = ANTHROPIC_SERVER_SIDE_FALLBACKS;
551
- if (isOAuthToken) params.system = [
552
- {
553
- type: "text",
554
- text: ANTHROPIC_CLAUDE_CODE_BILLING_SYSTEM_BLOCK
555
- },
556
- {
557
- type: "text",
558
- text: "You are Claude Code, Anthropic's official CLI for Claude."
559
- },
560
- ...context.systemPrompt ? [{
561
- type: "text",
562
- text: sanitizeTransportPayloadText(context.systemPrompt)
563
- }] : []
564
- ];
565
- else if (context.systemPrompt) params.system = [{
566
- type: "text",
567
- text: sanitizeTransportPayloadText(context.systemPrompt)
568
- }];
569
- if (options?.temperature !== void 0 && !options.thinkingEnabled && !supportsClaudeNativeXhighEffort(model)) params.temperature = options.temperature;
570
- if (options?.stop !== void 0 && options.stop.length > 0) params.stop_sequences = options.stop;
571
- let toolProjection;
572
- if (context.tools) {
573
- const convertedTools = convertAnthropicTools(context.tools, isOAuthToken);
574
- toolProjection = convertedTools.projection;
575
- if (convertedTools.tools.length > 0) params.tools = convertedTools.tools;
576
- }
577
- if (mandatoryAdaptiveThinking || model.reasoning || supportsClaudeAdaptiveThinking(model)) {
578
- if (mandatoryAdaptiveThinking || options?.thinkingEnabled) {
579
- if (supportsClaudeAdaptiveThinking(model)) {
580
- params.thinking = {
581
- type: "adaptive",
582
- display: options?.thinkingDisplay ?? "summarized"
583
- };
584
- const effort = options?.effort ?? (mandatoryAdaptiveThinking ? "high" : void 0);
585
- if (effort) params.output_config = { effort };
586
- } else params.thinking = {
587
- type: "enabled",
588
- budget_tokens: options?.thinkingBudgetTokens ?? 1024
589
- };
590
- } else if (options?.thinkingEnabled === false) params.thinking = { type: "disabled" };
591
- }
592
- if (options?.metadata && typeof options.metadata.user_id === "string") params.metadata = { user_id: options.metadata.user_id };
593
- if (options?.toolChoice) {
594
- const normalizedToolChoice = normalizeAnthropicToolChoice(replayThinkingEnabled, options.toolChoice);
595
- const projectedToolChoice = toolProjection ? reconcileAnthropicToolChoice(normalizedToolChoice, toolProjection) : normalizedToolChoice;
596
- if (projectedToolChoice) params.tool_choice = projectedToolChoice;
597
- }
598
- applyAnthropicPayloadPolicyToParams(params, payloadPolicy, cacheBreakpointOptOutMessageIndexes);
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);
599
346
  return {
600
347
  params,
601
348
  toolProjection,
@@ -630,7 +377,9 @@ function resolveAnthropicTransportOptions(model, options, apiKey) {
630
377
  toolChoice: options?.toolChoice,
631
378
  thinkingBudgets: options?.thinkingBudgets,
632
379
  reasoning,
633
- ...options?.anthropicServerCompaction === true ? { anthropicServerCompaction: true } : {},
380
+ anthropicServerCompaction: options?.anthropicServerCompaction,
381
+ anthropicCompactThreshold: options?.anthropicCompactThreshold,
382
+ cacheTtlPruning: options?.cacheTtlPruning,
634
383
  ...options?.authProfileId ? { authProfileId: options.authProfileId } : {}
635
384
  });
636
385
  if (reasoning === "off") {
@@ -661,27 +410,15 @@ function createAnthropicMessagesTransportStreamFn() {
661
410
  const options = rawOptions;
662
411
  const { eventStream, stream } = createWritableTransportEventStream();
663
412
  (async () => {
664
- const output = {
665
- role: "assistant",
666
- content: [],
667
- api: "anthropic-messages",
668
- provider: model.provider,
669
- model: model.id,
670
- usage: createEmptyTransportUsage(),
671
- stopReason: "stop",
672
- timestamp: Date.now()
673
- };
674
- const refusalBuffer = usesClaudeStreamingRefusalContract(model) ? createDeferredEventBuffer(stream, () => notifyLlmRequestActivity(options?.signal)) : void 0;
675
- const eventSink = refusalBuffer ?? stream;
676
- let costModel = model;
677
- let messageStartPromptUsage;
413
+ const output = createAssistantOutput(model, "anthropic-messages");
414
+ const refusalBuffer = usesClaudeStreamingRefusalContract(model) ? createDeferredEventBuffer(stream) : void 0;
678
415
  let usedCompactionReplay = false;
679
416
  try {
680
417
  const apiKey = options?.apiKey ?? getEnvApiKey(model.provider) ?? "";
681
418
  if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
682
419
  const transportOptions = resolveAnthropicTransportOptions(model, options, apiKey);
683
420
  const requestContext = prepareClaudeNoPrefillRequestContext(model, context);
684
- const { client, isOAuthToken } = createAnthropicTransportClient({
421
+ const { client, isOAuthToken, directApiKeyBetaHeader } = createAnthropicTransportClient({
685
422
  model,
686
423
  context: requestContext,
687
424
  apiKey,
@@ -691,13 +428,19 @@ function createAnthropicMessagesTransportStreamFn() {
691
428
  usedCompactionReplay = builtParams.usedCompactionReplay;
692
429
  let params = builtParams.params;
693
430
  const toolProjection = builtParams.toolProjection;
431
+ applyAnthropicContextManagementToRequest(params, model, transportOptions, directApiKeyBetaHeader);
694
432
  const nextParams = await transportOptions.onPayload?.(params, model);
695
433
  if (nextParams !== void 0) params = nextParams;
696
434
  applyClaudeRequestContract(params, model);
435
+ const betaHeader = resolveAnthropicContextManagementBetaHeader(params, directApiKeyBetaHeader);
436
+ const bindingHeaders = applyAnthropicThinkingBindingControls(params, betaHeader) ?? (betaHeader !== void 0 ? { "anthropic-beta": betaHeader } : void 0);
697
437
  const { response, stream: anthropicStream } = await client.messages.stream({
698
438
  ...params,
699
439
  stream: true
700
- }, transportOptions.signal ? { signal: transportOptions.signal } : void 0);
440
+ }, {
441
+ signal: transportOptions.signal,
442
+ headers: bindingHeaders
443
+ });
701
444
  await notifyProviderHttpResponse({
702
445
  options: transportOptions,
703
446
  response,
@@ -707,429 +450,17 @@ function createAnthropicMessagesTransportStreamFn() {
707
450
  const detail = await readAnthropicMessagesErrorBodySnippet(response);
708
451
  throw new Error(formatAnthropicMessagesHttpError(response, detail));
709
452
  }
710
- const blocks = output.content;
711
- const blockIndexes = /* @__PURE__ */ new Map();
712
- const toolArgumentPreviewSchedules = /* @__PURE__ */ new WeakMap();
713
- const sealedToolCalls = [];
714
- const compactionCapture = createCompactionCapture(output, model, transportOptions);
715
- const pendingThinkingSignatures = /* @__PURE__ */ new Map();
716
- const allowReasoningContentReplay = supportsReasoningContentReplay(model);
717
- const reasoningContentThinkingBlocks = /* @__PURE__ */ new Map();
718
- const reasoningContentTextBlocks = /* @__PURE__ */ new Map();
719
- let sawMessageStop = false;
720
- const pendingTextEnds = [];
721
- const flushPendingTextEnds = () => {
722
- for (const event of pendingTextEnds) eventSink.push(event);
723
- pendingTextEnds.length = 0;
724
- };
725
- const eventIndexKey = (eventIndex) => typeof eventIndex === "number" ? eventIndex : -1;
726
- const appendReasoningContentThinkingDelta = (eventIndex, rawText) => {
727
- if (typeof rawText !== "string") return false;
728
- const text = sanitizeTransportPayloadText(rawText);
729
- if (text.length === 0) return false;
730
- const key = eventIndexKey(eventIndex);
731
- let contentIndex = reasoningContentThinkingBlocks.get(key);
732
- let block = contentIndex === void 0 ? void 0 : output.content[contentIndex];
733
- if (!block || block.type !== "thinking") {
734
- block = {
735
- type: "thinking",
736
- thinking: "",
737
- thinkingSignature: "reasoning_content"
738
- };
739
- output.content.push(block);
740
- contentIndex = output.content.length - 1;
741
- reasoningContentThinkingBlocks.set(key, contentIndex);
742
- eventSink.push({
743
- type: "thinking_start",
744
- contentIndex,
745
- partial: output
746
- });
747
- }
748
- if (contentIndex === void 0) return false;
749
- block.thinking += text;
750
- block.thinkingSignature = "reasoning_content";
751
- eventSink.push({
752
- type: "thinking_delta",
753
- contentIndex,
754
- delta: text,
755
- partial: output
756
- });
757
- return true;
758
- };
759
- const appendReasoningContentTextDelta = (eventIndex, rawText) => {
760
- if (typeof rawText !== "string") return false;
761
- const text = sanitizeTransportPayloadText(rawText);
762
- if (text.length === 0) return false;
763
- const key = eventIndexKey(eventIndex);
764
- let contentIndex = reasoningContentTextBlocks.get(key);
765
- let block = contentIndex === void 0 ? void 0 : output.content[contentIndex];
766
- if (!block || block.type !== "text") {
767
- block = {
768
- type: "text",
769
- text: ""
770
- };
771
- output.content.push(block);
772
- contentIndex = output.content.length - 1;
773
- reasoningContentTextBlocks.set(key, contentIndex);
774
- eventSink.push({
775
- type: "text_start",
776
- contentIndex,
777
- partial: output
778
- });
779
- }
780
- if (contentIndex === void 0) return false;
781
- block.text += text;
782
- eventSink.push({
783
- type: "text_delta",
784
- contentIndex,
785
- delta: text,
786
- partial: output
787
- });
788
- return true;
789
- };
790
- const finishReasoningContentSidecars = (eventIndex) => {
791
- const key = eventIndexKey(eventIndex);
792
- const thinkingContentIndex = reasoningContentThinkingBlocks.get(key);
793
- if (thinkingContentIndex !== void 0) {
794
- reasoningContentThinkingBlocks.delete(key);
795
- const block = output.content[thinkingContentIndex];
796
- if (block?.type === "thinking") eventSink.push({
797
- type: "thinking_end",
798
- contentIndex: thinkingContentIndex,
799
- content: block.thinking,
800
- partial: output
801
- });
802
- }
803
- const textContentIndex = reasoningContentTextBlocks.get(key);
804
- if (textContentIndex === void 0) return;
805
- reasoningContentTextBlocks.delete(key);
806
- const block = output.content[textContentIndex];
807
- if (block?.type === "text") eventSink.push({
808
- type: "text_end",
809
- contentIndex: textContentIndex,
810
- content: block.text,
811
- partial: output
812
- });
813
- };
814
- for await (const event of anthropicStream) {
815
- if (event.type === "error") {
816
- const error = event.error;
817
- throw new Error(error?.message || "Anthropic Messages stream failed");
818
- }
819
- if (event.type === "message_start") {
820
- const message = event.message;
821
- const usage = message?.usage ?? {};
822
- output.responseId = typeof message?.id === "string" ? message.id : void 0;
823
- output.responseModel = typeof message?.model === "string" ? message.model : void 0;
824
- messageStartPromptUsage = applyAnthropicMessageStartUsage(output.usage, usage);
825
- calculateCost(costModel, output.usage);
826
- eventSink.push({
827
- type: "start",
828
- partial: output
829
- });
830
- continue;
831
- }
832
- if (event.type === "message_stop") {
833
- sawMessageStop = true;
834
- continue;
835
- }
836
- if (event.type === "content_block_start") {
837
- const contentBlock = event.content_block;
838
- const index = typeof event.index === "number" ? event.index : -1;
839
- if (transportOptions.anthropicServerCompaction === true && compactionCapture.begin(index, contentBlock, output.content.length)) continue;
840
- const fallbackBoundary = refusalBuffer ? readAnthropicFallbackBoundary(contentBlock) : null;
841
- if (fallbackBoundary) {
842
- refusalBuffer?.discard();
843
- sealedToolCalls.length = 0;
844
- pendingTextEnds.length = 0;
845
- blockIndexes.clear();
846
- pendingThinkingSignatures.clear();
847
- applyAnthropicFallbackBoundary({
848
- output,
849
- boundary: fallbackBoundary,
850
- provider: model.provider
851
- });
852
- costModel = {
853
- ...model,
854
- cost: resolveAnthropicFallbackServingModelCost({
855
- requestedModelId: model.id,
856
- servingModelId: fallbackBoundary.toModel,
857
- requestedCost: model.cost
858
- })
859
- };
860
- calculateCost(costModel, output.usage);
861
- eventSink.push({
862
- type: "start",
863
- partial: output
864
- });
865
- for (const [i, block] of output.content.entries()) {
866
- if (block.type !== "text") continue;
867
- delete block.index;
868
- eventSink.push({
869
- type: "text_start",
870
- contentIndex: i,
871
- partial: output
872
- });
873
- if (block.text) eventSink.push({
874
- type: "text_delta",
875
- contentIndex: i,
876
- delta: block.text,
877
- partial: output
878
- });
879
- pendingTextEnds.push({
880
- type: "text_end",
881
- contentIndex: i,
882
- content: block.text,
883
- partial: output
884
- });
885
- }
886
- continue;
887
- }
888
- pendingThinkingSignatures.delete(index);
889
- if (contentBlock?.type === "text") {
890
- const text = typeof contentBlock.text === "string" ? sanitizeTransportPayloadText(contentBlock.text) : "";
891
- const block = {
892
- type: "text",
893
- text,
894
- index
895
- };
896
- output.content.push(block);
897
- const contentIndex = output.content.length - 1;
898
- blockIndexes.set(index, contentIndex);
899
- eventSink.push({
900
- type: "text_start",
901
- contentIndex,
902
- partial: output
903
- });
904
- if (text.length > 0) eventSink.push({
905
- type: "text_delta",
906
- contentIndex,
907
- delta: text,
908
- partial: output
909
- });
910
- continue;
911
- }
912
- if (contentBlock?.type === "thinking") {
913
- const thinking = typeof contentBlock.thinking === "string" ? contentBlock.thinking : "";
914
- const block = {
915
- type: "thinking",
916
- thinking,
917
- thinkingSignature: typeof contentBlock.signature === "string" ? contentBlock.signature : "",
918
- index
919
- };
920
- output.content.push(block);
921
- const contentIndex = output.content.length - 1;
922
- blockIndexes.set(index, contentIndex);
923
- eventSink.push({
924
- type: "thinking_start",
925
- contentIndex,
926
- partial: output
927
- });
928
- if (thinking.length > 0) eventSink.push({
929
- type: "thinking_delta",
930
- contentIndex,
931
- delta: thinking,
932
- partial: output
933
- });
934
- continue;
935
- }
936
- if (contentBlock?.type === "redacted_thinking") {
937
- const block = {
938
- type: "thinking",
939
- thinking: "[Reasoning redacted]",
940
- thinkingSignature: typeof contentBlock.data === "string" ? contentBlock.data : "",
941
- redacted: true,
942
- index
943
- };
944
- output.content.push(block);
945
- blockIndexes.set(index, output.content.length - 1);
946
- eventSink.push({
947
- type: "thinking_start",
948
- contentIndex: output.content.length - 1,
949
- partial: output
950
- });
951
- continue;
952
- }
953
- if (contentBlock?.type === "tool_use") {
954
- tagPendingCommentaryText(output.content);
955
- flushPendingTextEnds();
956
- const block = {
957
- type: "toolCall",
958
- id: typeof contentBlock.id === "string" ? contentBlock.id : "",
959
- name: typeof contentBlock.name === "string" ? isOAuthToken ? resolveOriginalAnthropicToolName(contentBlock.name, toolProjection) : contentBlock.name : "",
960
- arguments: contentBlock.input && typeof contentBlock.input === "object" ? contentBlock.input : {},
961
- partialJson: "",
962
- index
963
- };
964
- output.content.push(block);
965
- blockIndexes.set(index, output.content.length - 1);
966
- toolArgumentPreviewSchedules.set(block, createToolArgumentPreviewSchedule());
967
- eventSink.push({
968
- type: "toolcall_start",
969
- contentIndex: output.content.length - 1,
970
- partial: output
971
- });
972
- }
973
- continue;
974
- }
975
- if (event.type === "content_block_delta") {
976
- const delta = event.delta;
977
- const eventIndex = typeof event.index === "number" ? event.index : void 0;
978
- if (eventIndex !== void 0 && compactionCapture.delta(eventIndex, delta)) continue;
979
- let index = eventIndex === void 0 ? void 0 : blockIndexes.get(eventIndex);
980
- let block = index === void 0 ? void 0 : blocks[index];
981
- if (allowReasoningContentReplay) {
982
- const appendedThinking = appendReasoningContentThinkingDelta(event.index, delta?.reasoning_content);
983
- 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";
984
- let appendedContent = false;
985
- if (!hasNativeAnthropicDelta && typeof delta?.content === "string" && delta.content.length > 0) {
986
- const text = sanitizeTransportPayloadText(delta.content);
987
- if (text.length > 0) {
988
- if (block?.type === "text" && index !== void 0) {
989
- block.text += text;
990
- eventSink.push({
991
- type: "text_delta",
992
- contentIndex: index,
993
- delta: text,
994
- partial: output
995
- });
996
- appendedContent = true;
997
- } else appendedContent = appendReasoningContentTextDelta(event.index, text);
998
- }
999
- }
1000
- if ((appendedThinking || appendedContent) && !hasNativeAnthropicDelta) continue;
1001
- }
1002
- if (!block && delta?.type === "text_delta" && typeof delta.text === "string") {
1003
- block = {
1004
- type: "text",
1005
- text: "",
1006
- index: typeof event.index === "number" ? event.index : blocks.length
1007
- };
1008
- output.content.push(block);
1009
- index = output.content.length - 1;
1010
- if (typeof event.index === "number") blockIndexes.set(event.index, index);
1011
- eventSink.push({
1012
- type: "text_start",
1013
- contentIndex: index,
1014
- partial: output
1015
- });
1016
- }
1017
- if (index === void 0) continue;
1018
- if (block?.type === "text" && delta?.type === "text_delta" && typeof delta.text === "string") {
1019
- block.text += delta.text;
1020
- eventSink.push({
1021
- type: "text_delta",
1022
- contentIndex: index,
1023
- delta: delta.text,
1024
- partial: output
1025
- });
1026
- continue;
1027
- }
1028
- if (block?.type === "thinking" && delta?.type === "thinking_delta" && typeof delta.thinking === "string") {
1029
- block.thinking += delta.thinking;
1030
- eventSink.push({
1031
- type: "thinking_delta",
1032
- contentIndex: index,
1033
- delta: delta.thinking,
1034
- partial: output
1035
- });
1036
- continue;
1037
- }
1038
- if (block?.type === "toolCall" && delta?.type === "input_json_delta" && typeof delta.partial_json === "string") {
1039
- const partialJson = `${block.partialJson ?? ""}${delta.partial_json}`;
1040
- block.partialJson = partialJson;
1041
- if (toolArgumentPreviewSchedules.get(block)?.(partialJson.length)) block.arguments = parseAnthropicToolCallArguments(partialJson);
1042
- eventSink.push({
1043
- type: "toolcall_delta",
1044
- contentIndex: index,
1045
- delta: delta.partial_json,
1046
- partial: output
1047
- });
1048
- continue;
1049
- }
1050
- if (block?.type === "thinking" && delta?.type === "signature_delta" && typeof delta.signature === "string") {
1051
- const signatureIndex = eventIndexKey(event.index);
1052
- const pendingSignature = pendingThinkingSignatures.get(signatureIndex);
1053
- if (pendingSignature === void 0) {
1054
- block.thinkingSignature = "";
1055
- pendingThinkingSignatures.set(signatureIndex, delta.signature);
1056
- } else pendingThinkingSignatures.set(signatureIndex, pendingSignature + delta.signature);
1057
- }
1058
- continue;
1059
- }
1060
- if (event.type === "content_block_stop") {
1061
- const eventIndex = typeof event.index === "number" ? event.index : void 0;
1062
- if (eventIndex !== void 0 && compactionCapture.complete(eventIndex)) continue;
1063
- const pendingSignature = eventIndex === void 0 ? void 0 : pendingThinkingSignatures.get(eventIndex);
1064
- if (eventIndex !== void 0) pendingThinkingSignatures.delete(eventIndex);
1065
- const index = eventIndex === void 0 ? void 0 : blockIndexes.get(eventIndex);
1066
- const block = index === void 0 ? void 0 : blocks[index];
1067
- if (eventIndex === void 0 || index === void 0 || !block) {
1068
- finishReasoningContentSidecars(event.index);
1069
- continue;
1070
- }
1071
- blockIndexes.delete(eventIndex);
1072
- delete block.index;
1073
- if (block.type === "text") {
1074
- pendingTextEnds.push({
1075
- type: "text_end",
1076
- contentIndex: index,
1077
- content: block.text,
1078
- partial: output
1079
- });
1080
- finishReasoningContentSidecars(event.index);
1081
- continue;
1082
- }
1083
- if (block.type === "thinking") {
1084
- if (pendingSignature !== void 0) block.thinkingSignature = pendingSignature;
1085
- eventSink.push({
1086
- type: "thinking_end",
1087
- contentIndex: index,
1088
- content: block.thinking,
1089
- partial: output
1090
- });
1091
- finishReasoningContentSidecars(event.index);
1092
- continue;
1093
- }
1094
- if (block.type === "toolCall") {
1095
- sealedToolCalls.push({
1096
- block,
1097
- contentIndex: index
1098
- });
1099
- finishReasoningContentSidecars(event.index);
1100
- }
1101
- continue;
1102
- }
1103
- if (event.type === "message_delta") {
1104
- const delta = event.delta;
1105
- const usage = event.usage;
1106
- if (delta?.stop_reason) {
1107
- if (delta.stop_reason === "refusal") applyAnthropicRefusal(output, delta.stop_details, model.provider);
1108
- else output.stopReason = mapAnthropicStopReason(delta.stop_reason);
1109
- }
1110
- applyAnthropicMessageDeltaUsage(output.usage, usage, messageStartPromptUsage);
1111
- calculateCost(costModel, output.usage);
1112
- if (output.stopReason === "toolUse" || output.content.some((block) => block.type === "toolCall")) tagPendingCommentaryText(output.content);
1113
- flushPendingTextEnds();
1114
- }
1115
- }
1116
- if (isDirectAnthropicModel(model) && !sawMessageStop) throw new Error("Anthropic stream ended before message_stop");
1117
- if (transportOptions.signal?.aborted) throw transportAbortError(transportOptions.signal);
1118
- if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
1119
- if ([...blockIndexes.values()].some((index) => blocks[index]?.type === "toolCall")) throw new Error("Provider completed stream with an incomplete tool call");
1120
- finalizeTerminalToolCallArguments(sealedToolCalls.map(({ block }) => block), (block) => block.partialJson && block.partialJson.length > 0 ? block.partialJson : block.arguments);
1121
- for (const sealed of sealedToolCalls) {
1122
- delete sealed.block.partialJson;
1123
- eventSink.push({
1124
- type: "toolcall_end",
1125
- contentIndex: sealed.contentIndex,
1126
- toolCall: sealed.block,
1127
- partial: output
1128
- });
1129
- }
1130
- refusalBuffer?.flush();
1131
- if (output.stopReason === "toolUse" || output.content.some((block) => block.type === "toolCall")) tagPendingCommentaryText(output.content);
1132
- 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
+ });
1133
464
  finalizeTransportStream({
1134
465
  stream,
1135
466
  output
@@ -1155,63 +486,6 @@ function createAnthropicMessagesTransportStreamFn() {
1155
486
  };
1156
487
  }
1157
488
  //#endregion
1158
- //#region packages/ai/src/transports/model-max-tokens-params.ts
1159
- /**
1160
- * Max-token parameter normalization across provider/native naming variants.
1161
- * Callers canonicalize aliases before dispatch so payloads cannot carry
1162
- * conflicting limits.
1163
- */
1164
- const MAX_TOKENS_PARAM_KEYS = [
1165
- "maxTokens",
1166
- "max_completion_tokens",
1167
- "max_tokens"
1168
- ];
1169
- /** Resolve the first supported max-token parameter present in a params object. */
1170
- function resolveMaxTokensParam(params) {
1171
- if (!params) return;
1172
- for (const key of MAX_TOKENS_PARAM_KEYS) {
1173
- const resolved = asNonNegativeFiniteNumber(params[key]);
1174
- if (resolved !== void 0) return resolved;
1175
- }
1176
- }
1177
- /**
1178
- * Canonicalize merged params to `maxTokens`, preserving source precedence from
1179
- * left to right across the provided source objects.
1180
- */
1181
- function canonicalizeMaxTokensParam(params) {
1182
- let resolved;
1183
- for (const source of params.sources) {
1184
- const sourceValue = resolveMaxTokensParam(source);
1185
- if (sourceValue !== void 0) resolved = sourceValue;
1186
- }
1187
- if (resolved === void 0) return;
1188
- for (const key of MAX_TOKENS_PARAM_KEYS) delete params.merged[key];
1189
- params.merged.maxTokens = resolved;
1190
- }
1191
- //#endregion
1192
- //#region packages/ai/src/transports/model-transport-url.ts
1193
- /**
1194
- * Debug formatting helpers for model transport endpoints.
1195
- * Keeps logs useful without exposing credentials, request params, or fragments.
1196
- */
1197
- /** Return a sanitized URL suitable for logs and diagnostics. */
1198
- function formatModelTransportDebugUrl(rawUrl) {
1199
- try {
1200
- const parsed = new URL(rawUrl);
1201
- parsed.username = "";
1202
- parsed.password = "";
1203
- parsed.search = "";
1204
- parsed.hash = "";
1205
- return parsed.toString();
1206
- } catch {
1207
- return "<invalid-url>";
1208
- }
1209
- }
1210
- /** Format a configured base URL for debug output, or the implicit default. */
1211
- function formatModelTransportDebugBaseUrl(rawUrl) {
1212
- return rawUrl ? formatModelTransportDebugUrl(rawUrl) : "default";
1213
- }
1214
- //#endregion
1215
489
  //#region packages/ai/src/transports/openai-compatible-conversation-turn.ts
1216
490
  /**
1217
491
  * OpenAI-compatible conversation turn detector.
@@ -1248,488 +522,44 @@ function hasOpenAICompatibleConversationTurn(messages) {
1248
522
  });
1249
523
  }
1250
524
  //#endregion
1251
- //#region packages/ai/src/transports/openai-completions-string-content.ts
1252
- /**
1253
- * OpenAI Chat Completions compatibility helpers. Some providers only accept
1254
- * role/content messages with plain string content instead of text block arrays.
1255
- */
1256
- function flattenStringOnlyCompletionContent(content) {
1257
- if (!Array.isArray(content)) return content;
1258
- const textParts = [];
1259
- for (const item of content) {
1260
- if (!item || typeof item !== "object" || item.type !== "text" || typeof item.text !== "string") return content;
1261
- textParts.push(item.text);
1262
- }
1263
- return textParts.join("\n");
1264
- }
1265
- /** Flatten string-only text block content arrays into newline-joined strings. */
1266
- function flattenCompletionMessagesToStringContent(messages) {
1267
- return messages.map((message) => {
1268
- if (!message || typeof message !== "object") return message;
1269
- const content = message.content;
1270
- const flattenedContent = flattenStringOnlyCompletionContent(content);
1271
- if (flattenedContent === content) return message;
1272
- return {
1273
- ...message,
1274
- content: flattenedContent
1275
- };
1276
- });
1277
- }
1278
- /** Strip completion messages to role/content fields for strict providers. */
1279
- function stripCompletionMessagesToRoleContent(messages) {
1280
- return messages.map((message) => {
1281
- if (!message || typeof message !== "object" || Array.isArray(message)) return message;
1282
- const record = message;
1283
- const stripped = {};
1284
- if (Object.hasOwn(record, "role")) stripped.role = record.role;
1285
- if (Object.hasOwn(record, "content")) stripped.content = record.content;
1286
- return stripped;
1287
- });
1288
- }
1289
- //#endregion
1290
- //#region packages/ai/src/transports/openai-completions-host.ts
1291
- /**
1292
- * Chat Completions accepts Azure AI Foundry hosts in addition to traditional
1293
- * Azure OpenAI hosts. Do not replace this with isTraditionalAzureOpenAIHost,
1294
- * which intentionally excludes the .services.ai.azure.com Foundry suffix.
1295
- */
1296
- function isAzureOpenAICompatibleHost(hostname) {
1297
- return hostname.endsWith(".openai.azure.com") || hostname.endsWith(".services.ai.azure.com") || hostname.endsWith(".cognitiveservices.azure.com");
525
+ //#region packages/ai/src/transports/openai-completions-transport.ts
526
+ function assertOpenAICompletionsPayloadHasConversationTurn(params, model) {
527
+ const messages = params.messages;
528
+ if (!Array.isArray(messages) || hasOpenAICompatibleConversationTurn(messages)) return;
529
+ throw new Error(`OpenAI-compatible chat payload for ${model.provider}/${model.id} contains no non-empty user or assistant messages after compaction and transport transforms; refusing to send a system/tool-only request. Start a new user turn or repair the compacted session history.`);
1298
530
  }
1299
- //#endregion
1300
- //#region packages/ai/src/transports/openai-completions-replay.ts
1301
- function isGoogleOpenAICompatModel(model) {
1302
- const endpointClass = detectOpenAICompletionsCompat(model).capabilities.endpointClass;
1303
- return model.provider === "google" || endpointClass === "google-generative-ai" || endpointClass === "google-vertex";
1304
- }
1305
- function requiresGoogleCompatToolCallThoughtSignature(model) {
1306
- return isGoogleGemini3ProModel(model.id) || isGoogleGemini3FlashModel(model.id);
1307
- }
1308
- const GOOGLE_COMPAT_THOUGHT_SIGNATURE_ELLIPSIS_RE = /[\u2026]|\.\.\./;
1309
- const GOOGLE_COMPAT_THOUGHT_SIGNATURE_BASE64_RE = /^[A-Za-z0-9+/=]+$/;
1310
- function hasGoogleCompatThoughtSignatureTruncationFootprint(value) {
1311
- return GOOGLE_COMPAT_THOUGHT_SIGNATURE_ELLIPSIS_RE.test(value) || GOOGLE_COMPAT_THOUGHT_SIGNATURE_BASE64_RE.test(value) && value.length % 4 !== 0;
1312
- }
1313
- function injectToolCallThoughtSignatures(outgoingMessages, context, model) {
1314
- if (!isGoogleOpenAICompatModel(model)) return;
1315
- const sigById = /* @__PURE__ */ new Map();
1316
- const fallbackSig = requiresGoogleCompatToolCallThoughtSignature(model) ? GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP : void 0;
1317
- for (const msg of context.messages ?? []) {
1318
- if (msg.role !== "assistant") continue;
1319
- const source = msg;
1320
- if (!Array.isArray(source.content)) continue;
1321
- for (const block of source.content) {
1322
- if (block.type !== "toolCall") continue;
1323
- const id = block.id;
1324
- const sig = block.thoughtSignature;
1325
- if (typeof id === "string" && typeof sig === "string" && sig.length > 0) {
1326
- const isSameRoute = source.api === model.api && source.provider === model.provider && source.model === model.id;
1327
- if (!isSameRoute && !fallbackSig) continue;
1328
- sigById.set(id, isSameRoute ? sig : fallbackSig ?? sig);
1329
- }
1330
- }
1331
- }
1332
- if (sigById.size === 0 && !fallbackSig) return;
1333
- for (const message of outgoingMessages) {
1334
- const toolCalls = message.tool_calls;
1335
- if (!Array.isArray(toolCalls)) continue;
1336
- for (const toolCall of toolCalls) {
1337
- const id = toolCall.id;
1338
- if (typeof id !== "string") continue;
1339
- let sig = sigById.get(id) ?? fallbackSig;
1340
- if (typeof sig === "string" && sig.length > 0) {
1341
- if (hasGoogleCompatThoughtSignatureTruncationFootprint(sig.trim())) sig = fallbackSig;
531
+ const SSE_DONE_LINE_RE = /^data:[ \t]*\[DONE\][ \t]*$/i;
532
+ const SSE_DONE_MAX_LINE_CHARS = 1024;
533
+ function createSseDoneDetector() {
534
+ const decoder = new TextDecoder();
535
+ let line = "";
536
+ let lineOverflowed = false;
537
+ let sawDone = false;
538
+ const finishLine = () => {
539
+ if (!lineOverflowed && SSE_DONE_LINE_RE.test(line)) sawDone = true;
540
+ line = "";
541
+ lineOverflowed = false;
542
+ };
543
+ const observeText = (text) => {
544
+ for (const char of text) {
545
+ if (char === "\n" || char === "\r") {
546
+ finishLine();
547
+ continue;
1342
548
  }
1343
- if (typeof sig !== "string" || sig.length === 0) continue;
1344
- const extra = toolCall.extra_content && typeof toolCall.extra_content === "object" ? toolCall.extra_content : {};
1345
- toolCall.extra_content = extra;
1346
- const google = extra.google && typeof extra.google === "object" ? extra.google : {};
1347
- extra.google = google;
1348
- google.thought_signature = sig;
549
+ if (!lineOverflowed && line.length < SSE_DONE_MAX_LINE_CHARS) line += char;
550
+ else lineOverflowed = true;
1349
551
  }
1350
- }
1351
- }
1352
- const COMPLETIONS_REASONING_REPLAY_FIELDS = [
1353
- "reasoning_details",
1354
- "reasoning_content",
1355
- "reasoning",
1356
- "reasoning_text"
1357
- ];
1358
- function stripCompletionsReasoningReplayFields(record) {
1359
- for (const field of COMPLETIONS_REASONING_REPLAY_FIELDS) if (field in record) delete record[field];
1360
- }
1361
- function sanitizeOpenRouterReasoningReplayFields(record) {
1362
- const reasoningDetails = record.reasoning_details;
1363
- if (typeof reasoningDetails === "string") {
1364
- if (reasoningDetails.length > 0 && typeof record.reasoning !== "string") record.reasoning = reasoningDetails;
1365
- delete record.reasoning_details;
1366
- } else if (reasoningDetails !== void 0 && !Array.isArray(reasoningDetails)) delete record.reasoning_details;
1367
- if ("reasoning" in record && (typeof record.reasoning !== "string" || record.reasoning === "")) delete record.reasoning;
1368
- if ("reasoning_content" in record && (typeof record.reasoning_content !== "string" || record.reasoning_content === "")) delete record.reasoning_content;
1369
- const reasoningText = record.reasoning_text;
1370
- if (typeof reasoningText === "string" && reasoningText.length > 0 && typeof record.reasoning !== "string" && typeof record.reasoning_content !== "string") record.reasoning = reasoningText;
1371
- if ("reasoning_text" in record) delete record.reasoning_text;
1372
- }
1373
- function sanitizeReasoningContentReplayFields(record) {
1374
- if ("reasoning_content" in record && typeof record.reasoning_content !== "string") delete record.reasoning_content;
1375
- delete record.reasoning_details;
1376
- delete record.reasoning;
1377
- delete record.reasoning_text;
1378
- }
1379
- const REASONING_CONTENT_REPLAY_MODEL_IDS = /* @__PURE__ */ new Set([
1380
- "deepseek-v4-flash",
1381
- "deepseek-v4-pro",
1382
- "kimi-for-coding",
1383
- "kimi-k2.5",
1384
- "kimi-k2.6",
1385
- "kimi-k2.7-code",
1386
- "kimi-k2.7-code-highspeed",
1387
- "kimi-k3",
1388
- "kimi-k2-thinking",
1389
- "kimi-k2-thinking-turbo",
1390
- "mimo-v2-pro",
1391
- "mimo-v2-omni",
1392
- "mimo-v2.5",
1393
- "mimo-v2.5-pro",
1394
- "mimo-v2.6-pro"
1395
- ]);
1396
- const REASONING_CONTENT_REPLAY_TIER_SUFFIXES = [
1397
- "-free",
1398
- "-paid",
1399
- "-trial"
1400
- ];
1401
- function stripReasoningContentReplayTierSuffix(modelId) {
1402
- for (const suffix of REASONING_CONTENT_REPLAY_TIER_SUFFIXES) if (modelId.length > suffix.length && modelId.endsWith(suffix)) return modelId.slice(0, -suffix.length);
1403
- return modelId;
1404
- }
1405
- function getReasoningContentReplayModelIdCandidates(modelId) {
1406
- if (typeof modelId !== "string") return [];
1407
- const normalized = modelId.trim().toLowerCase();
1408
- if (!normalized) return [];
1409
- const parts = normalized.split("/").filter(Boolean);
1410
- const finalPart = parts[parts.length - 1] ?? normalized;
1411
- const candidates = [finalPart];
1412
- const colonParts = finalPart.split(":").filter(Boolean);
1413
- if (colonParts.length > 1) candidates.push(colonParts[0] ?? "", colonParts[colonParts.length - 1] ?? "");
1414
- const baseCount = candidates.length;
1415
- for (let index = 0; index < baseCount; index += 1) {
1416
- const candidate = candidates[index];
1417
- if (typeof candidate !== "string") continue;
1418
- const stripped = stripReasoningContentReplayTierSuffix(candidate);
1419
- if (stripped !== candidate) candidates.push(stripped);
1420
- }
1421
- return uniqueStrings(candidates.filter(Boolean));
1422
- }
1423
- function shouldPreserveReasoningContentReplay(model, compat) {
1424
- if (compat.requiresReasoningContentOnAssistantMessages || compat.thinkingFormat === "deepseek" || compat.thinkingFormat === "zai" || shouldTrustReasoningContentReplayMetadata(model)) return true;
1425
- return getReasoningContentReplayModelIdCandidates(model.id).some((modelId) => REASONING_CONTENT_REPLAY_MODEL_IDS.has(modelId));
1426
- }
1427
- function shouldPreserveOpenRouterReasoningReplay(model) {
1428
- if (model.provider !== "openrouter") return true;
1429
- const normalizedModelId = model.id.trim().toLowerCase();
1430
- return !(normalizedModelId.startsWith("anthropic/") || normalizedModelId.startsWith("x-ai/"));
1431
- }
1432
- function shouldTrustReasoningContentReplayMetadata(model) {
1433
- if (!model.reasoning) return false;
1434
- if (model.provider.trim().toLowerCase() === "openai") return false;
1435
- return shouldPreserveOpenRouterReasoningReplay(model);
1436
- }
1437
- function sanitizeCompletionsReasoningReplayFields(messages, options) {
1438
- if (!Array.isArray(messages)) return;
1439
- for (const msg of messages) {
1440
- if (!msg || typeof msg !== "object") continue;
1441
- const record = msg;
1442
- if (record.role !== "assistant") continue;
1443
- if (options.preserveOpenRouterReasoning) sanitizeOpenRouterReasoningReplayFields(record);
1444
- else if (options.preserveReasoningContent) sanitizeReasoningContentReplayFields(record);
1445
- else stripCompletionsReasoningReplayFields(record);
1446
- }
1447
- }
1448
- function applyCompletionsReplay(outgoingMessages, context, model, compat) {
1449
- injectToolCallThoughtSignatures(outgoingMessages, context, model);
1450
- sanitizeCompletionsReasoningReplayFields(outgoingMessages, {
1451
- preserveOpenRouterReasoning: compat.thinkingFormat === "openrouter" && shouldPreserveOpenRouterReasoningReplay(model),
1452
- preserveReasoningContent: shouldPreserveReasoningContentReplay(model, compat)
1453
- });
1454
- }
1455
- //#endregion
1456
- //#region packages/ai/src/transports/openai-completions-params.ts
1457
- function isKnownOpenAICompletionsEndpoint(model) {
1458
- if (!model.baseUrl.trim()) return true;
1459
- const endpointClass = resolveProviderEndpoint(model).endpointClass;
1460
- if (endpointClass === "openai-public" || endpointClass === "azure-openai") return true;
1461
- try {
1462
- return isAzureOpenAICompatibleHost(new URL(model.baseUrl).hostname.toLowerCase());
1463
- } catch {
1464
- return false;
1465
- }
1466
- }
1467
- function resolveOpenAICompletionsReasoningEffort(options) {
1468
- return options?.reasoningEffort ?? options?.reasoning ?? "high";
1469
- }
1470
- function resolveOpenAICompletionsMaxTokens(model, options) {
1471
- if (options?.maxTokens) return {
1472
- maxTokens: options.maxTokens,
1473
- clampToModelMaxTokens: true
1474
- };
1475
- const paramsMaxTokens = resolveMaxTokensParam(model.params);
1476
- if (paramsMaxTokens) return {
1477
- maxTokens: paramsMaxTokens,
1478
- clampToModelMaxTokens: false
1479
552
  };
1480
553
  return {
1481
- maxTokens: model.maxTokens,
1482
- clampToModelMaxTokens: false
1483
- };
1484
- }
1485
- function resolveOpenAICompletionsModelMaxTokens(model) {
1486
- return typeof model.maxTokens === "number" && Number.isFinite(model.maxTokens) && model.maxTokens > 0 ? Math.floor(model.maxTokens) : void 0;
1487
- }
1488
- const OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN = 1.25;
1489
- const OPENAI_COMPLETIONS_IMAGE_CHAR_ESTIMATE = 8e3;
1490
- function estimateOpenAICompletionsInputTokens(payload) {
1491
- let adjustedChars = 0;
1492
- adjustedChars += estimateOpenAICompletionsMessagesChars(payload.messages);
1493
- if (Array.isArray(payload.tools) && payload.tools.length > 0) try {
1494
- adjustedChars += estimateStringChars(JSON.stringify(payload.tools));
1495
- } catch {
1496
- adjustedChars += 1024;
1497
- }
1498
- if (payload.response_format !== void 0) try {
1499
- adjustedChars += estimateStringChars(JSON.stringify(payload.response_format));
1500
- } catch {
1501
- adjustedChars += 256;
1502
- }
1503
- return Math.ceil(adjustedChars / 4 * OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN);
1504
- }
1505
- function estimateOpenAICompletionsMessagesChars(messages) {
1506
- if (!Array.isArray(messages)) return 0;
1507
- let adjustedChars = 0;
1508
- for (const message of messages) {
1509
- if (!message || typeof message !== "object") continue;
1510
- const record = message;
1511
- adjustedChars += estimateOpenAICompletionsContentChars(record.content);
1512
- for (const field of COMPLETIONS_REASONING_REPLAY_FIELDS) adjustedChars += estimateOpenAICompletionsContentChars(record[field]);
1513
- if (record.tool_calls !== void 0) try {
1514
- adjustedChars += estimateStringChars(JSON.stringify(record.tool_calls));
1515
- } catch {
1516
- adjustedChars += 256;
1517
- }
1518
- }
1519
- return adjustedChars;
1520
- }
1521
- function estimateOpenAICompletionsContentChars(value) {
1522
- if (typeof value === "string") return estimateStringChars(value);
1523
- if (!Array.isArray(value)) return 0;
1524
- let adjustedChars = 0;
1525
- for (const block of value) {
1526
- if (!block || typeof block !== "object") continue;
1527
- const record = block;
1528
- if (record.type === "image_url" || record.type === "input_image") {
1529
- adjustedChars += OPENAI_COMPLETIONS_IMAGE_CHAR_ESTIMATE;
1530
- continue;
1531
- }
1532
- const text = record.text;
1533
- if (typeof text === "string") {
1534
- adjustedChars += estimateStringChars(text);
1535
- continue;
1536
- }
1537
- try {
1538
- adjustedChars += estimateStringChars(JSON.stringify(block));
1539
- } catch {
1540
- adjustedChars += 256;
1541
- }
1542
- }
1543
- return adjustedChars;
1544
- }
1545
- function resolveOpenAICompletionsEffectiveContextTokens(model) {
1546
- const contextTokens = model.contextTokens;
1547
- if (typeof contextTokens === "number" && Number.isFinite(contextTokens) && contextTokens > 0) return contextTokens;
1548
- return typeof model.contextWindow === "number" && Number.isFinite(model.contextWindow) && model.contextWindow > 0 ? model.contextWindow : void 0;
1549
- }
1550
- function isQwenOpenAICompletionsThinkingFormat(format) {
1551
- return format === "qwen" || format === "qwen-chat-template";
1552
- }
1553
- function setQwenChatTemplateThinking(params, enabled) {
1554
- const existing = params.chat_template_kwargs;
1555
- params.chat_template_kwargs = existing && typeof existing === "object" && !Array.isArray(existing) ? {
1556
- ...existing,
1557
- enable_thinking: enabled
1558
- } : { enable_thinking: enabled };
1559
- }
1560
- function applyQwenOpenAICompletionsThinkingParams(params) {
1561
- if (!params.modelReasoning || !isQwenOpenAICompletionsThinkingFormat(params.compatThinkingFormat)) return false;
1562
- const enabled = isOpenAICompletionsThinkingEnabled(params.requestedEffort);
1563
- if (params.compatThinkingFormat === "qwen-chat-template") setQwenChatTemplateThinking(params.payload, enabled);
1564
- else params.payload.enable_thinking = enabled;
1565
- return true;
1566
- }
1567
- function applyTogetherOpenAICompletionsThinkingParams(params) {
1568
- if (!params.modelReasoning || params.compatThinkingFormat !== "together") return;
1569
- params.payload.reasoning = { enabled: isOpenAICompletionsThinkingEnabled(params.requestedEffort) };
1570
- }
1571
- function convertTools(tools, compat, model) {
1572
- const projection = projectOpenAITools(tools);
1573
- const strict = resolveOpenAIStrictToolFlagWithDiagnostics(projection, resolveOpenAIStrictToolSetting(model, {
1574
- transport: "stream",
1575
- supportsStrictMode: compat?.supportsStrictMode
1576
- }), {
1577
- transport: "completions",
1578
- model
1579
- });
1580
- return {
1581
- projection,
1582
- tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
1583
- const functionTool = {
1584
- name: tool.name,
1585
- description: tool.description,
1586
- parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, model.compat)
1587
- };
1588
- if (strict !== void 0) functionTool.strict = strict;
1589
- return {
1590
- type: "function",
1591
- function: functionTool
1592
- };
1593
- })
1594
- };
1595
- }
1596
- function buildOpenAICompletionsParams(model, context, options) {
1597
- const compat = getCompat(model);
1598
- const compatDetection = detectOpenAICompletionsCompat(model);
1599
- const completionsContext = context.systemPrompt ? {
1600
- ...context,
1601
- systemPrompt: stripSystemPromptCacheBoundary(context.systemPrompt)
1602
- } : context;
1603
- let messages = convertMessages(model, completionsContext, compat);
1604
- applyCompletionsReplay(messages, context, model, compat);
1605
- if (compat.strictMessageKeys) messages = stripCompletionMessagesToRoleContent(messages);
1606
- const cacheRetention = resolveCacheRetention(options?.cacheRetention);
1607
- const promptCacheKey = resolvePromptCacheKey(options, cacheRetention);
1608
- const params = {
1609
- model: model.id,
1610
- messages: compat.requiresStringContent ? flattenCompletionMessagesToStringContent(messages) : messages,
1611
- stream: true
1612
- };
1613
- if (compat.supportsUsageInStreaming) params.stream_options = { include_usage: true };
1614
- if (compat.supportsStore) params.store = false;
1615
- if (compat.supportsPromptCacheKey && promptCacheKey) {
1616
- params.prompt_cache_key = promptCacheKey;
1617
- if (cacheRetention === "long" && compat.supportsLongCacheRetention) params.prompt_cache_retention = "24h";
1618
- }
1619
- if (options?.temperature !== void 0) params.temperature = options.temperature;
1620
- if (options?.topP !== void 0) params.top_p = options.topP;
1621
- const responseFormat = resolveOpenAICompletionsResponseFormat(shouldOmitOllamaCompatResponseFormat({
1622
- provider: model.provider,
1623
- baseUrl: model.baseUrl,
1624
- hasTools: () => Boolean(context.tools?.length)
1625
- }) ? void 0 : options?.responseFormat, compat.supportsJsonSchemaResponseFormat);
1626
- if (responseFormat !== void 0) params.response_format = responseFormat;
1627
- if (options?.frequencyPenalty !== void 0) params.frequency_penalty = options.frequencyPenalty;
1628
- if (options?.presencePenalty !== void 0) params.presence_penalty = options.presencePenalty;
1629
- if (options?.seed !== void 0) params.seed = options.seed;
1630
- if (options?.stop !== void 0 && options.stop.length > 0) params.stop = options.stop;
1631
- if (supportsModelTools(model)) {
1632
- if (context.tools) {
1633
- const converted = convertTools(context.tools, compat, model);
1634
- if (converted.tools.length > 0 || converted.projection.inputToolCount === 0 && converted.projection.diagnostics.length === 0) params.tools = converted.tools;
1635
- else if (hasToolCallHistory(context.messages)) params.tools = [];
1636
- if (options?.toolChoice) {
1637
- const toolChoice = reconcileOpenAICompletionsToolChoice(options.toolChoice, converted.projection);
1638
- if (toolChoice !== void 0) params.tool_choice = toolChoice;
1639
- } else if (compatDetection.capabilities.usesExplicitProxyLikeEndpoint && Array.isArray(params.tools) && params.tools.length > 0) params.tool_choice = "auto";
1640
- } else if (hasToolCallHistory(context.messages)) params.tools = [];
1641
- if (compatDetection.capabilities.usesExplicitProxyLikeEndpoint && Array.isArray(params.tools) && params.tools.length === 0) {
1642
- delete params.tools;
1643
- delete params.tool_choice;
1644
- }
1645
- }
1646
- {
1647
- const maxTokenBudget = resolveOpenAICompletionsMaxTokens(model, options);
1648
- const effectiveMaxTokens = maxTokenBudget.maxTokens;
1649
- const effectiveContextTokens = resolveOpenAICompletionsEffectiveContextTokens(model);
1650
- let clampedMaxTokens = effectiveMaxTokens;
1651
- const modelMaxTokens = resolveOpenAICompletionsModelMaxTokens(model);
1652
- if (maxTokenBudget.clampToModelMaxTokens && clampedMaxTokens !== void 0 && modelMaxTokens !== void 0 && clampedMaxTokens > modelMaxTokens) {
1653
- clampedMaxTokens = modelMaxTokens;
1654
- emitModelTransportDebug(log, `[completions] clamp_max_tokens provider=${model.provider} api=${model.api} model=${model.id} requested=${effectiveMaxTokens} output=${clampedMaxTokens} modelMaxTokens=${modelMaxTokens}`);
1655
- }
1656
- if (compatDetection.capabilities.usesExplicitProxyLikeEndpoint && clampedMaxTokens !== void 0 && effectiveContextTokens !== void 0) {
1657
- const estimatedInputTokens = estimateOpenAICompletionsInputTokens(params);
1658
- const remainingBudget = Math.max(1, effectiveContextTokens - estimatedInputTokens - 1);
1659
- if (clampedMaxTokens > remainingBudget) {
1660
- clampedMaxTokens = remainingBudget;
1661
- emitModelTransportDebug(log, `[completions] clamp_max_tokens provider=${model.provider} api=${model.api} model=${model.id} requested=${effectiveMaxTokens} output=${clampedMaxTokens} effectiveContext=${effectiveContextTokens} estimatedInput=${estimatedInputTokens}`);
1662
- }
1663
- }
1664
- if (clampedMaxTokens) {
1665
- if (compat.maxTokensField === "max_tokens") params.max_tokens = clampedMaxTokens;
1666
- else params.max_completion_tokens = clampedMaxTokens;
1667
- }
1668
- }
1669
- const completionsReasoningEffort = resolveOpenAICompletionsReasoningEffort(options);
1670
- const resolvedCompletionsReasoningEffort = completionsReasoningEffort ? resolveOpenAIReasoningEffortForModel({
1671
- model,
1672
- effort: completionsReasoningEffort,
1673
- fallbackMap: compat.reasoningEffortMap
1674
- }) : void 0;
1675
- const omitChatCompletionsToolReasoningEffort = Array.isArray(params.tools) && params.tools.length > 0 && (isOpenAIGpt54MiniModel(model) || isOpenAIGpt55Model(model) && isKnownOpenAICompletionsEndpoint(model));
1676
- const disableChatCompletionsToolReasoning = Array.isArray(params.tools) && params.tools.length > 0 && isOpenAIGpt56Model(model) && isKnownOpenAICompletionsEndpoint(model);
1677
- const handledQwenThinkingFormat = applyQwenOpenAICompletionsThinkingParams({
1678
- compatThinkingFormat: compat.thinkingFormat,
1679
- modelReasoning: model.reasoning,
1680
- payload: params,
1681
- requestedEffort: completionsReasoningEffort
1682
- });
1683
- applyTogetherOpenAICompletionsThinkingParams({
1684
- compatThinkingFormat: compat.thinkingFormat,
1685
- modelReasoning: model.reasoning,
1686
- payload: params,
1687
- requestedEffort: completionsReasoningEffort
1688
- });
1689
- if (disableChatCompletionsToolReasoning) params.reasoning_effort = "none";
1690
- else if (compat.thinkingFormat === "openrouter" && model.reasoning && resolvedCompletionsReasoningEffort) params.reasoning = { effort: resolvedCompletionsReasoningEffort };
1691
- else if (resolvedCompletionsReasoningEffort && model.reasoning && compat.supportsReasoningEffort && !handledQwenThinkingFormat && !omitChatCompletionsToolReasoningEffort) params.reasoning_effort = resolvedCompletionsReasoningEffort;
1692
- return params;
1693
- }
1694
- //#endregion
1695
- //#region packages/ai/src/transports/openai-completions-transport.ts
1696
- function assertOpenAICompletionsPayloadHasConversationTurn(params, model) {
1697
- const messages = params.messages;
1698
- if (!Array.isArray(messages) || hasOpenAICompatibleConversationTurn(messages)) return;
1699
- throw new Error(`OpenAI-compatible chat payload for ${model.provider}/${model.id} contains no non-empty user or assistant messages after compaction and transport transforms; refusing to send a system/tool-only request. Start a new user turn or repair the compacted session history.`);
1700
- }
1701
- const SSE_DONE_LINE_RE = /^data:[ \t]*\[DONE\][ \t]*$/i;
1702
- const SSE_DONE_MAX_LINE_CHARS = 1024;
1703
- function createSseDoneDetector() {
1704
- const decoder = new TextDecoder();
1705
- let line = "";
1706
- let lineOverflowed = false;
1707
- let sawDone = false;
1708
- const finishLine = () => {
1709
- if (!lineOverflowed && SSE_DONE_LINE_RE.test(line)) sawDone = true;
1710
- line = "";
1711
- lineOverflowed = false;
1712
- };
1713
- const observeText = (text) => {
1714
- for (const char of text) {
1715
- if (char === "\n" || char === "\r") {
1716
- finishLine();
1717
- continue;
1718
- }
1719
- if (!lineOverflowed && line.length < SSE_DONE_MAX_LINE_CHARS) line += char;
1720
- else lineOverflowed = true;
1721
- }
1722
- };
1723
- return {
1724
- observe(chunk) {
1725
- if (!sawDone) observeText(decoder.decode(chunk, { stream: true }));
1726
- },
1727
- finish() {
1728
- if (sawDone) return;
1729
- observeText(decoder.decode());
1730
- if (line || lineOverflowed) finishLine();
1731
- },
1732
- sawDone: () => sawDone
554
+ observe(chunk) {
555
+ if (!sawDone) observeText(decoder.decode(chunk, { stream: true }));
556
+ },
557
+ finish() {
558
+ if (sawDone) return;
559
+ observeText(decoder.decode());
560
+ if (line || lineOverflowed) finishLine();
561
+ },
562
+ sawDone: () => sawDone
1733
563
  };
1734
564
  }
1735
565
  function createOpenAICompletionsClient(model, context, apiKey, optionHeaders, opts) {
@@ -1823,7 +653,7 @@ function createOpenAICompletionsTransportStreamFn() {
1823
653
  statusText: response.statusText
1824
654
  });
1825
655
  };
1826
- const client = createOpenAICompletionsClient(model, context, apiKey, options?.headers, { fetch: doneDetectingFetch });
656
+ const client = createOpenAICompletionsClient(model, context, apiKey, resolveOpencodeSessionHeaders(model, options), { fetch: doneDetectingFetch });
1827
657
  let params = buildOpenAICompletionsParams(model, context, options);
1828
658
  const nextParams = await options?.onPayload?.(params, model);
1829
659
  if (nextParams !== void 0) params = nextParams;
@@ -1880,164 +710,6 @@ function createOpenAICompletionsTransportStreamFn() {
1880
710
  };
1881
711
  }
1882
712
  //#endregion
1883
- //#region packages/ai/src/transports/openai-responses-compact-request.ts
1884
- const COMPACT_REQUEST = Symbol("openaiResponsesCompactRequest");
1885
- function claimResponsesCompactRequest(options) {
1886
- const controller = options ? Reflect.get(options, COMPACT_REQUEST) : void 0;
1887
- if (controller?.claimed === false) {
1888
- controller.claimed = true;
1889
- return controller;
1890
- }
1891
- }
1892
- /** Run a compact-endpoint request through the session's prepared stream stack. */
1893
- async function requestPreparedOpenAIResponsesCompaction(streamFn, model, context, options) {
1894
- const preparedOptions = { ...options };
1895
- let resolveResult;
1896
- let rejectResult;
1897
- const result = new Promise((resolve, reject) => {
1898
- resolveResult = resolve;
1899
- rejectResult = reject;
1900
- });
1901
- const controller = {
1902
- claimed: false,
1903
- resolve: resolveResult,
1904
- reject: rejectResult
1905
- };
1906
- Reflect.set(preparedOptions, COMPACT_REQUEST, controller);
1907
- const stream = await Promise.resolve(streamFn(model, context, preparedOptions));
1908
- if (!controller.claimed) throw new Error("Prepared stream did not reach an OpenAI Responses transport");
1909
- try {
1910
- return await result;
1911
- } finally {
1912
- await stream.result().catch(() => void 0);
1913
- }
1914
- }
1915
- //#endregion
1916
- //#region packages/ai/src/transports/openai-responses-continuation.ts
1917
- const HTTP_CONTINUATION_IDLE_TTL_MS = 3e5;
1918
- const TURN_HEADERS = /* @__PURE__ */ new Set([
1919
- "traceparent",
1920
- "x-openclaw-turn-id",
1921
- "x-openclaw-turn-attempt"
1922
- ]);
1923
- function jsonValuesEqual(left, right) {
1924
- return stableStringify(JSON.parse(JSON.stringify(left))) === stableStringify(JSON.parse(JSON.stringify(right)));
1925
- }
1926
- function requestWithoutInput(request) {
1927
- const { input: _input, previous_response_id: _previousResponseId, instructions: _instructions, tools: _tools, ...rest } = request;
1928
- if (!isRecord(rest.metadata)) return rest;
1929
- const metadata = Object.fromEntries(Object.entries(rest.metadata).filter(([key]) => key !== "openclaw_turn_id" && key !== "openclaw_turn_attempt"));
1930
- return {
1931
- ...rest,
1932
- metadata
1933
- };
1934
- }
1935
- function normalizeAssistantReplayInput(input, fromResponse = false) {
1936
- return input.map((item) => {
1937
- if (!isRecord(item)) return item;
1938
- if (item.type === "reasoning") return { type: "reasoning" };
1939
- if (item.type !== "function_call" && !(item.type === "message" && item.role === "assistant")) return item;
1940
- const { id: _id, status: _status, ...stableItem } = item;
1941
- if (fromResponse && item.type === "function_call") {
1942
- const args = parseJsonObjectPreservingUnsafeIntegers(stableItem.arguments);
1943
- stableItem.arguments = args ? JSON.stringify(args) : stableItem.arguments;
1944
- }
1945
- if (item.type === "message" && Array.isArray(stableItem.content)) stableItem.content = stableItem.content.map((part) => {
1946
- if (!isRecord(part) || part.type !== "output_text") return part;
1947
- const { annotations: _annotations, logprobs: _logprobs, ...stablePart } = part;
1948
- return stablePart;
1949
- });
1950
- return stableItem;
1951
- });
1952
- }
1953
- function resolveResponsesContinuationRequest(continuation, request) {
1954
- if (!continuation) return {
1955
- request,
1956
- continuationStatus: "no_previous_response"
1957
- };
1958
- if (request.previous_response_id) return {
1959
- request,
1960
- continuationStatus: "explicit_previous_response_id"
1961
- };
1962
- if (!jsonValuesEqual(requestWithoutInput(request), requestWithoutInput(continuation.lastRequest))) return {
1963
- request,
1964
- continuationStatus: "request_changed"
1965
- };
1966
- const currentInput = request.input ?? [];
1967
- const previousInput = continuation.lastRequest.input ?? [];
1968
- const baselineLength = previousInput.length + continuation.lastResponseItems.length;
1969
- if (currentInput.length < baselineLength) return {
1970
- request,
1971
- continuationStatus: "history_shorter"
1972
- };
1973
- if (!jsonValuesEqual(normalizeAssistantReplayInput(currentInput.slice(0, previousInput.length)), normalizeAssistantReplayInput(previousInput)) || !jsonValuesEqual(normalizeAssistantReplayInput(currentInput.slice(previousInput.length, baselineLength)), normalizeAssistantReplayInput(continuation.lastResponseItems, true))) return {
1974
- request,
1975
- continuationStatus: "history_changed"
1976
- };
1977
- return {
1978
- request: {
1979
- ...request,
1980
- previous_response_id: continuation.lastResponseId,
1981
- input: currentInput.slice(baselineLength)
1982
- },
1983
- continuationStatus: "continued"
1984
- };
1985
- }
1986
- const httpContinuationEntries = /* @__PURE__ */ new Map();
1987
- let nextHttpContinuationGeneration = 1;
1988
- function connectionIdentity(params) {
1989
- const headers = Object.entries(resolveAiTransportHeaderSentinels(params.headers) ?? {}).map(([name, value]) => [name.toLowerCase(), value]).filter(([name]) => !TURN_HEADERS.has(name)).toSorted(([a], [b]) => a.localeCompare(b));
1990
- return sha256Hex(JSON.stringify([
1991
- getAiTransportHost().resolveSecretSentinel(params.apiKey),
1992
- params.baseUrl,
1993
- headers
1994
- ]));
1995
- }
1996
- function claimOpenAIResponsesHttpContinuation(params) {
1997
- const key = `${params.sessionId}\0${connectionIdentity(params)}`;
1998
- const previous = httpContinuationEntries.get(key);
1999
- if (previous?.kind === "claimed") return;
2000
- if (previous?.kind === "ready") clearTimeout(previous.idleTimer);
2001
- const generation = nextHttpContinuationGeneration++;
2002
- const claimed = {
2003
- kind: "claimed",
2004
- sessionId: params.sessionId,
2005
- generation
2006
- };
2007
- httpContinuationEntries.set(key, claimed);
2008
- return {
2009
- request: resolveResponsesContinuationRequest(previous?.kind === "ready" ? previous.state : void 0, params.request).request,
2010
- commit: (effectiveRequest, response) => {
2011
- if (httpContinuationEntries.get(key) !== claimed) return;
2012
- const idleTimer = setTimeout(() => {
2013
- const current = httpContinuationEntries.get(key);
2014
- if (current?.kind === "ready" && current.generation === generation) httpContinuationEntries.delete(key);
2015
- }, HTTP_CONTINUATION_IDLE_TTL_MS);
2016
- idleTimer.unref?.();
2017
- const ready = {
2018
- ...claimed,
2019
- kind: "ready",
2020
- state: {
2021
- lastRequest: effectiveRequest,
2022
- lastResponseId: response.id,
2023
- lastResponseItems: response.output
2024
- },
2025
- idleTimer
2026
- };
2027
- httpContinuationEntries.set(key, ready);
2028
- },
2029
- release: () => {
2030
- if (httpContinuationEntries.get(key) === claimed) httpContinuationEntries.delete(key);
2031
- }
2032
- };
2033
- }
2034
- registerSessionResourceCleanup((sessionId) => {
2035
- for (const [key, entry] of httpContinuationEntries) if (!sessionId || entry.sessionId === sessionId) {
2036
- if (entry.kind === "ready") clearTimeout(entry.idleTimer);
2037
- httpContinuationEntries.delete(key);
2038
- }
2039
- });
2040
- //#endregion
2041
713
  //#region packages/ai/src/transports/openai-responses-params-internal.ts
2042
714
  const OPENAI_RESPONSES_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([
2043
715
  "openai",
@@ -2045,30 +717,6 @@ const OPENAI_RESPONSES_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([
2045
717
  "azure-openai-responses",
2046
718
  "github-copilot"
2047
719
  ]);
2048
- function convertResponsesTools(tools, model, options) {
2049
- const projection = projectOpenAITools(tools);
2050
- const strict = resolveOpenAIStrictToolFlagWithDiagnostics(projection, options?.strict, {
2051
- transport: "responses",
2052
- model
2053
- });
2054
- return {
2055
- projection,
2056
- tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
2057
- const result = {
2058
- type: "function",
2059
- name: tool.name,
2060
- description: tool.description,
2061
- parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, model.compat)
2062
- };
2063
- if (strict !== void 0) result.strict = strict;
2064
- return result;
2065
- })
2066
- };
2067
- }
2068
- function getPromptCacheRetention(baseUrl, cacheRetention) {
2069
- if (cacheRetention !== "long") return;
2070
- return baseUrl?.includes("api.openai.com") ? "24h" : void 0;
2071
- }
2072
720
  function resolveOpenAIReasoningEffort(options) {
2073
721
  return normalizeOpenAIReasoningEffort(options?.reasoningEffort ?? options?.reasoning ?? "high");
2074
722
  }
@@ -2101,6 +749,7 @@ const OPENAI_CODEX_RESPONSES_UNSUPPORTED_PARAMS = [
2101
749
  "max_output_tokens",
2102
750
  "metadata",
2103
751
  "prompt_cache_retention",
752
+ "prompt_cache_options",
2104
753
  "service_tier",
2105
754
  "temperature",
2106
755
  "top_p"
@@ -2116,6 +765,7 @@ function stripOpenAICodexResponsesUnsupportedTextFields(params) {
2116
765
  function sanitizeOpenAICodexResponsesParams(model, params) {
2117
766
  if (!usesNativeOpenAICodexResponsesBackend(model)) return params;
2118
767
  for (const key of OPENAI_CODEX_RESPONSES_UNSUPPORTED_PARAMS) delete params[key];
768
+ Object.assign(params, { store: false });
2119
769
  stripOpenAICodexResponsesUnsupportedTextFields(params);
2120
770
  return params;
2121
771
  }
@@ -2151,84 +801,399 @@ function resolveOpenAIResponsesTextFormat(responseFormat) {
2151
801
  ...responseFormat.json_schema,
2152
802
  type: "json_schema"
2153
803
  };
2154
- return responseFormat;
804
+ return responseFormat;
805
+ }
806
+ function convertOpenAIResponsesMessagesForRequest(model, context, options, replayMode) {
807
+ const isNativeCodexResponses = usesNativeOpenAICodexResponsesBackend(model);
808
+ const payloadPolicy = resolveOpenAIResponsesPayloadPolicy(model, { storeMode: "disable" });
809
+ const policyAllowsReplayIds = payloadPolicy.explicitStore !== false && !payloadPolicy.shouldStripStore;
810
+ const replayResponsesItemIds = !isNativeCodexResponses && (options?.replayResponsesItemIds ?? policyAllowsReplayIds);
811
+ return convertResponsesMessages(model, context, OPENAI_RESPONSES_TOOL_CALL_PROVIDERS, {
812
+ includeSystemPrompt: !payloadPolicy.usesInstructionsField,
813
+ replayReasoningItems: true,
814
+ replayResponsesItemIds,
815
+ authProfileId: options?.authProfileId,
816
+ sessionId: options?.sessionId,
817
+ replayMode
818
+ });
819
+ }
820
+ function buildOpenAIResponsesParams(model, context, options, metadata, replayMode = "checkpoint") {
821
+ const payloadPolicy = resolveOpenAIResponsesPayloadPolicy(model, { storeMode: "disable" });
822
+ const messages = convertOpenAIResponsesMessagesForRequest(model, context, options, replayMode);
823
+ ensureOpenAIResponsesNonEmptyInput(messages, context);
824
+ const cacheRetention = resolveCacheRetention(options?.cacheRetention);
825
+ const compat = getCompat(model);
826
+ const promptCacheKey = compat.supportsPromptCacheKey ? resolvePromptCacheKey(options, cacheRetention) : void 0;
827
+ const instructions = resolveOpenAIResponsesInstructions(model, context, payloadPolicy.usesInstructionsField);
828
+ const params = {
829
+ model: model.id,
830
+ input: messages,
831
+ stream: true,
832
+ prompt_cache_key: promptCacheKey,
833
+ ...resolveOpenAIPromptCacheParams(model, cacheRetention, compat),
834
+ ...instructions ? { instructions } : {},
835
+ ...metadata ? { metadata } : {}
836
+ };
837
+ const effectiveMaxTokens = options?.maxTokens || model.maxTokens;
838
+ if (effectiveMaxTokens) params.max_output_tokens = Math.max(effectiveMaxTokens, 16);
839
+ if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
840
+ if (options?.topP !== void 0 && model.id !== "gpt-6-astra") params.top_p = options.topP;
841
+ if (options?.responseFormat !== void 0) params.text = {
842
+ ...params.text,
843
+ format: resolveOpenAIResponsesTextFormat(options.responseFormat)
844
+ };
845
+ if (options?.serviceTier !== void 0 && payloadPolicy.allowsServiceTier) params.service_tier = options.serviceTier;
846
+ if (context.tools) {
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;
852
+ if (options?.toolChoice) {
853
+ const toolChoice = reconcileOpenAIResponsesToolChoice(options.toolChoice, projection);
854
+ if (toolChoice !== void 0) params.tool_choice = toolChoice;
855
+ }
856
+ }
857
+ if (model.reasoning) {
858
+ if (options?.reasoningEffort || options?.reasoning || options?.reasoningSummary) {
859
+ const requestedReasoningEffort = resolveOpenAIReasoningEffort(options);
860
+ const resolvedReasoningEffort = resolveOpenAIReasoningEffortForModel({
861
+ model,
862
+ effort: requestedReasoningEffort
863
+ });
864
+ const reasoningEffort = resolvedReasoningEffort ? raiseMinimalReasoningForResponsesWebSearch({
865
+ model,
866
+ effort: resolvedReasoningEffort,
867
+ tools: params.tools
868
+ }) : void 0;
869
+ if (reasoningEffort) {
870
+ params.reasoning = {
871
+ effort: reasoningEffort,
872
+ ...reasoningEffort === "none" ? {} : { summary: options?.reasoningSummary || "auto" }
873
+ };
874
+ if (reasoningEffort !== "none") params.include = ["reasoning.encrypted_content"];
875
+ }
876
+ } else if (model.provider !== "github-copilot") {
877
+ const reasoningEffort = resolveOpenAIReasoningEffortForModel({
878
+ model,
879
+ effort: "none"
880
+ });
881
+ if (reasoningEffort) params.reasoning = { effort: reasoningEffort };
882
+ }
883
+ }
884
+ applyOpenAIResponsesPayloadPolicy(params, payloadPolicy);
885
+ return sanitizeOpenAICodexResponsesParams(model, params);
886
+ }
887
+ //#endregion
888
+ //#region packages/ai/src/transports/openai-responses-reasoning-update.ts
889
+ function isConfigurationUpdate(value) {
890
+ return isRecord(value) && value.type === "configuration_update" && isRecord(value.reasoning) && typeof value.reasoning.effort === "string";
891
+ }
892
+ function isResponsesReasoningUpdateCompatible(request) {
893
+ const mode = isRecord(request.reasoning) ? request.reasoning.mode : void 0;
894
+ return request.model === "gpt-6-astra" && (mode === void 0 || mode === "standard") && (!isRecord(request.multi_agent) || request.multi_agent.enabled !== true) && request.truncation !== "auto" && (!Array.isArray(request.context_management) || !request.context_management.some((item) => isRecord(item) && item.type === "compaction"));
895
+ }
896
+ function supportsResponsesReasoningUpdate(request) {
897
+ return isResponsesReasoningUpdateCompatible(request) && isRecord(request.reasoning) && typeof request.reasoning.effort === "string";
898
+ }
899
+ function canReferenceResponsesReasoningHistory(previous, request) {
900
+ return !previous.input?.some(isConfigurationUpdate) || isResponsesReasoningUpdateCompatible(request);
901
+ }
902
+ /** Rehydrate input controls only provisionally; continuation must validate the full prefix. */
903
+ function replayResponsesReasoningUpdates(previous, request, previousOutputLength, steering) {
904
+ if (steering !== "required-input" && (!supportsResponsesReasoningUpdate(previous) || !supportsResponsesReasoningUpdate(request)) || !Array.isArray(previous.input) || !Array.isArray(request.input) || request.input.some(isConfigurationUpdate)) return request;
905
+ const input = [...request.input];
906
+ let activeEffort = isRecord(previous.reasoning) ? previous.reasoning.effort : void 0;
907
+ for (const [index, item] of previous.input.entries()) if (isConfigurationUpdate(item)) {
908
+ input.splice(index, 0, item);
909
+ activeEffort = item.reasoning.effort;
910
+ }
911
+ if (steering === "required-input") return input.length === request.input.length ? request : {
912
+ ...request,
913
+ input
914
+ };
915
+ if (!isRecord(previous.reasoning) || !isRecord(request.reasoning) || typeof request.reasoning.effort !== "string") return request;
916
+ if (activeEffort !== request.reasoning.effort && steering !== "automatic") {
917
+ const baselineLength = previous.input.length + previousOutputLength;
918
+ const nextUser = input.findIndex((item, index) => index >= baselineLength && "role" in item && item.role === "user");
919
+ if (nextUser === -1) return request;
920
+ input.splice(nextUser, 0, {
921
+ type: "configuration_update",
922
+ reasoning: { effort: request.reasoning.effort }
923
+ });
924
+ }
925
+ if (input.length === request.input.length && activeEffort === request.reasoning.effort) return request;
926
+ return {
927
+ ...request,
928
+ reasoning: {
929
+ ...request.reasoning,
930
+ effort: previous.reasoning.effort
931
+ },
932
+ input
933
+ };
934
+ }
935
+ //#endregion
936
+ //#region packages/ai/src/transports/openai-responses-continuation.ts
937
+ const HTTP_CONTINUATION_IDLE_TTL_MS = 3e5;
938
+ const TURN_HEADERS = /* @__PURE__ */ new Set([
939
+ "traceparent",
940
+ "x-openclaw-turn-id",
941
+ "x-openclaw-turn-attempt"
942
+ ]);
943
+ function jsonValuesEqual(left, right) {
944
+ const leftJson = JSON.stringify(left);
945
+ const normalizedLeft = stableStringify(JSON.parse(leftJson));
946
+ const rightJson = JSON.stringify(right);
947
+ return leftJson === rightJson || normalizedLeft === stableStringify(JSON.parse(rightJson));
948
+ }
949
+ function requestWithoutInput(request) {
950
+ const { input: _input, previous_response_id: _previousResponseId, instructions: _instructions, tools: _tools, ...rest } = request;
951
+ if (!isRecord(rest.metadata)) return rest;
952
+ const metadata = Object.fromEntries(Object.entries(rest.metadata).filter(([key]) => key !== "openclaw_turn_id" && key !== "openclaw_turn_attempt"));
953
+ return {
954
+ ...rest,
955
+ metadata
956
+ };
957
+ }
958
+ function normalizeAssistantReplayInput(input, fromResponse = false) {
959
+ return input.map((item) => {
960
+ if (!isRecord(item)) return item;
961
+ if (item.type === "reasoning") return { type: "reasoning" };
962
+ if (item.type !== "function_call" && !(item.type === "message" && item.role === "assistant")) return item;
963
+ const { id: _id, status: _status, ...stableItem } = item;
964
+ if (fromResponse && item.type === "function_call") {
965
+ const args = parseJsonObjectPreservingUnsafeIntegers(stableItem.arguments);
966
+ stableItem.arguments = args ? JSON.stringify(args) : stableItem.arguments;
967
+ }
968
+ if (item.type === "message" && Array.isArray(stableItem.content)) stableItem.content = stableItem.content.map((part) => {
969
+ if (!isRecord(part) || part.type !== "output_text") return part;
970
+ const { annotations: _annotations, logprobs: _logprobs, ...stablePart } = part;
971
+ return stablePart;
972
+ });
973
+ return stableItem;
974
+ });
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
+ }
984
+ function resolveResponsesContinuationRequest(continuation, request, steering) {
985
+ if (!continuation) return {
986
+ request,
987
+ continuationStatus: "no_previous_response"
988
+ };
989
+ if (request.previous_response_id) return {
990
+ request,
991
+ continuationStatus: "explicit_previous_response_id"
992
+ };
993
+ if (!canReferenceResponsesReasoningHistory(continuation.lastRequest, request)) return {
994
+ request,
995
+ continuationStatus: "request_changed"
996
+ };
997
+ const prepared = replayResponsesReasoningUpdates(continuation.lastRequest, request, continuation.lastResponseItems.length, steering);
998
+ if (steering !== "required-input" && !jsonValuesEqual(requestWithoutInput(prepared), requestWithoutInput(continuation.lastRequest))) return {
999
+ request,
1000
+ continuationStatus: "request_changed"
1001
+ };
1002
+ const currentInput = prepared.input ?? [];
1003
+ const previousInput = continuation.lastRequest.input ?? [];
1004
+ const baselineLength = previousInput.length + continuation.lastResponseItems.length;
1005
+ if (currentInput.length < baselineLength) return {
1006
+ request,
1007
+ continuationStatus: "history_shorter"
1008
+ };
1009
+ if (!jsonValuesEqual(normalizeAssistantReplayInput(currentInput.slice(0, previousInput.length)), normalizeAssistantReplayInput(previousInput)) || !jsonValuesEqual(normalizeAssistantReplayInput(currentInput.slice(previousInput.length, baselineLength)), normalizeAssistantReplayInput(continuation.lastResponseItems, true))) return {
1010
+ request,
1011
+ continuationStatus: "history_changed"
1012
+ };
1013
+ return {
1014
+ request: {
1015
+ ...prepared,
1016
+ previous_response_id: continuation.lastResponseId,
1017
+ input: currentInput.slice(baselineLength)
1018
+ },
1019
+ ...prepared !== request ? { fullRequest: prepared } : {},
1020
+ continuationStatus: "continued"
1021
+ };
2155
1022
  }
2156
- function convertOpenAIResponsesMessagesForRequest(model, context, options, replayMode) {
2157
- const isNativeCodexResponses = usesNativeOpenAICodexResponsesBackend(model);
2158
- const payloadPolicy = resolveOpenAIResponsesPayloadPolicy(model, { storeMode: "disable" });
2159
- const policyAllowsReplayIds = payloadPolicy.explicitStore !== false && !payloadPolicy.shouldStripStore;
2160
- const replayResponsesItemIds = !isNativeCodexResponses && (options?.replayResponsesItemIds ?? policyAllowsReplayIds);
2161
- return convertResponsesMessages(model, context, OPENAI_RESPONSES_TOOL_CALL_PROVIDERS, {
2162
- includeSystemPrompt: !payloadPolicy.usesInstructionsField,
2163
- replayReasoningItems: true,
2164
- replayResponsesItemIds,
2165
- authProfileId: options?.authProfileId,
2166
- sessionId: options?.sessionId,
2167
- replayMode
2168
- });
1023
+ const httpContinuationEntries = /* @__PURE__ */ new Map();
1024
+ function deleteHttpContinuationIfOwned(key, entry) {
1025
+ if (httpContinuationEntries.get(key) === entry) httpContinuationEntries.delete(key);
2169
1026
  }
2170
- function buildOpenAIResponsesParams(model, context, options, metadata, replayMode = "checkpoint") {
2171
- const payloadPolicy = resolveOpenAIResponsesPayloadPolicy(model, { storeMode: "disable" });
2172
- const messages = convertOpenAIResponsesMessagesForRequest(model, context, options, replayMode);
2173
- ensureOpenAIResponsesNonEmptyInput(messages, context);
2174
- const cacheRetention = resolveCacheRetention(options?.cacheRetention);
2175
- const promptCacheKey = resolvePromptCacheKey(options, cacheRetention);
2176
- const instructions = resolveOpenAIResponsesInstructions(model, context, payloadPolicy.usesInstructionsField);
2177
- const params = {
2178
- model: model.id,
2179
- input: messages,
2180
- stream: true,
2181
- prompt_cache_key: promptCacheKey,
2182
- prompt_cache_retention: getPromptCacheRetention(model.baseUrl, cacheRetention),
2183
- ...instructions ? { instructions } : {},
2184
- ...metadata ? { metadata } : {}
2185
- };
2186
- const effectiveMaxTokens = options?.maxTokens || model.maxTokens;
2187
- if (effectiveMaxTokens) params.max_output_tokens = effectiveMaxTokens;
2188
- if (options?.temperature !== void 0) params.temperature = options.temperature;
2189
- if (options?.topP !== void 0) params.top_p = options.topP;
2190
- if (options?.responseFormat !== void 0) params.text = {
2191
- ...params.text,
2192
- format: resolveOpenAIResponsesTextFormat(options.responseFormat)
1027
+ function connectionIdentity(params) {
1028
+ const headers = Object.entries(resolveAiTransportHeaderSentinels(params.headers) ?? {}).map(([name, value]) => [name.toLowerCase(), value]).filter(([name]) => !TURN_HEADERS.has(name)).toSorted(([a], [b]) => a.localeCompare(b));
1029
+ return sha256Hex(JSON.stringify([
1030
+ getAiTransportHost().resolveSecretSentinel(params.apiKey),
1031
+ params.baseUrl,
1032
+ headers
1033
+ ]));
1034
+ }
1035
+ function claimOpenAIResponsesHttpContinuation(params) {
1036
+ const key = `${params.sessionId}\0${connectionIdentity(params)}`;
1037
+ const previous = httpContinuationEntries.get(key);
1038
+ if (previous?.kind === "claimed") return;
1039
+ if (previous?.kind === "ready") clearTimeout(previous.idleTimer);
1040
+ const claimed = {
1041
+ kind: "claimed",
1042
+ sessionId: params.sessionId
2193
1043
  };
2194
- if (options?.serviceTier !== void 0 && payloadPolicy.allowsServiceTier) params.service_tier = options.serviceTier;
2195
- if (context.tools) {
2196
- const converted = convertResponsesTools(context.tools, model, { strict: resolveOpenAIStrictToolSetting(model, { transport: "stream" }) });
2197
- if (converted.tools.length > 0 || converted.projection.inputToolCount === 0 && converted.projection.diagnostics.length === 0) params.tools = converted.tools;
2198
- if (options?.toolChoice) {
2199
- const toolChoice = reconcileOpenAIResponsesToolChoice(options.toolChoice, converted.projection);
2200
- if (toolChoice !== void 0) params.tool_choice = toolChoice;
2201
- }
2202
- }
2203
- if (model.reasoning) {
2204
- if (options?.reasoningEffort || options?.reasoning || options?.reasoningSummary) {
2205
- const requestedReasoningEffort = resolveOpenAIReasoningEffort(options);
2206
- const resolvedReasoningEffort = resolveOpenAIReasoningEffortForModel({
2207
- model,
2208
- effort: requestedReasoningEffort
2209
- });
2210
- const reasoningEffort = resolvedReasoningEffort ? raiseMinimalReasoningForResponsesWebSearch({
2211
- model,
2212
- effort: resolvedReasoningEffort,
2213
- tools: params.tools
2214
- }) : void 0;
2215
- if (reasoningEffort) {
2216
- params.reasoning = {
2217
- effort: reasoningEffort,
2218
- ...reasoningEffort === "none" ? {} : { summary: options?.reasoningSummary || "auto" }
1044
+ httpContinuationEntries.set(key, claimed);
1045
+ try {
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;
1049
+ return {
1050
+ request: params.request.store === false ? fullRequest : resolved.request,
1051
+ fullRequest,
1052
+ commit: (effectiveRequest, response) => {
1053
+ if (httpContinuationEntries.get(key) !== claimed) return;
1054
+ const ready = {
1055
+ ...claimed,
1056
+ kind: "ready",
1057
+ state: {
1058
+ lastRequest: effectiveRequest,
1059
+ lastResponseId: response.id,
1060
+ lastResponseItems: response.output
1061
+ },
1062
+ idleTimer: setTimeout(() => deleteHttpContinuationIfOwned(key, ready), HTTP_CONTINUATION_IDLE_TTL_MS)
2219
1063
  };
2220
- if (reasoningEffort !== "none") params.include = ["reasoning.encrypted_content"];
1064
+ ready.idleTimer.unref?.();
1065
+ httpContinuationEntries.set(key, ready);
1066
+ },
1067
+ release: () => deleteHttpContinuationIfOwned(key, claimed)
1068
+ };
1069
+ } catch (error) {
1070
+ deleteHttpContinuationIfOwned(key, claimed);
1071
+ throw error;
1072
+ }
1073
+ }
1074
+ registerSessionResourceCleanup((sessionId) => {
1075
+ for (const [key, entry] of httpContinuationEntries) if (!sessionId || entry.sessionId === sessionId) {
1076
+ if (entry.kind === "ready") clearTimeout(entry.idleTimer);
1077
+ httpContinuationEntries.delete(key);
1078
+ }
1079
+ });
1080
+ //#endregion
1081
+ //#region packages/ai/src/transports/openai-responses-steering.ts
1082
+ function cloneWireRequest(request) {
1083
+ const serialized = JSON.stringify(request);
1084
+ return JSON.parse(serialized);
1085
+ }
1086
+ async function projectResponsesSteeringInput(request, project) {
1087
+ const { input: activeInput, ...activeSettings } = cloneWireRequest(request);
1088
+ if (!Array.isArray(activeInput)) return [];
1089
+ const { input, ...settings } = cloneWireRequest(await project());
1090
+ if (!Array.isArray(input) || stableStringify(settings) !== stableStringify(activeSettings) || stableStringify(input.slice(0, activeInput.length)) !== stableStringify(activeInput)) return [];
1091
+ const projected = input.slice(activeInput.length);
1092
+ return projected.every((item) => isRecord(item) && item.role === "user") ? projected : [];
1093
+ }
1094
+ /** One response owns admission; accepted input stays on this connection until continuation. */
1095
+ function createResponsesSteering(params) {
1096
+ let responseId;
1097
+ let sealed = false;
1098
+ let unsubscribe;
1099
+ const pending = [];
1100
+ const accepted = /* @__PURE__ */ new Map();
1101
+ const acknowledged = /* @__PURE__ */ new Set();
1102
+ const seal = () => {
1103
+ sealed = true;
1104
+ const cleanup = unsubscribe;
1105
+ unsubscribe = void 0;
1106
+ cleanup?.();
1107
+ };
1108
+ return {
1109
+ get responseId() {
1110
+ return responseId;
1111
+ },
1112
+ get pending() {
1113
+ return pending.length > 0;
1114
+ },
1115
+ get acceptedInput() {
1116
+ return [...accepted.values()].flat();
1117
+ },
1118
+ seal,
1119
+ close(error) {
1120
+ seal();
1121
+ for (const submission of pending.splice(0)) submission.reject(error);
1122
+ },
1123
+ handle(event) {
1124
+ if (!isRecord(event)) return false;
1125
+ if (event.type === "response.created" && !responseId && !sealed) {
1126
+ const response = isRecord(event.response) ? event.response : void 0;
1127
+ if (typeof response?.id !== "string" || !response.id.trim()) throw new Error("Responses steering requires a response identity");
1128
+ const activeResponseId = response.id;
1129
+ responseId = activeResponseId;
1130
+ const cleanup = params.onActiveResponse({
1131
+ needsContinuation: params.needsContinuation,
1132
+ steer(messages) {
1133
+ if (sealed || messages.length === 0) return Promise.resolve(false);
1134
+ params.assertActive();
1135
+ const converted = params.toInput(messages);
1136
+ const submit = (input) => {
1137
+ if (sealed || input.length === 0) return Promise.resolve(false);
1138
+ params.assertActive();
1139
+ return new Promise((resolve, reject) => {
1140
+ pending.push({
1141
+ input,
1142
+ resolve,
1143
+ reject
1144
+ });
1145
+ params.send({
1146
+ type: "response.steer",
1147
+ previous_response_id: activeResponseId,
1148
+ input
1149
+ });
1150
+ });
1151
+ };
1152
+ return Array.isArray(converted) ? submit(converted) : converted.then(submit);
1153
+ }
1154
+ });
1155
+ if (sealed) cleanup?.();
1156
+ else unsubscribe = cleanup;
1157
+ return false;
2221
1158
  }
2222
- } else if (model.provider !== "github-copilot") {
2223
- const reasoningEffort = resolveOpenAIReasoningEffortForModel({
2224
- model,
2225
- effort: "none"
2226
- });
2227
- if (reasoningEffort) params.reasoning = { effort: reasoningEffort };
1159
+ if (event.type !== "response.steer.accepted" && event.type !== "response.steer.failed" && event.type !== "response.steer.pending") return false;
1160
+ const steer = isRecord(event.steer) ? event.steer : void 0;
1161
+ if (!responseId || steer?.previous_response_id !== responseId) throw new Error("Responses steering acknowledgement has an unexpected identity");
1162
+ if (event.type === "response.steer.failed" && steer.id === void 0) {
1163
+ const index = pending.findIndex((submission) => stableStringify(submission.input) === stableStringify(steer.input));
1164
+ const submission = pending[index];
1165
+ if (!submission) throw new Error("Responses steering acknowledgement has no pending submission");
1166
+ pending.splice(index, 1);
1167
+ submission.resolve(false);
1168
+ return true;
1169
+ }
1170
+ if (typeof steer.id !== "string" || !steer.id.trim()) throw new Error("Responses steering acknowledgement has an unexpected identity");
1171
+ if (event.type === "response.steer.pending") {
1172
+ if (!accepted.has(steer.id)) throw new Error("Responses steering pending event has no accepted submission");
1173
+ return true;
1174
+ }
1175
+ if (event.type === "response.steer.failed" && accepted.has(steer.id)) throw new Error("OpenAI could not apply accepted steering; the queued message remains in the conversation");
1176
+ if (acknowledged.has(steer.id)) throw new Error("Responses steering acknowledgement was already applied");
1177
+ const submission = pending.shift();
1178
+ if (!submission) throw new Error("Responses steering acknowledgement has no pending submission");
1179
+ acknowledged.add(steer.id);
1180
+ if (event.type === "response.steer.accepted") {
1181
+ accepted.set(steer.id, submission.input);
1182
+ submission.resolve(true);
1183
+ } else submission.resolve(false);
1184
+ return true;
2228
1185
  }
1186
+ };
1187
+ }
1188
+ /** Accepted steering is prepended by the server, so never repeat it in response.create. */
1189
+ function omitAcceptedSteering(input, accepted) {
1190
+ const remaining = [...input];
1191
+ for (const message of accepted) {
1192
+ const index = remaining.findIndex((item) => stableStringify(item) === stableStringify(message));
1193
+ if (index < 0) throw new Error("Responses steering continuation no longer contains the accepted user input");
1194
+ remaining.splice(index, 1);
2229
1195
  }
2230
- applyOpenAIResponsesPayloadPolicy(params, payloadPolicy);
2231
- return sanitizeOpenAICodexResponsesParams(model, params);
1196
+ return remaining;
2232
1197
  }
2233
1198
  //#endregion
2234
1199
  //#region packages/ai/src/transports/openai-responses-websocket.ts
@@ -2263,6 +1228,9 @@ function invalidateOwnedWebSocketSession(cacheKey, entry, reason = "done") {
2263
1228
  entry.idleTimer = void 0;
2264
1229
  }
2265
1230
  closeWebSocketSilently(entry.socket, reason);
1231
+ entry.steeringContinuation?.steering.close(/* @__PURE__ */ new Error("Responses steering connection closed"));
1232
+ entry.steeringContinuation?.iterator.return?.().catch(() => void 0);
1233
+ entry.steeringContinuation = void 0;
2266
1234
  if (websocketSessionCache.get(cacheKey) === entry) websocketSessionCache.delete(cacheKey);
2267
1235
  }
2268
1236
  function scheduleSessionWebSocketExpiry(cacheKey, entry) {
@@ -2312,11 +1280,14 @@ function createTransientWebSocketLease(connection) {
2312
1280
  }
2313
1281
  function createCachedWebSocketLease(cacheKey, entry, reusedConnection) {
2314
1282
  entry.busy = true;
1283
+ const steeringContinuation = entry.steeringContinuation;
1284
+ entry.steeringContinuation = void 0;
2315
1285
  return {
2316
1286
  socket: entry.socket,
2317
- iterator: entry.socket.stream(),
1287
+ iterator: steeringContinuation?.iterator ?? entry.socket.stream(),
2318
1288
  entry,
2319
1289
  reusedConnection,
1290
+ steeringContinuation,
2320
1291
  release: ({ keep } = {}) => {
2321
1292
  if (!keep || entry.socket.socket.readyState !== WEBSOCKET_OPEN_STATE) {
2322
1293
  invalidateOwnedWebSocketSession(cacheKey, entry);
@@ -2378,7 +1349,7 @@ function readServerEvent(message) {
2378
1349
  }
2379
1350
  function createOpenAIResponsesWebSocketStream(params) {
2380
1351
  const connection = prepareWebSocketConnection(params.client, params.headers);
2381
- const fullRequest = sanitizeWebSocketRequest(params.request);
1352
+ let fullRequest = sanitizeWebSocketRequest(params.request);
2382
1353
  const requestModel = typeof fullRequest.model === "string" ? fullRequest.model : "";
2383
1354
  const degradationKey = `${params.sessionId ?? ""}\0${connection.identity}\0${requestModel}`;
2384
1355
  const degraded = degradedWebSocketConnections.get(degradationKey);
@@ -2400,15 +1371,20 @@ function createOpenAIResponsesWebSocketStream(params) {
2400
1371
  throw new OpenAIResponsesWebSocketPreDispatchError(error);
2401
1372
  }
2402
1373
  let prepared;
1374
+ const resumedSteering = lease.steeringContinuation;
1375
+ const steeringMode = resumedSteering ? resumedSteering.requiresInput ? "required-input" : "automatic" : void 0;
2403
1376
  try {
2404
1377
  const continuation = lease.entry?.continuation;
2405
1378
  if (continuation && lease.entry) {
2406
1379
  lease.entry.continuation = void 0;
2407
- prepared = resolveResponsesContinuationRequest(continuation, fullRequest);
2408
- } else prepared = {
2409
- request: fullRequest,
2410
- continuationStatus: lease.entry ? "no_previous_response" : "socket_not_cached"
2411
- };
1380
+ prepared = resolveResponsesContinuationRequest(continuation, fullRequest, steeringMode);
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
+ }
2412
1388
  } catch (error) {
2413
1389
  lease.iterator.return?.().catch(() => void 0);
2414
1390
  lease.release({ keep: false });
@@ -2418,11 +1394,54 @@ function createOpenAIResponsesWebSocketStream(params) {
2418
1394
  let terminalResponse;
2419
1395
  let terminalReceived = false;
2420
1396
  let released = false;
1397
+ let retainIterator = false;
1398
+ let deferredInput = false;
1399
+ let inputReplay;
1400
+ if (resumedSteering) try {
1401
+ if (prepared.continuationStatus !== "continued" || !prepared.request.previous_response_id) throw new Error("Responses steering continuation changed its request or history");
1402
+ const input = omitAcceptedSteering(prepared.request.input ?? [], resumedSteering.acceptedInput);
1403
+ if (!resumedSteering.requiresInput && (stableStringify(fullRequest.instructions) !== stableStringify(resumedSteering.instructions) || stableStringify(fullRequest.tools) !== stableStringify(resumedSteering.tools))) throw new Error("Responses automatic steering continuation cannot change instructions or tools");
1404
+ const baseline = prepared.fullRequest ?? fullRequest;
1405
+ const priorLength = (baseline.input?.length ?? 0) - (prepared.request.input?.length ?? 0);
1406
+ const fingerprints = input.map(responsesInputFingerprint);
1407
+ if (fingerprints.length > 0) inputReplay = {
1408
+ afterResponseId: prepared.request.previous_response_id,
1409
+ before: resumedSteering.requiresInput ? fingerprints : [],
1410
+ after: resumedSteering.requiresInput ? [] : fingerprints
1411
+ };
1412
+ const delivered = resumedSteering.requiresInput ? input : [];
1413
+ prepared.fullRequest = {
1414
+ ...baseline,
1415
+ input: [
1416
+ ...(baseline.input ?? []).slice(0, priorLength),
1417
+ ...resumedSteering.acceptedInput,
1418
+ ...delivered
1419
+ ]
1420
+ };
1421
+ prepared.request = {
1422
+ ...prepared.request,
1423
+ input: delivered
1424
+ };
1425
+ deferredInput = !resumedSteering.requiresInput && input.length > 0;
1426
+ } catch (error) {
1427
+ lease.iterator.return?.().catch(() => void 0);
1428
+ lease.release({ keep: false });
1429
+ throw new OpenAIResponsesWebSocketPostDispatchError(error);
1430
+ }
1431
+ const steering = lease.entry && params.onActiveResponse && params.steeringInput ? createResponsesSteering({
1432
+ onActiveResponse: params.onActiveResponse,
1433
+ toInput: params.steeringInput,
1434
+ send: (event) => lease.socket.sendRaw(JSON.stringify(event)),
1435
+ needsContinuation: () => deferredInput,
1436
+ assertActive: () => {
1437
+ if (released || terminalReceived || params.signal?.aborted) throw new Error("Responses steering is no longer active");
1438
+ }
1439
+ }) : void 0;
2421
1440
  const finish = ({ keep = true } = {}) => {
2422
1441
  if (released) return;
2423
1442
  released = true;
2424
1443
  if (keep && lease.entry && terminalResponse) lease.entry.continuation = {
2425
- lastRequest: fullRequest,
1444
+ lastRequest: prepared.fullRequest ?? fullRequest,
2426
1445
  lastResponseId: terminalResponse.id,
2427
1446
  lastResponseItems: terminalResponse.output
2428
1447
  };
@@ -2436,8 +1455,19 @@ function createOpenAIResponsesWebSocketStream(params) {
2436
1455
  let requestDispatched = false;
2437
1456
  try {
2438
1457
  if (params.signal?.aborted) throw transportAbortError(params.signal);
1458
+ if (resumedSteering) {
1459
+ requestDispatched = true;
1460
+ if (resumedSteering.requiresInput) lease.socket.send({
1461
+ ...prepared.request,
1462
+ type: "response.create"
1463
+ });
1464
+ }
2439
1465
  for (;;) {
2440
- const next = await nextWebSocketMessage(iterator, params.signal);
1466
+ const buffered = resumedSteering?.buffered.shift();
1467
+ const next = buffered ? {
1468
+ value: buffered,
1469
+ done: false
1470
+ } : await nextWebSocketMessage(iterator, params.signal);
2441
1471
  if (next.done) throw new Error("OpenAI Responses WebSocket closed before a terminal response event");
2442
1472
  if (next.value.type === "open") {
2443
1473
  if (!requestDispatched) {
@@ -2451,8 +1481,51 @@ function createOpenAIResponsesWebSocketStream(params) {
2451
1481
  }
2452
1482
  const event = readServerEvent(next.value);
2453
1483
  if (!event) continue;
1484
+ if (isRecord(event) && typeof event.type === "string" && event.type.startsWith("response.steer.")) {
1485
+ if ((isRecord(event.steer) && event.steer.previous_response_id === steering?.responseId ? steering : resumedSteering?.steering ?? steering)?.handle(event)) continue;
1486
+ }
1487
+ steering?.handle(event);
2454
1488
  if (event.type === "response.completed") terminalResponse = event.response;
2455
1489
  terminalReceived = event.type === "response.completed" || event.type === "response.incomplete" || event.type === "response.failed";
1490
+ if (terminalReceived) {
1491
+ steering?.seal();
1492
+ if (event.type === "response.failed") steering?.close(/* @__PURE__ */ new Error("Responses failed before steering could be applied"));
1493
+ const continuationBuffer = [];
1494
+ for (;;) {
1495
+ if (!steering?.pending) break;
1496
+ const acknowledgement = await nextWebSocketMessage(iterator, params.signal);
1497
+ if (acknowledgement.done) throw new Error("Responses closed before acknowledging steering");
1498
+ const acknowledgedEvent = readServerEvent(acknowledgement.value);
1499
+ if (!steering.handle(acknowledgedEvent)) continuationBuffer.push(acknowledgement.value);
1500
+ }
1501
+ const acceptedInput = steering?.acceptedInput ?? [];
1502
+ const isSteered = event.type === "response.incomplete" && isRecord(event.response.incomplete_details) && event.response.incomplete_details.reason === "steered";
1503
+ if (lease.entry && steering && acceptedInput.length > 0 && (event.type === "response.completed" || isSteered)) {
1504
+ if (event.type === "response.incomplete") terminalResponse = event.response;
1505
+ lease.entry.steeringContinuation = {
1506
+ iterator,
1507
+ buffered: continuationBuffer,
1508
+ acceptedInput,
1509
+ requiresInput: (terminalResponse?.output ?? []).some((item) => (item.type === "function_call" || item.type === "custom_tool_call") && !(isRecord(item) && item.async === true) || item.type === "mcp_approval_request"),
1510
+ steering,
1511
+ instructions: fullRequest.instructions,
1512
+ tools: fullRequest.tools
1513
+ };
1514
+ retainIterator = true;
1515
+ if (isSteered) {
1516
+ yield {
1517
+ ...event,
1518
+ type: "response.completed",
1519
+ response: {
1520
+ ...event.response,
1521
+ status: "completed",
1522
+ incomplete_details: null
1523
+ }
1524
+ };
1525
+ return;
1526
+ }
1527
+ }
1528
+ }
2456
1529
  yield event;
2457
1530
  if (terminalReceived) {
2458
1531
  degradedWebSocketConnections.delete(degradationKey);
@@ -2460,20 +1533,28 @@ function createOpenAIResponsesWebSocketStream(params) {
2460
1533
  }
2461
1534
  }
2462
1535
  } catch (error) {
1536
+ const steeringDispatched = Boolean(steering?.pending || steering?.acceptedInput.length || resumedSteering);
1537
+ steering?.close(error instanceof Error ? error : /* @__PURE__ */ new Error("Responses steering failed"));
2463
1538
  if (lease.entry) lease.entry.continuation = void 0;
2464
- const safeRetry = error instanceof OpenAIResponsesWebSocketSafeRetryError;
1539
+ const safeRetry = error instanceof OpenAIResponsesWebSocketSafeRetryError && !steeringDispatched;
2465
1540
  if (!params.callerSignal?.aborted && !safeRetry) markDegraded();
2466
1541
  if (!requestDispatched && !params.signal?.aborted) throw new OpenAIResponsesWebSocketPreDispatchError(error);
2467
1542
  if (!requestDispatched || params.callerSignal?.aborted || safeRetry) throw error;
2468
1543
  throw new OpenAIResponsesWebSocketPostDispatchError(error);
2469
1544
  } finally {
2470
- await iterator.return?.().catch(() => void 0);
1545
+ steering?.seal();
1546
+ if (!retainIterator) {
1547
+ steering?.close(/* @__PURE__ */ new Error("Responses stream ended before steering was confirmed"));
1548
+ await iterator.return?.().catch(() => void 0);
1549
+ }
2471
1550
  if (!terminalReceived) finish({ keep: false });
2472
1551
  }
2473
1552
  } },
2474
1553
  request: prepared.request,
1554
+ fullRequest: prepared.fullRequest ?? fullRequest,
2475
1555
  reusedConnection: lease.reusedConnection,
2476
1556
  continuationStatus: prepared.continuationStatus,
1557
+ inputReplay,
2477
1558
  finish
2478
1559
  };
2479
1560
  }
@@ -2486,6 +1567,123 @@ function closeOpenAIResponsesWebSocketSessions(sessionId) {
2486
1567
  }
2487
1568
  registerSessionResourceCleanup(closeOpenAIResponsesWebSocketSessions);
2488
1569
  //#endregion
1570
+ //#region packages/ai/src/transports/openai-responses-compact-client.ts
1571
+ async function postOpenAIResponsesCompaction(params) {
1572
+ const compactInput = typeof params.request.instructions === "string" && params.request.instructions.length > 0 ? [buildOpenAIResponsesCompactSystemMessage(params.model, params.request.instructions), ...params.request.input ?? []] : params.request.input;
1573
+ const response = await params.client.post("/responses/compact", {
1574
+ ...buildOpenAISdkRequestOptions(params.model, params.options?.signal, { timeoutMs: params.options?.timeoutMs }),
1575
+ body: {
1576
+ model: params.request.model,
1577
+ input: compactInput
1578
+ }
1579
+ });
1580
+ const output = isRecord(response) && Array.isArray(response.output) ? response.output : [];
1581
+ const item = output.at(-1);
1582
+ const retainedItems = output.slice(0, -1);
1583
+ const retainedUserMessageCount = retainedItems.filter((candidate) => isRecord(candidate) && candidate.type === "message" && candidate.role === "user" && Array.isArray(candidate.content)).length;
1584
+ const inputUserMessageCount = Array.isArray(params.request.input) ? params.request.input.filter((candidate) => isRecord(candidate) && candidate.type === "message" && candidate.role === "user").length : 0;
1585
+ const retainedMessagePrefixSupported = supportsNativeOpenAIResponsesEndpoint(params.model);
1586
+ const usage = isRecord(response) && isRecord(response.usage) ? response.usage : void 0;
1587
+ if (!isRecord(response) || response.object !== "response.compaction" || !isOpenAIResponsesCompactionOutput(output, params.model) || retainedItems.length > 0 && (!retainedMessagePrefixSupported || retainedUserMessageCount !== inputUserMessageCount) || !isRecord(item) || item.type !== "compaction" || typeof item.encrypted_content !== "string" || item.encrypted_content.length === 0 || !usage || typeof usage.input_tokens !== "number" || typeof usage.output_tokens !== "number") throw new Error("Responses compact endpoint did not return one trailing compaction item");
1588
+ return {
1589
+ output,
1590
+ item,
1591
+ historyMode: retainedUserMessageCount > 0 ? "retained-users" : "compacted-prefix",
1592
+ usage,
1593
+ model: params.model,
1594
+ replayMetadata: buildOpenAIResponsesReasoningReplayMetadata(params.model, {
1595
+ authProfileId: params.options?.authProfileId,
1596
+ sessionId: params.options?.sessionId
1597
+ })
1598
+ };
1599
+ }
1600
+ //#endregion
1601
+ //#region packages/ai/src/transports/openai-responses-compact-request.ts
1602
+ const COMPACT_REQUEST = Symbol("openaiResponsesCompactRequest");
1603
+ function claimResponsesCompactRequest(options) {
1604
+ const controller = options ? Reflect.get(options, COMPACT_REQUEST) : void 0;
1605
+ if (controller?.claimed === false) {
1606
+ controller.claimed = true;
1607
+ return controller;
1608
+ }
1609
+ }
1610
+ /** Run a compact-endpoint request through the session's prepared stream stack. */
1611
+ async function requestPreparedOpenAIResponsesCompaction(streamFn, model, context, options) {
1612
+ const preparedOptions = { ...options };
1613
+ let resolveResult;
1614
+ let rejectResult;
1615
+ const result = new Promise((resolve, reject) => {
1616
+ resolveResult = resolve;
1617
+ rejectResult = reject;
1618
+ });
1619
+ const controller = {
1620
+ claimed: false,
1621
+ resolve: resolveResult,
1622
+ reject: rejectResult
1623
+ };
1624
+ Reflect.set(preparedOptions, COMPACT_REQUEST, controller);
1625
+ const stream = await Promise.resolve(streamFn(model, context, preparedOptions));
1626
+ if (!controller.claimed) throw new Error("Prepared stream did not reach an OpenAI Responses transport");
1627
+ try {
1628
+ return await result;
1629
+ } finally {
1630
+ await stream.result().catch(() => void 0);
1631
+ }
1632
+ }
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
2489
1687
  //#region packages/ai/src/transports/openai-responses-client.ts
2490
1688
  function resolveNativeOpenAIResponsesWebSocketMode(model, transport) {
2491
1689
  if (transport !== "websocket" && transport !== "websocket-cached" && transport !== "auto") return;
@@ -2529,35 +1727,6 @@ function createOpenAIResponsesClient(model, context, apiKey, optionHeaders, turn
2529
1727
  ...buildOpenAISdkClientOptions(model)
2530
1728
  });
2531
1729
  }
2532
- async function postOpenAIResponsesCompaction(params) {
2533
- const compactInput = typeof params.request.instructions === "string" && params.request.instructions.length > 0 ? [buildOpenAIResponsesCompactSystemMessage(params.model, params.request.instructions), ...params.request.input ?? []] : params.request.input;
2534
- const response = await params.client.post("/responses/compact", {
2535
- ...buildOpenAISdkRequestOptions(params.model, params.options?.signal, { timeoutMs: params.options?.timeoutMs }),
2536
- body: {
2537
- model: params.request.model,
2538
- input: compactInput
2539
- }
2540
- });
2541
- const output = isRecord(response) && Array.isArray(response.output) ? response.output : [];
2542
- const item = output.at(-1);
2543
- const retainedItems = output.slice(0, -1);
2544
- const retainedUserMessageCount = retainedItems.filter((candidate) => isRecord(candidate) && candidate.type === "message" && candidate.role === "user" && Array.isArray(candidate.content)).length;
2545
- const inputUserMessageCount = Array.isArray(params.request.input) ? params.request.input.filter((candidate) => isRecord(candidate) && candidate.type === "message" && candidate.role === "user").length : 0;
2546
- const retainedMessagePrefixSupported = supportsNativeOpenAIResponsesEndpoint(params.model);
2547
- const usage = isRecord(response) && isRecord(response.usage) ? response.usage : void 0;
2548
- if (!isRecord(response) || response.object !== "response.compaction" || !isOpenAIResponsesCompactionOutput(output, params.model) || retainedItems.length > 0 && (!retainedMessagePrefixSupported || retainedUserMessageCount !== inputUserMessageCount) || !isRecord(item) || item.type !== "compaction" || typeof item.encrypted_content !== "string" || item.encrypted_content.length === 0 || !usage || typeof usage.input_tokens !== "number" || typeof usage.output_tokens !== "number") throw new Error("Responses compact endpoint did not return one trailing compaction item");
2549
- return {
2550
- output,
2551
- item,
2552
- historyMode: retainedUserMessageCount > 0 ? "retained-users" : "compacted-prefix",
2553
- usage,
2554
- model: params.model,
2555
- replayMetadata: buildOpenAIResponsesReasoningReplayMetadata(params.model, {
2556
- authProfileId: params.options?.authProfileId,
2557
- sessionId: params.options?.sessionId
2558
- })
2559
- };
2560
- }
2561
1730
  function createResponsesTransportExecutor(config) {
2562
1731
  return (model, context, options) => {
2563
1732
  const responsesOptions = options;
@@ -2579,8 +1748,10 @@ function createResponsesTransportExecutor(config) {
2579
1748
  const websocketSessionPolicy = websocketMode ? turnState?.websocket : void 0;
2580
1749
  const websocketHeaders = websocketMode ? buildOpenAIClientHeaders(model, context, options?.headers, websocketSessionPolicy?.headers, options?.sessionId) : void 0;
2581
1750
  const client = config.createClient(model, context, apiKey, options?.headers, turnState?.headers, options?.sessionId, compactRequest ? createBoundedOpenAIResponsesCompactionFetch(buildGuardedModelFetch(model)) : void 0);
2582
- const buildRequest = async (replayMode) => {
2583
- let params = config.buildRequest(model, context, responsesOptions, turnState?.metadata, replayMode);
1751
+ const nativeAstra = model.id === "gpt-6-astra" && supportsNativeOpenAIResponsesEndpoint(model);
1752
+ const asyncToolExecutionEligible = nativeAstra && options?.asyncToolExecution === true && !responsesOptions?.openclawCodeModeToolSurface;
1753
+ const prepareRequest = async (request) => {
1754
+ let params = request;
2584
1755
  const nextParams = await options?.onPayload?.(params, model);
2585
1756
  if (nextParams !== void 0) params = nextParams;
2586
1757
  if (!isOpenAICodexResponsesModel(model)) params = mergeTransportMetadata(params, turnState?.metadata);
@@ -2592,9 +1763,15 @@ function createResponsesTransportExecutor(config) {
2592
1763
  enforceCodeModeResponsesToolSurface(params, visibleToolNames, allowedHostedToolTypes, codeModeToolSurfaceObserver.get(options));
2593
1764
  assertCodeModeResponsesToolSurface(params, visibleToolNames, allowedHostedToolTypes);
2594
1765
  }
1766
+ if (asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true && params.tools) params.tools = params.tools.map((tool) => tool.type === "function" ? {
1767
+ ...tool,
1768
+ async: true
1769
+ } : tool);
2595
1770
  return params;
2596
1771
  };
2597
- const params = await buildRequest("checkpoint");
1772
+ const buildRequest = (replayMode, requestContext = context) => prepareRequest(config.buildRequest(model, requestContext, responsesOptions, turnState?.metadata, replayMode));
1773
+ let params = await buildRequest("checkpoint");
1774
+ const asyncTools = asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true;
2598
1775
  if (compactRequest) {
2599
1776
  const compacted = await postOpenAIResponsesCompaction({
2600
1777
  client,
@@ -2618,13 +1795,17 @@ function createResponsesTransportExecutor(config) {
2618
1795
  provider: model.provider,
2619
1796
  api: model.api,
2620
1797
  baseUrl: model.baseUrl
2621
- }) && sessionId && params.store === true && !params.previous_response_id) continuationClaim = claimOpenAIResponsesHttpContinuation({
2622
- sessionId,
2623
- apiKey,
2624
- baseUrl: model.baseUrl,
2625
- headers: buildOpenAIClientHeaders(model, context, options?.headers, turnState?.headers, sessionId),
2626
- request: params
2627
- });
1798
+ }) && sessionId && (params.store === true || supportsResponsesReasoningUpdate(params)) && !params.previous_response_id) {
1799
+ continuationClaim = claimOpenAIResponsesHttpContinuation({
1800
+ sessionId,
1801
+ apiKey,
1802
+ baseUrl: model.baseUrl,
1803
+ headers: buildOpenAIClientHeaders(model, context, options?.headers, turnState?.headers, sessionId),
1804
+ request: params,
1805
+ restoreRequest: () => restoreResponsesReasoningState(context, model, responsesOptions, params)
1806
+ });
1807
+ if (continuationClaim) params = continuationClaim.fullRequest;
1808
+ }
2628
1809
  const observePrompt = createResponsesPromptEgressObserver(responsesOptions, context.systemPrompt);
2629
1810
  const requestStartedAt = Date.now();
2630
1811
  let started = false;
@@ -2659,7 +1840,7 @@ function createResponsesTransportExecutor(config) {
2659
1840
  onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, responsesOptions, checkpoint),
2660
1841
  canRetryStream: () => output.content.length === 0,
2661
1842
  wrapStream: ({ stream: rawResponseStream, response, attempt }) => {
2662
- if (continuationClaim) continuationBaseline = attempt.request.previous_response_id ? params : attempt.request;
1843
+ continuationBaseline = attempt.request.previous_response_id ? params : attempt.request;
2663
1844
  return withProviderResponseHook({
2664
1845
  stream: observeResponsesStream(rawResponseStream, model, requestStartedAt),
2665
1846
  signal: firstEvent.signal,
@@ -2675,6 +1856,7 @@ function createResponsesTransportExecutor(config) {
2675
1856
  return responseStream;
2676
1857
  };
2677
1858
  let responseStream;
1859
+ let websocketBaseline;
2678
1860
  let finishWebSocket;
2679
1861
  let transport = "sse";
2680
1862
  const logWebSocketFallback = (reason) => emitModelTransportDebug(log, `[responses] websocket_fallback provider=${model.provider} api=${model.api} model=${model.id} reason=${reason}`);
@@ -2688,14 +1870,22 @@ function createResponsesTransportExecutor(config) {
2688
1870
  const websocket = createOpenAIResponsesWebSocketStream({
2689
1871
  client,
2690
1872
  request: params,
1873
+ restoreRequest: (request) => restoreResponsesReasoningState(context, model, responsesOptions, request),
2691
1874
  mode: websocketMode,
2692
1875
  sessionId: options?.sessionId,
2693
1876
  headers: websocketHeaders,
2694
1877
  signal: websocketSignal,
2695
1878
  callerSignal: options?.signal,
2696
- degradeCooldownMs: websocketSessionPolicy?.degradeCooldownMs
1879
+ degradeCooldownMs: websocketSessionPolicy?.degradeCooldownMs,
1880
+ onActiveResponse: nativeAstra && params.model === "gpt-6-astra" ? options?.onActiveResponse : void 0,
1881
+ steeringInput: (messages) => projectResponsesSteeringInput(params, () => buildRequest("checkpoint", {
1882
+ ...context,
1883
+ messages: [...context.messages, ...messages]
1884
+ }))
2697
1885
  });
2698
1886
  finishWebSocket = websocket.finish;
1887
+ websocketBaseline = websocket.fullRequest;
1888
+ recordResponsesInputReplay(output, websocket.inputReplay);
2699
1889
  observePrompt?.(websocket.request, {
2700
1890
  egress: "responses-websocket",
2701
1891
  payloadVariant: "initial"
@@ -2737,7 +1927,8 @@ function createResponsesTransportExecutor(config) {
2737
1927
  yield* await createSseStream();
2738
1928
  }
2739
1929
  } };
2740
- } catch {
1930
+ } catch (error) {
1931
+ if (error instanceof OpenAIResponsesWebSocketPostDispatchError) throw error;
2741
1932
  closeWebSocketForFallback("setup_failure");
2742
1933
  responseStream = await createSseStream();
2743
1934
  }
@@ -2752,11 +1943,14 @@ function createResponsesTransportExecutor(config) {
2752
1943
  reasoningReplayMetadata: buildOpenAIResponsesReasoningReplayMetadata(model, {
2753
1944
  authProfileId: responsesOptions?.authProfileId,
2754
1945
  sessionId: options?.sessionId
2755
- })
1946
+ }),
1947
+ asyncToolExecution: asyncTools
2756
1948
  });
2757
1949
  finishWebSocket?.();
2758
1950
  if (options?.signal?.aborted) throw transportAbortError(options.signal);
2759
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);
2760
1954
  if (continuationClaim && continuationBaseline && terminal) continuationClaim.commit(continuationBaseline, terminal);
2761
1955
  } catch (error) {
2762
1956
  finishWebSocket?.({ keep: false });
@@ -3039,7 +2233,7 @@ const SIMPLE_TRANSPORT_API_ALIAS = {
3039
2233
  "google-generative-ai": "openclaw-google-generative-ai-transport"
3040
2234
  };
3041
2235
  function createProviderOwnedGoogleTransportStreamFn(model, ctx) {
3042
- return getAiTransportHost().plugin.resolveProviderStream({
2236
+ const streamFn = getAiTransportHost().plugin.resolveProviderStream({
3043
2237
  provider: model.provider,
3044
2238
  config: ctx?.cfg,
3045
2239
  workspaceDir: ctx?.workspaceDir,
@@ -3066,6 +2260,10 @@ function createProviderOwnedGoogleTransportStreamFn(model, ctx) {
3066
2260
  model
3067
2261
  }
3068
2262
  }) ?? void 0;
2263
+ return streamFn ? (requestModel, context, options) => streamFn(requestModel, context, {
2264
+ ...options,
2265
+ headers: resolveOpencodeSessionHeaders(requestModel, options)
2266
+ }) : void 0;
3069
2267
  }
3070
2268
  function createSupportedTransportStreamFn(model, ctx) {
3071
2269
  switch (model.api) {
@@ -3250,7 +2448,9 @@ function prepareProviderStreamModel(params) {
3250
2448
  const streamFn = providerStreamFn ? wrapPluginProviderStream(providerStreamFn) : transportFallback && params.model.api === "google-generative-ai" ? wrapPluginProviderStream(transportFallback) : transportFallback;
3251
2449
  if (!streamFn) return;
3252
2450
  const api = params.apiRegistry.getApiProvider(params.model.api) ? resolveProviderStreamApi(params.model) : params.model.api;
3253
- if (!registerCustomApi(params.apiRegistry, api, streamFn)) return;
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;
3254
2454
  return api === params.model.api ? params.model : projectModel(params.model, { api });
3255
2455
  }
3256
2456
  function prepareModelForSimpleCompletion(params) {
@@ -3275,4 +2475,4 @@ function prepareModelForSimpleCompletion(params) {
3275
2475
  return applyProviderSimpleCompletionWrapper(apiRegistry, model, cfg);
3276
2476
  }
3277
2477
  //#endregion
3278
- export { CompactionReplayRefreshRequiredError, GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP, MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE, applyAnthropicCacheControlToMessages, applyAnthropicEphemeralCacheControlMarkers, applyAnthropicPayloadPolicyToParams, applyOpenAIResponsesPayloadPolicy, assertCodeModeResponsesToolSurface, assignTransportErrorDetails, buildOpenAIClientHeaders, buildOpenAICompletionsParams, buildOpenAISdkClientOptions, buildOpenAISdkRequestOptions, buildTransportAwareSimpleStreamFn, canonicalizeMaxTokensParam, captureOpenAIResponsesCompaction, coerceTransportToolCallArguments, 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, isCodeModeModelVisibleToolName, isCompactionReplayCheckpoint, isOpenAICodexResponsesModel, isOpenAICompletionsThinkingEnabled, log, measureUtf8AppendBytes, mergeTransportHeaders, mergeTransportMetadata, normalizeCodexResponsesBaseUrlForOpenAISdk, notifyProviderHttpMetadata, notifyProviderHttpResponse, notifyProviderStreamOpened, parseJsonObjectPreservingUnsafeIntegers, parseJsonPreservingUnsafeIntegers, parseOpenAICompletionsUsage, parseTerminalToolCallArguments, prepareModelForSimpleCompletion, prepareTransportAwareSimpleModel, preserveCompactionReplayWindow, quoteUnsafeIntegerLiterals, readCodeModePayloadToolName, readOpenAICompletionsContentDeltas, readOpenAICompletionsReasoningBatch, replaceCompactionReplayOwnerContent, requestPreparedOpenAIResponsesCompaction, requiresCompactionReplayRefresh, resolveAnthropicEphemeralCacheControl, resolveAnthropicMessagesUrl, resolveAnthropicPayloadPolicy, resolveAnthropicServerCompactionPlan, resolveCodeModeResponsesVisibleToolNames, resolveCompactionReplayEligibility, resolveCompactionReplayPressure, resolveMaxTokensParam, resolveModelPayloadDebugMode, resolveModelSseDebugMode, resolveOpenAIClientBaseUrl, resolveOpenAICompletionsCompat, resolveOpenAIReasoningEffortMap, resolveOpenAIResponsesCompactEndpointPlan, resolveOpenAIResponsesPayloadPolicy, resolveOpenAIResponsesServerCompactionPlan, resolveOpenAIStrictToolFlagWithDiagnostics, resolvePromptCacheKey, resolveReplayableResponsesMessageId, resolveTransportAwareSimpleApi, sanitizeNonEmptyTransportPayloadText, sanitizeResponsesImagePayload, sanitizeTransportPayloadText, sortPromptCacheToolsByName as sortTransportToolsByName, stripCompactionReplayCheckpoint, stripCompactionReplayCheckpointInPlace, stripCompletionMessagesToRoleContent, throwIfModelStreamAborted, transportAbortError, usesNativeOpenAICodexResponsesBackend, withProviderAcceptanceObserver, withProviderResponseHook };
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 };