mirror of
https://github.com/openai/codex.git
synced 2026-05-02 04:11:39 +03:00
feat: change multi-agent to use path-like system instead of uuids (#15313)
This PR add an URI-based system to reference agents within a tree. This comes from a sync between research and engineering. The main agent (the one manually spawned by a user) is always called `/root`. Any sub-agent spawned by it will be `/root/agent_1` for example where `agent_1` is chosen by the model. Any agent can contact any agents using the path. Paths can be used either in absolute or relative to the calling agents Resume is not supported for now on this new path
This commit is contained in:
@@ -129,20 +129,29 @@ fn agent_status_output_schema() -> JsonValue {
|
||||
})
|
||||
}
|
||||
|
||||
fn spawn_agent_output_schema() -> JsonValue {
|
||||
fn spawn_agent_output_schema(multi_agent_v2: bool) -> JsonValue {
|
||||
let task_name_description = if multi_agent_v2 {
|
||||
"Canonical task name for the spawned agent."
|
||||
} else {
|
||||
"Canonical task name for the spawned agent when one was assigned."
|
||||
};
|
||||
json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent_id": {
|
||||
"type": "string",
|
||||
"description": "Thread identifier for the spawned agent."
|
||||
"type": ["string", "null"],
|
||||
"description": "Thread identifier for the spawned agent when no task name was assigned."
|
||||
},
|
||||
"task_name": {
|
||||
"type": ["string", "null"],
|
||||
"description": task_name_description
|
||||
},
|
||||
"nickname": {
|
||||
"type": ["string", "null"],
|
||||
"description": "User-facing nickname for the spawned agent when available."
|
||||
}
|
||||
},
|
||||
"required": ["agent_id", "nickname"],
|
||||
"required": ["agent_id", "task_name", "nickname"],
|
||||
"additionalProperties": false
|
||||
})
|
||||
}
|
||||
@@ -178,7 +187,7 @@ fn wait_output_schema() -> JsonValue {
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "object",
|
||||
"description": "Final statuses keyed by agent id for agents that finished before the timeout.",
|
||||
"description": "Final statuses keyed by canonical task name when available, otherwise by agent id.",
|
||||
"additionalProperties": agent_status_output_schema()
|
||||
},
|
||||
"timed_out": {
|
||||
@@ -276,6 +285,7 @@ pub(crate) struct ToolsConfig {
|
||||
pub js_repl_tools_only: bool,
|
||||
pub can_request_original_image_detail: bool,
|
||||
pub collab_tools: bool,
|
||||
pub multi_agent_v2: bool,
|
||||
pub artifact_tools: bool,
|
||||
pub request_user_input: bool,
|
||||
pub default_mode_request_user_input: bool,
|
||||
@@ -325,6 +335,7 @@ impl ToolsConfig {
|
||||
let include_js_repl_tools_only =
|
||||
include_js_repl && features.enabled(Feature::JsReplToolsOnly);
|
||||
let include_collab_tools = features.enabled(Feature::Collab);
|
||||
let include_multi_agent_v2 = features.enabled(Feature::MultiAgentV2);
|
||||
let include_agent_jobs = features.enabled(Feature::SpawnCsv);
|
||||
let include_request_user_input = !matches!(session_source, SessionSource::SubAgent(_));
|
||||
let include_default_mode_request_user_input =
|
||||
@@ -408,6 +419,7 @@ impl ToolsConfig {
|
||||
js_repl_tools_only: include_js_repl_tools_only,
|
||||
can_request_original_image_detail: include_original_image_detail,
|
||||
collab_tools: include_collab_tools,
|
||||
multi_agent_v2: include_multi_agent_v2,
|
||||
artifact_tools: include_artifact_tools,
|
||||
request_user_input: include_request_user_input,
|
||||
default_mode_request_user_input: include_default_mode_request_user_input,
|
||||
@@ -1076,7 +1088,8 @@ fn create_collab_input_items_schema() -> JsonSchema {
|
||||
|
||||
fn create_spawn_agent_tool(config: &ToolsConfig) -> ToolSpec {
|
||||
let available_models_description = spawn_agent_models_description(&config.available_models);
|
||||
let properties = BTreeMap::from([
|
||||
let return_value_description = "Returns the canonical task name when the spawned agent was named, otherwise the agent id, plus the user-facing nickname when available.";
|
||||
let mut properties = BTreeMap::from([
|
||||
(
|
||||
"message".to_string(),
|
||||
JsonSchema::String {
|
||||
@@ -1123,6 +1136,15 @@ fn create_spawn_agent_tool(config: &ToolsConfig) -> ToolSpec {
|
||||
},
|
||||
),
|
||||
]);
|
||||
properties.insert(
|
||||
"task_name".to_string(),
|
||||
JsonSchema::String {
|
||||
description: Some(
|
||||
"Optional task name for the new agent. Use lowercase letters, digits, and underscores."
|
||||
.to_string(),
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
ToolSpec::Function(ResponsesApiTool {
|
||||
name: "spawn_agent".to_string(),
|
||||
@@ -1131,7 +1153,7 @@ fn create_spawn_agent_tool(config: &ToolsConfig) -> ToolSpec {
|
||||
Only use `spawn_agent` if and only if the user explicitly asks for sub-agents, delegation, or parallel agent work.
|
||||
Requests for depth, thoroughness, research, investigation, or detailed codebase analysis do not count as permission to spawn.
|
||||
Agent-role guidance below only helps choose which agent to use after spawning is already authorized; it never authorizes spawning by itself.
|
||||
Spawn a sub-agent for a well-scoped task. Returns the agent id (and user-facing nickname when available) to use to communicate with this agent. This spawn_agent tool provides you access to smaller but more efficient sub-agents. A mini model can solve many tasks faster than the main model. You should follow the rules and guidelines below to use this tool.
|
||||
Spawn a sub-agent for a well-scoped task. {return_value_description} This spawn_agent tool provides you access to smaller but more efficient sub-agents. A mini model can solve many tasks faster than the main model. You should follow the rules and guidelines below to use this tool.
|
||||
|
||||
{available_models_description}
|
||||
### When to delegate vs. do the subtask yourself
|
||||
@@ -1170,7 +1192,7 @@ fn create_spawn_agent_tool(config: &ToolsConfig) -> ToolSpec {
|
||||
required: None,
|
||||
additional_properties: Some(false.into()),
|
||||
},
|
||||
output_schema: Some(spawn_agent_output_schema()),
|
||||
output_schema: Some(spawn_agent_output_schema(config.multi_agent_v2)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1335,9 +1357,11 @@ fn create_report_agent_job_result_tool() -> ToolSpec {
|
||||
fn create_send_input_tool() -> ToolSpec {
|
||||
let properties = BTreeMap::from([
|
||||
(
|
||||
"id".to_string(),
|
||||
"target".to_string(),
|
||||
JsonSchema::String {
|
||||
description: Some("Agent id to message (from spawn_agent).".to_string()),
|
||||
description: Some(
|
||||
"Agent id or canonical task name to message (from spawn_agent).".to_string(),
|
||||
),
|
||||
},
|
||||
),
|
||||
(
|
||||
@@ -1369,7 +1393,7 @@ fn create_send_input_tool() -> ToolSpec {
|
||||
defer_loading: None,
|
||||
parameters: JsonSchema::Object {
|
||||
properties,
|
||||
required: Some(vec!["id".to_string()]),
|
||||
required: Some(vec!["target".to_string()]),
|
||||
additional_properties: Some(false.into()),
|
||||
},
|
||||
output_schema: Some(send_input_output_schema()),
|
||||
@@ -1404,11 +1428,11 @@ fn create_resume_agent_tool() -> ToolSpec {
|
||||
fn create_wait_agent_tool() -> ToolSpec {
|
||||
let mut properties = BTreeMap::new();
|
||||
properties.insert(
|
||||
"ids".to_string(),
|
||||
"targets".to_string(),
|
||||
JsonSchema::Array {
|
||||
items: Box::new(JsonSchema::String { description: None }),
|
||||
description: Some(
|
||||
"Agent ids to wait on. Pass multiple ids to wait for whichever finishes first."
|
||||
"Agent ids or canonical task names to wait on. Pass multiple targets to wait for whichever finishes first."
|
||||
.to_string(),
|
||||
),
|
||||
},
|
||||
@@ -1430,7 +1454,7 @@ fn create_wait_agent_tool() -> ToolSpec {
|
||||
defer_loading: None,
|
||||
parameters: JsonSchema::Object {
|
||||
properties,
|
||||
required: Some(vec!["ids".to_string()]),
|
||||
required: Some(vec!["targets".to_string()]),
|
||||
additional_properties: Some(false.into()),
|
||||
},
|
||||
output_schema: Some(wait_output_schema()),
|
||||
@@ -1556,9 +1580,11 @@ fn create_request_permissions_tool() -> ToolSpec {
|
||||
fn create_close_agent_tool() -> ToolSpec {
|
||||
let mut properties = BTreeMap::new();
|
||||
properties.insert(
|
||||
"id".to_string(),
|
||||
"target".to_string(),
|
||||
JsonSchema::String {
|
||||
description: Some("Agent id to close (from spawn_agent).".to_string()),
|
||||
description: Some(
|
||||
"Agent id or canonical task name to close (from spawn_agent).".to_string(),
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1569,7 +1595,7 @@ fn create_close_agent_tool() -> ToolSpec {
|
||||
defer_loading: None,
|
||||
parameters: JsonSchema::Object {
|
||||
properties,
|
||||
required: Some(vec!["id".to_string()]),
|
||||
required: Some(vec!["target".to_string()]),
|
||||
additional_properties: Some(false.into()),
|
||||
},
|
||||
output_schema: Some(close_agent_output_schema()),
|
||||
@@ -2966,12 +2992,15 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_resume_agent_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
if !config.multi_agent_v2 {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_resume_agent_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("resume_agent", Arc::new(ResumeAgentHandler));
|
||||
}
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_wait_agent_tool(),
|
||||
@@ -2986,7 +3015,6 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
);
|
||||
builder.register_handler("spawn_agent", Arc::new(SpawnAgentHandler));
|
||||
builder.register_handler("send_input", Arc::new(SendInputHandler));
|
||||
builder.register_handler("resume_agent", Arc::new(ResumeAgentHandler));
|
||||
builder.register_handler("wait_agent", Arc::new(WaitAgentHandler));
|
||||
builder.register_handler("close_agent", Arc::new(CloseAgentHandler));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user