@yansigit/opencodex 2.31.3 → 2.33.0

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 (176) hide show
  1. package/README.md +2 -2
  2. package/bin/ocx.mjs +99 -70
  3. package/gui/dist/assets/index-DKLr4LTE.js +102 -0
  4. package/gui/dist/assets/index-DrSQdTRd.css +1 -0
  5. package/gui/dist/index.html +2 -2
  6. package/package.json +6 -5
  7. package/src/adapters/anthropic.ts +25 -13
  8. package/src/adapters/azure.ts +20 -4
  9. package/src/adapters/base.ts +5 -1
  10. package/src/adapters/command-code.ts +42 -10
  11. package/src/adapters/cursor/live-models.ts +8 -0
  12. package/src/adapters/cursor/live-transport.ts +1 -1
  13. package/src/adapters/cursor/native-exec-desktop.ts +16 -0
  14. package/src/adapters/cursor/protobuf-events.ts +158 -7
  15. package/src/adapters/cursor/protobuf-request.ts +33 -15
  16. package/src/adapters/cursor/request-builder.ts +4 -3
  17. package/src/adapters/cursor/tool-definitions.ts +27 -1
  18. package/src/adapters/cursor/types.ts +4 -3
  19. package/src/adapters/cursor.ts +9 -0
  20. package/src/adapters/google-antigravity-replay.ts +2 -2
  21. package/src/adapters/google-antigravity-wire.ts +7 -0
  22. package/src/adapters/google-errors.ts +6 -2
  23. package/src/adapters/google-http.ts +30 -7
  24. package/src/adapters/google-truncation.ts +5 -0
  25. package/src/adapters/google-wire-compiler.ts +38 -6
  26. package/src/adapters/google.ts +154 -33
  27. package/src/adapters/kiro-tools.ts +20 -9
  28. package/src/adapters/kiro.ts +0 -3
  29. package/src/adapters/openai-chat.ts +9 -0
  30. package/src/adapters/openai-responses.ts +4 -1
  31. package/src/adapters/tool-catalog-nudge.ts +1 -1
  32. package/src/adapters/xai-web-search.ts +7 -2
  33. package/src/bridge.ts +133 -24
  34. package/src/claude/context-windows.ts +16 -9
  35. package/src/cli/dispatch.ts +50 -2
  36. package/src/cli/doctor.ts +26 -13
  37. package/src/cli/help.ts +4 -3
  38. package/src/cli/index.ts +20 -6
  39. package/src/cli/models.ts +13 -3
  40. package/src/cli/observe.ts +20 -5
  41. package/src/cli/provider.ts +8 -1
  42. package/src/cli/registry.ts +7 -5
  43. package/src/cli/status.ts +25 -1
  44. package/src/cli/system-restart-client.ts +1 -1
  45. package/src/cli/usage-report.ts +134 -0
  46. package/src/codex/app-server-processes.ts +3 -1
  47. package/src/codex/auth-api.ts +4 -2
  48. package/src/codex/autostart-health.ts +16 -0
  49. package/src/codex/catalog/aggregation.ts +12 -0
  50. package/src/codex/catalog/effort.ts +42 -12
  51. package/src/codex/catalog/metadata.ts +27 -1
  52. package/src/codex/catalog/model-metadata.ts +593 -0
  53. package/src/codex/catalog/parsing.ts +71 -27
  54. package/src/codex/catalog/provider-fetch.ts +189 -33
  55. package/src/codex/catalog/sync.ts +6 -5
  56. package/src/codex/convergence.ts +5 -0
  57. package/src/codex/desktop-app-restart.ts +342 -0
  58. package/src/codex/history-job.ts +32 -3
  59. package/src/codex/history-manifest.ts +112 -0
  60. package/src/codex/history-migration-guardian.ts +5 -5
  61. package/src/codex/history-provider.ts +825 -247
  62. package/src/codex/history-worker.ts +8 -5
  63. package/src/codex/inject.ts +49 -21
  64. package/src/codex/injected-marker.ts +1 -1
  65. package/src/codex/internal/history-writer.ts +4 -3
  66. package/src/codex/native-profile-startup.ts +157 -27
  67. package/src/codex/native-residue.ts +26 -33
  68. package/src/codex/shim.ts +56 -3
  69. package/src/combos/failover.ts +27 -0
  70. package/src/compatibility/index.ts +26 -0
  71. package/src/compatibility/manifest.ts +253 -0
  72. package/src/compatibility/openai-responses.ts +81 -0
  73. package/src/config/atomic-write.ts +219 -0
  74. package/src/config/paths.ts +40 -0
  75. package/src/config/process-state.ts +308 -0
  76. package/src/config/provider-validation.ts +214 -0
  77. package/src/config.ts +153 -814
  78. package/src/generated/compatibility-version.json +232 -148
  79. package/src/images/loop.ts +37 -6
  80. package/src/images/plan.ts +5 -4
  81. package/src/integrations/ownership-policy.ts +141 -0
  82. package/src/integrations/ownership.ts +10 -0
  83. package/src/integrations/state.ts +44 -5
  84. package/src/integrations/writer.ts +6 -0
  85. package/src/lib/azure-identity.ts +154 -0
  86. package/src/lib/bounded-body.ts +14 -2
  87. package/src/lib/debug.ts +42 -0
  88. package/src/lib/errors.ts +14 -0
  89. package/src/lib/process-control.ts +2 -1
  90. package/src/lib/provider-outbound.ts +45 -33
  91. package/src/lib/provider-tls-profile.ts +309 -0
  92. package/src/lib/proxy-env.ts +49 -0
  93. package/src/lib/redact.ts +10 -1
  94. package/src/lib/state-store-registrations.ts +2 -0
  95. package/src/lib/tool-argument-integers.ts +56 -5
  96. package/src/oauth/antigravity-routing.ts +282 -236
  97. package/src/oauth/callback-server.ts +22 -2
  98. package/src/oauth/command-code.ts +5 -16
  99. package/src/oauth/google-antigravity.ts +42 -5
  100. package/src/oauth/health.ts +1 -1
  101. package/src/oauth/index.ts +15 -3
  102. package/src/oauth/kimi.ts +9 -1
  103. package/src/oauth/open-browser-choice.ts +26 -0
  104. package/src/oauth/store.ts +6 -0
  105. package/src/providers/antigravity-quota.ts +3 -1
  106. package/src/providers/api-keys.ts +2 -1
  107. package/src/providers/auto-compact-budget.ts +65 -0
  108. package/src/providers/derive.ts +4 -0
  109. package/src/providers/key-failover.ts +5 -1
  110. package/src/providers/openai-tiers.ts +5 -0
  111. package/src/providers/provider-id-rewrite.ts +1 -0
  112. package/src/providers/quota.ts +59 -13
  113. package/src/providers/registry.ts +4 -2
  114. package/src/providers/request-pacing.ts +33 -6
  115. package/src/providers/xai-transport.ts +21 -0
  116. package/src/reasoning-effort.ts +19 -2
  117. package/src/responses/apply-patch-envelope.ts +63 -0
  118. package/src/responses/custom-tool-compat.ts +132 -38
  119. package/src/responses/google-provider-options.ts +36 -0
  120. package/src/responses/namespace-tool-compat.ts +84 -4
  121. package/src/responses/parser.ts +14 -2
  122. package/src/responses/provider-opaque-metadata.ts +3 -3
  123. package/src/responses/reasoning-replay-cache.ts +81 -3
  124. package/src/responses/schema.ts +37 -0
  125. package/src/responses/state.ts +94 -4
  126. package/src/router.ts +8 -2
  127. package/src/server/auth-cors.ts +37 -7
  128. package/src/server/images.ts +19 -35
  129. package/src/server/index.ts +102 -21
  130. package/src/server/local-management-read-client.ts +1 -1
  131. package/src/server/local-provider-reload-client.ts +1 -1
  132. package/src/server/management/agent-settings-routes.ts +206 -16
  133. package/src/server/management/combo-routes.ts +6 -0
  134. package/src/server/management/config-routes.ts +35 -6
  135. package/src/server/management/context.ts +1 -1
  136. package/src/server/management/logs-usage-routes.ts +27 -6
  137. package/src/server/management/model-routes.ts +8 -4
  138. package/src/server/management/model-rows.ts +4 -0
  139. package/src/server/management/native-integration-routes.ts +2 -1
  140. package/src/server/management/oauth-account-routes.ts +25 -4
  141. package/src/server/management/provider-capability-config.ts +1 -1
  142. package/src/server/management/provider-routes.ts +113 -15
  143. package/src/server/management/routing-profile-routes.ts +3 -0
  144. package/src/server/management/system-restart.ts +1 -1
  145. package/src/server/port-reclaim.ts +1 -1
  146. package/src/server/proxy-liveness.ts +2 -1
  147. package/src/server/request-log-conversation.ts +30 -0
  148. package/src/server/request-log.ts +21 -0
  149. package/src/server/responses/agent-task-recovery.ts +1 -1
  150. package/src/server/responses/codex-auth-error.ts +55 -0
  151. package/src/server/responses/combo-stream-preflight.ts +171 -0
  152. package/src/server/responses/compact.ts +36 -22
  153. package/src/server/responses/core.ts +584 -247
  154. package/src/server/responses/empty-completion-guard.ts +35 -6
  155. package/src/server/responses/fetch-helpers.ts +20 -102
  156. package/src/server/responses/v2-native-parent-override.ts +59 -0
  157. package/src/server/responses/ws-upstream.ts +75 -2
  158. package/src/server/responses-custom-tool-repair.ts +41 -5
  159. package/src/server/responses-undeclared-tool-guard.ts +241 -18
  160. package/src/service.ts +9 -5
  161. package/src/types/config.ts +16 -1
  162. package/src/types/provider.ts +16 -0
  163. package/src/types/request.ts +34 -1
  164. package/src/types/tools.ts +114 -11
  165. package/src/types.ts +7 -1
  166. package/src/update/index.ts +5 -4
  167. package/src/update/job.ts +3 -1
  168. package/src/update/transactional-install.mjs +8 -1
  169. package/src/usage/log.ts +16 -8
  170. package/src/usage/summary.ts +201 -8
  171. package/src/vision/describe.ts +18 -13
  172. package/src/web-search/executor.ts +10 -3
  173. package/src/web-search/gemini-executor.ts +6 -4
  174. package/src/web-search/loop.ts +42 -6
  175. package/gui/dist/assets/index-CGoDO3uO.css +0 -1
  176. package/gui/dist/assets/index-Cxt5fZMP.js +0 -102
