Skip to content

Stop image prompts from posting a second user bubble - #43

Merged
ArtificialNotImbecile merged 1 commit into
mainfrom
fix-image-prompt-duplicate
Aug 24, 2026
Merged

Stop image prompts from posting a second user bubble#43
ArtificialNotImbecile merged 1 commit into
mainfrom
fix-image-prompt-duplicate

Conversation

@ArtificialNotImbecile

@ArtificialNotImbecile ArtificialNotImbecile commented Aug 24, 2026

Copy link
Copy Markdown
Owner

What was wrong

Sending a message with image attachments painted the user turn twice: once as the bubble with its thumbnails, then again as a copy carrying the Attached local paths: block and one [Image] line per image. The copy was persisted, so it survived a reload.

Why

Pi stores an image-carrying prompt as a text block plus one content block per image. userTextFromSessionEntry read that entry through the generic content renderer, which renders an image block as [Image], so the entry's text came back as the prompt text plus a placeholder line per image.

The runtime identifies its own prompt among the new session entries by exact text match — sessionEntriesToMessages skips that entry because the caller already has a row for it, and linkCurrentPromptEntry uses the same match to link the message to its Pi entry. With images attached the match never succeeded, so the run emitted its own prompt as a new user turn (live and persisted), and the turn was left without a sessionEntryId, so it could not be branched from.

Fix

Read user entries from their text blocks alone. Attachments already travel on the message row, so the placeholders carried nothing the bubble needed. Assistant and tool-result rendering is untouched.

Test

tests/unit/pi-runtime-equivalence.mjs only ever ran image attachments through the vision-capability rejection path, so nothing reached the identity match with images attached. The new case sends a two-image prompt to a vision-capable mock provider and asserts the persisted rows, the streamed live snapshot, and the prompt link.

Verified red before the fix (['user','assistant'] instead of ['assistant'], and a user role in the live snapshot), green after.

Checks run

  • npm run build
  • npm run test:unit — all suites pass except pi-remote, which fails on a stale local runtime.tar.gz left over from another branch (its gitignored artifact hash predates main's artifact.json); unrelated to this change and not reproducible on a clean checkout
  • npm run harness:check

Full E2E is CI's to confirm.

Also

AGENTS.md no longer routes changes through @codex review; green CI on the head commit is the bar.

🤖 Generated with Claude Code

Pi stores an image-carrying prompt as a text block plus one block per
image. Reading that entry back through the generic content renderer
appended an "[Image]" line per image, so the current prompt no longer
matched the text Jasmine sent. The run then treated its own prompt as a
new user turn: the bubble was painted twice live and persisted twice.
The same match links the prompt to its Pi entry, so an image turn was
also left unbranchable.

Read user entries from their text blocks alone. Attachments already
travel on the message row, so the placeholders carried no information
the bubble needed.

The runtime suite only ever ran image attachments through the
vision-capability rejection path, so no case reached the identity match
with images attached. The new case covers the persisted rows, the live
snapshot, and the prompt link.

Also drop the Codex review step from the change workflow; CI green on the
head commit is now the bar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ArtificialNotImbecile
ArtificialNotImbecile merged commit 0d2df19 into main Aug 24, 2026
11 of 12 checks passed
@ArtificialNotImbecile
ArtificialNotImbecile deleted the fix-image-prompt-duplicate branch August 24, 2026 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant