- fix(web): Svelte 5 identity-based reactivity broke text_delta streaming — immutable message objects in all three chat handlers so text streams live - feat(web): streaming cursor + inline status indicator merged into message flow - feat(web): expandable inline tool call cards in chat thread - feat(web): merge Plan + Event log into one backbone Activity timeline — filled status nodes, branch stubs, auto-scroll follow mode, per-session activityLog, compact for the rail - fix(nomos): add X-Accel-Buffering:no to /chat SSE (proxy buffering) - fix(nomos): plan step auto-close SQL param bug (store.go) - polish: timestamps, role labels, code copy button, table overflow, min window size, delete AgentIndicator/ActivityTimeline dead code
3.1 KiB
3.1 KiB
2026-07-21 Chat window full polish
Context
After fixing the streaming reactivity bug and merging the double thinking indicator, the chat window still has structural UX gaps: no streaming affordance while text flows, tools never rendered inline, no timestamps, no code copy, cross-session store leaks in floating windows, and minor overflow/style holes.
Decisions
| Question | Answer |
|---|---|
| Streaming feel | Typing cursor (blinking ▍) + inline indicator |
| Tool calls | Expandable inline tool cards in message flow |
| Empty state | Minimal — title + tagline, no suggestions |
| Dark theme | Keep neutral (skip) |
| Scope | Full polish — everything |
Changes
P0.1 Streaming cursor
- File:
web/src/lib/components/ChatThread.svelte - Add a blinking block-cursor (▍) appended after rendered markdown when
streamingis true and the last assistant message has text. - Keep the inline spinner + activity label for the empty-text state.
- CSS:
@keyframesblink,0.8scycle,primarycolor,inline-block.
P0.2 Tool call cards
- New:
web/src/lib/components/ToolCallCard.svelte - Modify:
ChatThread.svelte - Render
msg.toolsas collapsible cards between text blocks. - Collapsed: tool icon + name + status (running/done/error).
- Expanded: pretty-printed args + result/error in
preblocks. - Keep it minimal — one card per tool call, no grouping.
- Wire
pendingApprovalsfrommsg.pendingApprovalsas approval cards below the tool list.
P1.3 Timestamps + role labels
- Modify:
ChatThread.svelte,ChatMessageinterface - Add
created_at?: stringtoChatMessage(populated fromMessage.created_at). - Show small muted timestamp (HH:MM) on hover or inline next to role label.
- Add tiny "You" / "Nomos" labels above bubbles (subtle, muted).
P1.4 Code copy button
- Modify:
ChatThread.svelteprose styles - Wrap
preblocks in a relative container; add a copy button (clipboard icon, top-right, opacity-0 → visible on hover). - Use
navigator.clipboard.writeText.
P1.5 Table overflow + user bubble fix
- Modify:
ChatThread.svelteprose styles - Wrap tables in
overflow-x-autocontainer. - Add
overflow-wrap: break-wordto user bubbles.
P2.6 Cross-session fixes
- Modify:
web/src/lib/stores/chat.ts,SessionChatWindow.svelte chatErrors: keep global for now (session-scoped errors are rare and the dismiss is manual anyway).activityLog: per-session — the store inactivity.tsalready derives from messages; makecomputeActivityLogsession-scoped so each floating window only sees its own activity.
P2.7 Min window size
- Modify:
web/src/lib/stores/windows.ts(openTaskWindow) - Add
minWidth: 600, minHeight: 400to chat window open call.
P2.8 Cleanup
- Delete
web/src/lib/components/AgentIndicator.svelte(dead code). - Update stale comments in
SessionChatWindow.svelteandTaskContextPanel.sveltethat reference a "main Chat page." - Fix prose heading hierarchy: h1 = 1.15em, h2 = 1.1em, h3 = 1.05em.
Verification
npx eslinton all changed filesgo vet ./cmd/nomos/...go build -o /dev/null ./cmd/nomos/...