@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.
Files changed (119) hide show
  1. package/README.md +2 -1
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +56 -25
  4. package/dist/api/anthropic-messages.js.map +1 -1
  5. package/dist/api/anthropic-tool-pairs.d.ts +3 -0
  6. package/dist/api/anthropic-tool-pairs.d.ts.map +1 -0
  7. package/dist/api/anthropic-tool-pairs.js +134 -0
  8. package/dist/api/anthropic-tool-pairs.js.map +1 -0
  9. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  10. package/dist/api/azure-openai-responses.js +7 -3
  11. package/dist/api/azure-openai-responses.js.map +1 -1
  12. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  13. package/dist/api/bedrock-converse-stream.js +64 -4
  14. package/dist/api/bedrock-converse-stream.js.map +1 -1
  15. package/dist/api/google-generative-ai.d.ts.map +1 -1
  16. package/dist/api/google-generative-ai.js +12 -2
  17. package/dist/api/google-generative-ai.js.map +1 -1
  18. package/dist/api/google-shared.d.ts.map +1 -1
  19. package/dist/api/google-shared.js +13 -6
  20. package/dist/api/google-shared.js.map +1 -1
  21. package/dist/api/google-vertex.d.ts.map +1 -1
  22. package/dist/api/google-vertex.js +12 -2
  23. package/dist/api/google-vertex.js.map +1 -1
  24. package/dist/api/mistral-conversations.d.ts.map +1 -1
  25. package/dist/api/mistral-conversations.js +19 -10
  26. package/dist/api/mistral-conversations.js.map +1 -1
  27. package/dist/api/openai-codex-responses/fallback-state.d.ts +24 -0
  28. package/dist/api/openai-codex-responses/fallback-state.d.ts.map +1 -0
  29. package/dist/api/openai-codex-responses/fallback-state.js +70 -0
  30. package/dist/api/openai-codex-responses/fallback-state.js.map +1 -0
  31. package/dist/api/openai-codex-responses.d.ts +2 -16
  32. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  33. package/dist/api/openai-codex-responses.js +94 -105
  34. package/dist/api/openai-codex-responses.js.map +1 -1
  35. package/dist/api/openai-completions.d.ts.map +1 -1
  36. package/dist/api/openai-completions.js +19 -10
  37. package/dist/api/openai-completions.js.map +1 -1
  38. package/dist/api/openai-prompt-cache.d.ts +1 -0
  39. package/dist/api/openai-prompt-cache.d.ts.map +1 -1
  40. package/dist/api/openai-prompt-cache.js +7 -0
  41. package/dist/api/openai-prompt-cache.js.map +1 -1
  42. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  43. package/dist/api/openai-responses-shared.js +11 -1
  44. package/dist/api/openai-responses-shared.js.map +1 -1
  45. package/dist/api/openai-responses.d.ts.map +1 -1
  46. package/dist/api/openai-responses.js +9 -5
  47. package/dist/api/openai-responses.js.map +1 -1
  48. package/dist/api/openrouter-images.js +3 -2
  49. package/dist/api/openrouter-images.js.map +1 -1
  50. package/dist/api/pi-messages.js +2 -2
  51. package/dist/api/pi-messages.js.map +1 -1
  52. package/dist/api/simple-options.d.ts.map +1 -1
  53. package/dist/api/simple-options.js +1 -0
  54. package/dist/api/simple-options.js.map +1 -1
  55. package/dist/auth/oauth/openrouter.d.ts +3 -1
  56. package/dist/auth/oauth/openrouter.d.ts.map +1 -1
  57. package/dist/auth/oauth/openrouter.js +81 -26
  58. package/dist/auth/oauth/openrouter.js.map +1 -1
  59. package/dist/auth/resolve.d.ts +2 -0
  60. package/dist/auth/resolve.d.ts.map +1 -1
  61. package/dist/auth/resolve.js +16 -8
  62. package/dist/auth/resolve.js.map +1 -1
  63. package/dist/index.d.ts +1 -0
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +1 -0
  66. package/dist/index.js.map +1 -1
  67. package/dist/model.d.ts +2 -1
  68. package/dist/model.d.ts.map +1 -1
  69. package/dist/model.js.map +1 -1
  70. package/dist/models.d.ts +14 -0
  71. package/dist/models.d.ts.map +1 -1
  72. package/dist/models.js +95 -19
  73. package/dist/models.js.map +1 -1
  74. package/dist/providers/data/.manifest.json +1 -1
  75. package/dist/providers/data/amazon-bedrock.json +1 -1
  76. package/dist/providers/data/azure-openai-responses.json +1 -1
  77. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  78. package/dist/providers/data/fireworks.json +1 -1
  79. package/dist/providers/data/github-copilot.json +1 -1
  80. package/dist/providers/data/huggingface.json +1 -1
  81. package/dist/providers/data/mistral.json +1 -1
  82. package/dist/providers/data/openai-codex.json +1 -1
  83. package/dist/providers/data/openai.json +1 -1
  84. package/dist/providers/data/opencode-go.json +1 -1
  85. package/dist/providers/data/opencode.json +1 -1
  86. package/dist/providers/data/openrouter.json +1 -1
  87. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  88. package/dist/providers/data/qwen-token-plan.json +1 -1
  89. package/dist/providers/data/together.json +1 -1
  90. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  91. package/dist/providers/data/zai-coding-cn.json +1 -1
  92. package/dist/providers/data/zai.json +1 -1
  93. package/dist/providers/faux.d.ts.map +1 -1
  94. package/dist/providers/faux.js +4 -1
  95. package/dist/providers/faux.js.map +1 -1
  96. package/dist/providers/opencode-go.js +1 -1
  97. package/dist/providers/opencode-go.js.map +1 -1
  98. package/dist/types.d.ts +18 -1
  99. package/dist/types.d.ts.map +1 -1
  100. package/dist/types.js.map +1 -1
  101. package/dist/utils/error-body.d.ts.map +1 -1
  102. package/dist/utils/error-body.js +23 -4
  103. package/dist/utils/error-body.js.map +1 -1
  104. package/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
  105. package/dist/utils/prompt-cache-ttl.js +10 -1
  106. package/dist/utils/prompt-cache-ttl.js.map +1 -1
  107. package/dist/utils/provider-retry.d.ts +3 -0
  108. package/dist/utils/provider-retry.d.ts.map +1 -1
  109. package/dist/utils/provider-retry.js +13 -12
  110. package/dist/utils/provider-retry.js.map +1 -1
  111. package/dist/utils/retry-hint.d.ts +24 -0
  112. package/dist/utils/retry-hint.d.ts.map +1 -0
  113. package/dist/utils/retry-hint.js +233 -0
  114. package/dist/utils/retry-hint.js.map +1 -0
  115. package/dist/utils/unavailable-tool-text.d.ts +3 -0
  116. package/dist/utils/unavailable-tool-text.d.ts.map +1 -0
  117. package/dist/utils/unavailable-tool-text.js +36 -0
  118. package/dist/utils/unavailable-tool-text.js.map +1 -0
  119. 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: "stop",
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
- const retryAfterDelayMs = getRetryAfterDelayMs(response.headers);
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
- throw new Error(info.friendlyMessage || info.message);
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.thinkingLevelMap?.max !== undefined
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
- throw new CodexApiError(`Codex error: ${message || code || JSON.stringify(event)}`, {
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
- throw new CodexApiError(message || "Codex response failed", { code, payload: event });
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
- const stats = websocketDebugStats.get(sessionId);
663
- return stats ? { ...stats } : undefined;
659
+ return getWebSocketDebugStats(sessionId);
664
660
  }
665
661
  export function resetOpenAICodexWebSocketDebugStats(sessionId) {
666
- if (sessionId) {
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 = websocketSessionCache.get(sessionId);
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 entry of websocketSessionCache.values()) {
688
- closeEntry(entry);
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.delete(sessionId);
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
- const cached = websocketSessionCache.get(sessionId);
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
- websocketSessionCache.delete(sessionId);
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.delete(sessionId);
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
- websocketSessionCache.delete(sessionId);
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.set(sessionId, entry);
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
- if (websocketSessionCache.get(sessionId) === entry) {
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
- if (sessionId) {
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.set("x-client-request-id", requestId);
1315
- headers.set("session-id", requestId);
1304
+ applyOpenAICodexCacheAffinityHeaders(headers, requestId);
1316
1305
  return headers;
1317
1306
  }
1318
1307
  //# sourceMappingURL=openai-codex-responses.js.map