Codex Handbook
core/src/tools/handlers/multi_agents/send_input.rs 150 lines
use super::*;use crate::agent::control::render_input_preview;use crate::tools::handlers::multi_agents_spec::create_send_input_tool_v1;use crate::turn_timing::now_unix_timestamp_ms;use codex_tools::ToolSpec;pub(crate) struct Handler;impl ToolExecutor<ToolInvocation> for Handler {    fn tool_name(&self) -> ToolName {        ToolName::namespaced(MULTI_AGENT_V1_NAMESPACE, "send_input")    }    fn spec(&self) -> ToolSpec {        create_send_input_tool_v1()    }    fn search_info(&self) -> Option<ToolSearchInfo> {        multi_agent_tool_search_info(            "send_input send message existing agent subagent follow up interrupt redirect queue target",            self.spec(),        )    }    fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {        Box::pin(self.handle_call(invocation))    }}impl Handler {    async fn handle_call(        &self,        invocation: ToolInvocation,    ) -> Result<Box<dyn crate::tools::context::ToolOutput>, FunctionCallError> {        let ToolInvocation {            session,            turn,            payload,            call_id,            ..        } = invocation;        let arguments = function_arguments(payload)?;        let args: SendInputArgs = parse_arguments(&arguments)?;        let receiver_thread_id = parse_agent_id_target(&args.target)?;        let input_items = parse_collab_input(args.message, args.items)?;        let prompt = render_input_preview(&input_items);        let receiver_agent = session            .services            .agent_control            .get_agent_metadata(receiver_thread_id);        if receiver_agent.is_some() {            let resume_config = build_agent_resume_config(turn.as_ref())?;            session                .services                .agent_control                .ensure_v2_agent_loaded(resume_config, receiver_thread_id)                .await                .map_err(|err| collab_agent_error(receiver_thread_id, err))?;        }        let receiver_agent = receiver_agent.unwrap_or_default();        if args.interrupt {            session                .services                .agent_control                .interrupt_agent(receiver_thread_id)                .await                .map_err(|err| collab_agent_error(receiver_thread_id, err))?;        }        session            .send_event(                &turn,                CollabAgentInteractionBeginEvent {                    call_id: call_id.clone(),                    started_at_ms: now_unix_timestamp_ms(),                    sender_thread_id: session.thread_id,                    receiver_thread_id,                    prompt: prompt.clone(),                }                .into(),            )            .await;        let agent_control = session.services.agent_control.clone();        let result = agent_control            .send_input(receiver_thread_id, input_items)            .await            .map_err(|err| collab_agent_error(receiver_thread_id, err));        let status = session            .services            .agent_control            .get_status(receiver_thread_id)            .await;        session            .send_event(                &turn,                CollabAgentInteractionEndEvent {                    call_id,                    completed_at_ms: now_unix_timestamp_ms(),                    sender_thread_id: session.thread_id,                    receiver_thread_id,                    receiver_agent_nickname: receiver_agent.agent_nickname,                    receiver_agent_role: receiver_agent.agent_role,                    prompt,                    status,                }                .into(),            )            .await;        let submission_id = result?;        Ok(boxed_tool_output(SendInputResult { submission_id }))    }}impl CoreToolRuntime for Handler {    fn matches_kind(&self, payload: &ToolPayload) -> bool {        matches!(payload, ToolPayload::Function { .. })    }}#[derive(Debug, Deserialize)]struct SendInputArgs {    target: String,    message: Option<String>,    items: Option<Vec<UserInput>>,    #[serde(default)]    interrupt: bool,}#[derive(Debug, Serialize)]pub(crate) struct SendInputResult {    submission_id: String,}impl ToolOutput for SendInputResult {    fn log_preview(&self) -> String {        tool_output_json_text(self, "send_input")    }    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), "send_input")    }    fn code_mode_result(&self, _payload: &ToolPayload) -> JsonValue {        tool_output_code_mode_result(self, "send_input")    }}