converse-mcp-server 3.2.4 → 3.4.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/.env.example CHANGED
@@ -80,9 +80,9 @@ OPENROUTER_API_KEY=your_openrouter_api_key_here
80
80
  # WARNING: Interactive policies may cause hangs in server/headless mode
81
81
  # CODEX_APPROVAL_POLICY=never
82
82
 
83
- # Default Codex model (default: gpt-5.6-sol)
84
- # Options: gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex-spark
85
- # CODEX_MODEL=gpt-5.6-sol
83
+ # Default Codex backend model (default: gpt-6-astra). Per-request override: models: ["codex:<model>"]
84
+ # Options: gpt-6-astra, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.3-codex-spark
85
+ # CODEX_MODEL=gpt-6-astra
86
86
 
87
87
  # ============================================
88
88
  # Server Configuration
package/README.md CHANGED
@@ -234,6 +234,7 @@ SUMMARIZATION_MODEL=gpt-5-nano # Default: gpt-5-nano
234
234
 
235
235
  - **gemini-3.1-pro-preview** (aliases: `pro`, `gemini-pro`): Most advanced reasoning with expanded thinking levels (1M context, 64K output)
236
236
  - **gemini-3.5-flash** (aliases: `gemini-3.5`, `flash-3.5`): Frontier-level agentic and coding performance at Flash speed (1M context, 65K output)
237
+ - **gemini-3.8-flash** (aliases: `gemini-3.8`, `flash-3.8`): Current-generation Flash with stronger long-horizon agentic performance (1M context, 65K output; thinking levels low/medium/high — no minimal)
237
238
  - **gemini-2.5-pro** (alias: `pro 2.5`): Deep reasoning with thinking budget (1M context, 65K output)
238
239
  - **gemini-2.5-flash** (alias: `flash`): Ultra-fast (1M context, 65K output)
239
240
  - **gemini-2.5-flash-lite** (alias: `flash-lite`): Lightweight fast model (1M context, 65K output)
@@ -280,7 +281,9 @@ Any other model works via its full `provider/model` slug or the `openrouter:` na
280
281
 
281
282
  ### Codex Models
282
283
 
283
- - **codex**: OpenAI Codex agentic coding assistant
284
+ - **codex**: OpenAI Codex agentic coding assistant (GPT-6 Astra by default)
285
+ - Pick another backend per request with `codex:<model>` (e.g. `codex:sol`, `codex:gpt-5.6-terra`) or globally with `CODEX_MODEL`; backends: `gpt-6-astra` (alias `astra`), `gpt-5.6-sol` (`sol`), `gpt-5.6-terra` (`terra`), `gpt-5.6-luna` (`luna`), `gpt-5.5`, `gpt-5.3-codex-spark` (`spark`)
286
+ - `reasoning_effort` maps onto the tiers the chosen backend accepts (GPT-6 Astra: `low` through `max`, no `none`)
284
287
  - Thread-based sessions with persistent context
285
288
  - Direct filesystem access from working directory
286
289
  - Typical response time: 6-20 seconds (longer for complex tasks)
@@ -301,7 +304,7 @@ Reach these with the `copilot:` namespace (e.g. `copilot:gpt-5.6-terra`); uses y
301
304
 
302
305
  - **OpenAI**: `gpt-5.6-sol` (aliases: `gpt-5.6`, `gpt-5`), `gpt-5.6-terra`, `gpt-5.6-luna` (all support `reasoning_effort`)
303
306
  - **Anthropic**: `claude-fable-5` (alias: `fable`), `claude-sonnet-5` (alias: `sonnet`), `claude-opus-4.8` (aliases: `opus`, `claude`)
304
- - **Google**: `gemini-3.1-pro-preview` (aliases: `gemini`, `gemini-3.1-pro`), `gemini-3.5-flash` (alias: `gemini-flash`)
307
+ - **Google**: `gemini-3.1-pro-preview` (aliases: `gemini`, `gemini-3.1-pro`), `gemini-3.8-flash` (aliases: `gemini-3.8`, `flash-3.8`), `gemini-3.5-flash` (alias: `gemini-flash`)
305
308
  - Any other `copilot:<id>` is forwarded to the Copilot backend verbatim
306
309
 
307
310
  ## 📚 Help & Documentation
@@ -356,6 +359,7 @@ CODEX_API_KEY=your_codex_api_key_here # Optional if ChatGPT login availabl
356
359
  CODEX_SANDBOX_MODE=read-only # read-only (default), workspace-write, danger-full-access
357
360
  CODEX_SKIP_GIT_CHECK=true # true (default), false
358
361
  CODEX_APPROVAL_POLICY=never # never (default), untrusted, on-failure, on-request
362
+ CODEX_MODEL=gpt-6-astra # gpt-6-astra (default), gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5
359
363
  ```
360
364
 
361
365
  ### Configuration Options
@@ -371,18 +375,42 @@ CODEX_APPROVAL_POLICY=never # never (default), untrusted, on-fa
371
375
 
372
376
  These must be set in your system environment or when launching Claude Code, NOT in the project .env file:
373
377
 
374
- | Variable | Description | Default | Example |
375
- | ----------------------- | --------------------------- | -------- | ------------------------------------ |
376
- | `MAX_MCP_OUTPUT_TOKENS` | Token response limit | `25000` | `200000` |
377
- | `MCP_TOOL_TIMEOUT` | Tool execution timeout (ms) | `120000` | `5400000` (90 min for deep research) |
378
+ | Variable | Description | Default | Example |
379
+ | ------------------------------------ | ----------------------------------------------------------------------- | ------------------------------- | --------------------------- |
380
+ | `MAX_MCP_OUTPUT_TOKENS` | Token response limit | `25000` | `200000` |
381
+ | `MCP_TOOL_TIMEOUT` | Wall-clock limit per tool call (ms) | ~28 hours when unset | `7200000` (2 h) |
382
+ | `CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT` | Idle window (ms) — aborts a call that produces no output for this long | 30 min (stdio) / 5 min (HTTP) | `3600000` (60 min) |
378
383
 
379
384
  ```bash
