[feat-007a] Live citation rendering for vision mode

↗ view on GitHub · Nick Whitehouse · 2026-05-04 · 436d028d

Three pieces working together so pills appear progressively as the
model streams, instead of all-at-once at end-of-turn:

1) Stream-parse the hidden <CITATIONS> JSON block. Once <CITATIONS>
   opens we accumulate into a buffer and brace-depth scan for newly
   completed {...} entries every delta, emitting a citation_added SSE
   event per entry the moment it's parseable. Each ref is deduped via
   a per-turn Set so the end-of-turn batched citations event doesn't
   re-emit. Resets the per-iter buffer in flushText.

2) Per-marker citation verifier (Olava non-streaming, parallel). When
   exactly one PDF is in scope we pre-extract its text once, then in
   onContentDelta scan iterText for newly-complete [N] or superscript
   runs and fire a verifyCitation Promise per marker without awaiting.
   Each resolution emits citation_added live + pushes to events. v1
   currently misses 0/N - debug logging added but the stream-parser
   path covers the live-pill UX independently.

3) Frontend rAF coalescer. A burst of 30+ citation_added events would
   otherwise yield 30 setMessages calls → 30 ChatView re-renders → 30
   updateScrollButton invocations, compounding into max-update-depth.
   Buffer pending citations in a ref and flush once per animation
   frame; force-flush at end-of-stream.

Plus: PDF render swapped from @napi-rs/canvas to node-canvas (napi
rejects pdfjs's internal Path2D objects in ctx.fill, breaking the
very first page). Frontend preprocessCitations also matches Unicode
superscript marker runs (¹²³⁴), which Olava sometimes prefers in
legal-style prose.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Repository nwhitehouse/mike
Author Nick Whitehouse <nick.whitehouse@mccarthyfinch.com>
Authored
Parents f870b0a2
Stats 7 files changed , +584 , -46
Part of Vision mode: PDF page images → Olava (feat-007a / 008 / 009 / 010 / bug-005)

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-436d028d.md from inside the repo you want the change in.

⬇ Download capture-commit-436d028d.md