mirror of
https://github.com/openai/codex.git
synced 2026-09-05 15:18:41 +00:00
## Why
Multi-agent V2 normally derives its mode instructions from reasoning
effort: Ultra enables proactive delegation, while other efforts require
an explicit request. Some deployments need to provide one configured
delegation policy that replaces those built-ins and remains stable when
reasoning effort changes.
## What changed
- Add `features.multi_agent_v2.multi_agent_mode_hint_text` alongside the
existing root and subagent hint settings.
- Treat any configured value, including an empty string, as
`MultiAgentMode::Custom(hint_text)`, so the configured text replaces the
built-in explicit-only and proactive policies.
- Persist the full custom variant and hint text in the turn-context
snapshot, so the durable comparison baseline detects both
reasoning-effort changes and configured policy-text changes.
- Preserve the existing explicit-only/proactive behavior when the
setting is absent.
- Replace the ambiguous `MultiAgentMode::None` variant with
`MultiAgentMode::Custom(String)` in new rollouts and API schemas. A
compatibility wire type maps legacy serialized `none` values to
`Custom("")` when resuming existing rollouts.
- Regenerate the config and app-server schemas.
## Configuration examples
The distinction is whether `multi_agent_mode_hint_text` is present. An
empty string is still a configured value and intentionally suppresses
the built-in mode instructions.
### Unset: preserve existing effort-derived behavior
```toml
[features.multi_agent_v2]
enabled = true
# multi_agent_mode_hint_text is omitted
```
- Ultra reasoning uses the built-in proactive delegation instructions.
- Other reasoning efforts use the built-in explicit-request-only
instructions.
### Empty: suppress all mode hint text
```toml
[features.multi_agent_v2]
enabled = true
multi_agent_mode_hint_text = ""
```
This selects effective mode `custom` at every reasoning effort and
injects an empty mode body, suppressing both built-in policies.
### Set: always use the configured text
```toml
[features.multi_agent_v2]
enabled = true
multi_agent_mode_hint_text = "Delegate to subagents when it will materially improve the result."
```
This selects effective mode `custom` at every reasoning effort and
injects the configured text verbatim instead of either built-in policy.
## Verification
- `just test -p codex-core multi_agent_mode`
- Covers a configured hint across High and Ultra reasoning efforts and
verifies the full custom hint is recorded for both turns.
- Covers an empty-string override suppressing both built-in instruction
bodies.
- `just test -p codex-protocol -p codex-app-server-protocol`
- Covers legacy `none` turn-context deserialization as `Custom("")` and
verifies the regenerated schemas.
69 lines
2.4 KiB
Rust
69 lines
2.4 KiB
Rust
use crate::config::MultiAgentV2Config;
|
|
use crate::session::turn_context::TurnContext;
|
|
use codex_protocol::config_types::MultiAgentMode;
|
|
use codex_protocol::openai_models::ReasoningEffort;
|
|
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(turn_context: &TurnContext) -> Option<MultiAgentMode> {
|
|
if turn_context.multi_agent_version != MultiAgentVersion::V2 {
|
|
return None;
|
|
}
|
|
|
|
// A configured hint, including an empty string, defines a custom policy instead of an
|
|
// effort-derived built-in policy.
|
|
let multi_agent_mode = match &turn_context
|
|
.config
|
|
.multi_agent_v2
|
|
.multi_agent_mode_hint_text
|
|
{
|
|
Some(hint_text) => MultiAgentMode::Custom(hint_text.clone()),
|
|
None => match turn_context.effective_reasoning_effort() {
|
|
Some(ReasoningEffort::Ultra) => MultiAgentMode::Proactive,
|
|
_ => MultiAgentMode::ExplicitRequestOnly,
|
|
},
|
|
};
|
|
|
|
match &turn_context.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,
|
|
}
|
|
}
|