Files
oikos/plans/2026-07-21-chat-full-polish.md
dtoro ce34cfeac7
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled
feat(web+nomos): fix chat streaming reactivity, unified activity timeline, tool cards in chat
- 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
2026-07-21 07:49:02 +02:00

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 streaming is true and the last assistant message has text.
  • Keep the inline spinner + activity label for the empty-text state.
  • CSS: @keyframes blink, 0.8s cycle, primary color, inline-block.

P0.2 Tool call cards

  • New: web/src/lib/components/ToolCallCard.svelte
  • Modify: ChatThread.svelte
  • Render msg.tools as collapsible cards between text blocks.
  • Collapsed: tool icon + name + status (running/done/error).
  • Expanded: pretty-printed args + result/error in pre blocks.
  • Keep it minimal — one card per tool call, no grouping.
  • Wire pendingApprovals from msg.pendingApprovals as approval cards below the tool list.

P1.3 Timestamps + role labels

  • Modify: ChatThread.svelte, ChatMessage interface
  • Add created_at?: string to ChatMessage (populated from Message.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.svelte prose styles
  • Wrap pre blocks 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.svelte prose styles
  • Wrap tables in overflow-x-auto container.
  • Add overflow-wrap: break-word to 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 in activity.ts already derives from messages; make computeActivityLog session-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: 400 to chat window open call.

P2.8 Cleanup

  • Delete web/src/lib/components/AgentIndicator.svelte (dead code).
  • Update stale comments in SessionChatWindow.svelte and TaskContextPanel.svelte that reference a "main Chat page."
  • Fix prose heading hierarchy: h1 = 1.15em, h2 = 1.1em, h3 = 1.05em.

Verification

  • npx eslint on all changed files
  • go vet ./cmd/nomos/...
  • go build -o /dev/null ./cmd/nomos/...