Codex Handbook
core/src/tools/handlers/multi_agents/close_agent.rs 146 lines
use super::*;use crate::tools::handlers::multi_agents_spec::create_close_agent_tool_v1;use crate::turn_timing::now_unix_timestamp_ms;use codex_protocol::error::CodexErr;use codex_tools::ToolSpec;pub(crate) struct Handler;impl ToolExecutor<ToolInvocation> for Handler {    fn tool_name(&self) -> ToolName {        ToolName::namespaced(MULTI_AGENT_V1_NAMESPACE, "close_agent")    }    fn spec(&self) -> ToolSpec {        create_close_agent_tool_v1()    }    fn search_info(&self) -> Option<ToolSearchInfo> {        multi_agent_tool_search_info(            "close_agent close shutdown stop agent subagent thread status target",            self.spec(),        )    }    fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {        Box::pin(async move { handle_close_agent(invocation).await.map(boxed_tool_output) })    }}async fn handle_close_agent(    invocation: ToolInvocation,) -> Result<CloseAgentResult, FunctionCallError> {    let ToolInvocation {        session,        turn,        payload,        call_id,        ..    } = invocation;    let arguments = function_arguments(payload)?;    let args: CloseAgentArgs = parse_arguments(&arguments)?;    let agent_id = parse_agent_id_target(&args.target)?;    let receiver_agent = session.services.agent_control.get_agent_metadata(agent_id);    let known_agent = receiver_agent.is_some();    let receiver_agent = receiver_agent.unwrap_or_default();    session        .send_event(            &turn,            CollabCloseBeginEvent {                call_id: call_id.clone(),                started_at_ms: now_unix_timestamp_ms(),                sender_thread_id: session.thread_id,                receiver_thread_id: agent_id,            }            .into(),        )        .await;    let status = match session        .services        .agent_control        .subscribe_status(agent_id)        .await    {        Ok(mut status_rx) => status_rx.borrow_and_update().clone(),        Err(CodexErr::ThreadNotFound(_)) if known_agent => {            session.services.agent_control.get_status(agent_id).await        }        Err(err) => {            let status = session.services.agent_control.get_status(agent_id).await;            session                .send_event(                    &turn,                    CollabCloseEndEvent {                        call_id: call_id.clone(),                        completed_at_ms: now_unix_timestamp_ms(),                        sender_thread_id: session.thread_id(),                        receiver_thread_id: agent_id,                        receiver_agent_nickname: receiver_agent.agent_nickname.clone(),                        receiver_agent_role: receiver_agent.agent_role.clone(),                        status,                    }                    .into(),                )                .await;            return Err(collab_agent_error(agent_id, err));        }    };    let result = Box::pin(session.services.agent_control.close_agent(agent_id))        .await        .map_err(|err| collab_agent_error(agent_id, err))        .map(|_| ());    session        .send_event(            &turn,            CollabCloseEndEvent {                call_id,                completed_at_ms: now_unix_timestamp_ms(),                sender_thread_id: session.thread_id,                receiver_thread_id: agent_id,                receiver_agent_nickname: receiver_agent.agent_nickname,                receiver_agent_role: receiver_agent.agent_role,                status: status.clone(),            }            .into(),        )        .await;    result?;    Ok(CloseAgentResult {        previous_status: status,    })}impl CoreToolRuntime for Handler {    fn matches_kind(&self, payload: &ToolPayload) -> bool {        matches!(payload, ToolPayload::Function { .. })    }}#[derive(Debug, Deserialize, Serialize)]pub(crate) struct CloseAgentResult {    pub(crate) previous_status: AgentStatus,}impl ToolOutput for CloseAgentResult {    fn log_preview(&self) -> String {        tool_output_json_text(self, "close_agent")    }    fn success_for_logging(&self) -> bool {        true    }    fn to_response_item(&self, call_id: &str, payload: &ToolPayload) -> ResponseInputItem {        tool_output_response_item(call_id, payload, self, Some(true), "close_agent")    }    fn code_mode_result(&self, _payload: &ToolPayload) -> JsonValue {        tool_output_code_mode_result(self, "close_agent")    }}#[derive(Debug, Deserialize)]struct CloseAgentArgs {    target: String,}