@oh-my-pi/pi-catalog 16.4.0 → 16.4.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.4.2] - 2026-07-10
6
+
7
+ ### Fixed
8
+
9
+ - Fixed OpenAI Codex model discovery to include the Codex version header alongside the client_version query parameter.
10
+
11
+ ## [16.4.1] - 2026-07-10
12
+
13
+ ### Added
14
+
15
+ - Added GPT-5.6 Luna, Sol, and Terra models
16
+ - Added perplexity-academic-researcher model
17
+
18
+ ### Changed
19
+
20
+ - Updated context windows for multiple GPT-5.6 models
21
+ - Increased max tokens for several models
22
+ - Updated cache write costs for GPT-5.6 variants
23
+ - Reduced pricing for select models
24
+
25
+ ### Removed
26
+
27
+ - Removed the generated GPT-5.6 pro-reasoning aliases (`gpt-5.6-{luna,sol,terra}-pro`) from the `openai-codex` subscription provider — pro reasoning is not offered on subscriptions; the `openai` API-key aliases remain
28
+
5
29
  ## [16.4.0] - 2026-07-10
6
30
 
7
31
  ### Breaking Changes
@@ -19,8 +19,6 @@ export interface CodexModelDiscoveryOptions {
19
19
  signal?: AbortSignal;
20
20
  /** Optional fetch implementation override for tests. */
21
21
  fetchFn?: typeof fetch;
22
- /** Optional registry fetch implementation override for client version lookup. */
23
- registryFetchFn?: typeof fetch;
24
22
  }
25
23
  /**
26
24
  * Normalized Codex discovery response.
@@ -56,14 +56,14 @@ export interface OpenAIModelManagerConfig {
56
56
  export declare function openaiModelManagerOptions(config?: OpenAIModelManagerConfig): ModelManagerOptions<"openai-responses">;
57
57
  /**
58
58
  * Re-derive the generated pro-reasoning aliases (`gpt-5.6-*-pro`) for the
59
- * first-party `openai`/`openai-codex` gpt-5.6 rows. Each alias inherits the
60
- * base row's metadata, requests the base wire id via `requestModelId`, and
61
- * sets `reasoningMode: "pro"` so Responses-family request builders emit
59
+ * first-party `openai` gpt-5.6 rows. Each alias inherits the base row's
60
+ * metadata, requests the base wire id via `requestModelId`, and sets
61
+ * `reasoningMode: "pro"` so Responses-family request builders emit
62
62
  * `reasoning: { mode: "pro" }`. Called by the models.json generator after all
63
- * sources merge: stale copies of the owned aliases (previous snapshot) are
64
- * dropped and re-projected from the current base rows so alias metadata always
65
- * tracks the base, while a real upstream model that occupies an alias id wins
66
- * and suppresses the projection.
63
+ * sources merge: stale copies of the owned aliases (previous snapshot,
64
+ * including retired `openai-codex` rows) are dropped and re-projected from the
65
+ * current base rows so alias metadata always tracks the base, while a real
66
+ * upstream model that occupies an alias id wins and suppresses the projection.
67
67
  */
68
68
  export declare function projectOpenAIProReasoningAliases(models: readonly ModelSpec<Api>[]): ModelSpec<Api>[];
