use std::fmt; use std::future::Future; use std::pin::Pin; use std::sync::Arc; use serde::Deserialize; use serde::Serialize; use serde_json::Value as JsonValue; use tokio::sync::oneshot; use tokio_util::sync::CancellationToken; use crate::CodeModeNestedToolCall; use crate::ExecuteRequest; use crate::RuntimeResponse; use crate::WaitOutcome; use crate::WaitRequest; pub type CodeModeSessionResultFuture<'a, T> = Pin> + Send + 'a>>; pub type CodeModeSessionProviderFuture<'a> = CodeModeSessionResultFuture<'a, Arc>; pub type ToolInvocationFuture<'a> = Pin> + Send + 'a>>; pub type NotificationFuture<'a> = Pin> + Send + 'a>>; #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct CellId(String); impl CellId { pub fn new(value: String) -> Self { Self(value) } pub fn as_str(&self) -> &str { &self.0 } } impl AsRef for CellId { fn as_ref(&self) -> &str { self.as_str() } } impl fmt::Display for CellId { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str(self.as_str()) } } pub struct StartedCell { pub cell_id: CellId, initial_response: CodeModeSessionResultFuture<'static, RuntimeResponse>, } impl StartedCell { pub fn new(cell_id: CellId, initial_response_rx: oneshot::Receiver) -> Self { Self { cell_id, initial_response: Box::pin(async move { initial_response_rx .await .map_err(|_| "exec runtime ended unexpectedly".to_string()) }), } } pub fn from_result_receiver( cell_id: CellId, initial_response_rx: oneshot::Receiver>, ) -> Self { Self { cell_id, initial_response: Box::pin(async move { initial_response_rx .await .map_err(|_| "exec runtime ended unexpectedly".to_string())? }), } } pub async fn initial_response(self) -> Result { self.initial_response.await } } /// Host callbacks used by a code-mode session while cells are executing. pub trait CodeModeSessionDelegate: Send + Sync { fn invoke_tool<'a>( &'a self, invocation: CodeModeNestedToolCall, cancellation_token: CancellationToken, ) -> ToolInvocationFuture<'a>; fn notify<'a>( &'a self, call_id: String, cell_id: CellId, text: String, cancellation_token: CancellationToken, ) -> NotificationFuture<'a>; /// Releases delegate state associated with a cell after it reaches a terminal state. fn cell_closed(&self, cell_id: &CellId); } /// A durable code-mode session owned by one Codex thread. /// /// Cells executed in the same session share stored values. Separate sessions /// must keep those values isolated. Implementations may execute cells /// in-process or remotely. pub trait CodeModeSession: Send + Sync { fn execute<'a>( &'a self, request: ExecuteRequest, ) -> CodeModeSessionResultFuture<'a, StartedCell>; fn wait<'a>(&'a self, request: WaitRequest) -> CodeModeSessionResultFuture<'a, WaitOutcome>; fn terminate<'a>(&'a self, cell_id: CellId) -> CodeModeSessionResultFuture<'a, WaitOutcome>; fn shutdown<'a>(&'a self) -> CodeModeSessionResultFuture<'a, ()>; } /// Creates code-mode sessions for Codex threads. /// /// Implementations may share a remote host process across all sessions created /// by one provider. pub trait CodeModeSessionProvider: Send + Sync { fn create_session<'a>( &'a self, delegate: Arc, ) -> CodeModeSessionProviderFuture<'a>; } #[cfg(test)] #[path = "session_tests.rs"] mod tests;