diff --git a/agentydragon/tasks/25-guard-tool-output-sequencing-rust.md b/agentydragon/tasks/25-guard-tool-output-sequencing-rust.md index 869e0bd582..952aa8d84b 100644 --- a/agentydragon/tasks/25-guard-tool-output-sequencing-rust.md +++ b/agentydragon/tasks/25-guard-tool-output-sequencing-rust.md @@ -30,7 +30,7 @@ We will implement the following high-level plan: - Add tests under `codex-rs/core/tests/` (e.g. `guard_tool_output_sequencing.rs`) that exercise interleaved input sequences: - A user message mid-rollout before tool output, ensuring it is delayed until after the tool result. - Normal flow where no buffering is needed. - - Cancellation or error-result paths that also trigger a flush of buffered messages. + - Cancellation paths (no tool output) inserting a fake "Tool cancelled" tool message and flushing buffered messages. ## Notes diff --git a/codex-rs/core/src/chat_completions.rs b/codex-rs/core/src/chat_completions.rs index b2accf9d6b..2e8963b1ee 100644 --- a/codex-rs/core/src/chat_completions.rs +++ b/codex-rs/core/src/chat_completions.rs @@ -116,6 +116,18 @@ pub(crate) async fn stream_chat_completions( } } + // If a tool invocation was never resolved (e.g. was cancelled), insert a fake cancellation result and flush buffered user inputs + if let Some(call_id) = pending_call.take() { + messages.push(json!({ + "role": "tool", + "tool_call_id": call_id, + "content": "Tool cancelled" + })); + for msg in buf_user.drain(..) { + messages.push(msg); + } + } + let tools_json = create_tools_json_for_chat_completions_api(prompt, model)?; let payload = json!({ "model": model, diff --git a/codex-rs/core/src/lib.rs b/codex-rs/core/src/lib.rs index cc42097523..66523db3cf 100644 --- a/codex-rs/core/src/lib.rs +++ b/codex-rs/core/src/lib.rs @@ -27,7 +27,7 @@ mod model_provider_info; pub use model_provider_info::ModelProviderInfo; pub use model_provider_info::WireApi; mod models; -pub use models::{ContentItem, ReasoningItemReasoningSummary, ResponseItem}; +pub use models::{ContentItem, ReasoningItemReasoningSummary, ResponseItem, FunctionCallOutputPayload}; pub mod openai_api_key; mod openai_tools; mod project_doc; @@ -37,4 +37,4 @@ mod safety; mod user_notification; pub mod util; -pub use client_common::model_supports_reasoning_summaries; +pub use client_common::{model_supports_reasoning_summaries, Prompt}; diff --git a/codex-rs/core/tests/guard_tool_output_sequencing.rs b/codex-rs/core/tests/guard_tool_output_sequencing.rs index e0f6682072..c37c2c6fb2 100644 --- a/codex-rs/core/tests/guard_tool_output_sequencing.rs +++ b/codex-rs/core/tests/guard_tool_output_sequencing.rs @@ -1,6 +1,5 @@ use serde_json::{json, Value}; -use codex_core::client_common::Prompt; -use codex_core::models::{ResponseItem, ContentItem, FunctionCallOutputPayload}; +use codex_core::{Prompt, ResponseItem, ContentItem, FunctionCallOutputPayload}; /// Reproduce the `messages` JSON construction from `stream_chat_completions` fn build_messages(input: Vec, model: &str) -> Vec {