@openclaw/ai 2026.10.3 → 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.
- package/dist/{anthropic-C4qygbtf.mjs → anthropic-DloU96D6.mjs} +2 -2
- package/dist/{anthropic-stream-reducer-CWyWE21W.mjs → anthropic-stream-reducer-Djl4yqrc.mjs} +2 -3
- package/dist/{assistant-text-phase-DVZOxbuR.mjs → assistant-text-phase-DzvV7Oso.mjs} +1 -1
- package/dist/{azure-openai-responses-DO-Fv8ha.mjs → azure-openai-responses-CAyTrcy6.mjs} +1 -2
- package/dist/internal/anthropic.mjs +2 -2
- package/dist/internal/openai.mjs +5 -7
- package/dist/{openai-chatgpt-responses-Cq3Igfi3.mjs → openai-chatgpt-responses-vk4XdUjX.mjs} +3 -5
- package/dist/{openai-completions-BxQw4S-A.mjs → openai-completions-XvUwdvJc.mjs} +1 -1
- package/dist/{openai-completions-transport-D_ZhLzh_.mjs → openai-completions-transport-QYABn8Uz.mjs} +1170 -13
- package/dist/{openai-responses-BhAZFsL9.mjs → openai-responses-DNWY56mK.mjs} +2 -3
- package/dist/{openai-responses-prompt-observer-internal-CefUzh8M.mjs → openai-responses-request-lifecycle-Dskvtz_Z.mjs} +36 -1
- package/dist/{openai-responses-shared-CKNmC3vC.mjs → openai-responses-shared-BMx2NAS-.mjs} +805 -67
- package/dist/{provider-transport-turn-state-BX6TfCyW.mjs → provider-transport-turn-state-1T3vwTvn.mjs} +1 -1
- package/dist/providers.mjs +5 -5
- package/dist/{text-signature-D_vRrx-z.mjs → text-signature-CbqxIB8B.mjs} +25 -2
- package/dist/transports.mjs +11 -1148
- package/package.json +1 -1
- package/dist/openai-responses-request-lifecycle-Fsag-IGZ.mjs +0 -36
- package/dist/openai-transport-params-D7JMUPjf.mjs +0 -735
- package/dist/openai-web-search-tools-Cfu0uLyN.mjs +0 -14
- package/dist/provider-replay-context-CO_Eplnc.mjs +0 -25
package/dist/{openai-completions-transport-D_ZhLzh_.mjs → openai-completions-transport-QYABn8Uz.mjs}
RENAMED
|
@@ -3,33 +3,39 @@ 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 {
|
|
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 {
|
|
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
|
|
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-
|
|
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-
|
|
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
|
"|",
|
|
@@ -1883,6 +1889,1141 @@ function hasOpenAICompletionsReasoningUsageActivity(rawUsage) {
|
|
|
1883
1889
|
return typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) && reasoningTokens > 0;
|
|
1884
1890
|
}
|
|
1885
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
|
|
1886
3027
|
//#region packages/ai/src/transports/openai-completions-transport.ts
|
|
1887
3028
|
function assertOpenAICompletionsPayloadHasConversationTurn(params, model) {
|
|
1888
3029
|
const messages = params.messages;
|
|
@@ -2004,7 +3145,23 @@ function createDirectCompletionsEventStream(output, stream) {
|
|
|
2004
3145
|
};
|
|
2005
3146
|
}
|
|
2006
3147
|
function createOpenAICompletionsTransportStreamFn() {
|
|
2007
|
-
|
|
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
|
+
};
|
|
2008
3165
|
}
|
|
2009
3166
|
function streamOpenAICompletionsRequest(model, context, options, mode) {
|
|
2010
3167
|
const { eventStream, stream } = createWritableTransportEventStream();
|
|
@@ -2175,4 +3332,4 @@ function createManagedCompletionsClient(model, context, options, apiKey, cacheRe
|
|
|
2175
3332
|
};
|
|
2176
3333
|
}
|
|
2177
3334
|
//#endregion
|
|
2178
|
-
export {
|
|
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 };
|