Files
codex/codex-rs/core/src/session/multi_agents.rs
T
jif c03742ca0a Simplify multi-agent mode controls (#29324)
## Why

Multi-agent delegation policy was split across `multiAgentMode`,
`features.multi_agent_mode`, and `usage_hint_enabled`. These controls
could disagree: a requested mode could be downgraded by the feature
flag, and disabling usage hints also disabled mode instructions.

Some clients also need multi-agent tools without adding
delegation-policy text to model context. The previous two-mode API could
not express that directly.

## What changed

`multiAgentMode` is now the only live delegation-policy control:

| Mode | Behavior |
| --- | --- |
| `none` | Keep multi-agent tools available without adding mode
instructions. |
| `explicitRequestOnly` | Only delegate after an explicit user request.
|
| `proactive` | Delegate when parallel work materially improves speed or
quality. |

- new threads default to `explicitRequestOnly`; omitting the mode on
later turns keeps the current value
- thread start, resume, fork, and settings responses always report the
concrete current mode instead of `null`
- mode selection remains sticky across turns and resume
- usage-hint text no longer controls whether mode instructions apply
- `features.multi_agent_mode` and `usage_hint_enabled` remain accepted
as ignored compatibility settings so existing configs continue to load
- app-server documentation and generated schemas describe the three-mode
API

## Tests

- `just test -p codex-core multi_agent_mode`
- `just test -p codex-core multi_agent_v2_config_from_feature_table`
- `just test -p codex-core spawn_agent_description`
- `just test -p codex-features`
- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server multi_agent_mode`
2026-06-22 10:05:36 +02:00

58 lines
1.9 KiB
Rust

use crate::config::MultiAgentV2Config;
use crate::session::turn_context::TurnContext;
use codex_protocol::config_types::MultiAgentMode;
use codex_protocol::protocol::MultiAgentVersion;
use codex_protocol::protocol::SessionSource;
use codex_protocol::protocol::SubAgentSource;
pub(super) fn usage_hint_text<'a>(
turn_context: &'a TurnContext,
session_source: &SessionSource,
) -> Option<&'a str> {
if turn_context.multi_agent_version != MultiAgentVersion::V2 {
return None;
}
let multi_agent_v2 = &turn_context.config.multi_agent_v2;
configured_usage_hint_text_for_source(multi_agent_v2, session_source)
}
fn configured_usage_hint_text_for_source<'a>(
multi_agent_v2: &'a MultiAgentV2Config,
session_source: &SessionSource,
) -> Option<&'a str> {
match session_source {
SessionSource::SubAgent(SubAgentSource::ThreadSpawn { .. }) => {
multi_agent_v2.subagent_usage_hint_text.as_deref()
}
SessionSource::Cli
| SessionSource::VSCode
| SessionSource::Exec
| SessionSource::Mcp
| SessionSource::Custom(_)
| SessionSource::Unknown => multi_agent_v2.root_agent_usage_hint_text.as_deref(),
SessionSource::Internal(_) | SessionSource::SubAgent(_) => None,
}
}
pub(crate) fn effective_multi_agent_mode(
multi_agent_version: MultiAgentVersion,
session_source: &SessionSource,
multi_agent_mode: MultiAgentMode,
) -> Option<MultiAgentMode> {
if multi_agent_version != MultiAgentVersion::V2 {
return None;
}
match session_source {
SessionSource::SubAgent(SubAgentSource::ThreadSpawn { .. })
| SessionSource::Cli
| SessionSource::VSCode
| SessionSource::Exec
| SessionSource::Mcp
| SessionSource::Custom(_)
| SessionSource::Unknown => Some(multi_agent_mode),
SessionSource::Internal(_) | SessionSource::SubAgent(_) => None,
}
}