@xiaoso/dsh-tool-plus 0.1.0-beta.2 → 0.1.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +122 -0
- package/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +4 -35
- package/lib/abort-B7izMMna.mjs +51 -0
- package/lib/amazon-bedrock-D-shAr1X.mjs +917 -0
- package/lib/anthropic-BWsZFzU8.mjs +262 -0
- package/lib/anthropic-CMT1Qj1t.mjs +3115 -0
- package/lib/api-key-login-CpzSezsi.mjs +157 -0
- package/lib/aws-credentials-8Mgn5MAy.mjs +867 -0
- package/lib/azure-openai-responses-CNkHiLUh.mjs +274 -0
- package/lib/bun-shim.mjs +172 -7
- package/lib/bundled-references-CSuBco5p.mjs +55 -0
- package/lib/callback-server-BEFNf-jf.mjs +398 -0
- package/lib/client.js +110 -40
- package/lib/cursor-BIQfBC6V.mjs +135 -0
- package/lib/cursor-DNk6eXDd.mjs +5470 -0
- package/lib/cursor-MjSm74IJ.mjs +273 -0
- package/lib/device-code-OI_tQcmc.mjs +51 -0
- package/lib/devin-CldyPD8K.mjs +95 -0
- package/lib/devin-CzRpTUOA.mjs +114 -0
- package/lib/devin-DXOeNyU7.mjs +542 -0
- package/lib/error-B3bevhrs.mjs +1449 -0
- package/lib/event-stream-BDPi64mK.mjs +151 -0
- package/lib/github-copilot-4GaMtQmg.mjs +208 -0
- package/lib/github-copilot-B2HGSIJK.mjs +104 -0
- package/lib/gitlab-duo-akICyfeD.mjs +155 -0
- package/lib/gitlab-duo-workflow-CSEgYk3N.mjs +91 -0
- package/lib/google-antigravity-Dlkdhahq.mjs +198 -0
- package/lib/google-auth-DhqpOYrX.mjs +232 -0
- package/lib/google-gemini-cli-BG_LRdIV.mjs +850 -0
- package/lib/google-gemini-cli-zJhiOcND.mjs +211 -0
- package/lib/google-oauth-shared-CwNWYdmR.mjs +147 -0
- package/lib/google-shared-DzhCb9b0.mjs +760 -0
- package/lib/google-vertex-kscbkyRb.mjs +99 -0
- package/lib/google-zyDOG9x7.mjs +30 -0
- package/lib/identity-DnB63pS7.mjs +219 -0
- package/lib/idle-iterator-C6XbWcuB.mjs +366 -0
- package/lib/index.mjs +2865 -2745
- package/lib/kimi-DMVI-zrZ.mjs +236 -0
- package/lib/markit-M0jhziqU.mjs +1417 -0
- package/lib/minimax-code-BK-3eBbz.mjs +53 -0
- package/lib/models-CfT4coYT.mjs +104660 -0
- package/lib/ollama-BQMGPxtV.mjs +589 -0
- package/lib/openai-codex-CQL_kvYL.mjs +255 -0
- package/lib/openai-codex-responses-Cz-2qpC7.mjs +3144 -0
- package/lib/openai-completions-i8doczAk.mjs +1360 -0
- package/lib/openai-reasoning-fallback-DGVVLgd1.mjs +286 -0
- package/lib/openai-responses-DTkBiiy-.mjs +867 -0
- package/lib/opencode-DaJjcUbf.mjs +38 -0
- package/lib/perplexity-9b-RQ0mV.mjs +194 -0
- package/lib/proxy-ZtUcl6r5.mjs +190 -0
- package/lib/scrapers-CL-WgdU1.mjs +9198 -0
- package/lib/scrapers-CipyKyCH.mjs +9198 -0
- package/lib/scrapers-DGfrYhtw.mjs +9198 -0
- package/lib/scrapers-DSUPYoUF.mjs +9198 -0
- package/lib/scrapers-DZ2GXmp7.mjs +9198 -0
- package/lib/src-DTid0g4K.mjs +5001 -0
- package/lib/stream-C_RAoxJC.mjs +10236 -0
- package/lib/stream-markup-healing-2toHXWXM.mjs +491 -0
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/config/fields.d.ts +1 -1
- package/lib/types/config/settings.d.ts +16 -2
- package/lib/types/tools/omp/sdk.d.ts +6 -0
- package/lib/types/tools/omp/tools/fetch.d.ts +2 -0
- package/lib/types/tools/omp/tools/read.d.ts +2 -8
- package/lib/types/tools/omp/utils/image-loading.d.ts +10 -36
- package/lib/types/tools/read/adapter/index.d.ts +4 -1
- package/lib/types/tools/read-image/index.d.ts +4 -0
- package/lib/types/tools/shared/bun-shim.d.ts +35 -3
- package/lib/types/tools/shared/image-bridge.d.ts +98 -0
- package/lib/types/tools/shared/omp-prompt.d.ts +4 -2
- package/lib/utils-2Wq2eATG.mjs +8119 -0
- package/lib/utils-BnX8O3vi.mjs +12303 -0
- package/lib/utils-CE8N8P4Q.mjs +12315 -0
- package/lib/utils-C_MrQ_0z.mjs +12301 -0
- package/lib/utils-D0Z1fyoO.mjs +12299 -0
- package/lib/utils-DppGHXQB.mjs +51 -0
- package/lib/utils-W8WdSBpX.mjs +12315 -0
- package/lib/vision-guard-BDD4OrKo.mjs +92 -0
- package/lib/wafer-DRU0EjZX.mjs +17 -0
- package/lib/xai-oauth-DPHDXKD7.mjs +446 -0
- package/lib/xiaomi-Dd87KSg5.mjs +157 -0
- package/lib/zai-CFeOt-53.mjs +203 -0
- package/lib/zip-D6QXpvaJ.mjs +1316 -0
- package/package.json +14 -10
- package/presets/package.json +1 -1
- package/presets/tool-plus-ptc/preset.yml +1 -1
- package/presets/tool-plus-standard/preset.yml +1 -1
|
@@ -0,0 +1,867 @@
|
|
|
1
|
+
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
|
+
__installBunShim();
|
|
3
|
+
import { r as __exportAll } from "./fs-promises-shim-B-9cMxz5.mjs";
|
|
4
|
+
import { I as $flag, S as debug, T as warn, t as structuredCloneJSON } from "./src-DTid0g4K.mjs";
|
|
5
|
+
import { A as isTransientStreamParseError, B as OpenAIHttpError, d as callWithCopilotModelRetry, l as finalize, n as StreamTimeoutError, s as ProviderResponseError, t as ConfigurationError, v as AbortError } from "./error-B3bevhrs.mjs";
|
|
6
|
+
import { A as NO_STRICT, L as sanitizeSchemaForOpenAIResponses, O as flattenExclusiveRequiredRootUnion, P as normalizeSchemaForMoonshot, a as normalizeSystemPrompts, j as adaptSchemaForStrict, k as toolWireSchema, l as sanitizeOpenAIResponsesAssistantHistoryItemsForReplay, s as resolveCacheRetention, t as createOpenAIResponsesHistoryPayload } from "./utils-2Wq2eATG.mjs";
|
|
7
|
+
import { $ as isOpenRouterAnthropicModel, Ct as withEmptyCompletionRetry, D as buildResponsesInput, E as buildResponsesDeltaInput, G as getJuiceValue, I as disableStrictToolsForScope, J as getOpenAIStrictToolsScope, K as getOpenAIPromptCacheKey, N as createInitialResponsesAssistantMessage, P as createOpenAIStrictToolsState, Q as isOpenAIResponsesProgressEvent, S as applyResponsesCompatPolicy, T as applyWireModelIdTransform, Y as getOpenRouterResponsesSessionId, Z as isCompiledGrammarTooLargeStrictError, _ as applyOpenAIExtraBody, _t as isForcedToolChoice, ct as resolveOpenAICompatPolicy, dt as resolveOpenAIRequestSetup, et as isStrictToolsDisabledForScope, ft as resolveOpenAIResponsesOutputClamp, g as applyCommonResponsesSamplingParams, k as clearOpenAIStrictToolsState, n as getEnvApiKey, ot as processResponsesStream, pt as shouldRetryWithoutStrictTools, q as getOpenAIResponsesRoutingSessionId, ut as resolveOpenAIOutputTokenParam, v as applyOpenAIGatewayRouting, w as applyVercelResponsesCacheControls, yt as mapToOpenAIResponsesToolChoice } from "./stream-C_RAoxJC.mjs";
|
|
8
|
+
import { t as createAbortSourceTracker } from "./abort-B7izMMna.mjs";
|
|
9
|
+
import { A as semverGte, D as bareModelId, j as hostMatchesUrl, k as parseOpenAIModel } from "./models-CfT4coYT.mjs";
|
|
10
|
+
import "./identity-DnB63pS7.mjs";
|
|
11
|
+
import { t as findStrictToolSchemaViolation } from "./strict-tool-validation-imVLUcbI.mjs";
|
|
12
|
+
import { t as AssistantMessageEventStream } from "./event-stream-BDPi64mK.mjs";
|
|
13
|
+
import { n as getOpenAIStreamFirstEventTimeoutMs, o as iterateWithIdleTimeout, r as getOpenAIStreamIdleTimeoutMs } from "./idle-iterator-C6XbWcuB.mjs";
|
|
14
|
+
import { t as notifyProviderResponse } from "./provider-response-C6vcbQyO.mjs";
|
|
15
|
+
import { t as compactGrammarDefinition } from "./grammar-D-NqNUxQ.mjs";
|
|
16
|
+
import { a as getOpenAIReasoningEffortFallback, c as postOpenAIStream, i as createOpenAIReasoningEffortFallbackState, n as clearOpenAIReasoningEffortFallbackState, o as rememberOpenAIReasoningEffortFallback, r as createOpenAIReasoningEffortFallbackKey, s as resolveOpenAIReasoningEffortFallback, t as applyOpenAIReasoningEffortFallback } from "./openai-reasoning-fallback-DGVVLgd1.mjs";
|
|
17
|
+
import { scheduler } from "node:timers/promises";
|
|
18
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/openai-responses.ts
|
|
19
|
+
var openai_responses_exports = /* @__PURE__ */ __exportAll({
|
|
20
|
+
buildParams: () => buildParams,
|
|
21
|
+
convertTools: () => convertTools,
|
|
22
|
+
mapOpenAIResponsesToolChoiceForTools: () => mapOpenAIResponsesToolChoiceForTools,
|
|
23
|
+
streamOpenAIResponses: () => streamOpenAIResponses,
|
|
24
|
+
supportsFreeformApplyPatch: () => supportsFreeformApplyPatch
|
|
25
|
+
});
|
|
26
|
+
const OPENAI_RESPONSES_PROVIDER_SESSION_STATE_PREFIX = "openai-responses:";
|
|
27
|
+
const OPENAI_RESPONSES_FIRST_EVENT_TIMEOUT_MESSAGE = "OpenAI responses stream timed out while waiting for the first event";
|
|
28
|
+
/** Consecutive stale-previous-response failures before chaining is disabled for the session. */
|
|
29
|
+
const OPENAI_RESPONSES_CHAIN_STALE_FAILURE_LIMIT = 3;
|
|
30
|
+
const OPENAI_RESPONSES_MAX_TRANSIENT_STREAM_RETRIES = 1;
|
|
31
|
+
const OPENAI_RESPONSES_TRANSIENT_STREAM_RETRY_DELAY_MS = 500;
|
|
32
|
+
function isOpenAIResponsesReplayUnsafeEvent(event) {
|
|
33
|
+
switch (event.type) {
|
|
34
|
+
case "response.output_text.delta":
|
|
35
|
+
case "response.refusal.delta":
|
|
36
|
+
case "response.reasoning_summary_text.delta":
|
|
37
|
+
case "response.reasoning_text.delta":
|
|
38
|
+
case "response.function_call_arguments.delta":
|
|
39
|
+
case "response.custom_tool_call_input.delta": return typeof event.delta === "string" && event.delta.length > 0;
|
|
40
|
+
case "response.reasoning_summary_part.done": return true;
|
|
41
|
+
case "response.output_item.done": return true;
|
|
42
|
+
default: return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function isRetryableOpenAIResponsesStreamFailure(error) {
|
|
46
|
+
return isTransientStreamParseError(error) || error instanceof ProviderResponseError && error.kind === "incomplete-stream";
|
|
47
|
+
}
|
|
48
|
+
function createOpenAIResponsesProviderSessionState() {
|
|
49
|
+
const strictToolsState = createOpenAIStrictToolsState();
|
|
50
|
+
const reasoningEffortFallbackState = createOpenAIReasoningEffortFallbackState();
|
|
51
|
+
const state = {
|
|
52
|
+
...strictToolsState,
|
|
53
|
+
...reasoningEffortFallbackState,
|
|
54
|
+
nativeHistoryReplayWarmed: false,
|
|
55
|
+
chains: /* @__PURE__ */ new Map(),
|
|
56
|
+
close: () => {
|
|
57
|
+
state.nativeHistoryReplayWarmed = false;
|
|
58
|
+
state.chains.clear();
|
|
59
|
+
clearOpenAIStrictToolsState(state);
|
|
60
|
+
clearOpenAIReasoningEffortFallbackState(state);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
return state;
|
|
64
|
+
}
|
|
65
|
+
function getOpenAIResponsesProviderSessionState(model, providerSessionState) {
|
|
66
|
+
if (!providerSessionState) return void 0;
|
|
67
|
+
const key = `${OPENAI_RESPONSES_PROVIDER_SESSION_STATE_PREFIX}${model.provider}`;
|
|
68
|
+
const existing = providerSessionState.get(key);
|
|
69
|
+
if (existing) return existing;
|
|
70
|
+
const created = createOpenAIResponsesProviderSessionState();
|
|
71
|
+
providerSessionState.set(key, created);
|
|
72
|
+
return created;
|
|
73
|
+
}
|
|
74
|
+
function isOpenAIResponsesStatefulEnabled(options, baseUrl) {
|
|
75
|
+
if (options?.statefulResponses === false) return false;
|
|
76
|
+
if (options?.statefulResponses === true) return true;
|
|
77
|
+
return $flag("PI_OPENAI_STATEFUL", !baseUrl || hostMatchesUrl(baseUrl, "openai"));
|
|
78
|
+
}
|
|
79
|
+
function getOpenAIResponsesChainState(providerSessionState, model, resolvedBaseUrl, sessionId) {
|
|
80
|
+
const key = `${resolvedBaseUrl ?? model.baseUrl ?? ""}\u0000${model.id}\u0000${sessionId}`;
|
|
81
|
+
const existing = providerSessionState.chains.get(key);
|
|
82
|
+
if (existing) return existing;
|
|
83
|
+
const created = {
|
|
84
|
+
canAppend: false,
|
|
85
|
+
staleFailures: 0,
|
|
86
|
+
disabled: false
|
|
87
|
+
};
|
|
88
|
+
providerSessionState.chains.set(key, created);
|
|
89
|
+
return created;
|
|
90
|
+
}
|
|
91
|
+
function resetOpenAIResponsesChainState(state) {
|
|
92
|
+
state.canAppend = false;
|
|
93
|
+
state.lastParams = void 0;
|
|
94
|
+
state.lastResponseId = void 0;
|
|
95
|
+
state.lastResponseItems = void 0;
|
|
96
|
+
state.lastPromptCacheBreakpointPolicy = void 0;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Shape the next turn's request: when the session's append baseline is intact
|
|
100
|
+
* (same options, strict history prefix), chain via `previous_response_id` +
|
|
101
|
+
* delta-only `input`; otherwise break the chain and replay the full transcript.
|
|
102
|
+
*
|
|
103
|
+
* The prefix check runs on the wire form of the conversation arguments, so
|
|
104
|
+
* history mutations or option changes force a full replay.
|
|
105
|
+
*/
|
|
106
|
+
function buildOpenAIResponsesChainedParams(params, trailingScaffoldingItems, chain) {
|
|
107
|
+
const historyParams = trailingScaffoldingItems > 0 && Array.isArray(params.input) ? {
|
|
108
|
+
...params,
|
|
109
|
+
input: params.input.slice(0, params.input.length - trailingScaffoldingItems)
|
|
110
|
+
} : params;
|
|
111
|
+
const deltaInput = chain.canAppend ? buildResponsesDeltaInput(chain.lastParams, chain.lastResponseItems, historyParams) : null;
|
|
112
|
+
if (deltaInput && deltaInput.length > 0 && chain.lastResponseId) {
|
|
113
|
+
const scaffolding = historyParams !== params && Array.isArray(params.input) ? params.input.slice(params.input.length - trailingScaffoldingItems) : [];
|
|
114
|
+
return {
|
|
115
|
+
params: {
|
|
116
|
+
...params,
|
|
117
|
+
previous_response_id: chain.lastResponseId,
|
|
118
|
+
input: [...deltaInput, ...scaffolding]
|
|
119
|
+
},
|
|
120
|
+
previousResponseId: chain.lastResponseId
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (chain.canAppend) resetOpenAIResponsesChainState(chain);
|
|
124
|
+
return { params };
|
|
125
|
+
}
|
|
126
|
+
function isOpenAIResponsesStalePreviousResponseError(error) {
|
|
127
|
+
if (!(error instanceof Error)) return false;
|
|
128
|
+
if (error.code === "previous_response_not_found") return true;
|
|
129
|
+
return /previous[ _]?response/i.test(error.message) && /not[ _]?found|invalid|expired|stale|unsupported/i.test(error.message);
|
|
130
|
+
}
|
|
131
|
+
function registerOpenAIResponsesChainStaleFailure(chain, error) {
|
|
132
|
+
resetOpenAIResponsesChainState(chain);
|
|
133
|
+
chain.staleFailures += 1;
|
|
134
|
+
if (chain.staleFailures >= OPENAI_RESPONSES_CHAIN_STALE_FAILURE_LIMIT) chain.disabled = true;
|
|
135
|
+
debug("OpenAI responses previous_response_id rejected; falling back to full context", {
|
|
136
|
+
error: error instanceof Error ? error.message : String(error),
|
|
137
|
+
consecutiveFailures: chain.staleFailures,
|
|
138
|
+
disabled: chain.disabled
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* One-shot ZDR signal: the org will never resolve a stored response, so skip
|
|
143
|
+
* the staleFailures counter and disable chaining immediately for this session.
|
|
144
|
+
*/
|
|
145
|
+
function markOpenAIResponsesChainZeroDataRetention(chain, error) {
|
|
146
|
+
resetOpenAIResponsesChainState(chain);
|
|
147
|
+
chain.disabled = true;
|
|
148
|
+
chain.staleFailures = OPENAI_RESPONSES_CHAIN_STALE_FAILURE_LIMIT;
|
|
149
|
+
debug("OpenAI responses chaining disabled (Zero Data Retention)", { error: error instanceof Error ? error.message : String(error) });
|
|
150
|
+
}
|
|
151
|
+
function maybeAddOpenRouterAnthropicCacheControl(params, model, cacheRetention) {
|
|
152
|
+
if (cacheRetention === "none" || !isOpenRouterAnthropicModel(model)) return;
|
|
153
|
+
if (params.cache_control != null) return;
|
|
154
|
+
params.cache_control = cacheRetention === "long" ? {
|
|
155
|
+
type: "ephemeral",
|
|
156
|
+
ttl: "1h"
|
|
157
|
+
} : { type: "ephemeral" };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Generate function for OpenAI Responses API
|
|
161
|
+
*/
|
|
162
|
+
const streamOpenAIResponsesOnce = (model, context, options) => {
|
|
163
|
+
const stream = new AssistantMessageEventStream();
|
|
164
|
+
(async () => {
|
|
165
|
+
const startTime = performance.now();
|
|
166
|
+
let firstTokenTime;
|
|
167
|
+
const output = createInitialResponsesAssistantMessage(model.api, model.provider, model.id);
|
|
168
|
+
let rawRequestDump;
|
|
169
|
+
let chainState;
|
|
170
|
+
let sentPreviousResponseId;
|
|
171
|
+
const abortTracker = createAbortSourceTracker(options?.signal);
|
|
172
|
+
const firstEventTimeoutAbortError = new StreamTimeoutError(OPENAI_RESPONSES_FIRST_EVENT_TIMEOUT_MESSAGE);
|
|
173
|
+
const { requestAbortController, requestSignal } = abortTracker;
|
|
174
|
+
const onSseEvent = options?.onSseEvent;
|
|
175
|
+
const rawSseObserver = onSseEvent ? (event) => {
|
|
176
|
+
if (!event.event && event.data && event.data !== "[DONE]") try {
|
|
177
|
+
const parsed = JSON.parse(event.data);
|
|
178
|
+
const resolvedEvent = typeof parsed.type === "string" ? parsed.type : typeof parsed.object === "string" ? parsed.object : null;
|
|
179
|
+
if (resolvedEvent) {
|
|
180
|
+
event.event = resolvedEvent;
|
|
181
|
+
event.raw = [`event: ${resolvedEvent}`, ...event.raw];
|
|
182
|
+
}
|
|
183
|
+
} catch {}
|
|
184
|
+
onSseEvent(event, model);
|
|
185
|
+
} : void 0;
|
|
186
|
+
try {
|
|
187
|
+
const routingSessionId = getOpenAIResponsesRoutingSessionId(options);
|
|
188
|
+
const promptCacheSessionId = getOpenAIPromptCacheKey(options);
|
|
189
|
+
const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
|
|
190
|
+
const { headers, copilotPremiumRequests, baseUrl } = resolveOpenAIRequestSetup(model, {
|
|
191
|
+
apiKey,
|
|
192
|
+
extraHeaders: options?.headers,
|
|
193
|
+
initiatorOverride: options?.initiatorOverride,
|
|
194
|
+
messages: context.messages,
|
|
195
|
+
openAISessionId: routingSessionId,
|
|
196
|
+
promptCacheSessionId
|
|
197
|
+
});
|
|
198
|
+
const premiumRequestsTotal = copilotPremiumRequests;
|
|
199
|
+
const providerSessionState = getOpenAIResponsesProviderSessionState(model, options?.providerSessionState);
|
|
200
|
+
const strictToolsScope = getOpenAIStrictToolsScope(model, baseUrl);
|
|
201
|
+
const promptCacheBreakpointPolicy = resolveCacheRetention(options?.cacheRetention) !== "none" && options?.promptCache?.mode === "explicit" ? options.promptCache.breakpoint ?? "latest-stable-message" : void 0;
|
|
202
|
+
if (isOpenAIResponsesStatefulEnabled(options, baseUrl) && routingSessionId && providerSessionState) {
|
|
203
|
+
chainState = getOpenAIResponsesChainState(providerSessionState, model, baseUrl, routingSessionId);
|
|
204
|
+
if (chainState.canAppend && chainState.lastPromptCacheBreakpointPolicy !== promptCacheBreakpointPolicy) resetOpenAIResponsesChainState(chainState);
|
|
205
|
+
}
|
|
206
|
+
const builtParams = buildParams(model, context, options, providerSessionState, strictToolsScope, false, chainState?.canAppend ? chainState.lastParams?.input : void 0);
|
|
207
|
+
const { params, trailingScaffoldingItems } = builtParams;
|
|
208
|
+
let activeParams = params;
|
|
209
|
+
let activeTrailingScaffoldingItems = trailingScaffoldingItems;
|
|
210
|
+
const resolvedBaseUrl = (baseUrl ?? "https://api.openai.com/v1").replace(/\/+$/, "");
|
|
211
|
+
const requestReasoningEffortFallbacks = /* @__PURE__ */ new Map();
|
|
212
|
+
const attemptedReasoningEffortFallbacks = /* @__PURE__ */ new Set();
|
|
213
|
+
let pendingReasoningEffortFallback;
|
|
214
|
+
let activeReasoningEffortFallbackKey;
|
|
215
|
+
let activeRequestParams;
|
|
216
|
+
const applyReasoningEffortFallbackForRequest = (requestParams) => {
|
|
217
|
+
const fallbackKey = createOpenAIReasoningEffortFallbackKey("responses", resolvedBaseUrl, typeof requestParams.model === "string" ? requestParams.model : model.id);
|
|
218
|
+
const requestReasoningEffortFallback = requestReasoningEffortFallbacks.has(fallbackKey) ? requestReasoningEffortFallbacks.get(fallbackKey) : getOpenAIReasoningEffortFallback(providerSessionState, fallbackKey);
|
|
219
|
+
if (requestReasoningEffortFallback !== void 0) applyOpenAIReasoningEffortFallback(requestParams, requestReasoningEffortFallback);
|
|
220
|
+
return fallbackKey;
|
|
221
|
+
};
|
|
222
|
+
if (chainState && !chainState.disabled) params.store = true;
|
|
223
|
+
applyReasoningEffortFallbackForRequest(params);
|
|
224
|
+
let chained = chainState && !chainState.disabled ? buildOpenAIResponsesChainedParams(params, trailingScaffoldingItems, chainState) : { params };
|
|
225
|
+
sentPreviousResponseId = chained.previousResponseId;
|
|
226
|
+
const idleTimeoutMs = options?.streamIdleTimeoutMs ?? getOpenAIStreamIdleTimeoutMs(model.compat.streamIdleTimeoutMs);
|
|
227
|
+
const firstEventTimeoutMs = options?.streamFirstEventTimeoutMs ?? getOpenAIStreamFirstEventTimeoutMs(idleTimeoutMs, model.compat.streamFirstEventTimeoutMs);
|
|
228
|
+
const requestTimeoutMs = firstEventTimeoutMs !== void 0 && firstEventTimeoutMs > 0 ? firstEventTimeoutMs : void 0;
|
|
229
|
+
const requestUrl = `${resolvedBaseUrl}/responses`;
|
|
230
|
+
const applyPayloadReplacement = async (requestParams) => {
|
|
231
|
+
const replacementPayload = await options?.onPayload?.(requestParams, model);
|
|
232
|
+
const payload = replacementPayload !== void 0 ? replacementPayload : requestParams;
|
|
233
|
+
applyReasoningEffortFallbackForRequest(payload);
|
|
234
|
+
return payload;
|
|
235
|
+
};
|
|
236
|
+
chained = {
|
|
237
|
+
...chained,
|
|
238
|
+
params: await applyPayloadReplacement(chained.params)
|
|
239
|
+
};
|
|
240
|
+
const activeRawRequestDump = {
|
|
241
|
+
provider: model.provider,
|
|
242
|
+
api: output.api,
|
|
243
|
+
model: model.id,
|
|
244
|
+
method: "POST",
|
|
245
|
+
url: requestUrl,
|
|
246
|
+
body: chained.params
|
|
247
|
+
};
|
|
248
|
+
rawRequestDump = activeRawRequestDump;
|
|
249
|
+
const openResponsesStream = (requestParams) => {
|
|
250
|
+
activeReasoningEffortFallbackKey = createOpenAIReasoningEffortFallbackKey("responses", resolvedBaseUrl, typeof requestParams.model === "string" ? requestParams.model : model.id);
|
|
251
|
+
activeRequestParams = requestParams;
|
|
252
|
+
return callWithCopilotModelRetry(async () => {
|
|
253
|
+
let requestTimeout;
|
|
254
|
+
if (requestTimeoutMs !== void 0) requestTimeout = setTimeout(() => abortTracker.abortLocally(firstEventTimeoutAbortError), requestTimeoutMs);
|
|
255
|
+
try {
|
|
256
|
+
const headersWithTimeout = { ...headers };
|
|
257
|
+
if (requestTimeoutMs !== void 0) headersWithTimeout["X-Stainless-Timeout"] = Math.floor(requestTimeoutMs / 1e3).toString();
|
|
258
|
+
const { events, response, requestId } = await postOpenAIStream({
|
|
259
|
+
url: requestUrl,
|
|
260
|
+
headers: headersWithTimeout,
|
|
261
|
+
body: requestParams,
|
|
262
|
+
signal: requestSignal,
|
|
263
|
+
fetch: options?.fetch,
|
|
264
|
+
onSseEvent: rawSseObserver
|
|
265
|
+
});
|
|
266
|
+
if (requestTimeout !== void 0) {
|
|
267
|
+
clearTimeout(requestTimeout);
|
|
268
|
+
requestTimeout = void 0;
|
|
269
|
+
}
|
|
270
|
+
await notifyProviderResponse(options, response, model, requestId);
|
|
271
|
+
return events;
|
|
272
|
+
} finally {
|
|
273
|
+
if (requestTimeout !== void 0) clearTimeout(requestTimeout);
|
|
274
|
+
}
|
|
275
|
+
}, {
|
|
276
|
+
provider: model.provider,
|
|
277
|
+
signal: requestSignal
|
|
278
|
+
});
|
|
279
|
+
};
|
|
280
|
+
let strictRetryAvailable = true;
|
|
281
|
+
let activeStrictToolsApplied = builtParams.strictToolsApplied;
|
|
282
|
+
let forceDisableStrictTools = false;
|
|
283
|
+
const openResponsesStreamWithFallbacks = async () => {
|
|
284
|
+
let openaiStream;
|
|
285
|
+
while (true) try {
|
|
286
|
+
openaiStream = await openResponsesStream(chained.params);
|
|
287
|
+
if (pendingReasoningEffortFallback) {
|
|
288
|
+
rememberOpenAIReasoningEffortFallback(providerSessionState, pendingReasoningEffortFallback.key, pendingReasoningEffortFallback.fallback);
|
|
289
|
+
pendingReasoningEffortFallback = void 0;
|
|
290
|
+
}
|
|
291
|
+
break;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
const capturedErrorResponse = error instanceof OpenAIHttpError ? error.captured : void 0;
|
|
294
|
+
const reasoningEffortFallback = activeReasoningEffortFallbackKey && activeRequestParams && !requestSignal.aborted ? resolveOpenAIReasoningEffortFallback(error, capturedErrorResponse, activeRequestParams, { explicitDisable: options?.forceReasoningOff === true || options?.disableReasoning === true && options.reasoning === void 0 }) : void 0;
|
|
295
|
+
if (reasoningEffortFallback !== void 0 && activeReasoningEffortFallbackKey) {
|
|
296
|
+
const retryMarker = `${activeReasoningEffortFallbackKey}:${String(reasoningEffortFallback)}`;
|
|
297
|
+
if (attemptedReasoningEffortFallbacks.has(retryMarker)) throw error;
|
|
298
|
+
attemptedReasoningEffortFallbacks.add(retryMarker);
|
|
299
|
+
requestReasoningEffortFallbacks.set(activeReasoningEffortFallbackKey, reasoningEffortFallback);
|
|
300
|
+
applyOpenAIReasoningEffortFallback(chained.params, reasoningEffortFallback);
|
|
301
|
+
applyOpenAIReasoningEffortFallback(activeParams, reasoningEffortFallback);
|
|
302
|
+
activeRawRequestDump.body = chained.params;
|
|
303
|
+
pendingReasoningEffortFallback = {
|
|
304
|
+
key: activeReasoningEffortFallbackKey,
|
|
305
|
+
fallback: reasoningEffortFallback
|
|
306
|
+
};
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
const compiledGrammarTooLarge = isOpenRouterAnthropicModel(model) && isCompiledGrammarTooLargeStrictError(error, capturedErrorResponse);
|
|
310
|
+
if (strictRetryAvailable && !requestSignal.aborted && (compiledGrammarTooLarge || shouldRetryWithoutStrictTools(error, capturedErrorResponse, {
|
|
311
|
+
model,
|
|
312
|
+
strictToolsApplied: activeStrictToolsApplied,
|
|
313
|
+
tools: context.tools
|
|
314
|
+
}))) {
|
|
315
|
+
strictRetryAvailable = false;
|
|
316
|
+
forceDisableStrictTools = true;
|
|
317
|
+
disableStrictToolsForScope(providerSessionState, strictToolsScope);
|
|
318
|
+
const fallbackBuilt = buildParams(model, context, options, providerSessionState, strictToolsScope, true, chainState?.canAppend ? chainState.lastParams?.input : void 0);
|
|
319
|
+
const fallbackParams = fallbackBuilt.params;
|
|
320
|
+
if (chainState && !chainState.disabled) fallbackParams.store = true;
|
|
321
|
+
let fallbackChained = chainState && !chainState.disabled ? buildOpenAIResponsesChainedParams(fallbackParams, fallbackBuilt.trailingScaffoldingItems, chainState) : { params: fallbackParams };
|
|
322
|
+
sentPreviousResponseId = fallbackChained.previousResponseId;
|
|
323
|
+
fallbackChained = {
|
|
324
|
+
...fallbackChained,
|
|
325
|
+
params: await applyPayloadReplacement(fallbackChained.params)
|
|
326
|
+
};
|
|
327
|
+
chained = fallbackChained;
|
|
328
|
+
activeRawRequestDump.body = chained.params;
|
|
329
|
+
activeParams = fallbackParams;
|
|
330
|
+
activeTrailingScaffoldingItems = fallbackBuilt.trailingScaffoldingItems;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (!chainState || !sentPreviousResponseId || requestSignal.aborted) throw error;
|
|
334
|
+
const zdrRejection = error instanceof Error && /previous[ _]?response/i.test(error.message) && /zero[ _-]?data[ _-]?retention/i.test(error.message);
|
|
335
|
+
const isPromptBlocked = error instanceof Error && (error.code === "invalid_prompt" || /invalid_prompt|Request blocked/i.test(error.message));
|
|
336
|
+
if (!zdrRejection && !isPromptBlocked && !isOpenAIResponsesStalePreviousResponseError(error)) throw error;
|
|
337
|
+
if (zdrRejection) markOpenAIResponsesChainZeroDataRetention(chainState, error);
|
|
338
|
+
else registerOpenAIResponsesChainStaleFailure(chainState, error);
|
|
339
|
+
sentPreviousResponseId = void 0;
|
|
340
|
+
const currentBuilt = buildParams(model, context, options, providerSessionState, strictToolsScope, forceDisableStrictTools);
|
|
341
|
+
const currentParams = currentBuilt.params;
|
|
342
|
+
currentParams.store = !zdrRejection;
|
|
343
|
+
const retryParams = await applyPayloadReplacement(currentParams);
|
|
344
|
+
chained = { params: retryParams };
|
|
345
|
+
activeRawRequestDump.body = retryParams;
|
|
346
|
+
activeParams = currentParams;
|
|
347
|
+
activeTrailingScaffoldingItems = currentBuilt.trailingScaffoldingItems;
|
|
348
|
+
activeStrictToolsApplied = currentBuilt.strictToolsApplied;
|
|
349
|
+
}
|
|
350
|
+
return openaiStream;
|
|
351
|
+
};
|
|
352
|
+
let openaiStream = await openResponsesStreamWithFallbacks();
|
|
353
|
+
if (premiumRequestsTotal !== void 0) output.usage.premiumRequests = premiumRequestsTotal;
|
|
354
|
+
stream.push({
|
|
355
|
+
type: "start",
|
|
356
|
+
partial: output
|
|
357
|
+
});
|
|
358
|
+
const nativeOutputItems = [];
|
|
359
|
+
let transientStreamRetryAttempt = 0;
|
|
360
|
+
while (true) {
|
|
361
|
+
let sawReplayUnsafeOutput = false;
|
|
362
|
+
let sawTerminalResponseEvent = false;
|
|
363
|
+
const attemptStream = new AssistantMessageEventStream();
|
|
364
|
+
let forwardAttemptLive = false;
|
|
365
|
+
const forwardAttemptEvents = () => {
|
|
366
|
+
for (const event of attemptStream.queue) stream.push(event);
|
|
367
|
+
attemptStream.queue.length = 0;
|
|
368
|
+
};
|
|
369
|
+
nativeOutputItems.length = 0;
|
|
370
|
+
const timedOpenaiStream = iterateWithIdleTimeout(openaiStream, {
|
|
371
|
+
idleTimeoutMs,
|
|
372
|
+
firstItemTimeoutMs: firstEventTimeoutMs,
|
|
373
|
+
firstItemErrorMessage: OPENAI_RESPONSES_FIRST_EVENT_TIMEOUT_MESSAGE,
|
|
374
|
+
errorMessage: "OpenAI responses stream stalled while waiting for the next event",
|
|
375
|
+
onFirstItemTimeout: () => abortTracker.abortLocally(firstEventTimeoutAbortError),
|
|
376
|
+
onIdle: () => requestAbortController.abort(),
|
|
377
|
+
abortSignal: options?.signal,
|
|
378
|
+
isProgressItem: isOpenAIResponsesProgressEvent
|
|
379
|
+
});
|
|
380
|
+
const observedOpenaiStream = (async function* () {
|
|
381
|
+
for await (const event of timedOpenaiStream) {
|
|
382
|
+
if (isOpenAIResponsesReplayUnsafeEvent(event)) {
|
|
383
|
+
sawReplayUnsafeOutput = true;
|
|
384
|
+
if (!forwardAttemptLive) {
|
|
385
|
+
forwardAttemptEvents();
|
|
386
|
+
forwardAttemptLive = true;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
yield event;
|
|
390
|
+
if (forwardAttemptLive) forwardAttemptEvents();
|
|
391
|
+
}
|
|
392
|
+
})();
|
|
393
|
+
try {
|
|
394
|
+
await processResponsesStream(observedOpenaiStream, output, attemptStream, model, {
|
|
395
|
+
onFirstToken: () => {
|
|
396
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
397
|
+
},
|
|
398
|
+
onOutputItemDone: (item) => {
|
|
399
|
+
nativeOutputItems.push(item);
|
|
400
|
+
},
|
|
401
|
+
onCompleted: () => {
|
|
402
|
+
sawTerminalResponseEvent = true;
|
|
403
|
+
},
|
|
404
|
+
requestServiceTier: options?.serviceTier
|
|
405
|
+
});
|
|
406
|
+
const localAbortReason = abortTracker.getLocalAbortReason();
|
|
407
|
+
if (localAbortReason) throw localAbortReason;
|
|
408
|
+
if (abortTracker.wasCallerAbort()) throw new AbortError();
|
|
409
|
+
if (!sawTerminalResponseEvent) throw new ProviderResponseError("OpenAI responses stream closed before a terminal response event was received", {
|
|
410
|
+
provider: model.provider,
|
|
411
|
+
kind: "incomplete-stream"
|
|
412
|
+
});
|
|
413
|
+
if (output.stopReason === "aborted" || output.stopReason === "error") throw new ProviderResponseError(output.errorMessage ?? "An unknown error occurred", {
|
|
414
|
+
provider: model.provider,
|
|
415
|
+
kind: "runtime"
|
|
416
|
+
});
|
|
417
|
+
forwardAttemptEvents();
|
|
418
|
+
break;
|
|
419
|
+
} catch (error) {
|
|
420
|
+
const streamFailure = abortTracker.getLocalAbortReason() ?? error;
|
|
421
|
+
if (!(!sawReplayUnsafeOutput && !requestSignal.aborted && !abortTracker.wasCallerAbort() && transientStreamRetryAttempt < OPENAI_RESPONSES_MAX_TRANSIENT_STREAM_RETRIES && isRetryableOpenAIResponsesStreamFailure(streamFailure))) {
|
|
422
|
+
forwardAttemptEvents();
|
|
423
|
+
throw streamFailure;
|
|
424
|
+
}
|
|
425
|
+
transientStreamRetryAttempt++;
|
|
426
|
+
debug("OpenAI responses stream ended before replay-unsafe output; retrying", {
|
|
427
|
+
provider: model.provider,
|
|
428
|
+
model: model.id,
|
|
429
|
+
attempt: transientStreamRetryAttempt,
|
|
430
|
+
error: streamFailure instanceof Error ? streamFailure.message : String(streamFailure)
|
|
431
|
+
});
|
|
432
|
+
const retryOutput = createInitialResponsesAssistantMessage(model.api, model.provider, model.id);
|
|
433
|
+
output.content.length = 0;
|
|
434
|
+
output.responseId = void 0;
|
|
435
|
+
output.upstreamProvider = void 0;
|
|
436
|
+
output.errorMessage = void 0;
|
|
437
|
+
output.errorStatus = void 0;
|
|
438
|
+
output.errorId = void 0;
|
|
439
|
+
output.stopDetails = void 0;
|
|
440
|
+
output.providerPayload = void 0;
|
|
441
|
+
output.usage = retryOutput.usage;
|
|
442
|
+
if (premiumRequestsTotal !== void 0) output.usage.premiumRequests = premiumRequestsTotal;
|
|
443
|
+
output.stopReason = "stop";
|
|
444
|
+
output.duration = void 0;
|
|
445
|
+
output.ttft = void 0;
|
|
446
|
+
firstTokenTime = void 0;
|
|
447
|
+
nativeOutputItems.length = 0;
|
|
448
|
+
if (options?.providerRetryWait) await options.providerRetryWait(OPENAI_RESPONSES_TRANSIENT_STREAM_RETRY_DELAY_MS, options.signal);
|
|
449
|
+
else await scheduler.wait(OPENAI_RESPONSES_TRANSIENT_STREAM_RETRY_DELAY_MS, { signal: options?.signal });
|
|
450
|
+
if (abortTracker.wasCallerAbort()) throw new AbortError();
|
|
451
|
+
openaiStream = await openResponsesStreamWithFallbacks();
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
output.providerPayload = createOpenAIResponsesHistoryPayload(model.provider, nativeOutputItems);
|
|
455
|
+
const replayableResponseItems = sanitizeOpenAIResponsesAssistantHistoryItemsForReplay(structuredCloneJSON(nativeOutputItems));
|
|
456
|
+
if (replayableResponseItems) {
|
|
457
|
+
if (providerSessionState) providerSessionState.nativeHistoryReplayWarmed = true;
|
|
458
|
+
if (chainState) {
|
|
459
|
+
chainState.lastParams = structuredCloneJSON(activeTrailingScaffoldingItems > 0 && Array.isArray(activeParams.input) ? {
|
|
460
|
+
...activeParams,
|
|
461
|
+
input: activeParams.input.slice(0, activeParams.input.length - activeTrailingScaffoldingItems)
|
|
462
|
+
} : activeParams);
|
|
463
|
+
chainState.lastPromptCacheBreakpointPolicy = promptCacheBreakpointPolicy;
|
|
464
|
+
if (output.responseId) {
|
|
465
|
+
chainState.lastResponseId = output.responseId;
|
|
466
|
+
chainState.lastResponseItems = replayableResponseItems;
|
|
467
|
+
chainState.canAppend = true;
|
|
468
|
+
if (sentPreviousResponseId) chainState.staleFailures = 0;
|
|
469
|
+
} else chainState.canAppend = false;
|
|
470
|
+
}
|
|
471
|
+
} else if (chainState) {
|
|
472
|
+
chainState.canAppend = false;
|
|
473
|
+
chainState.lastParams = structuredCloneJSON(activeTrailingScaffoldingItems > 0 && Array.isArray(activeParams.input) ? {
|
|
474
|
+
...activeParams,
|
|
475
|
+
input: activeParams.input.slice(0, activeParams.input.length - activeTrailingScaffoldingItems)
|
|
476
|
+
} : activeParams);
|
|
477
|
+
chainState.lastPromptCacheBreakpointPolicy = promptCacheBreakpointPolicy;
|
|
478
|
+
chainState.lastResponseId = void 0;
|
|
479
|
+
chainState.lastResponseItems = void 0;
|
|
480
|
+
}
|
|
481
|
+
output.duration = performance.now() - startTime;
|
|
482
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
483
|
+
stream.push({
|
|
484
|
+
type: "done",
|
|
485
|
+
reason: output.stopReason,
|
|
486
|
+
message: output
|
|
487
|
+
});
|
|
488
|
+
stream.end();
|
|
489
|
+
} catch (error) {
|
|
490
|
+
if (chainState) resetOpenAIResponsesChainState(chainState);
|
|
491
|
+
const capturedErrorResponse = error instanceof OpenAIHttpError ? error.captured : void 0;
|
|
492
|
+
const result = await finalize(error, {
|
|
493
|
+
api: model.api,
|
|
494
|
+
provider: model.provider,
|
|
495
|
+
abortTracker,
|
|
496
|
+
rawRequestDump,
|
|
497
|
+
capturedErrorResponse
|
|
498
|
+
});
|
|
499
|
+
output.stopReason = result.stopReason;
|
|
500
|
+
output.errorStatus = result.status;
|
|
501
|
+
output.errorId = result.id;
|
|
502
|
+
output.errorMessage = result.message;
|
|
503
|
+
const rawMetadata = error?.error?.metadata?.raw;
|
|
504
|
+
if (rawMetadata) output.errorMessage += `\n${rawMetadata}`;
|
|
505
|
+
output.duration = performance.now() - startTime;
|
|
506
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
507
|
+
stream.push({
|
|
508
|
+
type: "error",
|
|
509
|
+
reason: output.stopReason,
|
|
510
|
+
error: output
|
|
511
|
+
});
|
|
512
|
+
stream.end();
|
|
513
|
+
}
|
|
514
|
+
})();
|
|
515
|
+
return stream;
|
|
516
|
+
};
|
|
517
|
+
/**
|
|
518
|
+
* Public entry: wrap the single-attempt Responses streamer with bounded
|
|
519
|
+
* empty-completion retries — a `response.completed` carrying no content/usage
|
|
520
|
+
* would otherwise stall the agent loop. Shared with the OpenAI-completions and
|
|
521
|
+
* Anthropic providers via `withEmptyCompletionRetry`.
|
|
522
|
+
*/
|
|
523
|
+
const streamOpenAIResponses = (model, context, options) => withEmptyCompletionRetry(model, context, options, streamOpenAIResponsesOnce);
|
|
524
|
+
function isOfficialOpenAIResponsesEndpoint(model) {
|
|
525
|
+
if (model.provider !== "openai") return false;
|
|
526
|
+
if (!model.baseUrl) return true;
|
|
527
|
+
try {
|
|
528
|
+
return new URL(model.baseUrl).hostname === "api.openai.com";
|
|
529
|
+
} catch {
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* GPT-5.6+ family check for Responses routes. The model id classifies the
|
|
535
|
+
* reasoning family regardless of the provider/host serving it — a cliproxy or
|
|
536
|
+
* other OpenAI-compatible gateway carrying `gpt-5.6-sol` gets the same
|
|
537
|
+
* scaffolding as the official endpoint.
|
|
538
|
+
*/
|
|
539
|
+
function isGpt56PlusResponsesModel(model) {
|
|
540
|
+
const parsed = parseOpenAIModel(bareModelId(model.requestModelId ?? model.id));
|
|
541
|
+
return parsed !== null && semverGte(parsed.version, "5.6");
|
|
542
|
+
}
|
|
543
|
+
function isResponsesPromptCacheableContentBlock(block) {
|
|
544
|
+
if (typeof block !== "object" || block === null || !("type" in block)) return false;
|
|
545
|
+
return block.type === "input_text" || block.type === "input_image" || block.type === "input_file";
|
|
546
|
+
}
|
|
547
|
+
function isResponsesPromptCacheableMessage(item) {
|
|
548
|
+
if (typeof item !== "object" || item === null || !("role" in item) || !("content" in item)) return false;
|
|
549
|
+
if (item.role !== "assistant" && item.role !== "developer" && item.role !== "system" && item.role !== "user") return false;
|
|
550
|
+
return Array.isArray(item.content) && item.content.every(isResponsesPromptCacheableContentBlock);
|
|
551
|
+
}
|
|
552
|
+
function isStableStringResponsesInstruction(item) {
|
|
553
|
+
if (typeof item !== "object" || item === null || !("role" in item) || !("content" in item)) return false;
|
|
554
|
+
return (item.role === "developer" || item.role === "system") && typeof item.content === "string" && item.content.length > 0;
|
|
555
|
+
}
|
|
556
|
+
function matchesResponsesCacheBaseline(baseline, current) {
|
|
557
|
+
if (baseline.role !== current.role || baseline.content.length !== current.content.length) return false;
|
|
558
|
+
for (let index = 0; index < baseline.content.length; index++) {
|
|
559
|
+
const baselineBlock = baseline.content[index];
|
|
560
|
+
const currentBlock = current.content[index];
|
|
561
|
+
if (!baselineBlock || !currentBlock) return false;
|
|
562
|
+
const breakpoint = baselineBlock.prompt_cache_breakpoint;
|
|
563
|
+
if (breakpoint) {
|
|
564
|
+
if (!Bun.deepEquals(baselineBlock, {
|
|
565
|
+
...currentBlock,
|
|
566
|
+
prompt_cache_breakpoint: breakpoint
|
|
567
|
+
})) return false;
|
|
568
|
+
} else if (!Bun.deepEquals(baselineBlock, currentBlock)) return false;
|
|
569
|
+
}
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
function restoreResponsesCacheBreakpointsFromBaseline(input, baseline) {
|
|
573
|
+
if (!input || !baseline) return false;
|
|
574
|
+
let restored = false;
|
|
575
|
+
for (let i = 0; i < baseline.length && i < input.length; i++) {
|
|
576
|
+
const baselineMessage = baseline[i];
|
|
577
|
+
const message = input[i];
|
|
578
|
+
if (!isResponsesPromptCacheableMessage(baselineMessage)) continue;
|
|
579
|
+
if (isStableStringResponsesInstruction(message)) {
|
|
580
|
+
const [baselineBlock] = baselineMessage.content;
|
|
581
|
+
if (baselineMessage.role === message.role && baselineBlock?.type === "input_text" && baselineBlock.text === message.content && baselineBlock.prompt_cache_breakpoint) {
|
|
582
|
+
Object.assign(message, { content: [{
|
|
583
|
+
type: "input_text",
|
|
584
|
+
text: message.content,
|
|
585
|
+
prompt_cache_breakpoint: baselineBlock.prompt_cache_breakpoint
|
|
586
|
+
}] });
|
|
587
|
+
restored = true;
|
|
588
|
+
}
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
if (!isResponsesPromptCacheableMessage(message) || !matchesResponsesCacheBaseline(baselineMessage, message)) continue;
|
|
592
|
+
for (let j = 0; j < baselineMessage.content.length; j++) {
|
|
593
|
+
const baselineBlock = baselineMessage.content[j];
|
|
594
|
+
const block = message.content[j];
|
|
595
|
+
if (!baselineBlock?.prompt_cache_breakpoint || !block) continue;
|
|
596
|
+
Object.assign(block, { prompt_cache_breakpoint: baselineBlock.prompt_cache_breakpoint });
|
|
597
|
+
restored = true;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return restored;
|
|
601
|
+
}
|
|
602
|
+
function hasResponsesCacheBreakpoint(input) {
|
|
603
|
+
return input?.some((message) => isResponsesPromptCacheableMessage(message) && message.content.some((block) => block.prompt_cache_breakpoint !== void 0)) ?? false;
|
|
604
|
+
}
|
|
605
|
+
function markLatestStableResponsesCacheBreakpoint(input, statefulBaseline) {
|
|
606
|
+
if (!input) return false;
|
|
607
|
+
if (statefulBaseline) {
|
|
608
|
+
if (restoreResponsesCacheBreakpointsFromBaseline(input, statefulBaseline)) return true;
|
|
609
|
+
if (!hasResponsesCacheBreakpoint(statefulBaseline)) return false;
|
|
610
|
+
}
|
|
611
|
+
let latestInputMessage = -1;
|
|
612
|
+
for (let i = input.length - 1; i >= 0; i--) {
|
|
613
|
+
const message = input[i];
|
|
614
|
+
if (!("role" in message)) continue;
|
|
615
|
+
if (message.role === "user" || message.role === "developer") {
|
|
616
|
+
latestInputMessage = i;
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (latestInputMessage <= 0) return false;
|
|
621
|
+
for (let i = latestInputMessage - 1; i >= 0; i--) {
|
|
622
|
+
const message = input[i];
|
|
623
|
+
if (isStableStringResponsesInstruction(message)) {
|
|
624
|
+
const text = message.content;
|
|
625
|
+
Object.assign(message, { content: [{
|
|
626
|
+
type: "input_text",
|
|
627
|
+
text,
|
|
628
|
+
prompt_cache_breakpoint: { mode: "explicit" }
|
|
629
|
+
}] });
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
if (!isResponsesPromptCacheableMessage(message)) continue;
|
|
633
|
+
for (let j = message.content.length - 1; j >= 0; j--) {
|
|
634
|
+
const block = message.content[j];
|
|
635
|
+
if (!isResponsesPromptCacheableContentBlock(block)) continue;
|
|
636
|
+
Object.assign(block, { prompt_cache_breakpoint: { mode: "explicit" } });
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
function applyOpenAIResponsesPromptCachePolicy(params, model, options, statefulCacheBaseline) {
|
|
643
|
+
const promptCache = options?.promptCache;
|
|
644
|
+
if (!promptCache || resolveCacheRetention(options?.cacheRetention) === "none") return;
|
|
645
|
+
if (!model.compat.supportsPromptCacheBreakpoints) {
|
|
646
|
+
if (promptCache.mode === "explicit") throw new ConfigurationError(`OpenAI explicit prompt caching is unsupported for ${model.provider}/${model.id}; enable compat.supportsPromptCacheBreakpoints only for a compatible endpoint.`);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
params.prompt_cache_options = {
|
|
650
|
+
mode: promptCache.mode,
|
|
651
|
+
ttl: promptCache.ttl ?? model.compat.promptCacheBreakpointTtl
|
|
652
|
+
};
|
|
653
|
+
if (promptCache.mode === "explicit" && promptCache.breakpoint !== "none") markLatestStableResponsesCacheBreakpoint(params.input, statefulCacheBaseline);
|
|
654
|
+
}
|
|
655
|
+
function buildParams(model, context, options, providerSessionState, strictToolsScope, disableStrictToolsOverride = false, statefulCacheBaseline) {
|
|
656
|
+
const policy = resolveOpenAICompatPolicy(model, {
|
|
657
|
+
endpoint: "responses",
|
|
658
|
+
reasoning: options?.reasoning,
|
|
659
|
+
disableReasoning: options?.disableReasoning,
|
|
660
|
+
toolChoice: options?.toolChoice,
|
|
661
|
+
strictResponsesPairing: options?.strictResponsesPairing,
|
|
662
|
+
includeEncryptedReasoning: options?.includeEncryptedReasoning,
|
|
663
|
+
filterReasoningHistory: options?.filterReasoningHistory,
|
|
664
|
+
omitReasoningEffort: options?.omitReasoningEffort
|
|
665
|
+
});
|
|
666
|
+
const strictResponsesPairing = policy.tools.strictResponsesPairing;
|
|
667
|
+
const shouldReplayNativeHistory = providerSessionState?.nativeHistoryReplayWarmed ?? true;
|
|
668
|
+
const messages = buildResponsesInput({
|
|
669
|
+
model,
|
|
670
|
+
context,
|
|
671
|
+
strictResponsesPairing,
|
|
672
|
+
supportsImageDetailOriginal: model.compat.supportsImageDetailOriginal,
|
|
673
|
+
nativeHistory: {
|
|
674
|
+
replay: shouldReplayNativeHistory,
|
|
675
|
+
filterReasoning: policy.reasoning.filterReasoningHistory
|
|
676
|
+
},
|
|
677
|
+
includeThinkingSignatures: shouldReplayNativeHistory && !policy.reasoning.filterReasoningHistory,
|
|
678
|
+
requiresReasoningReplayForAllTurns: policy.reasoning.enabled && policy.reasoning.requiresReasoningContentForAllAssistantTurns,
|
|
679
|
+
requiresReasoningReplayForToolCalls: policy.reasoning.enabled && policy.reasoning.requiresReasoningContentForToolCalls,
|
|
680
|
+
repairOrphanOutputs: true
|
|
681
|
+
});
|
|
682
|
+
const systemPrompts = normalizeSystemPrompts(context.systemPrompt);
|
|
683
|
+
let systemInstructions;
|
|
684
|
+
if (systemPrompts.length > 0) {
|
|
685
|
+
if (policy.messages.systemRole === "developer") messages.unshift(...systemPrompts.map((systemPrompt) => ({
|
|
686
|
+
role: "developer",
|
|
687
|
+
content: systemPrompt
|
|
688
|
+
})));
|
|
689
|
+
else systemInstructions = systemPrompts.join("\n\n");
|
|
690
|
+
}
|
|
691
|
+
const cacheRetention = resolveCacheRetention(options?.cacheRetention);
|
|
692
|
+
const promptCacheKey = getOpenAIPromptCacheKey(options);
|
|
693
|
+
const params = {
|
|
694
|
+
model: applyWireModelIdTransform(model.requestModelId ?? model.id, model.compat.wireModelIdMode, options?.openrouterVariant),
|
|
695
|
+
input: messages,
|
|
696
|
+
instructions: systemInstructions,
|
|
697
|
+
stream: true,
|
|
698
|
+
prompt_cache_key: promptCacheKey,
|
|
699
|
+
prompt_cache_retention: promptCacheKey ? cacheRetention === "long" && model.compat.supportsLongPromptCacheRetention ? "24h" : void 0 : void 0,
|
|
700
|
+
session_id: model.compat.isOpenRouterHost ? getOpenRouterResponsesSessionId(options) : void 0,
|
|
701
|
+
store: false,
|
|
702
|
+
stream_options: model.compat.supportsObfuscationOptOut ? { include_obfuscation: false } : void 0
|
|
703
|
+
};
|
|
704
|
+
if (options?.include?.length) params.include = Array.from(new Set(options.include));
|
|
705
|
+
maybeAddOpenRouterAnthropicCacheControl(params, model, cacheRetention);
|
|
706
|
+
const outputToken = resolveOpenAIOutputTokenParam({
|
|
707
|
+
field: "max_output_tokens",
|
|
708
|
+
maxTokens: options?.maxTokens,
|
|
709
|
+
maxTokensExplicit: options?.maxTokensExplicit ?? options?.maxTokens !== void 0,
|
|
710
|
+
modelMaxTokens: model.maxTokens,
|
|
711
|
+
omitMaxOutputTokens: model.omitMaxOutputTokens ?? false,
|
|
712
|
+
isOpenRouterHost: model.compat.isOpenRouterHost,
|
|
713
|
+
alwaysSendMaxTokens: model.compat.alwaysSendMaxTokens,
|
|
714
|
+
providerOutputClamp: resolveOpenAIResponsesOutputClamp(model)
|
|
715
|
+
});
|
|
716
|
+
applyCommonResponsesSamplingParams(params, {
|
|
717
|
+
...options,
|
|
718
|
+
maxTokens: outputToken?.value
|
|
719
|
+
}, model);
|
|
720
|
+
if (options?.textVerbosity && isOfficialOpenAIResponsesEndpoint(model)) params.text = {
|
|
721
|
+
...params.text,
|
|
722
|
+
verbosity: options.textVerbosity
|
|
723
|
+
};
|
|
724
|
+
let strictToolsApplied = false;
|
|
725
|
+
if (context.tools) {
|
|
726
|
+
const strictMode = !(disableStrictToolsOverride || isStrictToolsDisabledForScope(providerSessionState, strictToolsScope)) && model.compat.supportsStrictMode !== false;
|
|
727
|
+
params.tools = convertTools(context.tools, strictMode, model);
|
|
728
|
+
strictToolsApplied = params.tools.some((t) => t.strict === true);
|
|
729
|
+
if (options?.toolChoice) {
|
|
730
|
+
const emittedNames = new Set(params.tools.map((t) => t.name).filter((n) => n !== void 0));
|
|
731
|
+
const emittedComputer = params.tools.some((tool) => tool.type === "computer");
|
|
732
|
+
const survivingTools = params.tools.length === context.tools.length ? context.tools : context.tools.filter((t) => emittedNames.has(t.customWireName ?? t.name) || t.native?.type === "computer" && emittedComputer);
|
|
733
|
+
const toolChoice = mapOpenAIResponsesToolChoiceForTools(options.toolChoice, survivingTools, model);
|
|
734
|
+
if (toolChoice !== void 0 && params.tools.length > 0) {
|
|
735
|
+
if (typeof toolChoice === "object" && toolChoice.type === "function" && !model.compat.supportsNamedToolChoice) {
|
|
736
|
+
params.tools = params.tools.filter((tool) => tool.type === "function" && tool.name === toolChoice.name);
|
|
737
|
+
params.tool_choice = "required";
|
|
738
|
+
} else params.tool_choice = toolChoice;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
const reasoningPolicy = resolveOpenAICompatPolicy(model, {
|
|
743
|
+
endpoint: "responses",
|
|
744
|
+
reasoning: options?.reasoning,
|
|
745
|
+
disableReasoning: options?.disableReasoning,
|
|
746
|
+
toolChoice: params.tool_choice,
|
|
747
|
+
strictResponsesPairing: options?.strictResponsesPairing,
|
|
748
|
+
includeEncryptedReasoning: options?.includeEncryptedReasoning,
|
|
749
|
+
filterReasoningHistory: options?.filterReasoningHistory,
|
|
750
|
+
omitReasoningEffort: options?.omitReasoningEffort
|
|
751
|
+
});
|
|
752
|
+
const reasoningSummary = model.compat.supportsReasoningSummary ? options?.reasoningSummary : options?.reasoning === void 0 ? void 0 : null;
|
|
753
|
+
applyResponsesCompatPolicy(params, reasoningPolicy, {
|
|
754
|
+
reasoningSummary,
|
|
755
|
+
forceReasoningOff: options?.forceReasoningOff,
|
|
756
|
+
mapEffort: (effort) => model.compat.reasoningEffortMap?.[effort] ?? model.thinking?.effortMap?.[effort] ?? effort
|
|
757
|
+
});
|
|
758
|
+
if (model.reasoningMode && !options?.forceReasoningOff) params.reasoning = {
|
|
759
|
+
...params.reasoning,
|
|
760
|
+
mode: model.reasoningMode
|
|
761
|
+
};
|
|
762
|
+
if (model.compat.isVercelGatewayHost) applyVercelResponsesCacheControls(params, model.compat, cacheRetention);
|
|
763
|
+
else applyOpenAIGatewayRouting(params, model.compat);
|
|
764
|
+
applyOpenAIExtraBody(params, options?.extraBody);
|
|
765
|
+
applyOpenAIResponsesPromptCachePolicy(params, model, options, statefulCacheBaseline);
|
|
766
|
+
let trailingScaffoldingItems = 0;
|
|
767
|
+
if (options?.forceReasoningOff && isGpt56PlusResponsesModel(model)) {
|
|
768
|
+
const effort = options.reasoning ?? "medium";
|
|
769
|
+
const juice = getJuiceValue(effort);
|
|
770
|
+
messages.push({
|
|
771
|
+
role: "developer",
|
|
772
|
+
content: [{
|
|
773
|
+
type: "input_text",
|
|
774
|
+
text: `# Juice: ${juice} !important`
|
|
775
|
+
}]
|
|
776
|
+
});
|
|
777
|
+
trailingScaffoldingItems = 1;
|
|
778
|
+
}
|
|
779
|
+
return {
|
|
780
|
+
params,
|
|
781
|
+
trailingScaffoldingItems,
|
|
782
|
+
strictToolsApplied
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Whether this model should get the OpenAI custom-tool grammar variant
|
|
787
|
+
* for `apply_patch`. The generated model catalog sets
|
|
788
|
+
* `model.applyPatchToolType` for first-party GPT-5 Responses models; this
|
|
789
|
+
* runtime path only consumes that metadata.
|
|
790
|
+
* @internal Exported for tests.
|
|
791
|
+
*/
|
|
792
|
+
function supportsFreeformApplyPatch(model) {
|
|
793
|
+
return model.applyPatchToolType === "freeform";
|
|
794
|
+
}
|
|
795
|
+
/** @internal Exported for tests. */
|
|
796
|
+
function mapOpenAIResponsesToolChoiceForTools(choice, tools, model) {
|
|
797
|
+
if (!model.compat.supportsToolChoice) return void 0;
|
|
798
|
+
if (isForcedToolChoice(choice) && !model.compat.supportsForcedToolChoice) return "auto";
|
|
799
|
+
if (typeof choice !== "string" && choice?.type === "computer") {
|
|
800
|
+
const computer = tools.find((tool) => tool.native?.type === "computer");
|
|
801
|
+
if (!computer) return void 0;
|
|
802
|
+
return model.supportsComputerUse === true ? { type: "computer" } : {
|
|
803
|
+
type: "function",
|
|
804
|
+
name: computer.name
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
const mapped = mapToOpenAIResponsesToolChoice(choice);
|
|
808
|
+
if (!mapped || typeof mapped === "string" || mapped.type !== "function") return mapped;
|
|
809
|
+
const directTool = tools.find((tool) => tool.name === mapped.name);
|
|
810
|
+
const customTool = supportsFreeformApplyPatch(model) ? tools.find((tool) => tool.customFormat && (tool.name === mapped.name || tool.customWireName === mapped.name)) : void 0;
|
|
811
|
+
const offeredTool = customTool ?? directTool;
|
|
812
|
+
if (offeredTool?.native?.type === "computer") return model.supportsComputerUse === true ? { type: "computer" } : {
|
|
813
|
+
type: "function",
|
|
814
|
+
name: offeredTool.name
|
|
815
|
+
};
|
|
816
|
+
if (!offeredTool) return;
|
|
817
|
+
return customTool ? {
|
|
818
|
+
type: "custom",
|
|
819
|
+
name: customTool.customWireName ?? customTool.name
|
|
820
|
+
} : mapped;
|
|
821
|
+
}
|
|
822
|
+
/** @internal Exported for tests. */
|
|
823
|
+
function convertTools(tools, strictMode, model, onQuarantine = (toolName, schemaPath) => warn(`Tool "${toolName}" omitted from the openai-responses request: its parameter schema is invalid for this provider at ${schemaPath} (an enum/const value cannot match its declared type). Other tools are unaffected.`)) {
|
|
824
|
+
const allowFreeform = supportsFreeformApplyPatch(model);
|
|
825
|
+
const rejectXaiRootObjectUnion = model.provider === "xai" || model.provider === "xai-oauth";
|
|
826
|
+
const out = [];
|
|
827
|
+
for (const tool of tools) {
|
|
828
|
+
if (tool.native?.type === "computer" && model.supportsComputerUse === true) {
|
|
829
|
+
out.push({ type: "computer" });
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
if (allowFreeform && tool.customFormat) {
|
|
833
|
+
out.push({
|
|
834
|
+
type: "custom",
|
|
835
|
+
name: tool.customWireName ?? tool.name,
|
|
836
|
+
description: tool.description || "",
|
|
837
|
+
format: {
|
|
838
|
+
type: "grammar",
|
|
839
|
+
syntax: tool.customFormat.syntax,
|
|
840
|
+
definition: compactGrammarDefinition(tool.customFormat.syntax, tool.customFormat.definition)
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
const strict = !NO_STRICT && strictMode && tool.strict !== false;
|
|
846
|
+
const baseParameters = toolWireSchema(tool);
|
|
847
|
+
const sanitized = sanitizeSchemaForOpenAIResponses(baseParameters);
|
|
848
|
+
const providerParameters = rejectXaiRootObjectUnion ? flattenExclusiveRequiredRootUnion(sanitized) : sanitized;
|
|
849
|
+
const responseParameters = model.compat.toolSchemaFlavor === "moonshot-mfjs" ? normalizeSchemaForMoonshot(providerParameters) : providerParameters;
|
|
850
|
+
const { schema: parameters, strict: effectiveStrict } = adaptSchemaForStrict(responseParameters, strict);
|
|
851
|
+
const violation = findStrictToolSchemaViolation(parameters, "#", { rejectXaiRootObjectUnion });
|
|
852
|
+
if (violation) {
|
|
853
|
+
onQuarantine(tool.name, violation);
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
out.push({
|
|
857
|
+
type: "function",
|
|
858
|
+
name: tool.name,
|
|
859
|
+
description: tool.description || "",
|
|
860
|
+
parameters,
|
|
861
|
+
...effectiveStrict ? { strict: true } : !NO_STRICT && strictMode && tool.strict === false ? { strict: false } : {}
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
return out;
|
|
865
|
+
}
|
|
866
|
+
//#endregion
|
|
867
|
+
export { openai_responses_exports as t };
|