Download codex-rs/code-mode-runtime/src/runtime/mod.rs from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 18.4 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/code-mode-runtime/src/runtime/mod.rs
- Command line
-
hf download hf://SaylorTwift/codex/codex-rs/code-mode-runtime/src/runtime/mod.rs
-
curl -L -o mod.rs https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/code-mode-runtime/src/runtime/mod.rs
18.4 kB
| mod audio; | |
| mod callbacks; | |
| mod globals; | |
| mod module_loader; | |
| mod timers; | |
| mod value; | |
| use std::collections::HashMap; | |
| use std::panic::AssertUnwindSafe; | |
| use std::panic::catch_unwind; | |
| use std::sync::mpsc as std_mpsc; | |
| use std::thread; | |
| use codex_code_mode_protocol::CodeModeToolKind; | |
| use codex_code_mode_protocol::EnabledToolMetadata; | |
| use codex_code_mode_protocol::ExecuteRequest; | |
| use codex_code_mode_protocol::FunctionCallOutputContentItem; | |
| use codex_code_mode_protocol::enabled_tool_metadata; | |
| use codex_protocol::ToolName; | |
| use serde_json::Value as JsonValue; | |
| use tokio::sync::mpsc; | |
| use crate::TaskFailureHandler; | |
| use crate::v8_init::ensure_v8_initialized; | |
| const EXIT_SENTINEL: &str = "__codex_code_mode_exit__"; | |
| pub(crate) enum RuntimeCommand { | |
| ToolResponse { id: String, result: JsonValue }, | |
| ToolError { id: String, error_text: String }, | |
| TimeoutFired { id: u64 }, | |
| ObservePendingFrontier, | |
| Terminate, | |
| } | |
| pub(crate) enum PendingRuntimeMode { | |
| Continue, | |
| PauseUntilResumed, | |
| } | |
| pub(crate) enum RuntimeControlCommand { | |
| Continue, | |
| Resume, | |
| Terminate, | |
| } | |
| pub(crate) enum RuntimeEvent { | |
| Started, | |
| Pending, | |
| ContentItem(FunctionCallOutputContentItem), | |
| YieldRequested, | |
| ToolCall { | |
| id: String, | |
| name: ToolName, | |
| kind: CodeModeToolKind, | |
| input: Option<JsonValue>, | |
| }, | |
| Notify { | |
| call_id: String, | |
| text: String, | |
| }, | |
| Result { | |
| stored_value_writes: HashMap<String, JsonValue>, | |
| error_text: Option<String>, | |
| }, | |
| ThreadPanicked, | |
| } | |
| pub(crate) fn spawn_runtime( | |
| stored_values: HashMap<String, JsonValue>, | |
| request: ExecuteRequest, | |
| event_tx: mpsc::UnboundedSender<RuntimeEvent>, | |
| pending_mode: PendingRuntimeMode, | |
| task_failure_handler: Option<TaskFailureHandler>, | |
| ) -> Result< | |
| ( | |
| std_mpsc::Sender<RuntimeCommand>, | |
| std_mpsc::Sender<RuntimeControlCommand>, | |
| v8::IsolateHandle, | |
| ), | |
| String, | |
| > { | |
| ensure_v8_initialized()?; | |
| let (command_tx, command_rx) = std_mpsc::channel(); | |
| let (control_tx, control_rx) = std_mpsc::channel(); | |
| let runtime_command_tx = command_tx.clone(); | |
| let (isolate_handle_tx, isolate_handle_rx) = std_mpsc::sync_channel(1); | |
| let enabled_tools = request | |
| .enabled_tools | |
| .iter() | |
| .map(enabled_tool_metadata) | |
| .collect::<Vec<_>>(); | |
| let config = RuntimeConfig { | |
| tool_call_id: request.tool_call_id, | |
| enabled_tools, | |
| source: request.source, | |
| stored_values, | |
| }; | |
| let runtime_handle = tokio::runtime::Handle::current(); | |
| spawn_supervised_runtime_thread(event_tx.clone(), task_failure_handler, move || { | |
| let _runtime_guard = runtime_handle.enter(); | |
| run_runtime( | |
| config, | |
| event_tx, | |
| command_rx, | |
| control_rx, | |
| pending_mode, | |
| isolate_handle_tx, | |
| runtime_command_tx, | |
| ); | |
| }); | |
| let isolate_handle = isolate_handle_rx | |
| .recv() | |
| .map_err(|_| "failed to initialize code mode runtime".to_string())?; | |
| Ok((command_tx, control_tx, isolate_handle)) | |
| } | |
| fn spawn_supervised_runtime_thread( | |
| event_tx: mpsc::UnboundedSender<RuntimeEvent>, | |
| task_failure_handler: Option<TaskFailureHandler>, | |
| runtime: impl FnOnce() + Send + 'static, | |
| ) { | |
| thread::spawn(move || { | |
| if catch_unwind(AssertUnwindSafe(runtime)).is_err() { | |
| if let Some(task_failure_handler) = task_failure_handler { | |
| task_failure_handler("code-mode V8 runtime thread panicked".to_string()); | |
| } | |
| let _ = event_tx.send(RuntimeEvent::ThreadPanicked); | |
| } | |
| }); | |
| } | |
| struct RuntimeConfig { | |
| tool_call_id: String, | |
| enabled_tools: Vec<EnabledToolMetadata>, | |
| source: String, | |
| stored_values: HashMap<String, JsonValue>, | |
| } | |
| pub(super) struct RuntimeState { | |
| event_tx: mpsc::UnboundedSender<RuntimeEvent>, | |
| pending_tool_calls: HashMap<String, v8::Global<v8::PromiseResolver>>, | |
| pending_timeouts: HashMap<u64, timers::ScheduledTimeout>, | |
| stored_values: HashMap<String, JsonValue>, | |
| stored_value_writes: HashMap<String, JsonValue>, | |
| enabled_tools: Vec<EnabledToolMetadata>, | |
| next_tool_call_id: u64, | |
| next_timeout_id: u64, | |
| tool_call_id: String, | |
| runtime_command_tx: std_mpsc::Sender<RuntimeCommand>, | |
| exit_requested: bool, | |
| } | |
| pub(super) enum CompletionState { | |
| Pending, | |
| Completed { | |
| stored_value_writes: HashMap<String, JsonValue>, | |
| error_text: Option<String>, | |
| }, | |
| } | |
| fn run_runtime( | |
| config: RuntimeConfig, | |
| event_tx: mpsc::UnboundedSender<RuntimeEvent>, | |
| command_rx: std_mpsc::Receiver<RuntimeCommand>, | |
| control_rx: std_mpsc::Receiver<RuntimeControlCommand>, | |
| pending_mode: PendingRuntimeMode, | |
| isolate_handle_tx: std_mpsc::SyncSender<v8::IsolateHandle>, | |
| runtime_command_tx: std_mpsc::Sender<RuntimeCommand>, | |
| ) { | |
| let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); | |
| let isolate_handle = isolate.thread_safe_handle(); | |
| if isolate_handle_tx.send(isolate_handle).is_err() { | |
| return; | |
| } | |
| isolate.set_host_import_module_dynamically_callback(module_loader::dynamic_import_callback); | |
| v8::scope!(let scope, isolate); | |
| let context = v8::Context::new(scope, Default::default()); | |
| let scope = &mut v8::ContextScope::new(scope, context); | |
| scope.set_slot(RuntimeState { | |
| event_tx: event_tx.clone(), | |
| pending_tool_calls: HashMap::new(), | |
| pending_timeouts: HashMap::new(), | |
| stored_values: config.stored_values, | |
| stored_value_writes: HashMap::new(), | |
| enabled_tools: config.enabled_tools, | |
| next_tool_call_id: 1, | |
| next_timeout_id: 1, | |
| tool_call_id: config.tool_call_id, | |
| runtime_command_tx, | |
| exit_requested: false, | |
| }); | |
| if let Err(error_text) = globals::install_globals(scope) { | |
| send_result(&event_tx, HashMap::new(), Some(error_text)); | |
| return; | |
| } | |
| let _ = event_tx.send(RuntimeEvent::Started); | |
| let pending_promise = match module_loader::evaluate_main_module(scope, &config.source) { | |
| Ok(pending_promise) => pending_promise, | |
| Err(error_text) => { | |
| capture_scope_send_error(scope, &event_tx, Some(error_text)); | |
| return; | |
| } | |
| }; | |
| match module_loader::completion_state(scope, pending_promise.as_ref()) { | |
| CompletionState::Completed { | |
| stored_value_writes, | |
| error_text, | |
| } => { | |
| send_result(&event_tx, stored_value_writes, error_text); | |
| return; | |
| } | |
| CompletionState::Pending => {} | |
| } | |
| let mut pending_promise = pending_promise; | |
| while let Some(command) = | |
| next_runtime_command(&event_tx, &command_rx, &control_rx, pending_mode) | |
| { | |
| match command { | |
| RuntimeCommand::Terminate => break, | |
| RuntimeCommand::ToolResponse { id, result } => { | |
| if let Err(error_text) = | |
| module_loader::resolve_tool_response(scope, &id, Ok(result)) | |
| { | |
| capture_scope_send_error(scope, &event_tx, Some(error_text)); | |
| return; | |
| } | |
| } | |
| RuntimeCommand::ToolError { id, error_text } => { | |
| if let Err(runtime_error) = | |
| module_loader::resolve_tool_response(scope, &id, Err(error_text)) | |
| { | |
| capture_scope_send_error(scope, &event_tx, Some(runtime_error)); | |
| return; | |
| } | |
| } | |
| RuntimeCommand::TimeoutFired { id } => { | |
| if let Err(runtime_error) = timers::invoke_timeout_callback(scope, id) { | |
| capture_scope_send_error(scope, &event_tx, Some(runtime_error)); | |
| return; | |
| } | |
| } | |
| RuntimeCommand::ObservePendingFrontier => {} | |
| } | |
| scope.perform_microtask_checkpoint(); | |
| match module_loader::completion_state(scope, pending_promise.as_ref()) { | |
| CompletionState::Completed { | |
| stored_value_writes, | |
| error_text, | |
| } => { | |
| send_result(&event_tx, stored_value_writes, error_text); | |
| return; | |
| } | |
| CompletionState::Pending => {} | |
| } | |
| if let Some(promise) = pending_promise.as_ref() { | |
| let promise = v8::Local::new(scope, promise); | |
| if promise.state() != v8::PromiseState::Pending { | |
| pending_promise = None; | |
| } | |
| } | |
| } | |
| } | |
| fn next_runtime_command( | |
| event_tx: &mpsc::UnboundedSender<RuntimeEvent>, | |
| command_rx: &std_mpsc::Receiver<RuntimeCommand>, | |
| control_rx: &std_mpsc::Receiver<RuntimeControlCommand>, | |
| pending_mode: PendingRuntimeMode, | |
| ) -> Option<RuntimeCommand> { | |
| loop { | |
| match command_rx.try_recv() { | |
| Ok(command) => return Some(command), | |
| Err(std_mpsc::TryRecvError::Disconnected) => return None, | |
| Err(std_mpsc::TryRecvError::Empty) => {} | |
| } | |
| let _ = event_tx.send(RuntimeEvent::Pending); | |
| match pending_mode { | |
| PendingRuntimeMode::Continue => return command_rx.recv().ok(), | |
| PendingRuntimeMode::PauseUntilResumed => match control_rx.recv().ok()? { | |
| RuntimeControlCommand::Continue => return command_rx.recv().ok(), | |
| RuntimeControlCommand::Resume => continue, | |
| RuntimeControlCommand::Terminate => return Some(RuntimeCommand::Terminate), | |
| }, | |
| } | |
| } | |
| } | |
| fn capture_scope_send_error( | |
| scope: &mut v8::PinScope<'_, '_>, | |
| event_tx: &mpsc::UnboundedSender<RuntimeEvent>, | |
| error_text: Option<String>, | |
| ) { | |
| let stored_value_writes = scope | |
| .get_slot::<RuntimeState>() | |
| .map(|state| state.stored_value_writes.clone()) | |
| .unwrap_or_default(); | |
| send_result(event_tx, stored_value_writes, error_text); | |
| } | |
| fn send_result( | |
| event_tx: &mpsc::UnboundedSender<RuntimeEvent>, | |
| stored_value_writes: HashMap<String, JsonValue>, | |
| error_text: Option<String>, | |
| ) { | |
| let _ = event_tx.send(RuntimeEvent::Result { | |
| stored_value_writes, | |
| error_text, | |
| }); | |
| } | |
| mod tests { | |
| use std::collections::HashMap; | |
| use std::time::Duration; | |
| use pretty_assertions::assert_eq; | |
| use tokio::sync::mpsc; | |
| use super::ExecuteRequest; | |
| use super::PendingRuntimeMode; | |
| use super::RuntimeCommand; | |
| use super::RuntimeControlCommand; | |
| use super::RuntimeEvent; | |
| use super::spawn_runtime; | |
| use super::spawn_supervised_runtime_thread; | |
| use crate::FunctionCallOutputContentItem; | |
| 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 linked_v8_has_sandbox_enabled() { | |
| unsafe extern "C" { | |
| fn v8__V8__IsSandboxEnabled() -> bool; | |
| } | |
| // `rusty_v8` exposes this symbol for verifying linked sandbox support. | |
| assert!( | |
| unsafe { v8__V8__IsSandboxEnabled() }, | |
| "code mode must link against sandbox-enabled V8" | |
| ); | |
| } | |
| async fn runtime_thread_panic_before_initialization_is_reported_directly() { | |
| let (event_tx, event_rx) = mpsc::unbounded_channel(); | |
| drop(event_rx); | |
| let (failure_tx, mut failure_rx) = mpsc::unbounded_channel(); | |
| spawn_supervised_runtime_thread( | |
| event_tx, | |
| Some(std::sync::Arc::new(move |reason| { | |
| let _ = failure_tx.send(reason); | |
| })), | |
| || panic!("runtime thread panic probe"), | |
| ); | |
| assert_eq!( | |
| tokio::time::timeout(Duration::from_secs(1), failure_rx.recv()) | |
| .await | |
| .expect("runtime failure timeout") | |
| .expect("runtime failure"), | |
| "code-mode V8 runtime thread panicked" | |
| ); | |
| } | |
| async fn runtime_thread_panic_is_forwarded_without_owner_supervision() { | |
| let (event_tx, mut event_rx) = mpsc::unbounded_channel(); | |
| spawn_supervised_runtime_thread( | |
| event_tx, | |
| /*task_failure_handler*/ None, | |
| || panic!("runtime thread panic probe"), | |
| ); | |
| assert!(matches!( | |
| tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .expect("runtime panic event timeout"), | |
| Some(RuntimeEvent::ThreadPanicked) | |
| )); | |
| } | |
| async fn terminate_execution_stops_cpu_bound_module() { | |
| let (event_tx, mut event_rx) = mpsc::unbounded_channel(); | |
| let (_runtime_tx, _runtime_control_tx, runtime_terminate_handle) = spawn_runtime( | |
| HashMap::new(), | |
| execute_request("while (true) {}"), | |
| event_tx, | |
| PendingRuntimeMode::Continue, | |
| /*task_failure_handler*/ None, | |
| ) | |
| .unwrap(); | |
| let started_event = tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .unwrap() | |
| .unwrap(); | |
| assert!(matches!(started_event, RuntimeEvent::Started)); | |
| assert!(runtime_terminate_handle.terminate_execution()); | |
| let result_event = tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .unwrap() | |
| .unwrap(); | |
| let RuntimeEvent::Result { error_text, .. } = result_event else { | |
| panic!("expected runtime result after termination"); | |
| }; | |
| assert!(error_text.is_some()); | |
| assert!( | |
| tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .unwrap() | |
| .is_none() | |
| ); | |
| } | |
| async fn pending_mode_freezes_runtime_commands_until_resume() { | |
| let (event_tx, mut event_rx) = mpsc::unbounded_channel(); | |
| let (runtime_tx, runtime_control_tx, _runtime_terminate_handle) = spawn_runtime( | |
| HashMap::new(), | |
| execute_request( | |
| r#" | |
| await new Promise((resolve) => setTimeout(resolve, 60_000)); | |
| text("after"); | |
| await new Promise(() => {}); | |
| "#, | |
| ), | |
| event_tx, | |
| PendingRuntimeMode::PauseUntilResumed, | |
| /*task_failure_handler*/ None, | |
| ) | |
| .unwrap(); | |
| assert!(matches!( | |
| tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .unwrap() | |
| .unwrap(), | |
| RuntimeEvent::Started | |
| )); | |
| assert!(matches!( | |
| tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .unwrap() | |
| .unwrap(), | |
| RuntimeEvent::Pending | |
| )); | |
| runtime_tx | |
| .send(RuntimeCommand::TimeoutFired { id: 1 }) | |
| .unwrap(); | |
| assert!( | |
| tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .is_err() | |
| ); | |
| runtime_control_tx | |
| .send(RuntimeControlCommand::Resume) | |
| .unwrap(); | |
| let content_event = tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .unwrap() | |
| .unwrap(); | |
| let RuntimeEvent::ContentItem(FunctionCallOutputContentItem::InputText { text }) = | |
| content_event | |
| else { | |
| panic!("expected resumed runtime output"); | |
| }; | |
| assert_eq!(text, "after"); | |
| assert!(matches!( | |
| tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .unwrap() | |
| .unwrap(), | |
| RuntimeEvent::Pending | |
| )); | |
| runtime_control_tx | |
| .send(RuntimeControlCommand::Terminate) | |
| .unwrap(); | |
| } | |
| async fn timers_release_tasks_when_cleared_or_the_cell_finishes() { | |
| let (event_tx, mut event_rx) = mpsc::unbounded_channel(); | |
| let (_runtime_tx, _runtime_control_tx, _runtime_terminate_handle) = spawn_runtime( | |
| HashMap::new(), | |
| execute_request( | |
| r#" | |
| clearTimeout(setTimeout(() => text("cancelled"), 3_600_000)); | |
| await new Promise((resolve) => setTimeout(resolve, 3_600_000)); | |
| text("done"); | |
| setTimeout(() => text("late"), 3_600_000); | |
| "#, | |
| ), | |
| event_tx, | |
| PendingRuntimeMode::Continue, | |
| /*task_failure_handler*/ None, | |
| ) | |
| .unwrap(); | |
| loop { | |
| match tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .unwrap() | |
| { | |
| Some(RuntimeEvent::Pending) => break, | |
| Some(_) => {} | |
| None => panic!("runtime closed before the timer was pending"), | |
| } | |
| } | |
| tokio::task::yield_now().await; | |
| assert_eq!( | |
| tokio::runtime::Handle::current() | |
| .metrics() | |
| .num_alive_tasks(), | |
| 1 | |
| ); | |
| tokio::time::pause(); | |
| tokio::time::advance(Duration::from_secs(3_600)).await; | |
| tokio::time::resume(); | |
| let mut output = Vec::new(); | |
| while let Some(event) = tokio::time::timeout(Duration::from_secs(1), event_rx.recv()) | |
| .await | |
| .expect("timer runtime should finish") | |
| { | |
| match event { | |
| RuntimeEvent::ContentItem(item) => output.push(item), | |
| RuntimeEvent::Result { error_text, .. } => assert_eq!(error_text, None), | |
| _ => {} | |
| } | |
| } | |
| assert_eq!( | |
| output, | |
| vec![FunctionCallOutputContentItem::InputText { | |
| text: "done".to_string() | |
| }] | |
| ); | |
| tokio::task::yield_now().await; | |
| assert_eq!( | |
| tokio::runtime::Handle::current() | |
| .metrics() | |
| .num_alive_tasks(), | |
| 0 | |
| ); | |
| } | |
| } | |