fix image drag drop (#5794)

fixing drag/drop photos bug in codex

state of the world before:

sometimes, when you drag screenshots into codex, the image does not
properly render into context. instead, the file name is shown in
quotation marks.


https://github.com/user-attachments/assets/3c0e540a-505c-4ec0-b634-e9add6a73119

the screenshot is not actually included in agent context. the agent
needs to manually call the view_image tool to see the screenshot. this
can be unreliable especially if the image is part of a longer prompt and
is dependent on the agent going out of its way to view the image.

state of the world after:


https://github.com/user-attachments/assets/5f2b7bf7-8a3f-4708-85f3-d68a017bfd97

now, images will always be directly embedded into chat context

## Technical Details

- MacOS sends screenshot paths with a narrow no‑break space right before
the “AM/PM” suffix, which used to trigger our non‑ASCII fallback in the
paste burst detector.
- That fallback flushed the partially buffered paste immediately, so the
path arrived in two separate `handle_paste` calls (quoted prefix +
`PM.png'`). The split string could not be normalized to a real path, so
we showed the quoted filename instead of embedding the image.
- We now append non‑ASCII characters into the burst buffer when a burst
is already active. Finder’s payload stays intact, the path normalizes,
and the image attaches automatically.
- When no burst is active (e.g. during IME typing), non‑ASCII characters
still bypass the buffer so text entry remains responsive.
This commit is contained in:
zhao-oai
2025-10-27 17:11:30 -07:00
committed by GitHub
parent b0bdc04c30
commit 4d6a42a622
2 changed files with 22 additions and 0 deletions

View File

@@ -573,6 +573,16 @@ impl ChatComposer {
#[inline] #[inline]
fn handle_non_ascii_char(&mut self, input: KeyEvent) -> (InputResult, bool) { fn handle_non_ascii_char(&mut self, input: KeyEvent) -> (InputResult, bool) {
if let KeyEvent {
code: KeyCode::Char(ch),
..
} = input
{
let now = Instant::now();
if self.paste_burst.try_append_char_if_active(ch, now) {
return (InputResult::None, true);
}
}
if let Some(pasted) = self.paste_burst.flush_before_modified_input() { if let Some(pasted) = self.paste_burst.flush_before_modified_input() {
self.handle_paste(pasted); self.handle_paste(pasted);
} }

View File

@@ -163,6 +163,18 @@ impl PasteBurst {
self.burst_window_until = Some(now + PASTE_ENTER_SUPPRESS_WINDOW); self.burst_window_until = Some(now + PASTE_ENTER_SUPPRESS_WINDOW);
} }
/// Try to append a char into the burst buffer only if a burst is already active.
///
/// Returns true when the char was captured into the existing burst, false otherwise.
pub fn try_append_char_if_active(&mut self, ch: char, now: Instant) -> bool {
if self.active || !self.buffer.is_empty() {
self.append_char_to_buffer(ch, now);
true
} else {
false
}
}
/// Decide whether to begin buffering by retroactively capturing recent /// Decide whether to begin buffering by retroactively capturing recent
/// chars from the slice before the cursor. /// chars from the slice before the cursor.
/// ///