Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions codex-rs/core/src/tools/handlers/multi_agents_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ pub fn create_send_message_tool() -> ToolSpec {
})
}

pub fn create_followup_task_tool() -> ToolSpec {
pub fn create_assign_task_tool() -> ToolSpec {
let properties = BTreeMap::from([
(
"target".to_string(),
Expand All @@ -196,7 +196,7 @@ pub fn create_followup_task_tool() -> ToolSpec {
]);

ToolSpec::Function(ResponsesApiTool {
name: "followup_task".to_string(),
name: "assign_task".to_string(),
description: "Send a message to an existing non-root target agent and trigger a turn in that target. If the target is currently mid-turn, the message is queued and will be used to start the target's next turn, after the current turn completes."
.to_string(),
strict: false,
Expand Down
10 changes: 6 additions & 4 deletions codex-rs/core/src/tools/handlers/multi_agents_spec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,23 +247,25 @@ fn send_message_tool_requires_message_and_has_no_output_schema() {
}

#[test]
fn followup_task_tool_requires_message_and_has_no_output_schema() {
fn assign_task_tool_requires_message_and_has_no_output_schema() {
let ToolSpec::Function(ResponsesApiTool {
name,
parameters,
output_schema,
..
}) = create_followup_task_tool()
}) = create_assign_task_tool()
else {
panic!("followup_task should be a function tool");
panic!("assign_task should be a function tool");
};
assert_eq!(name, "assign_task");
assert_eq!(
parameters.schema_type,
Some(JsonSchemaType::Single(JsonSchemaPrimitiveType::Object))
);
let properties = parameters
.properties
.as_ref()
.expect("followup_task should use object params");
.expect("assign_task should use object params");
assert!(properties.contains_key("target"));
assert!(properties.contains_key("message"));
assert!(!properties.contains_key("items"));
Expand Down
24 changes: 12 additions & 12 deletions codex-rs/core/src/tools/handlers/multi_agents_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::session::tests::make_session_and_context;
use crate::session_prefix::format_subagent_notification_message;
use crate::thread_manager::thread_store_from_config;
use crate::tools::context::ToolOutput;
use crate::tools::handlers::multi_agents_v2::AssignTaskHandler as AssignTaskHandlerV2;
use crate::tools::handlers::multi_agents_v2::CloseAgentHandler as CloseAgentHandlerV2;
use crate::tools::handlers::multi_agents_v2::FollowupTaskHandler as FollowupTaskHandlerV2;
use crate::tools::handlers::multi_agents_v2::ListAgentsHandler as ListAgentsHandlerV2;
use crate::tools::handlers::multi_agents_v2::SendMessageHandler as SendMessageHandlerV2;
use crate::tools::handlers::multi_agents_v2::SpawnAgentHandler as SpawnAgentHandlerV2;
Expand Down Expand Up @@ -1413,7 +1413,7 @@ async fn multi_agent_v2_send_message_accepts_root_target_from_child() {
}

#[tokio::test]
async fn multi_agent_v2_followup_task_rejects_root_target_from_child() {
async fn multi_agent_v2_assign_task_rejects_root_target_from_child() {
let (mut session, mut turn) = make_session_and_context().await;
let manager = thread_manager();
let root = manager
Expand Down Expand Up @@ -1461,19 +1461,19 @@ async fn multi_agent_v2_followup_task_rejects_root_target_from_child() {
agent_role: None,
});

let Err(err) = FollowupTaskHandlerV2
let Err(err) = AssignTaskHandlerV2
.handle(invocation(
Arc::new(session),
Arc::new(turn),
"followup_task",
"assign_task",
function_payload(json!({
"target": "/root",
"message": "run this",
})),
))
.await
else {
panic!("followup_task should reject the root target");
panic!("assign_task should reject the root target");
};

assert_eq!(
Expand Down Expand Up @@ -1868,7 +1868,7 @@ async fn multi_agent_v2_send_message_rejects_interrupt_parameter() {
}

#[tokio::test]
async fn multi_agent_v2_followup_task_completion_notifies_parent_on_every_turn() {
async fn multi_agent_v2_assign_task_completion_notifies_parent_on_every_turn() {
let (mut session, mut turn) = make_session_and_context().await;
let manager = thread_manager();
let root = manager
Expand Down Expand Up @@ -1923,18 +1923,18 @@ async fn multi_agent_v2_followup_task_completion_notifies_parent_on_every_turn()
)
.await;

FollowupTaskHandlerV2
AssignTaskHandlerV2
.handle(invocation(
session,
turn,
"followup_task",
"assign_task",
function_payload(json!({
"target": agent_id.to_string(),
"message": "continue",
})),
))
.await
.expect("followup_task should succeed");
.expect("assign_task should succeed");

let second_turn = thread.codex.session.new_default_turn().await;
thread
Expand Down Expand Up @@ -2003,7 +2003,7 @@ async fn multi_agent_v2_followup_task_completion_notifies_parent_on_every_turn()
}

#[tokio::test]
async fn multi_agent_v2_followup_task_rejects_legacy_items_field() {
async fn multi_agent_v2_assign_task_rejects_legacy_items_field() {
let (mut session, mut turn) = make_session_and_context().await;
let manager = thread_manager();
let root = manager
Expand Down Expand Up @@ -2039,14 +2039,14 @@ async fn multi_agent_v2_followup_task_rejects_legacy_items_field() {
let invocation = invocation(
session,
turn,
"followup_task",
"assign_task",
function_payload(json!({
"target": agent_id.to_string(),
"items": [{"type": "text", "text": "continue"}],
})),
);

let Err(err) = FollowupTaskHandlerV2.handle(invocation).await else {
let Err(err) = AssignTaskHandlerV2.handle(invocation).await else {
panic!("legacy items field should be rejected in v2");
};
let FunctionCallError::RespondToModel(message) = err else {
Expand Down
4 changes: 2 additions & 2 deletions codex-rs/core/src/tools/handlers/multi_agents_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ use serde::Deserialize;
use serde::Serialize;
use serde_json::Value as JsonValue;

pub(crate) use assign_task::Handler as AssignTaskHandler;
pub(crate) use close_agent::Handler as CloseAgentHandler;
pub(crate) use followup_task::Handler as FollowupTaskHandler;
pub(crate) use list_agents::Handler as ListAgentsHandler;
pub(crate) use send_message::Handler as SendMessageHandler;
pub(crate) use spawn::Handler as SpawnAgentHandler;
pub(crate) use wait::Handler as WaitAgentHandler;

mod assign_task;
mod close_agent;
mod followup_task;
mod list_agents;
mod message_tool;
mod send_message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
use super::message_tool::FollowupTaskArgs;
use super::message_tool::AssignTaskArgs;
use super::message_tool::MessageDeliveryMode;
use super::message_tool::handle_message_string_tool;
use super::*;
use crate::tools::handlers::multi_agents_spec::create_followup_task_tool;
use crate::tools::handlers::multi_agents_spec::create_assign_task_tool;
use codex_tools::ToolSpec;

pub(crate) struct Handler;

#[async_trait::async_trait]
impl ToolExecutor<ToolInvocation> for Handler {
fn tool_name(&self) -> ToolName {
ToolName::plain("followup_task")
ToolName::plain("assign_task")
Comment thread
jif-oai marked this conversation as resolved.
}

fn spec(&self) -> ToolSpec {
create_followup_task_tool()
create_assign_task_tool()
}

async fn handle(
&self,
invocation: ToolInvocation,
) -> Result<Box<dyn crate::tools::context::ToolOutput>, FunctionCallError> {
let arguments = function_arguments(invocation.payload.clone())?;
let args: FollowupTaskArgs = parse_arguments(&arguments)?;
let args: AssignTaskArgs = parse_arguments(&arguments)?;
handle_message_string_tool(
invocation,
MessageDeliveryMode::TriggerTurn,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Shared argument parsing and dispatch for the v2 text-only agent messaging tools.
//!
//! `send_message` and `followup_task` share the same submission path and differ only in whether the
//! `send_message` and `assign_task` share the same submission path and differ only in whether the
//! resulting `InterAgentCommunication` should wake the target immediately.

use super::*;
Expand Down Expand Up @@ -40,8 +40,8 @@ pub(crate) struct SendMessageArgs {

#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
/// Input for the MultiAgentV2 `followup_task` tool.
pub(crate) struct FollowupTaskArgs {
/// Input for the MultiAgentV2 `assign_task` tool.
pub(crate) struct AssignTaskArgs {
pub(crate) target: String,
pub(crate) message: String,
}
Expand All @@ -55,7 +55,7 @@ fn message_content(message: String) -> Result<String, FunctionCallError> {
Ok(message)
}

/// Handles the shared MultiAgentV2 plain-text message flow for both `send_message` and `followup_task`.
/// Handles the shared MultiAgentV2 plain-text message flow for both `send_message` and `assign_task`.
pub(crate) async fn handle_message_string_tool(
invocation: ToolInvocation,
mode: MessageDeliveryMode,
Expand Down
4 changes: 2 additions & 2 deletions codex-rs/core/src/tools/spec_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use crate::tools::handlers::multi_agents_common::MAX_WAIT_TIMEOUT_MS;
use crate::tools::handlers::multi_agents_common::MIN_WAIT_TIMEOUT_MS;
use crate::tools::handlers::multi_agents_spec::SpawnAgentToolOptions;
use crate::tools::handlers::multi_agents_spec::WaitAgentTimeoutOptions;
use crate::tools::handlers::multi_agents_v2::AssignTaskHandler as AssignTaskHandlerV2;
use crate::tools::handlers::multi_agents_v2::CloseAgentHandler as CloseAgentHandlerV2;
use crate::tools::handlers::multi_agents_v2::FollowupTaskHandler as FollowupTaskHandlerV2;
use crate::tools::handlers::multi_agents_v2::ListAgentsHandler as ListAgentsHandlerV2;
use crate::tools::handlers::multi_agents_v2::SendMessageHandler as SendMessageHandlerV2;
use crate::tools::handlers::multi_agents_v2::SpawnAgentHandler as SpawnAgentHandlerV2;
Expand Down Expand Up @@ -686,7 +686,7 @@ fn add_collaboration_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mu
exposure,
));
planned_tools.add_arc(override_tool_exposure(
multi_agent_v2_handler(FollowupTaskHandlerV2, tool_namespace),
multi_agent_v2_handler(AssignTaskHandlerV2, tool_namespace),
exposure,
));
planned_tools.add_arc(override_tool_exposure(
Expand Down
8 changes: 4 additions & 4 deletions codex-rs/core/src/tools/spec_plan_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ async fn multi_agent_feature_selects_one_agent_tool_family() {
"wait_agent",
"close_agent",
"send_message",
"followup_task",
"assign_task",
"list_agents",
]);
assert_eq!(
Expand All @@ -790,7 +790,7 @@ async fn multi_agent_feature_selects_one_agent_tool_family() {
v2.assert_visible_contains(&[
"spawn_agent",
"send_message",
"followup_task",
"assign_task",
"wait_agent",
"close_agent",
"list_agents",
Expand Down Expand Up @@ -895,7 +895,7 @@ async fn multi_agent_v2_can_use_configured_tool_namespace() {
for tool_name in [
"spawn_agent",
"send_message",
"followup_task",
"assign_task",
"wait_agent",
"close_agent",
"list_agents",
Expand Down Expand Up @@ -969,7 +969,7 @@ async fn code_mode_only_can_expose_namespaced_multi_agent_v2_as_normal_tools() {
for tool_name in [
"spawn_agent",
"send_message",
"followup_task",
"assign_task",
"wait_agent",
"close_agent",
"list_agents",
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/rollout-trace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ the edges between them.

```mermaid
flowchart LR
RootTool["root ToolCall\nspawn_agent / followup_task / send_message"]
RootTool["root ToolCall\nspawn_agent / assign_task / send_message"]
ChildInput["child ConversationItem\ninjected task/message"]
ChildThread["child AgentThread"]
ChildResult["child assistant ConversationItem\nresult message"]
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/rollout-trace/src/tool_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ fn dispatched_tool_kind(tool_name: &str, _payload: &ToolDispatchPayload) -> Tool
"image_generation" | "image_query" => ToolCallKind::ImageGeneration,
"spawn_agent" => ToolCallKind::SpawnAgent,
"send_message" => ToolCallKind::SendMessage,
"followup_task" => ToolCallKind::AssignAgentTask,
"assign_task" | "followup_task" => ToolCallKind::AssignAgentTask,
"wait_agent" => ToolCallKind::WaitAgent,
"close_agent" => ToolCallKind::CloseAgent,
other => ToolCallKind::Other {
Expand Down
Loading