codex-multi-auth 2.15.0 → 2.16.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.
@@ -52,7 +52,21 @@ const TOOL_CAPABILITIES = {
52
52
  compaction: false,
53
53
  },
54
54
  };
55
- export const CURRENT_CODEX_MODEL = "gpt-5.3-codex";
55
+ /**
56
+ * Where every codex-named id routes. No codex model is left: upstream Codex
57
+ * dropped `gpt-5.3-codex` from its catalog on 2026-07-08, and OpenAI's
58
+ * deprecations page names `gpt-5.6-sol` as the replacement for every retired
59
+ * codex id (`gpt-5-codex`, `gpt-5.1-codex*`, `gpt-5.2-codex`). The export
60
+ * keeps its name so callers that mean "the model a codex request runs on"
61
+ * still read naturally.
62
+ */
63
+ export const CURRENT_CODEX_MODEL = "gpt-5.6-sol";
64
+ /**
65
+ * The retired codex mini ids (`gpt-5.1-codex-mini`, `gpt-5-codex-mini`,
66
+ * `codex-mini-latest`) go to Terra, OpenAI's named replacement for
67
+ * `gpt-5.1-codex-mini`, rather than up to Sol.
68
+ */
69
+ const CODEX_MINI_REPLACEMENT_MODEL = "gpt-5.6-terra";
56
70
  export const DEFAULT_MODEL = "gpt-5.5";
57
71
  // Model used for diagnostic live/quota probes (`check`, `report`, `best`).
58
72
  // Deliberately distinct from DEFAULT_MODEL: GPT-5.6 is the latest general family
@@ -70,18 +84,18 @@ export const DEFAULT_MODEL = "gpt-5.5";
70
84
  export const DEFAULT_PROBE_MODEL = "gpt-5.6-sol";
71
85
  // Single source of truth for the live/quota probe fallback chain. Both the
72
86
  // manager probe (lib/quota-probe.ts) and the runtime probe (lib/runtime/quota-probe.ts)
73
- // import this so the ordered candidate list cannot drift between them. It leads
74
- // with GPT-5.6 and steps down so accounts without 5.6 entitlement still resolve
75
- // a working probe model.
87
+ // import this so the ordered candidate list cannot drift between them.
88
+ //
89
+ // Every entry must be a model the Codex backend still serves. The chain used to
90
+ // end on `gpt-5.4` and three codex models; all four are gone from the upstream
91
+ // catalog (`gpt-5.4` carries `retirement_at: 2026-08-31`), so a probe that
92
+ // reached them spent requests on guaranteed failures. `gpt-6-luna` closes it
93
+ // because it is offered on the most plans of any catalog model (24).
76
94
  export const QUOTA_PROBE_MODEL_CHAIN = [
77
95
  DEFAULT_PROBE_MODEL,
78
96
  DEFAULT_MODEL,
79
- "gpt-5.4",
80
- "gpt-5.3-codex",
81
- "gpt-5.2-codex",
82
- "gpt-5-codex",
97
+ "gpt-6-luna",
83
98
  ];
