Skip to content

TUI renders a user message twice when a prompt reuses an existing messageID #50945

Description

@AlexDochioiu

Version

opencode 1.18.32 (opencode serve + opencode attach)

Summary

Sending a prompt with the messageID of an existing message rewrites that message with a new time.created, but keeps the same id. The TUI sync store keys messages by time.created + id (packages/tui/src/context/sync.tsx, messageKey). When the second message.updated arrives, the lookup misses, so the TUI inserts a second row for the same id. Parts are keyed by message id, so both rows render the same content.

Storage is correct: the session has one message with one part. Reloading the session shows it once.

Repro

B=http://localhost:4096; H='x-opencode-directory: /tmp/dir'
SID=$(curl -s -X POST $B/session -H 'content-type: application/json' -H "$H" -d '{}' | jq -r .id)
# reserve an empty message
MID=$(curl -s -X POST $B/session/$SID/message -H 'content-type: application/json' -H "$H" \
  -d '{"parts":[],"noReply":true}' | jq -r .info.id)
# reuse it
curl -s -X POST $B/session/$SID/message -H 'content-type: application/json' -H "$H" \
  -d "{\"messageID\":\"$MID\",\"parts\":[{\"type\":\"text\",\"text\":\"hello\"}],\"noReply\":true}"

With opencode attach $B -s $SID open, "hello" appears in two user rows. The event stream shows two message.updated events for $MID with different time.created values.

Suggested fix

Key TUI messages by id alone. Ascending message ids already sort by creation time, so time.created in the key only breaks the lookup when a message is rewritten. Alternatively, keep the original time.created when a prompt reuses an existing messageID.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions