@openclaw/ai 2026.10.2 → 2026.10.4

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 (21) hide show
  1. package/dist/{anthropic-C4qygbtf.mjs → anthropic-DloU96D6.mjs} +2 -2
  2. package/dist/{anthropic-stream-reducer-CWyWE21W.mjs → anthropic-stream-reducer-Djl4yqrc.mjs} +2 -3
  3. package/dist/{assistant-text-phase-DVZOxbuR.mjs → assistant-text-phase-DzvV7Oso.mjs} +1 -1
  4. package/dist/{azure-openai-responses-DO-Fv8ha.mjs → azure-openai-responses-CAyTrcy6.mjs} +1 -2
  5. package/dist/internal/anthropic.mjs +2 -2
  6. package/dist/internal/openai.mjs +5 -7
  7. package/dist/{openai-chatgpt-responses-CHdn8YJ_.mjs → openai-chatgpt-responses-vk4XdUjX.mjs} +6 -7
  8. package/dist/{openai-completions-BZfHIaZ7.mjs → openai-completions-XvUwdvJc.mjs} +1 -1
  9. package/dist/{openai-completions-transport-CuoQfnKV.mjs → openai-completions-transport-QYABn8Uz.mjs} +1180 -29
  10. package/dist/{openai-responses-BhAZFsL9.mjs → openai-responses-DNWY56mK.mjs} +2 -3
  11. package/dist/{openai-responses-prompt-observer-internal-CefUzh8M.mjs → openai-responses-request-lifecycle-Dskvtz_Z.mjs} +36 -1
  12. package/dist/{openai-responses-shared-CKNmC3vC.mjs → openai-responses-shared-BMx2NAS-.mjs} +805 -67
  13. package/dist/{provider-transport-turn-state-BX6TfCyW.mjs → provider-transport-turn-state-1T3vwTvn.mjs} +1 -1
  14. package/dist/providers.mjs +5 -5
  15. package/dist/{text-signature-D_vRrx-z.mjs → text-signature-CbqxIB8B.mjs} +25 -2
  16. package/dist/transports.mjs +11 -1148
  17. package/package.json +1 -1
  18. package/dist/openai-responses-request-lifecycle-Fsag-IGZ.mjs +0 -36
  19. package/dist/openai-transport-params-D7JMUPjf.mjs +0 -735
  20. package/dist/openai-web-search-tools-Cfu0uLyN.mjs +0 -14
  21. package/dist/provider-replay-context-CO_Eplnc.mjs +0 -25
@@ -3,39 +3,51 @@ import { r as appendAssistantThinking } from "./event-stream-C5AbCAaZ.mjs";
3
3
  import { o as isRecord } from "./record-coerce-CNDovvft.mjs";
4
4
  import { s as readNonEmptyStringPreservingWhitespace, t as hasNonEmptyString } from "./string-coerce-CtgOVOSv.mjs";
5
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";
6
+ import { N as isImageWithMediaPayload, a as resolveAiTransportHeaderSentinels, r as getAiTransportHost } from "./host-u3o8XiAp.mjs";
7
+ import { A as resolveOpenAIThinkingApi, D as supportsOpenAITemperature, _ as isOpenAIGpt54MiniModel, b as isOpenAIGpt6Model, d as OpenAIResponsesWebSocketSafeRetryError, g as responsesServiceTierObserver, 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 isOpenAIGpt55Model, y as isOpenAIGpt56Model } from "./openai-responses-contracts-BKu8O7l4.mjs";
8
8
  import { r as uniqueStrings } from "./string-normalization-PN10hf6d.mjs";
9
- import { o as truncateUtf16Safe } from "./provider-error-DQBE1bUQ.mjs";
9
+ import { n as getSessionResourceOwnerId, r as registerSessionResourceCleanup } from "./session-resources-D1wgDQ8C.mjs";
10
+ import { o as truncateUtf16Safe, s as stableStringify } from "./provider-error-DQBE1bUQ.mjs";
10
11
  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";
12
+ import { r as emitModelTransportDebug, t as formatModelTransportDebugBaseUrl, u as hasOnlyResponsesFunctionTools } from "./diagnostics-Caj-4RBA.mjs";
13
+ import { d as supportsModelTools, i as providerReplayContextMatches, n as buildProviderReplayContext, o as estimateStringChars, r as isProviderReplayContext } from "./text-signature-CbqxIB8B.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-GMN8A0fm.mjs";
14
15
  import { i as resolveProviderEndpoint, t as buildGuardedModelFetch } from "./host-policy-BwhNNGQR.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 { E as createToolArgumentPreviewSchedule, M as racePromiseWithAbortSignal, O as parseStreamingJson, P as sanitizeSurrogates, S as withProviderResponseHook, _ as sanitizeNonEmptyTransportPayloadText, 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-CCR7hSW0.mjs";
17
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-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 { $ as supportsResponsesReasoningUpdate, A as recordResponsesContextUsage, At as parseOpenAICompletionsUsage, B as claimOpenAIResponsesHttpContinuation, C as resolveAzureOpenAIApiVersion, Ct as GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP, D as safeDebugValue, Dt as isOpenAICompletionsThinkingEnabled, E as logResponsesFailedNoDetails, Et as createResponseModelTracker, F as convertResponsesMessages, Ft as redactIdentifier, H as resolveResponsesContinuationRequest, It as sha256Hex, L as readResponsesInputReplayState, Mt as readOpenAICompletionsReasoningBatch, N as buildResponsesInputMessage, Nt as resolveOpenAIClientBaseUrl, O as summarizeOpenAITransportError, Ot as log, Pt as resolvePromptCacheKey, Q as replayResponsesReasoningUpdates, R as recordResponsesInputReplay, S as isInvalidEncryptedContentError, St as toOpenAIResponsesToolChoice, T as ResponsesStreamFailure, U as responsesContinuationPrefixFingerprint, V as recordResponsesContinuationState, W as responsesContinuationRequestFingerprint, Z as isConfigurationUpdate, a as prepareResponsesTools, at as assertCodeModeResponsesToolSurface, bt as reconcileOpenAICompletionsToolChoice, c as observeResponsesStream, ct as buildOpenAISdkRequestOptions, dt as getCompat, gt as resolveOpenAISimpleReasoningEffort, ht as resolveOpenAIRequestReasoning, it as suppressOpenAIResponsesCompaction, jt as readOpenAICompletionsContentDeltas, k as summarizeResponsesPayload, kt as measureUtf8AppendBytes, lt as enforceCodeModeResponsesToolSurface, mt as resolveOpenAIStrictToolFlagWithDiagnostics, n as applyResponsesServiceTierPricing, ot as buildOpenAIClientHeaders, pt as resolveCodeModeResponsesVisibleToolNames, s as processResponsesStream, st as buildOpenAISdkClientOptions, tt as buildOpenAIResponsesReasoningReplayMetadata, vt as prepareOpenAITools, w as resolveNextResponsesEncryptedContentAttempt, wt as createOpenAIProviderAcceptanceHook, x as createResponsesStreamWithEncryptedContentRetry, xt as reconcileOpenAIResponsesToolChoice, yt as projectOpenAITools, z as responsesInputFingerprint } from "./openai-responses-shared-BMx2NAS-.mjs";
19
20
  import { n as getEnvApiKey } from "./env-api-keys-CyX4VKGO.mjs";
20
21
  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 { a as tagUnresolvedTextAsCommentary, i as tagPendingCommentaryText, n as rememberPendingCommentaryTags, r as tagInterruptedTextPhases, t as clearPendingCommentaryText } from "./assistant-text-phase-DzvV7Oso.mjs";
22
23
  import { t as notifyLlmRequestActivity } from "./llm-request-activity-D8f_oxHj.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 { i as createOpenAIProviderClient, n as resolveProviderSimpleCompletionHeaders, r as resolveProviderTransportTurnState, t as filterProviderTurnHeadersForExplicitOpencodeSession } from "./provider-transport-turn-state-1T3vwTvn.mjs";
26
27
  import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-D9ZmL_s9.mjs";
27
28
  import { f as withPreparedToolSchemaNormalization, r as normalizeOpenAIStrictToolParameters } from "./openai-tool-schema-BIrI0mrA.mjs";
28
29
  import { isGoogleGemini3ThinkingLevelModel } from "./internal/google-model-family.mjs";
29
30
  import { t as mapOpenAIStopReason } from "./openai-stop-reason-8s70vDXj.mjs";
30
31
  import { t as createReasoningTagTextPartitioner } from "./reasoning-tag-text-partitioner-Ju9VpUGl.mjs";
32
+ import { i as resolveAzureDeploymentNameFromMap, t as isOpenAICompatibleAzureResponsesBaseUrl } from "./azure-openai-responses-client-compat-D0dvJMbZ.mjs";
33
+ import { a as applyOpenAIResponsesPayloadPolicy, i as sanitizeResponsesImagePayload, n as isOpenAIResponsesCompactionOutput, s as resolveOpenAIResponsesPayloadPolicy, t as createBoundedOpenAIResponsesCompactionFetch } from "./openai-responses-compaction-window-tA4QkU0o.mjs";
34
+ import { n as supportsNativeOpenAIResponsesEndpoint, t as isOfficialOpenAIResponsesBaseUrl } from "./openai-responses-endpoint-TV0y50fb.mjs";
35
+ import { n as withResponsesRequestAcceptance, r as createResponsesPromptEgressObserver, t as responsesRequestLifecycle } from "./openai-responses-request-lifecycle-Dskvtz_Z.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
  "|",
36
42
  "|",
37
43
  "||"
38
- ].map((bar) => `${bar}DSML${bar}`);
44
+ ].flatMap((bar) => [`${bar}DSML${bar}`, `${bar}DSML${bar} `]);
45
+ const DEEPSEEK_DSML_TOOL_OPEN_TOKENS = DEEPSEEK_DSML_MARKERS.flatMap((marker) => [
46
+ "calls",
47
+ "tool_calls",
48
+ "tool_call",
49
+ "function_calls"
50
+ ].map((kind) => `<${marker}${kind}>`));
39
51
  const DEEPSEEK_DSML_MARKER_PATTERN = `(${DEEPSEEK_DSML_MARKERS.map((marker) => marker.replaceAll("|", "\\|")).join("|")})`;
