diff --git a/code-rs/core/src/agent_defaults.rs b/code-rs/core/src/agent_defaults.rs index f87e34feac7..f5e92b4be33 100644 --- a/code-rs/core/src/agent_defaults.rs +++ b/code-rs/core/src/agent_defaults.rs @@ -213,9 +213,16 @@ const AGENT_MODEL_SPECS: &[AgentModelSpec] = &[ read_only_args: ANTIGRAVITY_READ_ONLY, write_args: ANTIGRAVITY_WRITE, model_args: &[], - description: "Google Antigravity CLI agent; use as the Google-agent path after consumer Gemini CLI retirement.", + description: "Google/Gemini-family agent via Antigravity CLI; use for Google perspective after consumer Gemini CLI retirement. AGY uses its configured model, not per-run Gemini Pro/Flash flags.", enabled_by_default: true, - aliases: &["agy", "google-antigravity"], + aliases: &[ + "agy", + "google", + "gemini", + "gemini-agent", + "gemini-perspective", + "google-antigravity", + ], gating_env: None, is_frontline: true, pro_only: false, @@ -497,7 +504,9 @@ fn model_guide_intro(active_agents: &[String]) -> String { } let frontline_str = present_frontline.join(", "); - format!("Preferred agent models: use {frontline_str} for challenging coding/agentic work.") + format!( + "Preferred agent models: use {frontline_str} for challenging coding/agentic work. For explicit multi-agent or dissent requests, prefer diverse model families when useful and budget allows; include `antigravity` for Google/Gemini-family perspective." + ) } fn model_guide_line(spec: &AgentModelSpec) -> String { @@ -698,6 +707,28 @@ mod tests { assert_eq!(legacy.slug, "claude-opus-4.8"); } + #[test] + fn google_intent_aliases_resolve_to_antigravity() { + for alias in ["google", "gemini", "gemini-agent", "gemini-perspective"] { + let spec = agent_model_spec(alias).expect("google-family alias should resolve"); + assert_eq!(spec.slug, "antigravity"); + assert!(spec.model_args.is_empty()); + } + } + + #[test] + fn model_guide_describes_antigravity_as_google_family_lane() { + let guide = build_model_guide_description(&[ + "code-gpt-5.5".to_string(), + "claude-sonnet-4.6".to_string(), + "antigravity".to_string(), + ]); + + assert!(guide.contains("include `antigravity` for Google/Gemini-family perspective")); + assert!(guide.contains("AGY uses its configured model")); + assert!(guide.contains("not per-run Gemini Pro/Flash flags")); + } + #[test] fn retired_codex_models_are_not_default_agent_specs() { let pro_specs = enabled_agent_model_specs_for_auth(Some(AuthMode::Chatgpt), true); diff --git a/code-rs/core/src/agent_tool.rs b/code-rs/core/src/agent_tool.rs index f1deac72f9d..b4982f48215 100644 --- a/code-rs/core/src/agent_tool.rs +++ b/code-rs/core/src/agent_tool.rs @@ -2004,8 +2004,7 @@ async fn execute_model_with_permissions( remove_review_output_json(review_output_json_path); let spec_opt = agent_model_spec(model) - .or_else(|| config.as_ref().and_then(|cfg| agent_model_spec(&cfg.name))) - .or_else(|| config.as_ref().and_then(|cfg| agent_model_spec(&cfg.command))); + .or_else(|| config.as_ref().and_then(|cfg| agent_model_spec(&cfg.name))); if let Some(spec) = spec_opt { if !spec.is_enabled() { @@ -2873,7 +2872,7 @@ pub fn create_agent_tool(allowed_models: &[String]) -> OpenAiTool { }, }), description: Some( - "Optional array of agent/model selector slugs (e.g., ['code-gpt-5.5','claude-sonnet-4.6','antigravity']; external CLI selectors use that tool's configured model)".to_string(), + "Optional array of agent/model selector slugs. For explicit multi-agent/dissent requests, prefer diverse families when useful and budget allows (for example ['code-gpt-5.5','claude-sonnet-4.6','antigravity']). Use `antigravity` for Google/Gemini-family perspective; AGY uses its configured model rather than per-run Gemini Pro/Flash selection. If you skip an obvious family, briefly explain why.".to_string(), ), }, ); @@ -3269,6 +3268,7 @@ mod tests { use super::AgentRetryMetadata; use super::AgentStatus; use super::AGENT_PROVIDER_RETRY_MAX_DELAY; + use super::create_agent_tool; use super::MAX_AGENT_PROGRESS_ENTRIES; use super::MAX_AGENT_RESULT_BYTES; use super::MAX_TRACKED_TERMINAL_AGENTS; @@ -3285,6 +3285,7 @@ mod tests { use super::agent_retry_delay; use super::AGENT_MANAGER; use crate::config_types::AgentConfig; + use crate::openai_tools::{JsonSchema, OpenAiTool}; use code_protocol::config_types::ReasoningEffort; use serial_test::serial; use std::collections::HashMap; @@ -4102,6 +4103,95 @@ mod tests { ); } + #[tokio::test] + async fn gemini_selector_uses_antigravity_cli() { + let _lock = env_lock().lock().expect("env lock"); + let _reset_path = EnvReset::capture("PATH"); + + let dir = tempdir().expect("tempdir"); + let agy = script_path(dir.path(), "agy"); + write_argv_script(&agy); + let workspace = dir.path().join("workspace"); + std::fs::create_dir_all(&workspace).expect("create workspace"); + + unsafe { + std::env::set_var("PATH", prepend_path(dir.path())); + } + + let output = execute_model_with_permissions( + "agent-test", + "gemini", + "hello from google lane", + true, + Some(workspace.clone()), + None, + ReasoningEffort::Low, + None, + None, + None, + ) + .await + .expect("execute gemini selector through antigravity"); + + let args: Vec<&str> = output.trim().split('|').collect(); + assert_eq!( + args, + vec![ + "--add-dir", + workspace.to_str().expect("workspace path utf-8"), + "-p", + "hello from google lane", + ] + ); + } + + #[tokio::test] + async fn explicit_gemini_command_keeps_gemini_cli_args() { + let _lock = env_lock().lock().expect("env lock"); + let _reset_path = EnvReset::capture("PATH"); + + let dir = tempdir().expect("tempdir"); + let gemini = script_path(dir.path(), "gemini"); + write_argv_script(&gemini); + let workspace = dir.path().join("workspace"); + std::fs::create_dir_all(&workspace).expect("create workspace"); + + unsafe { + std::env::set_var("PATH", prepend_path(dir.path())); + } + + let cfg = AgentConfig { + name: "corp-gemini".to_string(), + command: "gemini".to_string(), + args: Vec::new(), + read_only: true, + enabled: true, + description: None, + env: None, + args_read_only: None, + args_write: None, + instructions: None, + }; + + let output = execute_model_with_permissions( + "agent-test", + "corp-gemini", + "hello from gemini cli", + true, + Some(workspace), + Some(cfg), + ReasoningEffort::Low, + None, + None, + None, + ) + .await + .expect("execute explicit gemini CLI config"); + + let args: Vec<&str> = output.trim().split('|').collect(); + assert_eq!(args, vec!["-p", "hello from gemini cli"]); + } + fn env_lock() -> &'static Mutex<()> { static LOCK: OnceLock> = OnceLock::new(); LOCK.get_or_init(|| Mutex::new(())) @@ -4461,6 +4551,41 @@ exit 0 assert_eq!(agent_retry_delay(8), AGENT_PROVIDER_RETRY_MAX_DELAY); } + #[test] + fn agent_tool_models_description_guides_google_family_delegation() { + let tool = create_agent_tool(&[ + "code-gpt-5.5".to_string(), + "claude-sonnet-4.6".to_string(), + "antigravity".to_string(), + ]); + + let function = match tool { + OpenAiTool::Function(function) => function, + _ => panic!("agent tool should be a function"), + }; + let JsonSchema::Object { properties, .. } = function.parameters else { + panic!("agent tool should have object parameters"); + }; + let create_schema = properties.get("create").expect("create schema"); + let JsonSchema::Object { properties: create_properties, .. } = create_schema else { + panic!("create schema should be an object"); + }; + let models_schema = create_properties.get("models").expect("models schema"); + let JsonSchema::Array { items, description } = models_schema else { + panic!("models schema should be an array"); + }; + let description = description.as_deref().expect("models description"); + assert!(description.contains("diverse families")); + assert!(description.contains("Use `antigravity` for Google/Gemini-family perspective")); + assert!(description.contains("AGY uses its configured model")); + + let JsonSchema::String { allowed_values, .. } = items.as_ref() else { + panic!("models items should be strings"); + }; + let values = allowed_values.as_ref().expect("allowed models"); + assert!(values.contains(&"antigravity".to_string())); + } + #[tokio::test] #[serial] async fn agent_provider_retry_wrapper_recovers_from_transient_failure() { diff --git a/code-rs/core/tests/antigravity_agent_spec.rs b/code-rs/core/tests/antigravity_agent_spec.rs index 0bd999feeb8..c506f7bfb34 100644 --- a/code-rs/core/tests/antigravity_agent_spec.rs +++ b/code-rs/core/tests/antigravity_agent_spec.rs @@ -17,7 +17,18 @@ fn antigravity_replaces_builtin_gemini_agent_path() { .slug, "antigravity" ); - assert!(agent_model_spec("gemini").is_none()); + assert_eq!( + agent_model_spec("gemini") + .expect("gemini intent alias present") + .slug, + "antigravity" + ); + assert_eq!( + agent_model_spec("google") + .expect("google intent alias present") + .slug, + "antigravity" + ); assert!(agent_model_spec("gemini-3-flash-preview").is_none()); assert!(agent_model_spec("gemini-3.1-pro-preview").is_none()); } diff --git a/docs/agents.md b/docs/agents.md index 2955a801b8e..e1d1950462d 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -21,7 +21,7 @@ Field recap: `name` (slug/alias), `command` (absolute paths ok), `args*` (RO/RW ### Built-in defaults If no `[[agents]]` are configured, Every Code advertises built-in agent/model selectors (gated by env `CODE_ENABLE_CLOUD_AGENT_MODEL` for cloud variants): `code-gpt-5.5`, `code-gpt-5.4`, `code-gpt-5.4-mini`, `claude-opus-4.8`, `antigravity`, `claude-sonnet-4.6`, `claude-haiku-4.5`, `qwen3-coder-plus`, `cloud-gpt-5.1-codex-max`. Built-ins strip any user `--model/-m` flags to avoid conflicts and inject their own when the target CLI supports model flags. -Tip: `antigravity` uses Google's Antigravity CLI (`agy`) as the Google-agent path. Consumer Gemini CLI is no longer a built-in default; configure it manually only when you intentionally rely on enterprise/API-key Gemini CLI access. +Tip: `antigravity` uses Google's Antigravity CLI (`agy`) as the Google/Gemini-family agent path. Gemini/Google intent can resolve to `antigravity`, but AGY uses its configured model rather than a per-run Gemini Pro/Flash flag. Consumer Gemini CLI is no longer a built-in default; configure it manually only when you intentionally rely on enterprise/API-key Gemini CLI access. ## Subagents (`[[subagents.commands]]`) ```toml @@ -40,6 +40,8 @@ agent_instructions = "Preamble added to each spawned agent" The orchestrator fans out agents, waits for results, and merges reasoning according to your `hide_agent_reasoning` / `show_raw_agent_reasoning` settings. +When you ask the Every Code agent to "ask agents" or gather dissent, it should prefer a small, diverse batch when the task benefits from multiple viewpoints and budget allows. A typical diverse batch includes GPT, Claude, and `antigravity` for the Google/Gemini-family perspective. Narrow mechanical work can use fewer agents; if an obvious family is skipped, the agent should briefly say why. + ## TUI controls - `/agents` opens the settings overlay to the Agents section: toggle enabled/read-only, view defaults, and open editors. - Agent editor: create or edit a single agent (enable/disable, read-only, instructions). Args/env come from `config.toml`. diff --git a/docs/config.md b/docs/config.md index 2c78c035488..c7a117828ef 100644 --- a/docs/config.md +++ b/docs/config.md @@ -223,7 +223,7 @@ approval_policy = "never" Use `[[agents]]` blocks to register additional CLI programs that Code can launch as peers. Each block maps a short `name` (referenced elsewhere in the config) to the command to execute, optional default flags, and environment variables. -> **Note:** Built-in agent/model selectors (for example `code-gpt-5.4`, `claude-sonnet-4.6`, or `antigravity`) map to a CLI plus optional model flags. Code strips any user `--model`/`-m` flags from `args`, `args_read_only`, or `args_write` before launching a built-in to avoid conflicts. `antigravity` launches `agy` and uses Antigravity's configured model rather than injecting a Gemini model flag. +> **Note:** Built-in agent/model selectors (for example `code-gpt-5.4`, `claude-sonnet-4.6`, or `antigravity`) map to a CLI plus optional model flags. Code strips any user `--model`/`-m` flags from `args`, `args_read_only`, or `args_write` before launching a built-in to avoid conflicts. `antigravity` launches `agy` as the Google/Gemini-family path and uses Antigravity's configured model rather than injecting a Gemini model flag. ```toml [[agents]] @@ -473,7 +473,7 @@ tool_timeout_sec = 30 Sub-agents are orchestrated helper workflows you can trigger with slash commands (for example `/plan`, `/solve`, `/code`). Each entry under `[[subagents.commands]]` defines the slash command name, whether spawned agents run in read-only mode, which `agents` to launch, and extra guidance for both the orchestrator (Code) and the individual agents. -By default (when no `[[agents]]` are configured) Code advertises these agent/model selectors for multi-agent runs: `code-gpt-5.5`, `code-gpt-5.4`, `code-gpt-5.4-mini`, `claude-opus-4.8`, `antigravity`, `claude-sonnet-4.6`, `claude-haiku-4.5`, and `qwen3-coder-plus`. The cloud counterpart, `cloud-gpt-5.1-codex-max`, only appears when `CODE_ENABLE_CLOUD_AGENT_MODEL=1` is set. You can override the list by defining `[[agents]]` entries or by specifying `agents = [ … ]` on a given `[[subagents.commands]]` entry. Consumer Gemini CLI is not a built-in default; add a custom `[[agents]]` block only when you intentionally rely on enterprise/API-key Gemini CLI access. +By default (when no `[[agents]]` are configured) Code advertises these agent/model selectors for multi-agent runs: `code-gpt-5.5`, `code-gpt-5.4`, `code-gpt-5.4-mini`, `claude-opus-4.8`, `antigravity`, `claude-sonnet-4.6`, `claude-haiku-4.5`, and `qwen3-coder-plus`. The cloud counterpart, `cloud-gpt-5.1-codex-max`, only appears when `CODE_ENABLE_CLOUD_AGENT_MODEL=1` is set. You can override the list by defining `[[agents]]` entries or by specifying `agents = [ … ]` on a given `[[subagents.commands]]` entry. Consumer Gemini CLI is not a built-in default; add a custom `[[agents]]` block only when you intentionally rely on enterprise/API-key Gemini CLI access. Legacy Gemini-style agent selectors are treated as Google-family intent and resolve to `antigravity`, which still uses AGY's configured model. ```toml [[subagents.commands]]