core: route view_image through a sandbox-backed fs helper

This commit is contained in:
Michael Bolin
2026-03-19 20:23:55 -07:00
parent 45b4632cad
commit d63213b7d0
2 changed files with 150 additions and 33 deletions
+40 -33
View File
@@ -14,6 +14,7 @@ use crate::function_tool::FunctionCallError;
use crate::original_image_detail::can_request_original_image_detail;
use crate::protocol::EventMsg;
use crate::protocol::ViewImageToolCallEvent;
use crate::sandboxed_fs;
use crate::tools::context::ToolInvocation;
use crate::tools::context::ToolOutput;
use crate::tools::context::ToolPayload;
@@ -93,36 +94,6 @@ impl ToolHandler for ViewImageHandler {
AbsolutePathBuf::try_from(turn.resolve_path(Some(args.path))).map_err(|error| {
FunctionCallError::RespondToModel(format!("unable to resolve image path: {error}"))
})?;
let metadata = turn
.environment
.get_filesystem()
.get_metadata(&abs_path)
.await
.map_err(|error| {
FunctionCallError::RespondToModel(format!(
"unable to locate image at `{}`: {error}",
abs_path.display()
))
})?;
if !metadata.is_file {
return Err(FunctionCallError::RespondToModel(format!(
"image path `{}` is not a file",
abs_path.display()
)));
}
let file_bytes = turn
.environment
.get_filesystem()
.read_file(&abs_path)
.await
.map_err(|error| {
FunctionCallError::RespondToModel(format!(
"unable to read image at `{}`: {error}",
abs_path.display()
))
})?;
let event_path = abs_path.to_path_buf();
let can_request_original_detail =
@@ -135,14 +106,23 @@ impl ToolHandler for ViewImageHandler {
PromptImageMode::ResizeToFit
};
let image_detail = use_original_detail.then_some(ImageDetail::Original);
let image_bytes = sandboxed_fs::read_file(&session, &turn, abs_path.as_path())
.await
.map_err(|error| {
FunctionCallError::RespondToModel(render_view_image_read_error(
abs_path.as_path(),
&error,
))
})?;
let image =
load_for_prompt_bytes(abs_path.as_path(), file_bytes, image_mode).map_err(|error| {
let image = load_for_prompt_bytes(abs_path.as_path(), image_bytes, image_mode).map_err(
|error| {
FunctionCallError::RespondToModel(format!(
"unable to process image at `{}`: {error}",
abs_path.display()
))
})?;
},
)?;
let image_url = image.into_data_url();
session
@@ -201,6 +181,33 @@ impl ToolOutput for ViewImageOutput {
}
}
fn render_view_image_read_error(
path: &std::path::Path,
error: &sandboxed_fs::SandboxedFsError,
) -> String {
let operation_message = error
.operation_error_message()
.map(str::to_owned)
.unwrap_or_else(|| error.to_string());
match error.operation_error_kind() {
Some(codex_fs_ops::FsErrorKind::IsADirectory) => {
format!("image path `{}` is not a file", path.display())
}
Some(codex_fs_ops::FsErrorKind::NotFound) => {
format!(
"unable to locate image at `{}`: {operation_message}",
path.display()
)
}
Some(_) | None => {
format!(
"unable to read image at `{}`: {operation_message}",
path.display()
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;