Skip to content

Chat redesign: streaming, citation seals, sources panel, sidebar, themes - #41

Merged
Badri-Rajendran merged 11 commits into
mainfrom
feature_chat_redesign_ui
Sep 26, 2026
Merged

Badri-Rajendran merged 11 commits into
mainfrom
feature_chat_redesign_ui

Conversation

@Badri-Rajendran

Copy link
Copy Markdown
Owner

Problem

The chat read like a prototype:

  • answers showed raw Markdown and [Source: …] / [Plan: …] markers;
  • sources were bare file names;
  • answers arrived all at once behind three dots;
  • threads couldn't be searched or renamed;
  • there was no theme choice and no keyboard shortcuts;
  • on a phone the sidebar took 40% of the screen.

This PR is Part B of the approved chat redesign (spec docs/superpowers/specs/2026-09-26-chat-redesign-design.md, plan docs/superpowers/plans/2026-09-26-chat-redesign.md, mockups docs/design/chat-redesign/). It builds on the backend merged in #40.

Implementation

  • Tokens and theme:
    • the redesign's paper, ink and brass palette, in light and dark;
    • a System / Light / Dark choice, remembered per browser;
    • a new brass seal favicon.
  • Streaming:
    • fetch plus a hand-written SSE parser (services/sse.js), since EventSource can't POST with a Bearer token;
    • progress steps ("Searching the references", "Searching plans near you", "Reading Summaries of Benefits", "Writing the answer");
    • reset handling, and done replacing the draft with the saved answer;
    • Stop or Esc aborts the answer, keeps the question, and offers "Ask again".
  • Answers:
    • Markdown through react-markdown + remark-gfm, with no raw HTML, https-only links, and images shown as their alt text;
    • [Source: …] markers become numbered brass seals, which stamp in only on an answer that just finished;
    • [Plan: …] markers become plan links that scroll to and flash their row;
    • Copy writes plain text.
  • Sources panel: a desktop column, or a bottom sheet on a phone. It shows the brief quote, the document and section, a match meter, the carrier's PDF or the Wikipedia link, and Wikipedia's CC BY-SA credit, with the unverified, changed and missing states.
  • Plan table: rows are numbered, each has "Ask about this plan", and a plan named in the text jumps to its row. It keeps every existing premium, SBC and exchange note.
  • Sidebar:
    • threads grouped Today / Previous 7 days / Earlier;
    • search as you type, with highlighting;
    • inline rename, and delete with inline confirmation;
    • an account menu with the theme and shortcuts;
    • it can be hidden, and on a phone it becomes a drawer.
  • Shortcuts: Ctrl/⌘K for a new question, / to type, Esc to stop or close.
  • Sign-in, register and profile are restyled to match. Sign-in shows an example cited answer, and the profile page sits inside the app shell.
  • New dependencies, pinned exactly: lucide-react 1.48.0, motion 13.4.4, react-markdown 10.1.0 and remark-gfm 4.0.1. npm audit --omit=dev finds 0 vulnerabilities.

Validation

  • npm run lint passes. npm test: 430 tests in 62 files pass (188 before). npm run build passes.

  • The branch is rebased on main 8dcf2fe. The SSE event names and payload fields were checked against the merged src/api/routes/chat.py.

  • Playwright pass against the local stack (real API, real OpenAI calls, a local test account with ZIP 92101):

    • register;
    • a plan question streamed its progress steps, then text, then the 9-row numbered table;
    • a coverage question showed the standard-version notice and seals;
    • a seal opened Sharp's real SBC passage, starting at "Urgent care", with an 82% match and the PDF link;
    • rename, through the new PATCH, and search with highlighting;
    • the dark theme survived a reload, as did the renamed title, and the stamp didn't replay;
    • 390×844: scrollWidth === clientWidth (390), and the Sources sheet worked;
    • Stop: the question was kept, "Ask again" appeared, no partial answer was saved, and spend was recorded.

    Screenshots were taken locally (.playwright-mcp/e2e/, gitignored).

  • An independent code review found no critical issues, and confirmed the security points: no dangerouslySetInnerHTML or rehype-raw, https-only URLs, rel="noopener noreferrer" on every new-tab link, and only the theme and the sidebar flag in localStorage.

Security, DB and API impact

  • No backend, database or API change. It consumes the endpoints from Chat backend: streaming answers, cited passages, renaming threads #40.
  • Security: LLM output is treated as untrusted. Markdown renders without raw HTML, links pass an https-only transform, and the marker plugin emits only its own component nodes, whose plan names come from the API's plan data, not the model's text.

Follow-ups (known, deliberately not in this PR)

Important:

  1. Seal numbers change after a reload. The live done message lists sources in saved order, and a reload lists them by relevance. Fix: sort sources by relevance in _save_answer (backend).
  2. Sending while scrolled up doesn't scroll to the new question.
  3. A network drop mid-stream shows the browser's own error text ("Load failed"), can show an error after a saved answer, and doesn't cancel the reader. Fix: wrap the read loop in apiStream.
  4. The phone drawer doesn't keep keyboard focus inside it; the Sources sheet does.
  5. Screen readers don't hear the finished answer: the live region is removed at done.

Minor:

  • The Sources count counts passages, while seals count documents.
  • The seal stagger restarts after the plan table.
  • Seal labels don't name what they cite.
  • The panel says "the latest answer" when showing an older one.
  • 404 and 422 messages show as raw text and lose the draft; add a 4,000-character limit on the composer.
  • The plan-row flash timer isn't cleared on a second click.
  • The example seals on sign-in are focusable but do nothing.
  • Lazy-load the chat and profile routes, so sign-in doesn't load the Markdown and animation code (the bundle is 621 kB, 199 kB gzipped).
  • The model still repeats the plans as a bulleted list under the table (prompt: "show plans as a compact table").
  • Notices are recognised by their wording; a structured notices field would be sturdier.
  • Seals are numbered by cited document, not by array position; record this in ADR 0027.

Copilot AI lite review requested due to automatic review settings September 26, 2026 23:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Badri-Rajendran
Badri-Rajendran merged commit f32505b into main Sep 26, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants