From dcaa8b87695b96c6e12bbb2a77ec854aca065a61 Mon Sep 17 00:00:00 2001 From: lif <1835304752@qq.com> Date: Thu, 8 Jan 2026 20:14:02 +0800 Subject: [PATCH] fix: copy images to agent_working_dir when set (#1752) * fix: copy images to agent_working_dir when set When agent_working_dir is configured, copy images to //.vibe-images/ instead of /.vibe-images/ so that relative paths work correctly for the AI agent. Closes #1727 Signed-off-by: majiayu000 <1835304752@qq.com> * optionally append agent working directory in other image routes --------- Signed-off-by: majiayu000 <1835304752@qq.com> Co-authored-by: Gabriel Gordon-Hall --- crates/local-deployment/src/container.rs | 6 +++++- .../server/src/routes/task_attempts/images.rs | 19 +++++++++++++++---- crates/services/src/services/image.rs | 9 ++++++++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/crates/local-deployment/src/container.rs b/crates/local-deployment/src/container.rs index aadb1b02..92809214 100644 --- a/crates/local-deployment/src/container.rs +++ b/crates/local-deployment/src/container.rs @@ -725,7 +725,11 @@ impl LocalContainerService { if let Err(e) = self .image_service - .copy_images_by_task_to_worktree(workspace_dir, workspace.task_id) + .copy_images_by_task_to_worktree( + workspace_dir, + workspace.task_id, + workspace.agent_working_dir.as_deref(), + ) .await { tracing::warn!("Failed to copy task images to workspace: {}", e); diff --git a/crates/server/src/routes/task_attempts/images.rs b/crates/server/src/routes/task_attempts/images.rs index ed2da5ad..64e30374 100644 --- a/crates/server/src/routes/task_attempts/images.rs +++ b/crates/server/src/routes/task_attempts/images.rs @@ -51,9 +51,13 @@ pub async fn upload_image( .ensure_container_exists(&workspace) .await?; let workspace_path = std::path::PathBuf::from(container_ref); + let base_path = match workspace.agent_working_dir.as_deref() { + Some(dir) if !dir.is_empty() => workspace_path.join(dir), + _ => workspace_path, + }; deployment .image() - .copy_images_by_ids_to_worktree(&workspace_path, &[image_response.id]) + .copy_images_by_ids_to_worktree(&base_path, &[image_response.id]) .await?; Ok(ResponseJson(ApiResponse::success(image_response))) @@ -95,7 +99,11 @@ pub async fn get_image_metadata( .ensure_container_exists(&workspace) .await?; let workspace_path = std::path::PathBuf::from(container_ref); - let full_path = workspace_path.join(&query.path); + let base_path = match workspace.agent_working_dir.as_deref() { + Some(dir) if !dir.is_empty() => workspace_path.join(dir), + _ => workspace_path, + }; + let full_path = base_path.join(&query.path); // Check if file exists let metadata = match tokio::fs::metadata(&full_path).await { @@ -154,8 +162,11 @@ pub async fn serve_image( .ensure_container_exists(&workspace) .await?; let workspace_path = std::path::PathBuf::from(container_ref); - - let vibe_images_dir = workspace_path.join(utils::path::VIBE_IMAGES_DIR); + let base_path = match workspace.agent_working_dir.as_deref() { + Some(dir) if !dir.is_empty() => workspace_path.join(dir), + _ => workspace_path, + }; + let vibe_images_dir = base_path.join(utils::path::VIBE_IMAGES_DIR); let full_path = vibe_images_dir.join(&path); // Security: Canonicalize and verify path is within .vibe-images diff --git a/crates/services/src/services/image.rs b/crates/services/src/services/image.rs index 384a91f1..2237f2ac 100644 --- a/crates/services/src/services/image.rs +++ b/crates/services/src/services/image.rs @@ -166,9 +166,16 @@ impl ImageService { &self, worktree_path: &Path, task_id: Uuid, + agent_working_dir: Option<&str>, ) -> Result<(), ImageError> { let images = Image::find_by_task_id(&self.pool, task_id).await?; - self.copy_images(worktree_path, images) + // When agent_working_dir is set, copy images to that subdirectory + // so relative paths like .vibe-images/xxx.png work correctly + let target_path = match agent_working_dir { + Some(dir) if !dir.is_empty() => worktree_path.join(dir), + _ => worktree_path.to_path_buf(), + }; + self.copy_images(&target_path, images) } pub async fn copy_images_by_ids_to_worktree(