fix(tui): rehydrate drafts and restore image placeholders (#9040)

Fixes #9050

When a draft is stashed with Ctrl+C, we now persist the full draft state
(text elements, local image paths, and pending paste payloads) in local
history. Up/Down recall rehydrates placeholder elements and attachments
so styling remains correct and large pastes still expand on submit.
Persistent (cross‑session) history remains text‑only.

Backtrack prefills now reuse the selected user message’s text elements
and local image paths, so image placeholders/attachments rehydrate when
rolling back.

External editor replacements keep only attachments whose placeholders
remain and then normalize image placeholders to `[Image #1]..[Image #N]`
to keep the attachment mapping consistent.

Docs:
- docs/tui-chat-composer.md

Testing:
- just fix -p codex-tui
- cargo test -p codex-tui

Co-authored-by: Eric Traut <etraut@openai.com>
This commit is contained in:
Chriss4123
2026-02-07 20:08:45 -08:00
committed by GitHub
co-authored by Eric Traut
parent a94505a92a
commit d68e9c0f19
3 changed files with 255 additions and 42 deletions
+45
View File
@@ -123,6 +123,51 @@ positional args, Enter auto-submits without calling `prepare_submission_text`. T
- Prunes attachments based on expanded placeholders.
- Clears pending pastes after a successful auto-submit.
## History navigation (Up/Down) and backtrack prefill
`ChatComposerHistory` merges two kinds of history:
- **Persistent history** (cross-session, fetched from core on demand): text-only.
- **Local history** (this UI session): full draft state.
Local history entries capture:
- raw text (including placeholders),
- `TextElement` ranges for placeholders,
- local image paths,
- pending large-paste payloads (for drafts).
Persistent history entries only restore text. They intentionally do **not** rehydrate attachments
or pending paste payloads.
### Draft recovery (Ctrl+C)
Ctrl+C clears the composer but stashes the full draft state (text elements, image paths, and
pending paste payloads) into local history. Pressing Up immediately restores that draft, including
image placeholders and large-paste placeholders with their payloads.
### Submitted message recall
After a successful submission, the local history entry stores the submitted text and any element
ranges and local image paths. Pending paste payloads are cleared during submission, so large-paste
placeholders are expanded into their full text before being recorded. This means:
- Up/Down recall of a submitted message restores image placeholders and their local paths.
- Large-paste placeholders are not expected in recalled submitted history; the text is the
expanded paste content.
### Backtrack prefill
Backtrack selections read `UserHistoryCell` data from the transcript. The composer prefill now
reuses the selected messages text elements and local image paths, so image placeholders and
attachments rehydrate when rolling back to a prior user message.
### External editor edits
When the composer content is replaced from an external editor, the composer rebuilds text elements
and keeps only attachments whose placeholders still appear in the new text. Image placeholders are
then normalized to `[Image #1]..[Image #N]` to keep attachment mapping consistent after edits.
## Paste burst: concepts and assumptions
The burst detector is intentionally conservative: it only processes “plain” character input