TUI: clipboard image paste for text-only models saves the PNG, then discards its path — insert the path as text instead

Open 💬 2 comments Opened Aug 25, 2026 by liustack
💡 Likely answer: A maintainer (etraut-openai, contributor) responded on this thread — see the highlighted reply below.

Summary

When the active model does not advertise image input, pasting a clipboard image in the TUI writes the image to a temp file and then throws the path away, leaving only a warning. Every neighboring code path in the same situation preserves the path as plain text. Making the clipboard-paste branch do the same would let text-only models (paired with vision-bridge tooling) keep working, with a very small change.

Current behavior (rust-v0.149.1)

  1. Ctrl+V with an image on the clipboard always writes a temp PNG first: paste_image_to_temp_png() creates codex-clipboard-*.png before any modality check (clipboard_paste.rs#L121).
  2. attach_image then checks current_model_supports_images(); when false it emits a warning and returns, discarding the freshly saved path (chatwidget/interaction.rs#L204). The file stays on disk; its path survives only in debug logs.

Inconsistency with neighboring paths

  • Pasting an image file path (rather than a bitmap) into the composer with a text-only model falls through to insert_str, so the path is kept as plain text (chat_composer.rs#L1151).
  • Core request assembly for text-only models also preserves the path: strip_images_when_unsupported replaces only the InputImage pixels with a placeholder, while the <local_image [Image #N] path="..."> text tag survives (context_manager/normalize.rs#L317, protocol/models.rs#L1739).

So the design elsewhere is consistently "no pixels for text-only models, but keep the path as text". The TUI clipboard-paste branch is the one place that drops it.

Proposed change

In attach_image's unsupported branch, insert the already-saved temp path into the composer as plain text (same treatment as a pasted image file path), optionally keeping the existing warning. No request-level changes needed: core already strips pixels for text-only models.

Why it matters

Users on text-only models increasingly pair Codex with vision-bridge skills/tools that read an image from a path appearing in the conversation. Today the same user action (Ctrl+V) works in flows where the path label survives, but dead-ends in the TUI even though the bytes are already on disk. Reference report: https://github.com/liustack/modlens/issues/78

Suggested test coverage

  • Text-only model + clipboard bitmap → composer contains the temp PNG path as text; submitted request contains no input_image.
  • Image-capable model keeps the current attachment behavior.
  • Paths with spaces; WSL (PowerShell fallback already returns a converted path).

View original on GitHub ↗

2 Comments

etraut-openai contributor · 2 days ago

Out of curiosity, which model(s) are you using that don't have vision capabilities?

Alphaxiaoteng · 2 days ago

Verified local patch evidence for openai/codex#40595

I reproduced the text-only-model branch at unit level and validated a minimal local patch against the current public TUI code.

Root cause

paste_image_to_temp_png() saves the clipboard bitmap before modality checking. ChatWidget::attach_image() then warns and returns when the active model does not advertise image support, leaving the composer unchanged and discarding the only user-visible reference to the saved PNG.

Tested behavior

The local patch inserts the already-saved path into the composer as plain text in the unsupported-image branch, keeps the existing warning, and leaves image attachments empty. Submitting the draft produces a normal UserInput::Text, not an image payload.

Verification on the repository-pinned Rust 1.95.0 toolchain:

just fmt
  passed

just test -p codex-tui attach_image_with_text_only_model_inserts_path_as_text_and_warns
  1 passed, 3896 skipped

just test -p codex-tui chatwidget::tests::composer_submission
  60 passed, 3837 skipped

just fix -p codex-tui
  completed successfully

Changed public-source locations:

  • codex-rs/tui/src/chatwidget/interaction.rs
  • codex-rs/tui/src/chatwidget/tests/composer_submission.rs

The focused test verifies all four boundaries: path text is retained, no local image attachment is created, the existing warning is emitted, and submission remains text-only.

Per the repository contribution policy, I have not opened a code PR. I can provide the two-file patch if useful to the maintainers.