84
- const LEGACY_CODEX_MODEL = "gpt-5-codex";
85
99
  /**
86
100
  * GPT-5.6 tiers, per the upstream Codex catalog
87
101
  * (openai/codex `codex-rs/models-manager/models.json`).
@@ -112,8 +126,8 @@ const GPT_5_6_LUNA_EFFORTS = [
112
126
  /**
113
127
  * GPT-6 Astra, OpenAI's 2026-09-03 frontier release.
114
128
  *
115
- * There is no Sol/Terra/Luna split this generation: the announced lineup is the
116
- * flagship plus `aeon`, a long-horizon variant built for runs measured in days.
129
+ * The launch lineup was the flagship plus `aeon`, a long-horizon variant built
130
+ * for runs measured in days; Sol and Luna followed on 2026-09-22 (below).
117
131
  * `gpt-6-astra` is the API model name OpenAI published at launch;
118
132
  * `gpt-6-astra-aeon` is the second slug that shipped beside it in the Codex
119
133
  * model list. "Astra Pro" is a plan tier, not a separate slug we have seen, so
@@ -139,6 +153,24 @@ const GPT_6_ASTRA_EFFORTS = [
139
153
  "max",
140
154
  "ultra",
141
155
  ];
156
+ /**
157
+ * GPT-6 Sol and Luna, added to the upstream Codex catalog on 2026-09-22
158
+ * (openai/codex #47332) beside Astra. Sol is the everyday workhorse and Luna
159
+ * the small, cheap tier; there is no GPT-6 Terra. Upstream migrates `gpt-5.5`,
160
+ * `gpt-5.6-sol` and `gpt-5.6-terra` users to Sol and `gpt-5.6-luna` users to
161
+ * Luna. Ladders and defaults below are the catalog's own values: Sol reaches
162
+ * `ultra`, Luna stops at `max` (same split as 5.6), both default to `medium`.
163
+ */
164
+ const GPT_6_SOL_MODEL = "gpt-6-sol";
165
+ const GPT_6_LUNA_MODEL = "gpt-6-luna";
166
+ const GPT_6_SOL_EFFORTS = GPT_6_ASTRA_EFFORTS;
167
+ const GPT_6_LUNA_EFFORTS = [
168
+ "low",
169
+ "medium",
170
+ "high",
171
+ "xhigh",
172
+ "max",
173
+ ];
142
174
  /**
143
175
  * Cyber-specialty models from the upstream Codex catalog
144
176
  * (openai/codex `codex-rs/models-manager/models.json`).
@@ -166,33 +198,43 @@ const GPT_5_5_RELEASE_MODEL = "gpt-5.5-2026-04-23";
166
198
  const GPT_5_5_PRO_RELEASE_MODEL = "gpt-5.5-pro-2026-04-23";
167
199
  const GPT_5_5_RELEASE_COMPAT_MODEL = "gpt-5.5-20260423";
168
200
  const GPT_5_5_PRO_RELEASE_COMPAT_MODEL = "gpt-5.5-pro-20260423";
201
+ /**
202
+ * Where an unrecognised `gpt-5.<minor>` id lands. Every minor below 5.5 is
203
+ * retired (OpenAI deprecations page, upstream catalog removals), so each maps
204
+ * to the replacement OpenAI names for it rather than to a model that no longer
205
+ * answers: 5.1/5.2 to Sol, 5.4 to GPT-6 Sol/Luna as upstream Codex migrates it,
206
+ * and every `pro` to the one live pro model.
207
+ */
169
208
  const GENERAL_GPT5_VERSION_CATALOG = {
170
209
  1: {
171
- base: "gpt-5.1",
210
+ base: GPT_5_6_SOL_MODEL,
211
+ pro: GPT_5_5_PRO_CANONICAL_MODEL,
172
212
  },
173
213
  2: {
174
- base: "gpt-5.2",
175
- pro: "gpt-5.2-pro",
214
+ base: GPT_5_6_SOL_MODEL,
215
+ pro: GPT_5_5_PRO_CANONICAL_MODEL,
176
216
  },
177
217
  4: {
178
- base: DEFAULT_MODEL,
179
- pro: "gpt-5.4-pro",
180
- mini: "gpt-5.4-mini",
181
- nano: "gpt-5.4-nano",
218
+ base: GPT_6_SOL_MODEL,
219
+ pro: GPT_5_5_PRO_CANONICAL_MODEL,
220
+ mini: GPT_6_LUNA_MODEL,
221
+ nano: GPT_6_LUNA_MODEL,
182
222
  },
183
223
  5: {
184
224
  base: GPT_5_5_CANONICAL_MODEL,
185
225
  pro: GPT_5_5_PRO_CANONICAL_MODEL,
186
- mini: "gpt-5-mini",
187
- nano: "gpt-5-nano",
226
+ mini: GPT_5_6_TERRA_MODEL,
227
+ nano: GPT_5_6_LUNA_MODEL,
188
228
  },
189
229
  };
190
230
  const GENERAL_GPT5_STABLE_VARIANTS = GENERAL_GPT5_VERSION_CATALOG[5];
