diff --git a/codex-rs/core/src/tools/code_mode/execute_handler.rs b/codex-rs/core/src/tools/code_mode/execute_handler.rs index 1c65161fd..56a13ae47 100644 --- a/codex-rs/core/src/tools/code_mode/execute_handler.rs +++ b/codex-rs/core/src/tools/code_mode/execute_handler.rs @@ -32,7 +32,7 @@ impl CodeModeExecuteHandler { let stored_values = service.stored_values().await; let source = build_source(&code, &enabled_tools).map_err(FunctionCallError::RespondToModel)?; - let session_id = service.allocate_session_id().await; + let cell_id = service.allocate_cell_id().await; let request_id = service.allocate_request_id().await; let process_slot = service .ensure_started() @@ -41,7 +41,7 @@ impl CodeModeExecuteHandler { let started_at = std::time::Instant::now(); let message = HostToNodeMessage::Start { request_id: request_id.clone(), - session_id, + cell_id: cell_id.clone(), default_yield_time_ms: super::DEFAULT_EXEC_YIELD_TIME_MS, enabled_tools, stored_values, @@ -62,7 +62,7 @@ impl CodeModeExecuteHandler { Ok(message) => message, Err(error) => return Err(FunctionCallError::RespondToModel(error)), }; - handle_node_message(&exec, session_id, message, None, started_at).await + handle_node_message(&exec, cell_id, message, None, started_at).await }; match result { Ok(CodeModeSessionProgress::Finished(output)) diff --git a/codex-rs/core/src/tools/code_mode/mod.rs b/codex-rs/core/src/tools/code_mode/mod.rs index ce72f7ba1..9a92a2486 100644 --- a/codex-rs/core/src/tools/code_mode/mod.rs +++ b/codex-rs/core/src/tools/code_mode/mod.rs @@ -57,7 +57,7 @@ enum CodeModeSessionProgress { enum CodeModeExecutionStatus { Completed, Failed, - Running(i32), + Running(String), Terminated, } @@ -79,7 +79,7 @@ pub(crate) fn wait_tool_description() -> &'static str { async fn handle_node_message( exec: &ExecContext, - session_id: i32, + cell_id: String, message: protocol::NodeToHostMessage, poll_max_output_tokens: Option>, started_at: std::time::Instant, @@ -91,7 +91,7 @@ async fn handle_node_message( delta_items = truncate_code_mode_result(delta_items, poll_max_output_tokens.flatten()); prepend_script_status( &mut delta_items, - CodeModeExecutionStatus::Running(session_id), + CodeModeExecutionStatus::Running(cell_id), started_at.elapsed(), ); Ok(CodeModeSessionProgress::Yielded { @@ -161,8 +161,8 @@ fn prepend_script_status( match status { CodeModeExecutionStatus::Completed => "Script completed".to_string(), CodeModeExecutionStatus::Failed => "Script failed".to_string(), - CodeModeExecutionStatus::Running(session_id) => { - format!("Script running with session ID {session_id}") + CodeModeExecutionStatus::Running(cell_id) => { + format!("Script running with cell ID {cell_id}") } CodeModeExecutionStatus::Terminated => "Script terminated".to_string(), } diff --git a/codex-rs/core/src/tools/code_mode/protocol.rs b/codex-rs/core/src/tools/code_mode/protocol.rs index 6cd50d3f9..44757f858 100644 --- a/codex-rs/core/src/tools/code_mode/protocol.rs +++ b/codex-rs/core/src/tools/code_mode/protocol.rs @@ -41,7 +41,7 @@ pub(super) struct CodeModeToolCall { pub(super) enum HostToNodeMessage { Start { request_id: String, - session_id: i32, + cell_id: String, default_yield_time_ms: u64, enabled_tools: Vec, stored_values: HashMap, @@ -49,12 +49,12 @@ pub(super) enum HostToNodeMessage { }, Poll { request_id: String, - session_id: i32, + cell_id: String, yield_time_ms: u64, }, Terminate { request_id: String, - session_id: i32, + cell_id: String, }, Response { request_id: String, diff --git a/codex-rs/core/src/tools/code_mode/runner.cjs b/codex-rs/core/src/tools/code_mode/runner.cjs index 7668eb2ef..b2002a2b7 100644 --- a/codex-rs/core/src/tools/code_mode/runner.cjs +++ b/codex-rs/core/src/tools/code_mode/runner.cjs @@ -486,7 +486,7 @@ function createProtocol() { } if (message.type === 'poll') { - const session = sessions.get(message.session_id); + const session = sessions.get(message.cell_id); if (session) { session.request_id = String(message.request_id); if (session.pending_result) { @@ -500,7 +500,7 @@ function createProtocol() { request_id: message.request_id, content_items: [], stored_values: {}, - error_text: `exec session ${message.session_id} not found`, + error_text: `exec cell ${message.cell_id} not found`, max_output_tokens_per_exec_call: DEFAULT_MAX_OUTPUT_TOKENS_PER_EXEC_CALL, }); } @@ -508,7 +508,7 @@ function createProtocol() { } if (message.type === 'terminate') { - const session = sessions.get(message.session_id); + const session = sessions.get(message.cell_id); if (session) { session.request_id = String(message.request_id); void terminateSession(protocol, sessions, session); @@ -518,7 +518,7 @@ function createProtocol() { request_id: message.request_id, content_items: [], stored_values: {}, - error_text: `exec session ${message.session_id} not found`, + error_text: `exec cell ${message.cell_id} not found`, max_output_tokens_per_exec_call: DEFAULT_MAX_OUTPUT_TOKENS_PER_EXEC_CALL, }); } @@ -591,7 +591,7 @@ function startSession(protocol, sessions, start) { completed: false, content_items: [], default_yield_time_ms: normalizeYieldTime(start.default_yield_time_ms), - id: start.session_id, + id: start.cell_id, initial_yield_timer: null, initial_yield_triggered: false, max_output_tokens_per_exec_call: DEFAULT_MAX_OUTPUT_TOKENS_PER_EXEC_CALL, diff --git a/codex-rs/core/src/tools/code_mode/service.rs b/codex-rs/core/src/tools/code_mode/service.rs index 0df1f88dd..52b519651 100644 --- a/codex-rs/core/src/tools/code_mode/service.rs +++ b/codex-rs/core/src/tools/code_mode/service.rs @@ -24,7 +24,7 @@ pub(crate) struct CodeModeService { js_repl_node_path: Option, stored_values: Mutex>, process: Arc>>, - next_session_id: Mutex, + next_cell_id: Mutex, } impl CodeModeService { @@ -33,7 +33,7 @@ impl CodeModeService { js_repl_node_path, stored_values: Mutex::new(HashMap::new()), process: Arc::new(Mutex::new(None)), - next_session_id: Mutex::new(1), + next_cell_id: Mutex::new(1), } } @@ -95,11 +95,11 @@ impl CodeModeService { Some(process.worker(exec, tool_runtime)) } - pub(crate) async fn allocate_session_id(&self) -> i32 { - let mut next_session_id = self.next_session_id.lock().await; - let session_id = *next_session_id; - *next_session_id = next_session_id.saturating_add(1); - session_id + pub(crate) async fn allocate_cell_id(&self) -> String { + let mut next_cell_id = self.next_cell_id.lock().await; + let cell_id = *next_cell_id; + *next_cell_id = next_cell_id.saturating_add(1); + cell_id.to_string() } pub(crate) async fn allocate_request_id(&self) -> String { diff --git a/codex-rs/core/src/tools/code_mode/wait_description.md b/codex-rs/core/src/tools/code_mode/wait_description.md index 77ec11295..5780b007b 100644 --- a/codex-rs/core/src/tools/code_mode/wait_description.md +++ b/codex-rs/core/src/tools/code_mode/wait_description.md @@ -1,8 +1,8 @@ -- Use `exec_wait` only after `exec` returns `Script running with session ID ...`. -- `session_id` identifies the running `exec` session to resume. +- Use `exec_wait` only after `exec` returns `Script running with cell ID ...`. +- `cell_id` identifies the running `exec` cell to resume. - `yield_time_ms` controls how long to wait for more output before yielding again. If omitted, `exec_wait` uses its default wait timeout. - `max_tokens` limits how much new output this wait call returns. -- `terminate: true` stops the running session instead of waiting for more output. -- `exec_wait` returns only the new output since the last yield, or the final completion or termination result for that session. -- If the session is still running, `exec_wait` may yield again with the same `session_id`. -- If the session has already finished, `exec_wait` returns the completed result and closes the session. +- `terminate: true` stops the running cell instead of waiting for more output. +- `exec_wait` returns only the new output since the last yield, or the final completion or termination result for that cell. +- If the cell is still running, `exec_wait` may yield again with the same `cell_id`. +- If the cell has already finished, `exec_wait` returns the completed result and closes the cell. diff --git a/codex-rs/core/src/tools/code_mode/wait_handler.rs b/codex-rs/core/src/tools/code_mode/wait_handler.rs index fe9fe5e5b..caaf8c8c4 100644 --- a/codex-rs/core/src/tools/code_mode/wait_handler.rs +++ b/codex-rs/core/src/tools/code_mode/wait_handler.rs @@ -20,7 +20,7 @@ pub struct CodeModeWaitHandler; #[derive(Debug, Deserialize)] struct ExecWaitArgs { - session_id: i32, + cell_id: String, #[serde(default = "default_wait_yield_time_ms")] yield_time_ms: u64, #[serde(default)] @@ -73,12 +73,12 @@ impl ToolHandler for CodeModeWaitHandler { let message = if args.terminate { HostToNodeMessage::Terminate { request_id: request_id.clone(), - session_id: args.session_id, + cell_id: args.cell_id.clone(), } } else { HostToNodeMessage::Poll { request_id: request_id.clone(), - session_id: args.session_id, + cell_id: args.cell_id.clone(), yield_time_ms: args.yield_time_ms, } }; @@ -111,7 +111,7 @@ impl ToolHandler for CodeModeWaitHandler { }; handle_node_message( &exec, - args.session_id, + args.cell_id, message, Some(args.max_tokens), started_at, diff --git a/codex-rs/core/src/tools/spec.rs b/codex-rs/core/src/tools/spec.rs index a31fe612f..9fed64097 100644 --- a/codex-rs/core/src/tools/spec.rs +++ b/codex-rs/core/src/tools/spec.rs @@ -622,9 +622,9 @@ fn create_write_stdin_tool() -> ToolSpec { fn create_exec_wait_tool() -> ToolSpec { let properties = BTreeMap::from([ ( - "session_id".to_string(), - JsonSchema::Number { - description: Some("Identifier of the running exec session.".to_string()), + "cell_id".to_string(), + JsonSchema::String { + description: Some("Identifier of the running exec cell.".to_string()), }, ), ( @@ -647,7 +647,7 @@ fn create_exec_wait_tool() -> ToolSpec { ( "terminate".to_string(), JsonSchema::Boolean { - description: Some("Whether to terminate the running exec session.".to_string()), + description: Some("Whether to terminate the running exec cell.".to_string()), }, ), ]); @@ -655,13 +655,13 @@ fn create_exec_wait_tool() -> ToolSpec { ToolSpec::Function(ResponsesApiTool { name: WAIT_TOOL_NAME.to_string(), description: format!( - "Waits on a yielded `{PUBLIC_TOOL_NAME}` session and returns new output or completion.\n{}", + "Waits on a yielded `{PUBLIC_TOOL_NAME}` cell and returns new output or completion.\n{}", code_mode_wait_tool_description().trim() ), strict: false, parameters: JsonSchema::Object { properties, - required: Some(vec!["session_id".to_string()]), + required: Some(vec!["cell_id".to_string()]), additional_properties: Some(false.into()), }, output_schema: None, diff --git a/codex-rs/core/tests/suite/code_mode.rs b/codex-rs/core/tests/suite/code_mode.rs index 6baa50ada..a427a5bc9 100644 --- a/codex-rs/core/tests/suite/code_mode.rs +++ b/codex-rs/core/tests/suite/code_mode.rs @@ -52,12 +52,11 @@ fn text_item(items: &[Value], index: usize) -> &str { .expect("content item should be input_text") } -fn extract_running_session_id(text: &str) -> i32 { - text.strip_prefix("Script running with session ID ") +fn extract_running_cell_id(text: &str) -> String { + text.strip_prefix("Script running with cell ID ") .and_then(|rest| rest.split('\n').next()) - .expect("running header should contain a session ID") - .parse() - .expect("session ID should parse as i32") + .expect("running header should contain a cell ID") + .to_string() } fn wait_for_file_source(path: &Path) -> Result { @@ -422,12 +421,12 @@ output_text("phase 3"); assert_regex_match( concat!( r"(?s)\A", - r"Script running with session ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" + r"Script running with cell ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" ), text_item(&first_items, 0), ); assert_eq!(text_item(&first_items, 1), "phase 1"); - let session_id = extract_running_session_id(text_item(&first_items, 0)); + let cell_id = extract_running_cell_id(text_item(&first_items, 0)); responses::mount_sse_once( &server, @@ -437,7 +436,7 @@ output_text("phase 3"); "call-2", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": session_id, + "cell_id": cell_id.clone(), "yield_time_ms": 1_000, }))?, ), @@ -463,13 +462,13 @@ output_text("phase 3"); assert_regex_match( concat!( r"(?s)\A", - r"Script running with session ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" + r"Script running with cell ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" ), text_item(&second_items, 0), ); assert_eq!( - extract_running_session_id(text_item(&second_items, 0)), - session_id + extract_running_cell_id(text_item(&second_items, 0)), + cell_id ); assert_eq!(text_item(&second_items, 1), "phase 2"); @@ -481,7 +480,7 @@ output_text("phase 3"); "call-3", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": session_id, + "cell_id": cell_id.clone(), "yield_time_ms": 1_000, }))?, ), @@ -565,12 +564,12 @@ while (true) {} assert_regex_match( concat!( r"(?s)\A", - r"Script running with session ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" + r"Script running with cell ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" ), text_item(&first_items, 0), ); assert_eq!(text_item(&first_items, 1), "phase 1"); - let session_id = extract_running_session_id(text_item(&first_items, 0)); + let cell_id = extract_running_cell_id(text_item(&first_items, 0)); responses::mount_sse_once( &server, @@ -580,7 +579,7 @@ while (true) {} "call-2", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": session_id, + "cell_id": cell_id.clone(), "terminate": true, }))?, ), @@ -674,7 +673,7 @@ output_text("session b done"); let first_request = first_completion.single_request(); let first_items = custom_tool_output_items(&first_request, "call-1"); assert_eq!(first_items.len(), 2); - let session_a_id = extract_running_session_id(text_item(&first_items, 0)); + let session_a_id = extract_running_cell_id(text_item(&first_items, 0)); assert_eq!(text_item(&first_items, 1), "session a start"); responses::mount_sse_once( @@ -700,7 +699,7 @@ output_text("session b done"); let second_request = second_completion.single_request(); let second_items = custom_tool_output_items(&second_request, "call-2"); assert_eq!(second_items.len(), 2); - let session_b_id = extract_running_session_id(text_item(&second_items, 0)); + let session_b_id = extract_running_cell_id(text_item(&second_items, 0)); assert_eq!(text_item(&second_items, 1), "session b start"); assert_ne!(session_a_id, session_b_id); @@ -713,7 +712,7 @@ output_text("session b done"); "call-3", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": session_a_id, + "cell_id": session_a_id.clone(), "yield_time_ms": 1_000, }))?, ), @@ -753,7 +752,7 @@ output_text("session b done"); "call-4", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": session_b_id, + "cell_id": session_b_id.clone(), "yield_time_ms": 1_000, }))?, ), @@ -835,7 +834,7 @@ output_text("phase 2"); let first_request = first_completion.single_request(); let first_items = custom_tool_output_items(&first_request, "call-1"); assert_eq!(first_items.len(), 2); - let session_id = extract_running_session_id(text_item(&first_items, 0)); + let cell_id = extract_running_cell_id(text_item(&first_items, 0)); assert_eq!(text_item(&first_items, 1), "phase 1"); responses::mount_sse_once( @@ -846,7 +845,7 @@ output_text("phase 2"); "call-2", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": session_id, + "cell_id": cell_id.clone(), "terminate": true, }))?, ), @@ -937,7 +936,7 @@ async fn code_mode_exec_wait_returns_error_for_unknown_session() -> Result<()> { "call-1", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": 999_999, + "cell_id": "999999", "yield_time_ms": 1_000, }))?, ), @@ -954,7 +953,7 @@ async fn code_mode_exec_wait_returns_error_for_unknown_session() -> Result<()> { ) .await; - test.submit_turn("wait on an unknown exec session").await?; + test.submit_turn("wait on an unknown exec cell").await?; let request = completion.single_request(); let (_, success) = request @@ -973,7 +972,7 @@ async fn code_mode_exec_wait_returns_error_for_unknown_session() -> Result<()> { ); assert_eq!( text_item(&items, 1), - "Script error:\nexec session 999999 not found" + "Script error:\nexec cell 999999 not found" ); Ok(()) @@ -1046,7 +1045,7 @@ output_text("session b done"); let first_request = first_completion.single_request(); let first_items = custom_tool_output_items(&first_request, "call-1"); assert_eq!(first_items.len(), 2); - let session_a_id = extract_running_session_id(text_item(&first_items, 0)); + let session_a_id = extract_running_cell_id(text_item(&first_items, 0)); assert_eq!(text_item(&first_items, 1), "session a start"); responses::mount_sse_once( @@ -1072,7 +1071,7 @@ output_text("session b done"); let second_request = second_completion.single_request(); let second_items = custom_tool_output_items(&second_request, "call-2"); assert_eq!(second_items.len(), 2); - let session_b_id = extract_running_session_id(text_item(&second_items, 0)); + let session_b_id = extract_running_cell_id(text_item(&second_items, 0)); assert_eq!(text_item(&second_items, 1), "session b start"); fs::write(&session_a_gate, "ready")?; @@ -1084,7 +1083,7 @@ output_text("session b done"); "call-3", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": session_b_id, + "cell_id": session_b_id.clone(), "yield_time_ms": 1_000, }))?, ), @@ -1109,12 +1108,12 @@ output_text("session b done"); assert_regex_match( concat!( r"(?s)\A", - r"Script running with session ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" + r"Script running with cell ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" ), text_item(&third_items, 0), ); assert_eq!( - extract_running_session_id(text_item(&third_items, 0)), + extract_running_cell_id(text_item(&third_items, 0)), session_b_id ); @@ -1134,7 +1133,7 @@ output_text("session b done"); "call-4", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": session_a_id, + "cell_id": session_a_id.clone(), "terminate": true, }))?, ), @@ -1234,7 +1233,7 @@ output_text("after yield"); assert_regex_match( concat!( r"(?s)\A", - r"Script running with session ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" + r"Script running with cell ID \d+\nWall time \d+\.\d seconds\nOutput:\n\z" ), text_item(&first_items, 0), ); @@ -1327,7 +1326,7 @@ output_text("token one token two token three token four token five token six tok let first_items = custom_tool_output_items(&first_request, "call-1"); assert_eq!(first_items.len(), 2); assert_eq!(text_item(&first_items, 1), "phase 1"); - let session_id = extract_running_session_id(text_item(&first_items, 0)); + let cell_id = extract_running_cell_id(text_item(&first_items, 0)); fs::write(&completion_gate, "ready")?; responses::mount_sse_once( @@ -1338,7 +1337,7 @@ output_text("token one token two token three token four token five token six tok "call-2", "exec_wait", &serde_json::to_string(&serde_json::json!({ - "session_id": session_id, + "cell_id": cell_id.clone(), "yield_time_ms": 1_000, "max_tokens": 6, }))?,