mirror of
https://github.com/openai/codex.git
synced 2026-10-28 08:04:55 +00:00
Expose spawn agent types only when roles are configured (#33572)
## Why The `agent_type` argument is only useful when agent roles are configured. Avoid advertising an inapplicable override in the model-visible `spawn_agent` schema. ## What changed - Include `agent_type` in the V1 and V2 spawn tools only when configured roles are available. - Clarify that `agent_type` is an explicit override and document its interaction with context forking. - Remove the unused `agents.support_agent_type` configuration field. ## Testing - Add coverage for hiding `agent_type` without roles and exposing it when a role is configured. GitOrigin-RevId: 32e0f123b15f317e9cdb71774029375bc073d9ad
This commit is contained in:
@@ -15,6 +15,7 @@ pub const MULTI_AGENT_V1_NAMESPACE: &str = "multi_agent_v1";
|
||||
const MULTI_AGENT_V1_NAMESPACE_DESCRIPTION: &str = "Tools for spawning and managing sub-agents.";
|
||||
|
||||
const SPAWN_AGENT_INHERITED_MODEL_GUIDANCE: &str = "Spawned agents inherit your current model by default. Omit `model` to use that preferred default; set `model` only when an explicit override is needed.";
|
||||
const SPAWN_AGENT_TYPE_OVERRIDE_DESCRIPTION_V1: &str = "Agent type override for the new agent. Omit to inherit the parent agent type with a full-history fork; otherwise, `default` is used.";
|
||||
const SPAWN_AGENT_MODEL_OVERRIDE_DESCRIPTION: &str =
|
||||
"Model override for the new agent. Omit unless an explicit override is needed.";
|
||||
const SPAWN_AGENT_SERVICE_TIER_OVERRIDE_DESCRIPTION: &str =
|
||||
@@ -25,6 +26,7 @@ const MAX_REASONING_EFFORT_CHARS_IN_SPAWN_AGENT_DESCRIPTION: usize = 64;
|
||||
pub struct SpawnAgentToolOptions {
|
||||
pub available_models: Vec<ModelPreset>,
|
||||
pub agent_type_description: String,
|
||||
pub expose_agent_type: bool,
|
||||
pub hide_agent_type_model_reasoning: bool,
|
||||
pub expose_spawn_agent_model_overrides: bool,
|
||||
pub multi_agent_version: MultiAgentVersion,
|
||||
@@ -36,6 +38,7 @@ impl Default for SpawnAgentToolOptions {
|
||||
Self {
|
||||
available_models: Vec::new(),
|
||||
agent_type_description: String::new(),
|
||||
expose_agent_type: true,
|
||||
hide_agent_type_model_reasoning: false,
|
||||
expose_spawn_agent_model_overrides: false,
|
||||
multi_agent_version: MultiAgentVersion::Disabled,
|
||||
@@ -70,6 +73,9 @@ pub fn create_spawn_agent_tool_v1(options: SpawnAgentToolOptions) -> ToolSpec {
|
||||
let return_value_description =
|
||||
"Returns the spawned agent id plus the user-facing nickname when available.";
|
||||
let mut properties = spawn_agent_common_properties_v1(&options.agent_type_description);
|
||||
if !options.expose_agent_type {
|
||||
properties.remove("agent_type");
|
||||
}
|
||||
if options.hide_agent_type_model_reasoning {
|
||||
hide_spawn_agent_metadata_options(&mut properties);
|
||||
}
|
||||
@@ -101,8 +107,10 @@ pub fn create_spawn_agent_tool_v2(options: SpawnAgentToolOptions) -> ToolSpec {
|
||||
&& !options.hide_agent_type_model_reasoning)
|
||||
.then_some(SPAWN_AGENT_INHERITED_MODEL_GUIDANCE);
|
||||
let mut properties = spawn_agent_common_properties_v2(&options.agent_type_description);
|
||||
if options.hide_agent_type_model_reasoning {
|
||||
if !options.expose_agent_type {
|
||||
properties.remove("agent_type");
|
||||
}
|
||||
if options.hide_agent_type_model_reasoning {
|
||||
properties.remove("service_tier");
|
||||
}
|
||||
if !options.expose_spawn_agent_model_overrides {
|
||||
@@ -582,7 +590,9 @@ fn spawn_agent_common_properties_v1(agent_type_description: &str) -> BTreeMap<St
|
||||
("items".to_string(), create_collab_input_items_schema()),
|
||||
(
|
||||
"agent_type".to_string(),
|
||||
JsonSchema::string(Some(agent_type_description.to_string())),
|
||||
JsonSchema::string(Some(format!(
|
||||
"{SPAWN_AGENT_TYPE_OVERRIDE_DESCRIPTION_V1}\n{agent_type_description}"
|
||||
))),
|
||||
),
|
||||
(
|
||||
"fork_context".to_string(),
|
||||
@@ -624,7 +634,9 @@ fn spawn_agent_common_properties_v2(agent_type_description: &str) -> BTreeMap<St
|
||||
),
|
||||
(
|
||||
"agent_type".to_string(),
|
||||
JsonSchema::string(Some(agent_type_description.to_string())),
|
||||
JsonSchema::string(Some(format!(
|
||||
"Agent type override for the new agent. Omit unless explicitly asked. Set `fork_turns` to `none` or a positive integer when an explicit override is needed.\n{agent_type_description}"
|
||||
))),
|
||||
),
|
||||
(
|
||||
"fork_turns".to_string(),
|
||||
|
||||
@@ -48,6 +48,7 @@ fn spawn_agent_tool_v2_requires_task_name_and_lists_visible_models() {
|
||||
incompatible,
|
||||
],
|
||||
agent_type_description: "role help".to_string(),
|
||||
expose_agent_type: true,
|
||||
hide_agent_type_model_reasoning: false,
|
||||
expose_spawn_agent_model_overrides: true,
|
||||
multi_agent_version: MultiAgentVersion::V2,
|
||||
@@ -95,10 +96,6 @@ fn spawn_agent_tool_v2_requires_task_name_and_lists_visible_models() {
|
||||
assert!(properties.contains_key("fork_turns"));
|
||||
assert!(!properties.contains_key("items"));
|
||||
assert!(!properties.contains_key("fork_context"));
|
||||
assert_eq!(
|
||||
properties.get("agent_type"),
|
||||
Some(&JsonSchema::string(Some("role help".to_string())))
|
||||
);
|
||||
assert_eq!(
|
||||
properties
|
||||
.get("model")
|
||||
@@ -132,6 +129,7 @@ fn spawn_agent_tool_v1_keeps_legacy_fork_context_field() {
|
||||
let tool = create_spawn_agent_tool_v1(SpawnAgentToolOptions {
|
||||
available_models: Vec::new(),
|
||||
agent_type_description: "role help".to_string(),
|
||||
expose_agent_type: true,
|
||||
hide_agent_type_model_reasoning: false,
|
||||
expose_spawn_agent_model_overrides: true,
|
||||
multi_agent_version: MultiAgentVersion::V1,
|
||||
@@ -158,6 +156,12 @@ fn spawn_agent_tool_v1_keeps_legacy_fork_context_field() {
|
||||
|
||||
assert!(properties.contains_key("fork_context"));
|
||||
assert!(!properties.contains_key("fork_turns"));
|
||||
assert_eq!(
|
||||
properties.get("agent_type"),
|
||||
Some(&JsonSchema::string(Some(format!(
|
||||
"{SPAWN_AGENT_TYPE_OVERRIDE_DESCRIPTION_V1}\nrole help"
|
||||
))))
|
||||
);
|
||||
assert_eq!(
|
||||
properties
|
||||
.get("message")
|
||||
@@ -190,6 +194,7 @@ fn spawn_agent_tool_caps_visible_model_summaries() {
|
||||
model_preset("sixth", /*show_in_picker*/ true),
|
||||
],
|
||||
agent_type_description: "role help".to_string(),
|
||||
expose_agent_type: true,
|
||||
hide_agent_type_model_reasoning: false,
|
||||
expose_spawn_agent_model_overrides: true,
|
||||
multi_agent_version: MultiAgentVersion::V2,
|
||||
@@ -235,6 +240,7 @@ fn spawn_agent_tool_keeps_model_controls_when_spawn_metadata_is_hidden() {
|
||||
let tool = create_spawn_agent_tool_v2(SpawnAgentToolOptions {
|
||||
available_models: vec![model_preset("visible", /*show_in_picker*/ true)],
|
||||
agent_type_description: "role help".to_string(),
|
||||
expose_agent_type: false,
|
||||
hide_agent_type_model_reasoning: true,
|
||||
expose_spawn_agent_model_overrides: true,
|
||||
multi_agent_version: MultiAgentVersion::V2,
|
||||
@@ -267,6 +273,7 @@ fn spawn_agent_tool_hides_model_controls_without_override_exposure() {
|
||||
let tool = create_spawn_agent_tool_v2(SpawnAgentToolOptions {
|
||||
available_models: vec![model_preset("visible", /*show_in_picker*/ true)],
|
||||
agent_type_description: "role help".to_string(),
|
||||
expose_agent_type: false,
|
||||
hide_agent_type_model_reasoning: true,
|
||||
expose_spawn_agent_model_overrides: false,
|
||||
multi_agent_version: MultiAgentVersion::V2,
|
||||
|
||||
@@ -798,16 +798,15 @@ fn add_collaboration_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mu
|
||||
.flatten();
|
||||
let agent_type_description =
|
||||
agent_type_description(turn_context, context.default_agent_type_description);
|
||||
// TODO(jif): Wire `agents.support_agent_type` into the V2 spawn tool surface.
|
||||
let hide_spawn_agent_metadata =
|
||||
turn_context.config.multi_agent_v2.hide_spawn_agent_metadata;
|
||||
planned_tools.add_arc(override_tool_exposure(
|
||||
multi_agent_v2_handler(
|
||||
SpawnAgentHandlerV2::new(SpawnAgentToolOptions {
|
||||
available_models: turn_context.available_models.clone(),
|
||||
agent_type_description,
|
||||
hide_agent_type_model_reasoning: turn_context
|
||||
.config
|
||||
.multi_agent_v2
|
||||
.hide_spawn_agent_metadata,
|
||||
expose_agent_type: !turn_context.config.agent_roles.is_empty(),
|
||||
hide_agent_type_model_reasoning: hide_spawn_agent_metadata,
|
||||
expose_spawn_agent_model_overrides: turn_context
|
||||
.config
|
||||
.multi_agent_v2
|
||||
@@ -854,6 +853,7 @@ fn add_collaboration_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mu
|
||||
SpawnAgentHandler::new(SpawnAgentToolOptions {
|
||||
available_models: turn_context.available_models.clone(),
|
||||
agent_type_description,
|
||||
expose_agent_type: !turn_context.config.agent_roles.is_empty(),
|
||||
hide_agent_type_model_reasoning: false,
|
||||
expose_spawn_agent_model_overrides: true,
|
||||
multi_agent_version: turn_context.multi_agent_version,
|
||||
|
||||
@@ -1207,12 +1207,13 @@ async fn multi_agent_feature_selects_one_agent_tool_family() {
|
||||
.properties
|
||||
.as_ref()
|
||||
.expect("spawn_agent should use object params");
|
||||
for property in ["agent_type", "model", "reasoning_effort", "service_tier"] {
|
||||
for property in ["model", "reasoning_effort", "service_tier"] {
|
||||
assert!(
|
||||
properties.contains_key(property),
|
||||
"expected v1 spawn_agent to expose `{property}`"
|
||||
);
|
||||
}
|
||||
assert!(!properties.contains_key("agent_type"));
|
||||
|
||||
let v2 = probe(|turn| {
|
||||
set_feature(turn, Feature::MultiAgentV2, /*enabled*/ true);
|
||||
|
||||
Reference in New Issue
Block a user