From 3590e181fa2736c88a559389ea70dd1fe68d228e Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 18 Mar 2026 16:10:51 -0700 Subject: [PATCH] Add update_plan code mode result (#15103) It's empty! --- codex-rs/core/src/tools/handlers/plan.rs | 40 +++++++++++++++++++++--- codex-rs/core/tests/suite/code_mode.rs | 32 +++++++++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/codex-rs/core/src/tools/handlers/plan.rs b/codex-rs/core/src/tools/handlers/plan.rs index 9c9d3e959..af8dc2c31 100644 --- a/codex-rs/core/src/tools/handlers/plan.rs +++ b/codex-rs/core/src/tools/handlers/plan.rs @@ -3,21 +3,52 @@ use crate::client_common::tools::ToolSpec; use crate::codex::Session; use crate::codex::TurnContext; use crate::function_tool::FunctionCallError; -use crate::tools::context::FunctionToolOutput; use crate::tools::context::ToolInvocation; +use crate::tools::context::ToolOutput; use crate::tools::context::ToolPayload; use crate::tools::registry::ToolHandler; use crate::tools::registry::ToolKind; use crate::tools::spec::JsonSchema; use async_trait::async_trait; use codex_protocol::config_types::ModeKind; +use codex_protocol::models::FunctionCallOutputPayload; +use codex_protocol::models::ResponseInputItem; use codex_protocol::plan_tool::UpdatePlanArgs; use codex_protocol::protocol::EventMsg; +use serde_json::Value as JsonValue; use std::collections::BTreeMap; use std::sync::LazyLock; pub struct PlanHandler; +pub struct PlanToolOutput; + +const PLAN_UPDATED_MESSAGE: &str = "Plan updated"; + +impl ToolOutput for PlanToolOutput { + fn log_preview(&self) -> String { + PLAN_UPDATED_MESSAGE.to_string() + } + + fn success_for_logging(&self) -> bool { + true + } + + fn to_response_item(&self, call_id: &str, _payload: &ToolPayload) -> ResponseInputItem { + let mut output = FunctionCallOutputPayload::from_text(PLAN_UPDATED_MESSAGE.to_string()); + output.success = Some(true); + + ResponseInputItem::FunctionCallOutput { + call_id: call_id.to_string(), + output, + } + } + + fn code_mode_result(&self, _payload: &ToolPayload) -> JsonValue { + JsonValue::Object(serde_json::Map::new()) + } +} + pub static PLAN_TOOL: LazyLock = LazyLock::new(|| { let mut plan_item_props = BTreeMap::new(); plan_item_props.insert("step".to_string(), JsonSchema::String { description: None }); @@ -64,7 +95,7 @@ At most one step can be in_progress at a time. #[async_trait] impl ToolHandler for PlanHandler { - type Output = FunctionToolOutput; + type Output = PlanToolOutput; fn kind(&self) -> ToolKind { ToolKind::Function @@ -88,10 +119,9 @@ impl ToolHandler for PlanHandler { } }; - let content = - handle_update_plan(session.as_ref(), turn.as_ref(), arguments, call_id).await?; + handle_update_plan(session.as_ref(), turn.as_ref(), arguments, call_id).await?; - Ok(FunctionToolOutput::from_text(content, Some(true))) + Ok(PlanToolOutput) } } diff --git a/codex-rs/core/tests/suite/code_mode.rs b/codex-rs/core/tests/suite/code_mode.rs index 62d13e649..3fb149ead 100644 --- a/codex-rs/core/tests/suite/code_mode.rs +++ b/codex-rs/core/tests/suite/code_mode.rs @@ -363,6 +363,38 @@ text(output.output); Ok(()) } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn code_mode_update_plan_nested_tool_result_is_empty_object() -> Result<()> { + skip_if_no_network!(Ok(())); + + let server = responses::start_mock_server().await; + let (_test, second_mock) = run_code_mode_turn( + &server, + "use exec to run update_plan", + r#" +const result = await tools.update_plan({ + plan: [{ step: "Run update_plan from code mode", status: "in_progress" }], +}); +text(JSON.stringify(result)); +"#, + false, + ) + .await?; + + let req = second_mock.single_request(); + let (output, success) = custom_tool_output_body_and_success(&req, "call-1"); + assert_ne!( + success, + Some(false), + "exec update_plan call failed unexpectedly: {output}" + ); + + let parsed: Value = serde_json::from_str(&output)?; + assert_eq!(parsed, serde_json::json!({})); + + Ok(()) +} + #[cfg_attr(windows, ignore = "flaky on windows")] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn code_mode_nested_tool_calls_can_run_in_parallel() -> Result<()> {