agent_ui: Fix pasted image context showing Image instead of actual filename (#52082)

Suphachai Phetthamrong created

## What

Fix image context mentions always showing the generic label `Image`
instead of the actual filename when pasting from Finder or picking via
the `+` → Image button in the Agent Panel.

## Why

`insert_images_as_context` hardcoded the crease label to
`MentionUri::PastedImage.name()` (`"Image"`) for every image, regardless
of whether it originated from a named file. Both code paths that load
images from file paths — `paste_images_as_context` and
`add_images_from_picker` — discarded the filename before passing images
to the shared insert function.

## Fix

- `agent_ui/src/mention_set.rs`: Changed `insert_images_as_context` to
accept `Vec<(gpui::Image, SharedString)>` instead of `Vec<gpui::Image>`,
using the provided name as the crease label. In
`paste_images_as_context`, extract `file_name()` from each path and pair
it with the loaded image. Raw clipboard images (screenshots, copy from
image editors) continue to use `"Image"` as there is no filename.

- `agent_ui/src/message_editor.rs`: Same fix for
`add_images_from_picker` — extract `file_name()` from each selected path
and pass it alongside the image.

Closes #52079

## Test Plan

- [x] `cargo build -p agent_ui` compiles clean
- [x]  `cargo fmt --all -- --check` format check
- [x] Manual verification of:
- [x] Copy an image file in Finder (`Cmd+C`), paste into Agent Panel —
mention shows actual filename
   - [x] `+` → Image → pick a file — mention shows actual filename
   - [x] Screenshot paste (`Cmd+Shift+4`) still shows `Image`
   - [x] Regular text paste still works

## Screenshots

<img width="638" height="569" alt="image"
src="https://github.com/user-attachments/assets/859d852c-66f6-4faa-a5fe-59bd34cd3d85"
/>

---
Release Notes:

- Fixed image context mentions always showing `Image` instead of the
actual filename when pasting from Finder or using the image picker in
the Agent Panel

Change summary

crates/agent_ui/src/mention_set.rs    | 45 +++++++++++++++++-----------
crates/agent_ui/src/message_editor.rs |  7 +++
2 files changed, 33 insertions(+), 19 deletions(-)

Detailed changes

crates/agent_ui/src/mention_set.rs 🔗

@@ -739,7 +739,7 @@ mod tests {
 /// Inserts a list of images into the editor as context mentions.
 /// This is the shared implementation used by both paste and file picker operations.
 pub(crate) async fn insert_images_as_context(
-    images: Vec<gpui::Image>,
+    images: Vec<(gpui::Image, SharedString)>,
     editor: Entity<Editor>,
     mention_set: Entity<MentionSet>,
     workspace: WeakEntity<Workspace>,
@@ -751,7 +751,7 @@ pub(crate) async fn insert_images_as_context(
 
     let replacement_text = MentionUri::PastedImage.as_link().to_string();
 
-    for image in images {
+    for (image, name) in images {
         let Some((excerpt_id, text_anchor, multibuffer_anchor)) = editor
             .update_in(cx, |editor, window, cx| {
                 let snapshot = editor.snapshot(window, cx);
@@ -785,7 +785,7 @@ pub(crate) async fn insert_images_as_context(
                 excerpt_id,
                 text_anchor,
                 content_len,
-                MentionUri::PastedImage.name().into(),
+                name.clone(),
                 IconName::Image.path().into(),
                 None,
                 None,
@@ -856,10 +856,11 @@ pub(crate) fn paste_images_as_context(
 
     Some(window.spawn(cx, async move |mut cx| {
         use itertools::Itertools;
-        let (mut images, paths) = clipboard
+        let default_name: SharedString = MentionUri::PastedImage.name().into();
+        let (mut images, paths): (Vec<(gpui::Image, SharedString)>, Vec<_>) = clipboard
             .into_entries()
             .filter_map(|entry| match entry {
-                ClipboardEntry::Image(image) => Some(Either::Left(image)),
+                ClipboardEntry::Image(image) => Some(Either::Left((image, default_name.clone()))),
                 ClipboardEntry::ExternalPaths(paths) => Some(Either::Right(paths)),
                 _ => None,
             })
@@ -870,24 +871,32 @@ pub(crate) fn paste_images_as_context(
                 cx.background_spawn(async move {
                     let mut images = vec![];
                     for path in paths.into_iter().flat_map(|paths| paths.paths().to_owned()) {
-                        let Ok(content) = async_fs::read(path).await else {
+                        let Ok(content) = async_fs::read(&path).await else {
                             continue;
                         };
                         let Ok(format) = image::guess_format(&content) else {
                             continue;
                         };
-                        images.push(gpui::Image::from_bytes(
-                            match format {
-                                image::ImageFormat::Png => gpui::ImageFormat::Png,
-                                image::ImageFormat::Jpeg => gpui::ImageFormat::Jpeg,
-                                image::ImageFormat::WebP => gpui::ImageFormat::Webp,
-                                image::ImageFormat::Gif => gpui::ImageFormat::Gif,
-                                image::ImageFormat::Bmp => gpui::ImageFormat::Bmp,
-                                image::ImageFormat::Tiff => gpui::ImageFormat::Tiff,
-                                image::ImageFormat::Ico => gpui::ImageFormat::Ico,
-                                _ => continue,
-                            },
-                            content,
+                        let name: SharedString = path
+                            .file_name()
+                            .and_then(|n| n.to_str())
+                            .map(|s| SharedString::from(s.to_owned()))
+                            .unwrap_or_else(|| default_name.clone());
+                        images.push((
+                            gpui::Image::from_bytes(
+                                match format {
+                                    image::ImageFormat::Png => gpui::ImageFormat::Png,
+                                    image::ImageFormat::Jpeg => gpui::ImageFormat::Jpeg,
+                                    image::ImageFormat::WebP => gpui::ImageFormat::Webp,
+                                    image::ImageFormat::Gif => gpui::ImageFormat::Gif,
+                                    image::ImageFormat::Bmp => gpui::ImageFormat::Bmp,
+                                    image::ImageFormat::Tiff => gpui::ImageFormat::Tiff,
+                                    image::ImageFormat::Ico => gpui::ImageFormat::Ico,
+                                    _ => continue,
+                                },
+                                content,
+                            ),
+                            name,
                         ));
                     }
                     images

crates/agent_ui/src/message_editor.rs 🔗

@@ -1366,7 +1366,12 @@ impl MessageEditor {
                         continue;
                     };
 
-                    images.push(gpui::Image::from_bytes(format, content));
+                    let name: gpui::SharedString = path
+                        .file_name()
+                        .and_then(|n| n.to_str())
+                        .map(|s| gpui::SharedString::from(s.to_owned()))
+                        .unwrap_or_else(|| "Image".into());
+                    images.push((gpui::Image::from_bytes(format, content), name));
                 }
 
                 crate::mention_set::insert_images_as_context(