From 8415870520cdeedf62ae12aaa259df56b1bd7045 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Sun, 26 Apr 2026 21:06:19 -0700 Subject: [PATCH] fix(chat): pin historical user-message timestamps to activity created_at MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User flagged that all historical user bubbles render with the same "now" clock after a chat reload — both messages in the screenshot showed 9:01:58 PM despite being sent hours apart. ChatTab.tsx:142 minted user messages with createMessage(...) which calls new Date().toISOString() — fine for a freshly-typed message, wrong for hydrated history. Every reload re-stamped all user bubbles to the render moment, collapsing the visible chronology. The agent path on line 157 already overrides with a.created_at; mirror that. One-line fix (spread + override timestamp) plus a comment explaining why the override is load-bearing so the next refactor doesn't drop it. Co-Authored-By: Claude Opus 4.7 (1M context) --- canvas/src/components/tabs/ChatTab.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/canvas/src/components/tabs/ChatTab.tsx b/canvas/src/components/tabs/ChatTab.tsx index 68734f11..c4b326e7 100644 --- a/canvas/src/components/tabs/ChatTab.tsx +++ b/canvas/src/components/tabs/ChatTab.tsx @@ -136,10 +136,14 @@ async function loadMessagesFromDB(workspaceId: string): Promise<{ messages: Chat const messages: ChatMessage[] = []; // Activities are newest-first, reverse for chronological order for (const a of [...activities].reverse()) { - // Extract user message from request_body + // Extract user message from request_body. Pin the timestamp to + // the activity row's created_at — without this override every + // historical user bubble re-stamps to "now" on each chat reload, + // and ALL user messages collapse to the same render-time clock + // (same as the agent path on line 157). const userText = extractRequestText(a.request_body); if (userText && !isInternalSelfMessage(userText)) { - messages.push(createMessage("user", userText)); + messages.push({ ...createMessage("user", userText), timestamp: a.created_at }); } // Extract agent response — text AND any file attachments so a