380
385
  # Example: Set globally before starting Claude Code
381
386
  export MAX_MCP_OUTPUT_TOKENS=200000
382
- export MCP_TOOL_TIMEOUT=5400000 # 90 minutes for deep research models
387
+ export CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT=3600000 # 60 min for long silent agentic calls
383
388
  claude # Then start Claude Code
384
389
  ```
385
390
 
391
+ Or persist them in `~/.claude/settings.json`:
392
+
393
+ ```json
394
+ {
395
+ "env": {
396
+ "MAX_MCP_OUTPUT_TOKENS": "200000",
397
+ "CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT": "3600000"
398
+ }
399
+ }
400
+ ```
401
+
402
+ **The idle timeout is usually what kills long calls.** Agentic models (Codex, Claude Agent SDK) can work silently for 30+ minutes; Converse holds one MCP request open the whole time, and Claude Code aborts it after the idle window with an error like _"failed after 30 minutes of silence. The idle timeout aborted it."_ Progress-notification heartbeats can't prevent this — Claude Code doesn't send a `progressToken` on `tools/call`, so an MCP server has no spec-compliant way to emit them ([claude-code#58687](https://github.com/anthropics/claude-code/issues/58687)). Raising the idle window is the only fix.
403
+
404
+ #### Codex CLI Tool Timeout
405
+
406
+ If you register Converse in OpenAI's Codex CLI, note that Codex enforces its own **hard 300-second default** per MCP tool call (`tool_timeout_sec`, undocumented — it exists only in Codex's config schema). Progress notifications don't extend it. Raise it in `~/.codex/config.toml`:
407
+
408
+ ```toml
409
+ [mcp_servers.converse]
410
+ # ... command/env ...
411
+ tool_timeout_sec = 3600 # default 300 kills long calls at 5 minutes
412
+ ```
413
+
386
414
  ### Model Selection
387
415
 
388
416
  Use `"auto"` for automatic model selection, or specify exact models:
@@ -421,7 +449,7 @@ Use `"auto"` for automatic model selection, or specify exact models:
421
449
  Provider priority order (subscription-based SDK providers first, then API-key providers):
422
450
 
423
451
  1. Codex (`codex`)
424
- 2. Gemini via Antigravity CLI (`gemini`, `gemini:flash`)
452
+ 2. Gemini via Antigravity CLI (`gemini` → Gemini 3.8 Flash, `gemini:pro`)
425
453
  3. Claude Agent SDK (`claude` → Claude Fable 5)
426
454
  4. Copilot (`copilot`)
427
455
  5. OpenAI (`gpt-5.6`)
@@ -532,6 +560,13 @@ For development setup, see the [Development](#-development) section below.
532
560
 
533
561
  - Clear cache and reinstall: `npm run clean`
534
562
 
563
+ **Long tool calls aborted mid-run (idle/timeout errors):**
564
+
565
+ - The abort almost always comes from the MCP _client_, not Converse — Converse's own limits are 30 min per provider call and 90 min per async job.
566
+ - Claude Code: raise `CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT` (idle window, default 30 min stdio / 5 min HTTP) and check `MCP_TOOL_TIMEOUT` (wall-clock). See [Claude Code Environment Variables](#claude-code-environment-variables-systemglobal).
567
+ - Codex CLI: set `tool_timeout_sec` under `[mcp_servers.converse]` in `~/.codex/config.toml` — the undocumented default is 300 seconds.
568
+ - Immune alternative: run the call with `async: true` and poll `check_status` — each poll is a fresh short request, so no client timeout applies.
569
+
535
570
  ### Debug Mode
536
571
 
537
572
  ```bash
package/docs/API.md CHANGED
@@ -391,6 +391,7 @@ Provide models as plain name strings in the `models` array. Bare names and alias
391
391
  |-------|---------|---------|--------|-------|
392
392
  | `gemini-3.1-pro-preview` | `pro`, `gemini-pro` | 1M | 64K | Most advanced reasoning, expanded thinking levels |
393
393
  | `gemini-3.5-flash` | `gemini-3.5`, `flash-3.5` | 1M | 65K | Frontier agentic/coding at Flash speed |
394
+ | `gemini-3.8-flash` | `gemini-3.8`, `flash-3.8` | 1M | 65K | Current-generation Flash; thinking low/medium/high only |
394
395
  | `gemini-2.5-pro` | `pro 2.5` | 1M | 65K | Deep reasoning with thinking budget |
395
396
  | `gemini-2.5-flash` | `flash` | 1M | 65K | Ultra-fast |
396
397
  | `gemini-2.5-flash-lite` | `flash-lite` | 1M | 65K | Lightweight fast model |
