@bitkyc08/opencodex 2.52.0-preview.20260912 → 2.53.0-preview.20260913

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 (236) hide show
  1. package/gui/dist/assets/index-BBOZWGB6.css +1 -0
  2. package/gui/dist/assets/index-D7ynYo2K.js +128 -0
  3. package/gui/dist/index.html +2 -2
  4. package/native/remote-workspace-helper/Cargo.lock +130 -0
  5. package/native/remote-workspace-helper/Cargo.toml +24 -0
  6. package/native/remote-workspace-helper/src/main.rs +49 -0
  7. package/native/remote-workspace-helper/src/protocol.rs +246 -0
  8. package/native/remote-workspace-helper/src/sandbox/macos.rs +19 -0
  9. package/native/remote-workspace-helper/src/sandbox/mod.rs +77 -0
  10. package/native/remote-workspace-helper/src/sandbox/windows.rs +15 -0
  11. package/package.json +6 -1
  12. package/src/adapters/anthropic-image-normalize.ts +30 -2
  13. package/src/adapters/anthropic.ts +1 -1
  14. package/src/adapters/base.ts +8 -2
  15. package/src/adapters/cursor/cursor-errors.ts +12 -0
  16. package/src/adapters/cursor/thread-continuity.ts +93 -0
  17. package/src/adapters/cursor.ts +104 -73
  18. package/src/adapters/devin/cloud-direct/chat.ts +312 -23
  19. package/src/adapters/devin/cloud-direct/metadata.ts +31 -2
  20. package/src/adapters/devin/live-models.ts +70 -3
  21. package/src/adapters/devin.ts +281 -21
  22. package/src/adapters/google-wire-compiler.ts +14 -6
  23. package/src/adapters/google.ts +22 -8
  24. package/src/adapters/kiro/adapter.ts +316 -0
  25. package/src/adapters/kiro/conversation.ts +136 -0
  26. package/src/adapters/kiro/payload.ts +432 -0
  27. package/src/adapters/kiro/reasoning.ts +56 -0
  28. package/src/adapters/kiro/stream.ts +1153 -0
  29. package/src/adapters/kiro/usage.ts +223 -0
  30. package/src/adapters/kiro/wire.ts +76 -0
  31. package/src/adapters/kiro.ts +8 -2319
  32. package/src/adapters/mimo-free.ts +1 -1
  33. package/src/adapters/openai-chat-images.ts +101 -0
  34. package/src/adapters/openai-chat.ts +201 -181
  35. package/src/adapters/openai-responses.ts +92 -224
  36. package/src/adapters/registry.ts +0 -7
  37. package/src/adapters/run-turn-queue.ts +13 -6
  38. package/src/bridge.ts +14 -15
  39. package/src/chat/inbound.ts +29 -4
  40. package/src/chat/outbound.ts +145 -107
  41. package/src/claude/desktop-profile.ts +4 -6
  42. package/src/cli/account-api.ts +14 -0
  43. package/src/cli/account-extended.ts +1 -1
  44. package/src/cli/account-history.ts +60 -0
  45. package/src/cli/account-main.ts +80 -0
  46. package/src/cli/account.ts +11 -3
  47. package/src/cli/capabilities.ts +113 -0
  48. package/src/cli/catalog.ts +109 -0
  49. package/src/cli/dispatch.ts +9 -0
  50. package/src/cli/help.ts +2 -0
  51. package/src/cli/index.ts +2 -2
  52. package/src/cli/observe.ts +28 -1
  53. package/src/cli/opencode.ts +42 -8
  54. package/src/cli/provider-runtime.ts +11 -1
  55. package/src/cli/provider.ts +22 -2
  56. package/src/cli/registry.ts +21 -0
  57. package/src/cli/remote-workspace.ts +154 -0
  58. package/src/cli/status.ts +39 -7
  59. package/src/cli/usage-report.ts +14 -2
  60. package/src/client/hub-client.ts +34 -0
  61. package/src/client/hub-state.ts +9 -1
  62. package/src/codex/account-store.ts +78 -0
  63. package/src/codex/auth-api.ts +81 -54
  64. package/src/codex/auth-context.ts +45 -16
  65. package/src/codex/catalog/effort.ts +1 -1
  66. package/src/codex/catalog/metadata.ts +3 -6
  67. package/src/codex/catalog/native-models.ts +4 -4
  68. package/src/codex/catalog/parsing.ts +2 -20
  69. package/src/codex/catalog/provider-fetch.ts +10 -1
  70. package/src/codex/catalog/remote.ts +233 -0
  71. package/src/codex/catalog/sync.ts +403 -35
  72. package/src/codex/convergence.ts +1 -1
  73. package/src/codex/history-manifest.ts +36 -0
  74. package/src/codex/history-provider.ts +32 -5
  75. package/src/codex/inject.ts +9 -0
  76. package/src/codex/main-account.ts +113 -0
  77. package/src/codex/main-device-reauth-api.ts +89 -0
  78. package/src/codex/main-device-reauth.ts +217 -0
  79. package/src/codex/native-residue.ts +9 -2
  80. package/src/codex/quota-auto-refresh.ts +3 -2
  81. package/src/codex/quota-capacity.ts +98 -0
  82. package/src/codex/quota-history.ts +160 -0
  83. package/src/codex/quota-types.ts +8 -0
  84. package/src/codex/quota.ts +118 -91
  85. package/src/codex/refresh.ts +2 -1
  86. package/src/codex/routing.ts +90 -17
  87. package/src/codex/sync.ts +33 -4
  88. package/src/combos/request.ts +19 -1
  89. package/src/config/multi-agent-surface.ts +61 -0
  90. package/src/config/provider-validation.ts +176 -0
  91. package/src/config.ts +213 -11
  92. package/src/generated/compatibility-version.json +436 -168
  93. package/src/images/loop.ts +119 -36
  94. package/src/lib/admission.ts +12 -6
  95. package/src/lib/redact.ts +7 -0
  96. package/src/lib/translator-budget.ts +4 -3
  97. package/src/lib/windows-atomic-replace.ts +1 -0
  98. package/src/lib/windows-elevation.ts +1 -1
  99. package/src/oauth/chatgpt-device.ts +62 -5
  100. package/src/oauth/devin/cli-import.ts +130 -0
  101. package/src/oauth/devin.ts +63 -8
  102. package/src/oauth/index.ts +29 -14
  103. package/src/oauth/kiro.ts +18 -6
  104. package/src/oauth/login-cli.ts +9 -1
  105. package/src/oauth/meta-muse-device.ts +464 -0
  106. package/src/oauth/meta-muse.ts +123 -32
  107. package/src/oauth/pool-kernel.ts +9 -0
  108. package/src/oauth/pool-settings-capability.ts +2 -2
  109. package/src/oauth/store.ts +57 -0
  110. package/src/oauth/types.ts +31 -0
  111. package/src/providers/derive.ts +13 -3
  112. package/src/providers/devin-cli-authmode-migration.ts +57 -35
  113. package/src/providers/devin-provider-merge-migration.ts +240 -0
  114. package/src/providers/muse-key-quota.ts +117 -0
  115. package/src/providers/muse-subscription-usage.ts +14 -2
  116. package/src/providers/openai-sidecar.ts +25 -3
  117. package/src/providers/opencode-zen-rate-limit.ts +58 -0
  118. package/src/providers/provider-id-rewrite.ts +20 -5
  119. package/src/providers/quota-types.ts +12 -0
  120. package/src/providers/quota.ts +143 -102
  121. package/src/providers/reasoning-metadata.ts +543 -0
  122. package/src/providers/registry.ts +80 -49
  123. package/src/reasoning-effort.ts +26 -2
  124. package/src/remote/hub-usage.ts +32 -0
  125. package/src/remote-control/index.ts +192 -41
  126. package/src/remote-control/workspace-activation.ts +9 -0
  127. package/src/remote-control/workspace-agent-connection.ts +366 -0
  128. package/src/remote-control/workspace-claude-runtime.ts +243 -0
  129. package/src/remote-control/workspace-codex-runtime.ts +531 -0
  130. package/src/remote-control/workspace-codex-sandbox.ts +115 -0
  131. package/src/remote-control/workspace-command-runner.ts +748 -0
  132. package/src/remote-control/workspace-coordinator.ts +231 -0
  133. package/src/remote-control/workspace-device.ts +585 -0
  134. package/src/remote-control/workspace-executable.ts +43 -0
  135. package/src/remote-control/workspace-executor.ts +397 -0
  136. package/src/remote-control/workspace-hub.ts +519 -0
  137. package/src/remote-control/workspace-pi-runtime.ts +382 -0
  138. package/src/remote-control/workspace-process.ts +129 -0
  139. package/src/remote-control/workspace-rpc.ts +304 -0
  140. package/src/remote-control/workspace-runtime.ts +60 -0
  141. package/src/remote-control/workspace-secret-store.ts +39 -0
  142. package/src/remote-control/workspace-sessions.ts +799 -0
  143. package/src/remote-control/workspace-tool-bridge.ts +192 -0
  144. package/src/responses/code-mode-helper-compat.ts +22 -3
  145. package/src/responses/hosted-tool-policy.ts +0 -1
  146. package/src/responses/muse-tool-name-alias.ts +379 -0
  147. package/src/responses/plaintext-v2-agent-messages.ts +902 -0
  148. package/src/router.ts +7 -0
  149. package/src/routing/compatibility/behavior.ts +0 -1
  150. package/src/server/audio-client.ts +64 -0
  151. package/src/server/audio-dictation.ts +91 -0
  152. package/src/server/audio-live.ts +185 -0
  153. package/src/server/audio-transcriptions.ts +183 -0
  154. package/src/server/audio-upstream.ts +153 -0
  155. package/src/server/auth-cors.ts +61 -2
  156. package/src/server/chat-completions.ts +1 -1
  157. package/src/server/chat-native-sse.ts +92 -48
  158. package/src/server/chat-native.ts +37 -15
  159. package/src/server/hub-usage.ts +57 -0
  160. package/src/server/images.ts +4 -0
  161. package/src/server/index.ts +722 -57
  162. package/src/server/lifecycle.ts +5 -6
  163. package/src/server/live-call-bindings.ts +60 -0
  164. package/src/server/live.ts +12 -1
  165. package/src/server/management/agent-settings-routes.ts +25 -4
  166. package/src/server/management/api-access.ts +37 -0
  167. package/src/server/management/api-key-usage.ts +7 -2
  168. package/src/server/management/config-routes.ts +1 -18
  169. package/src/server/management/context.ts +15 -0
  170. package/src/server/management/logs-usage-routes.ts +2 -0
  171. package/src/server/management/oauth-account-routes.ts +39 -12
  172. package/src/server/management/provider-routes.ts +125 -2
  173. package/src/server/management/remote-workspace-routes.ts +140 -0
  174. package/src/server/management/route-registry.ts +15 -0
  175. package/src/server/management/usage-aggregate-cache.ts +14 -15
  176. package/src/server/management/usage-summary-cache.ts +2 -0
  177. package/src/server/management-api.ts +23 -0
  178. package/src/server/ports.ts +17 -0
  179. package/src/server/relay-eager.ts +4 -1
  180. package/src/server/relay.ts +70 -10
  181. package/src/server/request-decompress.ts +6 -3
  182. package/src/server/responses/agent-task-recovery.ts +25 -32
  183. package/src/server/responses/codex-auth-error.ts +11 -0
  184. package/src/server/responses/codex-ws-exchange.ts +52 -3
  185. package/src/server/responses/codex-ws-wire.ts +55 -0
  186. package/src/server/responses/compact.ts +9 -1
  187. package/src/server/responses/core.ts +337 -73
  188. package/src/server/responses/encrypted-payload.ts +45 -2
  189. package/src/server/responses/ws-upstream.ts +4 -1
  190. package/src/server/responses-self-named-namespace-scrub.ts +1 -3
  191. package/src/server/responses-undeclared-tool-guard.ts +1 -1
  192. package/src/server/search.ts +3 -0
  193. package/src/server/sse-payload-rewrite.ts +136 -51
  194. package/src/server/ws-bridge.ts +35 -1
  195. package/src/service/cli.ts +372 -0
  196. package/src/service/diagnostics.ts +340 -0
  197. package/src/service/guards.ts +303 -0
  198. package/src/service/health.ts +222 -0
  199. package/src/service/launchd.ts +853 -0
  200. package/src/service/orchestration.ts +617 -0
  201. package/src/service/repair.ts +334 -0
  202. package/src/service/state.ts +363 -0
  203. package/src/service/systemd.ts +229 -0
  204. package/src/service/windows-ops.ts +690 -0
  205. package/src/service/windows-scheduler.ts +769 -0
  206. package/src/service/windows-taskxml.ts +613 -0
  207. package/src/service.ts +22 -5550
  208. package/src/storage/cleanup/db.ts +258 -0
  209. package/src/storage/cleanup/execute.ts +358 -0
  210. package/src/storage/cleanup/paths.ts +189 -0
  211. package/src/storage/cleanup/pending.ts +140 -0
  212. package/src/storage/cleanup/preview.ts +292 -0
  213. package/src/storage/cleanup/reconcile.ts +347 -0
  214. package/src/storage/cleanup/restore.ts +932 -0
  215. package/src/storage/cleanup/satellite.ts +474 -0
  216. package/src/storage/cleanup/staging.ts +129 -0
  217. package/src/storage/cleanup/types.ts +98 -0
  218. package/src/storage/cleanup.ts +49 -3127
  219. package/src/types/accounts.ts +2 -0
  220. package/src/types/config.ts +13 -12
  221. package/src/types/provider.ts +37 -0
  222. package/src/types/request.ts +2 -0
  223. package/src/types/tools.ts +17 -5
  224. package/src/types.ts +1 -0
  225. package/src/usage/expected-prices.ts +127 -0
  226. package/src/usage/log.ts +58 -1
  227. package/src/vision/eligibility.ts +13 -2
  228. package/src/web-search/loop.ts +56 -3
  229. package/gui/dist/assets/index-D_t6sCWs.js +0 -115
  230. package/gui/dist/assets/index-EdoPnm9_.css +0 -1
  231. package/src/adapters/devin-cli/acp.ts +0 -204
  232. package/src/adapters/devin-cli/adapter.ts +0 -345
  233. package/src/adapters/devin-cli/binary.ts +0 -69
  234. package/src/adapters/devin-cli/models.ts +0 -57
  235. package/src/oauth/devin-cli.ts +0 -149
  236. package/src/server/responses-reasoning-summary-rewrite.ts +0 -178