@@ -0,0 +1,55 @@
1
+ import { formatErrorResponse } from "../../bridge";
2
+ import {
3
+ CodexAccountCooldownError,
4
+ codexMainProfileDrainingResponse,
5
+ cooldownErrorResponse,
6
+ CodexAuthContextError,
7
+ CodexDirectAuthenticationError,
8
+ CodexMainProfileDrainingError,
9
+ CodexMainSubstitutionUnavailableError,
10
+ CodexPoolAuthenticationError,
11
+ CodexThreadAffinityExpiredError,
12
+ } from "../../codex/auth-context";
13
+
14
+ export interface CodexAuthContextErrorResponseOptions {
15
+ accountSelector?: string;
16
+ now: number;
17
+ }
18
+
19
+ /** Shared HTTP contract for Codex auth-context failures on Responses surfaces. */
20
+ export function mapCodexAuthContextErrorToResponse(
21
+ error: unknown,
22
+ options: CodexAuthContextErrorResponseOptions,
23
+ ): Response | undefined {
24
+ if (error instanceof CodexAccountCooldownError) {
25
+ return cooldownErrorResponse(error, options.now, options.accountSelector);
26
+ }
27
+ if (error instanceof CodexMainProfileDrainingError) {
28
+ return codexMainProfileDrainingResponse();
29
+ }
30
+ if (error instanceof CodexThreadAffinityExpiredError) {
31
+ return formatErrorResponse(
32
+ 409,
33
+ "invalid_request_error",
34
+ "Codex thread account affinity expired; start a new session",
35
+ );
36
+ }
37
+ if (error instanceof CodexAuthContextError) {
38
+ return formatErrorResponse(
39
+ 401,
40
+ "authentication_error",
41
+ "Selected Codex account needs reauthentication",
42
+ );
43
+ }
44
+ if (error instanceof CodexPoolAuthenticationError || error instanceof CodexDirectAuthenticationError) {
45
+ return formatErrorResponse(401, "authentication_error", error.message);
46
+ }
47
+ if (error instanceof CodexMainSubstitutionUnavailableError) {
48
+ return formatErrorResponse(
49
+ 401,
50
+ "authentication_error",
51
+ "No usable Codex main credential to serve this request",
52
+ );
53
+ }
54
+ return undefined;
55
+ }
@@ -0,0 +1,171 @@
1
+ import type { ResponsesTerminalStatus } from "../../bridge";
2
+ import type { RequestLogContext } from "../request-log";
3
+ import { createSseInspector } from "../relay";
4
+ import { MAX_CLIENT_SSE_FRAME_BYTES } from "../sse-frame-buffer";
5
+
6
+ const COMBO_STREAM_PREFLIGHT_MAX_BYTES = MAX_CLIENT_SSE_FRAME_BYTES;
7
+
8
+ const PRE_OUTPUT_CONTROL_EVENTS = new Set([
9
+ "response.created",
10
+ "response.in_progress",
11
+ "response.queued",
12
+ "response.heartbeat",
13
+ ]);
14
+
15
+ const TERMINAL_EVENTS = new Set([
16
+ "response.completed",
17
+ "response.failed",
18
+ "response.incomplete",
19
+ ]);
20
+
21
+ /**
22
+ * Decide when replaying the request on another combo target would risk duplicating
23
+ * client-visible output or a tool-side effect. Unknown event types commit the child
24
+ * conservatively; only the small Responses lifecycle preamble remains replayable.
25
+ */
26
+ export function comboStreamPayloadCommitsOutput(payload: unknown): boolean {
27
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) return true;
28
+ const type = (payload as { type?: unknown }).type;
29
+ if (typeof type !== "string") return true;
30
+ return !PRE_OUTPUT_CONTROL_EVENTS.has(type) && !TERMINAL_EVENTS.has(type);
31
+ }
32
+
33
+ function replayBufferedResponse(
34
+ response: Response,
35
+ reader: ReadableStreamDefaultReader<Uint8Array>,
36
+ buffered: Uint8Array[],
37
+ ): Response {
38
+ let index = 0;
39
+ const body = new ReadableStream<Uint8Array>({
40
+ async pull(controller) {
41
+ if (index < buffered.length) {
42
+ controller.enqueue(buffered[index++]!);
43
+ return;
44
+ }
45
+ try {
46
+ const next = await reader.read();
47
+ if (next.done) controller.close();
48
+ else controller.enqueue(next.value);
49
+ } catch (error) {
50
+ try { controller.error(error); } catch { /* consumer already closed */ }
51
+ }
52
+ },
53
+ cancel(reason) {
54
+ reader.cancel(reason).catch(() => undefined);
55
+ },
56
+ });
57
+ return new Response(body, {
58
+ status: response.status,
59
+ statusText: response.statusText,
60
+ headers: response.headers,
61
+ });
62
+ }
63
+
64
+ function failedTerminalResponse(
65
+ response: Response,
66
+ terminalPayload: Record<string, unknown>,
67
+ logCtx: RequestLogContext,
68
+ ): Response {
69
+ const nested = terminalPayload.response;
70
+ const terminalResponse = nested && typeof nested === "object" && !Array.isArray(nested)
71
+ ? nested as Record<string, unknown>
72
+ : {};
73
+ const nestedError = terminalResponse.error;
74
+ const error = nestedError && typeof nestedError === "object" && !Array.isArray(nestedError)
75
+ ? nestedError as Record<string, unknown>
76
+ : {
77
+ type: "upstream_error",
78
+ code: "upstream_server_error",
79
+ message: logCtx.upstreamError ?? "Provider stream failed before producing output",
80
+ };
81
+ const headers = new Headers(response.headers);
82
+ headers.set("content-type", "application/json");
83
+ headers.delete("content-length");
84
+ headers.delete("content-encoding");
85
+ const usage = terminalResponse.usage;
86
+ return new Response(JSON.stringify({
87
+ error,
88
+ // The combo classifier needs only the error and optional usage. Do not carry
89
+ // response ids, provider metadata, or future terminal fields into the client
90
+ // error envelope merely because they shared the terminal snapshot.
91
+ response: {
92
+ error,
93
+ ...(usage && typeof usage === "object" && !Array.isArray(usage) ? { usage } : {}),
94
+ },
95
+ }), {
96
+ status: logCtx.terminalHttpStatus ?? 502,
97
+ headers,
98
+ });
99
+ }
100
+
101
+ export type ComboStreamPreflightResult =
102
+ | { kind: "accepted"; response: Response }
103
+ | { kind: "failed"; response: Response };
104
+
105
+ /**
106
+ * Buffer a combo child's downstream SSE only until the request becomes unsafe to
107
+ * replay or reaches a terminal. This owns exactly one body reader. The aggregate
108
+ * buffer is capped; hitting the cap commits the current target instead of growing
109
+ * memory or guessing that replay is safe.
110
+ */
111
+ export async function preflightComboStreamResponse(
112
+ response: Response,
113
+ logCtx: RequestLogContext,
114
+ ): Promise<ComboStreamPreflightResult> {
115
+ const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
116
+ if (!response.ok || !response.body || !contentType.includes("text/event-stream")) {
117
+ return { kind: "accepted", response };
118
+ }
119
+
120
+ const reader = response.body.getReader();
121
+ const buffered: Uint8Array[] = [];
122
+ let bufferedBytes = 0;
123
+ let outputCommitted = false;
124
+ let terminalStatus: ResponsesTerminalStatus | undefined;
125
+ let failedPayload: Record<string, unknown> | undefined;
126
+ const inspector = createSseInspector({
127
+ logCtx,
128
+ onParsedPayload: payload => {
129
+ if (comboStreamPayloadCommitsOutput(payload)) outputCommitted = true;
130
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) return;
131
+ if ((payload as { type?: unknown }).type === "response.failed") {
132
+ failedPayload = payload as Record<string, unknown>;
133
+ }
134
+ },
135
+ onTerminal: status => { terminalStatus = status; },
136
+ });
137
+
138
+ try {
139
+ for (;;) {
140
+ const next = await reader.read();
141
+ if (next.done) {
142
+ inspector.finish();
143
+ } else {
144
+ if (bufferedBytes + next.value.byteLength > COMBO_STREAM_PREFLIGHT_MAX_BYTES) {
145
+ // Keep the cap about memory the preflight allocates. The upstream chunk already exists;
146
+ // copying it before committing would transiently exceed the boundary for no
147
+ // replay benefit. Preserve it unsliced behind the already-bounded prefix.
148
+ return {
149
+ kind: "accepted",
150
+ response: replayBufferedResponse(response, reader, [...buffered, next.value]),
151
+ };
152
+ }
153
+ const retained = next.value.slice();
154
+ buffered.push(retained);
155
+ bufferedBytes += retained.byteLength;
156
+ inspector.feed(retained);
157
+ }
158
+
159
+ if (terminalStatus === "failed" && !outputCommitted && failedPayload) {
160
+ await reader.cancel("retrying zero-output combo stream failure").catch(() => undefined);
161
+ return { kind: "failed", response: failedTerminalResponse(response, failedPayload, logCtx) };
162
+ }
163
+ if (next.done || terminalStatus !== undefined || outputCommitted
164
+ || bufferedBytes >= COMBO_STREAM_PREFLIGHT_MAX_BYTES) {
165
+ return { kind: "accepted", response: replayBufferedResponse(response, reader, buffered) };
166
+ }
167
+ }
168
+ } finally {
169
+ inspector.dispose();
170
+ }
171
+ }
@@ -42,17 +42,9 @@ import { describeImagesInPlace, planVisionSidecar, shouldResolveOpenAiVisionSide
42
42
  import { createAdapterEventQueue, preflightAdapterEvents } from "../../adapters/run-turn-queue";
43
43
  import {
44
44
  applyCodexAuthContextToProvider,
45
- CodexAccountCooldownError,
46
- codexMainProfileDrainingResponse,
47
- cooldownErrorResponse,
48
- CodexAuthContextError,
49
- CodexDirectAuthenticationError,
50
45
  CodexMainProfileDrainingError,
51
- CodexPoolAuthenticationError,
52
- CodexThreadAffinityExpiredError,
53
46
  headersForCodexAuthContext,
54
47
  materializeCodexUpstreamAuth,
55
- CodexMainSubstitutionUnavailableError,
56
48
  isCodexAuthContextUsable,
57
49
  resolveCodexAuthContext,
58
50
  codexProbeLeaseId,
@@ -134,6 +126,8 @@ import {
134
126
  usesCodexForwardPoolAuth,
135
127
  } from "./core";
136
128
  import { fetchWithHeaderTimeout, providerFetch, safeHostLabel, safeOriginLabel } from "./fetch-helpers";
129
+ import { mapCodexAuthContextErrorToResponse } from "./codex-auth-error";
130
+ import { decideV2NativeParentOverride } from "./v2-native-parent-override";
137
131
 
138
132
  export const COMPACT_RESPONSE_MAX_BYTES = 32 * 1024 * 1024;
139
133
 
@@ -304,6 +298,31 @@ export async function handleResponsesCompact(
304
298
  }
305
299
  return formatErrorResponse(404, "invalid_request_error", err instanceof Error ? err.message : String(err));
306
300
  }
301
+ const requestedModel = raw.model;
302
+ // Populate source-route identity before the opt-in decision can fail closed. This keeps
303
+ // malformed/unavailable targets observable as the caller's route without exposing any new data.
304
+ logCtx.requestedModel = requestedModel;
305
+ logCtx.model = route.modelId;
306
+ logCtx.routeDecision = route.routeDecision;
307
+ logCtx.provider = route.codexAccountNamespace
308
+ ? `${route.providerName}-${route.codexAccountNamespace}`
309
+ : route.providerName;
310
+ logCtx.providerAdapter = route.provider.adapter;
311
+ const parentOverride = decideV2NativeParentOverride({
312
+ kind: "compact",
313
+ config,
314
+ headers: req.headers,
315
+ sourceRoute: route,
316
+ targetEvidence: evidenceFromBody(raw),
317
+ });
318
+ if (parentOverride.kind === "reject") {
319
+ if (parentOverride.trace) logCtx.routeDecision = parentOverride.trace as typeof logCtx.routeDecision;
320
+ return formatErrorResponse(404, "invalid_request_error", parentOverride.message);
321
+ }
322
+ if (parentOverride.kind === "override") {
323
+ route = parentOverride.route;
324
+ raw.model = route.modelId;
325
+ }
307
326
  const selectedModelId = route.modelId;
308
327
  // Derive from the RESOLVED route model, not the caller's raw string. An account-qualified
309
328
  // selector like `side/gpt-daybreak-blue-latest` does not match the gated map — `slugsEquivalent`
@@ -311,7 +330,7 @@ export async function handleResponsesCompact(
311
330
  // exactly the selector form back down the native compact endpoint this guard exists to avoid.
312
331
  // `route.modelId` is the same value `applyCodexAccountGatedWireNormalization` uses in core.ts.
313
332
  const accountGatedCompactWireModel = codexAccountGatedCanonicalWireModel(selectedModelId);
314
- logCtx.requestedModel = raw.model;
333
+ logCtx.requestedModel = requestedModel;
315
334
  logCtx.model = selectedModelId;
316
335
  logCtx.routeDecision = route.routeDecision;
317
336
  logCtx.provider = route.codexAccountNamespace
@@ -395,19 +414,11 @@ export async function handleResponsesCompact(
395
414
  }
396
415
  }
397
416
  } catch (err) {
398
- if (err instanceof CodexAccountCooldownError) {
399
- return cooldownErrorResponse(err, Date.now(), route.codexAccountNamespace);
400
- }
401
- if (err instanceof CodexMainProfileDrainingError) return codexMainProfileDrainingResponse();
402
- if (err instanceof CodexThreadAffinityExpiredError) {
403
- return formatErrorResponse(409, "invalid_request_error", "Codex thread account affinity expired; start a new session");
404
- }
405
- if (err instanceof CodexAuthContextError) {
406
- return formatErrorResponse(401, "authentication_error", "Selected Codex account needs reauthentication");
407
- }
408
- if (err instanceof CodexPoolAuthenticationError || err instanceof CodexDirectAuthenticationError) {
409
- return formatErrorResponse(401, "authentication_error", err.message);
410
- }
417
+ const response = mapCodexAuthContextErrorToResponse(err, {
418
+ accountSelector: route.codexAccountNamespace,
419
+ now: Date.now(),
420
+ });
421
+ if (response) return response;
411
422
  throw err;
412
423
  }
413
424
  const base = isCanonicalOpenAiForwardProvider(compactProvider)
@@ -692,6 +703,9 @@ export async function handleResponsesCompact(
692
703
  body: JSON.stringify(internalBody),
693
704
  });
694
705
  const response = await handleResponses(internalReq, config, logCtx, { abortSignal: req.signal, turnAdmissionLease, ...(admission ? { admission } : {}) });
706
+ // The internal summarizer is a routed Responses turn, but compact logs retain the
707
+ // caller's selector just like the native compact branch above.
708
+ logCtx.requestedModel = requestedModel;
695
709
  if (!response.ok) return response;
696
710
  let json: { output?: unknown[]; status?: unknown; error?: unknown };
697
711
  if (response.headers.get("content-type")?.includes("text/event-stream")) {