use std::collections::HashMap;use std::sync::Arc;use std::sync::atomic::AtomicBool;use std::sync::atomic::AtomicU64;use std::sync::atomic::Ordering;use std::time::Duration;use codex_code_mode_protocol::CellId;use codex_code_mode_protocol::CodeModeNestedToolCall;use codex_code_mode_protocol::CodeModeSession;use codex_code_mode_protocol::CodeModeSessionDelegate;use codex_code_mode_protocol::CodeModeSessionProvider;use codex_code_mode_protocol::CodeModeSessionProviderFuture;use codex_code_mode_protocol::CodeModeSessionResultFuture;use codex_code_mode_protocol::DEFAULT_EXEC_YIELD_TIME_MS;use codex_code_mode_protocol::ExecuteRequest;use codex_code_mode_protocol::ExecuteToPendingOutcome;use codex_code_mode_protocol::FunctionCallOutputContentItem;use codex_code_mode_protocol::NotificationFuture;use codex_code_mode_protocol::RuntimeResponse;use codex_code_mode_protocol::StartedCell;use codex_code_mode_protocol::ToolInvocationFuture;use codex_code_mode_protocol::WaitOutcome;use codex_code_mode_protocol::WaitRequest;use codex_code_mode_protocol::WaitToPendingOutcome;use codex_code_mode_protocol::WaitToPendingRequest;use serde_json::Value as JsonValue;use tokio::sync::Mutex;use tokio::sync::mpsc;use tokio::sync::oneshot;use tokio::task::JoinSet;use tokio_util::sync::CancellationToken;use tracing::warn;use crate::runtime::PendingRuntimeMode;use crate::runtime::RuntimeCommand;use crate::runtime::RuntimeControlCommand;use crate::runtime::RuntimeEvent;use crate::runtime::spawn_runtime;pub struct NoopCodeModeSessionDelegate;impl CodeModeSessionDelegate for NoopCodeModeSessionDelegate { fn invoke_tool<'a>( &'a self, _invocation: CodeModeNestedToolCall, cancellation_token: CancellationToken, ) -> ToolInvocationFuture<'a> { Box::pin(async move { cancellation_token.cancelled().await; Err("code mode nested tools are unavailable".to_string()) }) } fn notify<'a>( &'a self, _call_id: String, _cell_id: CellId, _text: String, _cancellation_token: CancellationToken, ) -> NotificationFuture<'a> { Box::pin(async { Ok(()) }) } fn cell_closed(&self, _cell_id: &CellId) {}}#[derive(Default)]pub struct InProcessCodeModeSessionProvider;impl CodeModeSessionProvider for InProcessCodeModeSessionProvider { fn create_session<'a>( &'a self, delegate: Arc<dyn CodeModeSessionDelegate>, ) -> CodeModeSessionProviderFuture<'a> { Box::pin(async move { let session: Arc<dyn CodeModeSession> = Arc::new(CodeModeService::with_delegate(delegate)); Ok(session) }) }}#[derive(Clone)]struct CellHandle { control_tx: mpsc::UnboundedSender<CellControlCommand>, runtime_tx: std::sync::mpsc::Sender<RuntimeCommand>, cancellation_token: CancellationToken, termination_requested: Arc<AtomicBool>,}struct Inner { stored_values: Mutex<HashMap<String, JsonValue>>, cells: Mutex<HashMap<CellId, CellHandle>>, delegate: Arc<dyn CodeModeSessionDelegate>, shutting_down: AtomicBool, next_cell_id: AtomicU64,}pub struct CodeModeService { inner: Arc<Inner>,}impl CodeModeService { pub fn new() -> Self { Self::with_delegate(Arc::new(NoopCodeModeSessionDelegate)) } pub fn with_delegate(delegate: Arc<dyn CodeModeSessionDelegate>) -> Self { Self { inner: Arc::new(Inner { stored_values: Mutex::new(HashMap::new()), cells: Mutex::new(HashMap::new()), delegate, shutting_down: AtomicBool::new(false), next_cell_id: AtomicU64::new(1), }), } } fn allocate_cell_id(&self) -> CellId { CellId::new( self.inner .next_cell_id .fetch_add(1, Ordering::Relaxed) .to_string(), ) } pub async fn execute(&self, request: ExecuteRequest) -> Result<StartedCell, String> { if self.inner.shutting_down.load(Ordering::Acquire) { return Err("code mode session is shutting down".to_string()); } let initial_yield_time_ms = request.yield_time_ms.unwrap_or(DEFAULT_EXEC_YIELD_TIME_MS); let (response_tx, response_rx) = oneshot::channel(); let cell_id = self.allocate_cell_id(); self.start_cell( cell_id.clone(), request, CellResponseSender::Runtime(response_tx), Some(initial_yield_time_ms), PendingRuntimeMode::Continue, ) .await?; Ok(StartedCell::from_result_receiver(cell_id, response_rx)) } pub async fn execute_to_pending( &self, request: ExecuteRequest, ) -> Result<ExecuteToPendingOutcome, String> { let (response_tx, response_rx) = oneshot::channel(); let cell_id = self.allocate_cell_id(); self.start_cell( cell_id, request, CellResponseSender::ExecuteToPending(response_tx), /*initial_yield_time_ms*/ None, PendingRuntimeMode::PauseUntilResumed, ) .await?; response_rx .await .map_err(|_| "exec runtime ended unexpectedly".to_string())? } async fn start_cell( &self, cell_id: CellId, request: ExecuteRequest, initial_response_tx: CellResponseSender, initial_yield_time_ms: Option<u64>, pending_mode: PendingRuntimeMode, ) -> Result<(), String> { let (event_tx, event_rx) = mpsc::unbounded_channel(); let (control_tx, control_rx) = mpsc::unbounded_channel(); let stored_values = self.inner.stored_values.lock().await.clone(); let cancellation_token = CancellationToken::new(); let (runtime_tx, runtime_control_tx, runtime_terminate_handle) = { let mut cells = self.inner.cells.lock().await; if self.inner.shutting_down.load(Ordering::Acquire) { return Err("code mode session is shutting down".to_string()); } if cells.contains_key(&cell_id) { return Err(format!("exec cell {cell_id} already exists")); } let (runtime_tx, runtime_control_tx, runtime_terminate_handle) = spawn_runtime(stored_values, request, event_tx, pending_mode)?; cells.insert( cell_id.clone(), CellHandle { control_tx, runtime_tx: runtime_tx.clone(), cancellation_token: cancellation_token.clone(), termination_requested: Arc::new(AtomicBool::new(false)), }, ); (runtime_tx, runtime_control_tx, runtime_terminate_handle) }; tokio::spawn(run_cell_control( Arc::clone(&self.inner), CellControlContext { cell_id, runtime_tx, runtime_control_tx, pending_mode, runtime_terminate_handle, cancellation_token, }, event_rx, control_rx, initial_response_tx, initial_yield_time_ms, )); Ok(()) } pub async fn wait(&self, request: WaitRequest) -> Result<WaitOutcome, String> { self.begin_wait(request).await.await } async fn begin_wait( &self, request: WaitRequest, ) -> CodeModeSessionResultFuture<'static, WaitOutcome> { let WaitRequest { cell_id, yield_time_ms, } = request; let handle = self.inner.cells.lock().await.get(&cell_id).cloned(); let Some(handle) = handle else { return missing_wait(cell_id); }; let (response_tx, response_rx) = oneshot::channel(); let control_message = CellControlCommand::Poll { yield_time_ms, response_tx, }; if handle.control_tx.send(control_message).is_err() { return missing_wait(cell_id); } wait_for_response(cell_id, response_rx) } pub async fn terminate(&self, cell_id: CellId) -> Result<WaitOutcome, String> { let handle = self.inner.cells.lock().await.get(&cell_id).cloned(); let Some(handle) = handle else { return Ok(WaitOutcome::MissingCell(missing_cell_response(cell_id))); }; if handle .termination_requested .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) .is_err() { return Err(already_terminating_error(&cell_id)); } let (response_tx, response_rx) = oneshot::channel(); if handle .control_tx .send(CellControlCommand::Terminate { response_tx }) .is_err() { handle.termination_requested.store(false, Ordering::Relaxed); return Ok(WaitOutcome::MissingCell(missing_cell_response(cell_id))); } match response_rx.await { Ok(Ok(response)) => Ok(WaitOutcome::LiveCell(response)), Ok(Err(error_text)) => Err(error_text), Err(_) => Ok(WaitOutcome::MissingCell(missing_cell_response(cell_id))), } } pub async fn wait_to_pending( &self, request: WaitToPendingRequest, ) -> Result<WaitToPendingOutcome, String> { let cell_id = request.cell_id; let handle = self.inner.cells.lock().await.get(&cell_id).cloned(); let Some(handle) = handle else { return Ok(WaitToPendingOutcome::MissingCell(missing_cell_response( cell_id, ))); }; let (response_tx, response_rx) = oneshot::channel(); if handle .control_tx .send(CellControlCommand::PollToPending { response_tx }) .is_err() { return Ok(WaitToPendingOutcome::MissingCell(missing_cell_response( cell_id, ))); } match response_rx.await { Ok(Ok(response)) => Ok(WaitToPendingOutcome::LiveCell(response)), Ok(Err(error_text)) => Err(error_text), Err(_) => Ok(WaitToPendingOutcome::MissingCell(missing_cell_response( cell_id, ))), } } pub async fn shutdown(&self) -> Result<(), String> { self.inner.shutting_down.store(true, Ordering::Release); let handles = self .inner .cells .lock() .await .values() .cloned() .collect::<Vec<_>>(); for handle in handles { handle.cancellation_token.cancel(); let (response_tx, _response_rx) = oneshot::channel(); let _ = handle .control_tx .send(CellControlCommand::Terminate { response_tx }); let _ = handle.runtime_tx.send(RuntimeCommand::Terminate); } while !self.inner.cells.lock().await.is_empty() { tokio::task::yield_now().await; } Ok(()) }}impl Default for CodeModeService { fn default() -> Self { Self::new() }}impl Drop for CodeModeService { fn drop(&mut self) { self.inner.shutting_down.store(true, Ordering::Release); if let Ok(cells) = self.inner.cells.try_lock() { for handle in cells.values() { handle.cancellation_token.cancel(); let (response_tx, _response_rx) = oneshot::channel(); let _ = handle .control_tx .send(CellControlCommand::Terminate { response_tx }); let _ = handle.runtime_tx.send(RuntimeCommand::Terminate); } } }}impl CodeModeSession for CodeModeService { fn is_alive(&self) -> bool { !self.inner.shutting_down.load(Ordering::Acquire) } fn execute<'a>( &'a self, request: ExecuteRequest, ) -> CodeModeSessionResultFuture<'a, StartedCell> { Box::pin(CodeModeService::execute(self, request)) } fn wait<'a>(&'a self, request: WaitRequest) -> CodeModeSessionResultFuture<'a, WaitOutcome> { Box::pin(CodeModeService::wait(self, request)) } fn terminate<'a>(&'a self, cell_id: CellId) -> CodeModeSessionResultFuture<'a, WaitOutcome> { Box::pin(CodeModeService::terminate(self, cell_id)) } fn shutdown<'a>(&'a self) -> CodeModeSessionResultFuture<'a, ()> { Box::pin(CodeModeService::shutdown(self)) }}enum CellControlCommand { Poll { yield_time_ms: u64, response_tx: oneshot::Sender<Result<RuntimeResponse, String>>, }, PollToPending { response_tx: oneshot::Sender<Result<ExecuteToPendingOutcome, String>>, }, Terminate { response_tx: oneshot::Sender<Result<RuntimeResponse, String>>, },}enum CellResponseSender { Runtime(oneshot::Sender<Result<RuntimeResponse, String>>), ExecuteToPending(oneshot::Sender<Result<ExecuteToPendingOutcome, String>>),}struct PendingResult { content_items: Vec<FunctionCallOutputContentItem>, error_text: Option<String>,}struct CellControlContext { cell_id: CellId, runtime_tx: std::sync::mpsc::Sender<RuntimeCommand>, runtime_control_tx: std::sync::mpsc::Sender<RuntimeControlCommand>, pending_mode: PendingRuntimeMode, runtime_terminate_handle: v8::IsolateHandle, cancellation_token: CancellationToken,}fn missing_cell_response(cell_id: CellId) -> RuntimeResponse { RuntimeResponse::Result { error_text: Some(format!("exec cell {cell_id} not found")), cell_id, content_items: Vec::new(), }}fn missing_wait(cell_id: CellId) -> CodeModeSessionResultFuture<'static, WaitOutcome> { Box::pin(async move { Ok(WaitOutcome::MissingCell(missing_cell_response(cell_id))) })}fn wait_for_response( cell_id: CellId, response_rx: oneshot::Receiver<Result<RuntimeResponse, String>>,) -> CodeModeSessionResultFuture<'static, WaitOutcome> { Box::pin(async move { match response_rx.await { Ok(Ok(response)) => Ok(WaitOutcome::LiveCell(response)), Ok(Err(error_text)) => Err(error_text), Err(_) => Ok(WaitOutcome::MissingCell(missing_cell_response(cell_id))), } })}fn busy_observer_error(cell_id: &CellId) -> String { format!("exec cell {cell_id} already has an active observer")}fn already_terminating_error(cell_id: &CellId) -> String { format!("exec cell {cell_id} is already terminating")}fn pending_result_response(cell_id: &CellId, result: PendingResult) -> RuntimeResponse { RuntimeResponse::Result { cell_id: cell_id.clone(), content_items: result.content_items, error_text: result.error_text, }}fn send_terminal_response(response_tx: CellResponseSender, response: RuntimeResponse) { match response_tx { CellResponseSender::Runtime(response_tx) => { let _ = response_tx.send(Ok(response)); } CellResponseSender::ExecuteToPending(response_tx) => { let _ = response_tx.send(Ok(ExecuteToPendingOutcome::Completed(response))); } }}fn send_termination_responses( response_tx: Option<CellResponseSender>, termination_response_tx: Option<oneshot::Sender<Result<RuntimeResponse, String>>>, response: RuntimeResponse,) { if let Some(response_tx) = response_tx { send_terminal_response(response_tx, response.clone()); } if let Some(termination_response_tx) = termination_response_tx { let _ = termination_response_tx.send(Ok(response)); }}fn send_or_buffer_result( cell_id: &CellId, result: PendingResult, response_tx: &mut Option<CellResponseSender>, pending_result: &mut Option<PendingResult>,) -> bool { if let Some(response_tx) = response_tx.take() { let response = pending_result_response(cell_id, result); send_terminal_response(response_tx, response); return true; } *pending_result = Some(result); false}fn send_yield_response( cell_id: &CellId, content_items: &mut Vec<FunctionCallOutputContentItem>, response_tx: &mut Option<CellResponseSender>,) { let Some(current_response_tx) = response_tx.take() else { return; }; match current_response_tx { CellResponseSender::Runtime(response_tx) => { let _ = response_tx.send(Ok(RuntimeResponse::Yielded { cell_id: cell_id.clone(), content_items: std::mem::take(content_items), })); } CellResponseSender::ExecuteToPending(execute_to_pending_tx) => { *response_tx = Some(CellResponseSender::ExecuteToPending(execute_to_pending_tx)); } }}async fn run_cell_control( inner: Arc<Inner>, context: CellControlContext, mut event_rx: mpsc::UnboundedReceiver<RuntimeEvent>, mut control_rx: mpsc::UnboundedReceiver<CellControlCommand>, initial_response_tx: CellResponseSender, initial_yield_time_ms: Option<u64>,) { let CellControlContext { cell_id, runtime_tx, runtime_control_tx, pending_mode, runtime_terminate_handle, cancellation_token, } = context; let mut content_items = Vec::new(); let mut pending_tool_call_ids = Vec::new(); let mut pending_result: Option<PendingResult> = None; let mut response_tx = Some(initial_response_tx); let mut termination_response_tx = None; let mut termination_requested = false; let mut runtime_closed = false; let mut yield_timer: Option<std::pin::Pin<Box<tokio::time::Sleep>>> = None; let mut notification_tasks = JoinSet::new(); let mut tool_tasks = JoinSet::new(); loop { let yield_deadline_elapsed = yield_timer .as_ref() .is_some_and(|yield_timer| yield_timer.deadline() <= tokio::time::Instant::now()); tokio::select! { biased; maybe_command = control_rx.recv() => { let Some(command) = maybe_command else { break; }; match command { CellControlCommand::Poll { yield_time_ms, response_tx: next_response_tx, } => { if let Some(result) = pending_result.take() { let _ = next_response_tx.send(Ok(pending_result_response(&cell_id, result))); break; } if response_tx.is_some() || termination_response_tx.is_some() { let _ = next_response_tx.send(Err(busy_observer_error(&cell_id))); continue; } response_tx = Some(CellResponseSender::Runtime(next_response_tx)); yield_timer = Some(Box::pin(tokio::time::sleep(Duration::from_millis(yield_time_ms)))); resume_paused_runtime(&runtime_control_tx, pending_mode); } CellControlCommand::PollToPending { response_tx: next_response_tx, } => { if let Some(result) = pending_result.take() { let response = pending_result_response(&cell_id, result); let _ = next_response_tx .send(Ok(ExecuteToPendingOutcome::Completed(response))); break; } if response_tx.is_some() || termination_response_tx.is_some() { let _ = next_response_tx.send(Err(busy_observer_error(&cell_id))); continue; } response_tx = Some(CellResponseSender::ExecuteToPending(next_response_tx)); yield_timer = None; resume_paused_runtime(&runtime_control_tx, pending_mode); } CellControlCommand::Terminate { response_tx: next_response_tx } => { if let Some(result) = pending_result.take() { let _ = next_response_tx.send(Ok(pending_result_response(&cell_id, result))); break; } if termination_response_tx.is_some() { let _ = next_response_tx.send(Err(already_terminating_error(&cell_id))); continue; } termination_response_tx = Some(next_response_tx); termination_requested = true; cancellation_token.cancel(); yield_timer = None; let _ = runtime_tx.send(RuntimeCommand::Terminate); terminate_paused_runtime(&runtime_control_tx, pending_mode); let _ = runtime_terminate_handle.terminate_execution(); if runtime_closed { finish_callbacks( &cancellation_token, &mut notification_tasks, &mut tool_tasks, CallbackCompletion::Cancel, ).await; let response = RuntimeResponse::Terminated { cell_id: cell_id.clone(), content_items: std::mem::take(&mut content_items), }; send_termination_responses( response_tx.take(), termination_response_tx.take(), response, ); break; } else { continue; } } } } _ = async { if let Some(yield_timer) = yield_timer.as_mut() { yield_timer.await; } else { std::future::pending::<()>().await; } } => { yield_timer = None; send_yield_response(&cell_id, &mut content_items, &mut response_tx); } maybe_event = async { if runtime_closed { std::future::pending::<Option<RuntimeEvent>>().await } else { event_rx.recv().await } }, if !yield_deadline_elapsed => { let Some(event) = maybe_event else { runtime_closed = true; if termination_requested { finish_callbacks( &cancellation_token, &mut notification_tasks, &mut tool_tasks, CallbackCompletion::Cancel, ).await; let response = RuntimeResponse::Terminated { cell_id: cell_id.clone(), content_items: std::mem::take(&mut content_items), }; send_termination_responses( response_tx.take(), termination_response_tx.take(), response, ); break; } if pending_result.is_none() { let result = PendingResult { content_items: std::mem::take(&mut content_items), error_text: Some("exec runtime ended unexpectedly".to_string()), }; if send_or_buffer_result( &cell_id, result, &mut response_tx, &mut pending_result, ) { break; } } continue; }; match event { RuntimeEvent::Started => { yield_timer = initial_yield_time_ms.map(|initial_yield_time_ms| { Box::pin(tokio::time::sleep(Duration::from_millis(initial_yield_time_ms))) }); } RuntimeEvent::Pending => { if let Some(current_response_tx) = response_tx.take() { match current_response_tx { CellResponseSender::Runtime(runtime_response_tx) => { response_tx = Some(CellResponseSender::Runtime(runtime_response_tx)); } CellResponseSender::ExecuteToPending(response_tx) => { let _ = response_tx.send(Ok(ExecuteToPendingOutcome::Pending { cell_id: cell_id.clone(), content_items: std::mem::take(&mut content_items), pending_tool_call_ids: std::mem::take( &mut pending_tool_call_ids, ), })); } } } } RuntimeEvent::ContentItem(item) => { content_items.push(item); } RuntimeEvent::YieldRequested => { yield_timer = None; send_yield_response(&cell_id, &mut content_items, &mut response_tx); } RuntimeEvent::Notify { call_id, text } => { let delegate = Arc::clone(&inner.delegate); let cell_id = cell_id.clone(); let cancellation_token = cancellation_token.child_token(); notification_tasks.spawn(async move { if let Err(err) = delegate .notify(call_id, cell_id.clone(), text, cancellation_token) .await { warn!( "failed to deliver code mode notification for cell {cell_id}: {err}" ); } }); } RuntimeEvent::ToolCall { id, name, kind, input, } => { if pending_mode == PendingRuntimeMode::PauseUntilResumed { pending_tool_call_ids.push(id.clone()); } let tool_call = CodeModeNestedToolCall { cell_id: cell_id.clone(), runtime_tool_call_id: id.clone(), tool_name: name, tool_kind: kind, input, }; let delegate = Arc::clone(&inner.delegate); let runtime_tx = runtime_tx.clone(); let cancellation_token = cancellation_token.child_token(); tool_tasks.spawn(async move { let response = delegate.invoke_tool(tool_call, cancellation_token).await; let command = match response { Ok(result) => RuntimeCommand::ToolResponse { id, result }, Err(error_text) => RuntimeCommand::ToolError { id, error_text }, }; let _ = runtime_tx.send(command); }); } RuntimeEvent::Result { stored_value_writes, error_text, } => { yield_timer = None; if termination_requested { finish_callbacks( &cancellation_token, &mut notification_tasks, &mut tool_tasks, CallbackCompletion::Cancel, ).await; let response = RuntimeResponse::Terminated { cell_id: cell_id.clone(), content_items: std::mem::take(&mut content_items), }; send_termination_responses( response_tx.take(), termination_response_tx.take(), response, ); break; } finish_callbacks( &cancellation_token, &mut notification_tasks, &mut tool_tasks, CallbackCompletion::DrainNotifications, ).await; inner .stored_values .lock() .await .extend(stored_value_writes); let result = PendingResult { content_items: std::mem::take(&mut content_items), error_text, }; if send_or_buffer_result( &cell_id, result, &mut response_tx, &mut pending_result, ) { break; } } } } task_result = notification_tasks.join_next(), if !notification_tasks.is_empty() => { if let Some(Err(err)) = task_result && !err.is_cancelled() { warn!("code mode notification task failed: {err}"); } } task_result = tool_tasks.join_next(), if !tool_tasks.is_empty() => { if let Some(Err(err)) = task_result && !err.is_cancelled() { warn!("code mode tool task failed: {err}"); } } } } let _ = runtime_tx.send(RuntimeCommand::Terminate); cancellation_token.cancel(); finish_callbacks( &cancellation_token, &mut notification_tasks, &mut tool_tasks, CallbackCompletion::Cancel, ) .await; terminate_paused_runtime(&runtime_control_tx, pending_mode); inner.cells.lock().await.remove(&cell_id); inner.delegate.cell_closed(&cell_id);}#[derive(Clone, Copy)]enum CallbackCompletion { DrainNotifications, Cancel,}async fn finish_callbacks( cancellation_token: &CancellationToken, notification_tasks: &mut JoinSet<()>, tool_tasks: &mut JoinSet<()>, completion: CallbackCompletion,) { if matches!(completion, CallbackCompletion::Cancel) { cancellation_token.cancel(); } drain_tasks(notification_tasks, "notification").await; cancellation_token.cancel(); drain_tasks(tool_tasks, "tool").await;}async fn drain_tasks(tasks: &mut JoinSet<()>, description: &str) { while let Some(result) = tasks.join_next().await { if let Err(err) = result && !err.is_cancelled() { warn!("code mode {description} task failed: {err}"); } }}fn resume_paused_runtime( runtime_control_tx: &std::sync::mpsc::Sender<RuntimeControlCommand>, pending_mode: PendingRuntimeMode,) { if pending_mode == PendingRuntimeMode::PauseUntilResumed { let _ = runtime_control_tx.send(RuntimeControlCommand::Resume); }}fn terminate_paused_runtime( runtime_control_tx: &std::sync::mpsc::Sender<RuntimeControlCommand>, pending_mode: PendingRuntimeMode,) { if pending_mode == PendingRuntimeMode::PauseUntilResumed { let _ = runtime_control_tx.send(RuntimeControlCommand::Terminate); }}#[cfg(test)]mod tests { use std::collections::HashMap; use std::sync::Arc; use std::sync::atomic::AtomicU64; use std::sync::atomic::Ordering; use std::time::Duration; use codex_protocol::ToolName; use pretty_assertions::assert_eq; use tokio::sync::Mutex; use tokio::sync::mpsc; use tokio::sync::oneshot; use super::CellControlCommand; use super::CellControlContext; use super::CellId; use super::CellResponseSender; use super::CodeModeService; use super::Inner; use super::NoopCodeModeSessionDelegate; use super::PendingRuntimeMode; use super::RuntimeCommand; use super::RuntimeResponse; use super::WaitOutcome; use super::WaitRequest; use super::WaitToPendingOutcome; use super::WaitToPendingRequest; use super::run_cell_control; use crate::CodeModeToolKind; use crate::ExecuteRequest; use crate::ExecuteToPendingOutcome; use crate::FunctionCallOutputContentItem; use crate::ToolDefinition; use crate::runtime::RuntimeEvent; use crate::runtime::spawn_runtime; fn execute_request(source: &str) -> ExecuteRequest { ExecuteRequest { tool_call_id: "call_1".to_string(), enabled_tools: Vec::new(), source: source.to_string(), yield_time_ms: Some(1), max_output_tokens: None, } } fn cell_id(value: &str) -> CellId { CellId::new(value.to_string()) } async fn execute(service: &CodeModeService, request: ExecuteRequest) -> RuntimeResponse { service .execute(request) .await .unwrap() .initial_response() .await .unwrap() } fn test_inner() -> Arc<Inner> { Arc::new(Inner { stored_values: Mutex::new(HashMap::new()), cells: Mutex::new(HashMap::new()), delegate: Arc::new(NoopCodeModeSessionDelegate), shutting_down: std::sync::atomic::AtomicBool::new(false), next_cell_id: AtomicU64::new(1), }) } #[tokio::test] async fn synchronous_exit_returns_successfully() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"text("before"); exit(); text("after");"#.to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "before".to_string(), }], error_text: None, } ); } #[tokio::test] async fn stored_values_are_shared_between_cells_but_not_sessions() { let first_session = CodeModeService::new(); let second_session = CodeModeService::new(); let write_response = execute( &first_session, ExecuteRequest { source: r#"store("key", "visible");"#.to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; let same_session = execute( &first_session, ExecuteRequest { source: r#"text(String(load("key")));"#.to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; let other_session = execute( &second_session, ExecuteRequest { source: r#"text(String(load("key")));"#.to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( write_response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: Vec::new(), error_text: None, } ); assert_eq!( same_session, RuntimeResponse::Result { cell_id: cell_id("2"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "visible".to_string(), }], error_text: None, } ); assert_eq!( other_session, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "undefined".to_string(), }], error_text: None, } ); } #[tokio::test] async fn shutdown_interrupts_cpu_bound_cells() { let service = CodeModeService::new(); let cell = service .execute(ExecuteRequest { source: "while (true) {}".to_string(), ..execute_request("") }) .await .unwrap(); assert_eq!( cell.initial_response().await.unwrap(), RuntimeResponse::Yielded { cell_id: cell_id("1"), content_items: Vec::new(), } ); tokio::time::timeout(Duration::from_secs(1), service.shutdown()) .await .unwrap() .unwrap(); } #[tokio::test] async fn start_cell_rejects_new_cell_after_shutdown_begins() { let service = CodeModeService::new(); service.inner.shutting_down.store(true, Ordering::Release); let (response_tx, _response_rx) = oneshot::channel(); let error = service .start_cell( cell_id("late-cell"), execute_request(""), CellResponseSender::Runtime(response_tx), Some(/*initial_yield_time_ms*/ 1), PendingRuntimeMode::Continue, ) .await .unwrap_err(); assert_eq!(error, "code mode session is shutting down".to_string()); assert!(service.inner.cells.lock().await.is_empty()); } #[tokio::test] async fn execute_to_pending_returns_completed_for_synchronous_results() { let service = CodeModeService::new(); let response = service .execute_to_pending(ExecuteRequest { source: r#"text("done");"#.to_string(), yield_time_ms: Some(60_000), ..execute_request("") }) .await .unwrap(); assert_eq!( response, ExecuteToPendingOutcome::Completed(RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "done".to_string(), }], error_text: None, }) ); } #[tokio::test] async fn execute_to_pending_returns_once_the_runtime_is_quiescent() { let service = CodeModeService::new(); let response = tokio::time::timeout( Duration::from_secs(1), service.execute_to_pending(ExecuteRequest { source: r#"text("before"); await new Promise(() => {});"#.to_string(), yield_time_ms: Some(60_000), ..execute_request("") }), ) .await .unwrap() .unwrap(); assert_eq!( response, ExecuteToPendingOutcome::Pending { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "before".to_string(), }], pending_tool_call_ids: Vec::new(), } ); let termination = service.terminate(cell_id("1")).await.unwrap(); assert_eq!( termination, WaitOutcome::LiveCell(RuntimeResponse::Terminated { cell_id: cell_id("1"), content_items: Vec::new(), }) ); } #[tokio::test] async fn execute_to_pending_identifies_tool_calls_in_paused_frontier() { let service = CodeModeService::new(); let response = service .execute_to_pending(ExecuteRequest { enabled_tools: vec![ToolDefinition { name: "echo".to_string(), tool_name: ToolName::plain("echo"), description: String::new(), kind: CodeModeToolKind::Function, input_schema: None, output_schema: None, }], source: r#"await Promise.all([ tools.echo({ value: "first" }), tools.echo({ value: "second" }),]);"# .to_string(), yield_time_ms: Some(60_000), ..execute_request("") }) .await .unwrap(); assert_eq!( response, ExecuteToPendingOutcome::Pending { cell_id: cell_id("1"), content_items: Vec::new(), pending_tool_call_ids: vec!["tool-1".to_string(), "tool-2".to_string()], } ); let termination = service.terminate(cell_id("1")).await.unwrap(); assert_eq!( termination, WaitOutcome::LiveCell(RuntimeResponse::Terminated { cell_id: cell_id("1"), content_items: Vec::new(), }) ); } #[tokio::test] async fn execute_to_pending_excludes_delayed_timeout_tool_calls_until_wait() { let service = CodeModeService::new(); let initial_response = service .execute_to_pending(ExecuteRequest { enabled_tools: vec![ToolDefinition { name: "echo".to_string(), tool_name: ToolName::plain("echo"), description: String::new(), kind: CodeModeToolKind::Function, input_schema: None, output_schema: None, }], source: r#"setTimeout(() => { tools.echo({ value: "delayed" });}, 1000);await Promise.all([ tools.echo({ value: "second" }), tools.echo({ value: "third" }),]);"# .to_string(), yield_time_ms: Some(60_000), ..execute_request("") }) .await .unwrap(); assert_eq!( initial_response, ExecuteToPendingOutcome::Pending { cell_id: cell_id("1"), content_items: Vec::new(), pending_tool_call_ids: vec!["tool-1".to_string(), "tool-2".to_string()], } ); let runtime_tx = service .inner .cells .lock() .await .get(&cell_id("1")) .unwrap() .runtime_tx .clone(); runtime_tx .send(RuntimeCommand::TimeoutFired { id: 1 }) .unwrap(); let resumed_response = tokio::time::timeout( Duration::from_secs(1), service.wait_to_pending(WaitToPendingRequest { cell_id: cell_id("1"), }), ) .await .unwrap() .unwrap(); assert_eq!( resumed_response, WaitToPendingOutcome::LiveCell(ExecuteToPendingOutcome::Pending { cell_id: cell_id("1"), content_items: Vec::new(), pending_tool_call_ids: vec!["tool-3".to_string()], }) ); let termination = service.terminate(cell_id("1")).await.unwrap(); assert_eq!( termination, WaitOutcome::LiveCell(RuntimeResponse::Terminated { cell_id: cell_id("1"), content_items: Vec::new(), }) ); } #[tokio::test] async fn wait_to_pending_returns_after_resumed_runtime_becomes_quiescent_again() { let service = CodeModeService::new(); let initial_response = service .execute_to_pending(ExecuteRequest { source: r#"await new Promise((resolve) => setTimeout(resolve, 60_000));text("after");await new Promise(() => {});"# .to_string(), yield_time_ms: Some(60_000), ..execute_request("") }) .await .unwrap(); assert_eq!( initial_response, ExecuteToPendingOutcome::Pending { cell_id: cell_id("1"), content_items: Vec::new(), pending_tool_call_ids: Vec::new(), } ); let runtime_tx = service .inner .cells .lock() .await .get(&cell_id("1")) .unwrap() .runtime_tx .clone(); runtime_tx .send(RuntimeCommand::TimeoutFired { id: 1 }) .unwrap(); let resumed_response = tokio::time::timeout( Duration::from_secs(1), service.wait_to_pending(WaitToPendingRequest { cell_id: cell_id("1"), }), ) .await .unwrap() .unwrap(); assert_eq!( resumed_response, WaitToPendingOutcome::LiveCell(ExecuteToPendingOutcome::Pending { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "after".to_string(), }], pending_tool_call_ids: Vec::new(), }) ); let termination = service.terminate(cell_id("1")).await.unwrap(); assert_eq!( termination, WaitOutcome::LiveCell(RuntimeResponse::Terminated { cell_id: cell_id("1"), content_items: Vec::new(), }) ); } #[tokio::test] async fn wait_to_pending_returns_completed_after_resumed_runtime_finishes() { let service = CodeModeService::new(); let initial_response = service .execute_to_pending(ExecuteRequest { source: r#"await new Promise((resolve) => setTimeout(resolve, 60_000));text("done");"# .to_string(), yield_time_ms: Some(60_000), ..execute_request("") }) .await .unwrap(); assert_eq!( initial_response, ExecuteToPendingOutcome::Pending { cell_id: cell_id("1"), content_items: Vec::new(), pending_tool_call_ids: Vec::new(), } ); let runtime_tx = service .inner .cells .lock() .await .get(&cell_id("1")) .unwrap() .runtime_tx .clone(); runtime_tx .send(RuntimeCommand::TimeoutFired { id: 1 }) .unwrap(); let resumed_response = tokio::time::timeout( Duration::from_secs(1), service.wait_to_pending(WaitToPendingRequest { cell_id: cell_id("1"), }), ) .await .unwrap() .unwrap(); assert_eq!( resumed_response, WaitToPendingOutcome::LiveCell(ExecuteToPendingOutcome::Completed( RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "done".to_string(), }], error_text: None, } )) ); } #[tokio::test] async fn v8_console_is_not_exposed_on_global_this() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"text(String(Object.hasOwn(globalThis, "console")));"#.to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "false".to_string(), }], error_text: None, } ); } #[tokio::test] async fn date_locale_string_formats_with_icu_data() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"const value = new Date("2025-01-02T03:04:05Z") .toLocaleString("fr-FR", { weekday: "long", month: "long", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, timeZone: "UTC", });text(value);"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "jeudi 2 janvier \u{e0} 03:04:05".to_string(), }], error_text: None, } ); } #[tokio::test] async fn intl_date_time_format_formats_with_icu_data() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"const formatter = new Intl.DateTimeFormat("fr-FR", { weekday: "long", month: "long", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, timeZone: "UTC",});text(formatter.format(new Date("2025-01-02T03:04:05Z")));"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputText { text: "jeudi 2 janvier \u{e0} 03:04:05".to_string(), }], error_text: None, } ); } #[tokio::test] async fn output_helpers_return_undefined() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"const returnsUndefined = [ text("first"), image("data:image/png;base64,AAA"), notify("ping"),].map((value) => value === undefined);text(JSON.stringify(returnsUndefined));"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![ FunctionCallOutputContentItem::InputText { text: "first".to_string(), }, FunctionCallOutputContentItem::InputImage { image_url: "data:image/png;base64,AAA".to_string(), detail: Some(crate::DEFAULT_IMAGE_DETAIL), }, FunctionCallOutputContentItem::InputText { text: "[true,true,true]".to_string(), }, ], error_text: None, } ); } #[tokio::test] async fn image_helper_accepts_raw_mcp_image_block_with_original_detail() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"image({ type: "image", data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==", mimeType: "image/png", _meta: { "codex/imageDetail": "original" },});"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputImage { image_url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==".to_string(), detail: Some(crate::ImageDetail::Original), }], error_text: None, } ); } #[tokio::test] async fn generated_image_helper_appends_image_and_output_hint() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"generatedImage({ image_url: "data:image/png;base64,AAA", output_hint: "generated image save hint",});"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![ FunctionCallOutputContentItem::InputImage { image_url: "data:image/png;base64,AAA".to_string(), detail: Some(crate::DEFAULT_IMAGE_DETAIL), }, FunctionCallOutputContentItem::InputText { text: "generated image save hint".to_string(), }, ], error_text: None, } ); } #[tokio::test] async fn image_helper_second_arg_overrides_explicit_object_detail() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"image( { image_url: "data:image/png;base64,AAA", detail: "high", }, "original",);"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputImage { image_url: "data:image/png;base64,AAA".to_string(), detail: Some(crate::ImageDetail::Original), }], error_text: None, } ); } #[tokio::test] async fn image_helper_second_arg_overrides_raw_mcp_image_detail() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"image( { type: "image", data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==", mimeType: "image/png", _meta: { "codex/imageDetail": "original" }, }, "high",);"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputImage { image_url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==".to_string(), detail: Some(crate::ImageDetail::High), }], error_text: None, } ); } #[tokio::test] async fn image_helper_accepts_low_detail() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"image({ image_url: "data:image/png;base64,AAA", detail: "low",});"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: vec![FunctionCallOutputContentItem::InputImage { image_url: "data:image/png;base64,AAA".to_string(), detail: Some(crate::ImageDetail::Low), }], error_text: None, } ); } #[tokio::test] async fn image_helpers_reject_remote_urls() { for image_url in [ "http://example.com/image.jpg", "https://example.com/image.jpg", ] { for source in [ format!("image({image_url:?});"), format!("generatedImage({{ image_url: {image_url:?} }});"), ] { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source, yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: Vec::new(), error_text: Some( "Tool call failed: remote image URLs are not supported in tool outputs. Pass a base64 data URI instead".to_string(), ), } ); } } } #[tokio::test] async fn image_helper_rejects_unsupported_detail() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"image({ image_url: "data:image/png;base64,AAA", detail: "medium",});"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: Vec::new(), error_text: Some( "image detail must be one of: auto, low, high, original".to_string() ), } ); } #[tokio::test] async fn image_helper_rejects_raw_mcp_result_container() { let service = CodeModeService::new(); let response = execute( &service, ExecuteRequest { source: r#"image({ content: [ { type: "image", data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==", mimeType: "image/png", _meta: { "codex/imageDetail": "original" }, }, ], isError: false,});"# .to_string(), yield_time_ms: None, ..execute_request("") }, ) .await; assert_eq!( response, RuntimeResponse::Result { cell_id: cell_id("1"), content_items: Vec::new(), error_text: Some( "image expects a non-empty image URL string, an object with image_url and optional detail, or a raw MCP image block".to_string(), ), } ); } #[tokio::test] async fn wait_reports_missing_cell_separately_from_runtime_results() { let service = CodeModeService::new(); let response = service .wait(WaitRequest { cell_id: cell_id("missing"), yield_time_ms: 1, }) .await .unwrap(); assert_eq!( response, WaitOutcome::MissingCell(RuntimeResponse::Result { cell_id: cell_id("missing"), content_items: Vec::new(), error_text: Some("exec cell missing not found".to_string()), }) ); } #[tokio::test] async fn terminate_waits_for_runtime_shutdown_before_responding() { let inner = test_inner(); let (event_tx, event_rx) = mpsc::unbounded_channel(); let (control_tx, control_rx) = mpsc::unbounded_channel(); let (initial_response_tx, initial_response_rx) = oneshot::channel(); let (runtime_event_tx, _runtime_event_rx) = mpsc::unbounded_channel(); let (runtime_tx, runtime_control_tx, runtime_terminate_handle) = spawn_runtime( HashMap::new(), ExecuteRequest { source: "await new Promise(() => {})".to_string(), yield_time_ms: None, ..execute_request("") }, runtime_event_tx, PendingRuntimeMode::Continue, ) .unwrap(); tokio::spawn(run_cell_control( inner, CellControlContext { cell_id: cell_id("cell-1"), runtime_tx: runtime_tx.clone(), runtime_control_tx, pending_mode: PendingRuntimeMode::Continue, runtime_terminate_handle, cancellation_token: tokio_util::sync::CancellationToken::new(), }, event_rx, control_rx, CellResponseSender::Runtime(initial_response_tx), Some(/*initial_yield_time_ms*/ 60_000), )); event_tx.send(RuntimeEvent::Started).unwrap(); event_tx.send(RuntimeEvent::YieldRequested).unwrap(); assert_eq!( initial_response_rx.await.unwrap(), Ok(RuntimeResponse::Yielded { cell_id: cell_id("cell-1"), content_items: Vec::new(), }) ); let (terminate_response_tx, terminate_response_rx) = oneshot::channel(); control_tx .send(CellControlCommand::Terminate { response_tx: terminate_response_tx, }) .unwrap(); let terminate_response = async { terminate_response_rx.await.unwrap() }; tokio::pin!(terminate_response); assert!( tokio::time::timeout(Duration::from_millis(100), terminate_response.as_mut()) .await .is_err() ); drop(event_tx); assert_eq!( terminate_response.await, Ok(RuntimeResponse::Terminated { cell_id: cell_id("cell-1"), content_items: Vec::new(), }) ); let _ = runtime_tx.send(RuntimeCommand::Terminate); }}#[cfg(test)]#[path = "service_contract_tests.rs"]mod contract_tests;