From 097782c7755f5df3016f580f9c9bc9c7f9d47755 Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Fri, 22 Aug 2025 15:18:54 -0700 Subject: [PATCH] Move models.rs to protocol (#2595) Moving models.rs to protocol so we can use them in `Codex` operations --- codex-rs/Cargo.lock | 3 ++ codex-rs/core/src/apply_patch.rs | 4 +-- codex-rs/core/src/chat_completions.rs | 40 +++++++++++++---------- codex-rs/core/src/client.rs | 2 +- codex-rs/core/src/client_common.rs | 4 +-- codex-rs/core/src/codex.rs | 16 ++++----- codex-rs/core/src/conversation_history.rs | 20 ++++++------ codex-rs/core/src/environment_context.rs | 4 +-- codex-rs/core/src/lib.rs | 1 - codex-rs/core/src/mcp_tool_call.rs | 4 +-- codex-rs/core/src/plan_tool.rs | 4 +-- codex-rs/core/src/rollout.rs | 2 +- codex-rs/protocol/Cargo.toml | 3 ++ codex-rs/protocol/src/lib.rs | 1 + codex-rs/{core => protocol}/src/models.rs | 1 - 15 files changed, 59 insertions(+), 50 deletions(-) rename codex-rs/{core => protocol}/src/models.rs (99%) diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 2fdf9873..325b8ee0 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -923,13 +923,16 @@ dependencies = [ name = "codex-protocol" version = "0.0.0" dependencies = [ + "base64 0.22.1", "mcp-types", + "mime_guess", "pretty_assertions", "serde", "serde_bytes", "serde_json", "strum 0.27.2", "strum_macros 0.27.2", + "tracing", "ts-rs", "uuid", ] diff --git a/codex-rs/core/src/apply_patch.rs b/codex-rs/core/src/apply_patch.rs index 4f9292b6..56fd01fe 100644 --- a/codex-rs/core/src/apply_patch.rs +++ b/codex-rs/core/src/apply_patch.rs @@ -1,13 +1,13 @@ use crate::codex::Session; use crate::codex::TurnContext; -use crate::models::FunctionCallOutputPayload; -use crate::models::ResponseInputItem; use crate::protocol::FileChange; use crate::protocol::ReviewDecision; use crate::safety::SafetyCheck; use crate::safety::assess_patch_safety; use codex_apply_patch::ApplyPatchAction; use codex_apply_patch::ApplyPatchFileChange; +use codex_protocol::models::FunctionCallOutputPayload; +use codex_protocol::models::ResponseInputItem; use std::collections::HashMap; use std::path::PathBuf; diff --git a/codex-rs/core/src/chat_completions.rs b/codex-rs/core/src/chat_completions.rs index 7131b8f4..55b20091 100644 --- a/codex-rs/core/src/chat_completions.rs +++ b/codex-rs/core/src/chat_completions.rs @@ -22,11 +22,11 @@ use crate::client_common::ResponseStream; use crate::error::CodexErr; use crate::error::Result; use crate::model_family::ModelFamily; -use crate::models::ContentItem; -use crate::models::ReasoningItemContent; -use crate::models::ResponseItem; use crate::openai_tools::create_tools_json_for_chat_completions_api; use crate::util::backoff; +use codex_protocol::models::ContentItem; +use codex_protocol::models::ReasoningItemContent; +use codex_protocol::models::ResponseItem; /// Implementation for the classic Chat Completions API. pub(crate) async fn stream_chat_completions( @@ -509,16 +509,19 @@ where // do NOT emit yet. Forward any other item (e.g. FunctionCall) right // away so downstream consumers see it. - let is_assistant_delta = matches!(&item, crate::models::ResponseItem::Message { role, .. } if role == "assistant"); + let is_assistant_delta = matches!(&item, codex_protocol::models::ResponseItem::Message { role, .. } if role == "assistant"); if is_assistant_delta { // Only use the final assistant message if we have not // seen any deltas; otherwise, deltas already built the // cumulative text and this would duplicate it. if this.cumulative.is_empty() - && let crate::models::ResponseItem::Message { content, .. } = &item + && let codex_protocol::models::ResponseItem::Message { content, .. } = + &item && let Some(text) = content.iter().find_map(|c| match c { - crate::models::ContentItem::OutputText { text } => Some(text), + codex_protocol::models::ContentItem::OutputText { text } => { + Some(text) + } _ => None, }) { @@ -542,26 +545,27 @@ where if !this.cumulative_reasoning.is_empty() && matches!(this.mode, AggregateMode::AggregatedOnly) { - let aggregated_reasoning = crate::models::ResponseItem::Reasoning { - id: String::new(), - summary: Vec::new(), - content: Some(vec![ - crate::models::ReasoningItemContent::ReasoningText { - text: std::mem::take(&mut this.cumulative_reasoning), - }, - ]), - encrypted_content: None, - }; + let aggregated_reasoning = + codex_protocol::models::ResponseItem::Reasoning { + id: String::new(), + summary: Vec::new(), + content: Some(vec![ + codex_protocol::models::ReasoningItemContent::ReasoningText { + text: std::mem::take(&mut this.cumulative_reasoning), + }, + ]), + encrypted_content: None, + }; this.pending .push_back(ResponseEvent::OutputItemDone(aggregated_reasoning)); emitted_any = true; } if !this.cumulative.is_empty() { - let aggregated_message = crate::models::ResponseItem::Message { + let aggregated_message = codex_protocol::models::ResponseItem::Message { id: None, role: "assistant".to_string(), - content: vec![crate::models::ContentItem::OutputText { + content: vec![codex_protocol::models::ContentItem::OutputText { text: std::mem::take(&mut this.cumulative), }], }; diff --git a/codex-rs/core/src/client.rs b/codex-rs/core/src/client.rs index 43f3f1de..6206b426 100644 --- a/codex-rs/core/src/client.rs +++ b/codex-rs/core/src/client.rs @@ -37,13 +37,13 @@ use crate::flags::CODEX_RS_SSE_FIXTURE; use crate::model_family::ModelFamily; use crate::model_provider_info::ModelProviderInfo; use crate::model_provider_info::WireApi; -use crate::models::ResponseItem; use crate::openai_tools::create_tools_json_for_responses_api; use crate::protocol::TokenUsage; use crate::user_agent::get_codex_user_agent; use crate::util::backoff; use codex_protocol::config_types::ReasoningEffort as ReasoningEffortConfig; use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig; +use codex_protocol::models::ResponseItem; use std::sync::Arc; #[derive(Debug, Deserialize)] diff --git a/codex-rs/core/src/client_common.rs b/codex-rs/core/src/client_common.rs index c9a8a429..c320d8d0 100644 --- a/codex-rs/core/src/client_common.rs +++ b/codex-rs/core/src/client_common.rs @@ -1,13 +1,13 @@ use crate::config_types::Verbosity as VerbosityConfig; use crate::error::Result; use crate::model_family::ModelFamily; -use crate::models::ContentItem; -use crate::models::ResponseItem; use crate::openai_tools::OpenAiTool; use crate::protocol::TokenUsage; use codex_apply_patch::APPLY_PATCH_TOOL_INSTRUCTIONS; use codex_protocol::config_types::ReasoningEffort as ReasoningEffortConfig; use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig; +use codex_protocol::models::ContentItem; +use codex_protocol::models::ResponseItem; use futures::Stream; use serde::Serialize; use std::borrow::Cow; diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index e99d5fb6..79b73a33 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -56,14 +56,6 @@ use crate::exec_env::create_env; use crate::mcp_connection_manager::McpConnectionManager; use crate::mcp_tool_call::handle_mcp_tool_call; use crate::model_family::find_family_for_model; -use crate::models::ContentItem; -use crate::models::FunctionCallOutputPayload; -use crate::models::LocalShellAction; -use crate::models::ReasoningItemContent; -use crate::models::ReasoningItemReasoningSummary; -use crate::models::ResponseInputItem; -use crate::models::ResponseItem; -use crate::models::ShellToolCallParams; use crate::openai_tools::ApplyPatchToolArgs; use crate::openai_tools::ToolsConfig; use crate::openai_tools::get_openai_tools; @@ -108,6 +100,14 @@ use crate::user_notification::UserNotification; use crate::util::backoff; use codex_protocol::config_types::ReasoningEffort as ReasoningEffortConfig; use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig; +use codex_protocol::models::ContentItem; +use codex_protocol::models::FunctionCallOutputPayload; +use codex_protocol::models::LocalShellAction; +use codex_protocol::models::ReasoningItemContent; +use codex_protocol::models::ReasoningItemReasoningSummary; +use codex_protocol::models::ResponseInputItem; +use codex_protocol::models::ResponseItem; +use codex_protocol::models::ShellToolCallParams; // A convenience extension trait for acquiring mutex locks where poisoning is // unrecoverable and should abort the program. This avoids scattered `.unwrap()` diff --git a/codex-rs/core/src/conversation_history.rs b/codex-rs/core/src/conversation_history.rs index 5955ce44..884c5a57 100644 --- a/codex-rs/core/src/conversation_history.rs +++ b/codex-rs/core/src/conversation_history.rs @@ -1,4 +1,4 @@ -use crate::models::ResponseItem; +use codex_protocol::models::ResponseItem; /// Transcript of conversation history #[derive(Debug, Clone, Default)] @@ -66,7 +66,7 @@ impl ConversationHistory { self.items.push(ResponseItem::Message { id: None, role: "assistant".to_string(), - content: vec![crate::models::ContentItem::OutputText { + content: vec![codex_protocol::models::ContentItem::OutputText { text: delta.to_string(), }], }); @@ -120,11 +120,11 @@ fn is_api_message(message: &ResponseItem) -> bool { /// Helper to append the textual content from `src` into `dst` in place. fn append_text_content( - dst: &mut Vec, - src: &Vec, + dst: &mut Vec, + src: &Vec, ) { for c in src { - if let crate::models::ContentItem::OutputText { text } = c { + if let codex_protocol::models::ContentItem::OutputText { text } = c { append_text_delta(dst, text); } } @@ -132,15 +132,15 @@ fn append_text_content( /// Append a single text delta to the last OutputText item in `content`, or /// push a new OutputText item if none exists. -fn append_text_delta(content: &mut Vec, delta: &str) { - if let Some(crate::models::ContentItem::OutputText { text }) = content +fn append_text_delta(content: &mut Vec, delta: &str) { + if let Some(codex_protocol::models::ContentItem::OutputText { text }) = content .iter_mut() .rev() - .find(|c| matches!(c, crate::models::ContentItem::OutputText { .. })) + .find(|c| matches!(c, codex_protocol::models::ContentItem::OutputText { .. })) { text.push_str(delta); } else { - content.push(crate::models::ContentItem::OutputText { + content.push(codex_protocol::models::ContentItem::OutputText { text: delta.to_string(), }); } @@ -149,7 +149,7 @@ fn append_text_delta(content: &mut Vec, delta: &str) #[cfg(test)] mod tests { use super::*; - use crate::models::ContentItem; + use codex_protocol::models::ContentItem; fn assistant_msg(text: &str) -> ResponseItem { ResponseItem::Message { diff --git a/codex-rs/core/src/environment_context.rs b/codex-rs/core/src/environment_context.rs index c89d7ca6..1af4c909 100644 --- a/codex-rs/core/src/environment_context.rs +++ b/codex-rs/core/src/environment_context.rs @@ -2,12 +2,12 @@ use serde::Deserialize; use serde::Serialize; use strum_macros::Display as DeriveDisplay; -use crate::models::ContentItem; -use crate::models::ResponseItem; use crate::protocol::AskForApproval; use crate::protocol::SandboxPolicy; use crate::shell::Shell; use codex_protocol::config_types::SandboxMode; +use codex_protocol::models::ContentItem; +use codex_protocol::models::ResponseItem; use std::path::PathBuf; /// wraps environment context message in a tag for the model to parse more easily. diff --git a/codex-rs/core/src/lib.rs b/codex-rs/core/src/lib.rs index 37f30a72..6d4699bc 100644 --- a/codex-rs/core/src/lib.rs +++ b/codex-rs/core/src/lib.rs @@ -39,7 +39,6 @@ mod conversation_manager; pub use conversation_manager::ConversationManager; pub use conversation_manager::NewConversation; pub mod model_family; -mod models; mod openai_model_info; mod openai_tools; pub mod plan_tool; diff --git a/codex-rs/core/src/mcp_tool_call.rs b/codex-rs/core/src/mcp_tool_call.rs index e92d7e84..57b29262 100644 --- a/codex-rs/core/src/mcp_tool_call.rs +++ b/codex-rs/core/src/mcp_tool_call.rs @@ -4,13 +4,13 @@ use std::time::Instant; use tracing::error; use crate::codex::Session; -use crate::models::FunctionCallOutputPayload; -use crate::models::ResponseInputItem; use crate::protocol::Event; use crate::protocol::EventMsg; use crate::protocol::McpInvocation; use crate::protocol::McpToolCallBeginEvent; use crate::protocol::McpToolCallEndEvent; +use codex_protocol::models::FunctionCallOutputPayload; +use codex_protocol::models::ResponseInputItem; /// Handles the specified tool call dispatches the appropriate /// `McpToolCallBegin` and `McpToolCallEnd` events to the `Session`. diff --git a/codex-rs/core/src/plan_tool.rs b/codex-rs/core/src/plan_tool.rs index bc39e4f6..a712b8b8 100644 --- a/codex-rs/core/src/plan_tool.rs +++ b/codex-rs/core/src/plan_tool.rs @@ -2,13 +2,13 @@ use std::collections::BTreeMap; use std::sync::LazyLock; use crate::codex::Session; -use crate::models::FunctionCallOutputPayload; -use crate::models::ResponseInputItem; use crate::openai_tools::JsonSchema; use crate::openai_tools::OpenAiTool; use crate::openai_tools::ResponsesApiTool; use crate::protocol::Event; use crate::protocol::EventMsg; +use codex_protocol::models::FunctionCallOutputPayload; +use codex_protocol::models::ResponseInputItem; // Use the canonical plan tool types from the protocol crate to ensure // type-identity matches events transported via `codex_protocol`. diff --git a/codex-rs/core/src/rollout.rs b/codex-rs/core/src/rollout.rs index f5a62ef8..46098c16 100644 --- a/codex-rs/core/src/rollout.rs +++ b/codex-rs/core/src/rollout.rs @@ -22,7 +22,7 @@ use uuid::Uuid; use crate::config::Config; use crate::git_info::GitInfo; use crate::git_info::collect_git_info; -use crate::models::ResponseItem; +use codex_protocol::models::ResponseItem; const SESSIONS_SUBDIR: &str = "sessions"; diff --git a/codex-rs/protocol/Cargo.toml b/codex-rs/protocol/Cargo.toml index c94bdb8e..aac24440 100644 --- a/codex-rs/protocol/Cargo.toml +++ b/codex-rs/protocol/Cargo.toml @@ -11,12 +11,15 @@ path = "src/lib.rs" workspace = true [dependencies] +base64 = "0.22.1" mcp-types = { path = "../mcp-types" } +mime_guess = "2.0.5" serde = { version = "1", features = ["derive"] } serde_bytes = "0.11" serde_json = "1" strum = "0.27.2" strum_macros = "0.27.2" +tracing = "0.1.41" ts-rs = { version = "11", features = ["uuid-impl", "serde-json-impl"] } uuid = { version = "1", features = ["serde", "v4"] } diff --git a/codex-rs/protocol/src/lib.rs b/codex-rs/protocol/src/lib.rs index 458ae659..d7aceeb9 100644 --- a/codex-rs/protocol/src/lib.rs +++ b/codex-rs/protocol/src/lib.rs @@ -1,6 +1,7 @@ pub mod config_types; pub mod mcp_protocol; pub mod message_history; +pub mod models; pub mod parse_command; pub mod plan_tool; pub mod protocol; diff --git a/codex-rs/core/src/models.rs b/codex-rs/protocol/src/models.rs similarity index 99% rename from codex-rs/core/src/models.rs rename to codex-rs/protocol/src/models.rs index aa092e18..31e61d8b 100644 --- a/codex-rs/core/src/models.rs +++ b/codex-rs/protocol/src/models.rs @@ -204,7 +204,6 @@ impl From> for ResponseInputItem { None } }, - _ => None, }) .collect::>(), }