codex-multi-auth 2.9.2 → 2.11.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 (81) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/README.md +2 -1
  3. package/config/README.md +3 -1
  4. package/config/codex-legacy.json +300 -0
  5. package/config/codex-modern.json +96 -0
  6. package/config/schema/config.schema.json +23 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +62 -2
  9. package/dist/lib/accounts.d.ts +25 -1
  10. package/dist/lib/accounts.d.ts.map +1 -1
  11. package/dist/lib/accounts.js +26 -6
  12. package/dist/lib/capability-policy.d.ts.map +1 -1
  13. package/dist/lib/capability-policy.js +16 -1
  14. package/dist/lib/codex-manager/backend-settings-helpers.d.ts.map +1 -1
  15. package/dist/lib/codex-manager/backend-settings-helpers.js +10 -1
  16. package/dist/lib/codex-manager/backend-settings-schema.d.ts +18 -0
  17. package/dist/lib/codex-manager/backend-settings-schema.d.ts.map +1 -1
  18. package/dist/lib/codex-manager/backend-settings-schema.js +19 -0
  19. package/dist/lib/codex-manager/experimental-settings-prompt.d.ts +1 -0
  20. package/dist/lib/codex-manager/experimental-settings-prompt.d.ts.map +1 -1
  21. package/dist/lib/codex-manager/experimental-settings-prompt.js +12 -0
  22. package/dist/lib/codex-manager/experimental-settings-schema.d.ts +2 -0
  23. package/dist/lib/codex-manager/experimental-settings-schema.d.ts.map +1 -1
  24. package/dist/lib/codex-manager/experimental-settings-schema.js +2 -0
  25. package/dist/lib/config.d.ts +29 -0
  26. package/dist/lib/config.d.ts.map +1 -1
  27. package/dist/lib/config.js +91 -1
  28. package/dist/lib/context-budget/model-context-windows.d.ts +25 -0
  29. package/dist/lib/context-budget/model-context-windows.d.ts.map +1 -0
  30. package/dist/lib/context-budget/model-context-windows.js +130 -0
  31. package/dist/lib/context-budget-guard.d.ts +100 -0
  32. package/dist/lib/context-budget-guard.d.ts.map +1 -0
  33. package/dist/lib/context-budget-guard.js +183 -0
  34. package/dist/lib/context-budget-response.d.ts +25 -0
  35. package/dist/lib/context-budget-response.d.ts.map +1 -0
  36. package/dist/lib/context-budget-response.js +57 -0
  37. package/dist/lib/context-overflow.d.ts.map +1 -1
  38. package/dist/lib/context-overflow.js +5 -60
  39. package/dist/lib/model-capability-matrix.d.ts.map +1 -1
  40. package/dist/lib/model-capability-matrix.js +9 -1
  41. package/dist/lib/request/error-classification.d.ts.map +1 -1
  42. package/dist/lib/request/error-classification.js +43 -2
  43. package/dist/lib/request/helpers/model-map.d.ts.map +1 -1
  44. package/dist/lib/request/helpers/model-map.js +181 -0
  45. package/dist/lib/request/rate-limit-decision.d.ts +4 -5
  46. package/dist/lib/request/rate-limit-decision.d.ts.map +1 -1
  47. package/dist/lib/request/rate-limit-decision.js +33 -4
  48. package/dist/lib/request/response-metadata.d.ts.map +1 -1
  49. package/dist/lib/request/response-metadata.js +1 -0
  50. package/dist/lib/request/stream-failover-runtime.d.ts +3 -1
  51. package/dist/lib/request/stream-failover-runtime.d.ts.map +1 -1
  52. package/dist/lib/request/stream-failover-runtime.js +7 -2
  53. package/dist/lib/runtime/context-budget-settings.d.ts +13 -0
  54. package/dist/lib/runtime/context-budget-settings.d.ts.map +1 -0
  55. package/dist/lib/runtime/context-budget-settings.js +8 -0
  56. package/dist/lib/runtime/loader-setup.d.ts +1 -0
  57. package/dist/lib/runtime/loader-setup.d.ts.map +1 -1
  58. package/dist/lib/runtime/loader-setup.js +1 -0
  59. package/dist/lib/runtime/rotation-account-selection.d.ts +23 -0
  60. package/dist/lib/runtime/rotation-account-selection.d.ts.map +1 -1
  61. package/dist/lib/runtime/rotation-account-selection.js +15 -6
  62. package/dist/lib/runtime/rotation-proxy-state.d.ts +2 -0
  63. package/dist/lib/runtime/rotation-proxy-state.d.ts.map +1 -1
  64. package/dist/lib/runtime/rotation-server-types.d.ts +11 -0
  65. package/dist/lib/runtime/rotation-server-types.d.ts.map +1 -1
  66. package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
  67. package/dist/lib/runtime-rotation-proxy.js +251 -43
  68. package/dist/lib/schemas.d.ts +4 -0
  69. package/dist/lib/schemas.d.ts.map +1 -1
  70. package/dist/lib/schemas.js +10 -0
  71. package/dist/lib/synthetic-response.d.ts +31 -0
  72. package/dist/lib/synthetic-response.d.ts.map +1 -0
  73. package/dist/lib/synthetic-response.js +79 -0
  74. package/dist/lib/ui/ui-copy.d.ts +2 -1
  75. package/dist/lib/ui/ui-copy.d.ts.map +1 -1
  76. package/dist/lib/ui/ui-copy.js +2 -1
  77. package/dist/lib/usage/pricing.d.ts +1 -1
  78. package/dist/lib/usage/pricing.d.ts.map +1 -1
  79. package/dist/lib/usage/pricing.js +33 -0
  80. package/package.json +1 -1
  81. package/scripts/codex.js +153 -2
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Shared builder for locally-answered Responses API replies.
3
+ *
4
+ * Both the reactive context-overflow handler (`lib/context-overflow.ts`) and
5
+ * the proactive context budget guard (`lib/context-budget-response.ts`) need
6
+ * to hand the caller a plugin-authored notice instead of forwarding to
7
+ * upstream, in the exact SSE dialect the Codex CLI / Responses client
8
+ * expects. Extracted here so both answer with one audited SSE shape rather
9
+ * than two independently-maintained copies of it.
10
+ */
11
+ function randomSuffix() {
12
+ return Math.random().toString(36).slice(2, 8);
13
+ }
14
+ /**
15
+ * Build a synthetic OpenAI Responses API SSE stream carrying a single
16
+ * assistant text message, then a terminal `response.completed`.
17
+ *
18
+ * Emits `response.*` events — the dialect the Codex CLI client and this
19
+ * package's own `convertSseToJson` parser speak, not the Anthropic Messages
20
+ * API dialect. Returns 200 OK so the host session never locks on a 4xx for a
21
+ * notice the plugin itself generated.
22
+ */
23
+ export function createSyntheticSseResponse(options) {
24
+ const { model, message, idPrefix, errorType } = options;
25
+ const messageId = `msg_${idPrefix}_${Date.now()}_${randomSuffix()}`;
26
+ const responseId = `resp_${idPrefix}_${Date.now()}_${randomSuffix()}`;
27
+ const events = [];
28
+ const push = (type, payload) => {
29
+ events.push(`event: ${type}\ndata: ${JSON.stringify({ type, ...payload })}\n\n`);
30
+ };
31
+ const baseResponse = {
32
+ id: responseId,
33
+ object: "response",
34
+ model,
35
+ };
36
+ push("response.created", { response: { ...baseResponse, status: "in_progress" } });
37
+ push("response.output_item.added", {
38
+ output_index: 0,
39
+ item: {
40
+ id: messageId,
41
+ type: "message",
42
+ role: "assistant",
43
+ content: [],
44
+ },
45
+ });
46
+ push("response.output_text.delta", {
47
+ output_index: 0,
48
+ content_index: 0,
49
+ delta: message,
50
+ });
51
+ push("response.output_text.done", {
52
+ output_index: 0,
53
+ content_index: 0,
54
+ text: message,
55
+ });
56
+ push("response.completed", {
57
+ response: {
58
+ ...baseResponse,
59
+ status: "completed",
60
+ output: [
61
+ {
62
+ id: messageId,
63
+ type: "message",
64
+ role: "assistant",
65
+ content: [{ type: "output_text", text: message }],
66
+ },
67
+ ],
68
+ usage: { input_tokens: 0, output_tokens: 0, total_tokens: 0 },
69
+ },
70
+ });
71
+ return new Response(events.join(""), {
72
+ status: 200,
73
+ headers: {
74
+ "Content-Type": "text/event-stream",
75
+ "X-Codex-Plugin-Synthetic": "true",
76
+ "X-Codex-Plugin-Error-Type": errorType,
77
+ },
78
+ });
79
+ }
@@ -91,7 +91,7 @@ export declare const UI_COPY: {
91
91
  readonly experimental: "Experimental";
92
92
  readonly experimentalTitle: "Experimental";
93
93
  readonly experimentalSubtitle: "Preview sync and backup actions before they become stable";
94
- readonly experimentalHelpMenu: "Enter Select | 1 Sync | 2 Backup | 3 Guard | [ - Down | ] + Up | S Save | Q Back";
94
+ readonly experimentalHelpMenu: "Enter Select | 1 Sync | 2 Backup | 3 Guard | 4 Budget | [ - Down | ] + Up | S Save | Q Back";
95
95
  readonly experimentalHelpPreview: "Enter Select | A Apply | Q Back";
96
96
  readonly experimentalHelpStatus: "Enter Select | Q Back";
97
97
  readonly experimentalSync: "Sync Accounts to oc-chatgpt-multi-auth";
@@ -102,6 +102,7 @@ export declare const UI_COPY: {
102
102
  readonly experimentalRefreshInterval: "Refresh Guard Interval";
103
103
  readonly experimentalDecreaseInterval: "Decrease Refresh Interval";
104
104
  readonly experimentalIncreaseInterval: "Increase Refresh Interval";
105
+ readonly experimentalContextBudgetGuard: "Enable Context Budget Guard";
105
106
  readonly backend: "Backend Controls";
106
107
  readonly back: "Back";
107
108
  readonly previewHeading: "Live Preview";
@@ -1 +1 @@
1
- {"version":3,"file":"ui-copy.d.ts","sourceRoot":"","sources":["../../../lib/ui/ui-copy.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gDAqDP,MAAM,gBACF,MAAM,WACX,MAAM;kDAGiB,MAAM,WAAW,MAAM;kDAEvB,MAAM,gBAAgB,MAAM;iDAE7B,MAAM,gBAAgB,MAAM;;;;;;;;;;;;;;;;;;;;uCAyBtC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CA+EA,MAAM;;;;CAM1B,CAAC;AAEX;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAIpE"}
1
+ {"version":3,"file":"ui-copy.d.ts","sourceRoot":"","sources":["../../../lib/ui/ui-copy.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gDAqDP,MAAM,gBACF,MAAM,WACX,MAAM;kDAGiB,MAAM,WAAW,MAAM;kDAEvB,MAAM,gBAAgB,MAAM;iDAE7B,MAAM,gBAAgB,MAAM;;;;;;;;;;;;;;;;;;;;uCAyBtC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAgFA,MAAM;;;;CAM1B,CAAC;AAEX;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAIpE"}
@@ -92,7 +92,7 @@ export const UI_COPY = {
92
92
  experimental: "Experimental",
93
93
  experimentalTitle: "Experimental",
94
94
  experimentalSubtitle: "Preview sync and backup actions before they become stable",
95
- experimentalHelpMenu: "Enter Select | 1 Sync | 2 Backup | 3 Guard | [ - Down | ] + Up | S Save | Q Back",
95
+ experimentalHelpMenu: "Enter Select | 1 Sync | 2 Backup | 3 Guard | 4 Budget | [ - Down | ] + Up | S Save | Q Back",
96
96
  experimentalHelpPreview: "Enter Select | A Apply | Q Back",
97
97
  experimentalHelpStatus: "Enter Select | Q Back",
98
98
  experimentalSync: "Sync Accounts to oc-chatgpt-multi-auth",
@@ -103,6 +103,7 @@ export const UI_COPY = {
103
103
  experimentalRefreshInterval: "Refresh Guard Interval",
104
104
  experimentalDecreaseInterval: "Decrease Refresh Interval",
105
105
  experimentalIncreaseInterval: "Increase Refresh Interval",
106
+ experimentalContextBudgetGuard: "Enable Context Budget Guard",
106
107
  backend: "Backend Controls",
107
108
  back: "Back",
108
109
  previewHeading: "Live Preview",
@@ -19,7 +19,7 @@ export interface UsageModelPricing {
19
19
  * `test/usage-pricing-coverage.test.ts` fails if a NEW routable model appears
20
20
  * in neither list.
21
21
  */
22
- export declare const UNPRICED_ROUTABLE_MODELS: readonly ["gpt-5.1", "gpt-5.2-pro", "gpt-5.4-mini", "gpt-5.4-nano", "gpt-5.4-pro", "gpt-5.5-pro", "gpt-5-mini", "gpt-5-nano"];
22
+ export declare const UNPRICED_ROUTABLE_MODELS: readonly ["gpt-6-astra-aeon", "gpt-daybreak-blue-latest", "gpt-daybreak-red-latest", "gpt-5.1", "gpt-5.2-pro", "gpt-5.4-mini", "gpt-5.4-nano", "gpt-5.4-pro", "gpt-5.5-pro", "gpt-5-mini", "gpt-5-nano"];
23
23
  export declare function getUsageModelPricing(model: string | null | undefined): UsageModelPricing | null;
24
24
  export declare function estimateUsageCostUsd(model: string | null | undefined, tokens: UsageTokenCounts): number | null;
25
25
  export declare function listUsageModelPricing(): Record<string, UsageModelPricing>;
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../../lib/usage/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IACjC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAChC;AA2DD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,+HAS3B,CAAC;AAOX,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,iBAAiB,GAAG,IAAI,CAM1B;AAED,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,MAAM,EAAE,gBAAgB,GACtB,MAAM,GAAG,IAAI,CAqBf;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAEzE"}
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../../lib/usage/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IACjC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAChC;AAwED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,0MAkB3B,CAAC;AAOX,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,iBAAiB,GAAG,IAAI,CAiB1B;AAED,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,MAAM,EAAE,gBAAgB,GACtB,MAAM,GAAG,IAAI,CAqBf;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAEzE"}
@@ -1,4 +1,17 @@
1
1
  const MODEL_PRICING = {
2
+ // GPT-6 Astra, published at the 2026-09-03 launch: $10 / 1M input,
3
+ // $50 / 1M output on the standard service tier. Fast mode is 2x standard
4
+ // ($20 / $100); this table has no service-tier dimension, so it prices the
5
+ // standard tier and a Fast-mode session is under-counted by half. No cached
6
+ // input rate was published, so `cachedInputUsdPerMillion` is deliberately
7
+ // absent: `estimateUsageCostUsd` then bills cached tokens at the full input
8
+ // rate, which over-states cost. That is the safe direction for a
9
+ // `maxCostUsd` budget — it trips early, never late.
10
+ "gpt-6-astra": {
11
+ inputUsdPerMillion: 10,
12
+ outputUsdPerMillion: 50,
13
+ reasoningUsdPerMillion: 50,
14
+ },
2
15
  "gpt-5-codex": {
3
16
  inputUsdPerMillion: 1.25,
4
17
  outputUsdPerMillion: 10,
@@ -69,6 +82,15 @@ const MODEL_PRICING = {
69
82
  * in neither list.
70
83
  */
71
84
  export const UNPRICED_ROUTABLE_MODELS = [
85
+ // OpenAI published a rate for the Astra flagship at launch but not for the
86
+ // long-horizon `aeon` variant, and the Daybreak cyber models are sold under
87
+ // a separate controlled-access agreement with no public per-token rate.
88
+ // Pricing `aeon` off the flagship would be a guess on the model whose whole
89
+ // purpose is running for days, which is exactly where a wrong rate does the
90
+ // most damage.
91
+ "gpt-6-astra-aeon",
92
+ "gpt-daybreak-blue-latest",
93
+ "gpt-daybreak-red-latest",
72
94
  "gpt-5.1",
73
95
  "gpt-5.2-pro",
74
96
  "gpt-5.4-mini",
@@ -87,6 +109,17 @@ export function getUsageModelPricing(model) {
87
109
  if (!normalized) {
88
110
  return null;
89
111
  }
112
+ // `Object.hasOwn`, not a bare index. The model string arrives raw from the
113
+ // client (`createUsageLedgerRow` only trims it), so `constructor`,
114
+ // `toString` and friends reach this lookup and a bare index hands back the
115
+ // matching `Object.prototype` member. That object is truthy, so it is
116
+ // returned as a rate, and every field on it is undefined: the cost comes out
117
+ // `NaN` instead of `null`. A NaN cost is worse than an unknown one, because
118
+ // `NaN >= limit` is false, so it silently makes a `maxCostUsd` budget
119
+ // unenforceable rather than failing closed the way an unpriced model does.
120
+ if (!Object.hasOwn(MODEL_PRICING, normalized)) {
121
+ return null;
122
+ }
90
123
  return MODEL_PRICING[normalized] ?? null;
91
124
  }
92
125
  export function estimateUsageCostUsd(model, tokens) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-multi-auth",
3
- "version": "2.9.2",
3
+ "version": "2.11.0",
4
4
  "description": "Codex CLI multi-account OAuth manager with account switching, health checks, runtime rotation, diagnostics, and recovery tools for @openai/codex",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/scripts/codex.js CHANGED
@@ -574,7 +574,27 @@ async function applyForcedAccountSelection(rawArgs, env = process.env) {
574
574
  }
575
575
 
576
576
  function resolveModelFamilyForStatus(model) {
577
- const normalized = typeof model === "string" ? model.trim().toLowerCase() : "";
577
+ // `resolveStatusModel` hands over the raw `--model` / `-m` value or the
578
+ // config value verbatim, so a provider-qualified id arrives intact. Every
579
+ // branch below is a `startsWith`, so `openai/gpt-6` used to match none of
580
+ // them and return null, dropping status routing back to `activeIndex`
581
+ // instead of the family index. Strip the prefix once, for all of them.
582
+ const normalized =
583
+ typeof model === "string"
584
+ ? stripProviderPrefix(model.trim()).toLowerCase()
585
+ : "";
586
+ // GPT-6 Astra and the Daybreak cyber models share the gpt-5.2 prompt family
587
+ // with the GPT-5.6 general tiers (see lib/request/helpers/model-map.ts
588
+ // MODEL_PROFILES). Daybreak has to be checked explicitly: its slug matches
589
+ // none of the branches below, so it used to fall through to `null` and get
590
+ // bucketed against no family at all.
591
+ if (
592
+ (normalized.startsWith("gpt-6") || normalized.startsWith("astra")) &&
593
+ !normalized.includes("codex")
594
+ ) {
595
+ return "gpt-5.2";
596
+ }
597
+ if (normalized.includes("daybreak")) return "gpt-5.2";
578
598
  // GPT-5.6 general tiers share the gpt-5.2 prompt family (see
579
599
  // lib/request/helpers/model-map.ts MODEL_PROFILES). Check before the generic
580
600
  // gpt-5 catch-all, which would otherwise mis-bucket them as codex.
@@ -1259,7 +1279,18 @@ const DIRECT_UNSUPPORTED_MODEL_PATTERN =
1259
1279
  /['"]([^'"]+)['"]\s+model is not supported when using codex with a chatgpt account/i;
1260
1280
  const CURRENT_CODEX_MODEL = "gpt-5.3-codex";
1261
1281
  const LEGACY_CODEX_MODEL = "gpt-5-codex";
1282
+ // Mirrors the GPT-6 rows of lib/request/error-classification.ts
1283
+ // `DEFAULT_UNSUPPORTED_CODEX_FALLBACK_CHAIN`. This table is walked differently
1284
+ // from lib's: `resolveUnsupportedModelRetryTarget` keys on the model named in
1285
+ // the error output and falls back to the original requested model, with
1286
+ // `attemptedModels` accumulating, so a row's later entries ARE reachable here.
1287
+ // The two tables are not identical today (`gpt-5.3-codex` has a row in lib and
1288
+ // not here), which predates GPT-6 and is left alone; the GPT-6 rows are pinned
1289
+ // in parity by test/codex-model-resolution.test.ts.
1262
1290
  const WRAPPER_UNSUPPORTED_MODEL_FALLBACK_CHAIN = {
1291
+ "gpt-6-astra": ["gpt-5.6-sol", "gpt-5.5"],
1292
+ "gpt-6-astra-aeon": ["gpt-6-astra", "gpt-5.6-sol"],
1293
+ "gpt-5.6-sol": ["gpt-5.5"],
1263
1294
  "gpt-5": ["gpt-5.5"],
1264
1295
  "gpt-5-pro": ["gpt-5.5-pro"],
1265
1296
  "gpt-5-chat-latest": ["gpt-5.5"],
@@ -1901,6 +1932,10 @@ function hasCliAuthCredentialsStoreOverride(args) {
1901
1932
  // This wrapper runs before the TypeScript build, so it cannot import that source.
1902
1933
  const SUPPORTED_REASONING_EFFORTS_BY_MODEL = {
1903
1934
  [CURRENT_CODEX_MODEL]: ["low", "medium", "high", "xhigh"],
1935
+ "gpt-6-astra": ["low", "medium", "high", "xhigh", "max", "ultra"],
1936
+ "gpt-6-astra-aeon": ["low", "medium", "high", "xhigh", "max", "ultra"],
1937
+ "gpt-daybreak-blue-latest": ["low", "medium", "high", "xhigh", "max", "ultra"],
1938
+ "gpt-daybreak-red-latest": ["low", "medium", "high", "xhigh", "max", "ultra"],
1904
1939
  "gpt-5.6-sol": ["low", "medium", "high", "xhigh", "max", "ultra"],
1905
1940
  "gpt-5.6-terra": ["low", "medium", "high", "xhigh", "max", "ultra"],
1906
1941
  "gpt-5.6-luna": ["low", "medium", "high", "xhigh", "max"],
@@ -1960,6 +1995,18 @@ const GPT_5_6_LUNA_MODEL = "gpt-5.6-luna";
1960
1995
  const GPT_5_6_FLAGSHIP_ALIAS = "gpt-5.6";
1961
1996
  const GPT_5_6_SOL_TERRA_EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
1962
1997
  const GPT_5_6_LUNA_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
1998
+ // GPT-6 Astra (2026-09-03). No Sol/Terra/Luna split this generation: the
1999
+ // flagship plus `aeon`, a long-horizon variant. Same frontier effort ladder as
2000
+ // 5.6 (no `none`/`minimal`, `ultra` at the top). Bare `gpt-6` -> flagship.
2001
+ const GPT_6_ASTRA_MODEL = "gpt-6-astra";
2002
+ const GPT_6_ASTRA_AEON_MODEL = "gpt-6-astra-aeon";
2003
+ const GPT_6_FLAGSHIP_ALIAS = "gpt-6";
2004
+ const GPT_6_ASTRA_EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
2005
+ // Daybreak cyber models from the upstream Codex catalog. `red` is the
2006
+ // cyber-permissive variant, `blue` the defensive one.
2007
+ const DAYBREAK_BLUE_MODEL = "gpt-daybreak-blue-latest";
2008
+ const DAYBREAK_RED_MODEL = "gpt-daybreak-red-latest";
2009
+ const DAYBREAK_EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
1963
2010
  const GENERAL_GPT5_VERSION_CATALOG = {
1964
2011
  1: {
1965
2012
  base: "gpt-5.1",
@@ -2163,6 +2210,47 @@ function seedRequestedModelAliases() {
2163
2210
  GPT_5_6_SOL_MODEL,
2164
2211
  GPT_5_6_SOL_TERRA_EFFORTS,
2165
2212
  );
2213
+ addRequestedModelEffortAliases(
2214
+ GPT_6_ASTRA_MODEL,
2215
+ GPT_6_ASTRA_MODEL,
2216
+ GPT_6_ASTRA_EFFORTS,
2217
+ );
2218
+ addRequestedModelEffortAliases(
2219
+ GPT_6_ASTRA_AEON_MODEL,
2220
+ GPT_6_ASTRA_AEON_MODEL,
2221
+ GPT_6_ASTRA_EFFORTS,
2222
+ );
2223
+ addRequestedModelEffortAliases(
2224
+ GPT_6_FLAGSHIP_ALIAS,
2225
+ GPT_6_ASTRA_MODEL,
2226
+ GPT_6_ASTRA_EFFORTS,
2227
+ );
2228
+ addRequestedModelEffortAliases("astra", GPT_6_ASTRA_MODEL, GPT_6_ASTRA_EFFORTS);
2229
+ addRequestedModelEffortAliases(
2230
+ "astra-aeon",
2231
+ GPT_6_ASTRA_AEON_MODEL,
2232
+ GPT_6_ASTRA_EFFORTS,
2233
+ );
2234
+ addRequestedModelEffortAliases(
2235
+ DAYBREAK_BLUE_MODEL,
2236
+ DAYBREAK_BLUE_MODEL,
2237
+ DAYBREAK_EFFORTS,
2238
+ );
2239
+ addRequestedModelEffortAliases(
2240
+ DAYBREAK_RED_MODEL,
2241
+ DAYBREAK_RED_MODEL,
2242
+ DAYBREAK_EFFORTS,
2243
+ );
2244
+ addRequestedModelEffortAliases(
2245
+ "daybreak-blue",
2246
+ DAYBREAK_BLUE_MODEL,
2247
+ DAYBREAK_EFFORTS,
2248
+ );
2249
+ addRequestedModelEffortAliases(
2250
+ "daybreak-red",
2251
+ DAYBREAK_RED_MODEL,
2252
+ DAYBREAK_EFFORTS,
2253
+ );
2166
2254
  addRequestedModelReasoningAliases(CURRENT_CODEX_MODEL, CURRENT_CODEX_MODEL);
2167
2255
  addRequestedModelReasoningAliases("gpt-5.3-codex-spark", CURRENT_CODEX_MODEL);
2168
2256
  addRequestedModelReasoningAliases(LEGACY_CODEX_MODEL, CURRENT_CODEX_MODEL);
@@ -2218,6 +2306,13 @@ function resolveStableGeneralGpt5Variant(variant) {
2218
2306
  return fallback;
2219
2307
  }
2220
2308
 
2309
+ // The final clause is a catch-all on the `codex` substring, matching
2310
+ // `resolveCodexCatalogModel` in lib/request/helpers/model-map.ts. It used to be
2311
+ // an exact `normalized === "codex"` check, so any codex id the explicit list
2312
+ // above did not name (`gpt-6-codex`, `gpt-5.7-codex`, …) resolved to nothing in
2313
+ // the wrapper while lib resolved it to the current codex model — a silent drift
2314
+ // between the two, which is exactly what test/codex-model-resolution.test.ts
2315
+ // exists to prevent.
2221
2316
  function resolveCodexRequestedModel(normalized) {
2222
2317
  if (
2223
2318
  normalized.includes("gpt-5.1-codex-max") ||
@@ -2246,7 +2341,7 @@ function resolveCodexRequestedModel(normalized) {
2246
2341
  normalized.includes("gpt 5.1 codex") ||
2247
2342
  normalized.includes("gpt-5-codex") ||
2248
2343
  normalized.includes("gpt 5 codex") ||
2249
- normalized === "codex"
2344
+ normalized.includes("codex")
2250
2345
  ) {
2251
2346
  return CURRENT_CODEX_MODEL;
2252
2347
  }
@@ -2258,6 +2353,51 @@ function resolveCodexRequestedModel(normalized) {
2258
2353
  // future `gpt-5.6-terra-fast`). Without this the general GPT-5 resolver sees
2259
2354
  // minor `6`, finds no catalog entry, and silently falls back to 5.5. Unknown
2260
2355
  // tiers resolve to Sol, matching OpenAI's bare `gpt-5.6` alias.
2356
+ // Resolve GPT-6 identifiers that are not exact aliases (a dated snapshot, the
2357
+ // `gpt-6-astra-pro` plan tier, or a tier OpenAI adds later). Without this the
2358
+ // general GPT-5 resolver never matches (it needs a `gpt 5` token pair) and the
2359
+ // id falls through to 5.5 — running GPT-5.5 for a caller who asked for the
2360
+ // frontier model. `aeon` keeps its own id because it is a behaviourally
2361
+ // different model, not a rename. Mirrors lib/request/helpers/model-map.ts.
2362
+ function resolveGpt6RequestedModel(stripped) {
2363
+ const tokens = tokenizeRequestedModel(stripped);
2364
+ const gptIndex = tokens.indexOf("gpt");
2365
+ // `gpt6` with no separator tokenizes as one token, so the `gpt` + `6` pair
2366
+ // never forms; mirror lib and claim it here.
2367
+ const versionToken = gptIndex === -1 ? undefined : tokens[gptIndex + 1];
2368
+ // `gpt6` with no separator tokenizes as one token, so the `gpt` + `6` pair
2369
+ // never forms; mirror lib and claim it here.
2370
+ const isGpt6 = versionToken === "6" || tokens.includes("gpt6");
2371
+ // A bare `astra` token counts too: picker labels and OpenAI's own material
2372
+ // say "Astra" with no `gpt-6` prefix, so `Astra Pro` arrives with no version
2373
+ // tokens and would otherwise miss every branch and land on 5.5. Anchored so
2374
+ // an id naming a different GPT major version, `gpt-4-astra-x`, is not
2375
+ // claimed for the frontier model.
2376
+ const namesOtherGptVersion =
2377
+ versionToken !== undefined &&
2378
+ /^\d+$/.test(versionToken) &&
2379
+ versionToken !== "6";
2380
+ const isAstra = tokens.includes("astra") && !namesOtherGptVersion;
2381
+ if ((!isGpt6 && !isAstra) || tokens.includes("codex")) {
2382
+ return "";
2383
+ }
2384
+ if (tokens.includes("aeon")) return GPT_6_ASTRA_AEON_MODEL;
2385
+ return GPT_6_ASTRA_MODEL;
2386
+ }
2387
+
2388
+ // Daybreak slugs carry neither a `codex` nor a `gpt 5` token, so every other
2389
+ // resolver declines them and they would reach the 5.5 default. An unrecognised
2390
+ // Daybreak id resolves to `blue`, the more restricted of the two, so a typo
2391
+ // cannot silently upgrade a caller into the cyber-permissive model.
2392
+ function resolveDaybreakRequestedModel(stripped) {
2393
+ const tokens = tokenizeRequestedModel(stripped);
2394
+ if (!tokens.includes("daybreak")) {
2395
+ return "";
2396
+ }
2397
+ if (tokens.includes("red")) return DAYBREAK_RED_MODEL;
2398
+ return DAYBREAK_BLUE_MODEL;
2399
+ }
2400
+
2261
2401
  function resolveGpt56RequestedModel(stripped) {
2262
2402
  const tokens = tokenizeRequestedModel(stripped);
2263
2403
  const gptIndex = tokens.indexOf("gpt");
@@ -2316,11 +2456,21 @@ function normalizeRequestedModel(model) {
2316
2456
  return exactMatch;
2317
2457
  }
2318
2458
 
2459
+ const daybreakModel = resolveDaybreakRequestedModel(stripped);
2460
+ if (daybreakModel) {
2461
+ return daybreakModel;
2462
+ }
2463
+
2319
2464
  const codexModel = resolveCodexRequestedModel(normalized);
2320
2465
  if (codexModel) {
2321
2466
  return codexModel;
2322
2467
  }
2323
2468
 
2469
+ const gpt6Model = resolveGpt6RequestedModel(stripped);
2470
+ if (gpt6Model) {
2471
+ return gpt6Model;
2472
+ }
2473
+
2324
2474
  const gpt56Model = resolveGpt56RequestedModel(stripped);
2325
2475
  if (gpt56Model) {
2326
2476
  return gpt56Model;
@@ -6240,6 +6390,7 @@ export {
6240
6390
  coerceReasoningEffortForModel,
6241
6391
  resolveModelFamilyForStatus,
6242
6392
  canonicalizeRequestedModelName,
6393
+ WRAPPER_UNSUPPORTED_MODEL_FALLBACK_CHAIN,
6243
6394
  };
6244
6395
 
6245
6396
  // Run the wrapper only when actually launched (as the `codex-multi-auth-codex`