Fix chat timeline hydration bug causing UI run-on text

This commit is contained in:
2026-06-15 15:54:23 -07:00
parent efa17311da
commit abf3856686
14 changed files with 32 additions and 22 deletions

View File

@@ -71,7 +71,7 @@ export function WizardTop({
}}
>
<img
src="/vibn-logo-circle-black.png"
src="/vibn-black-circle-logo.png"
alt="VIBN"
style={{ width: "100%", height: "100%", objectFit: "cover" }}
/>

View File

@@ -48,7 +48,7 @@ export default function RootLayout({
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="theme-color" content="#1a1510" />
<link rel="apple-touch-icon" href="/vibn-logo-circle-black.png" />
<link rel="apple-touch-icon" href="/vibn-logo-circle.png" />
<link rel="manifest" href="/manifest.json" />
</head>
<body

View File

@@ -160,7 +160,7 @@ export function VIBNSidebar({ workspace, tabs, activeTab }: VIBNSidebarProps) {
}}
>
<img
src="/vibn-logo-circle-black.png"
src="/vibn-black-circle-logo.png"
alt="VIBN"
style={{ width: "100%", height: "100%", objectFit: "cover" }}
/>
@@ -233,7 +233,7 @@ export function VIBNSidebar({ workspace, tabs, activeTab }: VIBNSidebarProps) {
}}
>
<img
src="/vibn-logo-circle-black.png"
src="/vibn-black-circle-logo.png"
alt="VIBN"
style={{ width: "100%", height: "100%", objectFit: "cover" }}
/>

View File

@@ -518,23 +518,30 @@ const MessageBubble = React.memo(function MessageBubble({
{!isUser && (
<div
style={{
width: 32,
height: 32,
width: 24,
height: 24,
borderRadius: "50%",
background: "#f4f4f5", // Zinc-100 instead of black
display: "flex",
alignItems: "center",
justifyContent: "center",
marginRight: 10,
marginRight: 8,
flexShrink: 0,
marginTop: 0,
overflow: "hidden"
marginTop: 2,
border: "1px solid #e4e4e7",
}}
>
<img
src="/vibn-logo-circle-black.png"
alt="Vibn AI"
style={{ width: "100%", height: "100%", objectFit: "cover" }}
/>
<span
style={{
color: "#18181b", // Dark gray instead of white
fontSize: "0.6rem",
fontWeight: 700,
fontFamily: "var(--font-lora),serif",
fontStyle: "italic",
}}
>
V.
</span>
</div>
)}
<div
@@ -1188,6 +1195,7 @@ export function ChatPanel({
(m: {
role: string;
textSegments?: string[];
timeline?: TimelineEntry[];
toolCalls?: Array<{
name: string;
args: Record<string, unknown>;
@@ -1195,6 +1203,13 @@ export function ChatPanel({
}>;
}) => {
if (m.role !== "assistant") return m as unknown as Message;
// If the backend provided a perfectly ordered timeline (from our new Postgres schema), use it directly!
if (Array.isArray(m.timeline) && m.timeline.length > 0) {
return { ...m, content: "" } as unknown as Message;
}
// Fallback for very old messages in the database before the timeline was tracked
const segs: string[] = Array.isArray(m.textSegments)
? m.textSegments
: [];
@@ -1203,12 +1218,7 @@ export function ChatPanel({
kind: "text",
text: t,
}));
// We don't have round-level interleaving for tool calls in
// the persisted shape (the schema flattens them), so we drop
// the toolCalls into the timeline at the end. The streamed
// shape preserves true ordering; this is just a reload
// approximation. Good enough — what the user really cares
// about is the text segments not run-on'ing into one blob.
if (Array.isArray(m.toolCalls)) {
for (const tc of m.toolCalls) {
timeline.push({ kind: "tool", name: tc.name, status: "done" });
@@ -2426,7 +2436,7 @@ export function ChatPanel({
style={{ flexShrink: 0, display: "flex" }}
>
<img
src="/vibn-logo-circle-black.png"
src="/vibn-black-circle-logo.png"
alt="VIBN"
width={26}
height={26}
@@ -2735,7 +2745,7 @@ export function ChatPanel({
style={{ flexShrink: 0, display: "flex" }}
>
<img
src="/vibn-logo-circle-black.png"
src="/vibn-black-circle-logo.png"
alt="VIBN"
width={26}
height={26}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 740 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 797 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 745 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 783 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 812 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 741 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 782 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 758 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 786 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 844 KiB