@@ -455,12 +456,13 @@ Any other model works via its full `provider/model` slug (e.g. `anthropic/claude
455
456
 
456
457
  **Codex** is an agentic coding assistant with direct filesystem access:
457
458
 
458
- - **Model**: `codex` (underlying model: GPT-5.6)
459
+ - **Model**: `codex` (underlying model: GPT-6 Astra by default)
460
+ - **Backend selection**: `codex:<model>` per request (e.g. `codex:astra`, `codex:sol`, `codex:gpt-5.6-terra`), or `CODEX_MODEL` globally; unknown names pass through to the CLI verbatim
459
461
  - **Thread-based sessions**: persistent conversation history via `continuation_id` in `chat` mode
460
462
  - **Direct file access**: reads files from the working directory (paths relative to `CLIENT_CWD`)
461
463
  - **Response times**: 6-20 seconds typical (complex tasks may take minutes)
462
464
  - **Authentication**: ChatGPT login OR `CODEX_API_KEY` (NOT `OPENAI_API_KEY`)
463
- - `reasoning_effort` and web search are not applicable — Codex manages its own execution
465
+ - `reasoning_effort` is clamped onto the tiers the chosen backend accepts (GPT-6 Astra: `low`–`max`, no `none`; GPT-5.6: `none`–`max`); web search is not applicable — Codex manages its own execution
464
466
 
465
467
  ### Claude Agent SDK (subscription)
466
468
 
@@ -476,7 +478,7 @@ Any other model works via its full `provider/model` slug (e.g. `anthropic/claude
476
478
 
477
479
  The **Antigravity CLI** (`agy`) provides subscription-based access to Gemini models through Google OAuth:
478
480
 
479
- - **Models** (text-only): `gemini` (= `gemini:pro`, Gemini 3.1 Pro), `gemini:flash` (Gemini 3.5 Flash)
481
+ - **Models** (text-only): `gemini` (= `gemini:flash`, Gemini 3.8 Flash), `gemini:pro` (Gemini 3.1 Pro)
480
482
  - **Authentication**: Google OAuth via `agy` (one-time interactive login)
481
483
  - **Setup**: install the Antigravity CLI and run `agy` once to log in
482
484
  - **Billing**: uses your Antigravity subscription/compute allowance instead of API credits
@@ -502,7 +504,7 @@ Reach these with the `copilot:` namespace (e.g. `copilot:gpt-5.6-terra`); uses y
502
504
 
503
505
  - **OpenAI**: `gpt-5.6-sol` (aliases: `gpt-5.6`, `gpt-5`), `gpt-5.6-terra`, `gpt-5.6-luna` (all accept `reasoning_effort`)
504
506
  - **Anthropic**: `claude-fable-5` (alias: `fable`), `claude-sonnet-5` (alias: `sonnet`), `claude-opus-5` (aliases: `opus`, `claude`), `claude-opus-4.8`
505
- - **Google**: `gemini-3.1-pro-preview` (aliases: `gemini`, `gemini-3.1-pro`), `gemini-3.5-flash` (alias: `gemini-flash`)
507
+ - **Google**: `gemini-3.1-pro-preview` (aliases: `gemini`, `gemini-3.1-pro`), `gemini-3.8-flash` (aliases: `gemini-3.8`, `flash-3.8`), `gemini-3.5-flash` (alias: `gemini-flash`)
506
508
  - Any other `copilot:<id>` is forwarded to the Copilot backend verbatim
507
509
 
508
510
  ### Model Selection
@@ -522,7 +524,7 @@ Use `"auto"` for automatic selection, or specify exact models:
522
524
  "opus" // Anthropic API (-> claude-opus-5)
523
525
  "claude" // Claude Agent SDK (-> Claude Fable 5)
524
526
  "claude:opus" // Claude Agent SDK (Claude Opus 5)
525
- "gemini" // Antigravity CLI (Gemini 3.1 Pro)
527
+ "gemini" // Antigravity CLI (Gemini 3.8 Flash)
526
528
  "copilot:gpt-5.6-terra" // GitHub Copilot SDK
527
529
  ```
528
530
 
package/docs/PROVIDERS.md CHANGED
@@ -24,6 +24,7 @@ This guide documents all supported AI providers in the Converse MCP Server and t
24
24
  - **Supported Models**:
25
25
  - `gemini-3.1-pro-preview` (aliases: `pro`, `gemini-pro`) - Most advanced reasoning with expanded thinking levels (1M context, 64K output)
26
26
  - `gemini-3.5-flash` (aliases: `gemini-3.5`, `flash-3.5`) - Frontier-level agentic and coding performance at Flash speed (1M context, 65K output)
27
+ - `gemini-3.8-flash` (aliases: `gemini-3.8`, `flash-3.8`) - Current-generation Flash with stronger long-horizon agentic performance (1M context, 65K output; thinking levels low/medium/high — no minimal)
27
28
  - `gemini-2.5-pro` (alias: `pro 2.5`) - Deep reasoning with thinking budget (1M context, 65K output)
28
29
  - `gemini-2.5-flash` (alias: `flash`) - Ultra-fast model with thinking budget (1M context, 65K output)
29
30
  - `gemini-2.5-flash-lite` (alias: `flash-lite`) - Lightweight fast model (1M context, 65K output)
@@ -100,9 +101,11 @@ This guide documents all supported AI providers in the Converse MCP Server and t
100
101
  - `CODEX_SANDBOX_MODE` - Filesystem access control (default: read-only)
101
102
  - `CODEX_SKIP_GIT_CHECK` - Skip Git repository validation (default: true)
102
103
  - `CODEX_APPROVAL_POLICY` - Command approval behavior (default: never)
103
- - `CODEX_MODEL` - Underlying model for Codex sessions (default: gpt-5.6-sol; e.g. gpt-5.6-terra, gpt-5.6-luna, gpt-5.5)
104
+ - `CODEX_MODEL` - Underlying model for Codex sessions (default: gpt-6-astra; e.g. gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5)
104
105
  - **Supported Models**:
105
- - `codex` - OpenAI Codex agentic coding assistant (GPT-5.6 by default)
106
+ - `codex` - OpenAI Codex agentic coding assistant (GPT-6 Astra by default)
107
+ - `codex:<model>` - Same, with an explicit backend: `codex:astra`, `codex:sol`, `codex:terra`, `codex:luna`, `codex:gpt-5.5`, `codex:spark`, or any slug the Codex CLI knows
108
+ - `reasoning_effort` is clamped onto what the backend accepts (GPT-6 Astra: `low`–`max`, no `none`)
106
109
  - Thread-based sessions with persistent context
107
110
  - Direct filesystem access from working directory
108
111
  - Typical response time: 6-20 seconds (longer for complex tasks)
@@ -129,8 +132,8 @@ This guide documents all supported AI providers in the Converse MCP Server and t
129
132
  2. Authenticate: run `agy` once interactively and complete the Google OAuth login. This also establishes workspace trust for your home directory (the provider spawns each call in a per-call subdirectory under `~/.converse/agy-runs`).
130
133
  - **Environment Variables**: None (the provider detects the `agy` binary on PATH or at the platform install location)
131
134
  - **Supported Models** (text-only — print mode has no image input channel):
132
- - `gemini` (= `gemini:pro`) - Gemini 3.1 Pro
133
- - `gemini:flash` - Gemini 3.5 Flash
135
+ - `gemini` (= `gemini:flash`) - Gemini 3.8 Flash (default)
136
+ - `gemini:pro` - Gemini 3.1 Pro
134
137
  - `reasoning_effort` selects the variant: `low` → (Low), `medium` → (Medium) for Flash / (High) for Pro, `high`/`max` → (High); unset defaults to (High)
135
138
 
136
139
  **Key Features:**
@@ -216,7 +219,7 @@ agy
216
219
  - `copilot` - Uses Copilot's default or env-configured model
217
220
  - OpenAI: `gpt-5.6-sol` (aliases: bare `gpt-5.6`, `gpt-5`), `gpt-5.6-terra` (recommended balanced tier), `gpt-5.6-luna`
218
221
  - Anthropic: `claude-fable-5` (alias: `fable`), `claude-sonnet-5` (alias: `sonnet`), `claude-opus-5` (aliases: `opus`, `claude`), `claude-opus-4.8`
219
- - Google: `gemini-3.1-pro-preview` (aliases: `gemini`, `gemini-3.1-pro`), `gemini-3.5-flash` (alias: `gemini-flash`)
222
+ - Google: `gemini-3.1-pro-preview` (aliases: `gemini`, `gemini-3.1-pro`), `gemini-3.8-flash` (aliases: `gemini-3.8`, `flash-3.8`), `gemini-3.5-flash` (alias: `gemini-flash`)
220
223
  - **Reasoning**: The `gpt-5.6-sol`/`terra`/`luna` tiers accept `reasoning_effort`.
221
224
  - **Explicit pass-through**: Any other `copilot:<id>` model string is forwarded to the Copilot backend verbatim, so IDs outside the curated list still work while the backend accepts them.
222
225
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "converse-mcp-server",
3
- "version": "3.2.4",
3
+ "version": "3.4.0",
4
4
  "description": "Converse MCP Server - Converse with other LLMs with chat and consensus tools",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -93,28 +93,28 @@
93
93
  ".env.example"
94
94
  ],
95
95
  "dependencies": {
96
- "@anthropic-ai/claude-agent-sdk": "^0.3.220",
97
- "@anthropic-ai/sdk": "^0.115.0",
98
- "@github/copilot-sdk": "^1.0.8",
99
- "@google/genai": "^2.13.0",
100
- "@lydell/node-pty": "1.2.0-beta.14",
101
- "@mistralai/mistralai": "^2.5.0",
102
- "@modelcontextprotocol/sdk": "^1.29.0",
103
- "@openai/codex-sdk": "^0.145.0",
96
+ "@anthropic-ai/claude-agent-sdk": "^0.3.261",
97
+ "@anthropic-ai/sdk": "^0.123.0",
98
+ "@github/copilot-sdk": "^1.0.11",
99
+ "@google/genai": "^2.21.0",
100
+ "@lydell/node-pty": "1.2.0-beta.15",
101
+ "@mistralai/mistralai": "^2.6.4",
102
+ "@modelcontextprotocol/sdk": "^1.30.0",
103
+ "@openai/codex-sdk": "^0.153.3",
104
104
  "cors": "^2.8.6",
105
105
  "dotenv": "^17.4.2",
106
106
  "express": "^5.2.1",
107
107
  "lru-cache": "^11.5.2",
108
- "nanoid": "^6.0.0",
109
- "openai": "^6.49.0",
110
- "p-limit": "^7.3.1",
111
- "vite": "^8.1.5"
108
+ "nanoid": "^6.0.1",
109
+ "openai": "^7.10.0",
110
+ "p-limit": "^7.3.2",
111
+ "vite": "^8.2.2"
112
112
  },
113
113
  "devDependencies": {
114
- "@vitest/coverage-v8": "^4.1.10",
114
+ "@vitest/coverage-v8": "^5.0.0",
115
115
  "cross-env": "^10.1.0",
116
- "eslint": "^10.8.0",
116
+ "eslint": "^10.10.0",
117
117
  "rimraf": "^6.1.3",
118
- "vitest": "^4.1.10"
118
+ "vitest": "^5.0.0"
119
119
  }
120
120
  }
package/src/config.js CHANGED
@@ -280,9 +280,9 @@ const CONFIG_SCHEMA = {
280
280
  },
281
281
  CODEX_MODEL: {
282
282
  type: 'string',
283
- default: 'gpt-5.6-sol',
283
+ default: 'gpt-6-astra',
284
284
  description:
285
- 'Default Codex model (e.g., gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5)',
285
+ 'Default Codex backend model (e.g., gpt-6-astra, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5)',
286
286
  },
287
287
 
288
288
  // Copilot configuration
@@ -17,35 +17,75 @@ import { debugLog, debugError } from '../utils/console.js';
17
17
  import { ProviderError, ErrorCodes, StopReasons } from './interface.js';
18
18
  import { normalizeExtendedPath } from '../utils/pathUtils.js';
19
19
 
20
- // Supported Codex models with their configurations
20
+ /**
21
+ * Every Codex reasoning tier, weakest to strongest. Used to clamp a requested
22
+ * tier onto the set a given backend model accepts.
23
+ *
24
+ * Codex also exposes 'ultra' above 'max', but that tier turns on automatic
25
+ * sub-agent delegation — a change in how the run executes, not just how deep
26
+ * it reasons — so nothing at the tool level maps to it and it is kept off the
27
+ * ladder so the clamp can never select it.
28
+ */
29
+ const EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
30
+
31
+ /**
32
+ * Backend models Codex can run, keyed by the slug passed to the CLI as
33
+ * --model. The reasoning tiers are the ones each model's API accepts, verified
34
+ * against the API's own rejection messages (gpt-6-astra: "Supported values
35
+ * are: 'low', 'medium', 'high', 'xhigh', and 'max'"). The SDK's
36
+ * ModelReasoningEffort type is the union across models, so the backend is the
37
+ * authority and requests are clamped per model.
38
+ */
39
+ const CODEX_BACKEND_MODELS = {
40
+ 'gpt-6-astra': {
41
+ aliases: ['astra', 'gpt-6', 'gpt6', 'gpt6-astra'],
42
+ contextWindow: 272000,
43
+ supportedEfforts: ['low', 'medium', 'high', 'xhigh', 'max'],
44
+ },
45
+ 'gpt-5.6-sol': {
46
+ aliases: ['sol', 'gpt-5.6', 'gpt5.6', 'gpt-5.6-codex'],
47
+ contextWindow: 272000,
48
+ supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
49
+ },
50
+ 'gpt-5.6-terra': {
51
+ aliases: ['terra'],
52
+ contextWindow: 272000,
53
+ supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
54
+ },
55
+ 'gpt-5.6-luna': {
56
+ aliases: ['luna'],
57
+ contextWindow: 272000,
58
+ supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
59
+ },
60
+ 'gpt-5.5': {
61
+ aliases: ['gpt5.5'],
62
+ contextWindow: 272000,
63
+ supportedEfforts: ['low', 'medium', 'high', 'xhigh'],
64
+ },
65
+ 'gpt-5.3-codex-spark': {
66
+ aliases: ['spark', 'codex-spark'],
67
+ contextWindow: 128000,
68
+ supportedEfforts: ['low', 'medium', 'high', 'xhigh'],
69
+ },
70
+ };
71
+
72
+ const DEFAULT_BACKEND_MODEL = 'gpt-6-astra';
73
+
74
+ // The single user-facing model the router exposes. The backend model behind it
75
+ // comes from CODEX_MODEL, or from a `codex:<model>` spec.
21
76
  const SUPPORTED_MODELS = {
22
77
  codex: {
23
78
  modelName: 'codex',
24
- friendlyName: 'OpenAI Codex (GPT-5.6)',
25
- contextWindow: 400000,
79
+ friendlyName: 'OpenAI Codex (GPT-6 Astra)',
80
+ contextWindow: CODEX_BACKEND_MODELS[DEFAULT_BACKEND_MODEL].contextWindow,
26
81
  maxOutputTokens: 128000,
27
82
  supportsStreaming: true,
28
83
  supportsImages: true, // Codex SDK 0.118+ supports images via --image (local_image input)
29
84
  supportsWebSearch: false, // Codex accesses files directly, not web
30
- // Reasoning tiers this model's backend actually accepts. GPT-5.6 dropped
31
- // 'minimal' and added 'none', while the SDK's ModelReasoningEffort type
32
- // still advertises the pre-5.6 set — the backend is the authority, so the
33
- // accepted tiers are declared per model and requests are clamped onto them.
34
- supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh'],
35
85
  timeout: 1800000, // 30 minutes
36
86
  description:
37
- 'OpenAI Codex agentic coding assistant with local file access and tool execution (GPT-5.6)',
38
- aliases: [
39
- 'gpt-5-codex',
40
- 'gpt5-codex',
41
- 'gpt-5.2-codex',
42
- 'gpt-5.3-codex',
43
- 'gpt5.3-codex',
44
- 'gpt-5.5',
45
- 'gpt5.5',
46
- 'gpt-5.6-codex',
47
- 'gpt5.6-codex',
48
- ],
87
+ 'OpenAI Codex agentic coding assistant with local file access and tool execution (GPT-6 Astra by default; pick another backend with codex:<model> or CODEX_MODEL)',
88
+ aliases: [],
49
89
  },
50
90
  };
51
91
 
@@ -195,6 +235,57 @@ function extractPromptText(input) {
195
235
  .join('\n\n');
196
236
  }
197
237
 
238
+ /**
239
+ * Resolve a backend slug or alias (case-insensitive) to its catalog slug.
240
+ * @param {string} name
241
+ * @returns {string|null}
242
+ */
243
+ function findBackendSlug(name) {
244
+ const lower = String(name || '').trim().toLowerCase();
245
+ if (!lower) {
246
+ return null;
247
+ }
248
+ if (CODEX_BACKEND_MODELS[lower]) {
249
+ return lower;
250
+ }
251
+ return (
252
+ Object.keys(CODEX_BACKEND_MODELS).find((slug) =>
253
+ CODEX_BACKEND_MODELS[slug].aliases.includes(lower),
254
+ ) || null
255
+ );
256
+ }
257
+
258
+ /**
259
+ * Catalog entry for a backend model, or null when the slug is not catalogued.
260
+ * @param {string} name - Backend slug or alias
261
+ * @returns {{ slug: string, aliases: string[], contextWindow: number, supportedEfforts: string[] }|null}
262
+ */
263
+ export function getBackendModelConfig(name) {
264
+ const slug = findBackendSlug(name);
265
+ return slug ? { slug, ...CODEX_BACKEND_MODELS[slug] } : null;
266
+ }
267
+
268
+ /**
269
+ * Resolve the requested model spec to the backend slug passed to the CLI.
270
+ *
271
+ * `codex` uses CODEX_MODEL (default gpt-6-astra); `codex:<model>` names a
272
+ * backend directly, by slug or alias. Unknown names pass through verbatim so a
273
+ * newly released model works before it is catalogued here — the CLI rejects
274
+ * anything the backend does not know.
275
+ *
276
+ * @param {string} spec - Requested model, e.g. 'codex' or 'codex:sol'
277
+ * @param {Object} [config] - Loaded configuration
278
+ * @returns {string} Backend slug for the SDK's `model` option
279
+ */
280
+ export function resolveBackendModel(spec, config) {
281
+ const raw = String(spec || '').trim();
282
+ const requested = raw.toLowerCase().startsWith('codex:')
283
+ ? raw.slice('codex:'.length).trim()
284
+ : '';
285
+ const name = requested || config?.providers?.codexmodel || DEFAULT_BACKEND_MODEL;
286
+ return findBackendSlug(name) || name;
287
+ }
288
+
198
289
  /**
199
290
  * Get thread ID from continuation metadata.
200
291
  * Codex thread IDs are stored per call-plan in `providerThreads`, keyed by a
@@ -216,12 +307,6 @@ async function getThreadIdFromContinuation(
216
307
  }
217
308
  }
218
309
 
219
- /**
220
- * Every Codex reasoning tier, weakest to strongest. Used to clamp a requested
221
- * tier onto the set a given model actually accepts.
222
- */
223
- const EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh'];
224
-
225
310
  /**
226
311
  * Tool-level reasoning_effort values translated to their Codex equivalent.
227
312
  * Tool enum: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'max'
@@ -232,7 +317,7 @@ const EFFORT_ALIASES = {
232
317
  low: 'low',
233
318
  medium: 'medium',
234
319
  high: 'high',
235
- max: 'xhigh',
320
+ max: 'max',
236
321
  };
237
322
 
238
323
  /**
@@ -403,8 +488,9 @@ export const codexProvider = {
403
488
  const approvalPolicy = config.providers?.codexapprovalpolicy || 'never';
404
489
 
405
490
  // Create or resume thread
491
+ const backendModel = resolveBackendModel(model, config);
406
492
  const threadOptions = {
407
- model: config.providers?.codexmodel,
493
+ model: backendModel,
408
494
  workingDirectory,
409
495
  sandboxMode,
410
496
  skipGitRepoCheck,
@@ -413,13 +499,12 @@ export const codexProvider = {
413
499
 
414
500
  if (reasoning_effort) {
415
501
  const supportedEfforts =
416
- findModelConfig(model)?.supportedEfforts ||
417
- SUPPORTED_MODELS.codex.supportedEfforts;
502
+ getBackendModelConfig(backendModel)?.supportedEfforts || EFFORT_LADDER;
418
503
  const mappedEffort = mapReasoningEffort(reasoning_effort, supportedEfforts);
419
504
  threadOptions.modelReasoningEffort = mappedEffort;
420
505
  if (mappedEffort !== EFFORT_ALIASES[reasoning_effort]) {
421
506
  debugLog(
422
- `[Codex] reasoning_effort "${reasoning_effort}" not supported by ${model} — using "${mappedEffort}"`,
507
+ `[Codex] reasoning_effort "${reasoning_effort}" not supported by ${backendModel} — using "${mappedEffort}"`,
423
508
  );
424
509
  }
425
510
  }
@@ -470,6 +555,7 @@ export const codexProvider = {
470
555
  metadata: {
471
556
  provider: 'codex',
472
557
  model,
558
+ backendModel,
473
559
  threadId: threadIdFromStream || thread.id,
474
560
  usage: usage
475
561
  ? {
@@ -20,7 +20,9 @@
20
20
  *
21
21
  * The provider registry key remains 'gemini-cli' and the user-facing alias
22
22
  * remains 'gemini' for routing/normalization stability. Only three user-facing
23
- * model names are exposed: gemini (= gemini:pro), gemini:pro, gemini:flash.
23
+ * model names are exposed: gemini (= gemini:flash), gemini:flash, gemini:pro.
24
+ * Flash is the default: Gemini 3.8 Flash is the current-generation model agy
25
+ * lists first, while 3.1 Pro remains the only Pro tier Antigravity offers.
24
26
  */
25
27
 
26
28
  import { existsSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
@@ -57,7 +59,7 @@ const PTY_COLS = 1000;
57
59
  const SUPPORTED_MODELS = {
58
60
  gemini: {
59
61
  modelName: 'gemini',
60
- friendlyName: 'Gemini 3.1 Pro (via Antigravity CLI)',
62
+ friendlyName: 'Gemini 3.8 Flash (via Antigravity CLI)',
61
63
  contextWindow: 1048576,
62
64
  maxOutputTokens: 65536,
63
65
  supportsStreaming: true,
@@ -66,14 +68,14 @@ const SUPPORTED_MODELS = {
66
68
  supportsThinking: true,
67
69
  timeout: DEFAULT_TIMEOUT_MS,
68
70
  description:
69
- 'Gemini 3.1 Pro via Antigravity CLI (agy) - requires Antigravity Google OAuth login',
71
+ 'Gemini 3.8 Flash via Antigravity CLI (agy) - requires Antigravity Google OAuth login',
70
72
  aliases: ['gemini-cli'],
71
73
  // agy display-name base; reasoning_effort selects the parenthesized variant
72
- agyModelBase: 'Gemini 3.1 Pro',
74
+ agyModelBase: 'Gemini 3.8 Flash',
73
75
  },
74
- 'gemini:pro': {
75
- modelName: 'gemini:pro',
76
- friendlyName: 'Gemini 3.1 Pro (via Antigravity CLI)',
76
+ 'gemini:flash': {
77
+ modelName: 'gemini:flash',
78
+ friendlyName: 'Gemini 3.8 Flash (via Antigravity CLI)',
77
79
  contextWindow: 1048576,
78
80
  maxOutputTokens: 65536,
79
81
  supportsStreaming: true,
@@ -82,13 +84,13 @@ const SUPPORTED_MODELS = {
82
84
  supportsThinking: true,
83
85
  timeout: DEFAULT_TIMEOUT_MS,
84
86
  description:
85
- 'Gemini 3.1 Pro via Antigravity CLI (agy) - explicit alias of `gemini`',
86
- aliases: [],
87
- agyModelBase: 'Gemini 3.1 Pro',
87
+ 'Gemini 3.8 Flash via Antigravity CLI (agy) - explicit alias of `gemini`',
88
+ aliases: ['flash'],
89
+ agyModelBase: 'Gemini 3.8 Flash',
88
90
  },
89
- 'gemini:flash': {
90
- modelName: 'gemini:flash',
91
- friendlyName: 'Gemini 3.5 Flash (via Antigravity CLI)',
91
+ 'gemini:pro': {
92
+ modelName: 'gemini:pro',
93
+ friendlyName: 'Gemini 3.1 Pro (via Antigravity CLI)',
92
94
  contextWindow: 1048576,
93
95
  maxOutputTokens: 65536,
94
96
  supportsStreaming: true,
@@ -97,9 +99,9 @@ const SUPPORTED_MODELS = {
97
99
  supportsThinking: true,
98
100
  timeout: DEFAULT_TIMEOUT_MS,
99
101
  description:
100
- 'Gemini 3.5 Flash via Antigravity CLI (agy) - requires Antigravity Google OAuth login',
101
- aliases: ['flash'],
102
- agyModelBase: 'Gemini 3.5 Flash',
102
+ 'Gemini 3.1 Pro via Antigravity CLI (agy) - requires Antigravity Google OAuth login',
103
+ aliases: ['pro'],
104
+ agyModelBase: 'Gemini 3.1 Pro',
103
105
  },
104
106
  };
105
107
 
@@ -175,7 +177,7 @@ export function findAgyBinary() {
175
177
  /**
176
178
  * Map a reasoning_effort value to the agy parenthesized variant suffix.
177
179
  * Flash supports Low/Medium/High; Pro supports Low/High (no Medium).
178
- * @param {string} base - agy model base ('Gemini 3.5 Flash' / 'Gemini 3.1 Pro')
180
+ * @param {string} base - agy model base ('Gemini 3.8 Flash' / 'Gemini 3.1 Pro')
179
181
  * @param {string} [reasoningEffort]
180
182
  * @returns {string} e.g. '(Low)', '(Medium)', '(High)'
181
183
  */
@@ -207,7 +209,7 @@ function effortSuffix(base, reasoningEffort) {
207
209
  * verbatim so power users aren't blocked.
208
210
  * @param {string} model - e.g. 'gemini', 'gemini:flash', or a full agy name
209
211
  * @param {string} [reasoningEffort]
210
- * @returns {string} agy --model value, e.g. 'Gemini 3.1 Pro (High)'
212
+ * @returns {string} agy --model value, e.g. 'Gemini 3.8 Flash (High)'
211
213
  */
212
214
  export function resolveAgyModel(model, reasoningEffort) {
213
215
  const raw = typeof model === 'string' ? model.trim() : '';
@@ -230,11 +232,11 @@ export function resolveAgyModel(model, reasoningEffort) {
230
232
  !nameLower ||
231
233
  nameLower === 'gemini' ||
232
234
  nameLower === 'gemini-cli' ||
233
- nameLower === 'pro'
235
+ nameLower === 'flash'
234
236
  ) {
235
237
  base = SUPPORTED_MODELS.gemini.agyModelBase;
236
- } else if (nameLower === 'flash') {
237
- base = SUPPORTED_MODELS['gemini:flash'].agyModelBase;
238
+ } else if (nameLower === 'pro') {
239
+ base = SUPPORTED_MODELS['gemini:pro'].agyModelBase;
238
240
  } else {
239
241
  // Unknown suffix: pass through verbatim (power-user agy display name)
240
242
  return raw;
@@ -762,19 +764,16 @@ export const geminiCliProvider = {
762
764
 
763
765
  const name = modelName.toLowerCase().trim();
764
766
 
765
- // Full agy display-name passthrough → matching base config.
766
- if (/gemini 3\.5 flash/i.test(modelName)) {
767
+ // Full agy display-name passthrough → matching tier config. Any 3.x Flash
768
+ // (agy also lists 3.6/3.7) shares the Flash config; any 3.x Pro the Pro one.
769
+ if (/gemini 3\.\d+ flash/i.test(modelName)) {
767
770
  return SUPPORTED_MODELS['gemini:flash'];
768
771
  }
769
- if (/gemini 3\.1 pro/i.test(modelName)) {
770
- return SUPPORTED_MODELS.gemini;
771
- }
772
-
773
- if (name === 'pro') {
772
+ if (/gemini 3\.\d+ pro/i.test(modelName)) {
774
773
  return SUPPORTED_MODELS['gemini:pro'];
775
774
  }
776
775
 
777
- // Exact key match (gemini, gemini:pro, gemini:flash)
776
+ // Exact key match (gemini, gemini:flash, gemini:pro)
778
777
  if (SUPPORTED_MODELS[name]) {
779
778
  return SUPPORTED_MODELS[name];
780
779
  }
@@ -127,6 +127,32 @@ const SUPPORTED_MODELS = {
127
127
  '3.5-flash',
128
128
  ],
129
129
  },
130
+ 'gemini-3.8-flash': {
131
+ modelName: 'gemini-3.8-flash',
132
+ friendlyName: 'Gemini (Flash 3.8)',
133
+ contextWindow: 1048576, // 1M tokens
134
+ maxOutputTokens: 65536,
135
+ supportsStreaming: true,
136
+ supportsImages: true,
137
+ supportsThinking: true,
138
+ supportsWebSearch: true,
139
+ thinkingMode: 'level',
140
+ // 3.8 Flash rejects thinkingLevel "minimal" outright (API error), unlike 3.5.
141
+ thinkingLevels: ['low', 'medium', 'high'],
142
+ timeout: 900000,
143
+ description:
144
+ 'Gemini 3.8 Flash - Current-generation Flash with stronger long-horizon agentic performance (1M context)',
145
+ aliases: [
146
+ 'gemini-3.8',
147
+ 'gemini3.8',
148
+ 'gemini-3.8-flash-latest',
149
+ 'flash-3.8',
150
+ 'flash3.8',
151
+ 'gemini-flash-3.8',
152
+ 'gemini flash 3.8',
153
+ '3.8-flash',
154
+ ],
155
+ },
130
156
  };
131
157
 
132
158
  // Thinking mode budget percentages
@@ -514,10 +540,17 @@ export const googleProvider = {
514
540
  };
515
541
  thinkingLevel = levelMap[reasoning_effort] || 'high';
516
542
  if (!modelConfig.thinkingLevels.includes(thinkingLevel)) {
543
+ // Clamp to the nearest supported level: a request below the
544
+ // model's floor (e.g. minimal on 3.8 Flash) takes the lowest
545
+ // level, anything else the highest.
546
+ const rank = ['minimal', 'low', 'medium', 'high'];
547
+ const [lowest] = modelConfig.thinkingLevels;
517
548
  thinkingLevel =
518
- modelConfig.thinkingLevels[
519
- modelConfig.thinkingLevels.length - 1
520
- ];
549
+ rank.indexOf(thinkingLevel) < rank.indexOf(lowest)
550
+ ? lowest
551
+ : modelConfig.thinkingLevels[
552
+ modelConfig.thinkingLevels.length - 1
553
+ ];
521
554
  }
522
555
  } else {
523
556
  // Binary levels only (Gemini 3.0 Pro: low/high)
@@ -138,9 +138,10 @@ function classifyModelSpec(spec, providers) {
138
138
  }
139
139
 
140
140
  // Other explicit namespaces pass the spec through unchanged; the target
141
- // provider strips its own prefix (preserves current copilot/claude/gemini-cli
141
+ // provider strips its own prefix (preserves current codex/copilot/claude/gemini-cli
142
142
  // behavior).
143
143
  if (
144
+ lower.startsWith('codex:') ||
144
145
  lower.startsWith('copilot:') ||
145
146
  lower.startsWith('claude:') ||
146
147
  lower.startsWith('gemini:')
@@ -308,8 +309,9 @@ export function mapModelToProvider(model, providers) {
308
309
  return 'openai';
309
310
  }
310
311
 
311
- // Check Codex (exact match only - don't route "gpt-5-codex" etc to Codex provider)
312
- if (modelLower === 'codex') {
312
+ // Check Codex: bare `codex` or the `codex:<backend>` namespace (e.g. codex:astra,
313
+ // codex:gpt-5.6-sol). Bare "gpt-*" names never route here — they are OpenAI API models.
314
+ if (modelLower === 'codex' || modelLower.startsWith('codex:')) {
313
315
  return 'codex';
314
316
  }
315
317