@yansigit/opencodex 2.33.1 → 2.35.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 (177) hide show
  1. package/README.md +3 -3
  2. package/gui/dist/assets/index-BjCaHxdz.js +112 -0
  3. package/gui/dist/assets/index-DLkXOXLC.css +1 -0
  4. package/gui/dist/index.html +2 -2
  5. package/package.json +1 -3
  6. package/src/adapters/anthropic.ts +79 -2
  7. package/src/adapters/command-code.ts +40 -3
  8. package/src/adapters/cursor/call-id.ts +44 -0
  9. package/src/adapters/cursor/checkpoint-store.ts +15 -10
  10. package/src/adapters/cursor/discovery.ts +60 -2
  11. package/src/adapters/cursor/effort-map.ts +79 -1
  12. package/src/adapters/cursor/envelope-echo.ts +9 -9
  13. package/src/adapters/cursor/live-models.ts +7 -2
  14. package/src/adapters/cursor/live-transport.ts +14 -0
  15. package/src/adapters/cursor/message-mapper.ts +4 -1
  16. package/src/adapters/cursor/native-exec-shell.ts +103 -6
  17. package/src/adapters/cursor/native-exec.ts +20 -0
  18. package/src/adapters/cursor/protobuf-request.ts +74 -39
  19. package/src/adapters/cursor/request-builder.ts +32 -10
  20. package/src/adapters/cursor/tool-definitions.ts +13 -10
  21. package/src/adapters/cursor/tool-result-normalize.ts +35 -3
  22. package/src/adapters/cursor/types.ts +16 -4
  23. package/src/adapters/cursor.ts +97 -70
  24. package/src/adapters/google-antigravity-replay.ts +105 -25
  25. package/src/adapters/google-antigravity-wire.ts +5 -0
  26. package/src/adapters/google-errors.ts +41 -12
  27. package/src/adapters/google-http.ts +12 -11
  28. package/src/adapters/google.ts +156 -65
  29. package/src/adapters/image.ts +1 -1
  30. package/src/adapters/kiro-constants.ts +15 -0
  31. package/src/adapters/kiro-tools.ts +43 -15
  32. package/src/adapters/kiro.ts +54 -9
  33. package/src/adapters/openai-chat.ts +286 -242
  34. package/src/adapters/openai-responses.ts +334 -24
  35. package/src/adapters/run-turn-queue.ts +36 -1
  36. package/src/adapters/tool-catalog-nudge.ts +2 -2
  37. package/src/adapters/xai-tool-schema.ts +436 -0
  38. package/src/bridge.ts +67 -26
  39. package/src/chat/inbound.ts +14 -1
  40. package/src/chat/outbound.ts +15 -7
  41. package/src/claude/agents-inject.ts +8 -1
  42. package/src/claude/outbound.ts +10 -8
  43. package/src/cli/account-api.ts +27 -7
  44. package/src/cli/account-extended.ts +10 -3
  45. package/src/cli/account.ts +29 -5
  46. package/src/cli/alias.ts +66 -0
  47. package/src/cli/claude.ts +26 -1
  48. package/src/cli/dispatch.ts +13 -1
  49. package/src/cli/help.ts +1 -0
  50. package/src/cli/index.ts +5 -0
  51. package/src/cli/init.ts +1 -0
  52. package/src/cli/models-runtime.ts +95 -0
  53. package/src/cli/models.ts +13 -7
  54. package/src/cli/provider-runtime.ts +16 -2
  55. package/src/cli/registry.ts +6 -1
  56. package/src/cli/telemetry-commands.ts +25 -0
  57. package/src/cli/v2.ts +34 -10
  58. package/src/codex/account-pause.ts +2 -1
  59. package/src/codex/account-priority.ts +3 -2
  60. package/src/codex/app-server-processes.ts +80 -6
  61. package/src/codex/auth-api.ts +48 -8
  62. package/src/codex/auth-context.ts +21 -18
  63. package/src/codex/catalog/aggregation.ts +6 -0
  64. package/src/codex/catalog/model-metadata.ts +13 -1
  65. package/src/codex/catalog/native-models.ts +5 -2
  66. package/src/codex/catalog/parsing.ts +16 -0
  67. package/src/codex/catalog/provider-fetch.ts +20 -37
  68. package/src/codex/catalog/sync.ts +127 -2
  69. package/src/codex/catalog.ts +1 -1
  70. package/src/codex/codex-write-lock.ts +3 -1
  71. package/src/codex/convergence-types.ts +1 -1
  72. package/src/codex/convergence.ts +22 -2
  73. package/src/codex/desired-state.ts +2 -2
  74. package/src/codex/desktop-app-restart.ts +18 -5
  75. package/src/codex/inject-coordination.ts +83 -0
  76. package/src/codex/inject.ts +14 -1
  77. package/src/codex/log-guard/inspect.ts +22 -4
  78. package/src/codex/model-entitlements.ts +9 -2
  79. package/src/codex/prompt-layers.ts +371 -25
  80. package/src/codex/prompt-text-probe.ts +238 -0
  81. package/src/codex/quota.ts +123 -18
  82. package/src/codex/routing.ts +9 -0
  83. package/src/codex/subagent-model-fallback.ts +198 -27
  84. package/src/codex/transition-state.ts +107 -8
  85. package/src/combos/types.ts +10 -0
  86. package/src/compatibility/openai-responses.ts +33 -1
  87. package/src/config/autonomous-remediation.ts +21 -0
  88. package/src/config/provider-validation.ts +14 -0
  89. package/src/config/rebase-provenance.ts +68 -0
  90. package/src/config.ts +191 -17
  91. package/src/generated/compatibility-version.json +229 -153
  92. package/src/images/loop.ts +5 -4
  93. package/src/lab/conformance/fixtures/protocol-v1-cases.json +1 -1
  94. package/src/lab/fabric/producer-child.ts +1 -1
  95. package/src/lib/config-ownership.ts +20 -0
  96. package/src/lib/errors.ts +11 -2
  97. package/src/lib/package-tree-integrity.ts +101 -0
  98. package/src/oauth/aistudio-credentials.ts +65 -0
  99. package/src/oauth/aistudio-native-daemon.ts +54 -0
  100. package/src/oauth/generic-account-failover.ts +231 -0
  101. package/src/oauth/index.ts +57 -5
  102. package/src/oauth/key-providers.ts +10 -1
  103. package/src/oauth/kiro.ts +45 -0
  104. package/src/oauth/login-cli.ts +19 -20
  105. package/src/oauth/types.ts +15 -0
  106. package/src/providers/codex-capacity.ts +5 -2
  107. package/src/providers/command-code-efforts.ts +38 -6
  108. package/src/providers/context-cap.ts +4 -3
  109. package/src/providers/default-aliases.ts +65 -0
  110. package/src/providers/derive.ts +28 -0
  111. package/src/providers/fastwire.ts +7 -1
  112. package/src/providers/model-presets.ts +119 -0
  113. package/src/providers/new-model-policy.ts +146 -0
  114. package/src/providers/provider-id-rewrite.ts +2 -1
  115. package/src/providers/quota.ts +73 -14
  116. package/src/providers/registry.ts +160 -68
  117. package/src/providers/slug-codec.ts +52 -0
  118. package/src/responses/code-mode-helper-compat.ts +50 -0
  119. package/src/responses/custom-tool-compat.ts +34 -10
  120. package/src/responses/parser.ts +4 -0
  121. package/src/responses/schema.ts +5 -1
  122. package/src/responses/thought-signature-replay.ts +17 -0
  123. package/src/router.ts +40 -2
  124. package/src/routing/analytics.ts +1 -0
  125. package/src/routing/quota.ts +10 -0
  126. package/src/server/auth-cors.ts +23 -0
  127. package/src/server/chat-completions.ts +24 -16
  128. package/src/server/chat-native-sse.ts +3 -3
  129. package/src/server/chat-native.ts +30 -11
  130. package/src/server/claude-messages.ts +1 -1
  131. package/src/server/effort-policy.ts +16 -0
  132. package/src/server/index.ts +152 -80
  133. package/src/server/lifecycle.ts +52 -1
  134. package/src/server/management/agent-settings-routes.ts +31 -15
  135. package/src/server/management/codex-prompt-routes.ts +570 -0
  136. package/src/server/management/combo-routes.ts +2 -1
  137. package/src/server/management/config-routes.ts +27 -9
  138. package/src/server/management/context.ts +9 -0
  139. package/src/server/management/logs-usage-routes.ts +1 -1
  140. package/src/server/management/model-routes.ts +266 -0
  141. package/src/server/management/provider-routes.ts +137 -3
  142. package/src/server/management/routing-profile-routes.ts +2 -2
  143. package/src/server/management-api.ts +2 -0
  144. package/src/server/relay-eager.ts +147 -20
  145. package/src/server/relay.ts +251 -19
  146. package/src/server/request-log-conversation.ts +21 -0
  147. package/src/server/request-log.ts +46 -20
  148. package/src/server/responses/collaboration.ts +42 -5
  149. package/src/server/responses/combo-stream-preflight.ts +10 -3
  150. package/src/server/responses/core.ts +571 -137
  151. package/src/server/responses/empty-completion-guard.ts +35 -0
  152. package/src/server/responses/fetch-helpers.ts +14 -6
  153. package/src/server/responses/input-admission.ts +3 -1
  154. package/src/server/responses/passthrough-error.ts +33 -9
  155. package/src/server/responses/responses-field-backfill.ts +105 -13
  156. package/src/server/responses/ws-upstream.ts +35 -5
  157. package/src/server/responses-custom-tool-repair.ts +52 -7
  158. package/src/server/responses-terminal-repair.ts +25 -4
  159. package/src/server/sse-frame-buffer.ts +31 -4
  160. package/src/server/ws-bridge.ts +15 -4
  161. package/src/telemetry/dispatcher.ts +44 -0
  162. package/src/telemetry/fingerprint.ts +24 -0
  163. package/src/telemetry/hook.ts +43 -0
  164. package/src/telemetry/ledger.ts +54 -0
  165. package/src/telemetry/types.ts +23 -0
  166. package/src/types/config.ts +66 -14
  167. package/src/types/provider.ts +77 -0
  168. package/src/types/request.ts +16 -10
  169. package/src/types/tools.ts +20 -25
  170. package/src/types.ts +1 -0
  171. package/src/usage/expected-prices.ts +43 -24
  172. package/src/usage/log.ts +17 -7
  173. package/src/web-search/exa-executor.ts +40 -9
  174. package/src/web-search/loop.ts +5 -4
  175. package/gui/dist/assets/index-CIDo4y4k.js +0 -102
  176. package/gui/dist/assets/index-DrSQdTRd.css +0 -1
  177. package/src/server/aistudio-ws-hub.ts +0 -295
