diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 49ad611235..198c986d87 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -171,8 +171,7 @@ version = "0.0.0" dependencies = [ "anyhow", "assert_cmd", - "codex-protocol", - "mcp-types", + "codex-app-server-protocol", "serde", "serde_json", "tokio", @@ -657,6 +656,7 @@ dependencies = [ "app_test_support", "assert_cmd", "base64", + "codex-app-server-protocol", "codex-arg0", "codex-common", "codex-core", @@ -665,7 +665,6 @@ dependencies = [ "codex-protocol", "codex-utils-json-to-toml", "core_test_support", - "mcp-types", "os_info", "pretty_assertions", "serde", @@ -679,6 +678,21 @@ dependencies = [ "wiremock", ] +[[package]] +name = "codex-app-server-protocol" +version = "0.0.0" +dependencies = [ + "anyhow", + "codex-protocol", + "paste", + "pretty_assertions", + "serde", + "serde_json", + "strum_macros 0.27.2", + "ts-rs", + "uuid", +] + [[package]] name = "codex-apply-patch" version = "0.0.0" @@ -750,6 +764,7 @@ dependencies = [ "clap", "clap_complete", "codex-app-server", + "codex-app-server-protocol", "codex-arg0", "codex-chatgpt", "codex-cloud-tasks", @@ -820,6 +835,7 @@ name = "codex-common" version = "0.0.0" dependencies = [ "clap", + "codex-app-server-protocol", "codex-core", "codex-protocol", "serde", @@ -838,6 +854,7 @@ dependencies = [ "base64", "bytes", "chrono", + "codex-app-server-protocol", "codex-apply-patch", "codex-file-search", "codex-mcp-client", @@ -994,8 +1011,8 @@ dependencies = [ "anyhow", "base64", "chrono", + "codex-app-server-protocol", "codex-core", - "codex-protocol", "core_test_support", "rand 0.9.2", "reqwest", @@ -1071,6 +1088,7 @@ name = "codex-otel" version = "0.0.0" dependencies = [ "chrono", + "codex-app-server-protocol", "codex-protocol", "eventsource-stream", "opentelemetry", @@ -1103,8 +1121,6 @@ dependencies = [ "icu_locale_core", "mcp-types", "mime_guess", - "paste", - "pretty_assertions", "serde", "serde_json", "serde_with", @@ -1123,7 +1139,7 @@ version = "0.0.0" dependencies = [ "anyhow", "clap", - "codex-protocol", + "codex-app-server-protocol", "ts-rs", ] @@ -1171,6 +1187,7 @@ dependencies = [ "chrono", "clap", "codex-ansi-escape", + "codex-app-server-protocol", "codex-arg0", "codex-common", "codex-core", diff --git a/codex-rs/Cargo.toml b/codex-rs/Cargo.toml index 15a1cf49be..01dc47a70d 100644 --- a/codex-rs/Cargo.toml +++ b/codex-rs/Cargo.toml @@ -3,6 +3,7 @@ members = [ "backend-client", "ansi-escape", "app-server", + "app-server-protocol", "apply-patch", "arg0", "codex-backend-openapi-models", @@ -47,6 +48,7 @@ edition = "2024" app_test_support = { path = "app-server/tests/common" } codex-ansi-escape = { path = "ansi-escape" } codex-app-server = { path = "app-server" } +codex-app-server-protocol = { path = "app-server-protocol" } codex-apply-patch = { path = "apply-patch" } codex-arg0 = { path = "arg0" } codex-chatgpt = { path = "chatgpt" } diff --git a/codex-rs/app-server-protocol/Cargo.toml b/codex-rs/app-server-protocol/Cargo.toml new file mode 100644 index 0000000000..b18028fbe4 --- /dev/null +++ b/codex-rs/app-server-protocol/Cargo.toml @@ -0,0 +1,24 @@ +[package] +edition = "2024" +name = "codex-app-server-protocol" +version = { workspace = true } + +[lib] +name = "codex_app_server_protocol" +path = "src/lib.rs" + +[lints] +workspace = true + +[dependencies] +codex-protocol = { workspace = true } +paste = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +strum_macros = { workspace = true } +ts-rs = { workspace = true } +uuid = { workspace = true, features = ["serde", "v7"] } + +[dev-dependencies] +anyhow = { workspace = true } +pretty_assertions = { workspace = true } diff --git a/codex-rs/app-server-protocol/src/jsonrpc_lite.rs b/codex-rs/app-server-protocol/src/jsonrpc_lite.rs new file mode 100644 index 0000000000..e458125dd2 --- /dev/null +++ b/codex-rs/app-server-protocol/src/jsonrpc_lite.rs @@ -0,0 +1,66 @@ +//! We do not do true JSON-RPC 2.0, as we neither send nor expect the +//! "jsonrpc": "2.0" field. + +use serde::Deserialize; +use serde::Serialize; +use ts_rs::TS; + +pub const JSONRPC_VERSION: &str = "2.0"; + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Hash, Eq, TS)] +#[serde(untagged)] +pub enum RequestId { + String(String), + Integer(i64), +} + +pub type Result = serde_json::Value; + +/// Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[serde(untagged)] +pub enum JSONRPCMessage { + Request(JSONRPCRequest), + Notification(JSONRPCNotification), + Response(JSONRPCResponse), + Error(JSONRPCError), +} + +/// A request that expects a response. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +pub struct JSONRPCRequest { + pub id: RequestId, + pub method: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub params: Option, +} + +/// A notification which does not expect a response. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +pub struct JSONRPCNotification { + pub method: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub params: Option, +} + +/// A successful (non-error) response to a request. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +pub struct JSONRPCResponse { + pub id: RequestId, + pub result: Result, +} + +/// A response to a request that indicates an error occurred. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +pub struct JSONRPCError { + pub error: JSONRPCErrorError, + pub id: RequestId, +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +pub struct JSONRPCErrorError { + pub code: i64, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub data: Option, + pub message: String, +} diff --git a/codex-rs/app-server-protocol/src/lib.rs b/codex-rs/app-server-protocol/src/lib.rs new file mode 100644 index 0000000000..517702bbd8 --- /dev/null +++ b/codex-rs/app-server-protocol/src/lib.rs @@ -0,0 +1,5 @@ +mod jsonrpc_lite; +mod protocol; + +pub use jsonrpc_lite::*; +pub use protocol::*; diff --git a/codex-rs/protocol/src/mcp_protocol.rs b/codex-rs/app-server-protocol/src/protocol.rs similarity index 90% rename from codex-rs/protocol/src/mcp_protocol.rs rename to codex-rs/app-server-protocol/src/protocol.rs index bd672071b1..4bc10b2e65 100644 --- a/codex-rs/protocol/src/mcp_protocol.rs +++ b/codex-rs/app-server-protocol/src/protocol.rs @@ -1,20 +1,20 @@ use std::collections::HashMap; -use std::fmt::Display; use std::path::PathBuf; -use crate::config_types::ReasoningEffort; -use crate::config_types::ReasoningSummary; -use crate::config_types::SandboxMode; -use crate::config_types::Verbosity; -use crate::protocol::AskForApproval; -use crate::protocol::EventMsg; -use crate::protocol::FileChange; -use crate::protocol::ReviewDecision; -use crate::protocol::SandboxPolicy; -use crate::protocol::TurnAbortReason; -use mcp_types::JSONRPCNotification; -use mcp_types::JSONRPCRequest; -use mcp_types::RequestId; +use crate::JSONRPCNotification; +use crate::JSONRPCRequest; +use crate::RequestId; +use codex_protocol::ConversationId; +use codex_protocol::config_types::ReasoningEffort; +use codex_protocol::config_types::ReasoningSummary; +use codex_protocol::config_types::SandboxMode; +use codex_protocol::config_types::Verbosity; +use codex_protocol::protocol::AskForApproval; +use codex_protocol::protocol::EventMsg; +use codex_protocol::protocol::FileChange; +use codex_protocol::protocol::ReviewDecision; +use codex_protocol::protocol::SandboxPolicy; +use codex_protocol::protocol::TurnAbortReason; use paste::paste; use serde::Deserialize; use serde::Serialize; @@ -22,58 +22,6 @@ use strum_macros::Display; use ts_rs::TS; use uuid::Uuid; -#[derive(Debug, Clone, Copy, PartialEq, Eq, TS, Hash)] -#[ts(type = "string")] -pub struct ConversationId { - uuid: Uuid, -} - -impl ConversationId { - pub fn new() -> Self { - Self { - uuid: Uuid::now_v7(), - } - } - - pub fn from_string(s: &str) -> Result { - Ok(Self { - uuid: Uuid::parse_str(s)?, - }) - } -} - -impl Default for ConversationId { - fn default() -> Self { - Self::new() - } -} - -impl Display for ConversationId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.uuid) - } -} - -impl Serialize for ConversationId { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.collect_str(&self.uuid) - } -} - -impl<'de> Deserialize<'de> for ConversationId { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let value = String::deserialize(deserializer)?; - let uuid = Uuid::parse_str(&value).map_err(serde::de::Error::custom)?; - Ok(Self { uuid }) - } -} - #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, TS)] #[ts(type = "string")] pub struct GitSha(pub String); @@ -658,31 +606,15 @@ pub enum InputItem { /// Generates an `enum ServerRequest` where each variant is a request that the /// server can send to the client along with the corresponding params and /// response types. It also generates helper types used by the app/server -/// infrastructure (method constants, payload enum, and export helpers). +/// infrastructure (payload enum, request constructor, and export helpers). macro_rules! server_request_definitions { ( $( $(#[$variant_meta:meta])* - $variant:ident => $method:literal + $variant:ident ),* $(,)? ) => { paste! { - $(pub const [<$variant:snake:upper _METHOD>]: &str = $method;)* - - /// Method names for server-initiated requests (camelCase to match JSON-RPC). - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub enum ServerRequestMethod { - $( $variant ),* - } - - impl ServerRequestMethod { - pub const fn as_str(self) -> &'static str { - match self { - $(ServerRequestMethod::$variant => $method,)* - } - } - } - /// Request initiated from the server and sent to the client. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] #[serde(tag = "method", rename_all = "camelCase")] @@ -703,19 +635,7 @@ macro_rules! server_request_definitions { } impl ServerRequestPayload { - pub fn method(&self) -> &'static str { - match self { - $(Self::$variant(..) => $method,)* - } - } - - pub fn into_params_value(self) -> serde_json::Value { - match self { - $(Self::$variant(params) => serde_json::to_value(params).unwrap_or_default(),)* - } - } - - pub fn into_request(self, request_id: RequestId) -> ServerRequest { + pub fn request_with_id(self, request_id: RequestId) -> ServerRequest { match self { $(Self::$variant(params) => ServerRequest::$variant { request_id, params },)* } @@ -744,9 +664,9 @@ impl TryFrom for ServerRequest { server_request_definitions! { /// Request to approve a patch. - ApplyPatchApproval => "applyPatchApproval", + ApplyPatchApproval, /// Request to exec a command. - ExecCommandApproval => "execCommandApproval", + ExecCommandApproval, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] @@ -938,12 +858,6 @@ mod tests { Ok(()) } - #[test] - fn test_conversation_id_default_is_not_zeroes() { - let id = ConversationId::default(); - assert_ne!(id.uuid, Uuid::nil()); - } - #[test] fn conversation_id_serializes_as_plain_string() -> Result<()> { let id = ConversationId::from_string("67e55044-10b1-426f-9247-bb680e5fe0c8")?; @@ -1011,8 +925,7 @@ mod tests { ); let payload = ServerRequestPayload::ExecCommandApproval(params); - assert_eq!("execCommandApproval", EXEC_COMMAND_APPROVAL_METHOD); - assert_eq!(EXEC_COMMAND_APPROVAL_METHOD, payload.method()); + assert_eq!(payload.request_with_id(RequestId::Integer(7)), request); Ok(()) } } diff --git a/codex-rs/app-server/Cargo.toml b/codex-rs/app-server/Cargo.toml index 1cc25ef2d1..545ef4898c 100644 --- a/codex-rs/app-server/Cargo.toml +++ b/codex-rs/app-server/Cargo.toml @@ -22,10 +22,8 @@ codex-core = { workspace = true } codex-file-search = { workspace = true } codex-login = { workspace = true } codex-protocol = { workspace = true } +codex-app-server-protocol = { workspace = true } codex-utils-json-to-toml = { workspace = true } -# We should only be using mcp-types for JSON-RPC types: it would be nice to -# split this out into a separate crate at some point. -mcp-types = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } tokio = { workspace = true, features = [ diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 042f75edfc..1e5eb82ef0 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -3,6 +3,52 @@ use crate::error_code::INVALID_REQUEST_ERROR_CODE; use crate::fuzzy_file_search::run_fuzzy_file_search; use crate::outgoing_message::OutgoingMessageSender; use crate::outgoing_message::OutgoingNotification; +use codex_app_server_protocol::AddConversationListenerParams; +use codex_app_server_protocol::AddConversationSubscriptionResponse; +use codex_app_server_protocol::ApplyPatchApprovalParams; +use codex_app_server_protocol::ApplyPatchApprovalResponse; +use codex_app_server_protocol::ArchiveConversationParams; +use codex_app_server_protocol::ArchiveConversationResponse; +use codex_app_server_protocol::AuthStatusChangeNotification; +use codex_app_server_protocol::ClientRequest; +use codex_app_server_protocol::ConversationSummary; +use codex_app_server_protocol::ExecCommandApprovalParams; +use codex_app_server_protocol::ExecCommandApprovalResponse; +use codex_app_server_protocol::ExecOneOffCommandParams; +use codex_app_server_protocol::ExecOneOffCommandResponse; +use codex_app_server_protocol::FuzzyFileSearchParams; +use codex_app_server_protocol::FuzzyFileSearchResponse; +use codex_app_server_protocol::GetUserAgentResponse; +use codex_app_server_protocol::GetUserSavedConfigResponse; +use codex_app_server_protocol::GitDiffToRemoteResponse; +use codex_app_server_protocol::InputItem as WireInputItem; +use codex_app_server_protocol::InterruptConversationParams; +use codex_app_server_protocol::InterruptConversationResponse; +use codex_app_server_protocol::JSONRPCErrorError; +use codex_app_server_protocol::ListConversationsParams; +use codex_app_server_protocol::ListConversationsResponse; +use codex_app_server_protocol::LoginApiKeyParams; +use codex_app_server_protocol::LoginApiKeyResponse; +use codex_app_server_protocol::LoginChatGptCompleteNotification; +use codex_app_server_protocol::LoginChatGptResponse; +use codex_app_server_protocol::NewConversationParams; +use codex_app_server_protocol::NewConversationResponse; +use codex_app_server_protocol::RemoveConversationListenerParams; +use codex_app_server_protocol::RemoveConversationSubscriptionResponse; +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::Result as JsonRpcResult; +use codex_app_server_protocol::ResumeConversationParams; +use codex_app_server_protocol::SendUserMessageParams; +use codex_app_server_protocol::SendUserMessageResponse; +use codex_app_server_protocol::SendUserTurnParams; +use codex_app_server_protocol::SendUserTurnResponse; +use codex_app_server_protocol::ServerNotification; +use codex_app_server_protocol::ServerRequestPayload; +use codex_app_server_protocol::SessionConfiguredNotification; +use codex_app_server_protocol::SetDefaultModelParams; +use codex_app_server_protocol::SetDefaultModelResponse; +use codex_app_server_protocol::UserInfoResponse; +use codex_app_server_protocol::UserSavedConfig; use codex_core::AuthManager; use codex_core::CodexConversation; use codex_core::ConversationManager; @@ -36,57 +82,12 @@ use codex_core::protocol::ReviewDecision; use codex_login::ServerOptions as LoginServerOptions; use codex_login::ShutdownHandle; use codex_login::run_login_server; -use codex_protocol::mcp_protocol::AddConversationListenerParams; -use codex_protocol::mcp_protocol::AddConversationSubscriptionResponse; -use codex_protocol::mcp_protocol::ApplyPatchApprovalParams; -use codex_protocol::mcp_protocol::ApplyPatchApprovalResponse; -use codex_protocol::mcp_protocol::ArchiveConversationParams; -use codex_protocol::mcp_protocol::ArchiveConversationResponse; -use codex_protocol::mcp_protocol::AuthStatusChangeNotification; -use codex_protocol::mcp_protocol::ClientRequest; -use codex_protocol::mcp_protocol::ConversationId; -use codex_protocol::mcp_protocol::ConversationSummary; -use codex_protocol::mcp_protocol::ExecCommandApprovalParams; -use codex_protocol::mcp_protocol::ExecCommandApprovalResponse; -use codex_protocol::mcp_protocol::ExecOneOffCommandParams; -use codex_protocol::mcp_protocol::ExecOneOffCommandResponse; -use codex_protocol::mcp_protocol::FuzzyFileSearchParams; -use codex_protocol::mcp_protocol::FuzzyFileSearchResponse; -use codex_protocol::mcp_protocol::GetUserAgentResponse; -use codex_protocol::mcp_protocol::GetUserSavedConfigResponse; -use codex_protocol::mcp_protocol::GitDiffToRemoteResponse; -use codex_protocol::mcp_protocol::InputItem as WireInputItem; -use codex_protocol::mcp_protocol::InterruptConversationParams; -use codex_protocol::mcp_protocol::InterruptConversationResponse; -use codex_protocol::mcp_protocol::ListConversationsParams; -use codex_protocol::mcp_protocol::ListConversationsResponse; -use codex_protocol::mcp_protocol::LoginApiKeyParams; -use codex_protocol::mcp_protocol::LoginApiKeyResponse; -use codex_protocol::mcp_protocol::LoginChatGptCompleteNotification; -use codex_protocol::mcp_protocol::LoginChatGptResponse; -use codex_protocol::mcp_protocol::NewConversationParams; -use codex_protocol::mcp_protocol::NewConversationResponse; -use codex_protocol::mcp_protocol::RemoveConversationListenerParams; -use codex_protocol::mcp_protocol::RemoveConversationSubscriptionResponse; -use codex_protocol::mcp_protocol::ResumeConversationParams; -use codex_protocol::mcp_protocol::SendUserMessageParams; -use codex_protocol::mcp_protocol::SendUserMessageResponse; -use codex_protocol::mcp_protocol::SendUserTurnParams; -use codex_protocol::mcp_protocol::SendUserTurnResponse; -use codex_protocol::mcp_protocol::ServerNotification; -use codex_protocol::mcp_protocol::ServerRequestPayload; -use codex_protocol::mcp_protocol::SessionConfiguredNotification; -use codex_protocol::mcp_protocol::SetDefaultModelParams; -use codex_protocol::mcp_protocol::SetDefaultModelResponse; -use codex_protocol::mcp_protocol::UserInfoResponse; -use codex_protocol::mcp_protocol::UserSavedConfig; +use codex_protocol::ConversationId; use codex_protocol::models::ContentItem; use codex_protocol::models::ResponseItem; use codex_protocol::protocol::InputMessageKind; use codex_protocol::protocol::USER_MESSAGE_BEGIN; use codex_utils_json_to_toml::json_to_toml; -use mcp_types::JSONRPCErrorError; -use mcp_types::RequestId; use std::collections::HashMap; use std::ffi::OsStr; use std::path::PathBuf; @@ -385,7 +386,7 @@ impl CodexMessageProcessor { self.outgoing .send_response( request_id, - codex_protocol::mcp_protocol::CancelLoginChatGptResponse {}, + codex_app_server_protocol::CancelLoginChatGptResponse {}, ) .await; } else { @@ -421,7 +422,7 @@ impl CodexMessageProcessor { self.outgoing .send_response( request_id, - codex_protocol::mcp_protocol::LogoutChatGptResponse {}, + codex_app_server_protocol::LogoutChatGptResponse {}, ) .await; @@ -439,7 +440,7 @@ impl CodexMessageProcessor { async fn get_auth_status( &self, request_id: RequestId, - params: codex_protocol::mcp_protocol::GetAuthStatusParams, + params: codex_app_server_protocol::GetAuthStatusParams, ) { let include_token = params.include_token.unwrap_or(false); let do_refresh = params.refresh_token.unwrap_or(false); @@ -454,7 +455,7 @@ impl CodexMessageProcessor { let requires_openai_auth = self.config.model_provider.requires_openai_auth; let response = if !requires_openai_auth { - codex_protocol::mcp_protocol::GetAuthStatusResponse { + codex_app_server_protocol::GetAuthStatusResponse { auth_method: None, auth_token: None, requires_openai_auth: Some(false), @@ -474,13 +475,13 @@ impl CodexMessageProcessor { (None, None) } }; - codex_protocol::mcp_protocol::GetAuthStatusResponse { + codex_app_server_protocol::GetAuthStatusResponse { auth_method: reported_auth_method, auth_token: token_opt, requires_openai_auth: Some(true), } } - None => codex_protocol::mcp_protocol::GetAuthStatusResponse { + None => codex_app_server_protocol::GetAuthStatusResponse { auth_method: None, auth_token: None, requires_openai_auth: Some(true), @@ -807,7 +808,7 @@ impl CodexMessageProcessor { }); // Reply with conversation id + model and initial messages (when present) - let response = codex_protocol::mcp_protocol::ResumeConversationResponse { + let response = codex_app_server_protocol::ResumeConversationResponse { conversation_id, model: session_configured.model.clone(), initial_messages, @@ -1360,7 +1361,7 @@ fn derive_config_from_params( async fn on_patch_approval_response( event_id: String, - receiver: oneshot::Receiver, + receiver: oneshot::Receiver, codex: Arc, ) { let response = receiver.await; @@ -1402,7 +1403,7 @@ async fn on_patch_approval_response( async fn on_exec_approval_response( event_id: String, - receiver: oneshot::Receiver, + receiver: oneshot::Receiver, conversation: Arc, ) { let response = receiver.await; diff --git a/codex-rs/app-server/src/fuzzy_file_search.rs b/codex-rs/app-server/src/fuzzy_file_search.rs index eef760df26..146cc12a39 100644 --- a/codex-rs/app-server/src/fuzzy_file_search.rs +++ b/codex-rs/app-server/src/fuzzy_file_search.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; use std::sync::Arc; use std::sync::atomic::AtomicBool; +use codex_app_server_protocol::FuzzyFileSearchResult; use codex_file_search as file_search; -use codex_protocol::mcp_protocol::FuzzyFileSearchResult; use tokio::task::JoinSet; use tracing::warn; diff --git a/codex-rs/app-server/src/lib.rs b/codex-rs/app-server/src/lib.rs index a0c40db64a..3e888c6960 100644 --- a/codex-rs/app-server/src/lib.rs +++ b/codex-rs/app-server/src/lib.rs @@ -8,7 +8,7 @@ use codex_common::CliConfigOverrides; use codex_core::config::Config; use codex_core::config::ConfigOverrides; -use mcp_types::JSONRPCMessage; +use codex_app_server_protocol::JSONRPCMessage; use tokio::io::AsyncBufReadExt; use tokio::io::AsyncWriteExt; use tokio::io::BufReader; @@ -111,17 +111,17 @@ pub async fn run_main( let stdout_writer_handle = tokio::spawn(async move { let mut stdout = io::stdout(); while let Some(outgoing_message) = outgoing_rx.recv().await { - let msg: JSONRPCMessage = outgoing_message.into(); - match serde_json::to_string(&msg) { - Ok(json) => { + let Ok(value) = serde_json::to_value(outgoing_message) else { + error!("Failed to convert OutgoingMessage to JSON value"); + continue; + }; + match serde_json::to_string(&value) { + Ok(mut json) => { + json.push('\n'); if let Err(e) = stdout.write_all(json.as_bytes()).await { error!("Failed to write to stdout: {e}"); break; } - if let Err(e) = stdout.write_all(b"\n").await { - error!("Failed to write newline to stdout: {e}"); - break; - } } Err(e) => error!("Failed to serialize JSONRPCMessage: {e}"), } diff --git a/codex-rs/app-server/src/message_processor.rs b/codex-rs/app-server/src/message_processor.rs index 24e0f2320a..1b9fcffb71 100644 --- a/codex-rs/app-server/src/message_processor.rs +++ b/codex-rs/app-server/src/message_processor.rs @@ -3,20 +3,20 @@ use std::path::PathBuf; use crate::codex_message_processor::CodexMessageProcessor; use crate::error_code::INVALID_REQUEST_ERROR_CODE; use crate::outgoing_message::OutgoingMessageSender; -use codex_protocol::mcp_protocol::ClientInfo; -use codex_protocol::mcp_protocol::ClientRequest; -use codex_protocol::mcp_protocol::InitializeResponse; +use codex_app_server_protocol::ClientInfo; +use codex_app_server_protocol::ClientRequest; +use codex_app_server_protocol::InitializeResponse; +use codex_app_server_protocol::JSONRPCError; +use codex_app_server_protocol::JSONRPCErrorError; +use codex_app_server_protocol::JSONRPCNotification; +use codex_app_server_protocol::JSONRPCRequest; +use codex_app_server_protocol::JSONRPCResponse; use codex_core::AuthManager; use codex_core::ConversationManager; use codex_core::config::Config; use codex_core::default_client::USER_AGENT_SUFFIX; use codex_core::default_client::get_codex_user_agent; -use mcp_types::JSONRPCError; -use mcp_types::JSONRPCErrorError; -use mcp_types::JSONRPCNotification; -use mcp_types::JSONRPCRequest; -use mcp_types::JSONRPCResponse; use std::sync::Arc; pub(crate) struct MessageProcessor { diff --git a/codex-rs/app-server/src/outgoing_message.rs b/codex-rs/app-server/src/outgoing_message.rs index b9d886629f..96a2c5a96c 100644 --- a/codex-rs/app-server/src/outgoing_message.rs +++ b/codex-rs/app-server/src/outgoing_message.rs @@ -2,17 +2,12 @@ use std::collections::HashMap; use std::sync::atomic::AtomicI64; use std::sync::atomic::Ordering; -use codex_protocol::mcp_protocol::ServerNotification; -use codex_protocol::mcp_protocol::ServerRequestPayload; -use mcp_types::JSONRPC_VERSION; -use mcp_types::JSONRPCError; -use mcp_types::JSONRPCErrorError; -use mcp_types::JSONRPCMessage; -use mcp_types::JSONRPCNotification; -use mcp_types::JSONRPCRequest; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; -use mcp_types::Result; +use codex_app_server_protocol::JSONRPCErrorError; +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::Result; +use codex_app_server_protocol::ServerNotification; +use codex_app_server_protocol::ServerRequest; +use codex_app_server_protocol::ServerRequestPayload; use serde::Serialize; use tokio::sync::Mutex; use tokio::sync::mpsc; @@ -49,19 +44,8 @@ impl OutgoingMessageSender { request_id_to_callback.insert(id, tx_approve); } - let method = request.method(); - let params_value = request.into_params_value(); - let params = if params_value.is_null() { - None - } else { - Some(params_value) - }; - - let outgoing_message = OutgoingMessage::Request(OutgoingRequest { - id: outgoing_message_id, - method: method.to_string(), - params, - }); + let outgoing_message = + OutgoingMessage::Request(request.request_with_id(outgoing_message_id)); let _ = self.sender.send(outgoing_message); rx_approve } @@ -124,8 +108,10 @@ impl OutgoingMessageSender { } /// Outgoing message from the server to the client. +#[derive(Debug, Clone, Serialize)] +#[serde(untagged)] pub(crate) enum OutgoingMessage { - Request(OutgoingRequest), + Request(ServerRequest), Notification(OutgoingNotification), /// AppServerNotification is specific to the case where this is run as an /// "app server" as opposed to an MCP server. @@ -134,64 +120,6 @@ pub(crate) enum OutgoingMessage { Error(OutgoingError), } -impl From for JSONRPCMessage { - fn from(val: OutgoingMessage) -> Self { - use OutgoingMessage::*; - match val { - Request(OutgoingRequest { id, method, params }) => { - JSONRPCMessage::Request(JSONRPCRequest { - jsonrpc: JSONRPC_VERSION.into(), - id, - method, - params, - }) - } - Notification(OutgoingNotification { method, params }) => { - JSONRPCMessage::Notification(JSONRPCNotification { - jsonrpc: JSONRPC_VERSION.into(), - method, - params, - }) - } - AppServerNotification(notification) => { - let method = notification.to_string(); - let params = match notification.to_params() { - Ok(params) => Some(params), - Err(err) => { - warn!("failed to serialize notification params: {err}"); - None - } - }; - JSONRPCMessage::Notification(JSONRPCNotification { - jsonrpc: JSONRPC_VERSION.into(), - method, - params, - }) - } - Response(OutgoingResponse { id, result }) => { - JSONRPCMessage::Response(JSONRPCResponse { - jsonrpc: JSONRPC_VERSION.into(), - id, - result, - }) - } - Error(OutgoingError { id, error }) => JSONRPCMessage::Error(JSONRPCError { - jsonrpc: JSONRPC_VERSION.into(), - id, - error, - }), - } - } -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub(crate) struct OutgoingRequest { - pub id: RequestId, - pub method: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub params: Option, -} - #[derive(Debug, Clone, PartialEq, Serialize)] pub(crate) struct OutgoingNotification { pub method: String, @@ -213,7 +141,7 @@ pub(crate) struct OutgoingError { #[cfg(test)] mod tests { - use codex_protocol::mcp_protocol::LoginChatGptCompleteNotification; + use codex_app_server_protocol::LoginChatGptCompleteNotification; use pretty_assertions::assert_eq; use serde_json::json; use uuid::Uuid; @@ -229,18 +157,17 @@ mod tests { error: None, }); - let jsonrpc_notification: JSONRPCMessage = - OutgoingMessage::AppServerNotification(notification).into(); + let jsonrpc_notification = OutgoingMessage::AppServerNotification(notification); assert_eq!( - JSONRPCMessage::Notification(JSONRPCNotification { - jsonrpc: "2.0".into(), - method: "loginChatGptComplete".into(), - params: Some(json!({ + json!({ + "method": "loginChatGptComplete", + "params": { "loginId": Uuid::nil(), "success": true, - })), + }, }), - jsonrpc_notification, + serde_json::to_value(jsonrpc_notification) + .expect("ensure the strum macros serialize the method field correctly"), "ensure the strum macros serialize the method field correctly" ); } diff --git a/codex-rs/app-server/tests/common/Cargo.toml b/codex-rs/app-server/tests/common/Cargo.toml index 4cc711fb6b..306b1e187e 100644 --- a/codex-rs/app-server/tests/common/Cargo.toml +++ b/codex-rs/app-server/tests/common/Cargo.toml @@ -9,8 +9,7 @@ path = "lib.rs" [dependencies] anyhow = { workspace = true } assert_cmd = { workspace = true } -codex-protocol = { workspace = true } -mcp-types = { workspace = true } +codex-app-server-protocol = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true, features = [ diff --git a/codex-rs/app-server/tests/common/lib.rs b/codex-rs/app-server/tests/common/lib.rs index d088b184ea..2acb52de69 100644 --- a/codex-rs/app-server/tests/common/lib.rs +++ b/codex-rs/app-server/tests/common/lib.rs @@ -2,8 +2,8 @@ mod mcp_process; mod mock_model_server; mod responses; +use codex_app_server_protocol::JSONRPCResponse; pub use mcp_process::McpProcess; -use mcp_types::JSONRPCResponse; pub use mock_model_server::create_mock_chat_completions_server; pub use responses::create_apply_patch_sse_response; pub use responses::create_final_assistant_message_sse_response; diff --git a/codex-rs/app-server/tests/common/mcp_process.rs b/codex-rs/app-server/tests/common/mcp_process.rs index d36415641c..bdc96cad0a 100644 --- a/codex-rs/app-server/tests/common/mcp_process.rs +++ b/codex-rs/app-server/tests/common/mcp_process.rs @@ -11,30 +11,30 @@ use tokio::process::ChildStdout; use anyhow::Context; use assert_cmd::prelude::*; -use codex_protocol::mcp_protocol::AddConversationListenerParams; -use codex_protocol::mcp_protocol::ArchiveConversationParams; -use codex_protocol::mcp_protocol::CancelLoginChatGptParams; -use codex_protocol::mcp_protocol::ClientInfo; -use codex_protocol::mcp_protocol::ClientNotification; -use codex_protocol::mcp_protocol::GetAuthStatusParams; -use codex_protocol::mcp_protocol::InitializeParams; -use codex_protocol::mcp_protocol::InterruptConversationParams; -use codex_protocol::mcp_protocol::ListConversationsParams; -use codex_protocol::mcp_protocol::LoginApiKeyParams; -use codex_protocol::mcp_protocol::NewConversationParams; -use codex_protocol::mcp_protocol::RemoveConversationListenerParams; -use codex_protocol::mcp_protocol::ResumeConversationParams; -use codex_protocol::mcp_protocol::SendUserMessageParams; -use codex_protocol::mcp_protocol::SendUserTurnParams; -use codex_protocol::mcp_protocol::ServerRequest; -use codex_protocol::mcp_protocol::SetDefaultModelParams; - -use mcp_types::JSONRPC_VERSION; -use mcp_types::JSONRPCMessage; -use mcp_types::JSONRPCNotification; -use mcp_types::JSONRPCRequest; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; +use codex_app_server_protocol::AddConversationListenerParams; +use codex_app_server_protocol::ArchiveConversationParams; +use codex_app_server_protocol::CancelLoginChatGptParams; +use codex_app_server_protocol::ClientInfo; +use codex_app_server_protocol::ClientNotification; +use codex_app_server_protocol::GetAuthStatusParams; +use codex_app_server_protocol::InitializeParams; +use codex_app_server_protocol::InterruptConversationParams; +use codex_app_server_protocol::ListConversationsParams; +use codex_app_server_protocol::LoginApiKeyParams; +use codex_app_server_protocol::NewConversationParams; +use codex_app_server_protocol::RemoveConversationListenerParams; +use codex_app_server_protocol::ResumeConversationParams; +use codex_app_server_protocol::SendUserMessageParams; +use codex_app_server_protocol::SendUserTurnParams; +use codex_app_server_protocol::ServerRequest; +use codex_app_server_protocol::SetDefaultModelParams; + +use codex_app_server_protocol::JSONRPCError; +use codex_app_server_protocol::JSONRPCMessage; +use codex_app_server_protocol::JSONRPCNotification; +use codex_app_server_protocol::JSONRPCRequest; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::RequestId; use std::process::Command as StdCommand; use tokio::process::Command; @@ -318,7 +318,6 @@ impl McpProcess { let request_id = self.next_request_id.fetch_add(1, Ordering::Relaxed); let message = JSONRPCMessage::Request(JSONRPCRequest { - jsonrpc: JSONRPC_VERSION.into(), id: RequestId::Integer(request_id), method: method.to_string(), params, @@ -332,12 +331,8 @@ impl McpProcess { id: RequestId, result: serde_json::Value, ) -> anyhow::Result<()> { - self.send_jsonrpc_message(JSONRPCMessage::Response(JSONRPCResponse { - jsonrpc: JSONRPC_VERSION.into(), - id, - result, - })) - .await + self.send_jsonrpc_message(JSONRPCMessage::Response(JSONRPCResponse { id, result })) + .await } pub async fn send_notification( @@ -346,7 +341,6 @@ impl McpProcess { ) -> anyhow::Result<()> { let value = serde_json::to_value(notification)?; self.send_jsonrpc_message(JSONRPCMessage::Notification(JSONRPCNotification { - jsonrpc: JSONRPC_VERSION.into(), method: value .get("method") .and_then(|m| m.as_str()) @@ -429,7 +423,7 @@ impl McpProcess { pub async fn read_stream_until_error_message( &mut self, request_id: RequestId, - ) -> anyhow::Result { + ) -> anyhow::Result { loop { let message = self.read_jsonrpc_message().await?; match message { diff --git a/codex-rs/app-server/tests/suite/archive_conversation.rs b/codex-rs/app-server/tests/suite/archive_conversation.rs index 65a1589763..6dcfefdbb8 100644 --- a/codex-rs/app-server/tests/suite/archive_conversation.rs +++ b/codex-rs/app-server/tests/suite/archive_conversation.rs @@ -2,13 +2,13 @@ use std::path::Path; use app_test_support::McpProcess; use app_test_support::to_response; +use codex_app_server_protocol::ArchiveConversationParams; +use codex_app_server_protocol::ArchiveConversationResponse; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::NewConversationParams; +use codex_app_server_protocol::NewConversationResponse; +use codex_app_server_protocol::RequestId; use codex_core::ARCHIVED_SESSIONS_SUBDIR; -use codex_protocol::mcp_protocol::ArchiveConversationParams; -use codex_protocol::mcp_protocol::ArchiveConversationResponse; -use codex_protocol::mcp_protocol::NewConversationParams; -use codex_protocol::mcp_protocol::NewConversationResponse; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; use tempfile::TempDir; use tokio::time::timeout; diff --git a/codex-rs/app-server/tests/suite/auth.rs b/codex-rs/app-server/tests/suite/auth.rs index b19203d880..f45a27fda0 100644 --- a/codex-rs/app-server/tests/suite/auth.rs +++ b/codex-rs/app-server/tests/suite/auth.rs @@ -2,13 +2,13 @@ use std::path::Path; use app_test_support::McpProcess; use app_test_support::to_response; -use codex_protocol::mcp_protocol::AuthMode; -use codex_protocol::mcp_protocol::GetAuthStatusParams; -use codex_protocol::mcp_protocol::GetAuthStatusResponse; -use codex_protocol::mcp_protocol::LoginApiKeyParams; -use codex_protocol::mcp_protocol::LoginApiKeyResponse; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; +use codex_app_server_protocol::AuthMode; +use codex_app_server_protocol::GetAuthStatusParams; +use codex_app_server_protocol::GetAuthStatusResponse; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::LoginApiKeyParams; +use codex_app_server_protocol::LoginApiKeyResponse; +use codex_app_server_protocol::RequestId; use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; diff --git a/codex-rs/app-server/tests/suite/codex_message_processor_flow.rs b/codex-rs/app-server/tests/suite/codex_message_processor_flow.rs index e331ce2a5d..f1f34f952f 100644 --- a/codex-rs/app-server/tests/suite/codex_message_processor_flow.rs +++ b/codex-rs/app-server/tests/suite/codex_message_processor_flow.rs @@ -5,26 +5,26 @@ use app_test_support::create_final_assistant_message_sse_response; use app_test_support::create_mock_chat_completions_server; use app_test_support::create_shell_sse_response; use app_test_support::to_response; +use codex_app_server_protocol::AddConversationListenerParams; +use codex_app_server_protocol::AddConversationSubscriptionResponse; +use codex_app_server_protocol::ExecCommandApprovalParams; +use codex_app_server_protocol::JSONRPCNotification; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::NewConversationParams; +use codex_app_server_protocol::NewConversationResponse; +use codex_app_server_protocol::RemoveConversationListenerParams; +use codex_app_server_protocol::RemoveConversationSubscriptionResponse; +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::SendUserMessageParams; +use codex_app_server_protocol::SendUserMessageResponse; +use codex_app_server_protocol::SendUserTurnParams; +use codex_app_server_protocol::SendUserTurnResponse; +use codex_app_server_protocol::ServerRequest; use codex_core::protocol::AskForApproval; use codex_core::protocol::SandboxPolicy; use codex_core::protocol_config_types::ReasoningEffort; use codex_core::protocol_config_types::ReasoningSummary; use codex_core::spawn::CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR; -use codex_protocol::mcp_protocol::AddConversationListenerParams; -use codex_protocol::mcp_protocol::AddConversationSubscriptionResponse; -use codex_protocol::mcp_protocol::ExecCommandApprovalParams; -use codex_protocol::mcp_protocol::NewConversationParams; -use codex_protocol::mcp_protocol::NewConversationResponse; -use codex_protocol::mcp_protocol::RemoveConversationListenerParams; -use codex_protocol::mcp_protocol::RemoveConversationSubscriptionResponse; -use codex_protocol::mcp_protocol::SendUserMessageParams; -use codex_protocol::mcp_protocol::SendUserMessageResponse; -use codex_protocol::mcp_protocol::SendUserTurnParams; -use codex_protocol::mcp_protocol::SendUserTurnResponse; -use codex_protocol::mcp_protocol::ServerRequest; -use mcp_types::JSONRPCNotification; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; use pretty_assertions::assert_eq; use std::env; use tempfile::TempDir; @@ -116,7 +116,7 @@ async fn test_codex_jsonrpc_conversation_flow() { let send_user_id = mcp .send_send_user_message_request(SendUserMessageParams { conversation_id, - items: vec![codex_protocol::mcp_protocol::InputItem::Text { + items: vec![codex_app_server_protocol::InputItem::Text { text: "text".to_string(), }], }) @@ -266,7 +266,7 @@ async fn test_send_user_turn_changes_approval_policy_behavior() { let send_user_id = mcp .send_send_user_message_request(SendUserMessageParams { conversation_id, - items: vec![codex_protocol::mcp_protocol::InputItem::Text { + items: vec![codex_app_server_protocol::InputItem::Text { text: "run python".to_string(), }], }) @@ -331,7 +331,7 @@ async fn test_send_user_turn_changes_approval_policy_behavior() { let send_turn_id = mcp .send_send_user_turn_request(SendUserTurnParams { conversation_id, - items: vec![codex_protocol::mcp_protocol::InputItem::Text { + items: vec![codex_app_server_protocol::InputItem::Text { text: "run python again".to_string(), }], cwd: working_directory.clone(), diff --git a/codex-rs/app-server/tests/suite/config.rs b/codex-rs/app-server/tests/suite/config.rs index 13cb6c4a2f..577eeb388d 100644 --- a/codex-rs/app-server/tests/suite/config.rs +++ b/codex-rs/app-server/tests/suite/config.rs @@ -3,18 +3,18 @@ use std::path::Path; use app_test_support::McpProcess; use app_test_support::to_response; +use codex_app_server_protocol::GetUserSavedConfigResponse; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::Profile; +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::SandboxSettings; +use codex_app_server_protocol::Tools; +use codex_app_server_protocol::UserSavedConfig; use codex_core::protocol::AskForApproval; use codex_protocol::config_types::ReasoningEffort; use codex_protocol::config_types::ReasoningSummary; use codex_protocol::config_types::SandboxMode; use codex_protocol::config_types::Verbosity; -use codex_protocol::mcp_protocol::GetUserSavedConfigResponse; -use codex_protocol::mcp_protocol::Profile; -use codex_protocol::mcp_protocol::SandboxSettings; -use codex_protocol::mcp_protocol::Tools; -use codex_protocol::mcp_protocol::UserSavedConfig; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; diff --git a/codex-rs/app-server/tests/suite/create_conversation.rs b/codex-rs/app-server/tests/suite/create_conversation.rs index d5896fffcb..37a0db84fa 100644 --- a/codex-rs/app-server/tests/suite/create_conversation.rs +++ b/codex-rs/app-server/tests/suite/create_conversation.rs @@ -4,15 +4,15 @@ use app_test_support::McpProcess; use app_test_support::create_final_assistant_message_sse_response; use app_test_support::create_mock_chat_completions_server; use app_test_support::to_response; -use codex_protocol::mcp_protocol::AddConversationListenerParams; -use codex_protocol::mcp_protocol::AddConversationSubscriptionResponse; -use codex_protocol::mcp_protocol::InputItem; -use codex_protocol::mcp_protocol::NewConversationParams; -use codex_protocol::mcp_protocol::NewConversationResponse; -use codex_protocol::mcp_protocol::SendUserMessageParams; -use codex_protocol::mcp_protocol::SendUserMessageResponse; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; +use codex_app_server_protocol::AddConversationListenerParams; +use codex_app_server_protocol::AddConversationSubscriptionResponse; +use codex_app_server_protocol::InputItem; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::NewConversationParams; +use codex_app_server_protocol::NewConversationResponse; +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::SendUserMessageParams; +use codex_app_server_protocol::SendUserMessageResponse; use pretty_assertions::assert_eq; use serde_json::json; use tempfile::TempDir; diff --git a/codex-rs/app-server/tests/suite/fuzzy_file_search.rs b/codex-rs/app-server/tests/suite/fuzzy_file_search.rs index 12cbb7d574..8e33b130e1 100644 --- a/codex-rs/app-server/tests/suite/fuzzy_file_search.rs +++ b/codex-rs/app-server/tests/suite/fuzzy_file_search.rs @@ -1,6 +1,6 @@ use app_test_support::McpProcess; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::RequestId; use pretty_assertions::assert_eq; use serde_json::json; use tempfile::TempDir; diff --git a/codex-rs/app-server/tests/suite/interrupt.rs b/codex-rs/app-server/tests/suite/interrupt.rs index 087f1b6078..2500d20ff4 100644 --- a/codex-rs/app-server/tests/suite/interrupt.rs +++ b/codex-rs/app-server/tests/suite/interrupt.rs @@ -3,17 +3,17 @@ use std::path::Path; +use codex_app_server_protocol::AddConversationListenerParams; +use codex_app_server_protocol::InterruptConversationParams; +use codex_app_server_protocol::InterruptConversationResponse; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::NewConversationParams; +use codex_app_server_protocol::NewConversationResponse; +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::SendUserMessageParams; +use codex_app_server_protocol::SendUserMessageResponse; use codex_core::protocol::TurnAbortReason; -use codex_protocol::mcp_protocol::AddConversationListenerParams; -use codex_protocol::mcp_protocol::InterruptConversationParams; -use codex_protocol::mcp_protocol::InterruptConversationResponse; -use codex_protocol::mcp_protocol::NewConversationParams; -use codex_protocol::mcp_protocol::NewConversationResponse; -use codex_protocol::mcp_protocol::SendUserMessageParams; -use codex_protocol::mcp_protocol::SendUserMessageResponse; use core_test_support::skip_if_no_network; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; use tempfile::TempDir; use tokio::time::timeout; @@ -100,7 +100,7 @@ async fn shell_command_interruption() -> anyhow::Result<()> { let send_user_id = mcp .send_send_user_message_request(SendUserMessageParams { conversation_id, - items: vec![codex_protocol::mcp_protocol::InputItem::Text { + items: vec![codex_app_server_protocol::InputItem::Text { text: "run first sleep command".to_string(), }], }) diff --git a/codex-rs/app-server/tests/suite/list_resume.rs b/codex-rs/app-server/tests/suite/list_resume.rs index 9e91fdd9cd..a4178b0873 100644 --- a/codex-rs/app-server/tests/suite/list_resume.rs +++ b/codex-rs/app-server/tests/suite/list_resume.rs @@ -3,16 +3,16 @@ use std::path::Path; use app_test_support::McpProcess; use app_test_support::to_response; -use codex_protocol::mcp_protocol::ListConversationsParams; -use codex_protocol::mcp_protocol::ListConversationsResponse; -use codex_protocol::mcp_protocol::NewConversationParams; // reused for overrides shape -use codex_protocol::mcp_protocol::ResumeConversationParams; -use codex_protocol::mcp_protocol::ResumeConversationResponse; -use codex_protocol::mcp_protocol::ServerNotification; -use codex_protocol::mcp_protocol::SessionConfiguredNotification; -use mcp_types::JSONRPCNotification; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; +use codex_app_server_protocol::JSONRPCNotification; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::ListConversationsParams; +use codex_app_server_protocol::ListConversationsResponse; +use codex_app_server_protocol::NewConversationParams; // reused for overrides shape +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::ResumeConversationParams; +use codex_app_server_protocol::ResumeConversationResponse; +use codex_app_server_protocol::ServerNotification; +use codex_app_server_protocol::SessionConfiguredNotification; use pretty_assertions::assert_eq; use serde_json::json; use tempfile::TempDir; diff --git a/codex-rs/app-server/tests/suite/login.rs b/codex-rs/app-server/tests/suite/login.rs index 475af9ab57..6dcbde1125 100644 --- a/codex-rs/app-server/tests/suite/login.rs +++ b/codex-rs/app-server/tests/suite/login.rs @@ -3,15 +3,15 @@ use std::time::Duration; use app_test_support::McpProcess; use app_test_support::to_response; +use codex_app_server_protocol::CancelLoginChatGptParams; +use codex_app_server_protocol::CancelLoginChatGptResponse; +use codex_app_server_protocol::GetAuthStatusParams; +use codex_app_server_protocol::GetAuthStatusResponse; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::LoginChatGptResponse; +use codex_app_server_protocol::LogoutChatGptResponse; +use codex_app_server_protocol::RequestId; use codex_login::login_with_api_key; -use codex_protocol::mcp_protocol::CancelLoginChatGptParams; -use codex_protocol::mcp_protocol::CancelLoginChatGptResponse; -use codex_protocol::mcp_protocol::GetAuthStatusParams; -use codex_protocol::mcp_protocol::GetAuthStatusResponse; -use codex_protocol::mcp_protocol::LoginChatGptResponse; -use codex_protocol::mcp_protocol::LogoutChatGptResponse; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; use tempfile::TempDir; use tokio::time::timeout; diff --git a/codex-rs/app-server/tests/suite/send_message.rs b/codex-rs/app-server/tests/suite/send_message.rs index 81da0096f4..22fb02dca9 100644 --- a/codex-rs/app-server/tests/suite/send_message.rs +++ b/codex-rs/app-server/tests/suite/send_message.rs @@ -4,17 +4,17 @@ use app_test_support::McpProcess; use app_test_support::create_final_assistant_message_sse_response; use app_test_support::create_mock_chat_completions_server; use app_test_support::to_response; -use codex_protocol::mcp_protocol::AddConversationListenerParams; -use codex_protocol::mcp_protocol::AddConversationSubscriptionResponse; -use codex_protocol::mcp_protocol::ConversationId; -use codex_protocol::mcp_protocol::InputItem; -use codex_protocol::mcp_protocol::NewConversationParams; -use codex_protocol::mcp_protocol::NewConversationResponse; -use codex_protocol::mcp_protocol::SendUserMessageParams; -use codex_protocol::mcp_protocol::SendUserMessageResponse; -use mcp_types::JSONRPCNotification; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; +use codex_app_server_protocol::AddConversationListenerParams; +use codex_app_server_protocol::AddConversationSubscriptionResponse; +use codex_app_server_protocol::InputItem; +use codex_app_server_protocol::JSONRPCNotification; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::NewConversationParams; +use codex_app_server_protocol::NewConversationResponse; +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::SendUserMessageParams; +use codex_app_server_protocol::SendUserMessageResponse; +use codex_protocol::ConversationId; use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; diff --git a/codex-rs/app-server/tests/suite/set_default_model.rs b/codex-rs/app-server/tests/suite/set_default_model.rs index ce0d79d497..6769faa9dc 100644 --- a/codex-rs/app-server/tests/suite/set_default_model.rs +++ b/codex-rs/app-server/tests/suite/set_default_model.rs @@ -2,11 +2,11 @@ use std::path::Path; use app_test_support::McpProcess; use app_test_support::to_response; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::SetDefaultModelParams; +use codex_app_server_protocol::SetDefaultModelResponse; use codex_core::config::ConfigToml; -use codex_protocol::mcp_protocol::SetDefaultModelParams; -use codex_protocol::mcp_protocol::SetDefaultModelResponse; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; diff --git a/codex-rs/app-server/tests/suite/user_agent.rs b/codex-rs/app-server/tests/suite/user_agent.rs index a7f75eab37..95a0b1a3e0 100644 --- a/codex-rs/app-server/tests/suite/user_agent.rs +++ b/codex-rs/app-server/tests/suite/user_agent.rs @@ -1,8 +1,8 @@ use app_test_support::McpProcess; use app_test_support::to_response; -use codex_protocol::mcp_protocol::GetUserAgentResponse; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; +use codex_app_server_protocol::GetUserAgentResponse; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::RequestId; use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; diff --git a/codex-rs/app-server/tests/suite/user_info.rs b/codex-rs/app-server/tests/suite/user_info.rs index 10ca7d330a..edd041e553 100644 --- a/codex-rs/app-server/tests/suite/user_info.rs +++ b/codex-rs/app-server/tests/suite/user_info.rs @@ -5,14 +5,14 @@ use app_test_support::McpProcess; use app_test_support::to_response; use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; +use codex_app_server_protocol::JSONRPCResponse; +use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::UserInfoResponse; use codex_core::auth::AuthDotJson; use codex_core::auth::get_auth_file; use codex_core::auth::write_auth_json; use codex_core::token_data::IdTokenInfo; use codex_core::token_data::TokenData; -use codex_protocol::mcp_protocol::UserInfoResponse; -use mcp_types::JSONRPCResponse; -use mcp_types::RequestId; use pretty_assertions::assert_eq; use serde_json::json; use tempfile::TempDir; diff --git a/codex-rs/cli/Cargo.toml b/codex-rs/cli/Cargo.toml index 77f428bb81..c4dac80ec3 100644 --- a/codex-rs/cli/Cargo.toml +++ b/codex-rs/cli/Cargo.toml @@ -28,6 +28,7 @@ codex-login = { workspace = true } codex-mcp-server = { workspace = true } codex-process-hardening = { workspace = true } codex-protocol = { workspace = true } +codex-app-server-protocol = { workspace = true } codex-protocol-ts = { workspace = true } codex-responses-api-proxy = { workspace = true } codex-tui = { workspace = true } diff --git a/codex-rs/cli/src/login.rs b/codex-rs/cli/src/login.rs index 8dd4fb8333..2b497c0642 100644 --- a/codex-rs/cli/src/login.rs +++ b/codex-rs/cli/src/login.rs @@ -1,3 +1,4 @@ +use codex_app_server_protocol::AuthMode; use codex_common::CliConfigOverrides; use codex_core::CodexAuth; use codex_core::auth::CLIENT_ID; @@ -8,7 +9,6 @@ use codex_core::config::ConfigOverrides; use codex_login::ServerOptions; use codex_login::run_device_code_login; use codex_login::run_login_server; -use codex_protocol::mcp_protocol::AuthMode; use std::path::PathBuf; pub async fn login_with_chatgpt(codex_home: PathBuf) -> std::io::Result<()> { diff --git a/codex-rs/cli/src/main.rs b/codex-rs/cli/src/main.rs index 7559e16e6a..10e2621533 100644 --- a/codex-rs/cli/src/main.rs +++ b/codex-rs/cli/src/main.rs @@ -455,7 +455,7 @@ fn print_completion(cmd: CompletionCommand) { mod tests { use super::*; use codex_core::protocol::TokenUsage; - use codex_protocol::mcp_protocol::ConversationId; + use codex_protocol::ConversationId; fn finalize_from_args(args: &[&str]) -> TuiCli { let cli = MultitoolCli::try_parse_from(args).expect("parse"); diff --git a/codex-rs/common/Cargo.toml b/codex-rs/common/Cargo.toml index 3ce84a6f50..d8f30cc09d 100644 --- a/codex-rs/common/Cargo.toml +++ b/codex-rs/common/Cargo.toml @@ -10,6 +10,7 @@ workspace = true clap = { workspace = true, features = ["derive", "wrap_help"], optional = true } codex-core = { workspace = true } codex-protocol = { workspace = true } +codex-app-server-protocol = { workspace = true } serde = { workspace = true, optional = true } toml = { workspace = true, optional = true } diff --git a/codex-rs/common/src/model_presets.rs b/codex-rs/common/src/model_presets.rs index 1acfee88f6..68acb5ce90 100644 --- a/codex-rs/common/src/model_presets.rs +++ b/codex-rs/common/src/model_presets.rs @@ -1,5 +1,5 @@ +use codex_app_server_protocol::AuthMode; use codex_core::protocol_config_types::ReasoningEffort; -use codex_protocol::mcp_protocol::AuthMode; /// A simple preset pairing a model slug with a reasoning effort. #[derive(Debug, Clone, Copy)] diff --git a/codex-rs/core/Cargo.toml b/codex-rs/core/Cargo.toml index ff1103c3d2..22ba1ee626 100644 --- a/codex-rs/core/Cargo.toml +++ b/codex-rs/core/Cargo.toml @@ -24,6 +24,7 @@ codex-file-search = { workspace = true } codex-mcp-client = { workspace = true } codex-rmcp-client = { workspace = true } codex-protocol = { workspace = true } +codex-app-server-protocol = { workspace = true } codex-otel = { workspace = true, features = ["otel"] } dirs = { workspace = true } env-flags = { workspace = true } diff --git a/codex-rs/core/src/auth.rs b/codex-rs/core/src/auth.rs index 5ba6fdf7b2..b68540615a 100644 --- a/codex-rs/core/src/auth.rs +++ b/codex-rs/core/src/auth.rs @@ -15,7 +15,7 @@ use std::sync::Arc; use std::sync::Mutex; use std::time::Duration; -use codex_protocol::mcp_protocol::AuthMode; +use codex_app_server_protocol::AuthMode; use crate::token_data::PlanType; use crate::token_data::TokenData; diff --git a/codex-rs/core/src/client.rs b/codex-rs/core/src/client.rs index 685fbf45f2..9e0c1c0430 100644 --- a/codex-rs/core/src/client.rs +++ b/codex-rs/core/src/client.rs @@ -6,8 +6,8 @@ use std::time::Duration; use crate::AuthManager; use crate::auth::CodexAuth; use bytes::Bytes; -use codex_protocol::mcp_protocol::AuthMode; -use codex_protocol::mcp_protocol::ConversationId; +use codex_app_server_protocol::AuthMode; +use codex_protocol::ConversationId; use eventsource_stream::Eventsource; use futures::prelude::*; use regex_lite::Regex; diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index 7a2b2c8da0..1fbe701884 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -19,7 +19,7 @@ use async_channel::Sender; use codex_apply_patch::ApplyPatchAction; use codex_apply_patch::MaybeApplyPatchVerified; use codex_apply_patch::maybe_parse_apply_patch_verified; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use codex_protocol::protocol::ConversationPathResponseEvent; use codex_protocol::protocol::ExitedReviewModeEvent; use codex_protocol::protocol::ReviewRequest; @@ -3301,7 +3301,7 @@ mod tests { use crate::state::TaskKind; use crate::tasks::SessionTask; use crate::tasks::SessionTaskContext; - use codex_protocol::mcp_protocol::AuthMode; + use codex_app_server_protocol::AuthMode; use codex_protocol::models::ContentItem; use codex_protocol::models::ResponseItem; diff --git a/codex-rs/core/src/config.rs b/codex-rs/core/src/config.rs index 865bc9251f..af595b495d 100644 --- a/codex-rs/core/src/config.rs +++ b/codex-rs/core/src/config.rs @@ -23,12 +23,12 @@ use crate::openai_model_info::get_model_info; use crate::protocol::AskForApproval; use crate::protocol::SandboxPolicy; use anyhow::Context; +use codex_app_server_protocol::Tools; +use codex_app_server_protocol::UserSavedConfig; use codex_protocol::config_types::ReasoningEffort; use codex_protocol::config_types::ReasoningSummary; use codex_protocol::config_types::SandboxMode; use codex_protocol::config_types::Verbosity; -use codex_protocol::mcp_protocol::Tools; -use codex_protocol::mcp_protocol::UserSavedConfig; use dirs::home_dir; use serde::Deserialize; use std::collections::BTreeMap; diff --git a/codex-rs/core/src/config_profile.rs b/codex-rs/core/src/config_profile.rs index b98f78d311..da52176068 100644 --- a/codex-rs/core/src/config_profile.rs +++ b/codex-rs/core/src/config_profile.rs @@ -22,7 +22,7 @@ pub struct ConfigProfile { pub experimental_instructions_file: Option, } -impl From for codex_protocol::mcp_protocol::Profile { +impl From for codex_app_server_protocol::Profile { fn from(config_profile: ConfigProfile) -> Self { Self { model: config_profile.model, diff --git a/codex-rs/core/src/config_types.rs b/codex-rs/core/src/config_types.rs index 4728e76ef4..1b8f3ac067 100644 --- a/codex-rs/core/src/config_types.rs +++ b/codex-rs/core/src/config_types.rs @@ -313,7 +313,7 @@ pub struct SandboxWorkspaceWrite { pub exclude_slash_tmp: bool, } -impl From for codex_protocol::mcp_protocol::SandboxSettings { +impl From for codex_app_server_protocol::SandboxSettings { fn from(sandbox_workspace_write: SandboxWorkspaceWrite) -> Self { Self { writable_roots: sandbox_workspace_write.writable_roots, diff --git a/codex-rs/core/src/conversation_manager.rs b/codex-rs/core/src/conversation_manager.rs index 51854248a4..73d9b658ce 100644 --- a/codex-rs/core/src/conversation_manager.rs +++ b/codex-rs/core/src/conversation_manager.rs @@ -13,7 +13,7 @@ use crate::protocol::Event; use crate::protocol::EventMsg; use crate::protocol::SessionConfiguredEvent; use crate::rollout::RolloutRecorder; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use codex_protocol::models::ResponseItem; use codex_protocol::protocol::InitialHistory; use codex_protocol::protocol::RolloutItem; diff --git a/codex-rs/core/src/error.rs b/codex-rs/core/src/error.rs index c5965dae8d..c6cc8940fa 100644 --- a/codex-rs/core/src/error.rs +++ b/codex-rs/core/src/error.rs @@ -1,7 +1,7 @@ use crate::exec::ExecToolCallOutput; use crate::token_data::KnownPlan; use crate::token_data::PlanType; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use codex_protocol::protocol::RateLimitSnapshot; use reqwest::StatusCode; use serde_json; diff --git a/codex-rs/core/src/git_info.rs b/codex-rs/core/src/git_info.rs index 63ef82d77d..640ae4ab26 100644 --- a/codex-rs/core/src/git_info.rs +++ b/codex-rs/core/src/git_info.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use std::path::Path; use std::path::PathBuf; -use codex_protocol::mcp_protocol::GitSha; +use codex_app_server_protocol::GitSha; use codex_protocol::protocol::GitInfo; use futures::future::join_all; use serde::Deserialize; diff --git a/codex-rs/core/src/message_history.rs b/codex-rs/core/src/message_history.rs index bfd8bf0a9e..d102b2ef7c 100644 --- a/codex-rs/core/src/message_history.rs +++ b/codex-rs/core/src/message_history.rs @@ -30,7 +30,7 @@ use tokio::io::AsyncReadExt; use crate::config::Config; use crate::config_types::HistoryPersistence; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; #[cfg(unix)] use std::os::unix::fs::OpenOptionsExt; #[cfg(unix)] diff --git a/codex-rs/core/src/model_provider_info.rs b/codex-rs/core/src/model_provider_info.rs index 2850996dcf..a5707b34d1 100644 --- a/codex-rs/core/src/model_provider_info.rs +++ b/codex-rs/core/src/model_provider_info.rs @@ -6,7 +6,7 @@ //! key. These override or extend the defaults at runtime. use crate::CodexAuth; -use codex_protocol::mcp_protocol::AuthMode; +use codex_app_server_protocol::AuthMode; use serde::Deserialize; use serde::Serialize; use std::collections::HashMap; diff --git a/codex-rs/core/src/rollout/recorder.rs b/codex-rs/core/src/rollout/recorder.rs index 6d99dd1357..f67c076c04 100644 --- a/codex-rs/core/src/rollout/recorder.rs +++ b/codex-rs/core/src/rollout/recorder.rs @@ -6,7 +6,7 @@ use std::io::Error as IoError; use std::path::Path; use std::path::PathBuf; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use serde_json::Value; use time::OffsetDateTime; use time::format_description::FormatItem; diff --git a/codex-rs/core/src/rollout/tests.rs b/codex-rs/core/src/rollout/tests.rs index af5234d31b..de9c9cef58 100644 --- a/codex-rs/core/src/rollout/tests.rs +++ b/codex-rs/core/src/rollout/tests.rs @@ -18,7 +18,7 @@ use crate::rollout::list::Cursor; use crate::rollout::list::get_conversation; use crate::rollout::list::get_conversations; use anyhow::Result; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use codex_protocol::models::ContentItem; use codex_protocol::models::ResponseItem; use codex_protocol::protocol::CompactedItem; diff --git a/codex-rs/core/tests/chat_completions_payload.rs b/codex-rs/core/tests/chat_completions_payload.rs index 4551c5ca59..9e10b37822 100644 --- a/codex-rs/core/tests/chat_completions_payload.rs +++ b/codex-rs/core/tests/chat_completions_payload.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use codex_app_server_protocol::AuthMode; use codex_core::ContentItem; use codex_core::LocalShellAction; use codex_core::LocalShellExecAction; @@ -12,8 +13,7 @@ use codex_core::ResponseItem; use codex_core::WireApi; use codex_core::spawn::CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR; use codex_otel::otel_event_manager::OtelEventManager; -use codex_protocol::mcp_protocol::AuthMode; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use core_test_support::load_default_config_for_test; use futures::StreamExt; use serde_json::Value; diff --git a/codex-rs/core/tests/chat_completions_sse.rs b/codex-rs/core/tests/chat_completions_sse.rs index 9338a1af15..d8a8212932 100644 --- a/codex-rs/core/tests/chat_completions_sse.rs +++ b/codex-rs/core/tests/chat_completions_sse.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use tracing_test::traced_test; +use codex_app_server_protocol::AuthMode; use codex_core::ContentItem; use codex_core::ModelClient; use codex_core::ModelProviderInfo; @@ -10,8 +11,7 @@ use codex_core::ResponseItem; use codex_core::WireApi; use codex_core::spawn::CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR; use codex_otel::otel_event_manager::OtelEventManager; -use codex_protocol::mcp_protocol::AuthMode; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use core_test_support::load_default_config_for_test; use futures::StreamExt; use tempfile::TempDir; diff --git a/codex-rs/core/tests/suite/client.rs b/codex-rs/core/tests/suite/client.rs index 7b8eb42916..d4ff9da2d6 100644 --- a/codex-rs/core/tests/suite/client.rs +++ b/codex-rs/core/tests/suite/client.rs @@ -1,3 +1,4 @@ +use codex_app_server_protocol::AuthMode; use codex_core::CodexAuth; use codex_core::ContentItem; use codex_core::ConversationManager; @@ -17,8 +18,7 @@ use codex_core::protocol::EventMsg; use codex_core::protocol::InputItem; use codex_core::protocol::Op; use codex_otel::otel_event_manager::OtelEventManager; -use codex_protocol::mcp_protocol::AuthMode; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use codex_protocol::models::ReasoningItemReasoningSummary; use codex_protocol::models::WebSearchAction; use core_test_support::load_default_config_for_test; diff --git a/codex-rs/exec/tests/event_processor_with_json_output.rs b/codex-rs/exec/tests/event_processor_with_json_output.rs index 8489250b78..9cbff57943 100644 --- a/codex-rs/exec/tests/event_processor_with_json_output.rs +++ b/codex-rs/exec/tests/event_processor_with_json_output.rs @@ -52,10 +52,9 @@ fn event(id: &str, msg: EventMsg) -> Event { #[test] fn session_configured_produces_thread_started_event() { let mut ep = EventProcessorWithJsonOutput::new(None); - let session_id = codex_protocol::mcp_protocol::ConversationId::from_string( - "67e55044-10b1-426f-9247-bb680e5fe0c8", - ) - .unwrap(); + let session_id = + codex_protocol::ConversationId::from_string("67e55044-10b1-426f-9247-bb680e5fe0c8") + .unwrap(); let rollout_path = PathBuf::from("/tmp/rollout.json"); let ev = event( "e1", diff --git a/codex-rs/login/Cargo.toml b/codex-rs/login/Cargo.toml index e2a693e9ac..563515c637 100644 --- a/codex-rs/login/Cargo.toml +++ b/codex-rs/login/Cargo.toml @@ -10,7 +10,7 @@ workspace = true base64 = { workspace = true } chrono = { workspace = true, features = ["serde"] } codex-core = { workspace = true } -codex-protocol = { workspace = true } +codex-app-server-protocol = { workspace = true } rand = { workspace = true } reqwest = { workspace = true, features = ["json", "blocking"] } serde = { workspace = true, features = ["derive"] } diff --git a/codex-rs/login/src/lib.rs b/codex-rs/login/src/lib.rs index d5e5836f0f..df4fc1e76a 100644 --- a/codex-rs/login/src/lib.rs +++ b/codex-rs/login/src/lib.rs @@ -9,6 +9,7 @@ pub use server::ShutdownHandle; pub use server::run_login_server; // Re-export commonly used auth types and helpers from codex-core for compatibility +pub use codex_app_server_protocol::AuthMode; pub use codex_core::AuthManager; pub use codex_core::CodexAuth; pub use codex_core::auth::AuthDotJson; @@ -20,4 +21,3 @@ pub use codex_core::auth::logout; pub use codex_core::auth::try_read_auth_json; pub use codex_core::auth::write_auth_json; pub use codex_core::token_data::TokenData; -pub use codex_protocol::mcp_protocol::AuthMode; diff --git a/codex-rs/mcp-server/src/codex_tool_runner.rs b/codex-rs/mcp-server/src/codex_tool_runner.rs index db48da28e2..bcbfdf4471 100644 --- a/codex-rs/mcp-server/src/codex_tool_runner.rs +++ b/codex-rs/mcp-server/src/codex_tool_runner.rs @@ -22,7 +22,7 @@ use codex_core::protocol::InputItem; use codex_core::protocol::Op; use codex_core::protocol::Submission; use codex_core::protocol::TaskCompleteEvent; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use mcp_types::CallToolResult; use mcp_types::ContentBlock; use mcp_types::RequestId; diff --git a/codex-rs/mcp-server/src/message_processor.rs b/codex-rs/mcp-server/src/message_processor.rs index addc9572ec..039375b05d 100644 --- a/codex-rs/mcp-server/src/message_processor.rs +++ b/codex-rs/mcp-server/src/message_processor.rs @@ -7,7 +7,7 @@ use crate::codex_tool_config::create_tool_for_codex_tool_call_param; use crate::codex_tool_config::create_tool_for_codex_tool_call_reply_param; use crate::error_code::INVALID_REQUEST_ERROR_CODE; use crate::outgoing_message::OutgoingMessageSender; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use codex_core::AuthManager; use codex_core::ConversationManager; diff --git a/codex-rs/mcp-server/src/outgoing_message.rs b/codex-rs/mcp-server/src/outgoing_message.rs index 2e350dd9a9..4b6782d8de 100644 --- a/codex-rs/mcp-server/src/outgoing_message.rs +++ b/codex-rs/mcp-server/src/outgoing_message.rs @@ -234,8 +234,8 @@ mod tests { use anyhow::Result; use codex_core::protocol::EventMsg; use codex_core::protocol::SessionConfiguredEvent; + use codex_protocol::ConversationId; use codex_protocol::config_types::ReasoningEffort; - use codex_protocol::mcp_protocol::ConversationId; use pretty_assertions::assert_eq; use serde_json::json; use tempfile::NamedTempFile; diff --git a/codex-rs/otel/Cargo.toml b/codex-rs/otel/Cargo.toml index 610423f9cc..ea518c2e4f 100644 --- a/codex-rs/otel/Cargo.toml +++ b/codex-rs/otel/Cargo.toml @@ -4,9 +4,9 @@ name = "codex-otel" version = { workspace = true } [lib] +doctest = false name = "codex_otel" path = "src/lib.rs" -doctest = false [lints] workspace = true @@ -15,25 +15,30 @@ workspace = true # Compile-time gate for OTLP support; disabled by default. # Downstream crates can enable via `features = ["otel"]`. default = [] -otel = [ - "opentelemetry", - "opentelemetry_sdk", - "opentelemetry-otlp", - "tonic", -] +otel = ["opentelemetry", "opentelemetry_sdk", "opentelemetry-otlp", "tonic"] [dependencies] -codex-protocol = { path = "../protocol" } chrono = { workspace = true } -tracing = { workspace = true } +codex-app-server-protocol = { workspace = true } +codex-protocol = { workspace = true } +eventsource-stream = { workspace = true } opentelemetry = { workspace = true, features = ["logs"], optional = true } -opentelemetry_sdk = { workspace = true, features = ["logs", "rt-tokio"], optional = true } -opentelemetry-otlp = { workspace = true, features = ["grpc-tonic", "http-proto", "http-json", "reqwest", "reqwest-rustls"], optional = true } +opentelemetry-otlp = { workspace = true, features = [ + "grpc-tonic", + "http-proto", + "http-json", + "reqwest", + "reqwest-rustls", +], optional = true } opentelemetry-semantic-conventions = { workspace = true } -tonic = { workspace = true, optional = true } +opentelemetry_sdk = { workspace = true, features = [ + "logs", + "rt-tokio", +], optional = true } +reqwest = { workspace = true } serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } strum_macros = { workspace = true } -reqwest = { workspace = true } -eventsource-stream = { workspace = true } tokio = { workspace = true } -serde_json = { workspace = true } \ No newline at end of file +tonic = { workspace = true, optional = true } +tracing = { workspace = true } diff --git a/codex-rs/otel/src/otel_event_manager.rs b/codex-rs/otel/src/otel_event_manager.rs index 87ed6bb535..3e2ffeb7af 100644 --- a/codex-rs/otel/src/otel_event_manager.rs +++ b/codex-rs/otel/src/otel_event_manager.rs @@ -1,9 +1,9 @@ use chrono::SecondsFormat; use chrono::Utc; +use codex_app_server_protocol::AuthMode; +use codex_protocol::ConversationId; use codex_protocol::config_types::ReasoningEffort; use codex_protocol::config_types::ReasoningSummary; -use codex_protocol::mcp_protocol::AuthMode; -use codex_protocol::mcp_protocol::ConversationId; use codex_protocol::models::ResponseItem; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::InputItem; diff --git a/codex-rs/protocol-ts/Cargo.toml b/codex-rs/protocol-ts/Cargo.toml index ac24c2c51f..53f314ccbe 100644 --- a/codex-rs/protocol-ts/Cargo.toml +++ b/codex-rs/protocol-ts/Cargo.toml @@ -17,5 +17,5 @@ path = "src/main.rs" [dependencies] anyhow = { workspace = true } clap = { workspace = true, features = ["derive"] } -codex-protocol = { workspace = true } +codex-app-server-protocol = { workspace = true } ts-rs = { workspace = true } diff --git a/codex-rs/protocol-ts/src/lib.rs b/codex-rs/protocol-ts/src/lib.rs index de7189edc0..224fdd2d07 100644 --- a/codex-rs/protocol-ts/src/lib.rs +++ b/codex-rs/protocol-ts/src/lib.rs @@ -1,12 +1,12 @@ use anyhow::Context; use anyhow::Result; use anyhow::anyhow; -use codex_protocol::mcp_protocol::ClientNotification; -use codex_protocol::mcp_protocol::ClientRequest; -use codex_protocol::mcp_protocol::ServerNotification; -use codex_protocol::mcp_protocol::ServerRequest; -use codex_protocol::mcp_protocol::export_client_responses; -use codex_protocol::mcp_protocol::export_server_responses; +use codex_app_server_protocol::ClientNotification; +use codex_app_server_protocol::ClientRequest; +use codex_app_server_protocol::ServerNotification; +use codex_app_server_protocol::ServerRequest; +use codex_app_server_protocol::export_client_responses; +use codex_app_server_protocol::export_server_responses; use std::ffi::OsStr; use std::fs; use std::io::Read; diff --git a/codex-rs/protocol/Cargo.toml b/codex-rs/protocol/Cargo.toml index 990c701b42..72cf984e96 100644 --- a/codex-rs/protocol/Cargo.toml +++ b/codex-rs/protocol/Cargo.toml @@ -16,7 +16,6 @@ icu_decimal = { workspace = true } icu_locale_core = { workspace = true } mcp-types = { workspace = true } mime_guess = { workspace = true } -paste = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_with = { workspace = true, features = ["macros", "base64"] } @@ -33,7 +32,6 @@ uuid = { workspace = true, features = ["serde", "v7"] } [dev-dependencies] anyhow = { workspace = true } -pretty_assertions = { workspace = true } tempfile = { workspace = true } [package.metadata.cargo-shear] diff --git a/codex-rs/protocol/src/conversation_id.rs b/codex-rs/protocol/src/conversation_id.rs new file mode 100644 index 0000000000..687237e0ab --- /dev/null +++ b/codex-rs/protocol/src/conversation_id.rs @@ -0,0 +1,68 @@ +use std::fmt::Display; + +use serde::Deserialize; +use serde::Serialize; +use ts_rs::TS; +use uuid::Uuid; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, TS, Hash)] +#[ts(type = "string")] +pub struct ConversationId { + uuid: Uuid, +} + +impl ConversationId { + pub fn new() -> Self { + Self { + uuid: Uuid::now_v7(), + } + } + + pub fn from_string(s: &str) -> Result { + Ok(Self { + uuid: Uuid::parse_str(s)?, + }) + } +} + +impl Default for ConversationId { + fn default() -> Self { + Self::new() + } +} + +impl Display for ConversationId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.uuid) + } +} + +impl Serialize for ConversationId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.collect_str(&self.uuid) + } +} + +impl<'de> Deserialize<'de> for ConversationId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let value = String::deserialize(deserializer)?; + let uuid = Uuid::parse_str(&value).map_err(serde::de::Error::custom)?; + Ok(Self { uuid }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_conversation_id_default_is_not_zeroes() { + let id = ConversationId::default(); + assert_ne!(id.uuid, Uuid::nil()); + } +} diff --git a/codex-rs/protocol/src/lib.rs b/codex-rs/protocol/src/lib.rs index 7f746f25b7..11ab0b3fd6 100644 --- a/codex-rs/protocol/src/lib.rs +++ b/codex-rs/protocol/src/lib.rs @@ -1,6 +1,7 @@ +mod conversation_id; +pub use conversation_id::ConversationId; pub mod config_types; pub mod custom_prompts; -pub mod mcp_protocol; pub mod message_history; pub mod models; pub mod num_format; diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 01b4eb3a5a..98e218b962 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -10,10 +10,10 @@ use std::path::PathBuf; use std::str::FromStr; use std::time::Duration; +use crate::ConversationId; use crate::config_types::ReasoningEffort as ReasoningEffortConfig; use crate::config_types::ReasoningSummary as ReasoningSummaryConfig; use crate::custom_prompts::CustomPrompt; -use crate::mcp_protocol::ConversationId; use crate::message_history::HistoryEntry; use crate::models::ContentItem; use crate::models::ResponseItem; diff --git a/codex-rs/tui/Cargo.toml b/codex-rs/tui/Cargo.toml index 2e89288b02..21472d8fe9 100644 --- a/codex-rs/tui/Cargo.toml +++ b/codex-rs/tui/Cargo.toml @@ -39,6 +39,7 @@ codex-git-tooling = { workspace = true } codex-login = { workspace = true } codex-ollama = { workspace = true } codex-protocol = { workspace = true } +codex-app-server-protocol = { workspace = true } color-eyre = { workspace = true } crossterm = { workspace = true, features = ["bracketed-paste", "event-stream"] } diffy = { workspace = true } diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 9c30afdb4b..2d840a8c2c 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -16,7 +16,7 @@ use codex_core::config::persist_model_selection; use codex_core::model_family::find_family_for_model; use codex_core::protocol::TokenUsage; use codex_core::protocol_config_types::ReasoningEffort as ReasoningEffortConfig; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use color_eyre::eyre::Result; use color_eyre::eyre::WrapErr; use crossterm::event::KeyCode; @@ -451,7 +451,7 @@ mod tests { use codex_core::CodexAuth; use codex_core::ConversationManager; use codex_core::protocol::SessionConfiguredEvent; - use codex_protocol::mcp_protocol::ConversationId; + use codex_protocol::ConversationId; use ratatui::prelude::Line; use std::path::PathBuf; use std::sync::Arc; diff --git a/codex-rs/tui/src/app_backtrack.rs b/codex-rs/tui/src/app_backtrack.rs index cf03784d46..b5c1300b45 100644 --- a/codex-rs/tui/src/app_backtrack.rs +++ b/codex-rs/tui/src/app_backtrack.rs @@ -9,7 +9,7 @@ use crate::pager_overlay::Overlay; use crate::tui; use crate::tui::TuiEvent; use codex_core::protocol::ConversationPathResponseEvent; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use color_eyre::eyre::Result; use crossterm::event::KeyCode; use crossterm::event::KeyEvent; diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index da363d5dac..fecfd8e01f 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -41,7 +41,7 @@ use codex_core::protocol::TurnDiffEvent; use codex_core::protocol::UserMessageEvent; use codex_core::protocol::WebSearchBeginEvent; use codex_core::protocol::WebSearchEndEvent; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use codex_protocol::parse_command::ParsedCommand; use crossterm::event::KeyCode; use crossterm::event::KeyEvent; diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index ac8a79e3bf..34e8e3bcbe 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -34,7 +34,7 @@ use codex_core::protocol::ReviewRequest; use codex_core::protocol::StreamErrorEvent; use codex_core::protocol::TaskCompleteEvent; use codex_core::protocol::TaskStartedEvent; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use crossterm::event::KeyCode; use crossterm::event::KeyEvent; use crossterm::event::KeyModifiers; diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index 1d66251ff0..8130d64796 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -5,6 +5,7 @@ #![deny(clippy::disallowed_methods)] use app::App; pub use app::AppExitInfo; +use codex_app_server_protocol::AuthMode; use codex_core::AuthManager; use codex_core::BUILT_IN_OSS_MODEL_PROVIDER_ID; use codex_core::CodexAuth; @@ -19,7 +20,6 @@ use codex_core::protocol::AskForApproval; use codex_core::protocol::SandboxPolicy; use codex_ollama::DEFAULT_OSS_MODEL; use codex_protocol::config_types::SandboxMode; -use codex_protocol::mcp_protocol::AuthMode; use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge; use std::fs::OpenOptions; use std::path::PathBuf; diff --git a/codex-rs/tui/src/onboarding/auth.rs b/codex-rs/tui/src/onboarding/auth.rs index 2ea59a312a..cf481e6712 100644 --- a/codex-rs/tui/src/onboarding/auth.rs +++ b/codex-rs/tui/src/onboarding/auth.rs @@ -27,7 +27,7 @@ use ratatui::widgets::Paragraph; use ratatui::widgets::WidgetRef; use ratatui::widgets::Wrap; -use codex_protocol::mcp_protocol::AuthMode; +use codex_app_server_protocol::AuthMode; use std::sync::RwLock; use crate::LoginStatus; diff --git a/codex-rs/tui/src/onboarding/onboarding_screen.rs b/codex-rs/tui/src/onboarding/onboarding_screen.rs index 5806424b32..6408f237fa 100644 --- a/codex-rs/tui/src/onboarding/onboarding_screen.rs +++ b/codex-rs/tui/src/onboarding/onboarding_screen.rs @@ -11,7 +11,7 @@ use ratatui::style::Color; use ratatui::widgets::Clear; use ratatui::widgets::WidgetRef; -use codex_protocol::mcp_protocol::AuthMode; +use codex_app_server_protocol::AuthMode; use crate::LoginStatus; use crate::onboarding::auth::AuthModeWidget; diff --git a/codex-rs/tui/src/status/card.rs b/codex-rs/tui/src/status/card.rs index d983ba27c0..35f096e742 100644 --- a/codex-rs/tui/src/status/card.rs +++ b/codex-rs/tui/src/status/card.rs @@ -7,7 +7,7 @@ use codex_common::create_config_summary_entries; use codex_core::config::Config; use codex_core::protocol::SandboxPolicy; use codex_core::protocol::TokenUsage; -use codex_protocol::mcp_protocol::ConversationId; +use codex_protocol::ConversationId; use ratatui::prelude::*; use ratatui::style::Stylize; use std::collections::BTreeSet;