diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index 183756051..38f04d23b 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -9843,13 +9843,16 @@ max_concurrent_threads_per_session = 17 let config = resolve_multi_agent_v2_config(&config_toml); let concurrency_guidance = "There are 17 available concurrency slots, meaning that up to 17 agents can be active at once, including you."; + let expected_suffix = format!( + "{DEFAULT_MULTI_AGENT_V2_SHARED_USAGE_HINT_TEXT}\n{concurrency_guidance}\n\n{DEFAULT_MULTI_AGENT_V2_NO_SPAWN_HINT_TEXT}" + ); assert!( [ config.root_agent_usage_hint_text, config.subagent_usage_hint_text, ] .into_iter() - .all(|hint| hint.is_some_and(|hint| hint.ends_with(concurrency_guidance))) + .all(|hint| hint.is_some_and(|hint| hint.ends_with(expected_suffix.as_str()))) ); } diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 25da826b2..1dd4117e6 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -206,7 +206,6 @@ All agents in the team, including the agents that you can assign tasks to, are e You can use `spawn_agent` to create a new agent, `followup_task` to give an existing agent a new task and trigger a turn, and `send_message` to pass a message to a running agent without triggering a turn. Child agents can also spawn their own sub-agents. You can decide how much context you want to propagate to your sub-agents with the `fork_turns` parameter. -Do not spawn sub-agents unless the user explicitly asks for sub-agents, delegation, or parallel agent work. You will receive messages in the analysis channel in the form: ``` @@ -223,7 +222,6 @@ You can spawn sub-agents to handle subtasks, and those sub-agents can spawn thei You can use `spawn_agent` to create a new agent, `followup_task` to give an existing agent a new task and trigger a turn, and `send_message` to pass a message to a running agent. Child agents can also spawn their own sub-agents. -Do not spawn sub-agents unless the user explicitly asks for sub-agents, delegation, or parallel agent work. When you provide a response in the final channel, that content is immediately delivered back to your parent agent. @@ -237,10 +235,20 @@ Payload: ``` You may also see them addressed as to=/root/..., which indicates your identity is /root/... "#; +const DEFAULT_MULTI_AGENT_V2_SHARED_USAGE_HINT_TEXT: &str = r#"Note that collaboration tools cannot be called from inside `functions.exec`. Call `spawn_agent`, `send_message`, `followup_task`, `wait_agent`, `interrupt_agent`, and `list_agents` only as direct tool calls using the recipient shown in their tool definitions, such as `to=functions.spawn_agent` without a configured namespace or `to=functions.agents.spawn_agent` with `tool_namespace = "agents"`, since they are intentionally absent from the `functions.exec` `tools.*` namespace. Available tools in `functions.exec` are explicitly described with a `tools` namespace in the developer message. + +The goal is to correctly solve the problem in as little time as possible. Therefore, if at any point you can parallelize work by delegating tasks to another agent, you should do so to save time. + +All agents share the same directory. In detail: +- All agents have access to the same container and filesystem as you. +- All agents use the same current working directory. +- As a result, edits made by one agent are immediately visible to all other agents. +"#; +const DEFAULT_MULTI_AGENT_V2_NO_SPAWN_HINT_TEXT: &str = "Do not spawn sub-agents unless the user explicitly asks for sub-agents, delegation, or parallel agent work."; fn default_multi_agent_v2_usage_hint_text(usage_hint_text: &str, max_concurrency: usize) -> String { format!( - "{usage_hint_text}\nThere are {max_concurrency} available concurrency slots, meaning that up to {max_concurrency} agents can be active at once, including you." + "{usage_hint_text}\n{DEFAULT_MULTI_AGENT_V2_SHARED_USAGE_HINT_TEXT}\nThere are {max_concurrency} available concurrency slots, meaning that up to {max_concurrency} agents can be active at once, including you.\n\n{DEFAULT_MULTI_AGENT_V2_NO_SPAWN_HINT_TEXT}" ) } diff --git a/codex-rs/core/src/tools/handlers/multi_agents_spec.rs b/codex-rs/core/src/tools/handlers/multi_agents_spec.rs index 40462f63e..98f68b145 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents_spec.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents_spec.rs @@ -726,7 +726,9 @@ The spawned agent will have the same tools as you and the ability to spawn its o {inherited_model_guidance} Only call this tool for a concrete, bounded subtask that can run independently alongside useful local work; otherwise continue locally. It will be able to send you and other running agents messages, and its final answer will be provided to you when it finishes. -The new agent's canonical task name will be provided to it along with the message."# +The new agent's canonical task name will be provided to it along with the message. + +Note that passing `fork_turns="none"` will not pass any surrounding context to the spawned subagent, which may cause the agent to lack the context it needs to complete its task, whereas `fork_turns="all"` will provide the subagent with all surrounding context."# ); if !include_usage_hint { diff --git a/codex-rs/core/src/tools/spec_plan_tests.rs b/codex-rs/core/src/tools/spec_plan_tests.rs index 7a1e5d8aa..d7cc7b78a 100644 --- a/codex-rs/core/src/tools/spec_plan_tests.rs +++ b/codex-rs/core/src/tools/spec_plan_tests.rs @@ -1044,6 +1044,9 @@ async fn multi_agent_feature_selects_one_agent_tool_family() { other => panic!("expected spawn_agent function spec, got {other:?}"), }; assert!(!spawn_agent_description.contains("max_concurrent_threads_per_session")); + assert!(spawn_agent_description.contains( + "Note that passing `fork_turns=\"none\"` will not pass any surrounding context to the spawned subagent" + )); let direct_model_only = probe(|turn| { set_features(