-
Notifications
You must be signed in to change notification settings - Fork 46.2k
Description
Problem
The backend ChatMessage Prisma model already has a stable UUID id field, but the Pydantic ChatMessage model strips it in from_db(). This means:
- Hydrated messages (from REST API) get synthetic IDs like
${sessionId}-${index} - Streamed messages (from AI SDK via SSE) get their own auto-generated UUIDs
- Same message, different ID depending on the source
The frontend currently works around this with a content fingerprint deduplication function (deduplicateMessages in helpers.ts) that compares consecutive assistant messages by text content. This is fragile and adds complexity.
Root Cause
The backend Pydantic model (backend/copilot/model.py:ChatMessage) does not include the id field, even though the Prisma schema already has it as a UUID primary key.
Proposed Solution
Backend
- Add
id: str | None = Noneto the PydanticChatMessagemodel - Thread it through
from_db():id=prisma_message.id - Include
idin REST responses (session history endpoint) - Include
idin SSE stream events (when saving messages during streaming)
Frontend
- Update
convertChatSessionMessagesToUiMessagesto usemsg.idfrom the API response instead of${sessionId}-${index} - Align AI SDK streaming to use the same IDs when available
- Simplify or remove the
deduplicateMessagesfingerprint logic once IDs are stable
Files to Change
Backend:
backend/copilot/model.py- Addidfield toChatMessage, updatefrom_db()- Chat REST endpoints - Ensure
idis serialized in responses - SSE streaming - Include message
idin stream events
Frontend:
copilot/helpers/convertChatSessionToUiMessages.ts- Use backendidinstead of syntheticcopilot/helpers.ts- SimplifydeduplicateMessages(may become unnecessary)copilot/useCopilotStream.ts- Align hydrated + streamed message IDs
Context
Discussion: https://discord.com/channels/1126875755960336515/1126875756925046928/1478360192495128708
Originated from Zamil's review of Ubbe's SSE proxy removal PR (#12254) - the dedup logic raised questions about why IDs aren't aligned between backend and frontend.