feat(ai-partner): streaming chat UI with citation pills (#1455)#1485
Merged
Conversation
Wires the live Amicus conversation experience onto the shell from #1454. New service module: - services/amicus/streamParser.ts — pure helpers: extractDeltaText (SSE content_block_delta parser), parseAssistantMessage (interleaves text and citation pill nodes, strips trailing gap + follow_ups envelopes, preserves unknown source types as literal text, dedupes citations). - services/amicus/chat.ts — streamChat orchestrator: profile → retrieve → POST /ai/chat SSE → onDelta/onCitation/onGapSignal/onComplete/onError with typed AmicusError. New hook: - hooks/useAmicusThread — message history, optimistic send, AbortController for stop, typed error state, persistence on complete. New components under src/components/amicus/: - MessageList (inverted FlatList, "New message ↓" jump pill, follow-up chips slot) - UserMessageBubble (gold) - AssistantMessageBubble (renders parsed nodes with inline CitationPill, StreamingDot while streaming) - CitationPill (compact gold pill, tappable; navigation in #1456) - StreamingDot (pulsing Animated.Value) - FollowUpChips (3 tappable chips under final assistant message) - InputBar (multi-line, Send ↔ Stop button) Screen wiring: - screens/AmicusThreadScreen — swaps the shell for MessageList + InputBar and renders an ErrorBanner above the input for typed errors. Tests: - 14 new parser tests — CITE / [chunk_id] forms, dedup, unknown source type fallback, interleaved nodes, gap + follow_ups envelopes, non-JSON trailing brace preservation, cite→[chunk_id] normalization. Full suite (3,272 tests) passes; tsc clean. https://claude.ai/code/session_01Pht3kzgdvkn81DDfL9SnFe
Test Results✅ All tests passed
Coverage
⏱️ Duration: 78.9s |
Fixes the post-merge coverage drop flagged by CI on #1485. - 7 new component tests (CitationPill, InputBar, UserMessageBubble, AssistantMessageBubble, FollowUpChips, MessageList, StreamingDot) - 5 new chat.ts orchestrator tests covering happy path, 401/402 (PROXY_UNAUTHORIZED), 429 (rate limit), offline, and gap-envelope delivery - jest.config.js excludes dev-only smoke harness (screens/dev/ and services/amicus/__smoke__/) from coverage collection Global thresholds now pass: statements 80.39, lines 82.2, functions 72.7, branches 66.1. https://claude.ai/code/session_01Pht3kzgdvkn81DDfL9SnFe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1455. Phase 2 of epic #1446. Depends on #1454 + #1457 (both merged) + #1450 (merged).
Summary
Real-time streaming Amicus chat: token-by-token deltas, inline citation pills, follow-up chips, Stop button, typed error banners.
New modules
services/amicus/streamParser.ts— pure helpers for SSE + structured envelopesservices/amicus/chat.ts— end-to-end orchestrator (retrieve→/ai/chatSSE)hooks/useAmicusThread— per-thread state, optimistic send, abort, persistencecomponents/amicus/*— MessageList, UserMessageBubble, AssistantMessageBubble, CitationPill, StreamingDot, FollowUpChips, InputBarscreens/AmicusThreadScreen— wired to the full stackKey behaviors
[CITE:type:id]or[type:id]markers become tappable pills inline.{"follow_ups": [...]}and{"gap": true/false}envelopes are parsed off the end and removed from prose.AbortControllerand preserves partial text.AmicusErrorrendered as a dismissable banner above the input.onComplete.Test plan
npx tsc --noEmitcleanOut of scope
onCitationPresslogs for now.https://claude.ai/code/session_01Pht3kzgdvkn81DDfL9SnFe