@openclaw/ai 2026.10.2 → 2026.10.5-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +6 -0
  2. package/dist/{anthropic-C4qygbtf.mjs → anthropic-BalhAzs-.mjs} +33 -63
  3. package/dist/{anthropic-payload-policy-DD7vzpxE.d.mts → anthropic-payload-policy-DGblkHL5.d.mts} +19 -19
  4. package/dist/{anthropic-stream-reducer-CWyWE21W.mjs → anthropic-stream-reducer-DkKeXXx4.mjs} +215 -297
  5. package/dist/{api-registry-B3rC2qu3.d.mts → api-registry-BhXXYdRA.d.mts} +2 -2
  6. package/dist/assistant-message-events-CHMJgbhs.mjs +18 -0
  7. package/dist/{assistant-output-D5762GPH.mjs → assistant-output-BuhRpLeD.mjs} +2 -2
  8. package/dist/{assistant-text-phase-DVZOxbuR.mjs → assistant-text-phase-Bn1hbvK9.mjs} +7 -6
  9. package/dist/{azure-openai-responses-DO-Fv8ha.mjs → azure-openai-responses-DfT9Ndd8.mjs} +8 -9
  10. package/dist/{credential-redaction-BKv49aiv.d.mts → credential-redaction-BHxruEH6.d.mts} +3 -1
  11. package/dist/{diagnostics-Caj-4RBA.mjs → diagnostics-tQasYct1.mjs} +10 -3
  12. package/dist/diagnostics.d.mts +7 -7
  13. package/dist/diagnostics.mjs +3 -3
  14. package/dist/{env-api-keys-CyX4VKGO.mjs → env-api-keys-CrxwdylR.mjs} +24 -35
  15. package/dist/event-stream-6UNs-AhN.d.mts +1 -0
  16. package/dist/{event-stream-DrRM_90c.d.mts → event-stream-BcqWLo_u.d.mts} +1 -1
  17. package/dist/{event-stream-C5AbCAaZ.mjs → event-stream-X2gmsUWv.mjs} +5 -8
  18. package/dist/event-stream.d.mts +2 -2
  19. package/dist/event-stream.mjs +1 -1
  20. package/dist/{google-interactions-DNXzPPwQ.mjs → google-interactions-9SSqsJg9.mjs} +52 -84
  21. package/dist/{google-messages-l7wgIF5I.mjs → google-messages-DsB7fmoQ.mjs} +26 -35
  22. package/dist/google-provider-stream-CcEI2-MC.mjs +58 -0
  23. package/dist/google-sYI2wnY6.mjs +20 -0
  24. package/dist/{google-shared-V8jogVPq.mjs → google-shared-zGR0QUyS.mjs} +6 -15
  25. package/dist/google-vertex-Dw_abY1w.mjs +40 -0
  26. package/dist/{host-u3o8XiAp.mjs → host-Bf3NjYNj.mjs} +3 -2
  27. package/dist/{host-DiPhRjrc.d.mts → host-CTDz7LXD.d.mts} +6 -3
  28. package/dist/{host-policy-BwhNNGQR.mjs → host-policy-BzZluO6_.mjs} +1 -1
  29. package/dist/{index-D27wAoOr.d.mts → index-BYDvopUB.d.mts} +8 -7
  30. package/dist/index.d.mts +7 -7
  31. package/dist/index.mjs +7 -6
  32. package/dist/internal/anthropic.d.mts +5 -5
  33. package/dist/internal/anthropic.mjs +4 -4
  34. package/dist/internal/openai-completions-compat.d.mts +1 -1
  35. package/dist/internal/openai-completions-compat.mjs +1 -1
  36. package/dist/internal/openai-responses-payload-policy.d.mts +2 -2
  37. package/dist/internal/openai-responses-payload-policy.mjs +2 -3
  38. package/dist/internal/openai.d.mts +9 -9
  39. package/dist/internal/openai.mjs +9 -11
  40. package/dist/internal/runtime.d.mts +31 -13
  41. package/dist/internal/runtime.mjs +10 -13
  42. package/dist/internal/shared.d.mts +5 -5
  43. package/dist/internal/shared.mjs +6 -7
  44. package/dist/internal/tool-schema.mjs +2 -2
  45. package/dist/{llm-request-activity-D8f_oxHj.mjs → llm-request-activity-CfMuh5cC.mjs} +2 -2
  46. package/dist/{mistral-cnoBDSIg.mjs → mistral-dCDCR5ur.mjs} +71 -146
  47. package/dist/{model-transport-url-C5f59L3Y.d.mts → model-transport-url-BrsjjdjR.d.mts} +5 -1
  48. package/dist/{number-coercion-V8-BhME4.mjs → number-coercion-C3hztWoY.mjs} +5 -4
  49. package/dist/{openai-chatgpt-responses-CHdn8YJ_.mjs → openai-chatgpt-responses-V4iP0dv5.mjs} +118 -194
  50. package/dist/{openai-completions-BZfHIaZ7.mjs → openai-completions-BY-kr5IS.mjs} +7 -6
  51. package/dist/{openai-completions-compat-GMN8A0fm.mjs → openai-completions-compat-CYX18uDk.mjs} +10 -6
  52. package/dist/{openai-completions-compat-BgPg1BRs.d.mts → openai-completions-compat-i-nLZxFy.d.mts} +10 -11
  53. package/dist/{openai-completions-transport-CuoQfnKV.mjs → openai-completions-transport-v38m71Oq.mjs} +1449 -294
  54. package/dist/{openai-prompt-cache-CFviG_D4.d.mts → openai-prompt-cache-DIPMrMFy.d.mts} +2 -2
  55. package/dist/{openai-prompt-cache-BK6E2g4Q.mjs → openai-prompt-cache-r93BJhjm.mjs} +1 -1
  56. package/dist/{openai-responses-BhAZFsL9.mjs → openai-responses-D5oiAUOG.mjs} +9 -10
  57. package/dist/{openai-responses-compaction-replay-BBNo098-.d.mts → openai-responses-compaction-replay-B2FE4Nw8.d.mts} +4 -4
  58. package/dist/{openai-responses-contracts-D5yVZBp-.d.mts → openai-responses-contracts-DKqMJ1Ct.d.mts} +9 -4
  59. package/dist/{openai-responses-contracts-BKu8O7l4.mjs → openai-responses-contracts-DlKMMTxK.mjs} +26 -6
  60. package/dist/{openai-responses-compaction-window-tA4QkU0o.mjs → openai-responses-endpoint-CinGh4VZ.mjs} +17 -7
  61. package/dist/{openai-responses-payload-policy-s1apQlZZ.d.mts → openai-responses-payload-policy-C7GsA1y0.d.mts} +2 -4
  62. package/dist/{openai-responses-prompt-observer-internal-CefUzh8M.mjs → openai-responses-request-lifecycle-NSIJo9jY.mjs} +39 -4
  63. package/dist/{openai-responses-shared-CKNmC3vC.mjs → openai-responses-shared-D-aDYAkJ.mjs} +1037 -328
  64. package/dist/{openai-responses-terminal-usage-CempLedn.d.mts → openai-responses-terminal-usage-BygjiAdi.d.mts} +2 -2
  65. package/dist/{openai-tool-schema-BIrI0mrA.mjs → openai-tool-schema-DDPXsvJP.mjs} +220 -400
  66. package/dist/{positive-integer-CwLi8LUL.mjs → positive-integer-CqWjqSi9.mjs} +1 -1
  67. package/dist/{provider-error-DQBE1bUQ.mjs → provider-error-CF9GWCs2.mjs} +5 -3
  68. package/dist/{provider-options-CkieKvNJ.d.mts → provider-options-CVrXZBtA.d.mts} +6 -10
  69. package/dist/{provider-transport-turn-state-BX6TfCyW.mjs → provider-transport-turn-state-BOpxgm-J.mjs} +2 -2
  70. package/dist/{provider-types-v3bmqsfg.d.mts → provider-types-CHtRx0dI.d.mts} +3 -3
  71. package/dist/provider-types.d.mts +6 -6
  72. package/dist/providers.d.mts +2 -2
  73. package/dist/providers.mjs +12 -12
  74. package/dist/{reasoning-tag-text-partitioner-Ju9VpUGl.mjs → reasoning-tag-text-partitioner-CpOy9-IQ.mjs} +374 -235
  75. package/dist/{required-api-key-D4kn3252.mjs → required-api-key-CFJvcFy_.mjs} +1 -1
  76. package/dist/{simple-options-7QuSKriJ.mjs → simple-options-BAu4B54D.mjs} +9 -11
  77. package/dist/{src-VWy9E7DZ.mjs → src-C44MKrW5.mjs} +20 -9
  78. package/dist/{stream-DFaRxi2D.mjs → stream-Dd8DwRFL.mjs} +12 -21
  79. package/dist/{stream-first-event-timeout-D9ZmL_s9.mjs → stream-first-event-timeout-Dc42hKv6.mjs} +8 -21
  80. package/dist/{streaming-byte-guard-CC-HMn_u.mjs → streaming-byte-guard-DBXr1XYn.mjs} +16 -1
  81. package/dist/{string-normalization-PN10hf6d.mjs → string-normalization-I3ux50s9.mjs} +1 -1
  82. package/dist/{text-signature-D_vRrx-z.mjs → text-signature-Drb4Erb8.mjs} +32 -5
  83. package/dist/{tool-schema-json-projection-Ct8SeBeJ.mjs → tool-schema-json-projection-B8sG1I9v.mjs} +29 -23
  84. package/dist/{transport-stream-shared-DW-7-qLR.d.mts → transport-stream-shared-BmpzDtdQ.d.mts} +4 -4
  85. package/dist/{transport-stream-shared-CCR7hSW0.mjs → transport-stream-shared-CWGOuLcA.mjs} +8 -16
  86. package/dist/transports.d.mts +34 -23
  87. package/dist/transports.mjs +76 -1235
  88. package/dist/{types-DvzmWW8J.d.mts → types-Bd2T86VJ.d.mts} +5 -23
  89. package/dist/types-Kdfw_04V.d.mts +1 -0
  90. package/dist/types.d.mts +6 -6
  91. package/dist/types.mjs +5 -4
  92. package/dist/{validation-B3lQt_VE.d.mts → validation-DdGB1yy3.d.mts} +1 -1
  93. package/dist/{validation-DbqlIfDn.mjs → validation-ZX_sPVV0.mjs} +3 -9
  94. package/dist/validation.d.mts +1 -1
  95. package/dist/validation.mjs +1 -1
  96. package/package.json +4 -9
  97. package/dist/env-api-keys-BR0MUYYD.d.mts +0 -17
  98. package/dist/event-stream-DqDQWqiy.d.mts +0 -1
  99. package/dist/google-B2g_Xn4d.mjs +0 -54
  100. package/dist/google-vertex-_khoip47.mjs +0 -88
  101. package/dist/internal/env-api-keys.d.mts +0 -2
  102. package/dist/internal/env-api-keys.mjs +0 -2
  103. package/dist/openai-responses-endpoint-TV0y50fb.mjs +0 -11
  104. package/dist/openai-responses-request-lifecycle-Fsag-IGZ.mjs +0 -36
  105. package/dist/openai-transport-params-D7JMUPjf.mjs +0 -735
  106. package/dist/openai-web-search-tools-Cfu0uLyN.mjs +0 -14
  107. package/dist/provider-replay-context-CO_Eplnc.mjs +0 -25
  108. package/dist/types-UlNana-2.d.mts +0 -1
@@ -1,35 +1,41 @@
1
1
  import { _ as runtimeContextContentToText, f as hasRuntimeContextMarker, p as isRuntimeContextMessage } from "./types-CQc6JNG4.mjs";
2
- import { r as appendAssistantThinking } from "./event-stream-C5AbCAaZ.mjs";
3
- import { o as isRecord } from "./record-coerce-CNDovvft.mjs";
2
+ import { r as appendAssistantThinking } from "./event-stream-X2gmsUWv.mjs";
3
+ import { i as asOptionalRecord, o as isRecord, r as asOptionalObjectRecord } from "./record-coerce-CNDovvft.mjs";
4
4
  import { s as readNonEmptyStringPreservingWhitespace, t as hasNonEmptyString } from "./string-coerce-CtgOVOSv.mjs";
5
- import { n as asNonNegativeFiniteNumber } from "./number-coercion-V8-BhME4.mjs";
6
- import { N as isImageWithMediaPayload, r as getAiTransportHost } from "./host-u3o8XiAp.mjs";
7
- import { _ as isOpenAIGpt54MiniModel, v as isOpenAIGpt55Model, y as isOpenAIGpt56Model } from "./openai-responses-contracts-BKu8O7l4.mjs";
8
- import { r as uniqueStrings } from "./string-normalization-PN10hf6d.mjs";
9
- import { o as truncateUtf16Safe } from "./provider-error-DQBE1bUQ.mjs";
10
- import { r as resolveOpenAIPromptCacheParams } from "./openai-prompt-cache-BK6E2g4Q.mjs";
11
- import { r as emitModelTransportDebug } from "./diagnostics-Caj-4RBA.mjs";
12
- import { c as supportsModelTools, r as estimateStringChars } from "./text-signature-D_vRrx-z.mjs";
13
- import { i as resolveOpenAICompletionsCompat, l as shouldOmitOllamaCompatResponseFormat, n as isNativeOpenAIEndpoint, s as resolveOpenAICompletionsResponseFormat, t as detectOpenAICompletionsCompat } from "./openai-completions-compat-GMN8A0fm.mjs";
14
- import { i as resolveProviderEndpoint, t as buildGuardedModelFetch } from "./host-policy-BwhNNGQR.mjs";
5
+ import { n as asNonNegativeFiniteNumber, r as asPositiveFiniteNumber } from "./number-coercion-C3hztWoY.mjs";
6
+ import { N as isImageWithMediaPayload, a as resolveAiTransportHeaderSentinels, r as getAiTransportHost } from "./host-Bf3NjYNj.mjs";
7
+ import { M as resolveOpenAIThinkingApi, S as isOpenAIGpt6Model, _ as isResponsesServiceTierRejection, b as isOpenAIGpt55Model, d as OpenAIResponsesWebSocketSafeRetryError, g as responsesServiceTierObserver, k as supportsOpenAITemperature, l as OpenAIResponsesWebSocketPostDispatchError, m as parseOpenAIResponsesWebSocketServerError, r as OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS, t as AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS, u as OpenAIResponsesWebSocketPreDispatchError, v as nextResponsesServiceTier, x as isOpenAIGpt56Model, y as isOpenAIGpt54MiniModel } from "./openai-responses-contracts-DlKMMTxK.mjs";
8
+ import { r as uniqueStrings } from "./string-normalization-I3ux50s9.mjs";
9
+ import { n as getSessionResourceOwnerId, r as registerSessionResourceCleanup } from "./session-resources-D1wgDQ8C.mjs";
10
+ import { c as stableStringify, s as truncateUtf16Safe } from "./provider-error-CF9GWCs2.mjs";
11
+ import { r as resolveOpenAIPromptCacheParams } from "./openai-prompt-cache-r93BJhjm.mjs";
12
+ import { d as hasOnlyResponsesFunctionTools, i as emitModelTransportError, r as emitModelTransportDebug, t as formatModelTransportDebugBaseUrl } from "./diagnostics-tQasYct1.mjs";
13
+ import { f as supportsModelTools, i as providerReplayContextMatches, n as buildProviderReplayContext, o as estimateStringChars, r as isProviderReplayContext } from "./text-signature-Drb4Erb8.mjs";
14
+ import { c as resolveOpenAIResponsesTextFormat, i as resolveOpenAICompletionsCompat, l as shouldOmitOllamaCompatResponseFormat, n as isNativeOpenAIEndpoint, o as usesNativeOpenAICodexResponsesBackend, r as isOpenAICodexResponsesModel, s as resolveOpenAICompletionsResponseFormat, t as detectOpenAICompletionsCompat } from "./openai-completions-compat-CYX18uDk.mjs";
15
+ import { i as resolveProviderEndpoint, t as buildGuardedModelFetch } from "./host-policy-BzZluO6_.mjs";
15
16
  import { i as resolveCacheRetention, r as buildCopilotDynamicHeaders } from "./cloudflare-5qSGvIUH.mjs";