@@ -105,19 +105,27 @@ function normalizePinnedChatEffort(options: HandleNativeChatOptions): void {
105
105
  const from = typeof chatBody.reasoning_effort === "string" ? chatBody.reasoning_effort : undefined;
106
106
  logCtx.requestedEffort = from;
107
107
  // Compaction is normally excluded by native-route eligibility; preserve that boundary here too.
108
- const pinned = chatBody.compaction_trigger === undefined
108
+ const compaction = chatBody.compaction_trigger !== undefined;
109
+ const pinned = !compaction
109
110
  ? resolvePinnedEffort(route, selector, config)
110
111
  : undefined;
112
+ let normalizeForWire = false;
111
113
  if (pinned !== undefined) {
112
114
  logCtx.requestedEffort = from ? `${from}->${pinned}` : pinned;
113
115
  if (pinned === "none") delete chatBody.reasoning_effort;
114
116
  else chatBody.reasoning_effort = pinned;
115
- // The native lane historically passes caller effort through, including with caps set.
116
- // Only a newly operator-pinned value enters the cap and provider-mapping pipeline.
117
- if (effortCapAppliesTo(chatCollabSurface(chatBody), req.headers, config)) {
118
- const capped = applyChatEffortCap(chatBody, req.headers, config, supportedLadderFor(route));
119
- if (capped) logCtx.requestedEffort = `${logCtx.requestedEffort}->${capped.to}`;
117
+ normalizeForWire = true;
118
+ }
119
+ // A qualifying turn's ceiling is independent of whether an operator pin resolved.
120
+ if (effortCapAppliesTo(chatCollabSurface(chatBody), req.headers, config, compaction)) {
121
+ const capped = applyChatEffortCap(chatBody, req.headers, config, supportedLadderFor(route));
122
+ if (capped) {
123
+ logCtx.requestedEffort = `${logCtx.requestedEffort ?? capped.from}->${capped.to}`;
124
+ normalizeForWire = true;
120
125
  }
126
+ }
127
+ // Normalize operator-pinned values and cap rewrites; otherwise preserve caller spelling.
128
+ if (normalizeForWire) {
121
129
  const effort = typeof chatBody.reasoning_effort === "string" ? chatBody.reasoning_effort : undefined;
122
130
  const wireEffort = mapReasoningEffort(route.provider, route.modelId, effort);
123
131
  if (wireEffort === undefined) delete chatBody.reasoning_effort;
@@ -254,7 +262,7 @@ export async function handleNativeChatCompletions(options: HandleNativeChatOptio
254
262
  retainedRequestBytes = 0;
255
263
  };
256
264
  const retainRequest = (request: AdapterRequest) => {
257
- const bytes = new TextEncoder().encode(request.body).byteLength;
265
+ const bytes = Buffer.byteLength(request.body);
258
266
  translatorBudget.chargeRetained(bytes, { kind: "request_copies" });
259
267
  retainedRequestBytes = bytes;
260
268
  };
@@ -493,24 +501,29 @@ export async function handleNativeChatCompletions(options: HandleNativeChatOptio
493
501
  const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
494
502
  if (contentType.includes("text/event-stream") && response.body) {
495
503
  if (requestedStream) transferTurnToStream();
504
+ let terminalStatus: number | undefined;
496
505
  const stream = nativeChatSse(response.body, {
497
506
  requestedModel,
498
507
  translatorBudget,
499
508
  signal: upstream.signal,
509
+ stallTimeoutSec: config.stallTimeoutSec,
500
510
  onFirstOutput: logIds ? () => recordFirstOutput(logCtx, logIds.start) : undefined,
501
511
  onUsage: usage => {
502
512
  logCtx.usage = usage;
503
513
  attempt.usage = usage;
504
514
  },
515
+ onTerminal: (status: number, message?: string) => {
516
+ terminalStatus = status;
517
+ if (!requestedStream) return;
518
+ try {
519
+ cleanupAbort();
520
+ finishLog(status, message, "terminal");
521
+ if (status >= 400) upstream.abort();
522
+ } finally {
523
+ releaseStreamTurn();
524
+ }
525
+ },
505
526
  ...(requestedStream ? {
506
- onTerminal: (status: number, message?: string) => {
507
- try {
508
- cleanupAbort();
509
- finishLog(status, message, "terminal");
510
- } finally {
511
- releaseStreamTurn();
512
- }
513
- },
514
527
  onCancel: () => {
515
528
  try {
516
529
  cleanupAbort();
@@ -535,11 +548,20 @@ export async function handleNativeChatCompletions(options: HandleNativeChatOptio
535
548
  try {
536
549
  const completion = await collectChatCompletion(stream, requestedModel, translatorBudget);
537
550
  cleanupAbort();
551
+ // A cancelled native relay closes its downstream body. EOF alone must not
552
+ // promote the buffered prefix to a successful Chat completion. A terminal
553
+ // already accepted by the relay retains precedence over a later abort.
554
+ if (req.signal.aborted && terminalStatus === undefined) {
555
+ return fail(499, "Client cancelled request", "client_cancelled");
556
+ }
538
557
  finishLog(200);
539
558
  return Response.json(completion);
540
559
  } catch (error) {
541
560
  cleanupAbort();
542
561
  upstream.abort();
562
+ if (req.signal.aborted && terminalStatus === undefined) {
563
+ return fail(499, "Client cancelled request", "client_cancelled");
564
+ }
543
565
  if (isChatCompletionsStreamError(error)) {
544
566
  return fail(error.status, error.message, error.type, error.code);
545
567
  }
@@ -0,0 +1,57 @@
1
+ import type { OcxConfig } from "../types";
2
+ import { MAX_HUB_USAGE_BYTES, parseHubUsage } from "../remote/hub-usage";
3
+ import { parseRange, parseUsageSurface, USAGE_RANGES, USAGE_SURFACES } from "../usage/summary";
4
+ import { parseUsageTimeWindow } from "../usage/time-range";
5
+ import { getFilteredUsageAggregate } from "./management/usage-aggregate-cache";
6
+ import { isAllowedRequestOrigin, resolveDataPlaneAdmissionSecret, withCors, type RequestPolicyView } from "./auth-cors";
7
+
8
+ /** Read only the ledger rows belonging to an explicitly authenticated configured key. */
9
+ export async function handleHubUsage(req: Request, config: OcxConfig, policy: RequestPolicyView): Promise<Response> {
10
+ const reply = (body: unknown, status = 200) => withCors(Response.json(body, {
11
+ status, headers: { "cache-control": "no-store" },
12
+ }), req, policy);
13
+ const error = (code: string, message: string, status: number) => reply({ error: { code, message } }, status);
14
+ const token = req.headers.get("x-opencodex-api-key") ?? "";
15
+ const admission = resolveDataPlaneAdmissionSecret(token, config);
16
+ if (admission?.kind !== "configured") return error("hub_usage_unauthorized", "A configured client data key is required", 401);
17
+ if (!isAllowedRequestOrigin(req, policy)) return error("origin_rejected", "Cross-origin request blocked", 403);
18
+ if (config.runtimeRole !== "hub") return error("hub_usage_not_a_hub", "Usage is served here only by a hub", 404);
19
+ const keyId = admission.keyId;
20
+ // The existing aggregate filter trims IDs. Never let that normalization turn
21
+ // this authenticated identity into another configured key (or no filter).
22
+ if (!keyId || keyId.trim() !== keyId) return error("hub_usage_key_id_invalid", "Client key identity needs repair on the hub", 403);
23
+ const query = new URL(req.url).searchParams;
24
+ const allowed = new Set(["range", "surface", "provider", "model", "since", "until"]);
25
+ for (const key of query.keys()) {
26
+ if (!allowed.has(key) || query.getAll(key).length !== 1) return error("hub_usage_query_invalid", "Unknown or repeated usage option", 400);
27
+ }
28
+ const rangeInput = query.get("range") ?? "30d";
29
+ const surfaceInput = query.get("surface") ?? "all";
30
+ if (!(rangeInput === "1d" || (USAGE_RANGES as readonly string[]).includes(rangeInput))
31
+ || !(USAGE_SURFACES as readonly string[]).includes(surfaceInput)) {
32
+ return error("hub_usage_query_invalid", "Invalid usage range or surface", 400);
33
+ }
34
+ let window;
35
+ try { window = parseUsageTimeWindow(query.get("since"), query.get("until")); }
36
+ catch { return error("hub_usage_query_invalid", "Invalid usage time window", 400); }
37
+ try {
38
+ const aggregate = await getFilteredUsageAggregate({
39
+ apiKeyId: keyId, provider: query.get("provider"), model: query.get("model"),
40
+ }, window);
41
+ const current = resolveDataPlaneAdmissionSecret(token, config);
42
+ if (current?.kind !== "configured" || current.keyId !== keyId) {
43
+ return error("hub_usage_unauthorized", "The client key changed during the read", 401);
44
+ }
45
+ const summary = aggregate.accumulator.summarize(parseRange(rangeInput), Date.now(), parseUsageSurface(surfaceInput));
46
+ const body = parseHubUsage({ ...summary, schemaVersion: 1, source: "hub", scope: "client",
47
+ ...(aggregate.usageIncomplete ? { usageIncomplete: true, usageIncompleteReason: "oversized_rows" } : {}),
48
+ });
49
+ if (!body) return error("hub_usage_unavailable", "Usage could not be represented; narrow the requested range", 503);
50
+ if (Buffer.byteLength(JSON.stringify(body), "utf8") > MAX_HUB_USAGE_BYTES) {
51
+ return error("hub_usage_too_large", "Usage exceeds the response bound; narrow the requested range", 507);
52
+ }
53
+ return reply(body);
54
+ } catch {
55
+ return error("hub_usage_read_failed", "Hub usage could not be read", 503);
56
+ }
57
+ }
@@ -19,6 +19,7 @@ import {
19
19
  cooldownErrorResponse,
20
20
  CodexAuthContextError,
21
21
  CodexMainProfileDrainingError,
22
+ CodexModelAvailabilityError,
22
23
  CodexPoolAuthenticationError,
23
24
  CodexThreadAffinityExpiredError,
24
25
  } from "../codex/auth-context";
@@ -49,6 +50,7 @@ import { findXaiProvider, resolveXaiImageAuthToken } from "../images/plan";
49
50
  import { callXaiImages } from "../images/xai-client";
50
51
  import type { AdmissionLease } from "../lib/admission";
51
52
  import { codexAccountSelectionForTurn } from "./lifecycle";
53
+ import { codexModelAvailabilityErrorResponse } from "./responses/codex-auth-error";
52
54
 
53
55
  export type ImagesEndpoint = "generations" | "edits";
54
56
 
@@ -674,6 +676,8 @@ export async function handleImages(
674
676
  const safeAccountLabel = formatCodexProviderForLog("openai", err.accountId, config);
675
677
  console.error(`[images] Pool account ${safeAccountLabel} token failed; reauthentication required`);
676
678
  forwardAuthError = formatErrorResponse(401, "authentication_error", "Selected Codex account needs reauthentication");
679
+ } else if (err instanceof CodexModelAvailabilityError) {
680
+ forwardAuthError = codexModelAvailabilityErrorResponse(err);
677
681
  } else if (err instanceof CodexPoolAuthenticationError) {
678
682
  forwardAuthError = formatErrorResponse(401, "authentication_error", err.message);
679
683
  } else {