feat(core/agents): add 'cloud' agent support across run_agent, /plan, /solve; docs and examples; basic tests

- core/agent_tool: recognize "cloud" model and append prompt positionally; honor per‑mode args
- core/codex(agent_run): include "cloud" in command resolution + PATH check
- core/slash_commands: default /plan,/solve models now include "cloud"; test asserts prompt includes it
- core/agent_defaults: add cloud case (no default flags); unit test ensures empty defaults
- docs: note default agent set includes "cloud"; add config example

Build passes via ./build-fast.sh. Full test suite currently fails on unrelated preexisting test drift (protocol/test-support imports, enum shapes).
This commit is contained in:
James Peter
2025-10-02 23:53:36 +10:00
parent eb4b044983
commit db582085b5
7 changed files with 54 additions and 1 deletions
+13
View File
@@ -50,7 +50,20 @@ pub fn default_params_for(name: &str, read_only: bool) -> Vec<String> {
]
}
}
// Cloud agent: do not assume a prompt flag by default. Users can
// configure args via [[agents]]; we will append the prompt positionally.
"cloud" => Vec::new(),
_ => Vec::new(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cloud_defaults_are_empty_both_modes() {
assert!(default_params_for("cloud", true).is_empty());
assert!(default_params_for("cloud", false).is_empty());
}
}
+15
View File
@@ -652,6 +652,21 @@ async fn execute_model_with_permissions(
cmd.args(defaults);
}
}
// Cloud agent: append prompt positionally; do not assume a -p flag.
"cloud" => {
// If config provided explicit args for this mode, do not append defaults.
let have_mode_args = config
.as_ref()
.map(|c| if read_only { c.args_read_only.is_some() } else { c.args_write.is_some() })
.unwrap_or(false);
if have_mode_args {
cmd.arg(prompt);
} else {
let mut defaults = crate::agent_defaults::default_params_for(model_name, read_only);
defaults.push(prompt.to_string());
cmd.args(defaults);
}
}
_ => { return Err(format!("Unknown model: {}", model)); }
}
+2
View File
@@ -6491,6 +6491,8 @@ pub(crate) async fn handle_run_agent(sess: &Session, ctx: &ToolCallCtx, argument
"claude" => ("claude".to_string(), false),
"gemini" => ("gemini".to_string(), false),
"qwen" => ("qwen".to_string(), false),
// Cloud agent treated as external CLI by default.
"cloud" => ("cloud".to_string(), false),
_ => (m, false),
}
}
+5 -1
View File
@@ -22,6 +22,7 @@ fn get_default_models() -> Vec<String> {
"gemini".to_string(),
"qwen".to_string(),
"code".to_string(),
"cloud".to_string(),
]
}
@@ -238,7 +239,10 @@ mod tests {
// Test /plan command
let result = handle_slash_command("/plan implement a new feature", None);
assert!(result.is_some());
assert!(result.unwrap().contains("Create a comprehensive plan"));
let plan_prompt = result.unwrap();
assert!(plan_prompt.contains("Create a comprehensive plan"));
// Default agents list should include cloud when no [[agents]] configured
assert!(plan_prompt.to_ascii_lowercase().contains("cloud"));
// Test /solve command
let result = handle_slash_command("/solve fix the bug in authentication", None);
+13
View File
@@ -97,6 +97,19 @@ description = "Custom LLM implementation"
args = ["--config", "/path/to/config.json"]
env = { MODEL_PATH = "/models/custom.bin", TEMP = "0.7" }
# Cloud agent example
[[agents]]
name = "cloud"
command = "cloud" # or a fully-qualified CLI if different
enabled = true
read-only = true # cloud work typically runs remotely; local writes aren’t needed
description = "Submit tasks to a remote cloud worker"
# By default no extra flags are passed; the prompt is appended positionally.
# If your CLI expects a flag before the prompt, specify it here, e.g.:
# args = ["submit", "-p"]
# Optional environment:
# env = { CODEX_CLOUD_ENV = "prod" }
# Sandbox Configuration
# Controls file system access and permissions
sandbox-mode = "workspace-write"
+2
View File
@@ -424,6 +424,8 @@ 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 names for multi-agent runs: `claude`, `gemini`, `qwen`, `code`, and `cloud`. You can override that set by defining `[[agents]]` entries or by specifying `agents = [ … ]` on a given `[[subagents.commands]]` entry.
```toml
[[subagents.commands]]
name = "context"
+4
View File
@@ -93,3 +93,7 @@ Implementation Notes
new command, please update this document to keep the UI and docs in sync.
- Prompt formatting for `/plan`, `/solve`, and `/code` lives in
`codex-rs/core/src/slash_commands.rs`.
When no `[[agents]]` are configured, the orchestrator advertises the
following agent names to the LLM for multi‑agent runs: `claude`, `gemini`,
`qwen`, `code`, and `cloud`. You can replace or pin this set via `[[agents]]`
or per‑command `[[subagents.commands]].agents`.