40
52
  function findEarliestDsmlToken(text, tokens, fromIndex = 0) {
41
53
  let best = null;
@@ -63,13 +75,7 @@ function longestDsmlTokenPrefixSuffixLength(text, tokens, maxTokenLength) {
63
75
  * Removes provider-emitted DSML tool markup while buffering split tag prefixes
64
76
  * across streamed chunks.
65
77
  */
66
- const DSML_KINDS = [
67
- "tool_use_error",
68
- "tool_calls",
69
- "tool_call",
70
- "function_calls"
71
- ];
72
- const DSML_OPEN_TOKENS = DEEPSEEK_DSML_MARKERS.flatMap((marker) => DSML_KINDS.map((kind) => `<${marker}${kind}>`));
78
+ const DSML_OPEN_TOKENS = [...DEEPSEEK_DSML_TOOL_OPEN_TOKENS, ...DEEPSEEK_DSML_MARKERS.map((marker) => `<${marker}tool_use_error>`)];
73
79
  const MAX_OPEN_TOKEN_LEN = Math.max(...DSML_OPEN_TOKENS.map((token) => token.length));
74
80
  /** Create an incremental text filter that strips DeepSeek DSML tool blocks. */
75
81
  function createDeepSeekTextFilter() {
@@ -1126,12 +1132,6 @@ function buildOpenAICompletionsRequest(model, context, options, policy) {
1126
1132
  }
1127
1133
  //#endregion
1128
1134
  //#region packages/ai/src/transports/openai-completions-dsml.ts
1129
- const DEEPSEEK_DSML_TOOL_KINDS = [
1130
- "tool_calls",
1131
- "tool_call",
1132
- "function_calls"
1133
- ];
1134
- const DEEPSEEK_DSML_TOOL_OPEN_TOKENS = DEEPSEEK_DSML_MARKERS.flatMap((marker) => DEEPSEEK_DSML_TOOL_KINDS.map((kind) => `<${marker}${kind}>`));
1135
1135
  const DEEPSEEK_DSML_INVOKE_OPEN_PREFIXES = DEEPSEEK_DSML_MARKERS.map((marker) => `<${marker}invoke`);
1136
1136
  const DEEPSEEK_DSML_INVOKE_OPEN_TAG = new RegExp(`^<${DEEPSEEK_DSML_MARKER_PATTERN}invoke\\b[^<>]*>$`);
1137
1137
  const DEEPSEEK_DSML_TOOL_MAX_OPEN_TOKEN_LEN = Math.max(...DEEPSEEK_DSML_TOOL_OPEN_TOKENS.map((token) => token.length));
@@ -1489,9 +1489,9 @@ async function processCompletionsStream(responseStream, output, model, stream, o
1489
1489
  const emitReasoning = options?.emitReasoning ?? true;
1490
1490
  const compat = getCompat(model);
1491
1491
  const visibleReasoningDetailTypes = new Set(compat.visibleReasoningDetailTypes);
1492
- const shouldFilterDeepSeekDsmlText = !directMode && compat.thinkingFormat === "deepseek";
1492
+ const shouldFilterDeepSeekDsmlText = compat.thinkingFormat === "deepseek";
1493
1493
  const deepSeekTextFilter = shouldFilterDeepSeekDsmlText ? createDeepSeekTextFilter() : null;
1494
- const deepSeekToolCallRecoverer = shouldFilterDeepSeekDsmlText ? createDsmlRecoverer() : null;
1494
+ const deepSeekToolCallRecoverer = !directMode && shouldFilterDeepSeekDsmlText ? createDsmlRecoverer() : null;
1495
1495
  const gemmaToolCallRecoverer = !directMode && /gemma-?4/i.test(model.id) ? createGemmaToolCallRecoverer() : null;
1496
1496
  const reasoningTagTextPartitioner = createReasoningTagTextPartitioner();
1497
1497
  if (options?.strictReasoningTags) reasoningTagTextPartitioner.markStrict();
@@ -1889,6 +1889,1141 @@ function hasOpenAICompletionsReasoningUsageActivity(rawUsage) {
1889
1889
  return typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) && reasoningTokens > 0;
1890
1890
  }
1891
1891
  //#endregion
1892
+ //#region packages/ai/src/providers/openai-web-search-tools.ts
1893
+ function hasResponsesWebSearchTool(tools) {
1894
+ if (!Array.isArray(tools)) return false;
1895
+ return tools.some((tool) => {
1896
+ if (!isRecord(tool)) return false;
1897
+ if (tool.type === "web_search") return true;
1898
+ if (tool.type === "function" && tool.name === "web_search") return true;
1899
+ const fn = tool.function;
1900
+ return isRecord(fn) && fn.name === "web_search";
1901
+ });
1902
+ }
1903
+ //#endregion
1904
+ //#region packages/ai/src/transports/openai-responses-params-internal.ts
1905
+ const OPENAI_RESPONSES_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([
1906
+ "openai",
1907
+ "opencode",
1908
+ "azure-openai-responses",
1909
+ "github-copilot"
1910
+ ]);
1911
+ function raiseMinimalReasoningForResponsesWebSearch(params) {
1912
+ if (params.effort !== "minimal" || !hasResponsesWebSearchTool(params.tools)) return params.effort;
1913
+ for (const effort of [
1914
+ "low",
1915
+ "medium",
1916
+ "high"
1917
+ ]) {
1918
+ const resolved = resolveOpenAIRequestReasoning(params.model, effort).effort;
1919
+ if (resolved && resolved !== "none" && resolved !== "minimal") return resolved;
1920
+ }
1921
+ return params.effort;
1922
+ }
1923
+ const OPENAI_CODEX_RESPONSES_UNSUPPORTED_PARAMS = [
1924
+ "max_output_tokens",
1925
+ "metadata",
1926
+ "prompt_cache_retention",
1927
+ "prompt_cache_options",
1928
+ "service_tier",
1929
+ "temperature",
1930
+ "top_p"
1931
+ ];
1932
+ function stripOpenAICodexResponsesUnsupportedTextFields(params) {
1933
+ const text = params.text;
1934
+ if (!text || typeof text !== "object" || Array.isArray(text)) return;
1935
+ const sanitizedText = { ...text };
1936
+ delete sanitizedText.format;
1937
+ if (Object.keys(sanitizedText).length > 0) params.text = sanitizedText;
1938
+ else delete params.text;
1939
+ }
1940
+ function sanitizeOpenAICodexResponsesParams(model, params) {
1941
+ if (!usesNativeOpenAICodexResponsesBackend(model)) return params;
1942
+ for (const key of OPENAI_CODEX_RESPONSES_UNSUPPORTED_PARAMS) delete params[key];
1943
+ Object.assign(params, { store: false });
1944
+ stripOpenAICodexResponsesUnsupportedTextFields(params);
1945
+ return params;
1946
+ }
1947
+ function buildOpenAIResponsesInstructionsText(context) {
1948
+ if (!context.systemPrompt) return;
1949
+ return sanitizeTransportPayloadText(stripSystemPromptCacheBoundary(context.systemPrompt));
1950
+ }
1951
+ function resolveOpenAIResponsesInstructions(model, context, usesInstructionsField) {
1952
+ if (!usesInstructionsField) return;
1953
+ const instructions = buildOpenAIResponsesInstructionsText(context);
1954
+ if (instructions && instructions.trim().length > 0) return instructions;
1955
+ return usesNativeOpenAICodexResponsesBackend(model) ? OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS : void 0;
1956
+ }
1957
+ function buildOpenAIResponsesCompactSystemMessage(model, instructions) {
1958
+ const compat = getCompat(model);
1959
+ const supportsDeveloperRole = typeof compat.supportsDeveloperRole === "boolean" ? compat.supportsDeveloperRole : void 0;
1960
+ const role = model.reasoning && supportsDeveloperRole !== false ? "developer" : "system";
1961
+ return buildResponsesInputMessage(role, [{
1962
+ type: "input_text",
1963
+ text: instructions
1964
+ }]);
1965
+ }
1966
+ function ensureOpenAIResponsesNonEmptyInput(messages, context) {
1967
+ if (messages.length > 0 || !context.systemPrompt) return;
1968
+ if (!buildOpenAIResponsesInstructionsText(context)) throw new Error("OpenAI Responses requires non-empty input when only systemPrompt is provided.");
1969
+ messages.push(buildResponsesInputMessage("user", [{
1970
+ type: "input_text",
1971
+ text: " "
1972
+ }]));
1973
+ }
1974
+ function buildOpenAIResponsesParams(model, context, options, metadata, replayMode = "checkpoint") {
1975
+ const payloadPolicy = resolveOpenAIResponsesPayloadPolicy(model, { storeMode: "transport-default" });
1976
+ const policyAllowsReplayIds = payloadPolicy.explicitStore !== false && !payloadPolicy.shouldStripStore;
1977
+ const replayResponsesItemIds = !usesNativeOpenAICodexResponsesBackend(model) && (options?.replayResponsesItemIds ?? policyAllowsReplayIds);
1978
+ const messages = convertResponsesMessages(model, context, OPENAI_RESPONSES_TOOL_CALL_PROVIDERS, {
1979
+ includeSystemPrompt: !payloadPolicy.usesInstructionsField,
1980
+ replayReasoningItems: true,
1981
+ replayResponsesItemIds,
1982
+ authProfileId: options?.authProfileId,
1983
+ sessionId: options?.sessionId,
1984
+ replayMode
1985
+ });
1986
+ ensureOpenAIResponsesNonEmptyInput(messages, context);
1987
+ const cacheRetention = resolveCacheRetention(options?.cacheRetention);
1988
+ const compat = getCompat(model);
1989
+ const promptCacheKey = compat.supportsPromptCacheKey ? resolvePromptCacheKey(options, cacheRetention) : void 0;
1990
+ const instructions = resolveOpenAIResponsesInstructions(model, context, payloadPolicy.usesInstructionsField);
1991
+ const params = {
1992
+ model: model.id,
1993
+ input: messages,
1994
+ stream: true,
1995
+ prompt_cache_key: promptCacheKey,
1996
+ ...resolveOpenAIPromptCacheParams(model, cacheRetention, compat),
1997
+ ...instructions ? { instructions } : {},
1998
+ ...metadata ? { metadata } : {}
1999
+ };
2000
+ const effectiveMaxTokens = options?.maxTokens || model.maxTokens;
2001
+ if (effectiveMaxTokens) params.max_output_tokens = Math.max(effectiveMaxTokens, 16);
2002
+ if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
2003
+ if (options?.topP !== void 0 && (!isOpenAIGpt6Model(model) || resolveOpenAIThinkingApi(model.api) === "azure-openai-responses")) params.top_p = options.topP;
2004
+ if (options?.responseFormat !== void 0) params.text = {
2005
+ ...params.text,
2006
+ format: resolveOpenAIResponsesTextFormat(options.responseFormat)
2007
+ };
2008
+ if (options?.serviceTier !== void 0 && payloadPolicy.allowsServiceTier) params.service_tier = options.serviceTier;
2009
+ if (context.tools) {
2010
+ const tools = context.tools;
2011
+ const strict = getAiTransportHost().resolveOpenAIStrictToolSetting(model, {
2012
+ transport: "stream",
2013
+ supportsStrictMode: compat.supportsStrictMode
2014
+ });
2015
+ const { projection, tools: converted } = prepareResponsesTools(tools, strict, model);
2016
+ if (converted.length > 0 || projection.inputToolCount === 0 && projection.diagnostics.length === 0) params.tools = converted;
2017
+ if (options?.toolChoice) {
2018
+ const toolChoice = reconcileOpenAIResponsesToolChoice(options.toolChoice, projection);
2019
+ if (toolChoice !== void 0) params.tool_choice = toolChoice;
2020
+ }
2021
+ }
2022
+ if (model.reasoning) {
2023
+ const reasoning = options?.reasoning;
2024
+ const requestedEffort = options?.reasoningEffort ?? (reasoning === "none" ? "none" : resolveOpenAISimpleReasoningEffort(model, reasoning)) ?? (options?.reasoningSummary ? "high" : payloadPolicy.defaultManagedReasoningEffort);
2025
+ const resolvedEffort = requestedEffort === void 0 ? void 0 : resolveOpenAIRequestReasoning(model, requestedEffort).effort;
2026
+ if (resolvedEffort !== void 0) {
2027
+ const effort = raiseMinimalReasoningForResponsesWebSearch({
2028
+ model,
2029
+ effort: resolvedEffort,
2030
+ tools: params.tools
2031
+ });
2032
+ const summary = effort !== "none" && (options?.reasoningEffort || options?.reasoning || options?.reasoningSummary) ? options.reasoningSummary || "auto" : void 0;
2033
+ params.reasoning = {
2034
+ effort,
2035
+ ...summary ? { summary } : {}
2036
+ };
2037
+ if (summary) params.include = ["reasoning.encrypted_content"];
2038
+ }
2039
+ }
2040
+ applyOpenAIResponsesPayloadPolicy(params, payloadPolicy);
2041
+ return sanitizeOpenAICodexResponsesParams(model, params);
2042
+ }
2043
+ //#endregion
2044
+ //#region packages/ai/src/transports/openai-responses-compact-client.ts
2045
+ async function postOpenAIResponsesCompaction(params) {
2046
+ const instructions = typeof params.request.instructions === "string" && params.request.instructions.length > 0 ? params.request.instructions : void 0;
2047
+ const body = instructions && !supportsNativeOpenAIResponsesEndpoint(params.model) ? {
2048
+ model: params.request.model,
2049
+ input: [buildOpenAIResponsesCompactSystemMessage(params.model, instructions), ...params.request.input ?? []]
2050
+ } : {
2051
+ model: params.request.model,
2052
+ input: params.request.input,
2053
+ ...instructions ? { instructions } : {}
2054
+ };
2055
+ const response = await params.client.post("/responses/compact", {
2056
+ ...buildOpenAISdkRequestOptions(params.model, params.options?.signal, { timeoutMs: params.options?.timeoutMs }),
2057
+ body
2058
+ });
2059
+ const output = isRecord(response) && Array.isArray(response.output) ? response.output : [];
2060
+ const item = output.at(-1);
2061
+ const retainedItems = output.slice(0, -1);
2062
+ const retainedUserMessageCount = retainedItems.filter((candidate) => isRecord(candidate) && candidate.type === "message" && candidate.role === "user" && Array.isArray(candidate.content)).length;
2063
+ const inputUserMessageCount = Array.isArray(params.request.input) ? params.request.input.filter((candidate) => isRecord(candidate) && candidate.type === "message" && candidate.role === "user").length : 0;
2064
+ const retainedMessagePrefixSupported = supportsNativeOpenAIResponsesEndpoint(params.model);
2065
+ const usage = isRecord(response) && isRecord(response.usage) ? response.usage : void 0;
2066
+ 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");
2067
+ return {
2068
+ output,
2069
+ item,
2070
+ historyMode: retainedUserMessageCount > 0 ? "retained-users" : "compacted-prefix",
2071
+ usage,
2072
+ model: params.model,
2073
+ replayMetadata: buildOpenAIResponsesReasoningReplayMetadata(params.model, {
2074
+ authProfileId: params.options?.authProfileId,
2075
+ sessionId: params.options?.sessionId
2076
+ })
2077
+ };
2078
+ }
2079
+ //#endregion
2080
+ //#region packages/ai/src/transports/openai-responses-compact-request.ts
2081
+ const COMPACT_REQUEST = Symbol("openaiResponsesCompactRequest");
2082
+ function claimResponsesCompactRequest(options) {
2083
+ const controller = options ? Reflect.get(options, COMPACT_REQUEST) : void 0;
2084
+ if (controller?.claimed === false) {
2085
+ controller.claimed = true;
2086
+ return controller;
2087
+ }
2088
+ }
2089
+ /** Run a compact-endpoint request through the session's prepared stream stack. */
2090
+ async function requestPreparedOpenAIResponsesCompaction(streamFn, model, context, options) {
2091
+ const preparedOptions = { ...options };
2092
+ let resolveResult;
2093
+ let rejectResult;
2094
+ const result = new Promise((resolve, reject) => {
2095
+ resolveResult = resolve;
2096
+ rejectResult = reject;
2097
+ });
2098
+ const controller = {
2099
+ claimed: false,
2100
+ resolve: resolveResult,
2101
+ reject: rejectResult
2102
+ };
2103
+ Reflect.set(preparedOptions, COMPACT_REQUEST, controller);
2104
+ const stream = await Promise.resolve(streamFn(model, context, preparedOptions));
2105
+ if (!controller.claimed) throw new Error("Prepared stream did not reach an OpenAI Responses transport");
2106
+ try {
2107
+ return await result;
2108
+ } finally {
2109
+ await stream.result().catch(() => void 0);
2110
+ }
2111
+ }
2112
+ //#endregion
2113
+ //#region packages/ai/src/transports/openai-responses-reasoning-state.ts
2114
+ /** Save only admitted settings and hashes, never another copy of the conversation. */
2115
+ function recordResponsesReasoningState(message, model, identity, request, output) {
2116
+ if (!supportsResponsesReasoningUpdate(request) || !isRecord(request.reasoning) || !request.input || request.previous_response_id || message.providerReplay || output.some((item) => isRecord(item) && item.type === "compaction")) return;
2117
+ const reasoning = {
2118
+ ...buildProviderReplayContext(model, identity),
2119
+ effort: request.reasoning.effort,
2120
+ controls: request.input.flatMap((item, index) => isConfigurationUpdate(item) ? [{
2121
+ index,
2122
+ item
2123
+ }] : []),
2124
+ inputLength: request.input.length,
2125
+ outputLength: output.length,
2126
+ prefixHash: responsesContinuationPrefixFingerprint(request.input, output),
2127
+ requestHash: responsesContinuationRequestFingerprint(request)
2128
+ };
2129
+ Object.assign(message, { openclawResponsesInputReplay: {
2130
+ ...readResponsesInputReplayState(message),
2131
+ reasoning
2132
+ } });
2133
+ }
2134
+ /** A cold transport can replay controls, but cannot resurrect a server response handle. */
2135
+ function restoreResponsesReasoningState(context, model, identity, request) {
2136
+ const latest = context.messages.findLast((message) => message.role === "assistant");
2137
+ const state = latest ? readResponsesInputReplayState(latest)?.reasoning : void 0;
2138
+ if (!isRecord(state)) return request;
2139
+ const { effort, inputLength, outputLength, controls, prefixHash, requestHash } = state;
2140
+ 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;
2141
+ const previousInput = request.input.slice(0, inputLength - controls.length);
2142
+ let lastIndex = -1;
2143
+ for (const control of controls) {
2144
+ if (!isRecord(control) || typeof control.index !== "number" || !Number.isSafeInteger(control.index) || control.index <= lastIndex || control.index > previousInput.length || !isConfigurationUpdate(control.item)) return request;
2145
+ previousInput.splice(control.index, 0, control.item);
2146
+ lastIndex = control.index;
2147
+ }
2148
+ const previous = {
2149
+ ...request,
2150
+ reasoning: {
2151
+ ...request.reasoning,
2152
+ effort
2153
+ },
2154
+ input: previousInput
2155
+ };
2156
+ if (responsesContinuationRequestFingerprint(previous) !== requestHash) return request;
2157
+ const prepared = replayResponsesReasoningUpdates(previous, request, outputLength);
2158
+ if (responsesContinuationPrefixFingerprint((prepared.input ?? []).slice(0, inputLength + outputLength)) !== prefixHash) return request;
2159
+ return prepared;
2160
+ }
2161
+ //#endregion
2162
+ //#region packages/ai/src/transports/openai-responses-request-fetch.ts
2163
+ function withDefaultResponsesStreamEncoding(fetch) {
2164
+ return (input, init) => {
2165
+ const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
2166
+ if (headers.has("accept-encoding")) return fetch(input, init);
2167
+ headers.set("accept-encoding", "identity");
2168
+ return fetch(input, {
2169
+ ...init,
2170
+ headers
2171
+ });
2172
+ };
2173
+ }
2174
+ /** Preserve the existing fetch policy while binding explicit continuation dispatch to its signal. */
2175
+ function createResponsesRequestFetch(model, options) {
2176
+ const lifecycle = options.lifecycle;
2177
+ if (lifecycle && options.compact) throw new Error("Provider review continuation cannot replace its reviewed input with compaction");
2178
+ let fetchOverride = options.compact ? createBoundedOpenAIResponsesCompactionFetch(buildGuardedModelFetch(model)) : options.stream ? withDefaultResponsesStreamEncoding(buildGuardedModelFetch(model)) : void 0;
2179
+ if (lifecycle) {
2180
+ const dispatchFetch = fetchOverride ?? buildGuardedModelFetch(model);
2181
+ fetchOverride = async (input, init) => {
2182
+ const signal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
2183
+ await lifecycle.beforeDispatch(signal ?? void 0);
2184
+ signal?.throwIfAborted();
2185
+ lifecycle.assertCurrent();
2186
+ return dispatchFetch(input, init);
2187
+ };
2188
+ }
2189
+ return fetchOverride;
2190
+ }
2191
+ //#endregion
2192
+ //#region packages/ai/src/transports/openai-responses-steering.ts
2193
+ function cloneWireRequest(request) {
2194
+ const serialized = JSON.stringify(request);
2195
+ return JSON.parse(serialized);
2196
+ }
2197
+ async function projectResponsesSteeringInput(request, project) {
2198
+ const { input: activeInput, ...activeSettings } = cloneWireRequest(request);
2199
+ if (!Array.isArray(activeInput)) return [];
2200
+ const { input, ...settings } = cloneWireRequest(await project());
2201
+ if (!Array.isArray(input) || stableStringify(settings) !== stableStringify(activeSettings) || stableStringify(input.slice(0, activeInput.length)) !== stableStringify(activeInput)) return [];
2202
+ const projected = input.slice(activeInput.length);
2203
+ return projected.every((item) => isRecord(item) && item.role === "user") ? projected : [];
2204
+ }
2205
+ /** One response owns admission; accepted input stays on this connection until continuation. */
2206
+ function createResponsesSteering(params) {
2207
+ let responseId;
2208
+ let sealed = false;
2209
+ let unsubscribe;
2210
+ const pending = [];
2211
+ const accepted = /* @__PURE__ */ new Map();
2212
+ const acknowledged = /* @__PURE__ */ new Set();
2213
+ const seal = () => {
2214
+ sealed = true;
2215
+ const cleanup = unsubscribe;
2216
+ unsubscribe = void 0;
2217
+ cleanup?.();
2218
+ };
2219
+ return {
2220
+ get responseId() {
2221
+ return responseId;
2222
+ },
2223
+ get pending() {
2224
+ return pending.length > 0;
2225
+ },
2226
+ get acceptedInput() {
2227
+ return [...accepted.values()].flat();
2228
+ },
2229
+ seal,
2230
+ close(error) {
2231
+ seal();
2232
+ for (const submission of pending.splice(0)) submission.reject(error);
2233
+ },
2234
+ handle(event) {
2235
+ if (!isRecord(event)) return false;
2236
+ if (event.type === "response.created" && !responseId && !sealed) {
2237
+ const response = isRecord(event.response) ? event.response : void 0;
2238
+ if (typeof response?.id !== "string" || !response.id.trim()) throw new Error("Responses steering requires a response identity");
2239
+ const activeResponseId = response.id;
2240
+ responseId = activeResponseId;
2241
+ const cleanup = params.onActiveResponse({
2242
+ needsContinuation: params.needsContinuation,
2243
+ steer(messages) {
2244
+ if (sealed || messages.length === 0) return Promise.resolve(false);
2245
+ params.assertActive();
2246
+ const converted = params.toInput(messages);
2247
+ const submit = (input) => {
2248
+ if (sealed || input.length === 0) return Promise.resolve(false);
2249
+ params.assertActive();
2250
+ return new Promise((resolve, reject) => {
2251
+ pending.push({
2252
+ input,
2253
+ resolve,
2254
+ reject
2255
+ });
2256
+ params.send({
2257
+ type: "response.steer",
2258
+ previous_response_id: activeResponseId,
2259
+ input
2260
+ });
2261
+ });
2262
+ };
2263
+ return Array.isArray(converted) ? submit(converted) : converted.then(submit);
2264
+ }
2265
+ });
2266
+ if (sealed) cleanup?.();
2267
+ else unsubscribe = cleanup;
2268
+ return false;
2269
+ }
2270
+ if (event.type !== "response.steer.accepted" && event.type !== "response.steer.failed" && event.type !== "response.steer.pending") return false;
2271
+ const steer = isRecord(event.steer) ? event.steer : void 0;
2272
+ if (!responseId || steer?.previous_response_id !== responseId) throw new Error("Responses steering acknowledgement has an unexpected identity");
2273
+ if (event.type === "response.steer.failed" && steer.id === void 0) {
2274
+ const index = pending.findIndex((submission) => stableStringify(submission.input) === stableStringify(steer.input));
2275
+ const submission = pending[index];
2276
+ if (!submission) throw new Error("Responses steering acknowledgement has no pending submission");
2277
+ pending.splice(index, 1);
2278
+ submission.resolve(false);
2279
+ return true;
2280
+ }
2281
+ if (typeof steer.id !== "string" || !steer.id.trim()) throw new Error("Responses steering acknowledgement has an unexpected identity");
2282
+ if (event.type === "response.steer.pending") {
2283
+ if (!accepted.has(steer.id)) throw new Error("Responses steering pending event has no accepted submission");
2284
+ return true;
2285
+ }
2286
+ 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");
2287
+ if (acknowledged.has(steer.id)) throw new Error("Responses steering acknowledgement was already applied");
2288
+ const submission = pending.shift();
2289
+ if (!submission) throw new Error("Responses steering acknowledgement has no pending submission");
2290
+ acknowledged.add(steer.id);
2291
+ if (event.type === "response.steer.accepted") {
2292
+ accepted.set(steer.id, submission.input);
2293
+ submission.resolve(true);
2294
+ } else submission.resolve(false);
2295
+ return true;
2296
+ }
2297
+ };
2298
+ }
2299
+ /** Accepted steering is prepended by the server, so never repeat it in response.create. */
2300
+ function omitAcceptedSteering(input, accepted) {
2301
+ const remaining = [...input];
2302
+ for (const message of accepted) {
2303
+ const index = remaining.findIndex((item) => stableStringify(item) === stableStringify(message));
2304
+ if (index < 0) throw new Error("Responses steering continuation no longer contains the accepted user input");
2305
+ remaining.splice(index, 1);
2306
+ }
2307
+ return remaining;
2308
+ }
2309
+ //#endregion
2310
+ //#region packages/ai/src/transports/openai-responses-websocket.ts
2311
+ const SESSION_WEBSOCKET_CACHE_TTL_MS = 3e5;
2312
+ const SESSION_WEBSOCKET_MAX_AGE_MS = 33e5;
2313
+ const WEBSOCKET_OPEN_STATE = 1;
2314
+ const websocketSessionCache = /* @__PURE__ */ new Map();
2315
+ const degradedWebSocketConnections = /* @__PURE__ */ new Map();
2316
+ function closeWebSocketSilently(socket, reason = "done") {
2317
+ try {
2318
+ socket.close({
2319
+ code: 1e3,
2320
+ reason
2321
+ });
2322
+ } catch {}
2323
+ }
2324
+ function invalidateOwnedWebSocketSession(cacheKey, entry, reason = "done") {
2325
+ if (entry.idleTimer) {
2326
+ clearTimeout(entry.idleTimer);
2327
+ entry.idleTimer = void 0;
2328
+ }
2329
+ closeWebSocketSilently(entry.socket, reason);
2330
+ entry.steeringContinuation?.steering.close(/* @__PURE__ */ new Error("Responses steering connection closed"));
2331
+ entry.steeringContinuation?.iterator.return?.().catch(() => void 0);
2332
+ entry.steeringContinuation = void 0;
2333
+ if (websocketSessionCache.get(cacheKey) === entry) websocketSessionCache.delete(cacheKey);
2334
+ }
2335
+ function scheduleSessionWebSocketExpiry(cacheKey, entry) {
2336
+ if (entry.idleTimer) clearTimeout(entry.idleTimer);
2337
+ entry.idleTimer = setTimeout(() => {
2338
+ if (entry.busy) return;
2339
+ invalidateOwnedWebSocketSession(cacheKey, entry, "idle_timeout");
2340
+ }, SESSION_WEBSOCKET_CACHE_TTL_MS);
2341
+ entry.idleTimer.unref?.();
2342
+ }
2343
+ function prepareWebSocketConnection(client, headers) {
2344
+ if (!isOfficialOpenAIResponsesBaseUrl(client.baseURL)) throw new Error("OpenAI Responses WebSocket requires the official API endpoint");
2345
+ if (typeof client.apiKey !== "string" || client.apiKey.length === 0) throw new Error("OpenAI Responses WebSocket requires an API key");
2346
+ const owner = getAiTransportHost();
2347
+ const resolvedApiKey = owner.resolveSecretSentinel(client.apiKey);
2348
+ const resolvedHeaders = { ...resolveAiTransportHeaderSentinels(headers) };
2349
+ for (const key of Object.keys(resolvedHeaders)) {
2350
+ const normalizedKey = key.toLowerCase();
2351
+ if (normalizedKey === "authorization" || normalizedKey === "traceparent") delete resolvedHeaders[key];
2352
+ }
2353
+ if (!resolvedApiKey) throw new Error("OpenAI Responses WebSocket requires a resolved API key");
2354
+ return {
2355
+ client: client.withOptions({ apiKey: resolvedApiKey }),
2356
+ headers: resolvedHeaders,
2357
+ owner,
2358
+ ownerId: getSessionResourceOwnerId(owner),
2359
+ identity: sha256Hex(JSON.stringify([
2360
+ resolvedApiKey,
2361
+ client.baseURL,
2362
+ Object.entries(resolvedHeaders).toSorted(([a], [b]) => a.localeCompare(b))
2363
+ ]))
2364
+ };
2365
+ }
2366
+ function createWebSocket(connection, onError) {
2367
+ const socket = new ResponsesWS(connection.client, {
2368
+ headers: connection.headers,
2369
+ maxQueueSize: 1
2370
+ });
2371
+ socket.on("error", () => onError(socket));
2372
+ return socket;
2373
+ }
2374
+ function createTransientWebSocketLease(connection) {
2375
+ const socket = createWebSocket(connection, (failedSocket) => closeWebSocketSilently(failedSocket, "transport_error"));
2376
+ return {
2377
+ socket,
2378
+ iterator: socket.stream(),
2379
+ reusedConnection: false,
2380
+ release: () => closeWebSocketSilently(socket)
2381
+ };
2382
+ }
2383
+ function createCachedWebSocketLease(cacheKey, entry, reusedConnection) {
2384
+ entry.busy = true;
2385
+ const steeringContinuation = entry.steeringContinuation;
2386
+ entry.steeringContinuation = void 0;
2387
+ return {
2388
+ socket: entry.socket,
2389
+ iterator: steeringContinuation?.iterator ?? entry.socket.stream(),
2390
+ entry,
2391
+ reusedConnection,
2392
+ steeringContinuation,
2393
+ release: ({ keep } = {}) => {
2394
+ if (!keep || entry.socket.socket.readyState !== WEBSOCKET_OPEN_STATE) {
2395
+ invalidateOwnedWebSocketSession(cacheKey, entry);
2396
+ return;
2397
+ }
2398
+ entry.busy = false;
2399
+ scheduleSessionWebSocketExpiry(cacheKey, entry);
2400
+ }
2401
+ };
2402
+ }
2403
+ function acquireWebSocket(params, connection) {
2404
+ if (!(params.mode !== "websocket" && Boolean(params.sessionId)) || !params.sessionId) return createTransientWebSocketLease(connection);
2405
+ const cacheKey = `${connection.ownerId}\0${params.sessionId}\0${connection.identity}`;
2406
+ const cached = websocketSessionCache.get(cacheKey);
2407
+ if (cached) {
2408
+ if (cached.idleTimer) {
2409
+ clearTimeout(cached.idleTimer);
2410
+ cached.idleTimer = void 0;
2411
+ }
2412
+ if (cached.busy) return createTransientWebSocketLease(connection);
2413
+ const expired = Date.now() - cached.createdAt >= SESSION_WEBSOCKET_MAX_AGE_MS;
2414
+ if (!expired && cached.socket.socket.readyState === WEBSOCKET_OPEN_STATE) return createCachedWebSocketLease(cacheKey, cached, true);
2415
+ invalidateOwnedWebSocketSession(cacheKey, cached, expired ? "connection_age_limit" : "done");
2416
+ }
2417
+ const entry = {
2418
+ socket: createWebSocket(connection, (failedSocket) => {
2419
+ const failedEntry = websocketSessionCache.get(cacheKey);
2420
+ if (failedEntry?.socket === failedSocket) invalidateOwnedWebSocketSession(cacheKey, failedEntry, "transport_error");
2421
+ else closeWebSocketSilently(failedSocket, "transport_error");
2422
+ }),
2423
+ sessionId: params.sessionId,
2424
+ owner: connection.owner,
2425
+ busy: true,
2426
+ createdAt: Date.now()
2427
+ };
2428
+ websocketSessionCache.set(cacheKey, entry);
2429
+ return createCachedWebSocketLease(cacheKey, entry, false);
2430
+ }
2431
+ function sanitizeWebSocketRequest(request) {
2432
+ const { stream: _stream, background: _background, ...websocketRequest } = request;
2433
+ return websocketRequest;
2434
+ }
2435
+ async function nextWebSocketMessage(iterator, signal) {
2436
+ if (signal?.aborted) throw transportAbortError(signal);
2437
+ return await racePromiseWithAbortSignal(iterator.next(), signal, transportAbortError);
2438
+ }
2439
+ function readServerEvent(message) {
2440
+ if (message.type === "message") return message.message;
2441
+ if (message.type === "error") throw parseOpenAIResponsesWebSocketServerError(message.error) ?? new Error("OpenAI Responses WebSocket transport failed", { cause: message.error });
2442
+ if (message.type === "close") throw new Error(`OpenAI Responses WebSocket closed before completion (code ${message.code})`);
2443
+ }
2444
+ function createOpenAIResponsesWebSocketStream(params) {
2445
+ const connection = prepareWebSocketConnection(params.client, params.headers);
2446
+ let fullRequest = sanitizeWebSocketRequest(params.request);
2447
+ const requestModel = typeof fullRequest.model === "string" ? fullRequest.model : "";
2448
+ const degradationKey = `${connection.ownerId}\0${params.sessionId ?? ""}\0${connection.identity}\0${requestModel}`;
2449
+ const degraded = degradedWebSocketConnections.get(degradationKey);
2450
+ if (degraded && degraded.retryAt > Date.now()) throw new OpenAIResponsesWebSocketPreDispatchError(/* @__PURE__ */ new Error("OpenAI Responses WebSocket is cooling down after a transport failure"));
2451
+ if (degraded) clearTimeout(degraded.expiryTimer);
2452
+ degradedWebSocketConnections.delete(degradationKey);
2453
+ const markDegraded = () => {
2454
+ const cooldownMs = params.degradeCooldownMs;
2455
+ if (cooldownMs === void 0 || !Number.isFinite(cooldownMs) || cooldownMs <= 0) return;
2456
+ const entry = {
2457
+ sessionId: params.sessionId,
2458
+ owner: connection.owner,
2459
+ retryAt: Date.now() + cooldownMs,
2460
+ expiryTimer: setTimeout(() => {
2461
+ if (degradedWebSocketConnections.get(degradationKey) === entry) degradedWebSocketConnections.delete(degradationKey);
2462
+ }, cooldownMs)
2463
+ };
2464
+ entry.expiryTimer.unref?.();
2465
+ degradedWebSocketConnections.set(degradationKey, entry);
2466
+ };
2467
+ let lease;
2468
+ try {
2469
+ lease = acquireWebSocket(params, connection);
2470
+ } catch (error) {
2471
+ markDegraded();
2472
+ throw new OpenAIResponsesWebSocketPreDispatchError(error);
2473
+ }
2474
+ let prepared;
2475
+ let previousContinuation;
2476
+ const resumedSteering = lease.steeringContinuation;
2477
+ const steeringMode = resumedSteering ? resumedSteering.requiresInput ? "required-input" : "automatic" : void 0;
2478
+ try {
2479
+ const continuation = previousContinuation = lease.entry?.continuation;
2480
+ if (continuation && lease.entry) {
2481
+ lease.entry.continuation = void 0;
2482
+ prepared = resolveResponsesContinuationRequest(continuation, fullRequest, steeringMode);
2483
+ } else {
2484
+ fullRequest = params.restoreRequest?.(fullRequest) ?? fullRequest;
2485
+ prepared = {
2486
+ request: fullRequest,
2487
+ continuationStatus: lease.entry ? "no_previous_response" : "socket_not_cached"
2488
+ };
2489
+ }
2490
+ } catch (error) {
2491
+ lease.iterator.return?.().catch(() => void 0);
2492
+ lease.release({ keep: false });
2493
+ throw error;
2494
+ }
2495
+ let streamStarted = false;
2496
+ let terminalResponse;
2497
+ let terminalReceived = false;
2498
+ let released = false;
2499
+ let retainIterator = false;
2500
+ let deferredInput = false;
2501
+ let inputReplay;
2502
+ if (resumedSteering) try {
2503
+ if (prepared.continuationStatus !== "continued" || !prepared.request.previous_response_id) throw new Error("Responses steering continuation changed its request or history");
2504
+ const input = omitAcceptedSteering(prepared.request.input ?? [], resumedSteering.acceptedInput);
2505
+ 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");
2506
+ const baseline = prepared.fullRequest ?? fullRequest;
2507
+ const priorLength = (baseline.input?.length ?? 0) - (prepared.request.input?.length ?? 0);
2508
+ const fingerprints = input.map(responsesInputFingerprint);
2509
+ if (fingerprints.length > 0) inputReplay = {
2510
+ afterResponseId: prepared.request.previous_response_id,
2511
+ before: resumedSteering.requiresInput ? fingerprints : [],
2512
+ after: resumedSteering.requiresInput ? [] : fingerprints
2513
+ };
2514
+ const delivered = resumedSteering.requiresInput ? input : [];
2515
+ prepared.fullRequest = {
2516
+ ...baseline,
2517
+ input: [
2518
+ ...(baseline.input ?? []).slice(0, priorLength),
2519
+ ...resumedSteering.acceptedInput,
2520
+ ...delivered
2521
+ ]
2522
+ };
2523
+ prepared.request = {
2524
+ ...prepared.request,
2525
+ input: delivered
2526
+ };
2527
+ deferredInput = !resumedSteering.requiresInput && input.length > 0;
2528
+ } catch (error) {
2529
+ lease.iterator.return?.().catch(() => void 0);
2530
+ lease.release({ keep: false });
2531
+ throw new OpenAIResponsesWebSocketPostDispatchError(error);
2532
+ }
2533
+ const steering = lease.entry && params.onActiveResponse && params.steeringInput ? createResponsesSteering({
2534
+ onActiveResponse: params.onActiveResponse,
2535
+ toInput: params.steeringInput,
2536
+ send: (event) => lease.socket.sendRaw(JSON.stringify(event)),
2537
+ needsContinuation: () => deferredInput,
2538
+ assertActive: () => {
2539
+ if (released || terminalReceived || params.signal?.aborted) throw new Error("Responses steering is no longer active");
2540
+ }
2541
+ }) : void 0;
2542
+ const finish = ({ keep = true } = {}) => {
2543
+ if (released) return;
2544
+ released = true;
2545
+ if (keep && lease.entry && terminalResponse) lease.entry.continuation = recordResponsesContinuationState(previousContinuation, prepared.fullRequest ?? fullRequest, terminalResponse, previousContinuation?.lastResponseId === prepared.request.previous_response_id);
2546
+ lease.release({ keep });
2547
+ };
2548
+ return {
2549
+ stream: { async *[Symbol.asyncIterator]() {
2550
+ if (streamStarted) throw new Error("OpenAI Responses WebSocket stream can only be consumed once");
2551
+ streamStarted = true;
2552
+ const iterator = lease.iterator;
2553
+ let requestDispatched = false;
2554
+ try {
2555
+ if (params.signal?.aborted) throw transportAbortError(params.signal);
2556
+ if (resumedSteering) {
2557
+ requestDispatched = true;
2558
+ if (resumedSteering.requiresInput) lease.socket.send({
2559
+ ...prepared.request,
2560
+ type: "response.create"
2561
+ });
2562
+ }
2563
+ for (;;) {
2564
+ const buffered = resumedSteering?.buffered.shift();
2565
+ const next = buffered ? {
2566
+ value: buffered,
2567
+ done: false
2568
+ } : await nextWebSocketMessage(iterator, params.signal);
2569
+ if (next.done) throw new Error("OpenAI Responses WebSocket closed before a terminal response event");
2570
+ if (next.value.type === "open") {
2571
+ if (!requestDispatched) {
2572
+ requestDispatched = true;
2573
+ lease.socket.send({
2574
+ ...prepared.request,
2575
+ type: "response.create"
2576
+ });
2577
+ }
2578
+ continue;
2579
+ }
2580
+ const event = readServerEvent(next.value);
2581
+ if (!event) continue;
2582
+ if (isRecord(event) && typeof event.type === "string" && event.type.startsWith("response.steer.")) {
2583
+ if ((isRecord(event.steer) && event.steer.previous_response_id === steering?.responseId ? steering : resumedSteering?.steering ?? steering)?.handle(event)) continue;
2584
+ }
2585
+ steering?.handle(event);
2586
+ if (event.type === "response.completed") terminalResponse = event.response;
2587
+ terminalReceived = event.type === "response.completed" || event.type === "response.incomplete" || event.type === "response.failed";
2588
+ if (terminalReceived) {
2589
+ steering?.seal();
2590
+ if (event.type === "response.failed") steering?.close(/* @__PURE__ */ new Error("Responses failed before steering could be applied"));
2591
+ const continuationBuffer = [];
2592
+ for (;;) {
2593
+ if (!steering?.pending) break;
2594
+ const acknowledgement = await nextWebSocketMessage(iterator, params.signal);
2595
+ if (acknowledgement.done) throw new Error("Responses closed before acknowledging steering");
2596
+ const acknowledgedEvent = readServerEvent(acknowledgement.value);
2597
+ if (!steering.handle(acknowledgedEvent)) continuationBuffer.push(acknowledgement.value);
2598
+ }
2599
+ const acceptedInput = steering?.acceptedInput ?? [];
2600
+ const isSteered = event.type === "response.incomplete" && isRecord(event.response.incomplete_details) && event.response.incomplete_details.reason === "steered";
2601
+ if (lease.entry && steering && acceptedInput.length > 0 && (event.type === "response.completed" || isSteered)) {
2602
+ if (event.type === "response.incomplete") terminalResponse = event.response;
2603
+ lease.entry.steeringContinuation = {
2604
+ iterator,
2605
+ buffered: continuationBuffer,
2606
+ acceptedInput,
2607
+ requiresInput: (terminalResponse?.output ?? []).some((item) => (item.type === "function_call" || item.type === "custom_tool_call") && !(isRecord(item) && item.async === true) || item.type === "mcp_approval_request"),
2608
+ steering,
2609
+ instructions: fullRequest.instructions,
2610
+ tools: fullRequest.tools
2611
+ };
2612
+ retainIterator = true;
2613
+ if (isSteered) {
2614
+ yield {
2615
+ ...event,
2616
+ type: "response.completed",
2617
+ response: {
2618
+ ...event.response,
2619
+ status: "completed",
2620
+ incomplete_details: null
2621
+ }
2622
+ };
2623
+ return;
2624
+ }
2625
+ }
2626
+ }
2627
+ yield event;
2628
+ if (terminalReceived) {
2629
+ degradedWebSocketConnections.delete(degradationKey);
2630
+ return;
2631
+ }
2632
+ }
2633
+ } catch (error) {
2634
+ const steeringDispatched = Boolean(steering?.pending || steering?.acceptedInput.length || resumedSteering);
2635
+ steering?.close(error instanceof Error ? error : /* @__PURE__ */ new Error("Responses steering failed"));
2636
+ if (lease.entry) lease.entry.continuation = void 0;
2637
+ const safeRetry = error instanceof OpenAIResponsesWebSocketSafeRetryError && !steeringDispatched;
2638
+ if (!params.callerSignal?.aborted && !safeRetry) markDegraded();
2639
+ if (!requestDispatched && !params.signal?.aborted) throw new OpenAIResponsesWebSocketPreDispatchError(error);
2640
+ if (!requestDispatched || params.callerSignal?.aborted || safeRetry) throw error;
2641
+ throw new OpenAIResponsesWebSocketPostDispatchError(error);
2642
+ } finally {
2643
+ steering?.seal();
2644
+ if (!retainIterator) {
2645
+ steering?.close(/* @__PURE__ */ new Error("Responses stream ended before steering was confirmed"));
2646
+ await iterator.return?.().catch(() => void 0);
2647
+ }
2648
+ if (!terminalReceived) finish({ keep: false });
2649
+ }
2650
+ } },
2651
+ request: prepared.request,
2652
+ fullRequest: prepared.fullRequest ?? fullRequest,
2653
+ reusedConnection: lease.reusedConnection,
2654
+ continuationStatus: prepared.continuationStatus,
2655
+ inputReplay,
2656
+ finish
2657
+ };
2658
+ }
2659
+ function closeOpenAIResponsesWebSocketSessions(sessionId, owner) {
2660
+ for (const [cacheKey, entry] of websocketSessionCache) {
2661
+ if (owner && entry.owner !== owner || sessionId && entry.sessionId !== sessionId) continue;
2662
+ invalidateOwnedWebSocketSession(cacheKey, entry, "session_cleanup");
2663
+ }
2664
+ for (const [key, entry] of degradedWebSocketConnections) if ((!owner || entry.owner === owner) && (!sessionId || entry.sessionId === sessionId)) {
2665
+ clearTimeout(entry.expiryTimer);
2666
+ degradedWebSocketConnections.delete(key);
2667
+ }
2668
+ }
2669
+ registerSessionResourceCleanup(closeOpenAIResponsesWebSocketSessions);
2670
+ //#endregion
2671
+ //#region packages/ai/src/transports/openai-responses-client.ts
2672
+ function resolveNativeOpenAIResponsesWebSocketMode(model, transport) {
2673
+ if (transport !== "websocket" && transport !== "websocket-cached" && transport !== "auto") return;
2674
+ if (getAiTransportHost().requiresManagedTransport(model)) return;
2675
+ return supportsNativeOpenAIResponsesEndpoint(model) ? transport : void 0;
2676
+ }
2677
+ function combineWebSocketTimeoutSignal(signal, model, timeoutMs) {
2678
+ const resolvedTimeoutMs = timeoutMs !== void 0 && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : getAiTransportHost().resolveModelRequestTimeoutMs(model);
2679
+ if (resolvedTimeoutMs === void 0 || !Number.isFinite(resolvedTimeoutMs)) return signal;
2680
+ return AbortSignal.any([signal, AbortSignal.timeout(Math.max(1, resolvedTimeoutMs))]);
2681
+ }
2682
+ function createOpenAIResponsesClient(model, apiKey, defaultHeaders, fetchOverride) {
2683
+ return new OpenAI({
2684
+ apiKey,
2685
+ baseURL: resolveOpenAIClientBaseUrl(model),
2686
+ dangerouslyAllowBrowser: true,
2687
+ defaultHeaders,
2688
+ fetch: fetchOverride ?? buildGuardedModelFetch(model),
2689
+ ...buildOpenAISdkClientOptions(model)
2690
+ });
2691
+ }
2692
+ function createResponsesTransportExecutor(config) {
2693
+ return (model, context, options) => {
2694
+ const responsesOptions = options;
2695
+ const compactRequest = claimResponsesCompactRequest(responsesOptions);
2696
+ const { eventStream, stream } = createWritableTransportEventStream();
2697
+ (async () => {
2698
+ const output = createAssistantOutput(model, config.outputApi);
2699
+ let firstEventAbort;
2700
+ let continuationClaim;
2701
+ const requestLifecycle = responsesRequestLifecycle.get(options);
2702
+ try {
2703
+ const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
2704
+ const websocketMode = resolveNativeOpenAIResponsesWebSocketMode(model, responsesOptions?.transport);
2705
+ const encodeBody = prepareModelRequestBody(websocketMode || compactRequest ? void 0 : options);
2706
+ const turnState = resolveProviderTransportTurnState(model, {
2707
+ sessionId: options?.sessionId,
2708
+ turnId: randomUUID(),
2709
+ attempt: 1,
2710
+ transport: websocketMode ? "websocket" : "stream"
2711
+ });
2712
+ const websocketSessionPolicy = websocketMode ? turnState?.websocket : void 0;
2713
+ const httpTurnHeaders = filterProviderTurnHeadersForExplicitOpencodeSession(model, options, turnState?.headers);
2714
+ const websocketTurnHeaders = filterProviderTurnHeadersForExplicitOpencodeSession(model, options, websocketSessionPolicy?.headers);
2715
+ const websocketHeaders = websocketMode ? buildOpenAIClientHeaders(model, context, options?.headers, websocketTurnHeaders, options?.sessionId, options?.cacheRetention) : void 0;
2716
+ const httpHeaders = buildOpenAIClientHeaders(model, context, options?.headers, httpTurnHeaders, options?.sessionId, options?.cacheRetention);
2717
+ const fetchOverride = createResponsesRequestFetch(model, {
2718
+ compact: Boolean(compactRequest),
2719
+ stream: config.streamRequest,
2720
+ lifecycle: requestLifecycle
2721
+ });
2722
+ const client = config.createClient(model, apiKey, httpHeaders, fetchOverride);
2723
+ const nativeAstra = model.id === "gpt-6-astra" && supportsNativeOpenAIResponsesEndpoint(model);
2724
+ const asyncToolExecutionEligible = nativeAstra && options?.asyncToolExecution === true && !responsesOptions?.openclawCodeModeToolSurface;
2725
+ const prepareRequest = async (request) => {
2726
+ let params = request;
2727
+ const nextParams = await options?.onPayload?.(params, model);
2728
+ if (nextParams !== void 0) params = nextParams;
2729
+ params = sanitizeOpenAICodexResponsesParams(model, params);
2730
+ params = sanitizeResponsesImagePayload(params);
2731
+ if (responsesOptions?.openclawCodeModeToolSurface === true) {
2732
+ const visibleToolNames = resolveCodeModeResponsesVisibleToolNames(context);
2733
+ const allowedHostedToolTypes = responsesOptions?.openclawCodeModeAllowedHostedToolTypes;
2734
+ enforceCodeModeResponsesToolSurface(params, visibleToolNames, allowedHostedToolTypes, codeModeToolSurfaceObserver.get(options));
2735
+ assertCodeModeResponsesToolSurface(params, visibleToolNames, allowedHostedToolTypes);
2736
+ }
2737
+ if (asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true && params.tools) params.tools = params.tools.map((tool) => tool.type === "function" ? {
2738
+ ...tool,
2739
+ async: true
2740
+ } : tool);
2741
+ return params;
2742
+ };
2743
+ const buildRequest = (replayMode, requestContext = context) => prepareRequest(config.buildRequest(model, requestContext, responsesOptions, turnState?.metadata, replayMode));
2744
+ let params = await buildRequest("checkpoint");
2745
+ const asyncTools = asyncToolExecutionEligible && params.model === "gpt-6-astra" && params.multi_agent?.enabled !== true;
2746
+ if (compactRequest) {
2747
+ const compacted = await postOpenAIResponsesCompaction({
2748
+ client,
2749
+ model,
2750
+ request: params,
2751
+ options: responsesOptions
2752
+ });
2753
+ output.usage.input = compacted.usage.input_tokens;
2754
+ output.usage.output = compacted.usage.output_tokens;
2755
+ output.usage.totalTokens = compacted.usage.input_tokens + compacted.usage.output_tokens;
2756
+ compactRequest.resolve(compacted);
2757
+ finalizeTransportStream({
2758
+ stream,
2759
+ output,
2760
+ signal: options?.signal
2761
+ });
2762
+ return;
2763
+ }
2764
+ const sessionId = options?.sessionId;
2765
+ if (config.httpContinuation && !websocketMode && !getAiTransportHost().requiresManagedTransport(model) && (supportsNativeOpenAIResponsesEndpoint(model) || resolveOpenAIResponsesPayloadPolicy(model).explicitContinuationOptIn) && sessionId && (params.store === true || supportsResponsesReasoningUpdate(params)) && !params.previous_response_id) {
2766
+ continuationClaim = claimOpenAIResponsesHttpContinuation({
2767
+ sessionId,
2768
+ apiKey,
2769
+ baseUrl: model.baseUrl,
2770
+ headers: httpHeaders,
2771
+ request: params,
2772
+ restoreRequest: () => restoreResponsesReasoningState(context, model, responsesOptions, params)
2773
+ });
2774
+ if (continuationClaim) params = continuationClaim.fullRequest;
2775
+ }
2776
+ const observePrompt = createResponsesPromptEgressObserver(responsesOptions, context.systemPrompt);
2777
+ const requestStartedAt = Date.now();
2778
+ let started = false;
2779
+ const startStream = () => {
2780
+ if (!started) {
2781
+ started = true;
2782
+ stream.push({
2783
+ type: "start",
2784
+ partial: output
2785
+ });
2786
+ }
2787
+ };
2788
+ const firstEvent = createFirstStreamEventAbortController(options?.signal);
2789
+ firstEventAbort = firstEvent;
2790
+ const requestOptions = buildOpenAISdkRequestOptions(model, firstEvent.signal, {
2791
+ stream: config.streamRequest,
2792
+ timeoutMs: options?.timeoutMs
2793
+ });
2794
+ const websocketSignal = combineWebSocketTimeoutSignal(firstEvent.signal, model, requestOptions?.timeout);
2795
+ 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)}`);
2796
+ const responseModelTracker = createResponseModelTracker(isOpenAICodexResponsesModel(model));
2797
+ let continuationBaseline;
2798
+ let dispatchedPreviousResponseId;
2799
+ let contextUsageEligible = true;
2800
+ let requestedTier;
2801
+ const createSseStream = async (initialRequest = continuationClaim?.request ?? params, initialAttemptKind = "initial", initialRejectedCompaction) => {
2802
+ const { stream: responseStream } = await createResponsesStreamWithEncryptedContentRetry({
2803
+ client,
2804
+ request: initialRequest,
2805
+ requestOptions,
2806
+ model,
2807
+ encodeBody,
2808
+ observePrompt,
2809
+ initialAttemptKind,
2810
+ initialRejectedCompaction,
2811
+ buildFullHistoryRequest: () => buildRequest("full-history"),
2812
+ onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, responsesOptions, checkpoint),
2813
+ canRetryStream: () => output.content.length === 0,
2814
+ wrapStream: ({ stream: rawResponseStream, response, attempt }) => {
2815
+ requestedTier = attempt.request.service_tier;
2816
+ contextUsageEligible &&= attempt.kind === "initial";
2817
+ dispatchedPreviousResponseId = attempt.request.previous_response_id;
2818
+ continuationBaseline = attempt.request.previous_response_id ? params : attempt.request;
2819
+ const trackedResponseStream = responseModelTracker.track(response, rawResponseStream);
2820
+ return withProviderResponseHook({
2821
+ stream: observeResponsesStream(trackedResponseStream, model, requestStartedAt),
2822
+ signal: firstEvent.signal,
2823
+ abort: firstEvent.abort,
2824
+ hook: createOpenAIProviderAcceptanceHook(options, response, model),
2825
+ onReady: () => {
2826
+ emitModelTransportDebug(log, `[responses] headers provider=${model.provider} api=${model.api} model=${model.id} transport=sse elapsedMs=${Date.now() - requestStartedAt}`);
2827
+ startStream();
2828
+ }
2829
+ });
2830
+ }
2831
+ });
2832
+ return responseStream;
2833
+ };
2834
+ let responseStream;
2835
+ let websocketBaseline;
2836
+ let finishWebSocket;
2837
+ let transport = "sse";
2838
+ const logWebSocketFallback = (reason) => emitModelTransportDebug(log, `[responses] websocket_fallback provider=${model.provider} api=${model.api} model=${model.id} reason=${reason}`);
2839
+ const closeWebSocketForFallback = (reason) => {
2840
+ finishWebSocket?.({ keep: false });
2841
+ finishWebSocket = void 0;
2842
+ transport = "sse";
2843
+ logWebSocketFallback(reason);
2844
+ };
2845
+ if (websocketMode) try {
2846
+ const websocket = createOpenAIResponsesWebSocketStream({
2847
+ client,
2848
+ request: params,
2849
+ restoreRequest: (request) => restoreResponsesReasoningState(context, model, responsesOptions, request),
2850
+ mode: websocketMode,
2851
+ sessionId: options?.sessionId,
2852
+ headers: websocketHeaders,
2853
+ signal: websocketSignal,
2854
+ callerSignal: options?.signal,
2855
+ degradeCooldownMs: websocketSessionPolicy?.degradeCooldownMs,
2856
+ onActiveResponse: nativeAstra && params.model === "gpt-6-astra" ? options?.onActiveResponse : void 0,
2857
+ steeringInput: (messages) => {
2858
+ contextUsageEligible = false;
2859
+ return projectResponsesSteeringInput(params, () => buildRequest("checkpoint", {
2860
+ ...context,
2861
+ messages: [...context.messages, ...messages]
2862
+ }));
2863
+ }
2864
+ });
2865
+ finishWebSocket = websocket.finish;
2866
+ requestedTier = websocket.request.service_tier;
2867
+ websocketBaseline = websocket.fullRequest;
2868
+ recordResponsesInputReplay(output, websocket.inputReplay);
2869
+ contextUsageEligible &&= websocket.inputReplay === void 0;
2870
+ observePrompt?.(websocket.request, {
2871
+ egress: "responses-websocket",
2872
+ payloadVariant: "initial"
2873
+ });
2874
+ transport = "websocket";
2875
+ 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))))}`);
2876
+ const trackedWebSocketStream = responseModelTracker.track(void 0, websocket.stream);
2877
+ responseStream = { async *[Symbol.asyncIterator]() {
2878
+ let providerAccepted = false;
2879
+ try {
2880
+ for await (const event of trackedWebSocketStream) {
2881
+ if (!providerAccepted) {
2882
+ providerAccepted = true;
2883
+ await notifyProviderStreamOpened({
2884
+ options,
2885
+ cancelStream: () => websocket.finish({ keep: false })
2886
+ });
2887
+ }
2888
+ startStream();
2889
+ yield event;
2890
+ }
2891
+ } catch (error) {
2892
+ if (error instanceof OpenAIResponsesWebSocketSafeRetryError) {
2893
+ const encryptedContentRejected = isInvalidEncryptedContentError(error);
2894
+ const recovery = encryptedContentRejected ? await resolveNextResponsesEncryptedContentAttempt({
2895
+ kind: "initial",
2896
+ request: {
2897
+ ...websocket.request,
2898
+ stream: true
2899
+ }
2900
+ }, error, { buildFullHistoryRequest: () => buildRequest("full-history") }) : void 0;
2901
+ if (encryptedContentRejected && !recovery) throw error;
2902
+ closeWebSocketForFallback(`safe_server_error code=${error.code} status=${safeDebugValue(error.status)} param=${safeDebugValue(error.param)}`);
2903
+ yield* await createSseStream(recovery?.request ?? await buildRequest("full-history"), recovery?.kind ?? "continuation-rejected", recovery?.rejectedCompaction);
2904
+ return;
2905
+ }
2906
+ if (websocketSignal.aborted || !(error instanceof OpenAIResponsesWebSocketPreDispatchError)) throw error;
2907
+ transport = "sse";
2908
+ logWebSocketFallback("before_first_event");
2909
+ yield* await createSseStream();
2910
+ }
2911
+ } };
2912
+ } catch (error) {
2913
+ if (error instanceof OpenAIResponsesWebSocketPostDispatchError) throw error;
2914
+ closeWebSocketForFallback("setup_failure");
2915
+ responseStream = await createSseStream();
2916
+ }
2917
+ else responseStream = await createSseStream();
2918
+ try {
2919
+ const acceptedResponseStream = withResponsesRequestAcceptance(responseStream, requestLifecycle, transport === "websocket" ? websocketSignal : firstEvent.signal);
2920
+ const terminal = await processResponsesStream(acceptedResponseStream, output, stream, model, {
2921
+ canRetryIdentityConflict: () => hasOnlyResponsesFunctionTools(transport === "websocket" ? websocketBaseline : continuationBaseline),
2922
+ ...config.pricingOptions?.(responsesOptions, model),
2923
+ onServiceTier: (responseTier) => responsesServiceTierObserver.observe(options, requestedTier, responseTier),
2924
+ firstEventTimeoutMs: getFirstStreamEventTimeoutMs(options) ?? config.firstEventTimeoutMs,
2925
+ abortFirstEventStream: firstEvent.abort,
2926
+ onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
2927
+ signal: options?.signal,
2928
+ reasoningReplayMetadata: buildOpenAIResponsesReasoningReplayMetadata(model, {
2929
+ authProfileId: responsesOptions?.authProfileId,
2930
+ sessionId: options?.sessionId
2931
+ }),
2932
+ asyncToolExecution: asyncTools,
2933
+ ...responseModelTracker.terminalOptions
2934
+ });
2935
+ finishWebSocket?.();
2936
+ if (options?.signal?.aborted) throw transportAbortError(options.signal);
2937
+ if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
2938
+ const admitted = transport === "websocket" ? websocketBaseline : continuationBaseline;
2939
+ if (terminal && admitted && supportsNativeOpenAIResponsesEndpoint(model)) recordResponsesReasoningState(output, model, responsesOptions, admitted, terminal.output);
2940
+ if (continuationClaim && continuationBaseline && terminal) continuationClaim.commit(continuationBaseline, terminal, dispatchedPreviousResponseId);
2941
+ if (terminal && admitted && contextUsageEligible) recordResponsesContextUsage(output, model, responsesOptions, admitted, terminal.output, "transport");
2942
+ } catch (error) {
2943
+ finishWebSocket?.({ keep: false });
2944
+ throw error;
2945
+ }
2946
+ emitModelTransportDebug(log, `[responses] completed provider=${model.provider} api=${model.api} model=${model.id} transport=${transport} elapsedMs=${Date.now() - requestStartedAt}`);
2947
+ finalizeTransportStream({
2948
+ stream,
2949
+ output,
2950
+ signal: options?.signal
2951
+ });
2952
+ } catch (error) {
2953
+ if (requestLifecycle) await requestLifecycle.settle().catch(() => void 0);
2954
+ if (compactRequest) {
2955
+ compactRequest.reject(error);
2956
+ failTransportStream({
2957
+ stream,
2958
+ output,
2959
+ signal: options?.signal,
2960
+ error
2961
+ });
2962
+ return;
2963
+ }
2964
+ if (error instanceof ResponsesStreamFailure && error.observation) logResponsesFailedNoDetails(error.observation);
2965
+ const incompleteReason = output.diagnostics?.find(({ type }) => type === "openai_responses_terminal")?.details?.incompleteReason;
2966
+ log.warn(`[responses] error provider=${model.provider} api=${model.api} model=${model.id} ` + summarizeOpenAITransportError(error) + (typeof incompleteReason === "string" ? ` incompleteReason=${incompleteReason}` : ""));
2967
+ failTransportStream({
2968
+ stream,
2969
+ output,
2970
+ signal: options?.signal,
2971
+ error
2972
+ });
2973
+ } finally {
2974
+ continuationClaim?.release();
2975
+ firstEventAbort?.dispose();
2976
+ }
2977
+ })();
2978
+ return eventStream;
2979
+ };
2980
+ }
2981
+ function createOpenAIResponsesTransportStreamFn() {
2982
+ return createResponsesTransportExecutor({
2983
+ streamRequest: true,
2984
+ httpContinuation: true,
2985
+ createClient: createOpenAIResponsesClient,
2986
+ buildRequest: buildOpenAIResponsesParams,
2987
+ pricingOptions: (options, model) => ({
2988
+ serviceTier: options?.serviceTier,
2989
+ applyServiceTierPricing: (usage, serviceTier) => applyResponsesServiceTierPricing(usage, serviceTier, model)
2990
+ })
2991
+ });
2992
+ }
2993
+ function createAzureOpenAIResponsesTransportStreamFn() {
2994
+ return createResponsesTransportExecutor({
2995
+ outputApi: "azure-openai-responses",
2996
+ firstEventTimeoutMs: AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS,
2997
+ createClient: createAzureOpenAIClient,
2998
+ buildRequest: (model, context, options, metadata, replayMode) => {
2999
+ const deploymentName = resolveAzureDeploymentNameFromMap({
3000
+ modelId: model.id,
3001
+ deploymentMap: process.env.AZURE_OPENAI_DEPLOYMENT_NAME_MAP
3002
+ });
3003
+ const params = buildOpenAIResponsesParams(model, context, options, metadata, replayMode);
3004
+ params.model = deploymentName;
3005
+ delete params.store;
3006
+ return params;
3007
+ }
3008
+ });
3009
+ }
3010
+ function createAzureOpenAIClient(model, apiKey, defaultHeaders, fetchOverride) {
3011
+ const baseURL = model.baseUrl.replace(/\/+$/, "");
3012
+ const clientOptions = {
3013
+ apiKey,
3014
+ dangerouslyAllowBrowser: true,
3015
+ defaultHeaders,
3016
+ baseURL,
3017
+ fetch: fetchOverride ?? buildGuardedModelFetch(model),
3018
+ ...buildOpenAISdkClientOptions(model)
3019
+ };
3020
+ if (isOpenAICompatibleAzureResponsesBaseUrl(baseURL)) return new OpenAI(clientOptions);
3021
+ return new AzureOpenAI({
3022
+ ...clientOptions,
3023
+ apiVersion: resolveAzureOpenAIApiVersion()
3024
+ });
3025
+ }
3026
+ //#endregion
1892
3027
  //#region packages/ai/src/transports/openai-completions-transport.ts
