mirror of
https://github.com/openai/codex.git
synced 2026-10-17 17:08:55 +00:00
Preserve foreign working directories in extension tool environments (#47129)
## Why Extension calls omitted environments whose working directories could not be converted to host-native paths, preventing extensions from receiving those environments. ## What changed Store `ToolEnvironment.cwd` as `PathUri` and pass all turn environments to extension tools without requiring host-native path conversion. Keep image generation's existing path requirements by selecting the first environment with a convertible working directory when reading referenced images or saving generated images. GitOrigin-RevId: b4320c6e07d27ef59885cd0013e5d1c535f69659
This commit is contained in:
committed by
copyberry
parent
26cb4d73e2
commit
69759baefd
Generated
+1
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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<AbsolutePathBuf> = 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(),
|
||||
));
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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<dyn ExecutorFileSystem>,
|
||||
/// Sandbox context to use for filesystem operations.
|
||||
|
||||
Reference in New Issue
Block a user