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
2 changes: 1 addition & 1 deletion code-rs/core/prompt_coder.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ agent {
"task": "Implement JWT middleware (RS256) with key rotation and unit/integration tests. Preserve existing OAuth flows. Provide README usage snippet.",
"context": "Service: services/api (Rust Axum). Secrets via env. CI: `cargo test --all`.",
"files": ["services/api", "services/api/src", "services/api/Cargo.toml"],
"models": ["code-gpt-5.4","claude-sonnet-4.5","gemini-3-flash"],
"models": ["code-gpt-5.4","claude-sonnet-4.6","gemini-3-flash-preview"],
"output": "Middleware + passing tests + README snippet",
"write": true // Allow changes - will launch every agent in a separate worktree
}
Expand Down
44 changes: 25 additions & 19 deletions code-rs/core/src/agent_defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ pub const DEFAULT_AGENT_NAMES: &[&str] = &[
"code-gpt-5.3-codex",
"code-gpt-5.3-codex-spark",
"claude-opus-4.6",
"gemini-3-pro",
"gemini-3.1-pro-preview",
// Straightforward / cost-aware
"code-gpt-5.1-codex-mini",
"claude-sonnet-4.5",
"gemini-3-flash",
"claude-sonnet-4.6",
"gemini-3-flash-preview",
// Mixed/general and alternates
"claude-haiku-4.5",
"qwen-3-coder",
"qwen3-coder-plus",
"cloud-gpt-5.1-codex-max",
];

