diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 235cab683e..21f53df62a 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -4634,6 +4634,7 @@ dependencies = [ "codex-utils-absolute-path", "codex-utils-cargo-bin", "codex-utils-output-truncation", + "codex-utils-path-uri", "codex-utils-string", "jsonptr", "pretty_assertions", diff --git a/codex-rs/core/src/tools/handlers/extension_tools.rs b/codex-rs/core/src/tools/handlers/extension_tools.rs index ca1bc68fac..927e9b3d83 100644 --- a/codex-rs/core/src/tools/handlers/extension_tools.rs +++ b/codex-rs/core/src/tools/handlers/extension_tools.rs @@ -186,11 +186,6 @@ async fn to_extension_call(invocation: &ToolInvocation) -> ExtensionToolCall<'_> .and_then(|metadata| to_ascii_json_string(&metadata).ok()); let mut environments = Vec::new(); for environment in invocation.step_context.environments.turn_environments() { - // TODO(anp): Migrate extension ToolEnvironment and granted-permission lookup to PathUri - // so extensions can receive foreign environment cwd values. - let Ok(native_cwd) = environment.cwd().to_abs_path() else { - continue; - }; let additional_permissions = apply_granted_turn_permissions( invocation.session.as_ref(), environment, @@ -204,7 +199,7 @@ async fn to_extension_call(invocation: &ToolInvocation) -> ExtensionToolCall<'_> environments.push(ToolEnvironment { _lifetime: PhantomData, environment_id: environment.selection.environment_id.clone(), - cwd: native_cwd, + cwd: environment.cwd().clone(), file_system: environment.environment.get_filesystem(), file_system_sandbox_context, }); diff --git a/codex-rs/ext/image-generation/src/tool.rs b/codex-rs/ext/image-generation/src/tool.rs index 66864fea6b..07f00614a9 100644 --- a/codex-rs/ext/image-generation/src/tool.rs +++ b/codex-rs/ext/image-generation/src/tool.rs @@ -217,9 +217,13 @@ impl ImageGenerationTool { return Err(FunctionCallError::RespondToModel(message)); } }; + // TODO(anp): Migrate image tool path arguments and saved-path events to PathUri so image + // operations can use the primary environment even when its paths are foreign to the host. let saved_path = save_image_generation_result( self.save_root.as_ref(), - call.environments.first(), + call.environments + .iter() + .find(|environment| environment.cwd.to_abs_path().is_ok()), &self.thread_id, &call.call_id, &result, @@ -320,7 +324,8 @@ async fn save_image_generation_result( } None => { let environment = environment?; - let output_dir = environment.cwd.join("generated_images"); + let cwd = environment.cwd.to_abs_path().ok()?; + let output_dir = cwd.join("generated_images"); let save_result: io::Result = async { let result = result.trim(); if result.len() > MAX_EXECUTOR_GENERATED_IMAGE_BASE64_BYTES { @@ -339,8 +344,7 @@ async fn save_image_generation_result( )); } - let artifact_path = - image_generation_artifact_path(&environment.cwd, session_id, call_id); + let artifact_path = image_generation_artifact_path(&cwd, session_id, call_id); let path = output_dir.join(artifact_path.as_path().file_name().unwrap_or_default()); let sandbox = Some(&environment.file_system_sandbox_context); if let Some(parent) = path.parent() { @@ -440,7 +444,10 @@ async fn request_for_call_args( })); } (false, None) => { - let Some(environment) = environments.first() else { + let Some(environment) = environments + .iter() + .find(|environment| environment.cwd.to_abs_path().is_ok()) + else { return Err(FunctionCallError::RespondToModel( "referenced image paths are unavailable in this session".to_string(), )); diff --git a/codex-rs/tools/Cargo.toml b/codex-rs/tools/Cargo.toml index e621bb830b..f47815537f 100644 --- a/codex-rs/tools/Cargo.toml +++ b/codex-rs/tools/Cargo.toml @@ -17,6 +17,7 @@ codex-extension-items = { workspace = true } codex-protocol = { workspace = true } codex-utils-absolute-path = { workspace = true } codex-utils-output-truncation = { workspace = true } +codex-utils-path-uri = { workspace = true } codex-utils-string = { workspace = true } jsonptr = { workspace = true } rmcp = { workspace = true, default-features = false, features = [ diff --git a/codex-rs/tools/src/tool_call.rs b/codex-rs/tools/src/tool_call.rs index 8cf9bc6bed..a2c57a5015 100644 --- a/codex-rs/tools/src/tool_call.rs +++ b/codex-rs/tools/src/tool_call.rs @@ -6,9 +6,9 @@ use codex_file_system::ExecutorFileSystem; use codex_file_system::FileSystemSandboxContext; use codex_protocol::models::ResponseItem; use codex_protocol::protocol::EventMsg; -use codex_utils_absolute_path::AbsolutePathBuf; use codex_utils_output_truncation::TruncationPolicy; use codex_utils_output_truncation::with_serialization_allowance; +use codex_utils_path_uri::PathUri; use std::fmt; use std::future::Future; use std::marker::PhantomData; @@ -91,7 +91,7 @@ pub struct ToolEnvironment<'call> { /// Stable host environment id used to route executor-scoped capabilities. pub environment_id: String, /// Effective working directory for this turn in the environment. - pub cwd: AbsolutePathBuf, + pub cwd: PathUri, /// Filesystem implementation for this environment. pub file_system: Arc, /// Sandbox context to use for filesystem operations.