Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions docs/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<id>/`. 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 |
Expand Down
4 changes: 2 additions & 2 deletions src-rust/crates/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Expand Down
32 changes: 27 additions & 5 deletions src-rust/crates/api/src/model_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -1034,11 +1048,17 @@ fn codex_models_fallback(provider_id: &str, small: bool) -> Option<String> {
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 {
Expand All @@ -1049,7 +1069,7 @@ fn codex_models_fallback(provider_id: &str, small: bool) -> Option<String> {
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"],
}
}
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand Down
11 changes: 7 additions & 4 deletions src-rust/crates/api/src/providers/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
},
})
Expand Down
2 changes: 1 addition & 1 deletion src-rust/crates/commands/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 5 additions & 2 deletions src-rust/crates/core/src/codex_oauth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)"),
Expand All @@ -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 {
Expand Down
10 changes: 5 additions & 5 deletions src-rust/crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
29 changes: 22 additions & 7 deletions src-rust/crates/tui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ pub(crate) mod test_env {
old_anthropic_config_dir: Option<String>,
old_anthropic_api_key: Option<String>,
old_oauth_client_id: Option<String>,
old_claude_bin: Option<String>,
old_user: Option<String>,
old_username: Option<String>,
_lock: MutexGuard<'static, ()>,
Expand All @@ -293,6 +294,8 @@ pub(crate) mod test_env {
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(),
old_claude_bin: std::env::var(claurst_api::providers::claude_cli::CLAUDE_BIN_ENV)
.ok(),
old_user: std::env::var("USER").ok(),
old_username: std::env::var("USERNAME").ok(),
_lock: lock,
Expand All @@ -302,6 +305,7 @@ pub(crate) mod test_env {
std::env::remove_var("ANTHROPIC_CONFIG_DIR");
std::env::remove_var("ANTHROPIC_API_KEY");
std::env::remove_var(claurst_core::oauth::CLIENT_ID_ENV);
std::env::remove_var(claurst_api::providers::claude_cli::CLAUDE_BIN_ENV);
match user {
Some(value) => std::env::set_var("USER", value),
None => std::env::remove_var("USER"),
Expand Down Expand Up @@ -335,6 +339,12 @@ pub(crate) mod test_env {
Some(value) => std::env::set_var(claurst_core::oauth::CLIENT_ID_ENV, value),
None => std::env::remove_var(claurst_core::oauth::CLIENT_ID_ENV),
}
match &self.old_claude_bin {
Some(value) => {
std::env::set_var(claurst_api::providers::claude_cli::CLAUDE_BIN_ENV, value)
}
None => std::env::remove_var(claurst_api::providers::claude_cli::CLAUDE_BIN_ENV),
}
match &self.old_user {
Some(value) => std::env::set_var("USER", value),
None => std::env::remove_var("USER"),
Expand Down Expand Up @@ -7941,18 +7951,23 @@ role = "Research"
}

#[test]
fn provider_picker_prioritizes_import_when_claude_credentials_exist() {
fn provider_picker_marks_claude_cli_local_when_binary_exists() {
let temp = tempfile::tempdir().expect("tempdir");
let home = temp.path().join("home");
let coven_home = temp.path().join("coven");
std::fs::create_dir_all(home.join(".claude")).expect("claude dir");
let claude_bin = temp.path().join(if cfg!(windows) {
"claude.cmd"
} else {
"claude"
});
std::fs::create_dir_all(&home).expect("home");
std::fs::create_dir_all(&coven_home).expect("coven home");
std::fs::write(
home.join(".claude").join(".credentials.json"),
r#"{"claudeAiOauth":{"accessToken":"sk-ant-oat01-test"}}"#,
)
.expect("credentials");
std::fs::write(&claude_bin, "").expect("claude binary");
let _guard = EnvGuard::set(&home, &coven_home);
std::env::set_var(
claurst_api::providers::claude_cli::CLAUDE_BIN_ENV,
&claude_bin,
);

let items = provider_picker_items();

Expand Down
2 changes: 1 addition & 1 deletion src-rust/crates/tui/src/dialog_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down
4 changes: 3 additions & 1 deletion src-rust/crates/tui/src/model_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,9 @@ fn codex_provider_models() -> Vec<ModelEntry> {
.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",
Expand Down
2 changes: 1 addition & 1 deletion src-rust/crates/tui/src/onboarding_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: "",
},
Expand Down