@bman654/clodex 2.10.0 → 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.
package/README.md CHANGED
@@ -241,10 +241,11 @@ Manage favorite models (max 20) and short aliases. Favorites feed the endpoint-m
241
241
 
242
242
  #### Context stops and the pricing boundary
243
243
 
244
- A context window is a cost dial as much as a capacity number. OpenAI prices GPT-5.6
245
- prompts above **272,000 input tokens at 2x input and 1.5x output for the full
246
- request**, which is why the Codex catalog reports a 272,000 window rather than the
247
- model's ceiling. Clodex follows that: the default `standard` stop stays under the
244
+ A context window is a cost dial as much as a capacity number. OpenAI prices GPT-5.5
245
+ and later prompts above **272,000 input tokens at 2x input and 1.5x output for the
246
+ full request**, which is why the Codex catalog reports a 272,000 window rather than
247
+ the model's ceiling. Newer families inherit the same boundary, so a model released
248
+ after this was written is covered without a clodex update. Clodex follows that: the default `standard` stop stays under the
248
249
  line, and a larger window is something you ask for.
249
250
 
250
251
  ```sh
package/dist/cli.js CHANGED
@@ -382,7 +382,7 @@ import { join } from "path";
382
382
  // package.json
383
383
  var package_default = {
384
384
  name: "@bman654/clodex",
385
- version: "2.10.0",
385
+ version: "2.11.0",
386
386
  publishConfig: {
387
387
  access: "public"
388
388
  },
@@ -469,7 +469,7 @@ var package_default = {
469
469
 
470
470
  // src/constants.ts
471
471
  var CODEX_RESPONSES_LITE_WS_URL = "wss://chatgpt.com/backend-api/codex/responses";
472
- var CODEX_RESPONSES_LITE_VERSION = "0.144.1";
472
+ var CODEX_RESPONSES_LITE_VERSION = "0.153.3";
473
473
  var CODEX_RESPONSES_WEBSOCKETS_BETA = "responses_websockets=2026-02-06";
474
474
  var TEST_TIMEOUT_MS = 1e4;
475
475
  var CONFLICTING_ENV_VARS = [
@@ -5873,6 +5873,18 @@ var CHATGPT_CODEX_UNSUPPORTED_MODELS = /* @__PURE__ */ new Set([
5873
5873
  // confirmed: rejected by chatgpt.com/backend-api/codex
5874
5874
  ]);
5875
5875
  var OPENAI_OAUTH_MODEL_SEEDS = [
5876
+ // GPT-6 family. The window and ceiling are what the live Codex catalog returned on
5877
+ // 2026-09-04 and are deliberately NOT the published API numbers: the model card
5878
+ // lists a 1,050,000 context window, but the Codex client is served a smaller one,
5879
+ // and this path is Codex-only. Output limit and the pricing band come from the
5880
+ // card (https://developers.openai.com/api/docs/models/gpt-6-astra), which states
5881
+ // "Prompts with more than 272K input tokens are priced at 2x input and cache rates
5882
+ // and 1.5x output for the full request" — the same boundary the GPT-5.6 family has.
5883
+ { id: "gpt-6-astra", name: "GPT-6 Astra", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true },
5884
+ // "An alias for our flagship general-purpose models, with safeguards calibrated
5885
+ // for defensive cybersecurity work" — access is gated on a separate opt-in
5886
+ // program, so most installs will never see this id in their catalog.
5887
+ { id: "gpt-daybreak-blue-latest", name: "GPT Daybreak Blue", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true, useResponsesLite: true, preferWebSockets: true },
5876
5888
  // GPT-5.6 family (Sol / Terra / Luna)
5877
5889
  { id: "gpt-5.6-sol", name: "GPT-5.6 Sol", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true },
5878
5890
  { id: "gpt-5.6-terra", name: "GPT-5.6 Terra", contextWindow: 272e3, maxContextWindow: 872e3, maxOutputTokens: 128e3, reasoning: true },
@@ -5891,9 +5903,17 @@ var OPENAI_OAUTH_MODEL_SEEDS = [
5891
5903
  { id: "o1", name: "o1", reasoning: true },
5892
5904
  { id: "o1-mini", name: "o1 Mini", reasoning: true }
5893
5905
  ];
5894
- var PRICING_BOUNDARY_FAMILIES = /^gpt-5\.[56]/;
5906
+ function hasPricingBoundary(id) {
5907
+ const version = /^gpt-(\d+)(?:\.(\d+))?(?:-|$)/i.exec(id);
5908
+ if (version) {
5909
+ const major = Number(version[1]);
5910
+ const minor = version[2] ? Number(version[2]) : 0;
5911
+ if (major > 5 || major === 5 && minor >= 5) return true;
5912
+ }
5913
+ return /^gpt-daybreak(?:-|$)/i.test(id);
5914
+ }
5895
5915
  function openAiPricingMetadata(id) {
5896
- if (!PRICING_BOUNDARY_FAMILIES.test(id)) return {};
5916
+ if (!hasPricingBoundary(id)) return {};
5897
5917
  return {
5898
5918
  pricingBoundary: GPT_5_6_PRICING_BOUNDARY,
5899
5919
  pricingBoundaryNote: GPT_5_6_PRICING_NOTE
@@ -5910,7 +5930,8 @@ function applyOAuthSeedContextMetadata(models) {
5910
5930
  effectiveContextPercent: model.effectiveContextPercent ?? seed?.effectiveContextPercent ?? DEFAULT_EFFECTIVE_CONTEXT_PERCENT,
5911
5931
  pricingBoundary: model.pricingBoundary ?? seed?.pricingBoundary ?? pricing.pricingBoundary,
5912
5932
  pricingBoundaryNote: model.pricingBoundaryNote ?? seed?.pricingBoundaryNote ?? pricing.pricingBoundaryNote,
5913
- maxOutputTokens: model.maxOutputTokens ?? seed?.maxOutputTokens
5933
+ maxOutputTokens: model.maxOutputTokens ?? seed?.maxOutputTokens,
5934
+ reasoning: seed?.reasoning ?? model.reasoning
5914
5935
  };
5915
5936
  });
5916
5937
  }
@@ -10253,7 +10274,7 @@ async function createLanguageModel(spec) {
10253
10274
  }
10254
10275
  var ANTHROPIC_EFFORT_LEVELS = ["low", "medium", "high"];
10255
10276
  var OPENAI_EFFORT_LEVELS = ["low", "medium", "high", "xhigh"];
10256
- var GPT_56_EFFORT_LEVELS = ["none", "low", "medium", "high", "xhigh", "max"];
10277
+ var CODEX_EXTENDED_EFFORT_LEVELS = ["none", "low", "medium", "high", "xhigh", "max"];
10257
10278
  var GEMINI_EFFORT_LEVELS = ["low", "medium", "high"];
10258
10279
  var MISTRAL_EFFORT_LEVELS = ["high", "off"];
10259
10280
  var XAI_EFFORT_LEVELS = ["none", "low", "medium", "high"];
@@ -10417,14 +10438,32 @@ function mapCodexEffortToAnthropic(effort) {
10417
10438
  return void 0;
10418
10439
  }
10419
10440
  }
10420
- function isGpt56Model(modelId) {
10421
- return /^gpt-5\.6(?:-|$)/i.test(modelId);
10441
+ function isCodexReasoningFamily(modelId) {
10442
+ return !isChatVariant(modelId) && supportsExtendedCodexEffort(modelId);
10443
+ }
10444
+ function isChatVariant(modelId) {
10445
+ return /-chat(?:-|$)/i.test(modelId);
10446
+ }
10447
+ function supportsExtendedCodexEffort(modelId) {
10448
+ const version = /^gpt-(\d+)(?:\.(\d+))?(?:-|$)/i.exec(modelId);
10449
+ if (version) {
10450
+ const major = Number(version[1]);
10451
+ const minor = version[2] ? Number(version[2]) : 0;
10452
+ if (major > 5 || major === 5 && minor >= 6) return true;
10453
+ }
10454
+ return /^gpt-daybreak(?:-|$)/i.test(modelId);
10455
+ }
10456
+ function supportsNoneEffort(modelId) {
10457
+ return /^gpt-5\.6(?:-|$)/i.test(modelId) || /^gpt-daybreak-blue(?:-|$)/i.test(modelId);
10422
10458
  }
10423
10459
  function isReasoningSummaryUnsupportedModel(modelId) {
10424
10460
  return /codex-spark(?:-|$)/i.test(modelId);
10425
10461
  }
10426
10462
  function mapCodexEffortToOpenAI(effort, modelId) {
10427
- if (modelId && isGpt56Model(modelId) && GPT_56_EFFORT_LEVELS.includes(effort)) {
10463
+ if (effort === "none") {
10464
+ return modelId && supportsNoneEffort(modelId) ? "none" : void 0;
10465
+ }
10466
+ if (modelId && supportsExtendedCodexEffort(modelId) && CODEX_EXTENDED_EFFORT_LEVELS.includes(effort)) {
10428
10467
  return effort;
10429
10468
  }
10430
10469
  if (effort === "xhigh") return "high";
@@ -10565,9 +10604,9 @@ function getReasoningCapabilities(npm, modelId, metadata) {
10565
10604
  }
10566
10605
  if (npm === "@ai-sdk/openai" || npm === "@ai-sdk/azure") {
10567
10606
  const prefersResponses = modelPrefersResponsesApi(modelId);
10568
- if (prefersResponses || metadata?.reasoning) {
10607
+ if (prefersResponses || isCodexReasoningFamily(modelId) || metadata?.reasoning) {
10569
10608
  return {
10570
- levels: isGpt56Model(modelId) ? [...GPT_56_EFFORT_LEVELS] : [...OPENAI_EFFORT_LEVELS],
10609
+ levels: supportsExtendedCodexEffort(modelId) ? CODEX_EXTENDED_EFFORT_LEVELS.filter((level) => level !== "none" || supportsNoneEffort(modelId)) : [...OPENAI_EFFORT_LEVELS],
10571
10610
  defaultLevel: "medium",
10572
10611
  supportsSummaries: true,
10573
10612
  mode: "controllable",
@@ -10731,10 +10770,14 @@ function effortProviderOptions(npm, effort, modelId, metadata) {
10731
10770
  return mapped ? { openrouter: { reasoning: { effort: mapped, exclude: false } } } : void 0;
10732
10771
  }
10733
10772
  if (npm === "@ai-sdk/openai" || npm === "@ai-sdk/azure") {
10734
- if (!modelId || !modelPrefersResponsesApi(modelId)) return void 0;
10773
+ if (!modelId || isChatVariant(modelId)) return void 0;
10774
+ if (!(modelPrefersResponsesApi(modelId) || isCodexReasoningFamily(modelId))) {
10775
+ return void 0;
10776
+ }
10735
10777
  const reasoningEffort = mapCodexEffortToOpenAI(effort, modelId);
10736
10778
  if (!reasoningEffort) return void 0;
10737
- return isReasoningSummaryUnsupportedModel(modelId) ? { openai: { reasoningEffort, reasoningSummary: null } } : { openai: { reasoningEffort } };
10779
+ const openaiOptions = { reasoningEffort, forceReasoning: true };
10780
+ return isReasoningSummaryUnsupportedModel(modelId) ? { openai: { ...openaiOptions, reasoningSummary: null } } : { openai: openaiOptions };
10738
10781
  }
10739
10782
  if (npm === "@ai-sdk/xai") {
10740
10783
  if (!modelId || !isXaiReasoningEffortModel(modelId)) return void 0;
@@ -15021,7 +15064,7 @@ function parseOpenAiModelEntries(body) {
15021
15064
  }
15022
15065
  return [];
15023
15066
  }
15024
- function buildDynamicOAuthModel(entry, seedById) {
15067
+ function buildDynamicOAuthModel(entry, seedById, codexCatalog) {
15025
15068
  const seed = seedById.get(entry.id);
15026
15069
  if (seed) {
15027
15070
  return {
@@ -15052,7 +15095,19 @@ function buildDynamicOAuthModel(entry, seedById) {
15052
15095
  ...openAiPricingMetadata(id),
15053
15096
  modelFormat: "openai",
15054
15097
  npm: "@ai-sdk/openai",
15055
- reasoning: modelPrefersResponsesApi(id),
15098
+ // Assume a model from the Codex listing reasons. That endpoint reports no
15099
+ // reasoning field of its own, so the old `modelPrefersResponsesApi(id)` was an
15100
+ // id-pattern GUESS that silently said "no" to every family it had not been
15101
+ // taught yet — gpt-6-astra and gpt-daybreak-blue-latest both landed as
15102
+ // non-reasoning that way, which dropped the user's chosen effort and removed
15103
+ // the effort selector from the patched binary (getPatchReasoningCapabilities
15104
+ // early-returns on a `false`). Verified against all 11 models in the live
15105
+ // catalog on 2026-09-04.
15106
+ //
15107
+ // This only decides what the effort UI offers. It is NOT on its own enough to
15108
+ // put reasoning.effort on the wire — effortProviderOptions admits by family —
15109
+ // so a wrong `true` here costs an unusable menu entry, not a 400.
15110
+ reasoning: codexCatalog ? true : modelPrefersResponsesApi(id),
15056
15111
  useResponsesLite: entry.useResponsesLite,
15057
15112
  preferWebSockets: entry.preferWebSockets
15058
15113
  };
@@ -15081,7 +15136,7 @@ async function fetchJsonWithAuth(url, accessToken, timeoutMs) {
15081
15136
  async function refreshOpenAiOAuthModels(accessToken) {
15082
15137
  const TIMEOUT_MS = 1e4;
15083
15138
  const seedById = new Map(buildOpenAiOAuthModels().map((m) => [m.id, m]));
15084
- const toModels = (entries) => entries.map((entry) => buildDynamicOAuthModel(entry, seedById));
15139
+ const toModels = (entries, codexCatalog) => entries.map((entry) => buildDynamicOAuthModel(entry, seedById, codexCatalog));
15085
15140
  const claudeVersion = getInstalledClaudeVersion();
15086
15141
  const codexResult = await fetchJsonWithAuth(
15087
15142
  `https://chatgpt.com/backend-api/codex/models?client_version=${claudeVersion}`,