Expand Down Expand Up @@ -179,7 +179,7 @@ const AGENT_MODEL_SPECS: &[AgentModelSpec] = &[
cli: "claude",
read_only_args: CLAUDE_OPUS_READ_ONLY,
write_args: CLAUDE_OPUS_WRITE,
model_args: &["--model", "opus"],
model_args: &["--model", "claude-opus-4-6"],
description: "Higher-capacity Claude model for complex reasoning; use when you want the strongest Claude.",
enabled_by_default: true,
aliases: &["claude-opus", "claude-opus-4.1", "claude-opus-4.5"],
Expand All @@ -188,15 +188,15 @@ const AGENT_MODEL_SPECS: &[AgentModelSpec] = &[
pro_only: false,
},
AgentModelSpec {
slug: "claude-sonnet-4.5",
slug: "claude-sonnet-4.6",
family: "claude",
cli: "claude",
read_only_args: CLAUDE_SONNET_READ_ONLY,
write_args: CLAUDE_SONNET_WRITE,
model_args: &["--model", "sonnet"],
model_args: &["--model", "claude-sonnet-4-6"],
description: "Balanced Claude model for implementation and debugging; a solid default when you want Claude.",
enabled_by_default: true,
aliases: &["claude", "claude-sonnet"],
aliases: &["claude", "claude-sonnet", "claude-sonnet-4.5"],
gating_env: None,
is_frontline: false,
pro_only: false,
Expand All @@ -207,7 +207,7 @@ const AGENT_MODEL_SPECS: &[AgentModelSpec] = &[
cli: "claude",
read_only_args: CLAUDE_HAIKU_READ_ONLY,
write_args: CLAUDE_HAIKU_WRITE,
model_args: &["--model", "haiku"],
model_args: &["--model", "claude-haiku-4-5"],
description: "Fast Claude model for simple tasks, drafts, and quick iterations; pick when latency matters.",
enabled_by_default: true,
aliases: &["claude-haiku"],
Expand All @@ -216,15 +216,16 @@ const AGENT_MODEL_SPECS: &[AgentModelSpec] = &[
pro_only: false,
},
AgentModelSpec {
slug: "gemini-3-pro",
slug: "gemini-3.1-pro-preview",
family: "gemini",
cli: "gemini",
read_only_args: GEMINI_PRO_READ_ONLY,
write_args: GEMINI_PRO_WRITE,
model_args: &["--model", "pro"],
description: "Higher-capacity Gemini model for harder tasks; use when gemini-3-flash misses details.",
model_args: &["--model", "gemini-3.1-pro-preview"],
description: "Higher-capacity Gemini preview for harder tasks; use when gemini-3-flash-preview misses details.",
enabled_by_default: true,
aliases: &[
"gemini-3-pro",
"gemini-3-pro-preview",
"gemini-3",
"gemini3",
Expand All @@ -236,29 +237,34 @@ const AGENT_MODEL_SPECS: &[AgentModelSpec] = &[
pro_only: false,
},
AgentModelSpec {
slug: "gemini-3-flash",
slug: "gemini-3-flash-preview",
family: "gemini",
cli: "gemini",
read_only_args: GEMINI_FLASH_READ_ONLY,
write_args: GEMINI_FLASH_WRITE,
model_args: &["--model", "flash"],
description: "Primary Gemini default for most tasks; fast and low-cost with near gemini-3-pro quality.",
model_args: &["--model", "gemini-3-flash-preview"],
description: "Primary Gemini preview default for most tasks; fast and low-cost with near gemini-3.1-pro-preview quality.",
enabled_by_default: true,
aliases: &["gemini", "gemini-flash", "gemini-2.5-flash"],
aliases: &[
"gemini",
"gemini-flash",
"gemini-3-flash",
"gemini-2.5-flash",
],
gating_env: None,
is_frontline: false,
pro_only: false,
},
AgentModelSpec {
slug: "qwen-3-coder",
slug: "qwen3-coder-plus",
family: "qwen",
cli: "qwen",
read_only_args: QWEN_3_CODER_READ_ONLY,
write_args: QWEN_3_CODER_WRITE,
model_args: &["-m", "qwen-3-coder"],
model_args: &["-m", "qwen3-coder-plus"],
description: "Fast and capable alternative; useful as a second opinion or for cross-checking.",
enabled_by_default: true,
aliases: &["qwen", "qwen3"],
aliases: &["qwen", "qwen3", "qwen-3-coder"],
gating_env: None,
is_frontline: false,
pro_only: false,
Expand Down
6 changes: 3 additions & 3 deletions code-rs/core/src/agent_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2417,7 +2417,7 @@ pub fn create_agent_tool(allowed_models: &[String]) -> OpenAiTool {
},
}),
description: Some(
"Optional array of model names (e.g., ['code-gpt-5.4','claude-sonnet-4.5','code-gpt-5.3-codex-spark','gemini-3-flash'])".to_string(),
"Optional array of model names (e.g., ['code-gpt-5.4','claude-sonnet-4.6','code-gpt-5.3-codex-spark','gemini-3-flash-preview'])".to_string(),
),
},
);
Expand Down Expand Up @@ -2975,7 +2975,7 @@ mod tests {
}

let cfg = AgentConfig {
name: "claude-sonnet-4.5".to_string(),
name: "claude-sonnet-4.6".to_string(),
command: "claude".to_string(),
args: Vec::new(),
read_only: true,
Expand All @@ -2989,7 +2989,7 @@ mod tests {

let output = execute_model_with_permissions(
"agent-test",
"claude-sonnet-4.5",
"claude-sonnet-4.6",
"ok",
true,
None,
Expand Down
102 changes: 93 additions & 9 deletions code-rs/core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2969,6 +2969,90 @@ model_verbosity = "high"
assert_eq!(legacy.review_model.as_deref(), Some("gpt-5.1-codex"));
}

#[test]
fn upgrade_legacy_model_slugs_updates_agent_names() {
let mut cfg = ConfigToml::default();
cfg.agents = vec![
AgentConfig {
name: "claude-sonnet-4.5".to_string(),
command: "claude".to_string(),
args: Vec::new(),
read_only: false,
enabled: true,
description: None,
env: None,
args_read_only: None,
args_write: None,
instructions: None,
},
AgentConfig {
name: "gemini-3-pro".to_string(),
command: "gemini".to_string(),
args: Vec::new(),
read_only: false,
enabled: true,
description: None,
env: None,
args_read_only: None,
args_write: None,
instructions: None,
},
AgentConfig {
name: "qwen-3-coder".to_string(),
command: "qwen".to_string(),
args: Vec::new(),
read_only: false,
enabled: true,
description: None,
env: None,
args_read_only: None,
args_write: None,
instructions: None,
},
];

upgrade_legacy_model_slugs(&mut cfg);

assert_eq!(cfg.agents[0].name, "claude-sonnet-4.6");
assert_eq!(cfg.agents[1].name, "gemini-3.1-pro-preview");
assert_eq!(cfg.agents[2].name, "qwen3-coder-plus");
}

#[test]
fn upgrade_legacy_model_slugs_updates_subagent_agent_lists() {
let mut cfg = ConfigToml::default();
cfg.subagents = Some(crate::config_types::SubagentsToml {
max_depth: None,
commands: vec![crate::config_types::SubagentCommandConfig {
name: "code".to_string(),
read_only: false,
agents: vec![
"claude-sonnet-4.5".to_string(),
"gemini-3-flash".to_string(),
"qwen-3-coder".to_string(),
],
orchestrator_instructions: None,
agent_instructions: None,
}],
});

upgrade_legacy_model_slugs(&mut cfg);

let command = &cfg
.subagents
.as_ref()
.expect("subagents exist")
.commands[0];
assert_eq!(
command.agents,
vec![
"claude-sonnet-4.6".to_string(),
"gemini-3-flash-preview".to_string(),
"qwen3-coder-plus".to_string(),
]
);
}

#[test]
fn upgrade_legacy_model_slugs_does_not_rewrite_gpt_5_4() {
let mut cfg = ConfigToml {
Expand Down Expand Up @@ -3083,9 +3167,9 @@ model_verbosity = "high"

assert!(enabled_names.contains("code-gpt-5.3-codex"));
assert!(enabled_names.contains("code-gpt-5.4"));
assert!(enabled_names.contains("claude-sonnet-4.5"));
assert!(enabled_names.contains("gemini-3-pro"));
assert!(enabled_names.contains("qwen-3-coder"));
assert!(enabled_names.contains("claude-sonnet-4.6"));
assert!(enabled_names.contains("gemini-3.1-pro-preview"));
assert!(enabled_names.contains("qwen3-coder-plus"));
Ok(())
}

Expand Down Expand Up @@ -3296,20 +3380,20 @@ mod agent_merge_tests {
fn gemini_alias_and_canonical_dedupe_prefers_last_state() {
let agents = vec![
agent("gemini-2.5-pro", "gemini", true),
agent("gemini-3-pro", "gemini", false),
agent("gemini-3.1-pro-preview", "gemini", false),
];
let merged = merge_with_default_agents(agents);

let gemini = merged
.iter()
.find(|a| a.name.eq_ignore_ascii_case("gemini-3-pro"))
.find(|a| a.name.eq_ignore_ascii_case("gemini-3.1-pro-preview"))
.expect("gemini present");

assert!(!gemini.enabled, "later canonical disable should win");
assert_eq!(
merged
.iter()
.filter(|a| a.name.eq_ignore_ascii_case("gemini-3-pro"))
.filter(|a| a.name.eq_ignore_ascii_case("gemini-3.1-pro-preview"))
.count(),
1,
"should dedupe gemini alias/canonical"
Expand All @@ -3319,21 +3403,21 @@ mod agent_merge_tests {
#[test]
fn gemini_alias_disable_overrides_prior_canonical_enable() {
let agents = vec![
agent("gemini-3-pro", "gemini", true),
agent("gemini-3.1-pro-preview", "gemini", true),
agent("gemini-2.5-pro", "gemini", false),
];
let merged = merge_with_default_agents(agents);

let gemini = merged
.iter()
.find(|a| a.name.eq_ignore_ascii_case("gemini-3-pro"))
.find(|a| a.name.eq_ignore_ascii_case("gemini-3.1-pro-preview"))
.expect("gemini present");

assert!(!gemini.enabled, "later alias disable should win");
assert_eq!(
merged
.iter()
.filter(|a| a.name.eq_ignore_ascii_case("gemini-3-pro"))
.filter(|a| a.name.eq_ignore_ascii_case("gemini-3.1-pro-preview"))
.count(),
1,
"should dedupe gemini alias/canonical"
Expand Down
51 changes: 45 additions & 6 deletions code-rs/core/src/config/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,37 @@ pub(crate) fn upgrade_legacy_model_slugs(cfg: &mut ConfigToml) {
}
}

fn maybe_upgrade_name(field: &mut String) {
if let Some(new) = upgrade_legacy_model_slug(field) {
tracing::info!(
target: "code.config",
old = field.as_str(),
new,
"upgrading legacy agent slug to newer default",
);
*field = new;
}
}

maybe_upgrade(&mut cfg.model);
maybe_upgrade(&mut cfg.review_model);

for profile in cfg.profiles.values_mut() {
maybe_upgrade(&mut profile.model);
maybe_upgrade(&mut profile.review_model);
}

for agent in &mut cfg.agents {
maybe_upgrade_name(&mut agent.name);
}

if let Some(subagents) = cfg.subagents.as_mut() {
for command in &mut subagents.commands {
for agent in &mut command.agents {
maybe_upgrade_name(agent);
}
}
}
}

fn upgrade_legacy_model_slug(slug: &str) -> Option<String> {
Expand Down Expand Up @@ -199,14 +223,29 @@ fn upgrade_legacy_model_slug(slug: &str) -> Option<String> {
return Some("claude-opus-4.6".to_string());
}

// Upgrade Gemini 2.5 Pro to Gemini 3 Pro (or preview alias)
if slug.eq_ignore_ascii_case("gemini-2.5-pro") || slug.eq_ignore_ascii_case("gemini-3-pro-preview") {
return Some("gemini-3-pro".to_string());
// Upgrade Anthropic Sonnet 4.5 to 4.6.
if slug.eq_ignore_ascii_case("claude-sonnet-4.5") {
return Some("claude-sonnet-4.6".to_string());
}

// Upgrade Gemini Pro slugs to the latest preview track.
if slug.eq_ignore_ascii_case("gemini-2.5-pro")
|| slug.eq_ignore_ascii_case("gemini-3-pro")
|| slug.eq_ignore_ascii_case("gemini-3-pro-preview")
{
return Some("gemini-3.1-pro-preview".to_string());
}

// Upgrade Gemini Flash slugs to the latest preview track.
if slug.eq_ignore_ascii_case("gemini-2.5-flash")
|| slug.eq_ignore_ascii_case("gemini-3-flash")
{
return Some("gemini-3-flash-preview".to_string());
}

// Upgrade Gemini 2.5 Flash to Gemini 3 Flash
if slug.eq_ignore_ascii_case("gemini-2.5-flash") {
return Some("gemini-3-flash".to_string());
// Upgrade the older Qwen coder slug to the current plus line.
if slug.eq_ignore_ascii_case("qwen-3-coder") {
return Some("qwen3-coder-plus".to_string());
}

// Keep codex variants on their existing line; upgrades are surfaced via the
Expand Down
Loading