231
+ // `gpt-5-mini`/`gpt-5-nano` point at snapshots OpenAI retires on 2026-12-11;
232
+ // the deprecations page names Terra and Luna as their replacements.
191
233
  const GENERAL_GPT5_GENERIC_VARIANTS = {
192
234
  base: DEFAULT_MODEL,
193
235
  pro: GPT_5_5_PRO_CANONICAL_MODEL,
194
- mini: "gpt-5-mini",
195
- nano: "gpt-5-nano",
236
+ mini: GPT_5_6_TERRA_MODEL,
237
+ nano: GPT_5_6_LUNA_MODEL,
196
238
  };
197
239
  /**
198
240
  * Effective model profiles keyed by canonical model name.
@@ -203,41 +245,6 @@ const GENERAL_GPT5_GENERIC_VARIANTS = {
203
245
  * present in the latest upstream release.
204
246
  */
205
247
  export const MODEL_PROFILES = {
206
- [CURRENT_CODEX_MODEL]: {
207
- normalizedModel: CURRENT_CODEX_MODEL,
208
- promptFamily: "gpt-5-codex",
209
- defaultReasoningEffort: "high",
210
- supportedReasoningEfforts: ["low", "medium", "high", "xhigh"],
211
- capabilities: TOOL_CAPABILITIES.basic,
212
- },
213
- "gpt-5.4": {
214
- normalizedModel: "gpt-5.4",
215
- promptFamily: "gpt-5.2",
216
- defaultReasoningEffort: "none",
217
- supportedReasoningEfforts: ["none", "low", "medium", "high", "xhigh"],
218
- capabilities: TOOL_CAPABILITIES.full,
219
- },
220
- "gpt-5.4-pro": {
221
- normalizedModel: "gpt-5.4-pro",
222
- promptFamily: "gpt-5.2",
223
- defaultReasoningEffort: "high",
224
- supportedReasoningEfforts: ["medium", "high", "xhigh"],
225
- capabilities: TOOL_CAPABILITIES.computerAndCompact,
226
- },
227
- "gpt-5.4-mini": {
228
- normalizedModel: "gpt-5.4-mini",
229
- promptFamily: "gpt-5.2",
230
- defaultReasoningEffort: "medium",
231
- supportedReasoningEfforts: ["medium"],
232
- capabilities: TOOL_CAPABILITIES.compactOnly,
233
- },
234
- "gpt-5.4-nano": {
235
- normalizedModel: "gpt-5.4-nano",
236
- promptFamily: "gpt-5.2",
237
- defaultReasoningEffort: "medium",
238
- supportedReasoningEfforts: ["medium"],
239
- capabilities: TOOL_CAPABILITIES.compactOnly,
240
- },
241
248
  // Like GPT-5.6, GPT-6 Astra ships its base instructions inline in the
242
249
  // upstream model catalog rather than as a `gpt_6_prompt.md`, so it stays on
243
250
  // the GPT-5.2 prompt family with every other post-5.2 general model. Adding
@@ -258,6 +265,20 @@ export const MODEL_PROFILES = {
258
265
  supportedReasoningEfforts: GPT_6_ASTRA_EFFORTS,
259
266
  capabilities: TOOL_CAPABILITIES.full,
260
267
  },
268
+ [GPT_6_SOL_MODEL]: {
269
+ normalizedModel: GPT_6_SOL_MODEL,
270
+ promptFamily: "gpt-5.2",
271
+ defaultReasoningEffort: "medium",
272
+ supportedReasoningEfforts: GPT_6_SOL_EFFORTS,
273
+ capabilities: TOOL_CAPABILITIES.full,
274
+ },
275
+ [GPT_6_LUNA_MODEL]: {
276
+ normalizedModel: GPT_6_LUNA_MODEL,
277
+ promptFamily: "gpt-5.2",
278
+ defaultReasoningEffort: "medium",
279
+ supportedReasoningEfforts: GPT_6_LUNA_EFFORTS,
280
+ capabilities: TOOL_CAPABILITIES.full,
281
+ },
261
282
  [DAYBREAK_BLUE_MODEL]: {
262
283
  normalizedModel: DAYBREAK_BLUE_MODEL,
263
284
  promptFamily: "gpt-5.2",
@@ -310,41 +331,12 @@ export const MODEL_PROFILES = {
310
331
  supportedReasoningEfforts: ["medium", "high", "xhigh"],
311
332
  capabilities: TOOL_CAPABILITIES.computerAndCompact,
312
333
  },
313
- "gpt-5.2-pro": {
314
- normalizedModel: "gpt-5.2-pro",
315
- promptFamily: "gpt-5.2",
316
- defaultReasoningEffort: "high",
317
- supportedReasoningEfforts: ["medium", "high", "xhigh"],
318
- capabilities: TOOL_CAPABILITIES.basic,
319
- },
320
- "gpt-5.2": {
321
- normalizedModel: "gpt-5.2",
322
- promptFamily: "gpt-5.2",
323
- defaultReasoningEffort: "none",
324
- supportedReasoningEfforts: ["none", "low", "medium", "high", "xhigh"],
325
- capabilities: TOOL_CAPABILITIES.basic,
326
- },
327
- "gpt-5.1": {
328
- normalizedModel: "gpt-5.1",
329
- promptFamily: "gpt-5.1",
330
- defaultReasoningEffort: "none",
331
- supportedReasoningEfforts: ["none", "low", "medium", "high"],
332
- capabilities: TOOL_CAPABILITIES.basic,
333
- },
334
- "gpt-5-mini": {
335
- normalizedModel: "gpt-5-mini",
336
- promptFamily: "gpt-5.2",
337
- defaultReasoningEffort: "medium",
338
- supportedReasoningEfforts: ["medium"],
339
- capabilities: TOOL_CAPABILITIES.compactOnly,
340
- },
341
- "gpt-5-nano": {
342
- normalizedModel: "gpt-5-nano",
343
- promptFamily: "gpt-5.2",
344
- defaultReasoningEffort: "medium",
345
- supportedReasoningEfforts: ["medium"],
346
- capabilities: TOOL_CAPABILITIES.compactOnly,
347
- },
334
+ // Every model older than 5.5 is retired: `gpt-5.1`, `gpt-5.2` and the whole
335
+ // 5.4 family left the upstream Codex catalog, the codex models and the
336
+ // chat-latest snapshots are past their shutdown date on OpenAI's
337
+ // deprecations page, and `gpt-5-mini`/`gpt-5-nano` shut down 2026-12-11.
338
+ // Their ids stay accepted as aliases of the named replacement (below) so an
339
+ // old config keeps working, but no request is sent under a dead name.
348
340
  };
349
341
  const MODEL_MAP = {};
350
342
  function addAlias(alias, normalizedModel) {
@@ -382,6 +374,11 @@ function addGpt6Aliases() {
382
374
  // rather than letting it fall through to GPT-5.5.
383
375
  addEffortAliases("astra", GPT_6_ASTRA_MODEL, GPT_6_ASTRA_EFFORTS);
384
376
  addEffortAliases("astra-aeon", GPT_6_ASTRA_AEON_MODEL, GPT_6_ASTRA_EFFORTS);
377
+ // No bare `sol`/`luna` aliases: those names already mean the 5.6 tiers to
378
+ // anyone who used them before 2026-09-22, and re-pointing them would swap a
379
+ // user's model generation without asking.
380
+ addEffortAliases(GPT_6_SOL_MODEL, GPT_6_SOL_MODEL, GPT_6_SOL_EFFORTS);
381
+ addEffortAliases(GPT_6_LUNA_MODEL, GPT_6_LUNA_MODEL, GPT_6_LUNA_EFFORTS);
385
382
  }
386
383
  function addDaybreakAliases() {
387
384
  addEffortAliases(DAYBREAK_BLUE_MODEL, DAYBREAK_BLUE_MODEL, DAYBREAK_EFFORTS);
@@ -396,35 +393,61 @@ function addGeneralAliases() {
396
393
  addReasoningAliases(GPT_5_5_PRO_CANONICAL_MODEL, GPT_5_5_PRO_CANONICAL_MODEL);
397
394
  addReasoningAliases(GPT_5_5_PRO_RELEASE_MODEL, GPT_5_5_PRO_CANONICAL_MODEL);
398
395
  addReasoningAliases(GPT_5_5_PRO_RELEASE_COMPAT_MODEL, GPT_5_5_PRO_CANONICAL_MODEL);
399
- addReasoningAliases("gpt-5.4", "gpt-5.4");
400
- addReasoningAliases("gpt-5.4-pro", "gpt-5.4-pro");
401
- addReasoningAliases("gpt-5.4-mini", "gpt-5.4-mini");
402
- addReasoningAliases("gpt-5.4-nano", "gpt-5.4-nano");
403
- addReasoningAliases("gpt-5.2-pro", "gpt-5.2-pro");
404
396
  addReasoningAliases("gpt-5-pro", GPT_5_5_PRO_CANONICAL_MODEL);
405
- addReasoningAliases("gpt-5.2", "gpt-5.2");
406
- addReasoningAliases("gpt-5.1", "gpt-5.1");
407
397
  addReasoningAliases("gpt-5", DEFAULT_MODEL);
408
- addReasoningAliases("gpt-5-mini", "gpt-5-mini");
409
- addReasoningAliases("gpt-5-nano", "gpt-5-nano");
410
- addReasoningAliases("gpt-5.1-chat-latest", "gpt-5.1");
411
- addReasoningAliases("gpt-5-chat-latest", DEFAULT_MODEL);
412
398
  }
413
- function addCodexAliases() {
414
- addReasoningAliases(CURRENT_CODEX_MODEL, CURRENT_CODEX_MODEL);
415
- addReasoningAliases("gpt-5.3-codex-spark", CURRENT_CODEX_MODEL);
416
- addReasoningAliases(LEGACY_CODEX_MODEL, CURRENT_CODEX_MODEL);
417
- addReasoningAliases("gpt-5.2-codex", CURRENT_CODEX_MODEL);
418
- addReasoningAliases("gpt-5.1-codex", CURRENT_CODEX_MODEL);
399
+ /**
400
+ * Retired general ids, each kept as an alias of the replacement OpenAI names
401
+ * for it: the upstream Codex catalog's migration target where it has one
402
+ * (`gpt-5.4` -> GPT-6 Sol, `gpt-5.4-mini` -> GPT-6 Luna), otherwise the
403
+ * deprecations page's recommended replacement. The effort-suffixed forms
404
+ * (`gpt-5.4-high`, `gpt-5.1-none`, ...) come along so old configs resolve;
405
+ * efforts the replacement does not accept are coerced as for any request.
406
+ */
407
+ const RETIRED_GENERAL_MODEL_REPLACEMENTS = {
408
+ "gpt-5.4": GPT_6_SOL_MODEL,
409
+ "gpt-5.4-mini": GPT_6_LUNA_MODEL,
410
+ "gpt-5.4-nano": GPT_6_LUNA_MODEL,
411
+ "gpt-5.4-pro": GPT_5_5_PRO_CANONICAL_MODEL,
412
+ "gpt-5.2": GPT_5_6_SOL_MODEL,
413
+ "gpt-5.2-pro": GPT_5_5_PRO_CANONICAL_MODEL,
414
+ "gpt-5.1": GPT_5_6_SOL_MODEL,
415
+ "gpt-5-mini": GPT_5_6_TERRA_MODEL,
416
+ "gpt-5-nano": GPT_5_6_LUNA_MODEL,
417
+ "gpt-5-chat-latest": GPT_5_6_SOL_MODEL,
418
+ "gpt-5.1-chat-latest": GPT_5_6_SOL_MODEL,
419
+ "gpt-5.2-chat-latest": GPT_5_6_SOL_MODEL,
420
+ "gpt-5.3-chat-latest": GPT_5_6_SOL_MODEL,
421
+ };
422
+ /**
423
+ * Retired codex ids. All shut down on OpenAI's deprecations page or left the
424
+ * upstream Codex catalog; OpenAI names `gpt-5.6-sol` as the replacement for
425
+ * the full-size ones and `gpt-5.6-terra` for `gpt-5.1-codex-mini`.
426
+ */
427
+ const RETIRED_CODEX_MODEL_REPLACEMENTS = {
428
+ "gpt-5.3-codex": CURRENT_CODEX_MODEL,
429
+ "gpt-5.3-codex-spark": CURRENT_CODEX_MODEL,
430
+ "gpt-5.2-codex": CURRENT_CODEX_MODEL,
431
+ "gpt-5.1-codex": CURRENT_CODEX_MODEL,
432
+ "gpt-5.1-codex-max": CURRENT_CODEX_MODEL,
433
+ "gpt-5-codex": CURRENT_CODEX_MODEL,
434
+ "codex-max": CURRENT_CODEX_MODEL,
435
+ "gpt-5.1-codex-mini": CODEX_MINI_REPLACEMENT_MODEL,
436
+ "gpt-5-codex-mini": CODEX_MINI_REPLACEMENT_MODEL,
437
+ "codex-mini-latest": CODEX_MINI_REPLACEMENT_MODEL,
438
+ };
439
+ /** Every retired id and its replacement, for diagnostics and tests. */
440
+ export const RETIRED_MODEL_REPLACEMENTS = {
441
+ ...RETIRED_GENERAL_MODEL_REPLACEMENTS,
442
+ ...RETIRED_CODEX_MODEL_REPLACEMENTS,
443
+ };
444
+ function addRetiredAliases() {
445
+ for (const [retired, replacement] of Object.entries(RETIRED_MODEL_REPLACEMENTS)) {
446
+ addReasoningAliases(retired, replacement);
447
+ }
419
448
  addAlias("gpt_5_codex", CURRENT_CODEX_MODEL);
420
- addReasoningAliases("codex-max", CURRENT_CODEX_MODEL);
421
- addReasoningAliases("gpt-5.1-codex-max", CURRENT_CODEX_MODEL);
422
- addAlias("codex-max", CURRENT_CODEX_MODEL);
423
- addAlias("codex-mini-latest", CURRENT_CODEX_MODEL);
424
- addReasoningAliases("gpt-5-codex-mini", CURRENT_CODEX_MODEL);
425
- addReasoningAliases("gpt-5.1-codex-mini", CURRENT_CODEX_MODEL);
426
449
  }
427
- addCodexAliases();
450
+ addRetiredAliases();
428
451
  addGeneralAliases();
429
452
  addGpt56Aliases();
430
453
  addGpt6Aliases();
@@ -461,39 +484,21 @@ function resolveStableGeneralGpt5Variant(variant) {
461
484
  }
462
485
  throw new Error(`Stable GPT-5 fallback is missing for variant ${variant}`);
463
486
  }
487
+ /**
488
+ * Any id carrying a `codex` token. Every codex model is retired, so this only
489
+ * picks the replacement: a `mini` codex id goes to Terra, everything else to
490
+ * Sol (see RETIRED_CODEX_MODEL_REPLACEMENTS).
491
+ */
464
492
  function resolveCodexCatalogModel(modelId) {
465
493
  const normalized = modelId.toLowerCase();
466
- if (normalized.includes("gpt-5.3-codex-spark") ||
467
- normalized.includes("gpt 5.3 codex spark")) {
468
- return CURRENT_CODEX_MODEL;
469
- }
470
- if (normalized.includes("gpt-5.3-codex") ||
471
- normalized.includes("gpt 5.3 codex")) {
472
- return CURRENT_CODEX_MODEL;
473
- }
474
- if (normalized.includes("gpt-5.2-codex") ||
475
- normalized.includes("gpt 5.2 codex")) {
476
- return CURRENT_CODEX_MODEL;
477
- }
478
- if (normalized.includes("gpt-5.1-codex-max") ||
479
- normalized.includes("gpt 5.1 codex max")) {
480
- return CURRENT_CODEX_MODEL;
481
- }
482
- if (normalized.includes("gpt-5.1-codex-mini") ||
483
- normalized.includes("gpt 5.1 codex mini") ||
484
- normalized.includes("codex-mini-latest") ||
485
- normalized.includes("gpt-5-codex-mini") ||
486
- normalized.includes("gpt 5 codex mini")) {
487
- return CURRENT_CODEX_MODEL;
494
+ if (!normalized.includes("codex")) {
495
+ return undefined;
488
496
  }
489
- if (normalized.includes("gpt-5-codex") ||
490
- normalized.includes("gpt 5 codex") ||
491
- normalized.includes("gpt-5.1-codex") ||
492
- normalized.includes("gpt 5.1 codex") ||
493
- normalized.includes("codex")) {
494
- return CURRENT_CODEX_MODEL;
497
+ // Anchored so `codex-minimal` (an effort suffix) is not read as a mini.
498
+ if (/codex[- ]mini(?!mal)/.test(normalized)) {
499
+ return CODEX_MINI_REPLACEMENT_MODEL;
495
500
  }
496
- return undefined;
501
+ return CURRENT_CODEX_MODEL;
497
502
  }
498
503
  /**
499
504
  * Resolve GPT-5.6 identifiers that are not exact aliases (for example a future
@@ -514,8 +519,9 @@ function resolveCodexCatalogModel(modelId) {
514
519
  * `gpt 5` token pair) and every unrecognised GPT-6 id lands on `DEFAULT_MODEL`,
515
520
  * running GPT-5.5 for a caller who asked for the frontier model. `aeon` keeps
516
521
  * its own canonical id because it is a behaviourally different model (long
517
- * horizon), not a rename of the flagship; everything else resolves to the
518
- * flagship, matching OpenAI's bare `gpt-6` alias.
522
+ * horizon), not a rename of the flagship. A `sol`/`luna` tier token picks that
523
+ * tier; everything else resolves to the flagship, matching OpenAI's bare
524
+ * `gpt-6` alias.
519
525
  *
520
526
  * Ids carrying a `codex` token are left to `resolveCodexCatalogModel`, exactly
521
527
  * as the 5.6 resolver defers them.
@@ -547,6 +553,16 @@ function resolveGpt6CatalogModel(modelId) {
547
553
  }
548
554
  if (tokens.includes("aeon"))
549
555
  return GPT_6_ASTRA_AEON_MODEL;
556
+ if (isAstra)
557
+ return GPT_6_ASTRA_MODEL;
558
+ // Before Sol and Luna existed every non-Astra GPT-6 id fell to the line
559
+ // below, so `gpt-6-luna` silently ran Astra at 100x Luna's price. `terra`
560
+ // goes to Sol because there is no GPT-6 Terra and upstream migrates
561
+ // `gpt-5.6-terra` users to Sol.
562
+ if (tokens.includes("luna"))
563
+ return GPT_6_LUNA_MODEL;
564
+ if (tokens.includes("sol") || tokens.includes("terra"))
565
+ return GPT_6_SOL_MODEL;
550
566
  return GPT_6_ASTRA_MODEL;
551
567
  }
552
568
  /**
@@ -647,6 +663,17 @@ export function resolveNormalizedModel(model) {
647
663
  if (mappedModel) {
648
664
  return mappedModel;
649
665
  }
666
+ // `max`/`ultra` are not generated as aliases for the pre-5.6 ids, so
667
+ // `gpt-5.3-chat-latest-max` missed the retired table and the general GPT-5
668
+ // resolver sent it to 5.5 instead of its replacement. Retry the lookup
669
+ // without the suffix before any fuzzy resolver runs.
670
+ const withoutTopEffort = modelId.replace(/-(max|ultra)$/i, "");
671
+ if (withoutTopEffort !== modelId) {
672
+ const mappedWithoutEffort = lookupMappedModel(withoutTopEffort);
673
+ if (mappedWithoutEffort) {
674
+ return mappedWithoutEffort;
675
+ }
676
+ }
650
677
  // Daybreak first: its slugs carry neither a `codex` nor a `gpt 5` token, so
651
678
  // every other resolver declines them and they would reach DEFAULT_MODEL.
652
679
  const daybreakCatalogModel = resolveDaybreakCatalogModel(modelId);
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AAkCvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAqDtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,GACC,MAAM,CAmBR;AAED,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAER;AA0ED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKpE;AAED,wBAAgB,2BAA2B,CAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,MAAM,CAQR;AA2fD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CA6LrC"}
1
+ {"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AAkCvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAqDtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,GACC,MAAM,CAmBR;AAED,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAER;AA0ED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKpE;AAED,wBAAgB,2BAA2B,CAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,MAAM,CAQR;AA0fD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CA6LrC"}
@@ -496,10 +496,9 @@ function buildResponsesRequestContext(req, body) {
496
496
  method: "POST",
497
497
  upstreamPath: URL_PATHS.CODEX_RESPONSES,
498
498
  model,
499
- // The /codex/responses path is codex-family. A model-less request must
500
- // bucket into the codex family (rotation/cooldown/budget), so fall back to
501
- // the current codex model — NOT the general DEFAULT_MODEL (gpt-5.5), whose
502
- // family is gpt-5.2 and would mis-account a pass-through codex request.
499
+ // A model-less request buckets under the model a codex request runs on.
500
+ // With every codex model retired that is `gpt-5.6-sol`, whose family is
501
+ // gpt-5.2, the same family as DEFAULT_MODEL.
503
502
  family: getModelFamily(model ?? CURRENT_CODEX_MODEL),
504
503
  stream: parsedBody?.stream === true,
505
504
  sessionKey: resolveSessionKey(headers, parsedBody),
@@ -12,14 +12,31 @@ export interface UsageModelPricing {
12
12
  * row under-counts it by half and lets a `maxCostUsd` cap overrun.
13
13
  *
14
14
  * A tier absent from this map is deliberately NOT approximated from the
15
- * standard rate. Only Astra's Fast multiplier is published; inventing one for
15
+ * standard rate. Only the GPT-6 Fast rates are published; inventing one for
16
16
  * the rest would move a budget's trip point on a guess, which is the failure
17
17
  * this file exists to avoid. `estimateUsageCostUsd` reports an unlisted tier
18
18
  * as unknown cost instead, so a budget fails closed the same way it does for
19
19
  * an unpriced model.
20
20
  */
21
21
  serviceTiers?: Partial<Record<UsageServiceTier, UsageModelPricing>>;
22
+ /**
23
+ * Rates once a response's input exceeds `SHORT_CONTEXT_MAX_INPUT_TOKENS`.
24
+ *
25
+ * OpenAI bills a GPT-6 request whose context crosses 272K at a separate,
26
+ * higher rate. A row that declares this block (every tier inside it too) is
27
+ * priced from it past the threshold. A row that declares it but whose
28
+ * resolved service tier does not reports unknown cost there instead of the
29
+ * cheaper short-context figure, for the same fail-closed reason as an
30
+ * unlisted tier. Rows with no long-context data at all are unchanged.
31
+ */
32
+ longContext?: UsageModelPricing;
22
33
  }
34
+ /**
35
+ * Largest input still billed at the short-context rate. OpenAI's GPT-6 model
36
+ * pages say "Prompts with more than 272K input tokens are priced at 2x input
37
+ * and cache rates", so exactly 272,000 is short and 272,001 is long.
38
+ */
39
+ export declare const SHORT_CONTEXT_MAX_INPUT_TOKENS = 272000;
23
40
  /**
24
41
  * Models the router can normalize to that have no published rate here yet.
25
42
  *
@@ -34,7 +51,7 @@ export interface UsageModelPricing {
34
51
  * `test/usage-pricing-coverage.test.ts` fails if a NEW routable model appears
35
52
  * in neither list.
36
53
  */
37
- 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"];
54
+ export declare const UNPRICED_ROUTABLE_MODELS: readonly ["gpt-6-astra-aeon", "gpt-daybreak-blue-latest", "gpt-daybreak-red-latest", "gpt-5.5-pro"];
38
55
  export declare function getUsageModelPricing(model: string | null | undefined): UsageModelPricing | null;
39
56
  export declare function estimateUsageCostUsd(model: string | null | undefined, tokens: UsageTokenCounts): number | null;
40
57
  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,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAErE,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;IAChC;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC,CAAC;CACpE;AAyFD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,0MAkB3B,CAAC;AAOX,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,iBAAiB,GAAG,IAAI,CAiB1B;AAmBD,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,MAAM,EAAE,gBAAgB,GACtB,MAAM,GAAG,IAAI,CA8Bf;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":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAErE,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;IAChC;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACpE;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,SAAU,CAAC;AA8HtD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,qGAW3B,CAAC;AAOX,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,iBAAiB,GAAG,IAAI,CA0B1B;AAmCD,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,MAAM,EAAE,gBAAgB,GACtB,MAAM,GAAG,IAAI,CAsCf;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAEzE"}