69
69
  export interface GroqModelManagerConfig {
@@ -2,10 +2,15 @@
2
2
  * Constants for OpenAI Codex (ChatGPT OAuth) backend
3
3
  */
4
4
  export declare const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
5
+ /**
6
+ * Pinned OpenAI Codex client version (corresponds to @openai/codex package version).
7
+ */
8
+ export declare const CODEX_CLIENT_VERSION = "0.144.1";
5
9
  export declare const OPENAI_HEADERS: {
6
10
  readonly BETA: "OpenAI-Beta";
7
11
  readonly ACCOUNT_ID: "chatgpt-account-id";
8
12
  readonly ORIGINATOR: "originator";
13
+ readonly VERSION: "version";
9
14
  readonly SESSION_ID: "session_id";
10
15
  readonly CONVERSATION_ID: "conversation_id";
11
16
  readonly SCOPED_SESSION_ID: "session-id";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-catalog",
4
- "version": "16.4.0",
4
+ "version": "16.4.2",
5
5
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -34,12 +34,12 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@bufbuild/protobuf": "^2.12.0",
37
- "@oh-my-pi/pi-utils": "16.4.0",
38
- "arktype": "^2.2.0",
37
+ "@oh-my-pi/pi-utils": "16.4.2",
38
+ "arktype": "2.2.2",
39
39
  "zod": "^4"
40
40
  },
41
41
  "devDependencies": {
42
- "@oh-my-pi/pi-ai": "16.4.0",
42
+ "@oh-my-pi/pi-ai": "16.4.2",
43
43
  "@types/bun": "^1.3.14"
44
44
  },
45
45
  "engines": {
@@ -595,12 +595,13 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
595
595
  // Azure OpenAI and GitHub Copilot Responses paths require tool results
596
596
  // to strictly match prior tool calls when building Responses inputs.
597
597
  strictResponsesPairing: isAzure || spec.provider === "github-copilot",
598
- // GitHub Copilot's Responses endpoint rejects the `detail: "original"`
599
- // image hint with a 400; every other host preserves native-resolution
600
- // frames (snapcompact relies on `original`). Detect Copilot by provider id
601
- // or base-URL host (mirroring the Anthropic compat builder) so a model
602
- // pointed at the Copilot host under a different provider id still clamps.
603
- supportsImageDetailOriginal: !modelMatchesHost({ provider: spec.provider, baseUrl }, "githubCopilot"),
598
+ // GitHub Copilot and xAI OAuth reject `detail: "original"` (400 / 422).
599
+ // Every other host preserves native-resolution frames (snapcompact relies
600
+ // on `original`). Detect Copilot by provider id or base-URL host so a
601
+ // model pointed at the Copilot host under a different provider id still
602
+ // clamps; xai-oauth is provider-id only (same host family as paid `xai`).
603
+ supportsImageDetailOriginal:
604
+ spec.provider !== "xai-oauth" && !modelMatchesHost({ provider: spec.provider, baseUrl }, "githubCopilot"),
604
605
  reasoningEffortMap: {},
605
606
  supportsReasoningParams: true,
606
607
  thinkingFormat,
@@ -1,14 +1,11 @@
1
- import type { FetchImpl } from "@oh-my-pi/pi-utils";
2
1
  import { type } from "arktype";
3
2
  import type { ModelSpec } from "../types";
4
- import { discoveryFetch, isRecord } from "../utils";
5
- import { CODEX_BASE_URL, OPENAI_HEADER_VALUES, OPENAI_HEADERS } from "../wire/codex";
3
+ import { discoveryFetch } from "../utils";
4
+ import { CODEX_BASE_URL, CODEX_CLIENT_VERSION, OPENAI_HEADER_VALUES, OPENAI_HEADERS } from "../wire/codex";
6
5
 
7
6
  const DEFAULT_MODEL_LIST_PATHS = ["/codex/models", "/models"] as const;
8
7
  const DEFAULT_CONTEXT_WINDOW = 272_000;
9
8
  const DEFAULT_MAX_TOKENS = 128_000;
10
- const DEFAULT_CODEX_CLIENT_VERSION = "0.99.0";
11
- const NPM_CODEX_LATEST_URL = "https://registry.npmjs.org/@openai%2Fcodex/latest";
12
9
  const CODEX_REMOTE_COMPACTION = {
13
10
  enabled: true,
14
11
  api: "openai-codex-responses",
@@ -64,8 +61,6 @@ export interface CodexModelDiscoveryOptions {
64
61
  signal?: AbortSignal;
65
62
  /** Optional fetch implementation override for tests. */
66
63
  fetchFn?: typeof fetch;
67
- /** Optional registry fetch implementation override for client version lookup. */
68
- registryFetchFn?: typeof fetch;
69
64
  }
70
65
 
71
66
  /**
@@ -86,12 +81,8 @@ export async function fetchCodexModels(options: CodexModelDiscoveryOptions): Pro
86
81
  const fetchFn = discoveryFetch(options.fetchFn);
87
82
  const baseUrl = normalizeBaseUrl(options.baseUrl);
88
83
  const paths = normalizePaths(options.paths);
89
- const headers = buildCodexHeaders(options);
90
- const clientVersion = await resolveCodexClientVersion(
91
- options.clientVersion,
92
- options.registryFetchFn ?? fetchFn,
93
- options.signal,
94
- );
84
+ const clientVersion = normalizeClientVersion(options.clientVersion) ?? CODEX_CLIENT_VERSION;
85
+ const headers = buildCodexHeaders(options, clientVersion);
95
86
 
96
87
  let sawSuccessfulResponse = false;
97
88
  for (const path of paths) {
@@ -156,7 +147,7 @@ function buildModelsUrl(baseUrl: string, path: string, clientVersion: string | u
156
147
  return url.toString();
157
148
  }
158
149
 
159
- function buildCodexHeaders(options: CodexModelDiscoveryOptions): Headers {
150
+ function buildCodexHeaders(options: CodexModelDiscoveryOptions, clientVersion: string): Headers {
160
151
  const headers = new Headers(options.headers);
161
152
  headers.set("Authorization", `Bearer ${options.accessToken}`);
162
153
  if (options.accountId && options.accountId.trim().length > 0) {
@@ -164,42 +155,11 @@ function buildCodexHeaders(options: CodexModelDiscoveryOptions): Headers {
164
155
  }
165
156
  headers.set(OPENAI_HEADERS.BETA, OPENAI_HEADER_VALUES.BETA_RESPONSES);
166
157
  headers.set(OPENAI_HEADERS.ORIGINATOR, OPENAI_HEADER_VALUES.ORIGINATOR_CODEX);
158
+ headers.set(OPENAI_HEADERS.VERSION, clientVersion);
167
159
  headers.set("accept", "application/json");
168
160
  return headers;
169
161
  }
170
162
 
171
- async function resolveCodexClientVersion(
172
- clientVersion: string | undefined,
173
- fetchFn: FetchImpl,
174
- signal: AbortSignal | undefined,
175
- ): Promise<string> {
176
- const normalizedClientVersion = normalizeClientVersion(clientVersion);
177
- if (normalizedClientVersion) {
178
- return normalizedClientVersion;
179
- }
180
- try {
181
- const response = await fetchFn(NPM_CODEX_LATEST_URL, {
182
- method: "GET",
183
- headers: { Accept: "application/json" },
184
- signal,
185
- });
186
- if (!response.ok) {
187
- return DEFAULT_CODEX_CLIENT_VERSION;
188
- }
189
- const payload: unknown = await response.json();
190
- if (!isRecord(payload)) {
191
- return DEFAULT_CODEX_CLIENT_VERSION;
192
- }
193
- const npmVersion = normalizeClientVersion(payload.version);
194
- return npmVersion ?? DEFAULT_CODEX_CLIENT_VERSION;
195
- } catch (error) {
196
- if (isAbortError(error)) {
197
- throw error;
198
- }
199
- return DEFAULT_CODEX_CLIENT_VERSION;
200
- }
201
- }
202
-
203
163
  function normalizeClientVersion(value: unknown): string | undefined {
204
164
  if (typeof value !== "string") {
205
165
  return undefined;
@@ -211,10 +171,6 @@ function normalizeClientVersion(value: unknown): string | undefined {
211
171
  return trimmed;
212
172
  }
213
173
 
214
- function isAbortError(error: unknown): error is Error {
215
- return error instanceof Error && error.name === "AbortError";
216
- }
217
-
218
174
  function normalizeCodexModels(payload: unknown, baseUrl: string): ModelSpec<"openai-codex-responses">[] | null {
219
175
  const parsedResponse = codexModelsResponseSchema(payload);
220
176
  if (parsedResponse instanceof type.errors) {
package/src/models.json CHANGED
@@ -17387,6 +17387,26 @@
17387
17387
  "contextWindow": 200000,
17388
17388
  "maxTokens": 64000
17389
17389
  },
17390
+ "nemotron-3-ultra-nvfp4": {
17391
+ "id": "nemotron-3-ultra-nvfp4",
17392
+ "name": "Nemotron 3 Ultra",
17393
+ "api": "devin-agent",
17394
+ "provider": "devin",
17395
+ "baseUrl": "https://server.codeium.com",
17396
+ "reasoning": true,
17397
+ "input": [
17398
+ "text"
17399
+ ],
17400
+ "supportsTools": true,
17401
+ "cost": {
17402
+ "input": 0,
17403
+ "output": 0,
17404
+ "cacheRead": 0,
17405
+ "cacheWrite": 0
17406
+ },
17407
+ "contextWindow": 262144,
17408
+ "maxTokens": 64000
17409
+ },
17390
17410
  "swe-1-6": {
17391
17411
  "id": "swe-1-6",
17392
17412
  "name": "SWE-1.6",
@@ -18667,7 +18687,7 @@
18667
18687
  "cacheRead": 0.2,
18668
18688
  "cacheWrite": 0
18669
18689
  },
18670
- "contextWindow": 200000,
18690
+ "contextWindow": 1000000,
18671
18691
  "maxTokens": 64000,
18672
18692
  "headers": {
18673
18693
  "User-Agent": "opencode/1.3.15",
@@ -19190,7 +19210,7 @@
19190
19210
  "cacheRead": 0.5,
19191
19211
  "cacheWrite": 0
19192
19212
  },
19193
- "contextWindow": 400000,
19213
+ "contextWindow": 1050000,
19194
19214
  "maxTokens": 128000,
19195
19215
  "headers": {
19196
19216
  "User-Agent": "opencode/1.3.15",
@@ -19207,6 +19227,108 @@
19207
19227
  },
19208
19228
  "contextPromotionTarget": "github-copilot/gpt-5.4"
19209
19229
  },
19230
+ "gpt-5.6-luna": {
19231
+ "id": "gpt-5.6-luna",
19232
+ "name": "GPT-5.6 Luna",
19233
+ "api": "openai-responses",
19234
+ "provider": "github-copilot",
19235
+ "baseUrl": "https://api.githubcopilot.com",
19236
+ "reasoning": true,
19237
+ "input": [
19238
+ "text",
19239
+ "image"
19240
+ ],
19241
+ "cost": {
19242
+ "input": 1,
19243
+ "output": 6,
19244
+ "cacheRead": 0.1,
19245
+ "cacheWrite": 0
19246
+ },
19247
+ "contextWindow": 1050000,
19248
+ "maxTokens": 128000,
19249
+ "headers": {
19250
+ "User-Agent": "opencode/1.3.15",
19251
+ "X-GitHub-Api-Version": "2026-06-01"
19252
+ },
19253
+ "thinking": {
19254
+ "mode": "effort",
19255
+ "efforts": [
19256
+ "low",
19257
+ "medium",
19258
+ "high",
19259
+ "xhigh",
19260
+ "max"
19261
+ ]
19262
+ }
19263
+ },
19264
+ "gpt-5.6-sol": {
19265
+ "id": "gpt-5.6-sol",
19266
+ "name": "GPT-5.6 Sol",
19267
+ "api": "openai-responses",
19268
+ "provider": "github-copilot",
19269
+ "baseUrl": "https://api.githubcopilot.com",
19270
+ "reasoning": true,
19271
+ "input": [
19272
+ "text",
19273
+ "image"
19274
+ ],
19275
+ "cost": {
19276
+ "input": 5,
19277
+ "output": 30,
19278
+ "cacheRead": 0.5,
19279
+ "cacheWrite": 0
19280
+ },
19281
+ "contextWindow": 1050000,
19282
+ "maxTokens": 128000,
19283
+ "headers": {
19284
+ "User-Agent": "opencode/1.3.15",
19285
+ "X-GitHub-Api-Version": "2026-06-01"
19286
+ },
19287
+ "thinking": {
19288
+ "mode": "effort",
19289
+ "efforts": [
19290
+ "low",
19291
+ "medium",
19292
+ "high",
19293
+ "xhigh",
19294
+ "max"
19295
+ ]
19296
+ }
19297
+ },
19298
+ "gpt-5.6-terra": {
19299
+ "id": "gpt-5.6-terra",
19300
+ "name": "GPT-5.6 Terra",
19301
+ "api": "openai-responses",
19302
+ "provider": "github-copilot",
19303
+ "baseUrl": "https://api.githubcopilot.com",
19304
+ "reasoning": true,
19305
+ "input": [
19306
+ "text",
19307
+ "image"
19308
+ ],
19309
+ "cost": {
19310
+ "input": 2.5,
19311
+ "output": 15,
19312
+ "cacheRead": 0.25,
19313
+ "cacheWrite": 0
19314
+ },
19315
+ "contextWindow": 1050000,
19316
+ "maxTokens": 128000,
19317
+ "headers": {
19318
+ "User-Agent": "opencode/1.3.15",
19319
+ "X-GitHub-Api-Version": "2026-06-01"
19320
+ },
19321
+ "thinking": {
19322
+ "mode": "effort",
19323
+ "efforts": [
19324
+ "low",
19325
+ "medium",
19326
+ "high",
19327
+ "xhigh",
19328
+ "max"
19329
+ ]
19330
+ }
19331
+ },
19210
19332
  "grok-code-fast-1": {
19211
19333
  "id": "grok-code-fast-1",
19212
19334
  "name": "Grok Code Fast 1",
@@ -30992,7 +31114,7 @@
30992
31114
  },
30993
31115
  "openai/gpt-5.6-terra": {
30994
31116
  "id": "openai/gpt-5.6-terra",
30995
- "name": "GPT-5.6 Terra",
31117
+ "name": "GPT-5.6 Terra (new)",
30996
31118
  "api": "openai-completions",
30997
31119
  "provider": "kilo",
30998
31120
  "baseUrl": "https://api.kilo.ai/api/gateway",
@@ -48660,6 +48782,25 @@
48660
48782
  "contextWindow": null,
48661
48783
  "maxTokens": null
48662
48784
  },
48785
+ "perplexity-academic-researcher": {
48786
+ "id": "perplexity-academic-researcher",
48787
+ "name": "perplexity-academic-researcher",
48788
+ "api": "openai-completions",
48789
+ "provider": "nanogpt",
48790
+ "baseUrl": "https://nano-gpt.com/api/v1",
48791
+ "reasoning": false,
48792
+ "input": [
48793
+ "text"
48794
+ ],
48795
+ "cost": {
48796
+ "input": 0,
48797
+ "output": 0,
48798
+ "cacheRead": 0,
48799
+ "cacheWrite": 0
48800
+ },
48801
+ "contextWindow": null,
48802
+ "maxTokens": null
48803
+ },
48663
48804
  "phi-4-mini-instruct": {
48664
48805
  "id": "phi-4-mini-instruct",
48665
48806
  "name": "phi-4-mini-instruct",
@@ -62572,6 +62713,36 @@
62572
62713
  ]
62573
62714
  }
62574
62715
  },
62716
+ "gpt-realtime-2.1": {
62717
+ "id": "gpt-realtime-2.1",
62718
+ "name": "GPT-Realtime-2.1",
62719
+ "api": "openai-responses",
62720
+ "provider": "openai",
62721
+ "baseUrl": "https://api.openai.com/v1",
62722
+ "reasoning": true,
62723
+ "input": [
62724
+ "text",
62725
+ "image"
62726
+ ],
62727
+ "cost": {
62728
+ "input": 4,
62729
+ "output": 24,
62730
+ "cacheRead": 0.4,
62731
+ "cacheWrite": 0
62732
+ },
62733
+ "contextWindow": 128000,
62734
+ "maxTokens": 32000,
62735
+ "thinking": {
62736
+ "mode": "effort",
62737
+ "efforts": [
62738
+ "minimal",
62739
+ "low",
62740
+ "medium",
62741
+ "high",
62742
+ "xhigh"
62743
+ ]
62744
+ }
62745
+ },
62575
62746
  "o1": {
62576
62747
  "id": "o1",
62577
62748
  "name": "o1",
@@ -63390,47 +63561,6 @@
63390
63561
  ]
63391
63562
  }
63392
63563
  },
63393
- "gpt-5.6-luna-pro": {
63394
- "id": "gpt-5.6-luna-pro",
63395
- "name": "GPT-5.6 Luna Pro",
63396
- "api": "openai-codex-responses",
63397
- "provider": "openai-codex",
63398
- "baseUrl": "https://chatgpt.com/backend-api",
63399
- "reasoning": true,
63400
- "input": [
63401
- "text",
63402
- "image"
63403
- ],
63404
- "cost": {
63405
- "input": 1,
63406
- "output": 6,
63407
- "cacheRead": 0.1,
63408
- "cacheWrite": 1.25
63409
- },
63410
- "remoteCompaction": {
63411
- "enabled": true,
63412
- "api": "openai-codex-responses",
63413
- "v2StreamingEnabled": true
63414
- },
63415
- "contextWindow": 372000,
63416
- "maxTokens": 128000,
63417
- "preferWebsockets": true,
63418
- "useResponsesLite": true,
63419
- "priority": 3,
63420
- "requestModelId": "gpt-5.6-luna",
63421
- "reasoningMode": "pro",
63422
- "applyPatchToolType": "freeform",
63423
- "thinking": {
63424
- "mode": "effort",
63425
- "efforts": [
63426
- "low",
63427
- "medium",
63428
- "high",
63429
- "xhigh",
63430
- "max"
63431
- ]
63432
- }
63433
- },
63434
63564
  "gpt-5.6-sol": {
63435
63565
  "id": "gpt-5.6-sol",
63436
63566
  "name": "GPT-5.6 Sol",
@@ -63470,47 +63600,6 @@
63470
63600
  ]
63471
63601
  }
63472
63602
  },
63473
- "gpt-5.6-sol-pro": {
63474
- "id": "gpt-5.6-sol-pro",
63475
- "name": "GPT-5.6 Sol Pro",
63476
- "api": "openai-codex-responses",
63477
- "provider": "openai-codex",
63478
- "baseUrl": "https://chatgpt.com/backend-api",
63479
- "reasoning": true,
63480
- "input": [
63481
- "text",
63482
- "image"
63483
- ],
63484
- "cost": {
63485
- "input": 5,
63486
- "output": 30,
63487
- "cacheRead": 0.5,
63488
- "cacheWrite": 6.25
63489
- },
63490
- "remoteCompaction": {
63491
- "enabled": true,
63492
- "api": "openai-codex-responses",
63493
- "v2StreamingEnabled": true
63494
- },
63495
- "contextWindow": 372000,
63496
- "maxTokens": 128000,
63497
- "preferWebsockets": true,
63498
- "useResponsesLite": true,
63499
- "priority": 1,
63500
- "requestModelId": "gpt-5.6-sol",
63501
- "reasoningMode": "pro",
63502
- "applyPatchToolType": "freeform",
63503
- "thinking": {
63504
- "mode": "effort",
63505
- "efforts": [
63506
- "low",
63507
- "medium",
63508
- "high",
63509
- "xhigh",
63510
- "max"
63511
- ]
63512
- }
63513
- },
63514
63603
  "gpt-5.6-terra": {
63515
63604
  "id": "gpt-5.6-terra",
63516
63605
  "name": "GPT-5.6 Terra",
@@ -63549,47 +63638,6 @@
63549
63638
  "max"
63550
63639
  ]
63551
63640
  }
63552
- },
63553
- "gpt-5.6-terra-pro": {
63554
- "id": "gpt-5.6-terra-pro",
63555
- "name": "GPT-5.6 Terra Pro",
63556
- "api": "openai-codex-responses",
63557
- "provider": "openai-codex",
63558
- "baseUrl": "https://chatgpt.com/backend-api",
63559
- "reasoning": true,
63560
- "input": [
63561
- "text",
63562
- "image"
63563
- ],
63564
- "cost": {
63565
- "input": 2.5,
63566
- "output": 15,
63567
- "cacheRead": 0.25,
63568
- "cacheWrite": 3.125
63569
- },
63570
- "remoteCompaction": {
63571
- "enabled": true,
63572
- "api": "openai-codex-responses",
63573
- "v2StreamingEnabled": true
63574
- },
63575
- "contextWindow": 372000,
63576
- "maxTokens": 128000,
63577
- "preferWebsockets": true,
63578
- "useResponsesLite": true,
63579
- "priority": 2,
63580
- "requestModelId": "gpt-5.6-terra",
63581
- "reasoningMode": "pro",
63582
- "applyPatchToolType": "freeform",
63583
- "thinking": {
63584
- "mode": "effort",
63585
- "efforts": [
63586
- "low",
63587
- "medium",
63588
- "high",
63589
- "xhigh",
63590
- "max"
63591
- ]
63592
- }
63593
63641
  }
63594
63642
  },
63595
63643
  "opencode": {
@@ -65525,6 +65573,96 @@
65525
65573
  },
65526
65574
  "contextPromotionTarget": "opencode-zen/gpt-5.4"
65527
65575
  },
65576
+ "gpt-5.6-luna": {
65577
+ "id": "gpt-5.6-luna",
65578
+ "name": "GPT-5.6 Luna",
65579
+ "api": "openai-responses",
65580
+ "provider": "opencode-zen",
65581
+ "baseUrl": "https://opencode.ai/zen/v1",
65582
+ "reasoning": true,
65583
+ "input": [
65584
+ "text",
65585
+ "image"
65586
+ ],
65587
+ "cost": {
65588
+ "input": 1,
65589
+ "output": 6,
65590
+ "cacheRead": 0.1,
65591
+ "cacheWrite": 1.25
65592
+ },
65593
+ "contextWindow": 1050000,
65594
+ "maxTokens": 128000,
65595
+ "thinking": {
65596
+ "mode": "effort",
65597
+ "efforts": [
65598
+ "low",
65599
+ "medium",
65600
+ "high",
65601
+ "xhigh",
65602
+ "max"
65603
+ ]
65604
+ }
65605
+ },
65606
+ "gpt-5.6-sol": {
65607
+ "id": "gpt-5.6-sol",
65608
+ "name": "GPT-5.6 Sol",
65609
+ "api": "openai-responses",
65610
+ "provider": "opencode-zen",
65611
+ "baseUrl": "https://opencode.ai/zen/v1",
65612
+ "reasoning": true,
65613
+ "input": [
65614
+ "text",
65615
+ "image"
65616
+ ],
65617
+ "cost": {
65618
+ "input": 5,
65619
+ "output": 30,
65620
+ "cacheRead": 0.5,
65621
+ "cacheWrite": 6.25
65622
+ },
65623
+ "contextWindow": 1050000,
65624
+ "maxTokens": 128000,
65625
+ "thinking": {
65626
+ "mode": "effort",
65627
+ "efforts": [
65628
+ "low",
65629
+ "medium",
65630
+ "high",
65631
+ "xhigh",
65632
+ "max"
65633
+ ]
65634
+ }
65635
+ },
65636
+ "gpt-5.6-terra": {
65637
+ "id": "gpt-5.6-terra",
65638
+ "name": "GPT-5.6 Terra",
65639
+ "api": "openai-responses",
65640
+ "provider": "opencode-zen",
65641
+ "baseUrl": "https://opencode.ai/zen/v1",
65642
+ "reasoning": true,
65643
+ "input": [
65644
+ "text",
65645
+ "image"
65646
+ ],
65647
+ "cost": {
65648
+ "input": 2.5,
65649
+ "output": 15,
65650
+ "cacheRead": 0.25,
65651
+ "cacheWrite": 3.125
65652
+ },
65653
+ "contextWindow": 1050000,
65654
+ "maxTokens": 128000,
65655
+ "thinking": {
65656
+ "mode": "effort",
65657
+ "efforts": [
65658
+ "low",
65659
+ "medium",
65660
+ "high",
65661
+ "xhigh",
65662
+ "max"
65663
+ ]
65664
+ }
65665
+ },
65528
65666
  "grok-4.5": {
65529
65667
  "id": "grok-4.5",
65530
65668
  "name": "Grok 4.5",
@@ -65601,7 +65739,7 @@
65601
65739
  "cacheRead": 0,
65602
65740
  "cacheWrite": 0
65603
65741
  },
65604
- "contextWindow": 256000,
65742
+ "contextWindow": 190000,
65605
65743
  "maxTokens": 64000,
65606
65744
  "thinking": {
65607
65745
  "mode": "effort",
@@ -68111,13 +68249,13 @@
68111
68249
  "text"
68112
68250
  ],
68113
68251
  "cost": {
68114
- "input": 0.09,
68115
- "output": 0.18,
68116
- "cacheRead": 0.018,
68252
+ "input": 0.08399999999999999,
68253
+ "output": 0.16799999999999998,
68254
+ "cacheRead": 0.016800000000000002,
68117
68255
  "cacheWrite": 0
68118
68256
  },
68119
68257
  "contextWindow": 1048576,
68120
- "maxTokens": 65536,
68258
+ "maxTokens": 384000,
68121
68259
  "thinking": {
68122
68260
  "mode": "effort",
68123
68261
  "efforts": [
@@ -75529,9 +75667,9 @@
75529
75667
  "text"
75530
75668
  ],
75531
75669
  "cost": {
75532
- "input": 0.77,
75533
- "output": 2.42,
75534
- "cacheRead": 0.143,
75670
+ "input": 0.42,
75671
+ "output": 1.32,
75672
+ "cacheRead": 0.078,
75535
75673
  "cacheWrite": 0
75536
75674
  },
75537
75675
  "contextWindow": 1048576,
@@ -79347,7 +79485,7 @@
79347
79485
  "input": 1.25,
79348
79486
  "output": 7.5,
79349
79487
  "cacheRead": 0.125,
79350
- "cacheWrite": 0
79488
+ "cacheWrite": 1.5625
79351
79489
  },
79352
79490
  "contextWindow": 1000000,
79353
79491
  "maxTokens": 128000,
@@ -79377,7 +79515,7 @@
79377
79515
  "input": 1.25,
79378
79516
  "output": 7.5,
79379
79517
  "cacheRead": 0.125,
79380
- "cacheWrite": 0
79518
+ "cacheWrite": 1.5625
79381
79519
  },
79382
79520
  "contextWindow": 1000000,
79383
79521
  "maxTokens": 128000,
@@ -79407,7 +79545,7 @@
79407
79545
  "input": 6.25,
79408
79546
  "output": 37.5,
79409
79547
  "cacheRead": 0.625,
79410
- "cacheWrite": 0
79548
+ "cacheWrite": 7.8125
79411
79549
  },
79412
79550
  "contextWindow": 1000000,
79413
79551
  "maxTokens": 128000,
@@ -79437,7 +79575,7 @@
79437
79575
  "input": 6.25,
79438
79576
  "output": 37.5,
79439
79577
  "cacheRead": 0.625,
79440
- "cacheWrite": 0
79578
+ "cacheWrite": 7.8125
79441
79579
  },
79442
79580
  "contextWindow": 1000000,
79443
79581
  "maxTokens": 128000,
@@ -79467,7 +79605,7 @@
79467
79605
  "input": 3.125,
79468
79606
  "output": 18.75,
79469
79607
  "cacheRead": 0.3125,
79470
- "cacheWrite": 0
79608
+ "cacheWrite": 3.90625
79471
79609
  },
79472
79610
  "contextWindow": 1000000,
79473
79611
  "maxTokens": 128000,
@@ -79497,7 +79635,7 @@
79497
79635
  "input": 3.125,
79498
79636
  "output": 18.75,
79499
79637
  "cacheRead": 0.3125,
79500
- "cacheWrite": 0
79638
+ "cacheWrite": 3.90625
79501
79639
  },
79502
79640
  "contextWindow": 1000000,
79503
79641
  "maxTokens": 128000,
@@ -87162,7 +87300,8 @@
87162
87300
  "includeEncryptedReasoning": false,
87163
87301
  "filterReasoningHistory": true,
87164
87302
  "omitReasoningEffort": true,
87165
- "supportsReasoningEffort": false
87303
+ "supportsReasoningEffort": false,
87304
+ "supportsImageDetailOriginal": false
87166
87305
  }
87167
87306
  },
87168
87307
  "grok-4.20-0309-reasoning": {
@@ -87191,7 +87330,8 @@
87191
87330
  "includeEncryptedReasoning": false,
87192
87331
  "filterReasoningHistory": true,
87193
87332
  "omitReasoningEffort": true,
87194
- "supportsReasoningEffort": false
87333
+ "supportsReasoningEffort": false,
87334
+ "supportsImageDetailOriginal": false
87195
87335
  }
87196
87336
  },
87197
87337
  "grok-4.20-multi-agent-0309": {
@@ -87232,7 +87372,8 @@
87232
87372
  "includeEncryptedReasoning": false,
87233
87373
  "filterReasoningHistory": true,
87234
87374
  "omitReasoningEffort": false,
87235
- "supportsReasoningEffort": true
87375
+ "supportsReasoningEffort": true,
87376
+ "supportsImageDetailOriginal": false
87236
87377
  }
87237
87378
  },
87238
87379
  "grok-4.3": {
@@ -87274,7 +87415,8 @@
87274
87415
  "includeEncryptedReasoning": false,
87275
87416
  "filterReasoningHistory": true,
87276
87417
  "omitReasoningEffort": false,
87277
- "supportsReasoningEffort": true
87418
+ "supportsReasoningEffort": true,
87419
+ "supportsImageDetailOriginal": false
87278
87420
  }
87279
87421
  },
87280
87422
  "grok-4.5": {
@@ -87316,7 +87458,8 @@
87316
87458
  "includeEncryptedReasoning": false,
87317
87459
  "filterReasoningHistory": true,
87318
87460
  "omitReasoningEffort": false,
87319
- "supportsReasoningEffort": true
87461
+ "supportsReasoningEffort": true,
87462
+ "supportsImageDetailOriginal": false
87320
87463
  }
87321
87464
  },
87322
87465
  "grok-build": {
@@ -87345,7 +87488,8 @@
87345
87488
  "includeEncryptedReasoning": false,
87346
87489
  "filterReasoningHistory": true,
87347
87490
  "omitReasoningEffort": true,
87348
- "supportsReasoningEffort": false
87491
+ "supportsReasoningEffort": false,
87492
+ "supportsImageDetailOriginal": false
87349
87493
  }
87350
87494
  },
87351
87495
  "grok-build-0.1": {
@@ -87374,7 +87518,8 @@
87374
87518
  "includeEncryptedReasoning": false,
87375
87519
  "filterReasoningHistory": true,
87376
87520
  "omitReasoningEffort": true,
87377
- "supportsReasoningEffort": false
87521
+ "supportsReasoningEffort": false,
87522
+ "supportsImageDetailOriginal": false
87378
87523
  }
87379
87524
  },
87380
87525
  "grok-composer-2.5-fast": {
@@ -87402,7 +87547,8 @@
87402
87547
  "includeEncryptedReasoning": false,
87403
87548
  "filterReasoningHistory": true,
87404
87549
  "omitReasoningEffort": true,
87405
- "supportsReasoningEffort": false
87550
+ "supportsReasoningEffort": false,
87551
+ "supportsImageDetailOriginal": false
87406
87552
  }
87407
87553
  }
87408
87554
  },
@@ -823,17 +823,23 @@ const OPENAI_PRO_REASONING_BASE_IDS: Record<string, true> = {
823
823
  "gpt-5.6-sol": true,
824
824
  "gpt-5.6-terra": true,
825
825
  };
826
- const OPENAI_PRO_REASONING_PROVIDERS: Record<string, true> = { openai: true, "openai-codex": true };
826
+ /**
827
+ * Providers whose generated pro aliases this pass owns. `openai-codex` stays in
828
+ * the sweep so stale aliases from earlier snapshots are dropped on regen, but
829
+ * projection is `openai`-only — subscription (Codex) auth does not offer pro
830
+ * reasoning.
831
+ */
832
+ const OPENAI_PRO_REASONING_SWEEP_PROVIDERS: Record<string, true> = { openai: true, "openai-codex": true };
827
833
 
828
834
  /**
829
835
  * A row this generator pass owns: one of the derived `gpt-5.6-*-pro` alias ids
830
- * on `openai`/`openai-codex` that carries the generated `reasoningMode` marker.
836
+ * on a swept provider that carries the generated `reasoningMode` marker.
831
837
  * A real upstream model occupying the same id has no `reasoningMode` and is
832
838
  * never touched.
833
839
  */
834
840
  function isGeneratedOpenAIProReasoningAlias(model: ModelSpec<Api>): boolean {
835
841
  return (
836
- OPENAI_PRO_REASONING_PROVIDERS[model.provider] === true &&
842
+ OPENAI_PRO_REASONING_SWEEP_PROVIDERS[model.provider] === true &&
837
843
  model.reasoningMode !== undefined &&
838
844
  model.id.endsWith("-pro") &&
839
845
  OPENAI_PRO_REASONING_BASE_IDS[model.id.slice(0, -"-pro".length)] === true
@@ -842,21 +848,21 @@ function isGeneratedOpenAIProReasoningAlias(model: ModelSpec<Api>): boolean {
842
848
 
843
849
  /**
844
850
  * Re-derive the generated pro-reasoning aliases (`gpt-5.6-*-pro`) for the
845
- * first-party `openai`/`openai-codex` gpt-5.6 rows. Each alias inherits the
846
- * base row's metadata, requests the base wire id via `requestModelId`, and
847
- * sets `reasoningMode: "pro"` so Responses-family request builders emit
851
+ * first-party `openai` gpt-5.6 rows. Each alias inherits the base row's
852
+ * metadata, requests the base wire id via `requestModelId`, and sets
853
+ * `reasoningMode: "pro"` so Responses-family request builders emit
848
854
  * `reasoning: { mode: "pro" }`. Called by the models.json generator after all
849
- * sources merge: stale copies of the owned aliases (previous snapshot) are
850
- * dropped and re-projected from the current base rows so alias metadata always
851
- * tracks the base, while a real upstream model that occupies an alias id wins
852
- * and suppresses the projection.
855
+ * sources merge: stale copies of the owned aliases (previous snapshot,
856
+ * including retired `openai-codex` rows) are dropped and re-projected from the
857
+ * current base rows so alias metadata always tracks the base, while a real
858
+ * upstream model that occupies an alias id wins and suppresses the projection.
853
859
  */
854
860
  export function projectOpenAIProReasoningAliases(models: readonly ModelSpec<Api>[]): ModelSpec<Api>[] {
855
861
  const kept = models.filter(model => !isGeneratedOpenAIProReasoningAlias(model));
856
862
  const ids = new Set(kept.map(model => `${model.provider}/${model.id}`));
857
863
  const out = [...kept];
858
864
  for (const model of kept) {
859
- if (!OPENAI_PRO_REASONING_PROVIDERS[model.provider]) continue;
865
+ if (model.provider !== "openai") continue;
860
866
  if (!OPENAI_PRO_REASONING_BASE_IDS[model.id]) continue;
861
867
  const aliasId = `${model.id}-pro`;
862
868
  const aliasKey = `${model.provider}/${aliasId}`;
@@ -1170,6 +1176,7 @@ function withXaiOAuthCompatDefaults(model: ModelSpec<"openai-responses">): Model
1170
1176
  ...(model.compat ?? {}),
1171
1177
  includeEncryptedReasoning: model.compat?.includeEncryptedReasoning ?? false,
1172
1178
  filterReasoningHistory: model.compat?.filterReasoningHistory ?? true,
1179
+ supportsImageDetailOriginal: model.compat?.supportsImageDetailOriginal ?? false,
1173
1180
  omitReasoningEffort: model.compat?.omitReasoningEffort ?? !isGrokReasoningEffortCapable(model.id),
1174
1181
  };
1175
1182
  return { ...model, compat };
@@ -1212,6 +1219,7 @@ function mergeCuratedIntoModel(
1212
1219
  reasoningEffortMap: { ...XAI_REASONING_EFFORT_MAP, ...(base.compat?.reasoningEffortMap ?? {}) },
1213
1220
  includeEncryptedReasoning: base.compat?.includeEncryptedReasoning ?? false,
1214
1221
  filterReasoningHistory: base.compat?.filterReasoningHistory ?? true,
1222
+ supportsImageDetailOriginal: base.compat?.supportsImageDetailOriginal ?? false,
1215
1223
  omitReasoningEffort: !effortCapable,
1216
1224
  supportsReasoningEffort: effortCapable,
1217
1225
  };
package/src/wire/codex.ts CHANGED
@@ -4,10 +4,16 @@
4
4
 
5
5
  export const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
6
6
 
7
+ /**
8
+ * Pinned OpenAI Codex client version (corresponds to @openai/codex package version).
9
+ */
10
+ export const CODEX_CLIENT_VERSION = "0.144.1";
11
+
7
12
  export const OPENAI_HEADERS = {
8
13
  BETA: "OpenAI-Beta",
9
14
  ACCOUNT_ID: "chatgpt-account-id",
10
15
  ORIGINATOR: "originator",
16
+ VERSION: "version",
11
17
  SESSION_ID: "session_id",
12
18
  CONVERSATION_ID: "conversation_id",
13
19
  SCOPED_SESSION_ID: "session-id",