@@ -73,6 +73,27 @@ export function inboundClientThreadIdFromRequest(headers: Headers): string | und
73
73
  );
74
74
  }
75
75
 
76
+ /**
77
+ * Fixed-size logical turn lane (#820).
78
+ *
79
+ * A lane must be as SPECIFIC as the identity available, which is the opposite of what
80
+ * `codexPoolAffinityKey` wants. Affinity deliberately prefers the parent thread so a whole
81
+ * subagent fan-out pins to one account; a lane keyed that way would put every parallel
82
+ * subagent of one parent into a single lane and reject all but the first with 503 — the
83
+ * fan-out is the normal case, not an abuse.
84
+ *
85
+ * So the parent is a QUALIFIER, never the lane on its own when a child thread exists: the
86
+ * pair separates siblings while still keeping one conversation's overlapping turns together.
87
+ */
88
+ export function sessionLaneIdFromRequest(headers: Headers): string | undefined {
89
+ const parent = normalizeLogConversationId(headers.get("x-codex-parent-thread-id"));
90
+ const thread = normalizeLogConversationId(headers.get("thread-id"));
91
+ const session = normalizeLogConversationId(sessionIdHeaderFromRequest(headers));
92
+ const specific = thread ?? session;
93
+ if (parent && specific) return `${parent}\u0000${specific}`;
94
+ return specific ?? parent;
95
+ }
96
+
76
97
  function firstSanitizedConversationId(
77
98
  ...values: Array<string | null | undefined>
78
99
  ): string | undefined {
@@ -6,6 +6,7 @@ import {
6
6
  httpStatusFromTerminalError as httpStatusFromClassifiedTerminalError,
7
7
  isClientClosedMessage,
8
8
  isCyberPolicyCode,
9
+ isCyberPolicyMessage,
9
10
  } from "../lib/errors";
10
11
  import { CODEX_CONFIG_PATH, readRootTomlString } from "../codex/paths";
11
12
  import { readCodexCatalogPath } from "../codex/catalog";
@@ -19,7 +20,7 @@ import {
19
20
  isKnownAdmissionKind,
20
21
  isKnownInboundProtocol,
21
22
  isKnownUsageSurface,
22
- isCodexUsageAccountLogLabel,
23
+ isPersistableAccountLogLabel,
23
24
  isValidReasoningWireValue,
24
25
  readRecentUsageEntries,
25
26
  usageForFinalLog,
@@ -65,6 +66,8 @@ export interface RequestLogContext {
65
66
  /** Stable non-PII Codex Pool account identity for durable usage attribution. */
66
67
  accountLogLabel?: string;
67
68
  requestedModel?: string;
69
+ /** User-facing alias selector when routing resolved one; native model remains `model`. */
70
+ requestedAlias?: string;
68
71
  /** Original bare helper model when the opt-in shadow-call route rewrote this request. */
69
72
  shadowCallRewrittenFrom?: string;
70
73
  /** Internal structural combo identity; omitted from RequestLogEntry/JSONL. */
@@ -144,6 +147,7 @@ export interface RequestLogEntry {
144
147
  /** Best-effort chat/session correlation for Logs grouping (#330). */
145
148
  conversationId?: string;
146
149
  requestedModel?: string;
150
+ requestedAlias?: string;
147
151
  /** Original bare helper model when the opt-in shadow-call route rewrote this request. */
148
152
  shadowCallRewrittenFrom?: string;
149
153
  requestedEffort?: string;
@@ -255,10 +259,11 @@ export function requestLogEntryFromPersistedUsage(entry: PersistedUsageEntry): R
255
259
  ...(entry.firstOutputMs !== undefined ? { firstOutputMs: entry.firstOutputMs } : {}),
256
260
  ...(isKnownUsageSurface(entry.surface) ? { surface: entry.surface } : {}),
257
261
  ...(entry.conversationId ? { conversationId: entry.conversationId } : {}),
258
- ...(isCodexUsageAccountLogLabel(entry.accountLogLabel)
262
+ ...(isPersistableAccountLogLabel(entry.accountLogLabel)
259
263
  ? { accountLogLabel: entry.accountLogLabel }
260
264
  : {}),
261
265
  ...(entry.requestedModel ? { requestedModel: entry.requestedModel } : {}),
266
+ ...(entry.requestedAlias ? { requestedAlias: entry.requestedAlias } : {}),
262
267
  ...(entry.shadowCallRewrittenFrom
263
268
  ? { shadowCallRewrittenFrom: entry.shadowCallRewrittenFrom }
264
269
  : {}),
@@ -373,12 +378,13 @@ export function addRequestLog(entry: RequestLogEntry) {
373
378
  ...(entry.apiKeyId ? { apiKeyId: entry.apiKeyId } : {}),
374
379
  ...(isKnownAdmissionKind(entry.admissionKind) ? { admissionKind: entry.admissionKind } : {}),
375
380
  ...(isKnownInboundProtocol(entry.inboundProtocol) ? { inboundProtocol: entry.inboundProtocol } : {}),
376
- ...(isCodexUsageAccountLogLabel(entry.accountLogLabel)
381
+ ...(isPersistableAccountLogLabel(entry.accountLogLabel)
377
382
  ? { accountLogLabel: entry.accountLogLabel }
378
383
  : {}),
379
384
  ...(entry.conversationId ? { conversationId: entry.conversationId } : {}),
380
385
  ...(entry.resolvedModel ? { resolvedModel: entry.resolvedModel } : {}),
381
386
  ...(entry.requestedModel ? { requestedModel: entry.requestedModel } : {}),
387
+ ...(entry.requestedAlias ? { requestedAlias: entry.requestedAlias } : {}),
382
388
  ...(entry.shadowCallRewrittenFrom
383
389
  ? { shadowCallRewrittenFrom: entry.shadowCallRewrittenFrom }
384
390
  : {}),
@@ -765,7 +771,7 @@ function captureUpstreamErrorParsed(
765
771
  last_error?: { message?: unknown };
766
772
  response?: {
767
773
  error?: { type?: unknown; code?: unknown; message?: unknown };
768
- incomplete_details?: { reason?: unknown };
774
+ incomplete_details?: { reason?: unknown; message?: unknown };
769
775
  };
770
776
  };
771
777
  captureTerminalHttpStatus(logCtx, json);
@@ -779,7 +785,8 @@ function captureUpstreamErrorParsed(
779
785
  if (logCtx.upstreamError) return;
780
786
  const message = json?.error?.message
781
787
  ?? json?.last_error?.message
782
- ?? json?.response?.error?.message;
788
+ ?? json?.response?.error?.message
789
+ ?? json?.response?.incomplete_details?.message;
783
790
  if (typeof message === "string" && message.trim()) {
784
791
  logCtx.upstreamError = redactSecretString(message).slice(0, 500);
785
792
  return;
@@ -818,25 +825,43 @@ function captureTerminalHttpStatus(
818
825
  logCtx: RequestLogContext,
819
826
  json: {
820
827
  type?: unknown;
821
- response?: { error?: { type?: unknown; code?: unknown; message?: unknown } };
828
+ code?: unknown;
829
+ message?: unknown;
830
+ error?: { type?: unknown; code?: unknown; message?: unknown };
831
+ last_error?: { type?: unknown; code?: unknown; message?: unknown };
832
+ response?: {
833
+ error?: { type?: unknown; code?: unknown; message?: unknown };
834
+ incomplete_details?: { code?: unknown; message?: unknown };
835
+ };
822
836
  },
823
837
  ): void {
824
838
  if (logCtx.terminalHttpStatus !== undefined) return;
825
- if (json.type !== "response.failed") return;
826
- const error = json.response?.error;
827
- if (!error || typeof error !== "object") return;
828
- const terminalCode = error.code === null || typeof error.code === "string"
829
- ? error.code
830
- : undefined;
831
- if (isCyberPolicyCode(terminalCode)) {
839
+ const type = json.type;
840
+ if (type !== "response.failed" && type !== "response.incomplete" && type !== "error") return;
841
+ const responseError = json.response?.error;
842
+ const responseDetails = json.response?.incomplete_details;
843
+ const candidates = [json.error, json.last_error, responseError, responseDetails, json];
844
+ const policy = candidates.some(candidate => (
845
+ candidate?.code === null || typeof candidate?.code === "string"
846
+ ) && isCyberPolicyCode(candidate.code as string | null | undefined))
847
+ || candidates.some(candidate => (
848
+ typeof candidate?.message === "string"
849
+ && candidate.message.trim().length > 0
850
+ && isCyberPolicyMessage(candidate.message)
851
+ ));
852
+ if (policy) {
832
853
  logCtx.terminalErrorCode = CYBER_POLICY_ERROR_CODE;
833
- } else {
834
- delete logCtx.terminalErrorCode;
854
+ logCtx.terminalHttpStatus = 400;
855
+ return;
835
856
  }
857
+ if (type !== "response.failed" || !responseError || typeof responseError !== "object") return;
858
+ const responseCode = responseError.code === null || typeof responseError.code === "string"
859
+ ? responseError.code
860
+ : undefined;
836
861
  logCtx.terminalHttpStatus = httpStatusFromTerminalError({
837
- type: typeof error.type === "string" ? error.type : undefined,
838
- code: terminalCode,
839
- message: typeof error.message === "string" ? error.message : undefined,
862
+ type: typeof responseError.type === "string" ? responseError.type : undefined,
863
+ code: responseCode,
864
+ message: typeof responseError.message === "string" ? responseError.message : undefined,
840
865
  });
841
866
  }
842
867
 
@@ -945,11 +970,12 @@ export function addFinalRequestLog(
945
970
  ...(logCtx.apiKeyId ? { apiKeyId: logCtx.apiKeyId } : {}),
946
971
  ...(logCtx.admissionKind ? { admissionKind: logCtx.admissionKind } : {}),
947
972
  ...(logCtx.inboundProtocol ? { inboundProtocol: logCtx.inboundProtocol } : {}),
948
- ...(isCodexUsageAccountLogLabel(logCtx.accountLogLabel)
973
+ ...(isPersistableAccountLogLabel(logCtx.accountLogLabel)
949
974
  ? { accountLogLabel: logCtx.accountLogLabel }
950
975
  : {}),
951
976
  ...(logCtx.conversationId ? { conversationId: logCtx.conversationId } : {}),
952
977
  ...(logCtx.requestedModel ? { requestedModel: logCtx.requestedModel } : {}),
978
+ ...(logCtx.requestedAlias ? { requestedAlias: logCtx.requestedAlias } : {}),
953
979
  ...(shadowCallRewrittenFrom ? { shadowCallRewrittenFrom } : {}),
954
980
  ...(logCtx.requestedEffort ? { requestedEffort: logCtx.requestedEffort } : {}),
955
981
  ...(logCtx.effectiveEffort ? { effectiveEffort: logCtx.effectiveEffort } : {}),
@@ -1170,7 +1196,7 @@ export function sealRequestAttemptIdentity(
1170
1196
  if (!attempt) return;
1171
1197
  attempt.provider = provider;
1172
1198
  attempt.adapter = adapter;
1173
- if (isCodexUsageAccountLogLabel(accountLogLabel)) attempt.accountLogLabel = accountLogLabel;
1199
+ if (isPersistableAccountLogLabel(accountLogLabel)) attempt.accountLogLabel = accountLogLabel;
1174
1200
  }
1175
1201
 
1176
1202
  export function noteAttemptSend(
@@ -2,6 +2,7 @@ import type { Server } from "bun";
2
2
  import { bridgeToResponsesSSE, buildResponseJSON, formatErrorResponse, type ResponsesTerminalStatus } from "../../bridge";
3
3
  import {
4
4
  getConfigPath,
5
+ loadConfig,
5
6
  multiAgentGuidanceEnabled,
6
7
  resolveEnvValue,
7
8
  } from "../../config";
@@ -10,6 +11,7 @@ import { buildCompactV1Output, COMPACT_PROMPT, decodeCompactionSummary, extractC
10
11
  import { FORWARD_HEADERS, sanitizeReasoningInputContent } from "../../adapters/openai-responses";
11
12
  import { expandPreviousResponseInput, previousResponseProviderState, rememberResponseState } from "../../responses/state";
12
13
  import { routeModel } from "../../router";
14
+ import type { RawEntry } from "../../codex/catalog/parsing";
13
15
  import {
14
16
  advanceComboAfterFailure,
15
17
  comboDefaultEffort,
@@ -245,15 +247,47 @@ export async function resolveEffectiveSubagentRoster(
245
247
  surface: SpawnAgentSurface,
246
248
  ): Promise<EffectiveSubagentRoster> {
247
249
  const { effectiveSubagentRoster } = await import("../../codex/catalog");
248
- return effectiveSubagentRoster(configuredModels, surface);
250
+ return effectiveSubagentRoster(configuredModels, surface, await freshSubagentCatalogEntries());
251
+ }
252
+
253
+ /**
254
+ * The persisted Codex catalog, with native context metadata re-derived from the CURRENT config.
255
+ *
256
+ * The subagent roster reads the catalog FILE, which is only as fresh as the last sync. A row
257
+ * written before the operator widened the native window keeps its old `context_window`, so a
258
+ * child was planning and compacting against a narrower budget than its parent — measured at
259
+ * 272,000 x 95% = 258,400 while the request path resolved 922,000 (#2574).
260
+ *
261
+ * Re-applying the override is cheap and idempotent: it is the same function the writer uses,
262
+ * so a fresh catalog is unchanged and a stale one is repaired in memory rather than silently
263
+ * believed. It does not rewrite the file — the row on disk stays whatever the last sync wrote,
264
+ * and `ocx sync` remains what refreshes it.
265
+ */
266
+ async function freshSubagentCatalogEntries(): Promise<RawEntry[]> {
267
+ const { readCatalog, readCodexCatalogPath, nativeContextLimits } = await import("../../codex/catalog");
268
+ const { applyNativeOpenAiContextOverride } = await import("../../codex/catalog/parsing");
269
+ const entries = readCatalog(readCodexCatalogPath())?.models ?? [];
270
+ if (entries.length === 0) return [];
271
+ let limits: ReturnType<typeof nativeContextLimits>;
272
+ try {
273
+ limits = nativeContextLimits(loadConfig());
274
+ } catch {
275
+ // An unreadable config must not cost the caller its roster; serve the file as written.
276
+ return entries;
277
+ }
278
+ return entries.map(entry => {
279
+ const clone = { ...entry };
280
+ applyNativeOpenAiContextOverride(clone, limits);
281
+ return clone;
282
+ });
249
283
  }
250
284
 
251
285
  /** Reuse one parsed catalog snapshot across every roster projection for this request. */
252
286
  async function createRequestScopedSubagentRosterResolver(): Promise<NonNullable<
253
287
  MultiAgentGuidanceDeps["resolveEffectiveSubagentRoster"]
254
288
  >> {
255
- const { effectiveSubagentRoster, readCatalog, readCodexCatalogPath } = await import("../../codex/catalog");
256
- const catalogEntries = readCatalog(readCodexCatalogPath())?.models ?? [];
289
+ const { effectiveSubagentRoster } = await import("../../codex/catalog");
290
+ const catalogEntries = await freshSubagentCatalogEntries();
257
291
  return (configuredModels, surface) =>
258
292
  effectiveSubagentRoster(configuredModels, surface, catalogEntries);
259
293
  }
@@ -390,7 +424,10 @@ export async function multiAgentGuidanceText(
390
424
  + "use only models listed for this collaboration surface. "
391
425
  + "When setting either override, set fork_turns to \"none\" "
392
426
  + "(or a positive turn count such as \"3\"; full-history forks reject overrides) "
393
- + "and make the task message self-contained.";
427
+ + "and make the task message self-contained. "
428
+ + "When specifying model overrides, omit agent_type or use \"worker\" to prevent enforcing locked default models. "
429
+ + "Subagent exec runs in a pure V8 isolate without require('fs'); "
430
+ + "escape nested template literals in tools.apply_patch to prevent JavaScript syntax errors (e.g., write \\` and \\\${var}).";
394
431
  let preferredText = "";
395
432
  if (preferred) {
396
433
  preferredText = ` Preferred sub-agent: model "${preferred.model}"`
@@ -426,7 +463,7 @@ export async function multiAgentGuidanceText(
426
463
 
427
464
 
428
465
 
429
- export const V2_GUIDANCE_CHAR_BUDGET = 700;
466
+ export const V2_GUIDANCE_CHAR_BUDGET = 1200;
430
467
 
431
468
  export function applyInjectionPlaceholders(prompt: string, model?: string, effort?: string, roster?: string, fallback?: string, roles?: string): string {
432
469
  return prompt
@@ -4,6 +4,12 @@ import { createSseInspector } from "../relay";
4
4
  import { MAX_CLIENT_SSE_FRAME_BYTES } from "../sse-frame-buffer";
5
5
 
6
6
  const COMBO_STREAM_PREFLIGHT_MAX_BYTES = MAX_CLIENT_SSE_FRAME_BYTES;
7
+ // Keep retained object count proportional to the same byte budget used by the
8
+ // shared SSE framer. Tiny or empty upstream reads must not bypass the byte cap.
9
+ const COMBO_STREAM_PREFLIGHT_MAX_CHUNKS = Math.max(
10
+ 1,
11
+ Math.ceil(COMBO_STREAM_PREFLIGHT_MAX_BYTES / 1024),
12
+ );
7
13
 
8
14
  const PRE_OUTPUT_CONTROL_EVENTS = new Set([
9
15
  "response.created",
@@ -105,8 +111,8 @@ export type ComboStreamPreflightResult =
105
111
  /**
106
112
  * Buffer a combo child's downstream SSE only until the request becomes unsafe to
107
113
  * 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.
114
+ * buffer is capped by bytes and retained chunks; hitting either cap commits the
115
+ * current target instead of growing memory or guessing that replay is safe.
110
116
  */
111
117
  export async function preflightComboStreamResponse(
112
118
  response: Response,
@@ -161,7 +167,8 @@ export async function preflightComboStreamResponse(
161
167
  return { kind: "failed", response: failedTerminalResponse(response, failedPayload, logCtx) };
162
168
  }
163
169
  if (next.done || terminalStatus !== undefined || outputCommitted
164
- || bufferedBytes >= COMBO_STREAM_PREFLIGHT_MAX_BYTES) {
170
+ || bufferedBytes >= COMBO_STREAM_PREFLIGHT_MAX_BYTES
171
+ || buffered.length >= COMBO_STREAM_PREFLIGHT_MAX_CHUNKS) {
165
172
  return { kind: "accepted", response: replayBufferedResponse(response, reader, buffered) };
166
173
  }
167
174
  }