From db9eedcda8011cbacb94630db0942bebbaabea3a Mon Sep 17 00:00:00 2001 From: Timothy Wayne Gregg Date: Thu, 9 Jul 2026 14:51:48 -0400 Subject: [PATCH 1/4] feat(api): update OpenAI Codex models Signed-off-by: Timothy Wayne Gregg --- docs/providers.md | 9 ++++-- src-rust/crates/api/src/model_registry.rs | 32 +++++++++++++++++--- src-rust/crates/api/src/providers/codex.rs | 11 ++++--- src-rust/crates/commands/src/lib.rs | 2 +- src-rust/crates/core/src/codex_oauth.rs | 7 +++-- src-rust/crates/core/src/lib.rs | 10 +++--- src-rust/crates/tui/src/dialog_select.rs | 2 +- src-rust/crates/tui/src/model_picker.rs | 4 ++- src-rust/crates/tui/src/onboarding_dialog.rs | 2 +- 9 files changed, 56 insertions(+), 23 deletions(-) diff --git a/docs/providers.md b/docs/providers.md index 2cad144..a50b52c 100644 --- a/docs/providers.md +++ b/docs/providers.md @@ -76,18 +76,21 @@ Runs Claude-style coding sessions against OpenAI's Codex using your ChatGPT/Code **Authentication:** Sign in with `coven-code codex login` (ChatGPT/Codex OAuth). Tokens are stored per profile under `~/.coven-code/accounts/codex//`. See [auth.md](auth.md) for the multi-account flow. -**Default model:** `gpt-5.5` +**Default model:** `gpt-5.6-sol` **Bundled Codex model list:** | Model ID | Notes | |---|---| -| `gpt-5.5` | Default; recommended for most Codex tasks | +| `gpt-5.6-sol` | Default; flagship GPT-5.6 model for complex coding, computer use, research, and cybersecurity | +| `gpt-5.6-terra` | Balanced GPT-5.6 model for everyday work at lower cost than Sol | +| `gpt-5.6-luna` | Fast, lower-cost GPT-5.6 model for clear, repeatable tasks | +| `gpt-5.5` | Previous-generation frontier model for complex Codex tasks | | `gpt-5.4` | Frontier Codex model | | `gpt-5.4-mini` | Fast/lower-cost model for lighter coding tasks and subagents | | `gpt-5.3-codex-spark` | Research preview for ChatGPT Pro users | | `gpt-5.3-codex` | Deprecated for ChatGPT sign-in; retained for explicit selection | -| `gpt-5.2-codex` | Deprecated for ChatGPT sign-in; retained for explicit selection | +| `gpt-5.2-codex` | Legacy Codex/API-key compatibility model | | `gpt-5.1-codex` | Legacy Codex model | | `gpt-5.1-codex-mini` | Legacy mini model | | `gpt-5.1-codex-max` | Legacy max model | diff --git a/src-rust/crates/api/src/model_registry.rs b/src-rust/crates/api/src/model_registry.rs index 7277f99..c4e1c24 100644 --- a/src-rust/crates/api/src/model_registry.rs +++ b/src-rust/crates/api/src/model_registry.rs @@ -970,6 +970,11 @@ fn flagship_patterns_for(provider_id: &str) -> &'static [&'static str] { "claude-sonnet-3", ], "openai" => &[ + "gpt-5.6-sol", + "gpt-5.6-terra", + "gpt-5.6-luna", + "gpt-5.6", + "gpt-5.5", "gpt-5.2-pro", "gpt-5.2", "gpt-5.1", @@ -1001,7 +1006,16 @@ fn flagship_patterns_for(provider_id: &str) -> &'static [&'static str] { ], "zai" => &["glm-5.1", "glm-5", "glm-4.7"], "minimax" => &["minimax-m2"], - "codex" | "openai-codex" => &["gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex-spark"], + "codex" | "openai-codex" => &[ + "gpt-5.6-sol", + "gpt-5.6-terra", + "gpt-5.6-luna", + "gpt-5.6", + "gpt-5.5", + "gpt-5.4", + "gpt-5.4-mini", + "gpt-5.3-codex-spark", + ], "ollama" | "lmstudio" | "lm-studio" | "llamacpp" | "llama-cpp" => &[ "qwen3-coder", "qwen2.5-coder", @@ -1034,11 +1048,17 @@ fn codex_models_fallback(provider_id: &str, small: bool) -> Option { return None; } if small { - // Prefer the documented "mini" entry; fall through to the default - // model id if the constant is ever pruned. + // Prefer the latest documented cost-efficient Codex entry; fall + // through to older mini models or the default if the constant is ever + // pruned. claurst_core::codex_oauth::CODEX_MODELS .iter() - .find(|(id, _)| id.contains("mini")) + .find(|(id, _)| *id == "gpt-5.6-luna") + .or_else(|| { + claurst_core::codex_oauth::CODEX_MODELS + .iter() + .find(|(id, _)| id.contains("mini")) + }) .map(|(id, _)| (*id).to_string()) .or_else(|| Some(claurst_core::codex_oauth::DEFAULT_CODEX_MODEL.to_string())) } else { @@ -1049,7 +1069,7 @@ fn codex_models_fallback(provider_id: &str, small: bool) -> Option { fn small_patterns_for(provider_id: &str) -> &'static [&'static str] { match provider_id { "anthropic" => &["claude-haiku-4", "claude-haiku-3-5", "claude-haiku"], - "codex" | "openai" | "openai-codex" => &["gpt-5.4-mini", "gpt-5-mini"], + "codex" | "openai" | "openai-codex" => &["gpt-5.6-luna", "gpt-5.4-mini", "gpt-5-mini"], _ => &["mini", "haiku", "flash", "lite", "small", "nano"], } } @@ -1188,6 +1208,7 @@ mod tests { let best = reg .best_model_for_provider("codex") .expect("codex best model must fall back to CODEX_MODELS default"); + assert_eq!(best, claurst_core::codex_oauth::DEFAULT_CODEX_MODEL); assert!( claurst_core::codex_oauth::CODEX_MODELS .iter() @@ -1197,6 +1218,7 @@ mod tests { let small = reg .best_small_model_for_provider("codex") .expect("codex small model must fall back to a mini/default id"); + assert_eq!(small, "gpt-5.6-luna"); assert!( claurst_core::codex_oauth::CODEX_MODELS .iter() diff --git a/src-rust/crates/api/src/providers/codex.rs b/src-rust/crates/api/src/providers/codex.rs index 596b3b1..d1beaaa 100644 --- a/src-rust/crates/api/src/providers/codex.rs +++ b/src-rust/crates/api/src/providers/codex.rs @@ -918,7 +918,9 @@ impl LlmProvider for CodexProvider { provider_id: self.id.clone(), name: name.to_string(), context_window: match *id { - "gpt-5.5" | "gpt-5.4" => 1_050_000, + "gpt-5.6-sol" | "gpt-5.6-terra" | "gpt-5.6-luna" | "gpt-5.5" | "gpt-5.4" => { + 1_050_000 + } "gpt-5.4-mini" | "gpt-5.3-codex" | "gpt-5.2-codex" | "gpt-5.1-codex" | "gpt-5.1-codex-mini" | "gpt-5.1-codex-max" | "gpt-5.2" | "gpt-5-codex" | "gpt-5-mini" => 400_000, @@ -928,9 +930,10 @@ impl LlmProvider for CodexProvider { _ => 128_000, }, max_output_tokens: match *id { - "gpt-5.5" | "gpt-5.4" | "gpt-5.4-mini" | "gpt-5.3-codex" | "gpt-5.2-codex" - | "gpt-5.1-codex" | "gpt-5.1-codex-mini" | "gpt-5.1-codex-max" | "gpt-5.2" - | "gpt-5-codex" | "gpt-5-mini" => 128_000, + "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" | "gpt-5.2-codex" | "gpt-5.1-codex" + | "gpt-5.1-codex-mini" | "gpt-5.1-codex-max" | "gpt-5.2" | "gpt-5-codex" + | "gpt-5-mini" => 128_000, _ => 32_768, }, }) diff --git a/src-rust/crates/commands/src/lib.rs b/src-rust/crates/commands/src/lib.rs index 137d6ac..39f5ff9 100644 --- a/src-rust/crates/commands/src/lib.rs +++ b/src-rust/crates/commands/src/lib.rs @@ -773,7 +773,7 @@ impl SlashCommand for ModelCommand { /model — open the model picker\n\ /model claude-sonnet-4-6 — switch to Claude Sonnet 4.6\n\ /model claude-haiku-4-5 — switch to Claude Haiku 4.5\n\ - /model codex/gpt-5.5 — switch to Codex (requires codex login)" + /model codex/gpt-5.6-sol — switch to Codex (requires codex login)" } async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { diff --git a/src-rust/crates/core/src/codex_oauth.rs b/src-rust/crates/core/src/codex_oauth.rs index c9bd9d5..0a613d3 100644 --- a/src-rust/crates/core/src/codex_oauth.rs +++ b/src-rust/crates/core/src/codex_oauth.rs @@ -27,7 +27,10 @@ pub const CODEX_SCOPES: &str = "openid profile email offline_access"; /// Available Codex models pub const CODEX_MODELS: &[(&str, &str)] = &[ - ("gpt-5.5", "GPT-5.5 (default)"), + ("gpt-5.6-sol", "GPT-5.6 Sol (default)"), + ("gpt-5.6-terra", "GPT-5.6 Terra"), + ("gpt-5.6-luna", "GPT-5.6 Luna"), + ("gpt-5.5", "GPT-5.5"), ("gpt-5.4", "GPT-5.4"), ("gpt-5.4-mini", "GPT-5.4 Mini"), ("gpt-5.3-codex-spark", "GPT-5.3 Codex Spark (Pro preview)"), @@ -46,7 +49,7 @@ pub const CODEX_MODELS: &[(&str, &str)] = &[ ]; /// Default Codex model to use -pub const DEFAULT_CODEX_MODEL: &str = "gpt-5.5"; +pub const DEFAULT_CODEX_MODEL: &str = "gpt-5.6-sol"; #[cfg(test)] mod tests { diff --git a/src-rust/crates/core/src/lib.rs b/src-rust/crates/core/src/lib.rs index 3fc17a2..62271d7 100644 --- a/src-rust/crates/core/src/lib.rs +++ b/src-rust/crates/core/src/lib.rs @@ -832,17 +832,17 @@ pub mod config { ManagedAgentPreset { name: "codex-tiered", label: "Codex Tiered", - description: "gpt-5.5 manages, gpt-5.4-mini executes", - manager_model: "codex/gpt-5.5", - executor_model: "codex/gpt-5.4-mini", + description: "gpt-5.6-sol manages, gpt-5.6-luna executes", + manager_model: "codex/gpt-5.6-sol", + executor_model: "codex/gpt-5.6-luna", executor_max_turns: 10, max_concurrent_executors: 4, }, ManagedAgentPreset { name: "cross-codex-anthropic", label: "Cross: Codex + Claude", - description: "gpt-5.5 manages, Sonnet 4.6 executes", - manager_model: "codex/gpt-5.5", + description: "gpt-5.6-sol manages, Sonnet 4.6 executes", + manager_model: "codex/gpt-5.6-sol", executor_model: "anthropic/claude-sonnet-4-6", executor_max_turns: 10, max_concurrent_executors: 4, diff --git a/src-rust/crates/tui/src/dialog_select.rs b/src-rust/crates/tui/src/dialog_select.rs index c4e640f..28e10ba 100644 --- a/src-rust/crates/tui/src/dialog_select.rs +++ b/src-rust/crates/tui/src/dialog_select.rs @@ -445,7 +445,7 @@ mod tests { SelectItem { id: "codex".into(), title: "Codex".into(), - description: "gpt-5.5 via ChatGPT".into(), + description: "gpt-5.6-sol via ChatGPT".into(), category: "Recommended".into(), badge: None, }, diff --git a/src-rust/crates/tui/src/model_picker.rs b/src-rust/crates/tui/src/model_picker.rs index 7b88b40..bf66dc4 100644 --- a/src-rust/crates/tui/src/model_picker.rs +++ b/src-rust/crates/tui/src/model_picker.rs @@ -361,7 +361,9 @@ fn codex_provider_models() -> Vec { .iter() .map(|(id, name)| { let ctx = match *id { - "gpt-5.5" | "gpt-5.4" => "1M ctx", + "gpt-5.6-sol" | "gpt-5.6-terra" | "gpt-5.6-luna" | "gpt-5.5" | "gpt-5.4" => { + "1M ctx" + } "gpt-5.4-mini" | "gpt-5.3-codex" | "gpt-5.2" | "gpt-5.2-codex" | "gpt-5.1-codex" | "gpt-5.1-codex-mini" | "gpt-5.1-codex-max" => "400K ctx", "gpt-5.3-codex-spark" => "128K ctx", diff --git a/src-rust/crates/tui/src/onboarding_dialog.rs b/src-rust/crates/tui/src/onboarding_dialog.rs index 7eaf065..9488d83 100644 --- a/src-rust/crates/tui/src/onboarding_dialog.rs +++ b/src-rust/crates/tui/src/onboarding_dialog.rs @@ -165,7 +165,7 @@ const PROVIDER_ENTRIES: &[ProviderEntry] = &[ }, ProviderEntry { name: "Codex", - tagline: " gpt-5.5 via Codex CLI login", + tagline: " gpt-5.6-sol via Codex CLI login", setup: "Codex CLI", setup_suffix: "", }, From 307b7a30c915cf5468f3b55b967a904b9b1ccbc3 Mon Sep 17 00:00:00 2001 From: Timothy Wayne Gregg Date: Thu, 9 Jul 2026 16:23:50 -0400 Subject: [PATCH 2/4] fix(api): satisfy locked clippy formatting lint Signed-off-by: Timothy Wayne Gregg --- src-rust/crates/api/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-rust/crates/api/src/lib.rs b/src-rust/crates/api/src/lib.rs index 0fea2b1..f2c6f73 100644 --- a/src-rust/crates/api/src/lib.rs +++ b/src-rust/crates/api/src/lib.rs @@ -674,7 +674,7 @@ pub mod client { .header("anthropic-version", &self.config.api_version) .header("content-type", "application/json"); if self.config.use_bearer_auth { - req = req.header("Authorization", format!("Bearer {}", &self.config.api_key)); + req = req.header("Authorization", format!("Bearer {}", self.config.api_key)); } else { req = req.header("x-api-key", &self.config.api_key); } @@ -727,7 +727,7 @@ pub mod client { .header("accept", "text/event-stream"); if use_oauth { - req = req.header("Authorization", format!("Bearer {}", &self.config.api_key)); + req = req.header("Authorization", format!("Bearer {}", self.config.api_key)); } else { // Compute CCH billing hash and attach on the API-key path // only — this is the codepath the official client uses From ff7533b8edf091ddb777aefd93770eb4f35d4eae Mon Sep 17 00:00:00 2001 From: Timothy Wayne Gregg Date: Thu, 9 Jul 2026 17:00:55 -0400 Subject: [PATCH 3/4] fix(tui): stabilize provider picker credential test Signed-off-by: Timothy Wayne Gregg --- src-rust/crates/tui/src/app.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src-rust/crates/tui/src/app.rs b/src-rust/crates/tui/src/app.rs index 1e2cf40..506e2fd 100644 --- a/src-rust/crates/tui/src/app.rs +++ b/src-rust/crates/tui/src/app.rs @@ -272,6 +272,7 @@ pub(crate) mod test_env { pub(crate) struct EnvGuard { old_home: Option, old_coven_home: Option, + old_test_home: Option, old_anthropic_config_dir: Option, old_anthropic_api_key: Option, old_oauth_client_id: Option, @@ -290,6 +291,7 @@ pub(crate) mod test_env { let guard = Self { old_home: std::env::var("HOME").ok(), old_coven_home: std::env::var("COVEN_HOME").ok(), + old_test_home: std::env::var("COVEN_CODE_TEST_HOME").ok(), old_anthropic_config_dir: std::env::var("ANTHROPIC_CONFIG_DIR").ok(), old_anthropic_api_key: std::env::var("ANTHROPIC_API_KEY").ok(), old_oauth_client_id: std::env::var(claurst_core::oauth::CLIENT_ID_ENV).ok(), @@ -299,6 +301,7 @@ pub(crate) mod test_env { }; std::env::set_var("HOME", PathBuf::from(home)); std::env::set_var("COVEN_HOME", PathBuf::from(coven_home)); + std::env::set_var("COVEN_CODE_TEST_HOME", PathBuf::from(home)); std::env::remove_var("ANTHROPIC_CONFIG_DIR"); std::env::remove_var("ANTHROPIC_API_KEY"); std::env::remove_var(claurst_core::oauth::CLIENT_ID_ENV); @@ -323,6 +326,10 @@ pub(crate) mod test_env { Some(value) => std::env::set_var("COVEN_HOME", value), None => std::env::remove_var("COVEN_HOME"), } + match &self.old_test_home { + Some(value) => std::env::set_var("COVEN_CODE_TEST_HOME", value), + None => std::env::remove_var("COVEN_CODE_TEST_HOME"), + } match &self.old_anthropic_config_dir { Some(value) => std::env::set_var("ANTHROPIC_CONFIG_DIR", value), None => std::env::remove_var("ANTHROPIC_CONFIG_DIR"), @@ -418,7 +425,13 @@ fn provider_picker_items() -> Vec { } fn local_anthropic_cli_login_available() -> bool { - if let Some(home) = dirs::home_dir() { + let home_dir = std::env::var("COVEN_CODE_TEST_HOME") + .ok() + .filter(|home| !home.trim().is_empty()) + .map(std::path::PathBuf::from) + .or_else(dirs::home_dir); + + if let Some(home) = home_dir { let path = home.join(".claude").join(".credentials.json"); if let Ok(text) = std::fs::read_to_string(path) { if claurst_core::anthropic_cli_import::parse_claude_code(&text) From dd270866bda653293045f6a07ad4db223ad0ffd7 Mon Sep 17 00:00:00 2001 From: Timothy Wayne Gregg Date: Thu, 9 Jul 2026 17:38:06 -0400 Subject: [PATCH 4/4] fix(tui): avoid test-home env races Signed-off-by: Timothy Wayne Gregg --- src-rust/crates/tui/src/app.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src-rust/crates/tui/src/app.rs b/src-rust/crates/tui/src/app.rs index 27cb6b2..3a47437 100644 --- a/src-rust/crates/tui/src/app.rs +++ b/src-rust/crates/tui/src/app.rs @@ -272,7 +272,6 @@ pub(crate) mod test_env { pub(crate) struct EnvGuard { old_home: Option, old_coven_home: Option, - old_test_home: Option, old_anthropic_config_dir: Option, old_anthropic_api_key: Option, old_oauth_client_id: Option, @@ -292,7 +291,6 @@ pub(crate) mod test_env { let guard = Self { old_home: std::env::var("HOME").ok(), old_coven_home: std::env::var("COVEN_HOME").ok(), - old_test_home: std::env::var("COVEN_CODE_TEST_HOME").ok(), old_anthropic_config_dir: std::env::var("ANTHROPIC_CONFIG_DIR").ok(), old_anthropic_api_key: std::env::var("ANTHROPIC_API_KEY").ok(), old_oauth_client_id: std::env::var(claurst_core::oauth::CLIENT_ID_ENV).ok(), @@ -304,7 +302,6 @@ pub(crate) mod test_env { }; std::env::set_var("HOME", PathBuf::from(home)); std::env::set_var("COVEN_HOME", PathBuf::from(coven_home)); - std::env::set_var("COVEN_CODE_TEST_HOME", PathBuf::from(home)); std::env::remove_var("ANTHROPIC_CONFIG_DIR"); std::env::remove_var("ANTHROPIC_API_KEY"); std::env::remove_var(claurst_core::oauth::CLIENT_ID_ENV); @@ -330,10 +327,6 @@ pub(crate) mod test_env { Some(value) => std::env::set_var("COVEN_HOME", value), None => std::env::remove_var("COVEN_HOME"), } - match &self.old_test_home { - Some(value) => std::env::set_var("COVEN_CODE_TEST_HOME", value), - None => std::env::remove_var("COVEN_CODE_TEST_HOME"), - } match &self.old_anthropic_config_dir { Some(value) => std::env::set_var("ANTHROPIC_CONFIG_DIR", value), None => std::env::remove_var("ANTHROPIC_CONFIG_DIR"),