From 4d6a42a62288351eee4a7302e9d274635aea6f7e Mon Sep 17 00:00:00 2001 From: zhao-oai Date: Mon, 27 Oct 2025 17:11:30 -0700 Subject: [PATCH] fix image drag drop (#5794) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- codex-rs/tui/src/bottom_pane/chat_composer.rs | 10 ++++++++++ codex-rs/tui/src/bottom_pane/paste_burst.rs | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/codex-rs/tui/src/bottom_pane/chat_composer.rs b/codex-rs/tui/src/bottom_pane/chat_composer.rs index 7b4d2f7e..8691b5b1 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer.rs @@ -573,6 +573,16 @@ impl ChatComposer { #[inline] 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() { self.handle_paste(pasted); } diff --git a/codex-rs/tui/src/bottom_pane/paste_burst.rs b/codex-rs/tui/src/bottom_pane/paste_burst.rs index 33a02bde..49377cb2 100644 --- a/codex-rs/tui/src/bottom_pane/paste_burst.rs +++ b/codex-rs/tui/src/bottom_pane/paste_burst.rs @@ -163,6 +163,18 @@ impl PasteBurst { 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 /// chars from the slice before the cursor. ///