Chat turns render out of order after a reply #136

Closed
opened 2026-10-25 05:55:26 -07:00 by westfarn · 1 comment
Owner

What happens

After a reply finishes, the bubbles are no longer in the order they were sent.

Screenshots from the joke thread:

  • While the reply is generating, order is correct: "Tell me a joke", the joke, "I don't know", then the working status.
  • When the reply lands, order becomes: "I don't know", "Tell me a joke", the new answer, then the original joke. The action row sits on the joke, so the joke is treated as the last turn.

Same chat also fails to use the previous turn (backend). This ticket is the display order.

Why

  • GET conversation_details does not order prompts. The post-stream refetch (about 800ms after END) replaces the optimistic list with that unordered payload.
  • On START_OF_THE_STREAM, MessageContext copies conversationDetails from the websocket subscription closure into conversationRef. That closure can be the list from before the optimistic user turn. END then pops and appends on the short list.
  • Bubble keys are id || index. An optimistic row with no id can collide with a real id.

Fix

  • Sort turns oldest-first by created, then id, whenever the thread is written into state.
  • Keep conversationRef aligned with that state. Do not replace it from the websocket closure on START.
  • Give each optimistic turn a stable local key.

Backend prompt ordering is the matching chat_backend ticket.

## What happens After a reply finishes, the bubbles are no longer in the order they were sent. Screenshots from the joke thread: - While the reply is generating, order is correct: "Tell me a joke", the joke, "I don't know", then the working status. - When the reply lands, order becomes: "I don't know", "Tell me a joke", the new answer, then the original joke. The action row sits on the joke, so the joke is treated as the last turn. Same chat also fails to use the previous turn (backend). This ticket is the display order. ## Why - `GET conversation_details` does not order prompts. The post-stream refetch (about 800ms after END) replaces the optimistic list with that unordered payload. - On `START_OF_THE_STREAM`, `MessageContext` copies `conversationDetails` from the websocket subscription closure into `conversationRef`. That closure can be the list from before the optimistic user turn. `END` then pops and appends on the short list. - Bubble keys are `id || index`. An optimistic row with no id can collide with a real id. ## Fix - Sort turns oldest-first by `created`, then id, whenever the thread is written into state. - Keep `conversationRef` aligned with that state. Do not replace it from the websocket closure on START. - Give each optimistic turn a stable local key. Backend prompt ordering is the matching `chat_backend` ticket.
Author
Owner

Same-chat history and prompt ordering are chat_backend#84.

Same-chat history and prompt ordering are chat_backend#84.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ai_ml_operations/chat_web_app#136