16
- import { E as createToolArgumentPreviewSchedule, O as parseStreamingJson, P as sanitizeSurrogates, S as withProviderResponseHook, _ as sanitizeNonEmptyTransportPayloadText, b as transportAbortError, c as failTransportStream, d as iterateModelStream, l as finalizeTerminalToolCallArguments, s as createWritableTransportEventStream, u as finalizeTransportStream, y as throwIfModelStreamAborted } from "./transport-stream-shared-CCR7hSW0.mjs";
17
- import { C as stripSystemPromptCacheBoundary, D as sortPromptCacheToolsByName, S as splitSystemPromptRelocatableBoundary, d as describeToolResultMediaPlaceholder, l as codeModeToolSurfaceObserver, m as extractToolResultText, s as prepareModelRequestBody, u as reasoningTagTextPolicy, w as stripSystemPromptRelocatableBoundary, x as splitSystemPromptCacheBoundary } from "./simple-options-7QuSKriJ.mjs";
18
- import { C as log, D as readOpenAICompletionsReasoningBatch, E as readOpenAICompletionsContentDeltas, O as resolveOpenAIClientBaseUrl, S as isOpenAICompletionsThinkingEnabled, T as parseOpenAICompletionsUsage, a as enforceCodeModeResponsesToolSurface, d as prepareOpenAITools, f as projectOpenAITools, g as resolveOpenAISimpleReasoningEffort, h as resolveOpenAIRequestReasoning, i as buildOpenAISdkRequestOptions, k as resolvePromptCacheKey, l as resolveCodeModeResponsesVisibleToolNames, n as buildOpenAIClientHeaders, p as reconcileOpenAICompletionsToolChoice, r as buildOpenAISdkClientOptions, s as getCompat, t as assertCodeModeResponsesToolSurface, u as resolveOpenAIStrictToolFlagWithDiagnostics, v as GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP, w as measureUtf8AppendBytes, y as createOpenAIProviderAcceptanceHook } from "./openai-transport-params-D7JMUPjf.mjs";
19
- import { n as getEnvApiKey } from "./env-api-keys-CyX4VKGO.mjs";
20
- import { n as transformProviderMessages, t as createAssistantOutput } from "./assistant-output-D5762GPH.mjs";
21
- import { a as tagUnresolvedTextAsCommentary, i as tagPendingCommentaryText, n as rememberPendingCommentaryTags, r as tagInterruptedTextPhases, t as clearPendingCommentaryText } from "./assistant-text-phase-DVZOxbuR.mjs";
22
- import { t as notifyLlmRequestActivity } from "./llm-request-activity-D8f_oxHj.mjs";
17
+ import { E as createToolArgumentPreviewSchedule, M as racePromiseWithAbortSignal, O as parseStreamingJson, P as sanitizeSurrogates, S as withProviderResponseHook, b as transportAbortError, c as failTransportStream, d as iterateModelStream, h as notifyProviderStreamOpened, l as finalizeTerminalToolCallArguments, s as createWritableTransportEventStream, u as finalizeTransportStream, v as sanitizeTransportPayloadText, y as throwIfModelStreamAborted } from "./transport-stream-shared-CWGOuLcA.mjs";
18
+ import { C as stripSystemPromptCacheBoundary, D as sortPromptCacheToolsByName, S as splitSystemPromptRelocatableBoundary, d as describeToolResultMediaPlaceholder, l as codeModeToolSurfaceObserver, m as extractToolResultText, s as prepareModelRequestBody, u as reasoningTagTextPolicy, w as stripSystemPromptRelocatableBoundary, x as splitSystemPromptCacheBoundary } from "./simple-options-BAu4B54D.mjs";
19
+ import { $ as replayResponsesReasoningUpdates, A as summarizeResponsesPayload, At as measureUtf8AppendBytes, B as responsesInputFingerprint, C as readResponsesRecoveryEvent, Ct as toOpenAIResponsesToolChoice, D as logResponsesFailedNoDetails, Dt as createResponseModelTracker, E as ResponsesStreamFailure, Ft as resolvePromptCacheKey, G as responsesContinuationRequestFingerprint, H as recordResponsesContinuationState, I as convertResponsesMessages, It as redactIdentifier, Lt as sha256Hex, Mt as readOpenAICompletionsContentDeltas, Nt as readOpenAICompletionsReasoningBatch, O as safeDebugValue, Ot as isOpenAICompletionsThinkingEnabled, P as buildResponsesInputMessage, Pt as resolveOpenAIClientBaseUrl, Q as isConfigurationUpdate, R as readResponsesInputReplayState, S as isInvalidEncryptedContentError, St as reconcileOpenAIResponsesToolChoice, T as resolveNextResponsesEncryptedContentAttempt, Tt as createOpenAIProviderAcceptanceHook, U as resolveResponsesContinuationRequest, V as claimOpenAIResponsesHttpContinuation, W as responsesContinuationPrefixFingerprint, _t as resolveOpenAISimpleReasoningEffort, a as prepareResponsesTools, at as suppressOpenAIResponsesCompaction, bt as projectOpenAITools, c as observeResponsesStream, ct as buildOpenAISdkClientOptions, et as supportsResponsesReasoningUpdate, ft as getCompat, gt as resolveOpenAIRequestReasoning, ht as resolveOpenAIStrictToolFlagWithDiagnostics, j as recordResponsesContextUsage, jt as parseOpenAICompletionsUsage, k as summarizeOpenAITransportError, kt as log, lt as buildOpenAISdkRequestOptions, mt as resolveCodeModeResponsesVisibleToolNames, n as applyResponsesServiceTierPricing, nt as buildOpenAIResponsesReasoningReplayMetadata, ot as assertCodeModeResponsesToolSurface, s as processResponsesStream, st as buildOpenAIClientHeaders, ut as enforceCodeModeResponsesToolSurface, w as resolveAzureOpenAIApiVersion, wt as GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP, x as createResponsesStreamWithRecovery, xt as reconcileOpenAICompletionsToolChoice, yt as prepareOpenAITools, z as recordResponsesInputReplay } from "./openai-responses-shared-D-aDYAkJ.mjs";
20
+ import { n as getEnvApiKey } from "./env-api-keys-CrxwdylR.mjs";
21
+ import { n as transformProviderMessages, t as createAssistantOutput } from "./assistant-output-BuhRpLeD.mjs";
22
+ import { a as tagUnresolvedTextAsCommentary, i as tagPendingCommentaryText, n as rememberPendingCommentaryTags, r as tagInterruptedTextPhases, t as clearPendingCommentaryText } from "./assistant-text-phase-Bn1hbvK9.mjs";
23
+ import { t as notifyLlmRequestActivity } from "./llm-request-activity-CfMuh5cC.mjs";
23
24
  import { n as resolveOpencodeSessionHeaders } from "./session-affinity-DA4WHv1h.mjs";
24
25
  import "./types.mjs";
25
- import { i as createOpenAIProviderClient, n as resolveProviderSimpleCompletionHeaders, r as resolveProviderTransportTurnState, t as filterProviderTurnHeadersForExplicitOpencodeSession } from "./provider-transport-turn-state-BX6TfCyW.mjs";
26
- import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-D9ZmL_s9.mjs";
27
- import { f as withPreparedToolSchemaNormalization, r as normalizeOpenAIStrictToolParameters } from "./openai-tool-schema-BIrI0mrA.mjs";
26
+ import { i as createOpenAIProviderClient, n as resolveProviderSimpleCompletionHeaders, r as resolveProviderTransportTurnState, t as filterProviderTurnHeadersForExplicitOpencodeSession } from "./provider-transport-turn-state-BOpxgm-J.mjs";
27
+ import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-Dc42hKv6.mjs";
28
+ import { t as boundResponseBody } from "./streaming-byte-guard-DBXr1XYn.mjs";
29
+ import { f as withPreparedToolSchemaNormalization, r as normalizeOpenAIStrictToolParameters } from "./openai-tool-schema-DDPXsvJP.mjs";
28
30
  import { isGoogleGemini3ThinkingLevelModel } from "./internal/google-model-family.mjs";
29
31
  import { t as mapOpenAIStopReason } from "./openai-stop-reason-8s70vDXj.mjs";
30
- import { t as createReasoningTagTextPartitioner } from "./reasoning-tag-text-partitioner-Ju9VpUGl.mjs";
32
+ import { t as createReasoningTagTextPartitioner } from "./reasoning-tag-text-partitioner-CpOy9-IQ.mjs";
33
+ import { i as resolveAzureDeploymentNameFromMap, t as isOpenAICompatibleAzureResponsesBaseUrl } from "./azure-openai-responses-client-compat-D0dvJMbZ.mjs";
34
+ import { i as isOpenAIResponsesCompactionOutput, l as resolveOpenAIResponsesPayloadPolicy, n as supportsNativeOpenAIResponsesEndpoint, o as sanitizeResponsesImagePayload, r as createBoundedOpenAIResponsesCompactionFetch, s as applyOpenAIResponsesPayloadPolicy, t as isOfficialOpenAIResponsesBaseUrl } from "./openai-responses-endpoint-CinGh4VZ.mjs";
35
+ import { n as withResponsesRequestAcceptance, r as createResponsesPromptEgressObserver, t as responsesRequestLifecycle } from "./openai-responses-request-lifecycle-NSIJo9jY.mjs";
31
36
  import { randomUUID } from "node:crypto";
32
- import OpenAI from "openai";
37
+ import OpenAI, { AzureOpenAI } from "openai";
38
+ import { ResponsesWS } from "openai/resources/responses/ws.js";
33
39
  //#region packages/ai/src/transports/deepseek-dsml-grammar.ts
34
40
  const DEEPSEEK_DSML_MARKERS = [
35
41
  "|",
@@ -247,37 +253,33 @@ function applyCompletionsAnthropicCacheControl(payload, cacheControl = { type: "
247
253
  * OpenAI Chat Completions compatibility helpers. Some providers only accept
248
254
  * role/content messages with plain string content instead of text block arrays.
249
255
  */
250
- function flattenStringOnlyCompletionContent(content) {
251
- if (!Array.isArray(content)) return content;
252
- const textParts = [];
253
- for (const item of content) {
254
- if (!item || typeof item !== "object" || item.type !== "text" || typeof item.text !== "string") return content;
255
- textParts.push(item.text);
256
- }
257
- return textParts.join("\n");
258
- }
259
256
  /** Flatten string-only text block content arrays into newline-joined strings. */
260
257
  function flattenCompletionMessagesToStringContent(messages) {
261
258
  return messages.map((message) => {
262
- if (!message || typeof message !== "object") return message;
263
- const content = message.content;
264
- const flattenedContent = flattenStringOnlyCompletionContent(content);
265
- if (flattenedContent === content) return message;
259
+ const record = asOptionalObjectRecord(message);
260
+ const content = record?.content;
261
+ if (!Array.isArray(content)) return message;
262
+ const textParts = [];
263
+ for (const item of content) {
264
+ const part = asOptionalObjectRecord(item);
265
+ if (part?.type !== "text" || typeof part.text !== "string") return message;
266
+ textParts.push(part.text);
267
+ }
266
268
  return {
267
- ...message,
268
- content: flattenedContent
269
+ ...record,
270
+ content: textParts.join("\n")
269
271
  };
270
272
  });
271
273
  }
272
274
  /** Strip completion messages to role/content fields for strict providers. */
273
275
  function stripCompletionMessagesToRoleContent(messages) {
274
276
  return messages.map((message) => {
275
- if (!message || typeof message !== "object" || Array.isArray(message)) return message;
276
- const record = message;
277
- const stripped = {};
278
- if (Object.hasOwn(record, "role")) stripped.role = record.role;
279
- if (Object.hasOwn(record, "content")) stripped.content = record.content;
280
- return stripped;
277
+ const record = asOptionalRecord(message);
278
+ if (!record) return message;
279
+ return {
280
+ ...Object.hasOwn(record, "role") ? { role: record.role } : {},
281
+ ...Object.hasOwn(record, "content") ? { content: record.content } : {}
282
+ };
281
283
  });
282
284
  }
283
285
  //#endregion
@@ -321,6 +323,15 @@ function createOpenAIEncryptedToolCallReasoningTracker() {
321
323
  }
322
324
  };
323
325
  }
326
+ function hasObservableContent(value) {
327
+ if (typeof value === "string") return value.length > 0;
328
+ if (Array.isArray(value)) return value.some(hasObservableContent);
329
+ if (isRecord(value)) return Object.entries(value).some(([field, nestedValue]) => field !== "type" && field !== "id" && field !== "index" && hasObservableContent(nestedValue));
330
+ return false;
331
+ }
332
+ function hasOpenAICompletionsDeltaContent(delta) {
333
+ return Object.entries(delta).some(([field, value]) => field !== "role" && hasObservableContent(value));
334
+ }
324
335
  /** Normalize the SDK's legacy single-function lane into its modern tool-call shape. */
325
336
  function createOpenAICompletionsToolCallDeltaNormalizer() {
326
337
  let sawModernToolCall = false;
@@ -342,12 +353,6 @@ function createOpenAICompletionsToolCallDeltaNormalizer() {
342
353
  pendingFollowingDeltaBytes += nextDeltaBytes;
343
354
  pendingFollowingDeltas.push(delta);
344
355
  };
345
- const hasObservableContent = (value) => {
346
- if (typeof value === "string") return value.length > 0;
347
- if (Array.isArray(value)) return value.some(hasObservableContent);
348
- if (isRecord(value)) return Object.entries(value).some(([field, nestedValue]) => field !== "type" && field !== "id" && field !== "index" && hasObservableContent(nestedValue));
349
- return false;
350
- };
351
356
  return (delta, finishReason) => {
352
357
  const ordinaryDelta = { ...delta };
353
358
  delete ordinaryDelta.function_call;
@@ -383,7 +388,7 @@ function createOpenAICompletionsToolCallDeltaNormalizer() {
383
388
  }];
384
389
  const hadPendingLegacyCall = pendingLegacyToolCall !== void 0;
385
390
  const leadingDeltas = [];
386
- if (Object.entries(ordinaryDelta).some(([field, value]) => field !== "role" && hasObservableContent(value))) {
391
+ if (hasOpenAICompletionsDeltaContent(ordinaryDelta)) {
387
392
  if (hadPendingLegacyCall) bufferFollowingDelta(ordinaryDelta);
388
393
  else leadingDeltas.push({
389
394
  delta: ordinaryDelta,
@@ -435,10 +440,7 @@ function finalizeOpenAICompletionsToolCalls(output, options = {}) {
435
440
  const isToolCall = (block) => block.type === "toolCall";
436
441
  const hasToolCalls = output.content.some(isToolCall);
437
442
  if (output.stopReason === "toolUse" && !hasToolCalls) output.stopReason = "stop";
438
- if (output.stopReason === "stop" && hasToolCalls && options.allowSilentToolCallPromotion !== false && !output.content.some((block) => {
439
- const candidate = block;
440
- return candidate.type === "text" && typeof candidate.text === "string" && candidate.text.trim().length > 0;
441
- })) output.stopReason = "toolUse";
443
+ if (output.stopReason === "stop" && hasToolCalls && options.allowSilentToolCallPromotion !== false && !output.content.some((block) => block.type === "text" && block.text.trim().length > 0)) output.stopReason = "toolUse";
442
444
  if (output.stopReason !== "toolUse") {
443
445
  if (hasToolCalls) output.content = output.content.filter((block) => !isToolCall(block));
444
446
  return;
@@ -617,7 +619,7 @@ function convertMessages(model, context, compat, options = {}) {
617
619
  const images = toolMsg.content.filter(isImageWithMediaPayload);
618
620
  const toolResultMsg = {
619
621
  role: "tool",
620
- content: sanitizeNonEmptyTransportPayloadText(textResult, mediaPlaceholder),
622
+ content: textResult.trim() ? textResult : mediaPlaceholder ?? "(no output)",
621
623
  tool_call_id: toolMsg.toolCallId
622
624
  };
623
625
  if (compat.requiresToolResultName && toolMsg.toolName) toolResultMsg.name = toolMsg.toolName;
@@ -678,24 +680,36 @@ function relocateNonBehavioralRegion(args) {
678
680
  }
679
681
  }
680
682
  //#endregion
681
- //#region packages/ai/src/transports/openai-completions-direct-policy.ts
682
- function applyDirectCompletionsReasoningAndRouting(params, model, reasoning, compat) {
683
+ //#region packages/ai/src/transports/openai-completions-policy.ts
684
+ function applyCompletionsReasoningAndRouting(params, model, reasoning, compat, mode) {
685
+ const direct = mode === "direct";
683
686
  const nativeEffort = compat.thinkingFormat === "openrouter" ? void 0 : reasoning.effort;
684
- const reasoningEnabled = reasoning.thinkingEnabled ?? false;
685
- if (compat.thinkingFormat === "zai" && model.reasoning) params.thinking = reasoningEnabled ? {
686
- type: "enabled",
687
- clear_thinking: false
688
- } : { type: "disabled" };
689
- else if (compat.thinkingFormat === "qwen" && model.reasoning) params.enable_thinking = reasoningEnabled;
690
- else if (compat.thinkingFormat === "qwen-chat-template" && model.reasoning) params.chat_template_kwargs = {
691
- enable_thinking: reasoningEnabled,
692
- preserve_thinking: true
693
- };
694
- else if ((compat.thinkingFormat === "deepseek" || compat.thinkingFormat === "together") && model.reasoning) {
695
- if (compat.thinkingFormat === "deepseek") params.thinking = { type: reasoningEnabled ? "enabled" : "disabled" };
696
- else params.reasoning = { enabled: reasoningEnabled };
697
- if (reasoningEnabled && compat.supportsReasoningEffort && nativeEffort !== void 0) params.reasoning_effort = nativeEffort;
698
- } else if (model.reasoning && compat.supportsReasoningEffort && nativeEffort !== void 0) params.reasoning_effort = nativeEffort;
687
+ const enabled = reasoning.thinkingEnabled ?? false;
688
+ if (model.reasoning) {
689
+ let allowScalarEffort = true;
690
+ if (direct && compat.thinkingFormat === "zai") {
691
+ params.thinking = enabled ? {
692
+ type: "enabled",
693
+ clear_thinking: false
694
+ } : { type: "disabled" };
695
+ allowScalarEffort = false;
696
+ } else if (compat.thinkingFormat === "qwen") {
697
+ params.enable_thinking = enabled;
698
+ allowScalarEffort = false;
699
+ } else if (compat.thinkingFormat === "qwen-chat-template") {
700
+ params.chat_template_kwargs = {
701
+ enable_thinking: enabled,
702
+ ...direct ? { preserve_thinking: true } : {}
703
+ };
704
+ allowScalarEffort = false;
705
+ } else if (compat.thinkingFormat === "together" || direct && compat.thinkingFormat === "deepseek") {
706
+ if (compat.thinkingFormat === "deepseek") params.thinking = { type: enabled ? "enabled" : "disabled" };
707
+ else params.reasoning = { enabled };
708
+ allowScalarEffort = enabled;
709
+ }
710
+ if (allowScalarEffort && compat.supportsReasoningEffort && (direct ? nativeEffort !== void 0 : nativeEffort)) params.reasoning_effort = nativeEffort;
711
+ }
712
+ if (!direct) return;
699
713
  if (compat.openRouterRouting) params.provider = compat.openRouterRouting;
700
714
  if (model.baseUrl.includes("ai-gateway.vercel.sh") && model.compat?.vercelGatewayRouting) {
701
715
  const routing = model.compat.vercelGatewayRouting;
@@ -738,21 +752,15 @@ function injectToolCallThoughtSignatures(outgoingMessages, context, model) {
738
752
  }
739
753
  if (sigById.size === 0 && !fallbackSig) return;
740
754
  for (const message of outgoingMessages) {
741
- const toolCalls = message.tool_calls;
755
+ const toolCalls = "tool_calls" in message ? message.tool_calls : void 0;
742
756
  if (!Array.isArray(toolCalls)) continue;
743
757
  for (const toolCall of toolCalls) {
744
- const id = toolCall.id;
745
- if (typeof id !== "string") continue;
746
- let sig = sigById.get(id) ?? fallbackSig;
747
- if (typeof sig === "string" && sig.length > 0) {
758
+ let sig = sigById.get(toolCall.id) ?? fallbackSig;
759
+ if (sig) {
748
760
  if (hasGoogleCompatThoughtSignatureTruncationFootprint(sig.trim())) sig = fallbackSig;
749
761
  }
750
- if (typeof sig !== "string" || sig.length === 0) continue;
751
- const extra = toolCall.extra_content && typeof toolCall.extra_content === "object" ? toolCall.extra_content : {};
752
- toolCall.extra_content = extra;
753
- const google = extra.google && typeof extra.google === "object" ? extra.google : {};
754
- extra.google = google;
755
- google.thought_signature = sig;
762
+ if (!sig) continue;
763
+ Object.assign(toolCall, { extra_content: { google: { thought_signature: sig } } });
756
764
  }
757
765
  }
758
766
  }
@@ -762,9 +770,6 @@ const COMPLETIONS_REASONING_REPLAY_FIELDS = [
762
770
  "reasoning",
763
771
  "reasoning_text"
764
772
  ];
765
- function stripCompletionsReasoningReplayFields(record) {
766
- for (const field of COMPLETIONS_REASONING_REPLAY_FIELDS) delete record[field];
767
- }
768
773
  function sanitizeOpenRouterReasoningReplayFields(record) {
769
774
  const reasoningDetails = record.reasoning_details;
770
775
  if (typeof reasoningDetails === "string") {
@@ -776,12 +781,6 @@ function sanitizeOpenRouterReasoningReplayFields(record) {
776
781
  if (typeof reasoningText === "string" && reasoningText.length > 0 && typeof record.reasoning !== "string" && typeof record.reasoning_content !== "string") record.reasoning = reasoningText;
777
782
  delete record.reasoning_text;
778
783
  }
779
- function sanitizeReasoningContentReplayFields(record) {
780
- if ("reasoning_content" in record && typeof record.reasoning_content !== "string") delete record.reasoning_content;
781
- delete record.reasoning_details;
782
- delete record.reasoning;
783
- delete record.reasoning_text;
784
- }
785
784
  const REASONING_CONTENT_REPLAY_MODEL_IDS = /* @__PURE__ */ new Set([
786
785
  "deepseek-v4-flash",
787
786
  "deepseek-v4-pro",
@@ -839,23 +838,21 @@ function shouldTrustReasoningContentReplayMetadata(model) {
839
838
  if (model.provider.trim().toLowerCase() === "openai") return false;
840
839
  return shouldPreserveOpenRouterReasoningReplay(model);
841
840
  }
842
- function sanitizeCompletionsReasoningReplayFields(messages, options) {
843
- if (!Array.isArray(messages)) return;
844
- for (const msg of messages) {
845
- if (!msg || typeof msg !== "object") continue;
846
- const record = msg;
847
- if (record.role !== "assistant") continue;
848
- if (options.preserveOpenRouterReasoning) sanitizeOpenRouterReasoningReplayFields(record);
849
- else if (options.preserveReasoningContent) sanitizeReasoningContentReplayFields(record);
850
- else stripCompletionsReasoningReplayFields(record);
851
- }
852
- }
853
841
  function applyCompletionsReplay(outgoingMessages, context, model, compat) {
854
842
  injectToolCallThoughtSignatures(outgoingMessages, context, model);
855
- sanitizeCompletionsReasoningReplayFields(outgoingMessages, {
856
- preserveOpenRouterReasoning: compat.thinkingFormat === "openrouter" && shouldPreserveOpenRouterReasoningReplay(model),
857
- preserveReasoningContent: shouldPreserveReasoningContentReplay(model, compat)
858
- });
843
+ const preserveOpenRouterReasoning = compat.thinkingFormat === "openrouter" && shouldPreserveOpenRouterReasoningReplay(model);
844
+ const preserveReasoningContent = shouldPreserveReasoningContentReplay(model, compat);
845
+ for (const message of outgoingMessages) {
846
+ if (message.role !== "assistant") continue;
847
+ if (preserveOpenRouterReasoning) sanitizeOpenRouterReasoningReplayFields(message);
848
+ else {
849
+ const record = message;
850
+ for (const field of COMPLETIONS_REASONING_REPLAY_FIELDS) {
851
+ if (preserveReasoningContent && field === "reasoning_content" && typeof record[field] === "string") continue;
852
+ delete record[field];
853
+ }
854
+ }
855
+ }
859
856
  }
860
857
  //#endregion
861
858
  //#region packages/ai/src/transports/openai-completions-params.ts
@@ -882,7 +879,8 @@ function resolveOpenAICompletionsMaxTokens(model, options) {
882
879
  };
883
880
  }
884
881
  function resolveOpenAICompletionsModelMaxTokens(model) {
885
- return typeof model.maxTokens === "number" && Number.isFinite(model.maxTokens) && model.maxTokens > 0 ? Math.floor(model.maxTokens) : void 0;
882
+ const maxTokens = asPositiveFiniteNumber(model.maxTokens);
883
+ return maxTokens === void 0 ? void 0 : Math.floor(maxTokens);
886
884
  }
887
885
  const OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN = 1.25;
888
886
  const OPENAI_COMPLETIONS_IMAGE_CHAR_ESTIMATE = 8e3;
@@ -897,12 +895,11 @@ function estimateJsonChars(value, fallback) {
897
895
  function estimateOpenAICompletionsInputTokens(payload) {
898
896
  let adjustedChars = 0;
899
897
  adjustedChars += estimateOpenAICompletionsMessagesChars(payload.messages);
900
- if (Array.isArray(payload.tools) && payload.tools.length > 0) adjustedChars += estimateJsonChars(payload.tools, 1024);
898
+ if (payload.tools?.length) adjustedChars += estimateJsonChars(payload.tools, 1024);
901
899
  if (payload.response_format !== void 0) adjustedChars += estimateJsonChars(payload.response_format, 256);
902
900
  return Math.ceil(adjustedChars / 4 * OPENAI_COMPLETIONS_INPUT_TOKEN_SAFETY_MARGIN);
903
901
  }
904
902
  function estimateOpenAICompletionsMessagesChars(messages) {
905
- if (!Array.isArray(messages)) return 0;
906
903
  let adjustedChars = 0;
907
904
  for (const message of messages) {
908
905
  if (!message || typeof message !== "object") continue;
@@ -933,35 +930,6 @@ function estimateOpenAICompletionsContentChars(value) {
933
930
  }
934
931
  return adjustedChars;
935
932
  }
936
- function resolveOpenAICompletionsEffectiveContextTokens(model) {
937
- const contextTokens = model.contextTokens;
938
- if (typeof contextTokens === "number" && Number.isFinite(contextTokens) && contextTokens > 0) return contextTokens;
939
- return typeof model.contextWindow === "number" && Number.isFinite(model.contextWindow) && model.contextWindow > 0 ? model.contextWindow : void 0;
940
- }
941
- function setQwenChatTemplateThinking(params, enabled) {
942
- const existing = params.chat_template_kwargs;
943
- params.chat_template_kwargs = existing && typeof existing === "object" && !Array.isArray(existing) ? {
944
- ...existing,
945
- enable_thinking: enabled
946
- } : { enable_thinking: enabled };
947
- }
948
- /** Return whether the binary control replaces scalar reasoning effort. */
949
- function applyBinaryCompletionsThinkingParams(params) {
950
- if (!params.modelReasoning) return false;
951
- const enabled = params.thinkingEnabled;
952
- switch (params.compatThinkingFormat) {
953
- case "qwen-chat-template":
954
- setQwenChatTemplateThinking(params.payload, enabled);
955
- return true;
956
- case "qwen":
957
- params.payload.enable_thinking = enabled;
958
- return true;
959
- case "together":
960
- params.payload.reasoning = { enabled };
961
- return !enabled;
962
- default: return false;
963
- }
964
- }
965
933
  function convertTools(tools, compat, model, mode) {
966
934
  const prepared = mode === "managed" ? prepareOpenAITools(tools) : void 0;
967
935
  const projection = prepared?.projection ?? projectOpenAITools(tools);
@@ -1012,12 +980,13 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
1012
980
  "qwen"
1013
981
  ].includes(model.provider));
1014
982
  const cacheOptOutIndexes = /* @__PURE__ */ new Set();
1015
- let messages = convertMessages(model, context, compat, {
983
+ const convertedMessages = convertMessages(model, context, compat, {
1016
984
  cacheOptOutIndexes,
1017
985
  preserveSystemPromptCacheBoundary: cacheControl !== void 0 && !managedCompat?.requiresStringContent
1018
986
  });
987
+ let messages = convertedMessages;
1019
988
  if (managedCompat) {
1020
- applyCompletionsReplay(messages, context, model, managedCompat);
989
+ applyCompletionsReplay(convertedMessages, context, model, managedCompat);
1021
990
  if (managedCompat.strictMessageKeys) messages = stripCompletionMessagesToRoleContent(messages);
1022
991
  if (managedCompat.requiresStringContent) messages = flattenCompletionMessagesToStringContent(messages);
1023
992
  }
@@ -1025,10 +994,10 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
1025
994
  const params = {
1026
995
  model: model.id,
1027
996
  messages,
1028
- stream: true,
997
+ stream: (options?.streaming ?? model.params?.streaming) !== false,
1029
998
  ...resolveOpenAIPromptCacheParams(model, cacheRetention, compat)
1030
999
  };
1031
- if (compat.supportsUsageInStreaming) params.stream_options = { include_usage: true };
1000
+ if (params.stream && compat.supportsUsageInStreaming) params.stream_options = { include_usage: true };
1032
1001
  if (compat.supportsStore) params.store = false;
1033
1002
  if (policy.mode === "direct" || compat.supportsPromptCacheKey && promptCacheKey) params.prompt_cache_key = compat.supportsPromptCacheKey ? promptCacheKey : void 0;
1034
1003
  if (options?.temperature !== void 0) params.temperature = options.temperature;
@@ -1051,13 +1020,13 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
1051
1020
  if (policy.mode === "direct") directToolProjection = converted.projection;
1052
1021
  if (converted.tools.length > 0 || policy.mode === "managed" && converted.projection.inputToolCount === 0 && converted.projection.diagnostics.length === 0) params.tools = converted.tools;
1053
1022
  else if (hasToolCallHistory(context.messages)) params.tools = [];
1054
- if (policy.mode === "direct" && compat.zaiToolStream && converted.tools.length > 0) params.tool_stream = true;
1023
+ if (policy.mode === "direct" && params.stream && compat.zaiToolStream && converted.tools.length > 0) params.tool_stream = true;
1055
1024
  if (policy.mode === "managed" && options?.toolChoice) {
1056
1025
  const toolChoice = reconcileOpenAICompletionsToolChoice(options.toolChoice, converted.projection);
1057
1026
  if (toolChoice !== void 0) params.tool_choice = toolChoice;
1058
- } else if (compatDetection?.capabilities.usesExplicitProxyLikeEndpoint && Array.isArray(params.tools) && params.tools.length > 0) params.tool_choice = "auto";
1027
+ } else if (compatDetection?.capabilities.usesExplicitProxyLikeEndpoint && params.tools?.length) params.tool_choice = "auto";
1059
1028
  } else if (hasToolCallHistory(context.messages)) params.tools = [];
1060
- if (compatDetection?.capabilities.usesExplicitProxyLikeEndpoint && Array.isArray(params.tools) && params.tools.length === 0) {
1029
+ if (compatDetection?.capabilities.usesExplicitProxyLikeEndpoint && params.tools?.length === 0) {
1061
1030
  delete params.tools;
1062
1031
  delete params.tool_choice;
1063
1032
  }
@@ -1074,7 +1043,7 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
1074
1043
  ...model,
1075
1044
  compat: model.compat ?? void 0
1076
1045
  }, simpleReasoning)) ?? (usesBinaryOpenRouterThinking ? void 0 : "high");
1077
- const reasoning = resolveOpenAIRequestReasoning(model, requestedEffort);
1046
+ const reasoning = resolveOpenAIRequestReasoning(model, requestedEffort, compat.reasoningEffortForOff);
1078
1047
  const { effort, thinkingEnabled } = reasoning;
1079
1048
  {
1080
1049
  const maxTokenBudget = policy.mode === "direct" ? {
@@ -1082,7 +1051,7 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
1082
1051
  clampToModelMaxTokens: true
1083
1052
  } : resolveOpenAICompletionsMaxTokens(model, options);
1084
1053
  const effectiveMaxTokens = maxTokenBudget.maxTokens;
1085
- const effectiveContextTokens = resolveOpenAICompletionsEffectiveContextTokens(model);
1054
+ const effectiveContextTokens = asPositiveFiniteNumber(model.contextTokens) ?? asPositiveFiniteNumber(model.contextWindow);
1086
1055
  let clampedMaxTokens = effectiveMaxTokens;
1087
1056
  const modelMaxTokens = resolveOpenAICompletionsModelMaxTokens(model);
1088
1057
  if (maxTokenBudget.clampToModelMaxTokens && clampedMaxTokens !== void 0 && modelMaxTokens !== void 0 && clampedMaxTokens > modelMaxTokens) {
@@ -1107,17 +1076,8 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
1107
1076
  if (usesBinaryOpenRouterThinking && thinkingEnabled !== void 0) params.reasoning = { enabled: thinkingEnabled };
1108
1077
  else if (effort !== void 0) params.reasoning = { effort };
1109
1078
  }
1110
- if (policy.mode === "direct") applyDirectCompletionsReasoningAndRouting(params, model, reasoning, compat);
1111
- else {
1112
- const suppressScalarEffort = applyBinaryCompletionsThinkingParams({
1113
- compatThinkingFormat: compat.thinkingFormat,
1114
- modelReasoning: model.reasoning,
1115
- payload: params,
1116
- thinkingEnabled: thinkingEnabled ?? false
1117
- });
1118
- if (!isOpenRouter && effort && model.reasoning && compat.supportsReasoningEffort && !suppressScalarEffort) params.reasoning_effort = effort;
1119
- if (compat.cacheControlFormat === "anthropic") applyCompletionsAnthropicCacheControl(params, cacheControl ?? null, cacheOptOutIndexes, markTools, !managedCompat?.requiresStringContent);
1120
- }
1079
+ applyCompletionsReasoningAndRouting(params, model, reasoning, compat, policy.mode);
1080
+ if (policy.mode === "managed" && compat.cacheControlFormat === "anthropic") applyCompletionsAnthropicCacheControl(params, cacheControl ?? null, cacheOptOutIndexes, markTools, !managedCompat?.requiresStringContent);
1121
1081
  if (params.tools?.length && isKnownOpenAICompletionsEndpoint(model)) {
1122
1082
  if (isOpenAIGpt56Model(model)) params.reasoning_effort = "none";
1123
1083
  else if (isOpenAIGpt54MiniModel(model) || isOpenAIGpt55Model(model)) delete params.reasoning_effort;
@@ -1487,7 +1447,8 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1487
1447
  const MAX_POST_TOOL_CALL_BUFFER_BYTES = 256e3;
1488
1448
  const directMode = options?.mode === "direct";
1489
1449
  const emitReasoning = options?.emitReasoning ?? true;
1490
- const compat = getCompat(model);
1450
+ const openAIModel = model;
1451
+ const compat = getCompat(openAIModel);
1491
1452
  const visibleReasoningDetailTypes = new Set(compat.visibleReasoningDetailTypes);
1492
1453
  const shouldFilterDeepSeekDsmlText = !directMode && compat.thinkingFormat === "deepseek";
1493
1454
  const deepSeekTextFilter = shouldFilterDeepSeekDsmlText ? createDeepSeekTextFilter() : null;
@@ -1496,31 +1457,37 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1496
1457
  const reasoningTagTextPartitioner = createReasoningTagTextPartitioner();
1497
1458
  if (options?.strictReasoningTags) reasoningTagTextPartitioner.markStrict();
1498
1459
  let currentBlock = null;
1499
- let directTextBlock = null;
1500
- let directThinkingBlock = null;
1460
+ const directContent = { block: null };
1501
1461
  let currentTextSource;
1502
1462
  let pendingInterruptedTextBlock = null;
1503
1463
  let confirmedInterruptedTextBlock = null;
1504
1464
  let pendingPostToolCallDeltas = [];
1505
1465
  let pendingPostToolCallBytes = 0;
1506
- let isFlushingPendingPostToolCallDeltas = false;
1507
1466
  const toolCallBlocksByIndex = /* @__PURE__ */ new Map();
1508
1467
  const toolCallBlocksById = /* @__PURE__ */ new Map();
1509
1468
  const encryptedReasoning = createOpenAIEncryptedToolCallReasoningTracker();
1510
1469
  const toolArgumentPreviewSchedules = /* @__PURE__ */ new WeakMap();
1511
1470
  const provisionalCommentaryTags = directMode ? options.provisionalCommentaryTags : /* @__PURE__ */ new Map();
1512
- const contentBlockIndices = /* @__PURE__ */ new WeakMap();
1513
- const toolCallBlockIndices = /* @__PURE__ */ new WeakMap();
1471
+ const blockIndices = /* @__PURE__ */ new WeakMap();
1514
1472
  let explicitVisibleTextBlocks;
1515
1473
  const normalizeToolCallDeltas = createOpenAICompletionsToolCallDeltaNormalizer();
1516
1474
  let finishReason;
1517
1475
  let sawNativeToolCallDelta = false;
1518
- const blockIndex = () => directMode && currentBlock && currentBlock.type !== "toolCall" ? contentBlockIndices.get(currentBlock) ?? output.content.length - 1 : output.content.length - 1;
1476
+ const blockIndex = () => directMode && currentBlock && currentBlock.type !== "toolCall" ? blockIndices.get(currentBlock) ?? output.content.length - 1 : output.content.length - 1;
1519
1477
  let chunkPushedEvent = false;
1520
1478
  const pushStreamEvent = (event) => {
1521
1479
  chunkPushedEvent = true;
1522
1480
  stream.push(event);
1523
1481
  };
1482
+ const appendToolCallBlock = (block) => {
1483
+ output.content.push(block);
1484
+ blockIndices.set(block, output.content.length - 1);
1485
+ pushStreamEvent({
1486
+ type: "toolcall_start",
1487
+ contentIndex: blockIndices.get(block) ?? -1,
1488
+ partial: output
1489
+ });
1490
+ };
1524
1491
  const queuePostToolCallDelta = (next) => {
1525
1492
  const nextBytes = Buffer.byteLength(next.text, "utf8");
1526
1493
  if (pendingPostToolCallBytes + nextBytes > MAX_POST_TOOL_CALL_BUFFER_BYTES) throw new Error("Exceeded post-tool-call delta buffer limit");
@@ -1532,88 +1499,62 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1532
1499
  }
1533
1500
  previous.text += next.text;
1534
1501
  };
1535
- const appendThinkingDeltaInternal = (reasoningDelta) => {
1536
- if (directMode && directThinkingBlock) currentBlock = directThinkingBlock;
1537
- if (!currentBlock || currentBlock.type !== "thinking") {
1538
- options?.beforeContentBlock?.("thinking");
1539
- const thinkingSignature = reasoningDelta.signature;
1540
- currentBlock = {
1502
+ const appendContentDelta = (delta) => {
1503
+ flushPendingPostToolCallDeltas();
1504
+ if (directMode && directContent.block?.type === delta.kind) currentBlock = directContent.block;
1505
+ if (delta.kind === "text" && currentBlock?.type === "text" && currentTextSource !== delta.source) currentBlock = null;
1506
+ if (!currentBlock || currentBlock.type !== delta.kind) {
1507
+ options?.beforeContentBlock?.(delta.kind);
1508
+ if (delta.kind === "text") {
1509
+ currentBlock = {
1510
+ type: "text",
1511
+ text: ""
1512
+ };
1513
+ currentTextSource = delta.source;
1514
+ if (delta.source === "reasoning_detail") (explicitVisibleTextBlocks ??= /* @__PURE__ */ new Set()).add(currentBlock);
1515
+ } else currentBlock = {
1541
1516
  type: "thinking",
1542
1517
  thinking: "",
1543
- ...thinkingSignature ? { thinkingSignature } : {}
1518
+ ...delta.signature ? { thinkingSignature: delta.signature } : {}
1544
1519
  };
1545
- if (directMode) {
1546
- directTextBlock = null;
1547
- directThinkingBlock = currentBlock;
1548
- }
1520
+ if (directMode) directContent.block = currentBlock;
1549
1521
  output.content.push(currentBlock);
1550
- contentBlockIndices.set(currentBlock, output.content.length - 1);
1522
+ blockIndices.set(currentBlock, output.content.length - 1);
1551
1523
  pushStreamEvent({
1552
- type: "thinking_start",
1524
+ type: `${delta.kind}_start`,
1553
1525
  contentIndex: blockIndex(),
1554
1526
  partial: output
1555
1527
  });
1556
1528
  }
1557
- appendAssistantThinking(currentBlock, reasoningDelta.text);
1558
- pushStreamEvent({
1559
- type: "thinking_delta",
1529
+ if (currentBlock.type === "thinking") appendAssistantThinking(currentBlock, delta.text);
1530
+ else {
1531
+ currentBlock.text += delta.text;
1532
+ if (pendingInterruptedTextBlock && delta.text.trim()) {
1533
+ confirmedInterruptedTextBlock = pendingInterruptedTextBlock;
1534
+ pendingInterruptedTextBlock = null;
1535
+ }
1536
+ }
1537
+ const event = {
1560
1538
  contentIndex: blockIndex(),
1561
- delta: reasoningDelta.text,
1539
+ delta: delta.text
1540
+ };
1541
+ if (delta.kind === "thinking") pushStreamEvent({
1542
+ type: "thinking_delta",
1543
+ ...event,
1562
1544
  partial: output
1563
1545
  });
1564
- };
1565
- const appendTextDeltaInternal = (text, source) => {
1566
- if (directMode && directTextBlock) currentBlock = directTextBlock;
1567
- if (currentBlock?.type === "text" && currentTextSource !== source) currentBlock = null;
1568
- if (!currentBlock || currentBlock.type !== "text") {
1569
- options?.beforeContentBlock?.("text");
1570
- currentBlock = {
1571
- type: "text",
1572
- text: ""
1573
- };
1574
- currentTextSource = source;
1575
- if (directMode) {
1576
- directTextBlock = currentBlock;
1577
- directThinkingBlock = null;
1578
- }
1579
- if (source === "reasoning_detail") (explicitVisibleTextBlocks ??= /* @__PURE__ */ new Set()).add(currentBlock);
1580
- output.content.push(currentBlock);
1581
- contentBlockIndices.set(currentBlock, output.content.length - 1);
1582
- pushStreamEvent({
1583
- type: "text_start",
1584
- contentIndex: blockIndex(),
1585
- partial: output
1586
- });
1587
- }
1588
- currentBlock.text += text;
1589
- if (pendingInterruptedTextBlock && text.trim()) {
1590
- confirmedInterruptedTextBlock = pendingInterruptedTextBlock;
1591
- pendingInterruptedTextBlock = null;
1592
- }
1593
- pushStreamEvent({
1546
+ else pushStreamEvent({
1594
1547
  type: "text_delta",
1595
- contentIndex: blockIndex(),
1596
- delta: text,
1548
+ ...event,
1597
1549
  ...directMode ? { partial: output } : {}
1598
1550
  });
1599
1551
  };
1600
1552
  const flushPendingPostToolCallDeltas = () => {
1601
- if (isFlushingPendingPostToolCallDeltas || currentBlock?.type === "toolCall" || pendingPostToolCallDeltas.length === 0) return;
1602
- isFlushingPendingPostToolCallDeltas = true;
1553
+ if (currentBlock?.type === "toolCall" || pendingPostToolCallDeltas.length === 0) return;
1603
1554
  const bufferedDeltas = pendingPostToolCallDeltas;
1604
1555
  pendingPostToolCallDeltas = [];
1605
1556
  pendingPostToolCallBytes = 0;
1606
- for (const delta of bufferedDeltas) if (delta.kind === "text") appendTextDeltaInternal(delta.text, delta.source);
1607
- else if (emitReasoning) appendThinkingDeltaInternal(delta);
1608
- isFlushingPendingPostToolCallDeltas = false;
1609
- };
1610
- const appendThinkingDelta = (reasoningDelta) => {
1611
- flushPendingPostToolCallDeltas();
1612
- appendThinkingDeltaInternal(reasoningDelta);
1613
- };
1614
- const appendTextDelta = (text, source) => {
1615
- flushPendingPostToolCallDeltas();
1616
- appendTextDeltaInternal(text, source);
1557
+ for (const delta of bufferedDeltas) if (delta.kind === "text" || emitReasoning) appendContentDelta(delta);
1617
1558
  };
1618
1559
  const appendVisibleTextDelta = (text) => {
1619
1560
  if (!text) return;
@@ -1621,20 +1562,22 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1621
1562
  kind: "text",
1622
1563
  text
1623
1564
  });
1624
- else appendTextDelta(text);
1565
+ else appendContentDelta({
1566
+ kind: "text",
1567
+ text
1568
+ });
1625
1569
  };
1626
1570
  const appendReasoningDeltas = (reasoningDeltas) => {
1627
- for (const reasoningDelta of reasoningDeltas) {
1628
- if (reasoningDelta.kind === "thinking" && !emitReasoning) continue;
1571
+ for (const delta of reasoningDeltas) {
1572
+ if (delta.kind === "thinking" && !emitReasoning) continue;
1629
1573
  if (currentBlock?.type === "toolCall" && !directMode) {
1630
- queuePostToolCallDelta({ ...reasoningDelta });
1574
+ queuePostToolCallDelta({ ...delta });
1631
1575
  continue;
1632
1576
  }
1633
- if (reasoningDelta.kind === "text") appendTextDelta(reasoningDelta.text, reasoningDelta.source);
1634
- else if (emitReasoning) appendThinkingDelta(directMode && model.provider === "opencode-go" && reasoningDelta.signature === "reasoning" ? {
1635
- ...reasoningDelta,
1577
+ appendContentDelta(delta.kind === "thinking" && directMode && model.provider === "opencode-go" && delta.signature === "reasoning" ? {
1578
+ ...delta,
1636
1579
  signature: "reasoning_content"
1637
- } : reasoningDelta);
1580
+ } : delta);
1638
1581
  }
1639
1582
  };
1640
1583
  const appendRecoveredToolCall = (toolCall) => {
@@ -1650,18 +1593,11 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1650
1593
  arguments: toolCall.arguments,
1651
1594
  partialArgs: toolCall.partialArgs
1652
1595
  };
1653
- toolArgumentPreviewSchedules.set(block, createToolArgumentPreviewSchedule());
1654
1596
  currentBlock = block;
1655
- output.content.push(block);
1656
- toolCallBlockIndices.set(block, output.content.length - 1);
1657
- pushStreamEvent({
1658
- type: "toolcall_start",
1659
- contentIndex: toolCallBlockIndices.get(block) ?? -1,
1660
- partial: output
1661
- });
1597
+ appendToolCallBlock(block);
1662
1598
  pushStreamEvent({
1663
1599
  type: "toolcall_delta",
1664
- contentIndex: toolCallBlockIndices.get(block) ?? -1,
1600
+ contentIndex: blockIndices.get(block) ?? -1,
1665
1601
  delta: toolCall.partialArgs,
1666
1602
  partial: output
1667
1603
  });
@@ -1676,24 +1612,25 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1676
1612
  for (const part of parts) appendVisibleTextDelta(part);
1677
1613
  }
1678
1614
  };
1679
- const appendFilteredVisibleTextDelta = (text) => {
1680
- appendRecoveredParts(deepSeekToolCallRecoverer?.push(text) ?? [{
1615
+ const appendPartitionedVisibleDelta = (delta) => {
1616
+ if (delta.kind === "text") appendRecoveredParts(deepSeekToolCallRecoverer?.push(delta.text) ?? [{
1681
1617
  kind: "text",
1682
- text
1618
+ text: delta.text
1683
1619
  }]);
1684
1620
  };
1685
- const appendPartitionedVisibleDelta = (delta) => {
1686
- if (delta.kind === "text") appendFilteredVisibleTextDelta(delta.text);
1687
- };
1688
1621
  const emitReasoningUsageActivity = (hasReasoningUsageActivity) => {
1689
1622
  if (directMode || !hasReasoningUsageActivity || chunkPushedEvent || !emitReasoning) return;
1690
1623
  const latestBlock = output.content[output.content.length - 1];
1691
1624
  if (currentBlock?.type === "text" || currentBlock?.type === "toolCall") return;
1692
1625
  if (latestBlock?.type === "text" || latestBlock?.type === "toolCall") return;
1693
- appendThinkingDelta({ text: "" });
1626
+ appendContentDelta({
1627
+ kind: "thinking",
1628
+ text: ""
1629
+ });
1694
1630
  };
1695
- const flushReasoningTagTextPartitioner = () => {
1696
- for (const delta of reasoningTagTextPartitioner.flush()) appendPartitionedVisibleDelta(delta);
1631
+ const flushReasoningTagTextPartitioner = (allowRecovery = true) => {
1632
+ const recoverUnclosed = allowRecovery && output.stopReason !== "length" && output.stopReason !== "error" && output.stopReason !== "aborted";
1633
+ for (const delta of reasoningTagTextPartitioner.flush({ recoverUnclosed })) appendPartitionedVisibleDelta(delta);
1697
1634
  };
1698
1635
  const flushGemmaToolCallRecoverer = (allowRecovery = true) => {
1699
1636
  for (const part of gemmaToolCallRecoverer?.flush(allowRecovery) ?? []) if (part.kind === "toolCall") appendRecoveredToolCall(part);
@@ -1705,7 +1642,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1705
1642
  if (currentBlock?.type !== "text") return;
1706
1643
  if (currentTextSource !== "reasoning_detail" && currentBlock.text.trim()) pendingInterruptedTextBlock = currentBlock;
1707
1644
  currentBlock = null;
1708
- if (directMode) directTextBlock = null;
1645
+ if (directMode) directContent.block = null;
1709
1646
  currentTextSource = void 0;
1710
1647
  };
1711
1648
  const beginReasoning = (hasFollowingVisibleText, forceStrict = false) => {
@@ -1727,36 +1664,49 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1727
1664
  hint: "The provider may be stalled while parsing the tool payload; retry with a smaller tool surface or enable OPENCLAW_DEBUG_MODEL_PAYLOAD=tools to inspect exposed tools."
1728
1665
  });
1729
1666
  const events = directMode ? guardedStream : iterateModelStream(guardedStream, options?.signal);
1667
+ const maxUsageTokens = {
1668
+ prompt: 0,
1669
+ completion: 0,
1670
+ total: 0,
1671
+ reasoning: 0
1672
+ };
1730
1673
  for await (const rawChunk of events) {
1731
1674
  throwIfModelStreamAborted(options?.signal);
1732
1675
  chunkPushedEvent = false;
1733
1676
  if (!rawChunk || typeof rawChunk !== "object") continue;
1734
- notifyLlmRequestActivity(options?.signal);
1735
1677
  const chunk = rawChunk;
1736
1678
  output.responseId ||= chunk.id;
1737
1679
  if (typeof chunk.model === "string" && chunk.model.length > 0 && chunk.model !== model.id) output.responseModel ||= chunk.model;
1680
+ const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : void 0;
1681
+ const usage = chunk.usage || choice?.usage;
1682
+ let hasUsageProgress = false;
1738
1683
  let hasReasoningUsageActivity = false;
1739
- if (chunk.usage) {
1740
- output.usage = parseOpenAICompletionsUsage(chunk.usage, model, { includeReasoningTokens: !directMode });
1741
- hasReasoningUsageActivity = hasOpenAICompletionsReasoningUsageActivity(chunk.usage);
1684
+ for (const [counter, reported] of [
1685
+ ["prompt", usage?.prompt_tokens],
1686
+ ["completion", usage?.completion_tokens],
1687
+ ["total", usage?.total_tokens],
1688
+ ["reasoning", usage?.completion_tokens_details?.reasoning_tokens]
1689
+ ]) {
1690
+ const tokens = asPositiveFiniteNumber(reported) ?? 0;
1691
+ if (tokens > maxUsageTokens[counter]) {
1692
+ maxUsageTokens[counter] = tokens;
1693
+ hasUsageProgress = true;
1694
+ hasReasoningUsageActivity ||= counter === "reasoning";
1695
+ }
1742
1696
  }
1743
- const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : void 0;
1697
+ if (usage) output.usage = parseOpenAICompletionsUsage(usage, model, { includeReasoningTokens: !directMode });
1698
+ const rawChoiceDelta = choice?.delta ?? choice?.message;
1699
+ notifyLlmRequestActivity(options?.signal, Boolean(hasUsageProgress || choice?.finish_reason || rawChoiceDelta && (rawChoiceDelta.tool_calls?.length || hasOpenAICompletionsDeltaContent(rawChoiceDelta))));
1744
1700
  if (!choice) {
1745
1701
  emitReasoningUsageActivity(hasReasoningUsageActivity);
1746
1702
  continue;
1747
1703
  }
1748
- const choiceUsage = choice.usage;
1749
- if (!chunk.usage && choiceUsage) {
1750
- output.usage = parseOpenAICompletionsUsage(choiceUsage, model, { includeReasoningTokens: !directMode });
1751
- hasReasoningUsageActivity = hasOpenAICompletionsReasoningUsageActivity(choiceUsage);
1752
- }
1753
1704
  if (choice.finish_reason) {
1754
1705
  const finishReasonResult = mapOpenAIStopReason(choice.finish_reason, { allowSingularToolCall: true });
1755
1706
  output.stopReason = finishReasonResult.stopReason;
1756
1707
  finishReason = finishReasonResult.stopReason;
1757
1708
  if (finishReasonResult.errorMessage) output.errorMessage = finishReasonResult.errorMessage;
1758
1709
  }
1759
- const rawChoiceDelta = choice.delta ?? choice.message;
1760
1710
  if (!rawChoiceDelta) {
1761
1711
  emitReasoningUsageActivity(hasReasoningUsageActivity);
1762
1712
  continue;
@@ -1784,7 +1734,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1784
1734
  beginReasoning(contentDeltaIndex < lastVisibleTextIndex);
1785
1735
  if (emitReasoning) {
1786
1736
  if (currentBlock?.type === "toolCall" && !directMode) queuePostToolCallDelta(contentDelta);
1787
- else appendThinkingDelta(contentDelta);
1737
+ else appendContentDelta(contentDelta);
1788
1738
  }
1789
1739
  }
1790
1740
  if (!hasReasoningThinking) appendReasoningDeltas(reasoningDeltas);
@@ -1792,7 +1742,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1792
1742
  if (toolCallDeltas.length > 0) {
1793
1743
  flushGemmaToolCallRecoverer(false);
1794
1744
  sawNativeToolCallDelta = true;
1795
- flushReasoningTagTextPartitioner();
1745
+ flushReasoningTagTextPartitioner(false);
1796
1746
  rememberPendingCommentaryTags(provisionalCommentaryTags, tagPendingCommentaryText(output.content));
1797
1747
  for (const toolCall of toolCallDeltas) {
1798
1748
  const streamIndex = typeof toolCall.index === "number" ? toolCall.index : void 0;
@@ -1805,7 +1755,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1805
1755
  }
1806
1756
  const initialSig = directMode ? void 0 : extractToolCallThoughtSignature(toolCall);
1807
1757
  options?.beforeContentBlock?.("toolCall");
1808
- if (directMode) directThinkingBlock = null;
1758
+ if (directMode && directContent.block?.type === "thinking") directContent.block = null;
1809
1759
  block = {
1810
1760
  type: "toolCall",
1811
1761
  id: toolCall.id || "",
@@ -1816,13 +1766,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1816
1766
  };
1817
1767
  encryptedReasoning.rememberToolCall(block.id, block);
1818
1768
  toolArgumentPreviewSchedules.set(block, createToolArgumentPreviewSchedule());
1819
- output.content.push(block);
1820
- toolCallBlockIndices.set(block, output.content.length - 1);
1821
- pushStreamEvent({
1822
- type: "toolcall_start",
1823
- contentIndex: toolCallBlockIndices.get(block) ?? -1,
1824
- partial: output
1825
- });
1769
+ appendToolCallBlock(block);
1826
1770
  }
1827
1771
  if (streamIndex !== void 0 && !toolCallBlocksByIndex.has(streamIndex)) toolCallBlocksByIndex.set(streamIndex, block);
1828
1772
  if (toolCall.id) {
@@ -1843,7 +1787,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1843
1787
  }
1844
1788
  if (toolArgumentsDelta || directMode) pushStreamEvent({
1845
1789
  type: "toolcall_delta",
1846
- contentIndex: toolCallBlockIndices.get(block) ?? -1,
1790
+ contentIndex: blockIndices.get(block) ?? -1,
1847
1791
  delta: toolArgumentsDelta ?? "",
1848
1792
  partial: output
1849
1793
  });
@@ -1865,7 +1809,7 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1865
1809
  finalizeOpenAICompletionsToolCalls(output, {
1866
1810
  allowSilentToolCallPromotion: finishReason === "stop" || sawNativeToolCallDelta && (options?.sawStreamDONE?.() ?? false),
1867
1811
  onConfirmedToolCall(block, contentIndex) {
1868
- if (directMode || block.type !== "toolCall") return;
1812
+ if (directMode) return;
1869
1813
  pushStreamEvent({
1870
1814
  type: "toolcall_end",
1871
1815
  contentIndex,
@@ -1878,15 +1822,1203 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1878
1822
  if (output.stopReason !== "toolUse") clearPendingCommentaryText(provisionalCommentaryTags);
1879
1823
  if (output.stopReason === "error" || output.stopReason === "aborted") tagUnresolvedTextAsCommentary(output);
1880
1824
  if (output.stopReason === "toolUse") tagPendingCommentaryText(output.content);
1825
+ if (!output.usage.contextUsage && !options?.signal?.aborted && output.stopReason !== "error" && output.stopReason !== "aborted") {
1826
+ output.usage.contextUsage = { state: "unavailable" };
1827
+ if (!compat.supportsUsageInStreaming) warnMissingStreamingUsage(openAIModel);
1828
+ }
1829
+ }
1830
+ const MAX_MISSING_USAGE_HINT_KEYS = 256;
1831
+ const missingUsageHintKeys = /* @__PURE__ */ new Set();
1832
+ function warnMissingStreamingUsage(model) {
1833
+ if (detectOpenAICompletionsCompat(model).capabilities.endpointClass !== "custom") return;
1834
+ const key = `${model.provider}/${model.id}`;
1835
+ if (missingUsageHintKeys.has(key) || missingUsageHintKeys.size >= MAX_MISSING_USAGE_HINT_KEYS) return;
1836
+ missingUsageHintKeys.add(key);
1837
+ log.warn(`${key} returned no token usage; context size is estimated and token accounting is unavailable. If this endpoint supports stream_options.include_usage, set compat.supportsUsageInStreaming: true on the model in models.providers.${model.provider}.models.`, {
1838
+ provider: model.provider,
1839
+ model: model.id
1840
+ });
1881
1841
  }
1882
1842
  function shouldEmitOpenAICompletionsReasoning(model, options) {
1883
1843
  if (!model.reasoning) return false;
1884
1844
  const effort = options?.reasoningEffort ?? options?.reasoning ?? "high";
1885
1845
  return Boolean(effort) && isOpenAICompletionsThinkingEnabled(effort);
1886
1846
  }
1887
- function hasOpenAICompletionsReasoningUsageActivity(rawUsage) {
1888
- const reasoningTokens = rawUsage.completion_tokens_details?.reasoning_tokens;
1889
- return typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) && reasoningTokens > 0;
1847
+ //#endregion
1848
+ //#region packages/ai/src/providers/openai-web-search-tools.ts
1849
+ function hasResponsesWebSearchTool(tools) {
1850
+ if (!Array.isArray(tools)) return false;
1851
+ return tools.some((tool) => {
1852
+ if (!isRecord(tool)) return false;
1853
+ if (tool.type === "web_search") return true;
1854
+ if (tool.type === "function" && tool.name === "web_search") return true;
1855
+ const fn = tool.function;
1856
+ return isRecord(fn) && fn.name === "web_search";
1857
+ });
1858
+ }
1859
+ //#endregion
1860
+ //#region packages/ai/src/transports/openai-responses-params-internal.ts
1861
+ const OPENAI_RESPONSES_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([
1862
+ "openai",
1863
+ "opencode",
1864
+ "azure-openai-responses",
1865
+ "github-copilot"
1866
+ ]);
1867
+ function raiseMinimalReasoningForResponsesWebSearch(params) {
1868
+ if (params.effort !== "minimal" || !hasResponsesWebSearchTool(params.tools)) return params.effort;
1869
+ for (const effort of [
1870
+ "low",
1871
+ "medium",
1872
+ "high"
1873
+ ]) {
1874
+ const resolved = resolveOpenAIRequestReasoning(params.model, effort).effort;
1875
+ if (resolved && resolved !== "none" && resolved !== "minimal") return resolved;
1876
+ }
1877
+ return params.effort;
1878
+ }
1879
+ const OPENAI_CODEX_RESPONSES_UNSUPPORTED_PARAMS = [
1880
+ "max_output_tokens",
1881
+ "metadata",
1882
+ "prompt_cache_retention",
1883
+ "prompt_cache_options",
1884
+ "service_tier",
1885
+ "temperature",
1886
+ "top_p"
1887
+ ];
1888
+ function stripOpenAICodexResponsesUnsupportedTextFields(params) {
1889
+ const text = params.text;
1890
+ if (!text || typeof text !== "object" || Array.isArray(text)) return;
1891
+ const sanitizedText = { ...text };
1892
+ delete sanitizedText.format;
1893
+ if (Object.keys(sanitizedText).length > 0) params.text = sanitizedText;
1894
+ else delete params.text;
1895
+ }
1896
+ function sanitizeOpenAICodexResponsesParams(model, params) {
1897
+ if (!usesNativeOpenAICodexResponsesBackend(model)) return params;
1898
+ for (const key of OPENAI_CODEX_RESPONSES_UNSUPPORTED_PARAMS) delete params[key];
1899
+ Object.assign(params, { store: false });
1900
+ stripOpenAICodexResponsesUnsupportedTextFields(params);
1901
+ return params;
1902
+ }
1903
+ function buildOpenAIResponsesInstructionsText(context) {
1904
+ if (!context.systemPrompt) return;
1905
+ return sanitizeTransportPayloadText(stripSystemPromptCacheBoundary(context.systemPrompt));
1906
+ }
1907
+ function resolveOpenAIResponsesInstructions(model, context, usesInstructionsField) {
1908
+ if (!usesInstructionsField) return;
1909
+ const instructions = buildOpenAIResponsesInstructionsText(context);
1910
+ if (instructions && instructions.trim().length > 0) return instructions;
1911
+ return usesNativeOpenAICodexResponsesBackend(model) ? OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS : void 0;
1912
+ }
1913
+ function buildOpenAIResponsesCompactSystemMessage(model, instructions) {
1914
+ const compat = getCompat(model);
1915
+ const role = model.reasoning && compat.supportsDeveloperRole ? "developer" : "system";
1916
+ return buildResponsesInputMessage(role, [{
1917
+ type: "input_text",
1918
+ text: instructions
1919
+ }]);
1920
+ }
1921
+ function ensureOpenAIResponsesNonEmptyInput(messages, context) {
1922
+ if (messages.length > 0 || !context.systemPrompt) return;
1923
+ if (!buildOpenAIResponsesInstructionsText(context)) throw new Error("OpenAI Responses requires non-empty input when only systemPrompt is provided.");
1924
+ messages.push(buildResponsesInputMessage("user", [{
1925
+ type: "input_text",
1926
+ text: " "
1927
+ }]));
1928
+ }
1929
+ function buildOpenAIResponsesParams(model, context, options, metadata, replayMode = "checkpoint") {
1930
+ const payloadPolicy = resolveOpenAIResponsesPayloadPolicy(model, { storeMode: "transport-default" });
1931
+ const policyAllowsReplayIds = payloadPolicy.explicitStore !== false && !payloadPolicy.shouldStripStore;
1932
+ const replayResponsesItemIds = !usesNativeOpenAICodexResponsesBackend(model) && (options?.replayResponsesItemIds ?? policyAllowsReplayIds);
1933
+ const messages = convertResponsesMessages(model, context, OPENAI_RESPONSES_TOOL_CALL_PROVIDERS, {
1934
+ includeSystemPrompt: !payloadPolicy.usesInstructionsField,
1935
+ replayReasoningItems: true,
1936
+ replayResponsesItemIds,
1937
+ authProfileId: options?.authProfileId,
1938
+ sessionId: options?.sessionId,
1939
+ replayMode
1940
+ });
1941
+ ensureOpenAIResponsesNonEmptyInput(messages, context);
1942
+ const cacheRetention = resolveCacheRetention(options?.cacheRetention);
1943
+ const compat = getCompat(model);
1944
+ const promptCacheKey = compat.supportsPromptCacheKey ? resolvePromptCacheKey(options, cacheRetention) : void 0;
1945
+ const instructions = resolveOpenAIResponsesInstructions(model, context, payloadPolicy.usesInstructionsField);
1946
+ const params = {
1947
+ model: model.id,
1948
+ input: messages,
1949
+ stream: true,
1950
+ prompt_cache_key: promptCacheKey,
1951
+ ...resolveOpenAIPromptCacheParams(model, cacheRetention, compat),
1952
+ ...instructions ? { instructions } : {},
1953
+ ...metadata ? { metadata } : {}
1954
+ };
1955
+ const effectiveMaxTokens = options?.maxTokens || model.maxTokens;
1956
+ if (effectiveMaxTokens) params.max_output_tokens = Math.max(effectiveMaxTokens, 16);
1957
+ if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
1958
+ if (options?.topP !== void 0 && (!isOpenAIGpt6Model(model) || resolveOpenAIThinkingApi(model.api) === "azure-openai-responses")) params.top_p = options.topP;
1959
+ if (options?.responseFormat !== void 0) params.text = {
1960
+ ...params.text,
1961
+ format: resolveOpenAIResponsesTextFormat(options.responseFormat)
1962
+ };
1963
+ if (options?.serviceTier !== void 0 && payloadPolicy.allowsServiceTier) params.service_tier = options.serviceTier;
1964
+ if (context.tools) {
1965
+ const tools = context.tools;
1966
+ const strict = getAiTransportHost().resolveOpenAIStrictToolSetting(model, {
1967
+ transport: "stream",
1968
+ supportsStrictMode: compat.supportsStrictMode
1969
+ });
1970
+ const { projection, tools: converted } = prepareResponsesTools(tools, strict, model);
1971
+ if (converted.length > 0 || projection.inputToolCount === 0 && projection.diagnostics.length === 0) params.tools = converted;
1972
+ if (options?.toolChoice) {
1973
+ const toolChoice = reconcileOpenAIResponsesToolChoice(options.toolChoice, projection);
1974
+ if (toolChoice !== void 0) params.tool_choice = toolChoice;
1975
+ }
1976
+ }
1977
+ if (model.reasoning) {
1978
+ const reasoning = options?.reasoning;
1979
+ const requestedEffort = options?.reasoningEffort ?? (reasoning === "none" ? "none" : resolveOpenAISimpleReasoningEffort(model, reasoning)) ?? (options?.reasoningSummary ? "high" : payloadPolicy.defaultManagedReasoningEffort);
1980
+ const resolvedEffort = requestedEffort === void 0 ? void 0 : resolveOpenAIRequestReasoning(model, requestedEffort).effort;
1981
+ if (resolvedEffort !== void 0) {
1982
+ const effort = raiseMinimalReasoningForResponsesWebSearch({
1983
+ model,
1984
+ effort: resolvedEffort,
1985
+ tools: params.tools
1986
+ });
1987
+ const summary = effort !== "none" && (options?.reasoningEffort || options?.reasoning || options?.reasoningSummary) ? options.reasoningSummary || "auto" : void 0;
1988
+ params.reasoning = {
1989
+ effort,
1990
+ ...summary ? { summary } : {}
1991
+ };
1992
+ if (summary) params.include = ["reasoning.encrypted_content"];
1993
+ }
1994
+ }
1995
+ applyOpenAIResponsesPayloadPolicy(params, payloadPolicy);
1996
+ return sanitizeOpenAICodexResponsesParams(model, params);
1997
+ }
1998
+ //#endregion
1999
+ //#region packages/ai/src/transports/openai-responses-compact-client.ts
2000
+ async function postOpenAIResponsesCompaction(params) {
2001
+ const compactInput = typeof params.request.instructions === "string" && params.request.instructions.length > 0 ? [buildOpenAIResponsesCompactSystemMessage(params.model, params.request.instructions), ...params.request.input ?? []] : params.request.input;
2002
+ const response = await params.client.post("/responses/compact", {
2003
+ ...buildOpenAISdkRequestOptions(params.model, params.options?.signal, { timeoutMs: params.options?.timeoutMs }),
2004
+ body: {
2005
+ model: params.request.model,
2006
+ input: compactInput
2007
+ }
2008
+ });
2009
+ const output = isRecord(response) && Array.isArray(response.output) ? response.output : [];
2010
+ const item = output.at(-1);
2011
+ const retainedItems = output.slice(0, -1);
2012
+ const retainedUserMessageCount = retainedItems.filter((candidate) => isRecord(candidate) && candidate.type === "message" && candidate.role === "user" && Array.isArray(candidate.content)).length;
2013
+ const inputUserMessageCount = Array.isArray(params.request.input) ? params.request.input.filter((candidate) => isRecord(candidate) && candidate.type === "message" && candidate.role === "user").length : 0;
2014
+ const retainedMessagePrefixSupported = supportsNativeOpenAIResponsesEndpoint(params.model);
2015
+ const usage = isRecord(response) && isRecord(response.usage) ? response.usage : void 0;
2016
+ 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");
2017
+ return {
2018
+ output,
2019
+ item,
2020
+ historyMode: retainedUserMessageCount > 0 ? "retained-users" : "compacted-prefix",
2021
+ usage,
2022
+ model: params.model,
2023
+ replayMetadata: buildOpenAIResponsesReasoningReplayMetadata(params.model, {
2024
+ authProfileId: params.options?.authProfileId,
2025
+ sessionId: params.options?.sessionId
2026
+ })
2027
+ };
2028
+ }
2029
+ //#endregion
2030
+ //#region packages/ai/src/transports/openai-responses-compact-request.ts
2031
+ const COMPACT_REQUEST = Symbol("openaiResponsesCompactRequest");
2032
+ function claimResponsesCompactRequest(options) {
2033
+ const controller = options ? Reflect.get(options, COMPACT_REQUEST) : void 0;
2034
+ if (controller?.claimed === false) {
2035
+ controller.claimed = true;
2036
+ return controller;
2037
+ }
2038
+ }
2039
+ /** Run a compact-endpoint request through the session's prepared stream stack. */
2040
+ async function requestPreparedOpenAIResponsesCompaction(streamFn, model, context, options) {
2041
+ const preparedOptions = { ...options };
2042
+ let resolveResult;
2043
+ let rejectResult;
2044
+ const result = new Promise((resolve, reject) => {
2045
+ resolveResult = resolve;
2046
+ rejectResult = reject;
2047
+ });
2048
+ const controller = {
2049
+ claimed: false,
2050
+ resolve: resolveResult,
2051
+ reject: rejectResult
2052
+ };
2053
+ Reflect.set(preparedOptions, COMPACT_REQUEST, controller);
2054
+ const stream = await Promise.resolve(streamFn(model, context, preparedOptions));
2055
+ if (!controller.claimed) throw new Error("Prepared stream did not reach an OpenAI Responses transport");
2056
+ try {
2057
+ return await result;
2058
+ } finally {
2059
+ await stream.result().catch(() => void 0);
2060
+ }
2061
+ }
2062
+ //#endregion
2063
+ //#region packages/ai/src/transports/openai-responses-reasoning-state.ts
2064
+ /** Save only admitted settings and hashes, never another copy of the conversation. */
2065
+ function recordResponsesReasoningState(message, model, identity, request, output) {
2066
+ if (!supportsResponsesReasoningUpdate(request) || !isRecord(request.reasoning) || !request.input || request.previous_response_id || message.providerReplay || output.some((item) => isRecord(item) && item.type === "compaction")) return;
2067
+ const reasoning = {
2068
+ ...buildProviderReplayContext(model, identity),
2069
+ effort: request.reasoning.effort,
2070
+ controls: request.input.flatMap((item, index) => isConfigurationUpdate(item) ? [{
2071
+ index,
2072
+ item
2073
+ }] : []),
2074
+ inputLength: request.input.length,
2075
+ outputLength: output.length,
2076
+ prefixHash: responsesContinuationPrefixFingerprint(request.input, output),
2077
+ requestHash: responsesContinuationRequestFingerprint(request)
2078
+ };
2079
+ Object.assign(message, { openclawResponsesInputReplay: {
2080
+ ...readResponsesInputReplayState(message),
2081
+ reasoning
2082
+ } });
2083
+ }
2084
+ /** A cold transport can replay controls, but cannot resurrect a server response handle. */
2085
+ function restoreResponsesReasoningState(context, model, identity, request) {
2086
+ const latest = context.messages.findLast((message) => message.role === "assistant");
2087
+ const state = latest ? readResponsesInputReplayState(latest)?.reasoning : void 0;
2088
+ if (!isRecord(state)) return request;
2089
+ const { effort, inputLength, outputLength, controls, prefixHash, requestHash } = state;
2090
+ if (!isProviderReplayContext(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;
2091
+ const previousInput = request.input.slice(0, inputLength - controls.length);
2092
+ let lastIndex = -1;
2093
+ for (const control of controls) {
2094
+ if (!isRecord(control) || typeof control.index !== "number" || !Number.isSafeInteger(control.index) || control.index <= lastIndex || control.index > previousInput.length || !isConfigurationUpdate(control.item)) return request;
2095
+ previousInput.splice(control.index, 0, control.item);
2096
+ lastIndex = control.index;
2097
+ }
2098
+ const previous = {
2099
+ ...request,
2100
+ reasoning: {
2101
+ ...request.reasoning,
2102
+ effort
2103
+ },
2104
+ input: previousInput
2105
+ };
2106
+ if (responsesContinuationRequestFingerprint(previous) !== requestHash) return request;
2107
+ const prepared = replayResponsesReasoningUpdates(previous, request, outputLength);
2108
+ if (responsesContinuationPrefixFingerprint((prepared.input ?? []).slice(0, inputLength + outputLength)) !== prefixHash) return request;
2109
+ return prepared;
2110
+ }
2111
+ //#endregion
2112
+ //#region packages/ai/src/transports/openai-responses-request-fetch.ts
2113
+ function withDefaultResponsesStreamEncoding(fetch) {
2114
+ return (input, init) => {
2115
+ const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
2116
+ if (headers.has("accept-encoding")) return fetch(input, init);
2117
+ headers.set("accept-encoding", "identity");
2118
+ return fetch(input, {
2119
+ ...init,
2120
+ headers
2121
+ });
2122
+ };
2123
+ }
2124
+ /** Preserve the existing fetch policy while binding explicit continuation dispatch to its signal. */
2125
+ function createResponsesRequestFetch(model, options) {
2126
+ const lifecycle = options.lifecycle;
2127
+ if (lifecycle && options.compact) throw new Error("Provider review continuation cannot replace its reviewed input with compaction");
2128
+ let fetchOverride = options.compact ? createBoundedOpenAIResponsesCompactionFetch(buildGuardedModelFetch(model)) : options.stream ? withDefaultResponsesStreamEncoding(buildGuardedModelFetch(model, void 0, { onSseComment: options.onSseComment })) : void 0;
2129
+ if (lifecycle) {
2130
+ const dispatchFetch = fetchOverride ?? buildGuardedModelFetch(model);
2131
+ fetchOverride = async (input, init) => {
2132
+ const signal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
2133
+ await lifecycle.beforeDispatch(signal ?? void 0);
2134
+ signal?.throwIfAborted();
2135
+ lifecycle.assertCurrent();
2136
+ return dispatchFetch(input, init);
2137
+ };
2138
+ }
2139
+ return fetchOverride;
2140
+ }
2141
+ //#endregion
2142
+ //#region packages/ai/src/transports/openai-responses-steering.ts
2143
+ function cloneWireRequest(request) {
2144
+ const serialized = JSON.stringify(request);
2145
+ return JSON.parse(serialized);
2146
+ }
2147
+ async function projectResponsesSteeringInput(request, project) {
2148
+ const { input: activeInput, ...activeSettings } = cloneWireRequest(request);
2149
+ if (!Array.isArray(activeInput)) return [];
2150
+ const { input, ...settings } = cloneWireRequest(await project());
2151
+ if (!Array.isArray(input) || stableStringify(settings) !== stableStringify(activeSettings) || stableStringify(input.slice(0, activeInput.length)) !== stableStringify(activeInput)) return [];
2152
+ const projected = input.slice(activeInput.length);
2153
+ return projected.every((item) => isRecord(item) && item.role === "user") ? projected : [];
2154
+ }
2155
+ /** One response owns admission; accepted input stays on this connection until continuation. */
2156
+ function createResponsesSteering(params) {
2157
+ let responseId;
2158
+ let sealed = false;
2159
+ let unsubscribe;
2160
+ const pending = [];
2161
+ const accepted = /* @__PURE__ */ new Map();
2162
+ const acknowledged = /* @__PURE__ */ new Set();
2163
+ const seal = () => {
2164
+ sealed = true;
2165
+ const cleanup = unsubscribe;
2166
+ unsubscribe = void 0;
2167
+ cleanup?.();
2168
+ };
2169
+ return {
2170
+ get responseId() {
2171
+ return responseId;
2172
+ },
2173
+ get pending() {
2174
+ return pending.length > 0;
2175
+ },
2176
+ get acceptedInput() {
2177
+ return [...accepted.values()].flat();
2178
+ },
2179
+ seal,
2180
+ close(error) {
2181
+ seal();
2182
+ for (const submission of pending.splice(0)) submission.reject(error);
2183
+ },
2184
+ handle(event) {
2185
+ if (!isRecord(event)) return false;
2186
+ if (event.type === "response.created" && !responseId && !sealed) {
2187
+ const response = isRecord(event.response) ? event.response : void 0;
2188
+ if (typeof response?.id !== "string" || !response.id.trim()) throw new Error("Responses steering requires a response identity");
2189
+ const activeResponseId = response.id;
2190
+ responseId = activeResponseId;
2191
+ const cleanup = params.onActiveResponse({
2192
+ needsContinuation: params.needsContinuation,
2193
+ steer(messages) {
2194
+ if (sealed || messages.length === 0) return Promise.resolve(false);
2195
+ params.assertActive();
2196
+ const converted = params.toInput(messages);
2197
+ const submit = (input) => {
2198
+ if (sealed || input.length === 0) return Promise.resolve(false);
2199
+ params.assertActive();
2200
+ return new Promise((resolve, reject) => {
2201
+ pending.push({
2202
+ input,
2203
+ resolve,
2204
+ reject
2205
+ });
2206
+ params.send({
2207
+ type: "response.steer",
2208
+ previous_response_id: activeResponseId,
2209
+ input
2210
+ });
2211
+ });
2212
+ };
2213
+ return Array.isArray(converted) ? submit(converted) : converted.then(submit);
2214
+ }
2215
+ });
2216
+ if (sealed) cleanup?.();
2217
+ else unsubscribe = cleanup;
2218
+ return false;
2219
+ }
2220
+ if (event.type !== "response.steer.accepted" && event.type !== "response.steer.failed" && event.type !== "response.steer.pending") return false;
2221
+ const steer = isRecord(event.steer) ? event.steer : void 0;
2222
+ if (!responseId || steer?.previous_response_id !== responseId) throw new Error("Responses steering acknowledgement has an unexpected identity");
2223
+ if (event.type === "response.steer.failed" && steer.id === void 0) {
2224
+ const index = pending.findIndex((submission) => stableStringify(submission.input) === stableStringify(steer.input));
2225
+ const submission = pending[index];
2226
+ if (!submission) throw new Error("Responses steering acknowledgement has no pending submission");
2227
+ pending.splice(index, 1);
2228
+ submission.resolve(false);
2229
+ return true;
2230
+ }
2231
+ if (typeof steer.id !== "string" || !steer.id.trim()) throw new Error("Responses steering acknowledgement has an unexpected identity");
2232
+ if (event.type === "response.steer.pending") {
2233
+ if (!accepted.has(steer.id)) throw new Error("Responses steering pending event has no accepted submission");
2234
+ return true;
2235
+ }
2236
+ 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");
2237
+ if (acknowledged.has(steer.id)) throw new Error("Responses steering acknowledgement was already applied");
2238
+ const submission = pending.shift();
2239
+ if (!submission) throw new Error("Responses steering acknowledgement has no pending submission");
2240
+ acknowledged.add(steer.id);
2241
+ if (event.type === "response.steer.accepted") {
2242
+ accepted.set(steer.id, submission.input);
2243
+ submission.resolve(true);
2244
+ } else submission.resolve(false);
2245
+ return true;
2246
+ }
2247
+ };
2248
+ }
2249
+ /** Accepted steering is prepended by the server, so never repeat it in response.create. */
2250
+ function omitAcceptedSteering(input, accepted) {
2251
+ const remaining = [...input];
2252
+ for (const message of accepted) {
2253
+ const index = remaining.findIndex((item) => stableStringify(item) === stableStringify(message));
2254
+ if (index < 0) throw new Error("Responses steering continuation no longer contains the accepted user input");
2255
+ remaining.splice(index, 1);
2256
+ }
2257
+ return remaining;
2258
+ }
2259
+ //#endregion
2260
+ //#region packages/ai/src/transports/openai-responses-websocket-recovery.ts
2261
+ /** Owns safe WebSocket rejection recovery; transport selection and session leases stay with the caller. */
2262
+ function createRecoverableResponsesWebSocketStream(params) {
2263
+ const { trackedWebSocketStream, websocket, websocketSignal, options, output, buildRequest, createSseStream, closeWebSocketForFallback, logWebSocketFallback, startStream } = params;
2264
+ return { async *[Symbol.asyncIterator]() {
2265
+ let acceptance = "pending";
2266
+ let outputObserved = false;
2267
+ try {
2268
+ for await (const event of trackedWebSocketStream) {
2269
+ const { failure, hasResponseOutput, isPrelude } = readResponsesRecoveryEvent(event);
2270
+ outputObserved ||= hasResponseOutput;
2271
+ if (isResponsesServiceTierRejection(failure) && !websocket.hasActiveResponse) throw new OpenAIResponsesWebSocketSafeRetryError("invalid_request_error", void 0, "service_tier", "Invalid service_tier argument", failure);
2272
+ outputObserved ||= !isPrelude;
2273
+ if (acceptance === "pending") {
2274
+ acceptance = "observing";
2275
+ await notifyProviderStreamOpened({
2276
+ options,
2277
+ cancelStream: () => websocket.finish({ keep: false })
2278
+ });
2279
+ acceptance = "accepted";
2280
+ }
2281
+ startStream();
2282
+ yield event;
2283
+ }
2284
+ } catch (error) {
2285
+ if (error instanceof OpenAIResponsesWebSocketSafeRetryError) {
2286
+ if (isResponsesServiceTierRejection(error)) {
2287
+ const nextTier = nextResponsesServiceTier(websocket.request.service_tier, error);
2288
+ if (!nextTier || outputObserved || acceptance === "observing" || output.content.length || websocketSignal.aborted || websocket.hasActiveResponse) throw error;
2289
+ closeWebSocketForFallback("service_tier_rejected");
2290
+ const rejectedTier = websocket.request.service_tier;
2291
+ if (rejectedTier === "ultrafast" || rejectedTier === "priority") responsesServiceTierObserver.reject(options, rejectedTier);
2292
+ yield* await createSseStream({
2293
+ ...await buildRequest("full-history"),
2294
+ service_tier: nextTier
2295
+ });
2296
+ return;
2297
+ }
2298
+ const encryptedContentRejected = isInvalidEncryptedContentError(error);
2299
+ const recovery = encryptedContentRejected ? await resolveNextResponsesEncryptedContentAttempt({
2300
+ kind: "initial",
2301
+ request: {
2302
+ ...websocket.request,
2303
+ stream: true
2304
+ }
2305
+ }, error, { buildFullHistoryRequest: () => buildRequest("full-history") }) : void 0;
2306
+ if (encryptedContentRejected && !recovery) throw error;
2307
+ closeWebSocketForFallback(`safe_server_error code=${error.code} status=${safeDebugValue(error.status)} param=${safeDebugValue(error.param)}`);
2308
+ yield* await createSseStream(recovery?.request ?? await buildRequest("full-history"), recovery?.kind ?? "continuation-rejected", recovery?.rejectedCompaction);
2309
+ return;
2310
+ }
2311
+ if (websocketSignal.aborted || !(error instanceof OpenAIResponsesWebSocketPreDispatchError)) throw error;
2312
+ params.setTransportToSse();
2313
+ logWebSocketFallback("before_first_event");
2314
+ yield* await createSseStream();
2315
+ }
2316
+ } };
2317
+ }
2318
+ //#endregion
2319
+ //#region packages/ai/src/transports/openai-responses-websocket.ts
2320
+ const SESSION_WEBSOCKET_CACHE_TTL_MS = 3e5;
2321
+ const SESSION_WEBSOCKET_MAX_AGE_MS = 33e5;
2322
+ const WEBSOCKET_OPEN_STATE = 1;
2323
+ const websocketSessionCache = /* @__PURE__ */ new Map();
2324
+ const degradedWebSocketConnections = /* @__PURE__ */ new Map();
2325
+ function closeWebSocketSilently(socket, reason = "done") {
2326
+ try {
2327
+ socket.close({
2328
+ code: 1e3,
2329
+ reason
2330
+ });
2331
+ } catch {}
2332
+ }
2333
+ function invalidateOwnedWebSocketSession(cacheKey, entry, reason = "done") {
2334
+ if (entry.idleTimer) {
2335
+ clearTimeout(entry.idleTimer);
2336
+ entry.idleTimer = void 0;
2337
+ }
2338
+ closeWebSocketSilently(entry.socket, reason);
2339
+ entry.steeringContinuation?.steering.close(/* @__PURE__ */ new Error("Responses steering connection closed"));
2340
+ entry.steeringContinuation?.iterator.return?.().catch(() => void 0);
2341
+ entry.steeringContinuation = void 0;
2342
+ if (websocketSessionCache.get(cacheKey) === entry) websocketSessionCache.delete(cacheKey);
2343
+ }
2344
+ function scheduleSessionWebSocketExpiry(cacheKey, entry) {
2345
+ if (entry.idleTimer) clearTimeout(entry.idleTimer);
2346
+ entry.idleTimer = setTimeout(() => {
2347
+ if (entry.busy) return;
2348
+ invalidateOwnedWebSocketSession(cacheKey, entry, "idle_timeout");
2349
+ }, SESSION_WEBSOCKET_CACHE_TTL_MS);
2350
+ entry.idleTimer.unref?.();
2351
+ }
2352
+ function prepareWebSocketConnection(client, headers) {
2353
+ if (!isOfficialOpenAIResponsesBaseUrl(client.baseURL)) throw new Error("OpenAI Responses WebSocket requires the official API endpoint");
2354
+ if (typeof client.apiKey !== "string" || client.apiKey.length === 0) throw new Error("OpenAI Responses WebSocket requires an API key");
2355
+ const owner = getAiTransportHost();
2356
+ const resolvedApiKey = owner.resolveSecretSentinel(client.apiKey);
2357
+ const resolvedHeaders = { ...resolveAiTransportHeaderSentinels(headers) };
2358
+ for (const key of Object.keys(resolvedHeaders)) {
2359
+ const normalizedKey = key.toLowerCase();
2360
+ if (normalizedKey === "authorization" || normalizedKey === "traceparent") delete resolvedHeaders[key];
2361
+ }
2362
+ if (!resolvedApiKey) throw new Error("OpenAI Responses WebSocket requires a resolved API key");
2363
+ return {
2364
+ client: client.withOptions({ apiKey: resolvedApiKey }),
2365
+ headers: resolvedHeaders,
2366
+ owner,
2367
+ ownerId: getSessionResourceOwnerId(owner),
2368
+ identity: sha256Hex(JSON.stringify([
2369
+ resolvedApiKey,
2370
+ client.baseURL,
2371
+ Object.entries(resolvedHeaders).toSorted(([a], [b]) => a.localeCompare(b))
2372
+ ]))
2373
+ };
2374
+ }
2375
+ function createWebSocket(connection, onError) {
2376
+ const socket = new ResponsesWS(connection.client, {
2377
+ headers: connection.headers,
2378
+ maxQueueSize: 1
2379
+ });
2380
+ socket.on("error", () => onError(socket));
2381
+ return socket;
2382
+ }
2383
+ function createTransientWebSocketLease(connection) {
2384
+ const socket = createWebSocket(connection, (failedSocket) => closeWebSocketSilently(failedSocket, "transport_error"));
2385
+ return {
2386
+ socket,
2387
+ iterator: socket.stream(),
2388
+ reusedConnection: false,
2389
+ release: () => closeWebSocketSilently(socket)
2390
+ };
2391
+ }
2392
+ function createCachedWebSocketLease(cacheKey, entry, reusedConnection) {
2393
+ entry.busy = true;
2394
+ const steeringContinuation = entry.steeringContinuation;
2395
+ entry.steeringContinuation = void 0;
2396
+ return {
2397
+ socket: entry.socket,
2398
+ iterator: steeringContinuation?.iterator ?? entry.socket.stream(),
2399
+ entry,
2400
+ reusedConnection,
2401
+ steeringContinuation,
2402
+ release: ({ keep } = {}) => {
2403
+ if (!keep || entry.socket.socket.readyState !== WEBSOCKET_OPEN_STATE) {
2404
+ invalidateOwnedWebSocketSession(cacheKey, entry);
2405
+ return;
2406
+ }
2407
+ entry.busy = false;
2408
+ scheduleSessionWebSocketExpiry(cacheKey, entry);
2409
+ }
2410
+ };
2411
+ }
2412
+ function acquireWebSocket(params, connection) {
2413
+ if (params.mode === "websocket" || !params.sessionId) return createTransientWebSocketLease(connection);
2414
+ const cacheKey = `${connection.ownerId}\0${params.sessionId}\0${connection.identity}`;
2415
+ const cached = websocketSessionCache.get(cacheKey);
2416
+ if (cached) {
2417
+ if (cached.idleTimer) {
2418
+ clearTimeout(cached.idleTimer);
2419
+ cached.idleTimer = void 0;
2420
+ }
2421
+ if (cached.busy) return createTransientWebSocketLease(connection);
2422
+ const expired = Date.now() - cached.createdAt >= SESSION_WEBSOCKET_MAX_AGE_MS;
2423
+ if (!expired && cached.socket.socket.readyState === WEBSOCKET_OPEN_STATE) return createCachedWebSocketLease(cacheKey, cached, true);
2424
+ invalidateOwnedWebSocketSession(cacheKey, cached, expired ? "connection_age_limit" : "done");
2425
+ }
2426
+ const entry = {
2427
+ socket: createWebSocket(connection, (failedSocket) => {
2428
+ const failedEntry = websocketSessionCache.get(cacheKey);
2429
+ if (failedEntry?.socket === failedSocket) invalidateOwnedWebSocketSession(cacheKey, failedEntry, "transport_error");
2430
+ else closeWebSocketSilently(failedSocket, "transport_error");
2431
+ }),
2432
+ sessionId: params.sessionId,
2433
+ owner: connection.owner,
2434
+ busy: true,
2435
+ createdAt: Date.now()
2436
+ };
2437
+ websocketSessionCache.set(cacheKey, entry);
2438
+ return createCachedWebSocketLease(cacheKey, entry, false);
2439
+ }
2440
+ function sanitizeWebSocketRequest(request) {
2441
+ const { stream: _stream, background: _background, ...websocketRequest } = request;
2442
+ return websocketRequest;
2443
+ }
2444
+ async function nextWebSocketMessage(iterator, signal) {
2445
+ if (signal?.aborted) throw transportAbortError(signal);
2446
+ return await racePromiseWithAbortSignal(iterator.next(), signal, transportAbortError);
2447
+ }
2448
+ function readServerEvent(message) {
2449
+ if (message.type === "message") return message.message;
2450
+ if (message.type === "error") throw parseOpenAIResponsesWebSocketServerError(message.error) ?? new Error("OpenAI Responses WebSocket transport failed", { cause: message.error });
2451
+ if (message.type === "close") throw new Error(`OpenAI Responses WebSocket closed before completion (code ${message.code})`);
2452
+ }
2453
+ function createOpenAIResponsesWebSocketStream(params) {
2454
+ const connection = prepareWebSocketConnection(params.client, params.headers);
2455
+ let fullRequest = sanitizeWebSocketRequest(params.request);
2456
+ const requestModel = typeof fullRequest.model === "string" ? fullRequest.model : "";
2457
+ const degradationKey = `${connection.ownerId}\0${params.sessionId ?? ""}\0${connection.identity}\0${requestModel}`;
2458
+ const degraded = degradedWebSocketConnections.get(degradationKey);
2459
+ if (degraded && degraded.retryAt > Date.now()) throw new OpenAIResponsesWebSocketPreDispatchError(/* @__PURE__ */ new Error("OpenAI Responses WebSocket is cooling down after a transport failure"));
2460
+ if (degraded) clearTimeout(degraded.expiryTimer);
2461
+ degradedWebSocketConnections.delete(degradationKey);
2462
+ const markDegraded = () => {
2463
+ const cooldownMs = params.degradeCooldownMs;
2464
+ if (cooldownMs === void 0 || !Number.isFinite(cooldownMs) || cooldownMs <= 0) return;
2465
+ const entry = {
2466
+ sessionId: params.sessionId,
2467
+ owner: connection.owner,
2468
+ retryAt: Date.now() + cooldownMs,
2469
+ expiryTimer: setTimeout(() => {
2470
+ if (degradedWebSocketConnections.get(degradationKey) === entry) degradedWebSocketConnections.delete(degradationKey);
2471
+ }, cooldownMs)
2472
+ };
2473
+ entry.expiryTimer.unref?.();
2474
+ degradedWebSocketConnections.set(degradationKey, entry);
2475
+ };
2476
+ let lease;
2477
+ try {
2478
+ lease = acquireWebSocket(params, connection);
2479
+ } catch (error) {
2480
+ markDegraded();
2481
+ throw new OpenAIResponsesWebSocketPreDispatchError(error);
2482
+ }
2483
+ let prepared;
2484
+ let previousContinuation;
2485
+ const resumedSteering = lease.steeringContinuation;
2486
+ const steeringMode = resumedSteering ? resumedSteering.requiresInput ? "required-input" : "automatic" : void 0;
2487
+ try {
2488
+ const continuation = previousContinuation = lease.entry?.continuation;
2489
+ if (continuation && lease.entry) {
2490
+ lease.entry.continuation = void 0;
2491
+ prepared = resolveResponsesContinuationRequest(continuation, fullRequest, steeringMode);
2492
+ } else {
2493
+ fullRequest = params.restoreRequest?.(fullRequest) ?? fullRequest;
2494
+ prepared = {
2495
+ request: fullRequest,
2496
+ continuationStatus: lease.entry ? "no_previous_response" : "socket_not_cached"
2497
+ };
2498
+ }
2499
+ } catch (error) {
2500
+ lease.iterator.return?.().catch(() => void 0);
2501
+ lease.release({ keep: false });
2502
+ throw error;
2503
+ }
2504
+ let streamStarted = false;
2505
+ let terminalResponse;
2506
+ let terminalReceived = false;
2507
+ let released = false;
2508
+ let retainIterator = false;
2509
+ let deferredInput = false;
2510
+ let inputReplay;
2511
+ if (resumedSteering) try {
2512
+ if (prepared.continuationStatus !== "continued" || !prepared.request.previous_response_id) throw new Error("Responses steering continuation changed its request or history");
2513
+ const input = omitAcceptedSteering(prepared.request.input ?? [], resumedSteering.acceptedInput);
2514
+ 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");
2515
+ const baseline = prepared.fullRequest ?? fullRequest;
2516
+ const priorLength = (baseline.input?.length ?? 0) - (prepared.request.input?.length ?? 0);
2517
+ const fingerprints = input.map(responsesInputFingerprint);
2518
+ if (fingerprints.length > 0) inputReplay = {
2519
+ afterResponseId: prepared.request.previous_response_id,
2520
+ before: resumedSteering.requiresInput ? fingerprints : [],
2521
+ after: resumedSteering.requiresInput ? [] : fingerprints
2522
+ };
2523
+ const delivered = resumedSteering.requiresInput ? input : [];
2524
+ prepared.fullRequest = {
2525
+ ...baseline,
2526
+ input: [
2527
+ ...(baseline.input ?? []).slice(0, priorLength),
2528
+ ...resumedSteering.acceptedInput,
2529
+ ...delivered
2530
+ ]
2531
+ };
2532
+ prepared.request = {
2533
+ ...prepared.request,
2534
+ input: delivered
2535
+ };
2536
+ deferredInput = !resumedSteering.requiresInput && input.length > 0;
2537
+ } catch (error) {
2538
+ lease.iterator.return?.().catch(() => void 0);
2539
+ lease.release({ keep: false });
2540
+ throw new OpenAIResponsesWebSocketPostDispatchError(error);
2541
+ }
2542
+ const steering = lease.entry && params.onActiveResponse && params.steeringInput ? createResponsesSteering({
2543
+ onActiveResponse: params.onActiveResponse,
2544
+ toInput: params.steeringInput,
2545
+ send: (event) => lease.socket.sendRaw(JSON.stringify(event)),
2546
+ needsContinuation: () => deferredInput,
2547
+ assertActive: () => {
2548
+ if (released || terminalReceived || params.signal?.aborted) throw new Error("Responses steering is no longer active");
2549
+ }
2550
+ }) : void 0;
2551
+ const finish = ({ keep = true } = {}) => {
2552
+ if (released) return;
2553
+ released = true;
2554
+ if (keep && lease.entry && terminalResponse) lease.entry.continuation = recordResponsesContinuationState(previousContinuation, prepared.fullRequest ?? fullRequest, terminalResponse, previousContinuation?.lastResponseId === prepared.request.previous_response_id);
2555
+ lease.release({ keep });
2556
+ };
2557
+ return {
2558
+ stream: { async *[Symbol.asyncIterator]() {
2559
+ if (streamStarted) throw new Error("OpenAI Responses WebSocket stream can only be consumed once");
2560
+ streamStarted = true;
2561
+ const iterator = lease.iterator;
2562
+ let requestDispatched = false;
2563
+ try {
2564
+ if (params.signal?.aborted) throw transportAbortError(params.signal);
2565
+ if (resumedSteering) {
2566
+ requestDispatched = true;
2567
+ if (resumedSteering.requiresInput) lease.socket.send({
2568
+ ...prepared.request,
2569
+ type: "response.create"
2570
+ });
2571
+ }
2572
+ for (;;) {
2573
+ const buffered = resumedSteering?.buffered.shift();
2574
+ const next = buffered ? {
2575
+ value: buffered,
2576
+ done: false
2577
+ } : await nextWebSocketMessage(iterator, params.signal);
2578
+ if (next.done) throw new Error("OpenAI Responses WebSocket closed before a terminal response event");
2579
+ if (next.value.type === "open") {
2580
+ if (!requestDispatched) {
2581
+ requestDispatched = true;
2582
+ lease.socket.send({
2583
+ ...prepared.request,
2584
+ type: "response.create"
2585
+ });
2586
+ }
2587
+ continue;
2588
+ }
2589
+ const event = readServerEvent(next.value);
2590
+ if (!event) continue;
2591
+ if (isRecord(event) && typeof event.type === "string" && event.type.startsWith("response.steer.")) {
2592
+ if ((isRecord(event.steer) && event.steer.previous_response_id === steering?.responseId ? steering : resumedSteering?.steering ?? steering)?.handle(event)) continue;
2593
+ }
2594
+ steering?.handle(event);
2595
+ if (event.type === "response.completed") terminalResponse = event.response;
2596
+ terminalReceived = event.type === "response.completed" || event.type === "response.incomplete" || event.type === "response.failed";
2597
+ if (terminalReceived) {
2598
+ steering?.seal();
2599
+ if (event.type === "response.failed") steering?.close(/* @__PURE__ */ new Error("Responses failed before steering could be applied"));
2600
+ const continuationBuffer = [];
2601
+ for (;;) {
2602
+ if (!steering?.pending) break;
2603
+ const acknowledgement = await nextWebSocketMessage(iterator, params.signal);
2604
+ if (acknowledgement.done) throw new Error("Responses closed before acknowledging steering");
2605
+ const acknowledgedEvent = readServerEvent(acknowledgement.value);
2606
+ if (!steering.handle(acknowledgedEvent)) continuationBuffer.push(acknowledgement.value);
2607
+ }
2608
+ const acceptedInput = steering?.acceptedInput ?? [];
2609
+ const isSteered = event.type === "response.incomplete" && isRecord(event.response.incomplete_details) && event.response.incomplete_details.reason === "steered";
2610
+ if (lease.entry && steering && acceptedInput.length > 0 && (event.type === "response.completed" || isSteered)) {
2611
+ if (event.type === "response.incomplete") terminalResponse = event.response;
2612
+ lease.entry.steeringContinuation = {
2613
+ iterator,
2614
+ buffered: continuationBuffer,
2615
+ acceptedInput,
2616
+ requiresInput: (terminalResponse?.output ?? []).some((item) => (item.type === "function_call" || item.type === "custom_tool_call") && !(isRecord(item) && item.async === true) || item.type === "mcp_approval_request"),
2617
+ steering,
2618
+ instructions: fullRequest.instructions,
2619
+ tools: fullRequest.tools
2620
+ };
2621
+ retainIterator = true;
2622
+ if (isSteered) {
2623
+ yield {
2624
+ ...event,
2625
+ type: "response.completed",
2626
+ response: {
2627
+ ...event.response,
2628
+ status: "completed",
2629
+ incomplete_details: null
2630
+ }
2631
+ };
2632
+ return;
2633
+ }
2634
+ }
2635
+ }
2636
+ yield event;
2637
+ if (terminalReceived) {
2638
+ degradedWebSocketConnections.delete(degradationKey);
2639
+ return;
2640
+ }
2641
+ }
2642
+ } catch (error) {
2643
+ const steeringDispatched = Boolean(steering?.pending || steering?.acceptedInput.length || resumedSteering);
2644
+ steering?.close(error instanceof Error ? error : /* @__PURE__ */ new Error("Responses steering failed"));
2645
+ if (lease.entry) lease.entry.continuation = void 0;
2646
+ const safeRetry = error instanceof OpenAIResponsesWebSocketSafeRetryError && !steeringDispatched;
2647
+ if (!params.callerSignal?.aborted && !safeRetry) markDegraded();
2648
+ if (!requestDispatched && !params.signal?.aborted) throw new OpenAIResponsesWebSocketPreDispatchError(error);
2649
+ if (!requestDispatched || params.callerSignal?.aborted || safeRetry) throw error;
2650
+ throw new OpenAIResponsesWebSocketPostDispatchError(error);
2651
+ } finally {
2652
+ steering?.seal();
2653
+ if (!retainIterator) {
2654
+ steering?.close(/* @__PURE__ */ new Error("Responses stream ended before steering was confirmed"));
2655
+ await iterator.return?.().catch(() => void 0);
2656
+ }
2657
+ if (!terminalReceived) finish({ keep: false });
2658
+ }
2659
+ } },
2660
+ request: prepared.request,
2661
+ fullRequest: prepared.fullRequest ?? fullRequest,
2662
+ reusedConnection: lease.reusedConnection,
2663
+ continuationStatus: prepared.continuationStatus,
2664
+ inputReplay,
2665
+ get hasActiveResponse() {
2666
+ return Boolean(steering?.responseId || resumedSteering);
2667
+ },
2668
+ finish
2669
+ };
2670
+ }
2671
+ function closeOpenAIResponsesWebSocketSessions(sessionId, owner) {
2672
+ for (const [cacheKey, entry] of websocketSessionCache) {
2673
+ if (owner && entry.owner !== owner || sessionId && entry.sessionId !== sessionId) continue;
2674
+ invalidateOwnedWebSocketSession(cacheKey, entry, "session_cleanup");
2675
+ }
2676
+ for (const [key, entry] of degradedWebSocketConnections) if ((!owner || entry.owner === owner) && (!sessionId || entry.sessionId === sessionId)) {
2677
+ clearTimeout(entry.expiryTimer);
2678
+ degradedWebSocketConnections.delete(key);
2679
+ }
2680
+ }
2681
+ registerSessionResourceCleanup(closeOpenAIResponsesWebSocketSessions);
2682
+ //#endregion
2683
+ //#region packages/ai/src/transports/openai-responses-client.ts
2684
+ function resolveNativeOpenAIResponsesWebSocketMode(model, transport) {
2685
+ if (transport !== "websocket" && transport !== "websocket-cached" && transport !== "auto") return;
2686
+ if (getAiTransportHost().requiresManagedTransport(model)) return;
2687
+ return supportsNativeOpenAIResponsesEndpoint(model) ? transport : void 0;
2688
+ }
2689
+ function combineWebSocketTimeoutSignal(signal, model, timeoutMs) {
2690
+ const resolvedTimeoutMs = timeoutMs !== void 0 && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : getAiTransportHost().resolveModelRequestTimeoutMs(model);
2691
+ if (resolvedTimeoutMs === void 0 || !Number.isFinite(resolvedTimeoutMs)) return signal;
2692
+ return AbortSignal.any([signal, AbortSignal.timeout(Math.max(1, resolvedTimeoutMs))]);
2693
+ }
2694
+ function createOpenAIResponsesClient(model, apiKey, defaultHeaders, fetchOverride) {
2695
+ return new OpenAI({
2696
+ apiKey,
2697
+ baseURL: resolveOpenAIClientBaseUrl(model),
2698
+ dangerouslyAllowBrowser: true,
2699
+ defaultHeaders,
2700
+ fetch: fetchOverride ?? buildGuardedModelFetch(model),
2701
+ ...buildOpenAISdkClientOptions(model)
2702
+ });
2703
+ }
2704
+ function createResponsesTransportExecutor(config) {
2705
+ return (model, context, options) => {
2706
+ const responsesOptions = options;
2707
+ const compactRequest = claimResponsesCompactRequest(responsesOptions);
2708
+ const { eventStream, stream } = createWritableTransportEventStream();
2709
+ (async () => {
2710
+ const output = createAssistantOutput(model, config.outputApi);
2711
+ let firstEventAbort;
2712
+ let continuationClaim;
2713
+ const requestLifecycle = responsesRequestLifecycle.get(options);
2714
+ try {
2715
+ const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
2716
+ const websocketMode = resolveNativeOpenAIResponsesWebSocketMode(model, responsesOptions?.transport);
2717
+ const encodeBody = prepareModelRequestBody(websocketMode || compactRequest ? void 0 : options);
2718
+ const turnState = resolveProviderTransportTurnState(model, {
2719
+ sessionId: options?.sessionId,
2720
+ turnId: randomUUID(),
2721
+ attempt: 1,
2722
+ transport: websocketMode ? "websocket" : "stream"
2723
+ });
2724
+ const websocketSessionPolicy = websocketMode ? turnState?.websocket : void 0;
2725
+ const httpTurnHeaders = filterProviderTurnHeadersForExplicitOpencodeSession(model, options, turnState?.headers);
2726
+ const websocketTurnHeaders = filterProviderTurnHeadersForExplicitOpencodeSession(model, options, websocketSessionPolicy?.headers);
2727
+ const websocketHeaders = websocketMode ? buildOpenAIClientHeaders(model, context, options?.headers, websocketTurnHeaders, options?.sessionId, options?.cacheRetention) : void 0;
2728
+ const httpHeaders = buildOpenAIClientHeaders(model, context, options?.headers, httpTurnHeaders, options?.sessionId, options?.cacheRetention);
2729
+ const fetchOverride = createResponsesRequestFetch(model, {
2730
+ compact: Boolean(compactRequest),
2731
+ stream: config.streamRequest,
2732
+ lifecycle: requestLifecycle,
2733
+ onSseComment: () => notifyLlmRequestActivity(options?.signal, false)
2734
+ });
2735
+ const client = config.createClient(model, apiKey, httpHeaders, fetchOverride);
2736
+ const nativeAstra = model.id === "gpt-6-astra" && supportsNativeOpenAIResponsesEndpoint(model);
2737
+ const asyncToolExecutionEligible = nativeAstra && options?.asyncToolExecution === true && !responsesOptions?.openclawCodeModeToolSurface;
2738
+ const prepareRequest = async (request) => {
2739
+ let params = request;
2740
+ const nextParams = await options?.onPayload?.(params, model);
2741
+ if (nextParams !== void 0) params = nextParams;
2742
+ params = sanitizeOpenAICodexResponsesParams(model, params);
2743
+ params = sanitizeResponsesImagePayload(params);
2744
+ if (responsesOptions?.openclawCodeModeToolSurface === true) {
2745
+ const visibleToolNames = resolveCodeModeResponsesVisibleToolNames(context);
2746
+ const allowedHostedToolTypes = responsesOptions?.openclawCodeModeAllowedHostedToolTypes;
2747
+ enforceCodeModeResponsesToolSurface(params, visibleToolNames, allowedHostedToolTypes, codeModeToolSurfaceObserver.get(options));
2748
+ assertCodeModeResponsesToolSurface(params, visibleToolNames, allowedHostedToolTypes);
2749
+ }
2750
+ if (asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true && params.tools) {
2751
+ const synchronousTools = new Set(context.tools?.flatMap((tool) => tool.async === false ? [tool.name] : []));
2752
+ params.tools = params.tools.map((tool) => tool.type === "function" && !synchronousTools.has(tool.name) ? {
2753
+ ...tool,
2754
+ async: true
2755
+ } : tool);
2756
+ }
2757
+ return params;
2758
+ };
2759
+ const buildRequest = (replayMode, requestContext = context) => prepareRequest(config.buildRequest(model, requestContext, responsesOptions, turnState?.metadata, replayMode));
2760
+ let params = await buildRequest("checkpoint");
2761
+ const asyncTools = asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true;
2762
+ if (compactRequest) {
2763
+ const compacted = await postOpenAIResponsesCompaction({
2764
+ client,
2765
+ model,
2766
+ request: params,
2767
+ options: responsesOptions
2768
+ });
2769
+ output.usage.input = compacted.usage.input_tokens;
2770
+ output.usage.output = compacted.usage.output_tokens;
2771
+ output.usage.totalTokens = compacted.usage.input_tokens + compacted.usage.output_tokens;
2772
+ compactRequest.resolve(compacted);
2773
+ finalizeTransportStream({
2774
+ stream,
2775
+ output,
2776
+ signal: options?.signal
2777
+ });
2778
+ return;
2779
+ }
2780
+ const sessionId = options?.sessionId;
2781
+ if (config.httpContinuation && !websocketMode && !getAiTransportHost().requiresManagedTransport(model) && (supportsNativeOpenAIResponsesEndpoint(model) || resolveOpenAIResponsesPayloadPolicy(model).explicitContinuationOptIn) && sessionId && (params.store === true || supportsResponsesReasoningUpdate(params)) && !params.previous_response_id) {
2782
+ continuationClaim = claimOpenAIResponsesHttpContinuation({
2783
+ sessionId,
2784
+ apiKey,
2785
+ baseUrl: model.baseUrl,
2786
+ headers: httpHeaders,
2787
+ request: params,
2788
+ restoreRequest: () => restoreResponsesReasoningState(context, model, responsesOptions, params)
2789
+ });
2790
+ if (continuationClaim) params = continuationClaim.fullRequest;
2791
+ }
2792
+ const observePrompt = createResponsesPromptEgressObserver(responsesOptions, context.systemPrompt);
2793
+ const requestStartedAt = Date.now();
2794
+ let started = false;
2795
+ const startStream = () => {
2796
+ if (!started) {
2797
+ started = true;
2798
+ stream.push({
2799
+ type: "start",
2800
+ partial: output
2801
+ });
2802
+ }
2803
+ };
2804
+ const firstEvent = createFirstStreamEventAbortController(options?.signal);
2805
+ firstEventAbort = firstEvent;
2806
+ const requestOptions = buildOpenAISdkRequestOptions(model, firstEvent.signal, {
2807
+ stream: config.streamRequest,
2808
+ timeoutMs: options?.timeoutMs
2809
+ });
2810
+ const websocketSignal = combineWebSocketTimeoutSignal(firstEvent.signal, model, requestOptions?.timeout);
2811
+ emitModelTransportDebug(log, `[responses] start provider=${model.provider} api=${model.api} model=${model.id} requestIdHash=${redactIdentifier(options?.requestId, { len: 64 })} baseUrl=${formatModelTransportDebugBaseUrl(model.baseUrl)} timeoutMs=${safeDebugValue(requestOptions?.timeout)} apiKey=${apiKey ? "present" : "missing"} ${summarizeResponsesPayload(params)}`);
2812
+ const responseModelTracker = createResponseModelTracker(isOpenAICodexResponsesModel(model));
2813
+ let continuationBaseline;
2814
+ let dispatchedPreviousResponseId;
2815
+ let contextUsageEligible = true;
2816
+ let requestedTier;
2817
+ const createSseStream = async (initialRequest = continuationClaim?.request ?? params, initialAttemptKind = "initial", initialRejectedCompaction) => {
2818
+ const { stream: responseStream } = await createResponsesStreamWithRecovery({
2819
+ client,
2820
+ request: initialRequest,
2821
+ requestOptions,
2822
+ model,
2823
+ encodeBody,
2824
+ observePrompt,
2825
+ initialAttemptKind,
2826
+ initialRejectedCompaction,
2827
+ buildFullHistoryRequest: () => buildRequest("full-history"),
2828
+ onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, responsesOptions, checkpoint),
2829
+ canRetryStream: () => output.content.length === 0,
2830
+ onServiceTierRejected: (tier) => responsesServiceTierObserver.reject(options, tier),
2831
+ wrapStream: ({ stream: rawResponseStream, response, attempt }) => {
2832
+ requestedTier = attempt.request.service_tier;
2833
+ contextUsageEligible &&= attempt.kind === "initial";
2834
+ dispatchedPreviousResponseId = attempt.request.previous_response_id;
2835
+ continuationBaseline = attempt.request.previous_response_id ? params : attempt.request;
2836
+ const trackedResponseStream = responseModelTracker.track(response, rawResponseStream);
2837
+ return withProviderResponseHook({
2838
+ stream: observeResponsesStream(trackedResponseStream, model, requestStartedAt),
2839
+ signal: firstEvent.signal,
2840
+ abort: firstEvent.abort,
2841
+ hook: createOpenAIProviderAcceptanceHook(options, response, model),
2842
+ onReady: () => {
2843
+ emitModelTransportDebug(log, `[responses] headers provider=${model.provider} api=${model.api} model=${model.id} transport=sse elapsedMs=${Date.now() - requestStartedAt}`);
2844
+ startStream();
2845
+ }
2846
+ });
2847
+ }
2848
+ });
2849
+ return responseStream;
2850
+ };
2851
+ let responseStream;
2852
+ let websocketBaseline;
2853
+ let finishWebSocket;
2854
+ let transport = "sse";
2855
+ const logWebSocketFallback = (reason) => emitModelTransportDebug(log, `[responses] websocket_fallback provider=${model.provider} api=${model.api} model=${model.id} reason=${reason}`);
2856
+ const closeWebSocketForFallback = (reason) => {
2857
+ finishWebSocket?.({ keep: false });
2858
+ finishWebSocket = void 0;
2859
+ transport = "sse";
2860
+ logWebSocketFallback(reason);
2861
+ };
2862
+ if (websocketMode) try {
2863
+ const websocket = createOpenAIResponsesWebSocketStream({
2864
+ client,
2865
+ request: params,
2866
+ restoreRequest: (request) => restoreResponsesReasoningState(context, model, responsesOptions, request),
2867
+ mode: websocketMode,
2868
+ sessionId: options?.sessionId,
2869
+ headers: websocketHeaders,
2870
+ signal: websocketSignal,
2871
+ callerSignal: options?.signal,
2872
+ degradeCooldownMs: websocketSessionPolicy?.degradeCooldownMs,
2873
+ onActiveResponse: nativeAstra && params.model === "gpt-6-astra" ? options?.onActiveResponse : void 0,
2874
+ steeringInput: (messages) => {
2875
+ contextUsageEligible = false;
2876
+ return projectResponsesSteeringInput(params, () => buildRequest("checkpoint", {
2877
+ ...context,
2878
+ messages: [...context.messages, ...messages]
2879
+ }));
2880
+ }
2881
+ });
2882
+ finishWebSocket = websocket.finish;
2883
+ requestedTier = websocket.request.service_tier;
2884
+ websocketBaseline = websocket.fullRequest;
2885
+ recordResponsesInputReplay(output, websocket.inputReplay);
2886
+ contextUsageEligible &&= websocket.inputReplay === void 0;
2887
+ observePrompt?.(websocket.request, {
2888
+ egress: "responses-websocket",
2889
+ payloadVariant: "initial"
2890
+ });
2891
+ transport = "websocket";
2892
+ emitModelTransportDebug(log, `[responses] websocket_selected provider=${model.provider} api=${model.api} model=${model.id} mode=${websocketMode} reused=${websocket.reusedConnection} continuation=${websocket.continuationStatus === "continued"} continuationStatus=${websocket.continuationStatus} sessionIdHash=${redactIdentifier(options?.sessionId)} headersHash=${redactIdentifier(JSON.stringify(Object.entries(websocketHeaders ?? {}).toSorted(([a], [b]) => a.localeCompare(b))))}`);
2893
+ responseStream = createRecoverableResponsesWebSocketStream({
2894
+ trackedWebSocketStream: responseModelTracker.track(void 0, websocket.stream),
2895
+ websocket,
2896
+ websocketSignal,
2897
+ options,
2898
+ output,
2899
+ buildRequest,
2900
+ createSseStream,
2901
+ closeWebSocketForFallback,
2902
+ logWebSocketFallback,
2903
+ startStream,
2904
+ setTransportToSse: () => {
2905
+ transport = "sse";
2906
+ }
2907
+ });
2908
+ } catch (error) {
2909
+ if (error instanceof OpenAIResponsesWebSocketPostDispatchError) throw error;
2910
+ closeWebSocketForFallback("setup_failure");
2911
+ responseStream = await createSseStream();
2912
+ }
2913
+ else responseStream = await createSseStream();
2914
+ try {
2915
+ const acceptedResponseStream = withResponsesRequestAcceptance(responseStream, requestLifecycle, transport === "websocket" ? websocketSignal : firstEvent.signal);
2916
+ const terminal = await processResponsesStream(acceptedResponseStream, output, stream, model, {
2917
+ canRetryIdentityConflict: () => hasOnlyResponsesFunctionTools(transport === "websocket" ? websocketBaseline : continuationBaseline),
2918
+ ...config.pricingOptions?.(responsesOptions, model),
2919
+ resolveServiceTier: (responseTier, originalTier) => responseTier ?? (requestedTier === "priority" || requestedTier === "default" ? requestedTier : originalTier),
2920
+ onServiceTier: (responseTier) => responsesServiceTierObserver.observe(options, requestedTier, responseTier),
2921
+ firstEventTimeoutMs: getFirstStreamEventTimeoutMs(options) ?? config.firstEventTimeoutMs,
2922
+ abortFirstEventStream: firstEvent.abort,
2923
+ onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
2924
+ signal: options?.signal,
2925
+ reasoningReplayMetadata: buildOpenAIResponsesReasoningReplayMetadata(model, {
2926
+ authProfileId: responsesOptions?.authProfileId,
2927
+ sessionId: options?.sessionId
2928
+ }),
2929
+ asyncToolExecution: asyncTools,
2930
+ ...responseModelTracker.terminalOptions
2931
+ });
2932
+ finishWebSocket?.();
2933
+ if (options?.signal?.aborted) throw transportAbortError(options.signal);
2934
+ if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
2935
+ const admitted = transport === "websocket" ? websocketBaseline : continuationBaseline;
2936
+ if (terminal && admitted && supportsNativeOpenAIResponsesEndpoint(model)) recordResponsesReasoningState(output, model, responsesOptions, admitted, terminal.output);
2937
+ if (continuationClaim && continuationBaseline && terminal) continuationClaim.commit(continuationBaseline, terminal, dispatchedPreviousResponseId);
2938
+ if (terminal && admitted && contextUsageEligible) recordResponsesContextUsage(output, model, responsesOptions, admitted, terminal.output, "transport");
2939
+ } catch (error) {
2940
+ finishWebSocket?.({ keep: false });
2941
+ throw error;
2942
+ }
2943
+ emitModelTransportDebug(log, `[responses] completed provider=${model.provider} api=${model.api} model=${model.id} transport=${transport} elapsedMs=${Date.now() - requestStartedAt}`);
2944
+ finalizeTransportStream({
2945
+ stream,
2946
+ output,
2947
+ signal: options?.signal
2948
+ });
2949
+ } catch (error) {
2950
+ if (requestLifecycle) await requestLifecycle.settle().catch(() => void 0);
2951
+ if (compactRequest) {
2952
+ compactRequest.reject(error);
2953
+ failTransportStream({
2954
+ stream,
2955
+ output,
2956
+ signal: options?.signal,
2957
+ error
2958
+ });
2959
+ return;
2960
+ }
2961
+ if (error instanceof ResponsesStreamFailure && error.observation) logResponsesFailedNoDetails(error.observation);
2962
+ const incompleteReason = output.diagnostics?.find(({ type }) => type === "openai_responses_terminal")?.details?.incompleteReason;
2963
+ emitModelTransportError(log, "responses", `provider=${model.provider} api=${model.api} model=${model.id} ` + summarizeOpenAITransportError(error) + (typeof incompleteReason === "string" ? ` incompleteReason=${incompleteReason}` : ""), options?.signal);
2964
+ failTransportStream({
2965
+ stream,
2966
+ output,
2967
+ signal: options?.signal,
2968
+ error
2969
+ });
2970
+ } finally {
2971
+ continuationClaim?.release();
2972
+ firstEventAbort?.dispose();
2973
+ }
2974
+ })();
2975
+ return eventStream;
2976
+ };
2977
+ }
2978
+ function createOpenAIResponsesTransportStreamFn() {
2979
+ return createResponsesTransportExecutor({
2980
+ streamRequest: true,
2981
+ httpContinuation: true,
2982
+ createClient: createOpenAIResponsesClient,
2983
+ buildRequest: buildOpenAIResponsesParams,
2984
+ pricingOptions: (options, model) => ({
2985
+ serviceTier: options?.serviceTier,
2986
+ applyServiceTierPricing: (usage, serviceTier) => applyResponsesServiceTierPricing(usage, serviceTier, model)
2987
+ })
2988
+ });
2989
+ }
2990
+ function createAzureOpenAIResponsesTransportStreamFn() {
2991
+ return createResponsesTransportExecutor({
2992
+ outputApi: "azure-openai-responses",
2993
+ firstEventTimeoutMs: AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS,
2994
+ createClient: createAzureOpenAIClient,
2995
+ buildRequest: (model, context, options, metadata, replayMode) => {
2996
+ const deploymentName = resolveAzureDeploymentNameFromMap({
2997
+ modelId: model.id,
2998
+ deploymentMap: process.env.AZURE_OPENAI_DEPLOYMENT_NAME_MAP
2999
+ });
3000
+ const params = buildOpenAIResponsesParams(model, context, options, metadata, replayMode);
3001
+ params.model = deploymentName;
3002
+ delete params.store;
3003
+ return params;
3004
+ }
3005
+ });
3006
+ }
3007
+ function createAzureOpenAIClient(model, apiKey, defaultHeaders, fetchOverride) {
3008
+ const baseURL = model.baseUrl.replace(/\/+$/, "");
3009
+ const clientOptions = {
3010
+ apiKey,
3011
+ dangerouslyAllowBrowser: true,
3012
+ defaultHeaders,
3013
+ baseURL,
3014
+ fetch: fetchOverride ?? buildGuardedModelFetch(model),
3015
+ ...buildOpenAISdkClientOptions(model)
3016
+ };
3017
+ if (isOpenAICompatibleAzureResponsesBaseUrl(baseURL)) return new OpenAI(clientOptions);
3018
+ return new AzureOpenAI({
3019
+ ...clientOptions,
3020
+ apiVersion: resolveAzureOpenAIApiVersion()
3021
+ });
1890
3022
  }
1891
3023
  //#endregion
1892
3024
  //#region packages/ai/src/transports/openai-completions-transport.ts
@@ -2010,7 +3142,23 @@ function createDirectCompletionsEventStream(output, stream) {
2010
3142
  };
2011
3143
  }
2012
3144
  function createOpenAICompletionsTransportStreamFn() {
2013
- return (model, context, options) => streamOpenAICompletionsRequest(model, context, options, "managed");
3145
+ const streamResponses = createOpenAIResponsesTransportStreamFn();
3146
+ return (model, context, options) => {
3147
+ const completionsOptions = options;
3148
+ if (model.reasoning && context.tools?.length && supportsModelTools(model) && isNativeOpenAIEndpoint(model)) {
3149
+ const toolChoice = completionsOptions?.toolChoice;
3150
+ const responsesOptions = {
3151
+ ...options,
3152
+ ...completionsOptions?.reasoning === void 0 && completionsOptions?.reasoningEffort === void 0 ? { reasoningEffort: "high" } : {},
3153
+ ...toolChoice && typeof toolChoice === "object" ? { toolChoice: toOpenAIResponsesToolChoice(toolChoice) } : {}
3154
+ };
3155
+ return streamResponses(getAiTransportHost().inheritManagedTransport(model, {
3156
+ ...model,
3157
+ api: "openai-responses"
3158
+ }), context, responsesOptions);
3159
+ }
3160
+ return streamOpenAICompletionsRequest(model, context, completionsOptions, "managed");
3161
+ };
2014
3162
  }
2015
3163
  function streamOpenAICompletionsRequest(model, context, options, mode) {
2016
3164
  const { eventStream, stream } = createWritableTransportEventStream();
@@ -2054,9 +3202,21 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
2054
3202
  ...buildOpenAISdkRequestOptions(model, firstEventAbort.signal, { timeoutMs: options?.timeoutMs }),
2055
3203
  ...await encodeBody(params)
2056
3204
  };
2057
- const { data: responseStream, response } = await client.chat.completions.create(params, requestOptions).withResponse();
3205
+ const request = client.chat.completions.create(params, requestOptions);
3206
+ const response = await request.asResponse();
2058
3207
  const hookedResponseStream = withProviderResponseHook({
2059
- stream: responseStream,
3208
+ stream: { async *[Symbol.asyncIterator]() {
3209
+ if (!params.stream) {
3210
+ yield await boundResponseBody(response, {
3211
+ maxBytes: 16777216,
3212
+ onOverflow: ({ maxBytes }) => /* @__PURE__ */ new Error(`Chat Completions JSON response exceeds ${maxBytes} bytes`)
3213
+ }).json();
3214
+ return;
3215
+ }
3216
+ const data = await request;
3217
+ if (Symbol.asyncIterator in data) yield* data;
3218
+ else yield data;
3219
+ } },
2060
3220
  signal: firstEventAbort.signal,
2061
3221
  abort: firstEventAbort.abort,
2062
3222
  hook: createOpenAIProviderAcceptanceHook(options, response, model),
@@ -2102,7 +3262,6 @@ function streamOpenAICompletionsRequest(model, context, options, mode) {
2102
3262
  signal: options?.signal,
2103
3263
  error,
2104
3264
  cleanup: () => {
2105
- if (mode === "managed") output.stopReason = options?.signal?.aborted ? "aborted" : "error";
2106
3265
  finalizeOpenAICompletionsToolCalls(output, { allowSilentToolCallPromotion: false });
2107
3266
  clearPendingCommentaryText(provisionalCommentaryTags);
2108
3267
  tagUnresolvedTextAsCommentary(output);
@@ -2143,7 +3302,7 @@ function createManagedCompletionsClient(model, context, options, apiKey, cacheRe
2143
3302
  const optionHeaders = resolveOpencodeSessionHeaders(model, options);
2144
3303
  const turnHeaders = filterProviderTurnHeadersForExplicitOpencodeSession(model, options, turnState?.headers);
2145
3304
  const doneDetector = createSseDoneDetector();
2146
- const baseFetch = buildGuardedModelFetch(model);
3305
+ const baseFetch = buildGuardedModelFetch(model, void 0, { onSseComment: () => notifyLlmRequestActivity(options?.signal, false) });
2147
3306
  const doneDetectingFetch = async (url, init) => {
2148
3307
  const response = await baseFetch(url, init);
2149
3308
  if (!response.body || !response.ok) return response;
@@ -2157,11 +3316,7 @@ function createManagedCompletionsClient(model, context, options, apiKey, cacheRe
2157
3316
  doneDetector.finish();
2158
3317
  }
2159
3318
  }));
2160
- return new Response(transformed, {
2161
- headers: response.headers,
2162
- status: response.status,
2163
- statusText: response.statusText
2164
- });
3319
+ return new Response(transformed, response);
2165
3320
  };
2166
3321
  const clientConfig = buildOpenAICompletionsClientConfig(model, buildOpenAIClientHeaders(model, context, {
2167
3322
  ...turnHeaders,
@@ -2181,4 +3336,4 @@ function createManagedCompletionsClient(model, context, options, apiKey, cacheRe
2181
3336
  };
2182
3337
  }
2183
3338
  //#endregion
2184
- export { flattenCompletionMessagesToStringContent as a, hasOpenAICompatibleConversationTurn as c, createDeepSeekTextFilter as d, convertMessages as i, canonicalizeMaxTokensParam as l, streamOpenAICompletionsRequest as n, stripCompletionMessagesToRoleContent as o, buildOpenAICompletionsParams as r, applyCompletionsAnthropicCacheControl as s, createOpenAICompletionsTransportStreamFn as t, resolveMaxTokensParam as u };
3339
+ export { requestPreparedOpenAIResponsesCompaction as a, convertMessages as c, applyCompletionsAnthropicCacheControl as d, hasOpenAICompatibleConversationTurn as f, createDeepSeekTextFilter as h, createOpenAIResponsesTransportStreamFn as i, flattenCompletionMessagesToStringContent as l, resolveMaxTokensParam as m, streamOpenAICompletionsRequest as n, hasResponsesWebSearchTool as o, canonicalizeMaxTokensParam as p, createAzureOpenAIResponsesTransportStreamFn as r, buildOpenAICompletionsParams as s, createOpenAICompletionsTransportStreamFn as t, stripCompletionMessagesToRoleContent as u };