@@ -15090,7 +15145,7 @@ async function refreshOpenAiOAuthModels(accessToken) {
15090
15145
  );
15091
15146
  const codexEntries = parseOpenAiModelEntries(codexResult.body);
15092
15147
  if (codexEntries.length > 0) {
15093
- return { models: toModels(codexEntries), source: "live" };
15148
+ return { models: toModels(codexEntries, true), source: "live" };
15094
15149
  }
15095
15150
  const chatGptResult = await fetchJsonWithAuth(
15096
15151
  "https://chatgpt.com/backend-api/models",
@@ -15099,7 +15154,7 @@ async function refreshOpenAiOAuthModels(accessToken) {
15099
15154
  );
15100
15155
  const chatGptEntries = parseOpenAiModelEntries(chatGptResult.body).filter(({ id }) => !CHATGPT_CODEX_UNSUPPORTED_MODELS.has(id));
15101
15156
  if (chatGptEntries.length > 0) {
15102
- return { models: toModels(chatGptEntries), source: "live" };
15157
+ return { models: toModels(chatGptEntries, false), source: "live" };
15103
15158
  }
15104
15159
  const failures = [codexResult.error, chatGptResult.error].filter((error) => error !== void 0);
15105
15160
  const credentialFailure = failures.find((error) => /(?:\brejected\b|\b401\b|\b403\b)/i.test(error));