@code-yeongyu/senpi-ai 2026.7.31 → 2026.8.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.md +2 -1
- package/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +56 -25
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/anthropic-tool-pairs.d.ts +3 -0
- package/dist/api/anthropic-tool-pairs.d.ts.map +1 -0
- package/dist/api/anthropic-tool-pairs.js +134 -0
- package/dist/api/anthropic-tool-pairs.js.map +1 -0
- package/dist/api/azure-openai-responses.d.ts.map +1 -1
- package/dist/api/azure-openai-responses.js +7 -3
- package/dist/api/azure-openai-responses.js.map +1 -1
- package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.js +64 -4
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/api/google-generative-ai.d.ts.map +1 -1
- package/dist/api/google-generative-ai.js +12 -2
- package/dist/api/google-generative-ai.js.map +1 -1
- package/dist/api/google-shared.d.ts.map +1 -1
- package/dist/api/google-shared.js +13 -6
- package/dist/api/google-shared.js.map +1 -1
- package/dist/api/google-vertex.d.ts.map +1 -1
- package/dist/api/google-vertex.js +12 -2
- package/dist/api/google-vertex.js.map +1 -1
- package/dist/api/mistral-conversations.d.ts.map +1 -1
- package/dist/api/mistral-conversations.js +19 -10
- package/dist/api/mistral-conversations.js.map +1 -1
- package/dist/api/openai-codex-responses/fallback-state.d.ts +24 -0
- package/dist/api/openai-codex-responses/fallback-state.d.ts.map +1 -0
- package/dist/api/openai-codex-responses/fallback-state.js +70 -0
- package/dist/api/openai-codex-responses/fallback-state.js.map +1 -0
- package/dist/api/openai-codex-responses.d.ts +2 -16
- package/dist/api/openai-codex-responses.d.ts.map +1 -1
- package/dist/api/openai-codex-responses.js +94 -105
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-completions.d.ts.map +1 -1
- package/dist/api/openai-completions.js +19 -10
- package/dist/api/openai-completions.js.map +1 -1
- package/dist/api/openai-prompt-cache.d.ts +1 -0
- package/dist/api/openai-prompt-cache.d.ts.map +1 -1
- package/dist/api/openai-prompt-cache.js +7 -0
- package/dist/api/openai-prompt-cache.js.map +1 -1
- package/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/dist/api/openai-responses-shared.js +11 -1
- package/dist/api/openai-responses-shared.js.map +1 -1
- package/dist/api/openai-responses.d.ts.map +1 -1
- package/dist/api/openai-responses.js +9 -5
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/api/openrouter-images.js +3 -2
- package/dist/api/openrouter-images.js.map +1 -1
- package/dist/api/pi-messages.js +2 -2
- package/dist/api/pi-messages.js.map +1 -1
- package/dist/api/simple-options.d.ts.map +1 -1
- package/dist/api/simple-options.js +1 -0
- package/dist/api/simple-options.js.map +1 -1
- package/dist/auth/oauth/openrouter.d.ts +3 -1
- package/dist/auth/oauth/openrouter.d.ts.map +1 -1
- package/dist/auth/oauth/openrouter.js +81 -26
- package/dist/auth/oauth/openrouter.js.map +1 -1
- package/dist/auth/resolve.d.ts +2 -0
- package/dist/auth/resolve.d.ts.map +1 -1
- package/dist/auth/resolve.js +16 -8
- package/dist/auth/resolve.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/model.d.ts +2 -1
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js.map +1 -1
- package/dist/models.d.ts +14 -0
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +95 -19
- package/dist/models.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/azure-openai-responses.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/fireworks.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/huggingface.json +1 -1
- package/dist/providers/data/mistral.json +1 -1
- package/dist/providers/data/openai-codex.json +1 -1
- package/dist/providers/data/openai.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/qwen-token-plan-cn.json +1 -1
- package/dist/providers/data/qwen-token-plan.json +1 -1
- package/dist/providers/data/together.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/data/zai-coding-cn.json +1 -1
- package/dist/providers/data/zai.json +1 -1
- package/dist/providers/faux.d.ts.map +1 -1
- package/dist/providers/faux.js +4 -1
- package/dist/providers/faux.js.map +1 -1
- package/dist/providers/opencode-go.js +1 -1
- package/dist/providers/opencode-go.js.map +1 -1
- package/dist/types.d.ts +18 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/error-body.d.ts.map +1 -1
- package/dist/utils/error-body.js +23 -4
- package/dist/utils/error-body.js.map +1 -1
- package/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
- package/dist/utils/prompt-cache-ttl.js +10 -1
- package/dist/utils/prompt-cache-ttl.js.map +1 -1
- package/dist/utils/provider-retry.d.ts +3 -0
- package/dist/utils/provider-retry.d.ts.map +1 -1
- package/dist/utils/provider-retry.js +13 -12
- package/dist/utils/provider-retry.js.map +1 -1
- package/dist/utils/retry-hint.d.ts +24 -0
- package/dist/utils/retry-hint.d.ts.map +1 -0
- package/dist/utils/retry-hint.js +233 -0
- package/dist/utils/retry-hint.js.map +1 -0
- package/dist/utils/unavailable-tool-text.d.ts +3 -0
- package/dist/utils/unavailable-tool-text.d.ts.map +1 -0
- package/dist/utils/unavailable-tool-text.js +36 -0
- package/dist/utils/unavailable-tool-text.js.map +1 -0
- package/package.json +10 -6
|
@@ -6,7 +6,7 @@ function loadNodeOs() {
|
|
|
6
6
|
}
|
|
7
7
|
// NEVER convert to top-level runtime imports - breaks browser/Vite builds
|
|
8
8
|
const _os = loadNodeOs();
|
|
9
|
-
import { clampThinkingLevel, supportsXhigh } from "../models.js";
|
|
9
|
+
import { clampThinkingLevel, supportsMax, supportsXhigh } from "../models.js";
|
|
10
10
|
import { registerSessionResourceCleanup } from "../session-resources.js";
|
|
11
11
|
import { combineAbortSignals } from "../utils/abort-signals.js";
|
|
12
12
|
import { splitDeferredTools } from "../utils/deferred-tools.js";
|
|
@@ -16,10 +16,12 @@ import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
|
16
16
|
import { headersToRecord } from "../utils/headers.js";
|
|
17
17
|
import { resolveHttpProxyUrlForTarget } from "../utils/node-http-proxy.js";
|
|
18
18
|
import { extractOpenAiCodexAccountId } from "../utils/openai-codex-auth.js";
|
|
19
|
+
import { appendRetryAfterMsMarker, extract429RetryAfterMs } from "../utils/retry-hint.js";
|
|
19
20
|
import { uuidv7 } from "../utils/uuid.js";
|
|
20
21
|
import { createGrammarToolInputProperties } from "./constrained-sampling.js";
|
|
22
|
+
import { clearWebSocketFallbackState, getOrCreateWebSocketDebugStats, getWebSocketDebugStats, isWebSocketSseFallbackActive, recordWebSocketFailure, recordWebSocketSseFallback, } from "./openai-codex-responses/fallback-state.js";
|
|
21
23
|
import { buildCodexReasoning } from "./openai-codex-responses/reasoning.js";
|
|
22
|
-
import { clampOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
|
|
24
|
+
import { applyOpenAICodexCacheAffinityHeaders, clampOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
|
|
23
25
|
import { convertResponsesMessages, convertResponsesTools, processResponsesStream } from "./openai-responses-shared.js";
|
|
24
26
|
import { applyExtraBody, buildBaseOptions, clampMaxForOpenAI, OPENAI_RESPONSES_RESERVED_BODY_KEYS, } from "./simple-options.js";
|
|
25
27
|
// ============================================================================
|
|
@@ -46,6 +48,14 @@ const CODEX_RESPONSE_STATUSES = new Set([
|
|
|
46
48
|
"queued",
|
|
47
49
|
"in_progress",
|
|
48
50
|
]);
|
|
51
|
+
function assertSuccessfulOutput(output) {
|
|
52
|
+
if (output.stopReason === "pending") {
|
|
53
|
+
throw new Error("Codex stream ended without a stop reason");
|
|
54
|
+
}
|
|
55
|
+
if (output.stopReason === "error" || output.stopReason === "aborted") {
|
|
56
|
+
throw new Error(output.errorMessage || "An unknown error occurred");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
49
59
|
// ============================================================================
|
|
50
60
|
// Retry Helpers
|
|
51
61
|
// ============================================================================
|
|
@@ -61,28 +71,6 @@ function isRetryableError(status, errorText) {
|
|
|
61
71
|
}
|
|
62
72
|
return /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused/i.test(errorText);
|
|
63
73
|
}
|
|
64
|
-
function getRetryAfterDelayMs(headers) {
|
|
65
|
-
const retryAfterMs = headers.get("retry-after-ms");
|
|
66
|
-
if (retryAfterMs !== null) {
|
|
67
|
-
const millis = Number(retryAfterMs);
|
|
68
|
-
if (Number.isFinite(millis)) {
|
|
69
|
-
return Math.max(0, millis);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
const retryAfter = headers.get("retry-after");
|
|
73
|
-
if (!retryAfter) {
|
|
74
|
-
return undefined;
|
|
75
|
-
}
|
|
76
|
-
const seconds = Number(retryAfter);
|
|
77
|
-
if (Number.isFinite(seconds)) {
|
|
78
|
-
return Math.max(0, seconds * 1000);
|
|
79
|
-
}
|
|
80
|
-
const date = Date.parse(retryAfter);
|
|
81
|
-
if (!Number.isNaN(date)) {
|
|
82
|
-
return Math.max(0, date - Date.now());
|
|
83
|
-
}
|
|
84
|
-
return undefined;
|
|
85
|
-
}
|
|
86
74
|
class RetryDelayExceededError extends Error {
|
|
87
75
|
}
|
|
88
76
|
function validateRetryDelayMs(delayMs, options) {
|
|
@@ -162,7 +150,7 @@ export const stream = (model, context, options) => {
|
|
|
162
150
|
totalTokens: 0,
|
|
163
151
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
164
152
|
},
|
|
165
|
-
stopReason: "
|
|
153
|
+
stopReason: "pending",
|
|
166
154
|
timestamp: Date.now(),
|
|
167
155
|
};
|
|
168
156
|
try {
|
|
@@ -204,10 +192,11 @@ export const stream = (model, context, options) => {
|
|
|
204
192
|
startEmitted = true;
|
|
205
193
|
stream.push({ type: "start", partial: output });
|
|
206
194
|
}
|
|
207
|
-
}, httpTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, grammarToolInputProperties, options);
|
|
195
|
+
}, httpTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, accountId ?? apiKey, grammarToolInputProperties, options);
|
|
208
196
|
if (options?.signal?.aborted) {
|
|
209
197
|
throw new Error("Request was aborted");
|
|
210
198
|
}
|
|
199
|
+
assertSuccessfulOutput(output);
|
|
211
200
|
stream.push({
|
|
212
201
|
type: "done",
|
|
213
202
|
reason: output.stopReason,
|
|
@@ -267,7 +256,7 @@ export const stream = (model, context, options) => {
|
|
|
267
256
|
const headerTimeoutSignal = httpTimeoutMs !== undefined && httpTimeoutMs > 0 ? AbortSignal.timeout(httpTimeoutMs) : undefined;
|
|
268
257
|
const combinedSignal = combineAbortSignals([options?.signal, headerTimeoutSignal]);
|
|
269
258
|
try {
|
|
270
|
-
response = await fetch(resolveCodexUrl(model.baseUrl), {
|
|
259
|
+
response = await (options?.fetch ?? globalThis.fetch)(resolveCodexUrl(model.baseUrl), {
|
|
271
260
|
method: "POST",
|
|
272
261
|
headers: sseHeaders,
|
|
273
262
|
body: sseBody,
|
|
@@ -289,7 +278,14 @@ export const stream = (model, context, options) => {
|
|
|
289
278
|
}
|
|
290
279
|
const errorText = await response.text();
|
|
291
280
|
if (attempt < maxRetries && isRetryableError(response.status, errorText)) {
|
|
292
|
-
|
|
281
|
+
// Force 429 eligibility with empty body so the extractor checks
|
|
282
|
+
// only retry-after / retry-after-ms headers (matching the old
|
|
283
|
+
// getRetryAfterDelayMs behavior for all retryable statuses).
|
|
284
|
+
const retryAfterDelayMs = extract429RetryAfterMs({
|
|
285
|
+
status: 429,
|
|
286
|
+
headers: response.headers,
|
|
287
|
+
bodyText: "",
|
|
288
|
+
});
|
|
293
289
|
const delayMs = retryAfterDelayMs === undefined
|
|
294
290
|
? BASE_DELAY_MS * 2 ** attempt
|
|
295
291
|
: validateRetryDelayMs(retryAfterDelayMs, options);
|
|
@@ -302,7 +298,18 @@ export const stream = (model, context, options) => {
|
|
|
302
298
|
statusText: response.statusText,
|
|
303
299
|
});
|
|
304
300
|
const info = await parseErrorResponse(fakeResponse);
|
|
305
|
-
|
|
301
|
+
let errorMessage = info.friendlyMessage || info.message;
|
|
302
|
+
if (response.status === 429) {
|
|
303
|
+
const hintMs = extract429RetryAfterMs({
|
|
304
|
+
status: response.status,
|
|
305
|
+
headers: response.headers,
|
|
306
|
+
bodyText: errorText,
|
|
307
|
+
});
|
|
308
|
+
if (hintMs !== undefined) {
|
|
309
|
+
errorMessage = appendRetryAfterMsMarker(errorMessage, hintMs);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
throw new Error(errorMessage);
|
|
306
313
|
}
|
|
307
314
|
catch (error) {
|
|
308
315
|
if (error instanceof Error) {
|
|
@@ -336,6 +343,7 @@ export const stream = (model, context, options) => {
|
|
|
336
343
|
if (options?.signal?.aborted) {
|
|
337
344
|
throw new Error("Request was aborted");
|
|
338
345
|
}
|
|
346
|
+
assertSuccessfulOutput(output);
|
|
339
347
|
stream.push({ type: "done", reason: output.stopReason, message: output });
|
|
340
348
|
stream.end();
|
|
341
349
|
}
|
|
@@ -362,7 +370,7 @@ export const streamSimple = (model, context, options) => {
|
|
|
362
370
|
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
|
363
371
|
const reasoningEffort = clampedReasoning === "off"
|
|
364
372
|
? undefined
|
|
365
|
-
: clampedReasoning === "max" && model
|
|
373
|
+
: clampedReasoning === "max" && supportsMax(model)
|
|
366
374
|
? "max"
|
|
367
375
|
: clampMaxForOpenAI(clampedReasoning, supportsXhigh(model));
|
|
368
376
|
return stream(model, context, {
|
|
@@ -540,7 +548,12 @@ async function* mapCodexEvents(events) {
|
|
|
540
548
|
if (type === "error") {
|
|
541
549
|
const code = getCodexEventErrorCode(event);
|
|
542
550
|
const message = getCodexEventErrorMessage(event);
|
|
543
|
-
|
|
551
|
+
let errorText = `Codex error: ${message || code || JSON.stringify(event)}`;
|
|
552
|
+
const hintMs = extract429RetryAfterMs({ bodyText: JSON.stringify(event) });
|
|
553
|
+
if (hintMs !== undefined) {
|
|
554
|
+
errorText = appendRetryAfterMsMarker(errorText, hintMs);
|
|
555
|
+
}
|
|
556
|
+
throw new CodexApiError(errorText, {
|
|
544
557
|
code: code || undefined,
|
|
545
558
|
payload: event,
|
|
546
559
|
});
|
|
@@ -548,7 +561,12 @@ async function* mapCodexEvents(events) {
|
|
|
548
561
|
if (type === "response.failed") {
|
|
549
562
|
const code = getCodexEventErrorCode(event);
|
|
550
563
|
const message = getCodexEventErrorMessage(event);
|
|
551
|
-
|
|
564
|
+
let errorText = message || "Codex response failed";
|
|
565
|
+
const hintMs = extract429RetryAfterMs({ bodyText: JSON.stringify(event) });
|
|
566
|
+
if (hintMs !== undefined) {
|
|
567
|
+
errorText = appendRetryAfterMsMarker(errorText, hintMs);
|
|
568
|
+
}
|
|
569
|
+
throw new CodexApiError(errorText, { code, payload: event });
|
|
552
570
|
}
|
|
553
571
|
if (type === "response.done" || type === "response.completed" || type === "response.incomplete") {
|
|
554
572
|
const response = event.response;
|
|
@@ -637,39 +655,11 @@ const OPENAI_BETA_RESPONSES_WEBSOCKETS = "responses_websockets=2026-02-06";
|
|
|
637
655
|
const SESSION_WEBSOCKET_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
638
656
|
const SESSION_WEBSOCKET_MAX_AGE_MS = 55 * 60 * 1000;
|
|
639
657
|
const websocketSessionCache = new Map();
|
|
640
|
-
const websocketDebugStats = new Map();
|
|
641
|
-
const websocketSseFallbackSessions = new Set();
|
|
642
|
-
function getOrCreateWebSocketDebugStats(sessionId) {
|
|
643
|
-
let stats = websocketDebugStats.get(sessionId);
|
|
644
|
-
if (!stats) {
|
|
645
|
-
stats = {
|
|
646
|
-
requests: 0,
|
|
647
|
-
connectionsCreated: 0,
|
|
648
|
-
connectionsReused: 0,
|
|
649
|
-
cachedContextRequests: 0,
|
|
650
|
-
storeTrueRequests: 0,
|
|
651
|
-
fullContextRequests: 0,
|
|
652
|
-
deltaRequests: 0,
|
|
653
|
-
lastInputItems: 0,
|
|
654
|
-
websocketFailures: 0,
|
|
655
|
-
sseFallbacks: 0,
|
|
656
|
-
};
|
|
657
|
-
websocketDebugStats.set(sessionId, stats);
|
|
658
|
-
}
|
|
659
|
-
return stats;
|
|
660
|
-
}
|
|
661
658
|
export function getOpenAICodexWebSocketDebugStats(sessionId) {
|
|
662
|
-
|
|
663
|
-
return stats ? { ...stats } : undefined;
|
|
659
|
+
return getWebSocketDebugStats(sessionId);
|
|
664
660
|
}
|
|
665
661
|
export function resetOpenAICodexWebSocketDebugStats(sessionId) {
|
|
666
|
-
|
|
667
|
-
websocketDebugStats.delete(sessionId);
|
|
668
|
-
websocketSseFallbackSessions.delete(sessionId);
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
|
-
websocketDebugStats.clear();
|
|
672
|
-
websocketSseFallbackSessions.clear();
|
|
662
|
+
clearWebSocketFallbackState(sessionId);
|
|
673
663
|
}
|
|
674
664
|
export function closeOpenAICodexWebSocketSessions(sessionId) {
|
|
675
665
|
const closeEntry = (entry) => {
|
|
@@ -678,37 +668,20 @@ export function closeOpenAICodexWebSocketSessions(sessionId) {
|
|
|
678
668
|
closeWebSocketSilently(entry.socket, 1000, "debug_close");
|
|
679
669
|
};
|
|
680
670
|
if (sessionId) {
|
|
681
|
-
const entry
|
|
682
|
-
if (entry)
|
|
671
|
+
for (const entry of websocketSessionCache.get(sessionId)?.values() ?? [])
|
|
683
672
|
closeEntry(entry);
|
|
684
673
|
websocketSessionCache.delete(sessionId);
|
|
674
|
+
clearWebSocketFallbackState(sessionId);
|
|
685
675
|
return;
|
|
686
676
|
}
|
|
687
|
-
for (const
|
|
688
|
-
|
|
677
|
+
for (const accountEntries of websocketSessionCache.values()) {
|
|
678
|
+
for (const entry of accountEntries.values())
|
|
679
|
+
closeEntry(entry);
|
|
689
680
|
}
|
|
690
681
|
websocketSessionCache.clear();
|
|
682
|
+
clearWebSocketFallbackState();
|
|
691
683
|
}
|
|
692
684
|
registerSessionResourceCleanup(closeOpenAICodexWebSocketSessions);
|
|
693
|
-
function isWebSocketSseFallbackActive(sessionId) {
|
|
694
|
-
return sessionId ? websocketSseFallbackSessions.has(sessionId) : false;
|
|
695
|
-
}
|
|
696
|
-
function recordWebSocketSseFallback(sessionId) {
|
|
697
|
-
if (!sessionId)
|
|
698
|
-
return;
|
|
699
|
-
const stats = getOrCreateWebSocketDebugStats(sessionId);
|
|
700
|
-
stats.sseFallbacks++;
|
|
701
|
-
stats.websocketFallbackActive = isWebSocketSseFallbackActive(sessionId);
|
|
702
|
-
}
|
|
703
|
-
function recordWebSocketFailure(sessionId, error) {
|
|
704
|
-
if (!sessionId)
|
|
705
|
-
return;
|
|
706
|
-
websocketSseFallbackSessions.add(sessionId);
|
|
707
|
-
const stats = getOrCreateWebSocketDebugStats(sessionId);
|
|
708
|
-
stats.websocketFailures++;
|
|
709
|
-
stats.lastWebSocketError = formatThrownValue(error);
|
|
710
|
-
stats.websocketFallbackActive = true;
|
|
711
|
-
}
|
|
712
685
|
let _cachedWebsocket = null;
|
|
713
686
|
async function getWebSocketConstructor(env) {
|
|
714
687
|
if (!env && _cachedWebsocket)
|
|
@@ -784,7 +757,7 @@ function closeWebSocketSilently(socket, code = 1000, reason = "done") {
|
|
|
784
757
|
}
|
|
785
758
|
catch { }
|
|
786
759
|
}
|
|
787
|
-
function scheduleSessionWebSocketExpiry(sessionId, entry) {
|
|
760
|
+
function scheduleSessionWebSocketExpiry(sessionId, accountId, entry) {
|
|
788
761
|
if (entry.idleTimer) {
|
|
789
762
|
clearTimeout(entry.idleTimer);
|
|
790
763
|
}
|
|
@@ -792,7 +765,11 @@ function scheduleSessionWebSocketExpiry(sessionId, entry) {
|
|
|
792
765
|
if (entry.busy)
|
|
793
766
|
return;
|
|
794
767
|
closeWebSocketSilently(entry.socket, 1000, "idle_timeout");
|
|
795
|
-
websocketSessionCache.
|
|
768
|
+
const accountEntries = websocketSessionCache.get(sessionId);
|
|
769
|
+
if (accountEntries?.get(accountId) === entry)
|
|
770
|
+
accountEntries.delete(accountId);
|
|
771
|
+
if (accountEntries?.size === 0)
|
|
772
|
+
websocketSessionCache.delete(sessionId);
|
|
796
773
|
}, SESSION_WEBSOCKET_CACHE_TTL_MS);
|
|
797
774
|
}
|
|
798
775
|
async function connectWebSocket(url, headers, signal, connectTimeoutMs = DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS, env) {
|
|
@@ -863,7 +840,7 @@ async function connectWebSocket(url, headers, signal, connectTimeoutMs = DEFAULT
|
|
|
863
840
|
}
|
|
864
841
|
});
|
|
865
842
|
}
|
|
866
|
-
async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutMs, env) {
|
|
843
|
+
async function acquireWebSocket(url, headers, sessionId, accountId, signal, connectTimeoutMs, env) {
|
|
867
844
|
if (!sessionId) {
|
|
868
845
|
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);
|
|
869
846
|
return {
|
|
@@ -872,7 +849,8 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
|
|
|
872
849
|
release: () => closeWebSocketSilently(socket),
|
|
873
850
|
};
|
|
874
851
|
}
|
|
875
|
-
|
|
852
|
+
let accountEntries = websocketSessionCache.get(sessionId);
|
|
853
|
+
const cached = accountEntries?.get(accountId);
|
|
876
854
|
if (cached) {
|
|
877
855
|
if (cached.idleTimer) {
|
|
878
856
|
clearTimeout(cached.idleTimer);
|
|
@@ -880,7 +858,9 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
|
|
|
880
858
|
}
|
|
881
859
|
if (!cached.busy && isWebSocketSessionExpired(cached)) {
|
|
882
860
|
closeWebSocketSilently(cached.socket, 1000, "connection_age_limit");
|
|
883
|
-
|
|
861
|
+
accountEntries?.delete(accountId);
|
|
862
|
+
if (accountEntries?.size === 0)
|
|
863
|
+
websocketSessionCache.delete(sessionId);
|
|
884
864
|
}
|
|
885
865
|
else if (!cached.busy && isWebSocketReusable(cached.socket)) {
|
|
886
866
|
cached.busy = true;
|
|
@@ -891,11 +871,15 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
|
|
|
891
871
|
release: ({ keep } = {}) => {
|
|
892
872
|
if (!keep || !isWebSocketReusable(cached.socket)) {
|
|
893
873
|
closeWebSocketSilently(cached.socket);
|
|
894
|
-
websocketSessionCache.
|
|
874
|
+
const currentEntries = websocketSessionCache.get(sessionId);
|
|
875
|
+
if (currentEntries?.get(accountId) === cached)
|
|
876
|
+
currentEntries.delete(accountId);
|
|
877
|
+
if (currentEntries?.size === 0)
|
|
878
|
+
websocketSessionCache.delete(sessionId);
|
|
895
879
|
return;
|
|
896
880
|
}
|
|
897
881
|
cached.busy = false;
|
|
898
|
-
scheduleSessionWebSocketExpiry(sessionId, cached);
|
|
882
|
+
scheduleSessionWebSocketExpiry(sessionId, accountId, cached);
|
|
899
883
|
},
|
|
900
884
|
};
|
|
901
885
|
}
|
|
@@ -911,12 +895,19 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
|
|
|
911
895
|
}
|
|
912
896
|
if (!isWebSocketReusable(cached.socket)) {
|
|
913
897
|
closeWebSocketSilently(cached.socket);
|
|
914
|
-
|
|
898
|
+
accountEntries?.delete(accountId);
|
|
899
|
+
if (accountEntries?.size === 0)
|
|
900
|
+
websocketSessionCache.delete(sessionId);
|
|
915
901
|
}
|
|
916
902
|
}
|
|
917
903
|
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);
|
|
918
904
|
const entry = { socket, busy: true, createdAt: Date.now() };
|
|
919
|
-
websocketSessionCache.
|
|
905
|
+
accountEntries = websocketSessionCache.get(sessionId);
|
|
906
|
+
if (!accountEntries) {
|
|
907
|
+
accountEntries = new Map();
|
|
908
|
+
websocketSessionCache.set(sessionId, accountEntries);
|
|
909
|
+
}
|
|
910
|
+
accountEntries.set(accountId, entry);
|
|
920
911
|
return {
|
|
921
912
|
socket,
|
|
922
913
|
entry,
|
|
@@ -926,13 +917,15 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
|
|
|
926
917
|
closeWebSocketSilently(entry.socket);
|
|
927
918
|
if (entry.idleTimer)
|
|
928
919
|
clearTimeout(entry.idleTimer);
|
|
929
|
-
|
|
920
|
+
const currentEntries = websocketSessionCache.get(sessionId);
|
|
921
|
+
if (currentEntries?.get(accountId) === entry)
|
|
922
|
+
currentEntries.delete(accountId);
|
|
923
|
+
if (currentEntries?.size === 0)
|
|
930
924
|
websocketSessionCache.delete(sessionId);
|
|
931
|
-
}
|
|
932
925
|
return;
|
|
933
926
|
}
|
|
934
927
|
entry.busy = false;
|
|
935
|
-
scheduleSessionWebSocketExpiry(sessionId, entry);
|
|
928
|
+
scheduleSessionWebSocketExpiry(sessionId, accountId, entry);
|
|
936
929
|
},
|
|
937
930
|
};
|
|
938
931
|
}
|
|
@@ -1176,8 +1169,8 @@ async function* startWebSocketOutputOnFirstEvent(events, onStart) {
|
|
|
1176
1169
|
yield event;
|
|
1177
1170
|
}
|
|
1178
1171
|
}
|
|
1179
|
-
async function processWebSocketStream(url, body, headers, output, stream, model, onStart, idleTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, grammarToolInputProperties, options) {
|
|
1180
|
-
const { socket, entry, reused, release } = await acquireWebSocket(url, headers, cacheSessionId, options?.signal, websocketConnectTimeoutMs, options?.env);
|
|
1172
|
+
async function processWebSocketStream(url, body, headers, output, stream, model, onStart, idleTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, accountId, grammarToolInputProperties, options) {
|
|
1173
|
+
const { socket, entry, reused, release } = await acquireWebSocket(url, headers, cacheSessionId, accountId, options?.signal, websocketConnectTimeoutMs, options?.env);
|
|
1181
1174
|
let keepConnection = true;
|
|
1182
1175
|
const useCachedContext = options?.transport === "websocket-cached" || options?.transport === "auto";
|
|
1183
1176
|
// ChatGPT Codex Responses rejects `store: true` ("Store must be set to false").
|
|
@@ -1298,10 +1291,7 @@ function buildSSEHeaders(initHeaders, additionalHeaders, accountId, token, sessi
|
|
|
1298
1291
|
headers.set("OpenAI-Beta", "responses=experimental");
|
|
1299
1292
|
headers.set("accept", "text/event-stream");
|
|
1300
1293
|
headers.set("content-type", "application/json");
|
|
1301
|
-
|
|
1302
|
-
headers.set("session-id", sessionId);
|
|
1303
|
-
headers.set("x-client-request-id", sessionId);
|
|
1304
|
-
}
|
|
1294
|
+
applyOpenAICodexCacheAffinityHeaders(headers, sessionId);
|
|
1305
1295
|
return headers;
|
|
1306
1296
|
}
|
|
1307
1297
|
function buildWebSocketHeaders(initHeaders, additionalHeaders, accountId, token, requestId) {
|
|
@@ -1311,8 +1301,7 @@ function buildWebSocketHeaders(initHeaders, additionalHeaders, accountId, token,
|
|
|
1311
1301
|
headers.delete("OpenAI-Beta");
|
|
1312
1302
|
headers.delete("openai-beta");
|
|
1313
1303
|
headers.set("OpenAI-Beta", OPENAI_BETA_RESPONSES_WEBSOCKETS);
|
|
1314
|
-
headers
|
|
1315
|
-
headers.set("session-id", requestId);
|
|
1304
|
+
applyOpenAICodexCacheAffinityHeaders(headers, requestId);
|
|
1316
1305
|
return headers;
|
|
1317
1306
|
}
|
|
1318
1307
|
//# sourceMappingURL=openai-codex-responses.js.map
|