diff --git a/codex-rs/cli/src/proto.rs b/codex-rs/cli/src/proto.rs index ec395dd108..e22b7a690f 100644 --- a/codex-rs/cli/src/proto.rs +++ b/codex-rs/cli/src/proto.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use clap::Parser; use codex_common::CliConfigOverrides; use codex_core::Codex; +use codex_core::CodexConversation; use codex_core::config::Config; use codex_core::config::ConfigOverrides; use codex_core::protocol::Submission; @@ -35,7 +36,7 @@ pub async fn run_main(opts: ProtoCli) -> anyhow::Result<()> { let config = Config::load_with_cli_overrides(overrides_vec, ConfigOverrides::default())?; let ctrl_c = notify_on_sigint(); - let (codex, _init_id, _session_id) = Codex::spawn(config, ctrl_c.clone()).await?; + let CodexConversation { codex, .. } = Codex::spawn(config, ctrl_c.clone()).await?; let codex = Arc::new(codex); // Task that reads JSON lines from stdin and forwards to Submission Queue diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index f35348b779..189f64c3b2 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -96,11 +96,22 @@ pub struct Codex { rx_event: Receiver, } +/// Wrapper returned by [`Codex::spawn`] containing the spawned [`Codex`], +/// the submission id for the initial `ConfigureSession` request and the +/// unique session id. +pub struct CodexConversation { + pub codex: Codex, + pub init_id: String, + pub session_id: Uuid, +} + impl Codex { - /// Spawn a new [`Codex`] and initialize the session. Returns the instance - /// of `Codex` and the ID of the `SessionInitialized` event that was - /// submitted to start the session. - pub async fn spawn(config: Config, ctrl_c: Arc) -> CodexResult<(Codex, String, Uuid)> { + /// Spawn a new [`Codex`] and initialize the session. + /// + /// Returns a [`CodexConversation`] containing the [`Codex`] instance, + /// the submission id of the initial `ConfigureSession` request and the + /// unique session id. + pub async fn spawn(config: Config, ctrl_c: Arc) -> CodexResult { // experimental resume path (undocumented) let resume_path = config.experimental_resume.clone(); info!("resume_path: {resume_path:?}"); @@ -138,7 +149,11 @@ impl Codex { }; let init_id = codex.submit(configure_session).await?; - Ok((codex, init_id, session_id)) + Ok(CodexConversation { + codex, + init_id, + session_id, + }) } /// Submit the `op` wrapped in a `Submission` with a unique ID. diff --git a/codex-rs/core/src/codex_wrapper.rs b/codex-rs/core/src/codex_wrapper.rs index 31f8295ed4..65d851cb10 100644 --- a/codex-rs/core/src/codex_wrapper.rs +++ b/codex-rs/core/src/codex_wrapper.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use crate::Codex; +use crate::CodexConversation; use crate::config::Config; use crate::protocol::Event; use crate::protocol::EventMsg; @@ -15,7 +16,11 @@ use uuid::Uuid; /// that callers can surface the information to the UI. pub async fn init_codex(config: Config) -> anyhow::Result<(Codex, Event, Arc, Uuid)> { let ctrl_c = notify_on_sigint(); - let (codex, init_id, session_id) = Codex::spawn(config, ctrl_c.clone()).await?; + let CodexConversation { + codex, + init_id, + session_id, + } = Codex::spawn(config, ctrl_c.clone()).await?; // The first event must be `SessionInitialized`. Validate and forward it to // the caller so that they can display it in the conversation history. diff --git a/codex-rs/core/src/lib.rs b/codex-rs/core/src/lib.rs index 12321e0abc..876d76a816 100644 --- a/codex-rs/core/src/lib.rs +++ b/codex-rs/core/src/lib.rs @@ -11,6 +11,7 @@ mod client; mod client_common; pub mod codex; pub use codex::Codex; +pub use codex::CodexConversation; pub mod codex_wrapper; pub mod config; pub mod config_profile; diff --git a/codex-rs/core/tests/client.rs b/codex-rs/core/tests/client.rs index cb60fb216f..c50a98a6bd 100644 --- a/codex-rs/core/tests/client.rs +++ b/codex-rs/core/tests/client.rs @@ -1,4 +1,5 @@ use codex_core::Codex; +use codex_core::CodexConversation; use codex_core::ModelProviderInfo; use codex_core::exec::CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR; use codex_core::protocol::EventMsg; @@ -72,7 +73,7 @@ async fn includes_session_id_and_model_headers_in_request() { let mut config = load_default_config_for_test(&codex_home); config.model_provider = model_provider; let ctrl_c = std::sync::Arc::new(tokio::sync::Notify::new()); - let (codex, _init_id, _session_id) = Codex::spawn(config, ctrl_c.clone()).await.unwrap(); + let CodexConversation { codex, .. } = Codex::spawn(config, ctrl_c.clone()).await.unwrap(); codex .submit(Op::UserInput { @@ -148,7 +149,7 @@ async fn includes_base_instructions_override_in_request() { config.model_provider = model_provider; let ctrl_c = std::sync::Arc::new(tokio::sync::Notify::new()); - let (codex, ..) = Codex::spawn(config, ctrl_c.clone()).await.unwrap(); + let CodexConversation { codex, .. } = Codex::spawn(config, ctrl_c.clone()).await.unwrap(); codex .submit(Op::UserInput { diff --git a/codex-rs/core/tests/live_agent.rs b/codex-rs/core/tests/live_agent.rs index 9d81225b9f..ded8334d73 100644 --- a/codex-rs/core/tests/live_agent.rs +++ b/codex-rs/core/tests/live_agent.rs @@ -20,6 +20,7 @@ use std::time::Duration; use codex_core::Codex; +use codex_core::CodexConversation; use codex_core::error::CodexErr; use codex_core::protocol::AgentMessageEvent; use codex_core::protocol::ErrorEvent; @@ -48,7 +49,7 @@ async fn spawn_codex() -> Result { let mut config = load_default_config_for_test(&codex_home); config.model_provider.request_max_retries = Some(2); config.model_provider.stream_max_retries = Some(2); - let (agent, _init_id, _session_id) = + let CodexConversation { codex: agent, .. } = Codex::spawn(config, std::sync::Arc::new(Notify::new())).await?; Ok(agent) diff --git a/codex-rs/core/tests/stream_no_completed.rs b/codex-rs/core/tests/stream_no_completed.rs index 153330bf10..cfc80154ba 100644 --- a/codex-rs/core/tests/stream_no_completed.rs +++ b/codex-rs/core/tests/stream_no_completed.rs @@ -4,6 +4,7 @@ use std::time::Duration; use codex_core::Codex; +use codex_core::CodexConversation; use codex_core::ModelProviderInfo; use codex_core::exec::CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR; use codex_core::protocol::EventMsg; @@ -94,7 +95,7 @@ async fn retries_on_early_close() { let codex_home = TempDir::new().unwrap(); let mut config = load_default_config_for_test(&codex_home); config.model_provider = model_provider; - let (codex, _init_id, _session_id) = Codex::spawn(config, ctrl_c).await.unwrap(); + let CodexConversation { codex, .. } = Codex::spawn(config, ctrl_c).await.unwrap(); codex .submit(Op::UserInput {