Gate multi-agent v2 tools independently of collab (#20246)

## Why

`multi_agents_v2` is meant to be independently gated from the older
`collab` feature. The tool registry still treated the
collaboration-style agent tools as `collab`-only, so enabling
`multi_agents_v2` without `collab` omitted the v2 agent tools. Review
and guardian sub-sessions also need to keep agent spawning disabled even
when the outer session has `multi_agents_v2` enabled.

## What changed

- Include the collab-backed agent tools when either `multi_agents_v2` or
`collab` is enabled.
- Explicitly disable `multi_agents_v2` for review and guardian review
sub-sessions, matching the existing `spawn_csv` and `collab`
restrictions.
- Add a registry test that enables `multi_agents_v2`, disables `collab`,
and verifies the v2 agent tools are present while legacy `send_input`
and `resume_agent` remain hidden.

## Testing

- Added
`test_build_specs_multi_agent_v2_does_not_require_collab_feature`.
This commit is contained in:
jif-oai
2026-04-30 10:23:31 +02:00
committed by GitHub
Unverified
parent a73403a890
commit c37f7434ba
4 changed files with 43 additions and 1 deletions
@@ -931,6 +931,7 @@ pub(crate) fn build_guardian_review_session_config(
for feature in [
Feature::SpawnCsv,
Feature::Collab,
Feature::MultiAgentV2,
Feature::CodexHooks,
Feature::Apps,
Feature::Plugins,
+1
View File
@@ -110,6 +110,7 @@ async fn start_review_conversation(
}
let _ = sub_agent_config.features.disable(Feature::SpawnCsv);
let _ = sub_agent_config.features.disable(Feature::Collab);
let _ = sub_agent_config.features.disable(Feature::MultiAgentV2);
// Set explicit review rubric for the sub-agent
sub_agent_config.base_instructions = Some(crate::REVIEW_PROMPT.to_string());
+1 -1
View File
@@ -143,9 +143,9 @@ impl ToolsConfig {
let include_apply_patch_tool = features.enabled(Feature::ApplyPatchFreeform);
let include_code_mode = features.enabled(Feature::CodeMode);
let include_code_mode_only = include_code_mode && features.enabled(Feature::CodeModeOnly);
let include_collab_tools = features.enabled(Feature::Collab);
let include_goal_tools = features.enabled(Feature::Goals);
let include_multi_agent_v2 = features.enabled(Feature::MultiAgentV2);
let include_collab_tools = include_multi_agent_v2 || features.enabled(Feature::Collab);
let include_agent_jobs = features.enabled(Feature::SpawnCsv);
let include_search_tool =
model_info.supports_search_tool && features.enabled(Feature::ToolSearch);
@@ -385,6 +385,46 @@ fn test_build_specs_multi_agent_v2_uses_task_names_and_hides_resume() {
assert_lacks_tool_name(&tools, "resume_agent");
}
#[test]
fn test_build_specs_multi_agent_v2_does_not_require_collab_feature() {
let model_info = model_info();
let mut features = Features::with_defaults();
features.disable(Feature::Collab);
features.enable(Feature::MultiAgentV2);
assert!(!features.enabled(Feature::Collab));
let available_models = Vec::new();
let tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
available_models: &available_models,
features: &features,
image_generation_tool_auth_allowed: true,
web_search_mode: Some(WebSearchMode::Cached),
session_source: SessionSource::Cli,
permission_profile: &PermissionProfile::Disabled,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
});
let (tools, _) = build_specs(
&tools_config,
/*mcp_tools*/ None,
/*deferred_mcp_tools*/ None,
&[],
);
assert_contains_tool_names(
&tools,
&[
"spawn_agent",
"send_message",
"followup_task",
"wait_agent",
"close_agent",
"list_agents",
],
);
assert_lacks_tool_name(&tools, "send_input");
assert_lacks_tool_name(&tools, "resume_agent");
}
#[test]
fn test_build_specs_enable_fanout_enables_agent_jobs_and_collab_tools() {
let model_info = model_info();