[codex] update multi-agent v2 prompts (#28283)

## Summary

- align the default multi-agent v2 root and subagent hints with the
evaluated prompt guidance for direct collaboration-tool calls, parallel
delegation, and shared workspaces
- keep the current `interrupt_agent` tool name and existing
concurrency-hint placement, with the explicit no-spawn instruction last
- document the context tradeoff between `fork_turns="none"` and
`fork_turns="all"` in the v2 `spawn_agent` description
- extend the focused prompt and tool-surface tests

## Why

The evaluated multi-agent prompt includes operational guidance that is
missing from the current Codex defaults. This applies that guidance to
the current tool surface without restoring stale `close_agent` or
duplicated concurrency wording.

## User impact

Multi-agent v2 receives clearer instructions about when and how to
parallelize work, how agent workspaces interact, and how `fork_turns`
affects subagent context. The existing default opt-out behavior remains
in place.

## Testing

- `just fmt`
- `just test -p codex-core
multi_agent_v2_default_usage_hints_use_configured_thread_cap`
- `just test -p codex-core
multi_agent_feature_selects_one_agent_tool_family`
This commit is contained in:
jif
2026-06-15 11:21:02 +01:00
committed by GitHub
Unverified
parent b3c423e475
commit 127224cacc
4 changed files with 21 additions and 5 deletions
+4 -1
View File
@@ -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())))
);
}
+11 -3
View File
@@ -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}"
)
}
@@ -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 {
@@ -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(