1893
3028
  function assertOpenAICompletionsPayloadHasConversationTurn(params, model) {
1894
3029
  const messages = params.messages;
@@ -2010,7 +3145,23 @@ function createDirectCompletionsEventStream(output, stream) {
2010
3145
  };
2011
3146
  }
2012
3147
  function createOpenAICompletionsTransportStreamFn() {
2013
- return (model, context, options) => streamOpenAICompletionsRequest(model, context, options, "managed");
3148
+ const streamResponses = createOpenAIResponsesTransportStreamFn();
3149
+ return (model, context, options) => {
3150
+ const completionsOptions = options;
3151
+ if (model.reasoning && context.tools?.length && supportsModelTools(model) && isNativeOpenAIEndpoint(model)) {
3152
+ const toolChoice = completionsOptions?.toolChoice;
3153
+ const responsesOptions = {
3154
+ ...options,
3155
+ ...completionsOptions?.reasoning === void 0 && completionsOptions?.reasoningEffort === void 0 ? { reasoningEffort: "high" } : {},
3156
+ ...toolChoice && typeof toolChoice === "object" ? { toolChoice: toOpenAIResponsesToolChoice(toolChoice) } : {}
3157
+ };
3158
+ return streamResponses(getAiTransportHost().inheritManagedTransport(model, {
3159
+ ...model,
3160
+ api: "openai-responses"
3161
+ }), context, responsesOptions);
3162
+ }
3163
+ return streamOpenAICompletionsRequest(model, context, completionsOptions, "managed");
3164
+ };
2014
3165
  }
2015
3166
  function streamOpenAICompletionsRequest(model, context, options, mode) {
2016
3167
  const { eventStream, stream } = createWritableTransportEventStream();
@@ -2181,4 +3332,4 @@ function createManagedCompletionsClient(model, context, options, apiKey, cacheRe
2181
3332
  };
2182
3333
  }
2183
3334
  //#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 };
3335
+ 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 };