feat(client): render chat replies as markdown with collapsible thinking #359
No reviewers
Labels
No labels
area:auth
area:ci
area:db
area:infra
area:native
area:pwa
area:service
epic
feature
foundation
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
james/carol!359
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "352-chat-markdown"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Assistant chat replies now render as Markdown, and
<think>…</think>reasoning renders as a collapsed-by-default, expandable section.What's in it
lib/agent/parseAssistantContent.ts— pure, node-tested splitter carving an assistant string into orderedmarkdown/thinksegments. An unterminated<think>(still streaming) becomes a trailing thinking-in-progress block so the live bubble stays stable and settles cleanly when</think>arrives.lib/markdown/Markdown.tsx— self-rendered Markdown → RN primitives (headings, bold/italic, inline + fenced code, links viaLinking.openURL, blockquotes, lists). No dependency added — the mature RN markdown libs are stale against this React 19 / RN 0.85 / Expo 56 stack and carry old native transitives. NodangerouslySetInnerHTML→ no XSS surface (semgrep clean). Colors viatheme.tokens; tolerates partial markdown mid-stream.lib/agent/AssistantMessage.tsx— composes segments + a collapsibleThinkBlock(LucideChevronRight/ChevronDown).chat.tsxuses it for assistant rows + the live streaming bubble; user/tool text stays plain<Text>.chat.reasoning.{show,hide}("Show thinking" / "Hide thinking").Verification (local, re-run in the worktree)
typecheck✓ ·lint✓ ·test✓ 162 (+8parseAssistantContentcases) · nopackage.json/lockfile change (no dep) · semgrep ✓ 0 findings on the 4 changed source files⚠️ Needs maintainer verification (headless limit)
Client tests are
node-env — the visual Markdown rendering and the think-block collapse/expand need a real check on both Android and the PWA: progressive rendering as tokens stream, link taps, code-block/list/quote styling in light + dark themes, and the collapse toggle. The pure parsing layer is unit-tested.Closes #352
🤖 Generated with Claude Code
Assistant chat replies now render as Markdown, and `<think>…</think>` reasoning renders as a collapsed-by-default, expandable section. - lib/agent/parseAssistantContent.ts: pure, node-tested splitter that carves an assistant string into ordered markdown/think segments; handles an unterminated <think> (still streaming) as a trailing thinking-in-progress block so the live bubble stays stable. - lib/markdown/Markdown.tsx: self-rendered Markdown → RN primitives (headings, bold/italic, inline + fenced code, links via Linking, blockquotes, lists). No dependency added — the mature RN markdown libs are stale against this React 19 / RN 0.85 / Expo 56 stack and carry old native transitives. No dangerouslySetInnerHTML, so no XSS surface. Colors via theme.tokens; tolerates partial markdown mid-stream. - lib/agent/AssistantMessage.tsx: composes segments + a collapsible ThinkBlock (ChevronRight/ChevronDown). chat.tsx uses it for assistant rows + the live streaming bubble; user/tool text stays plain. - i18n: chat.reasoning.{show,hide}. Closes #352 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>📊 Test coverage
Patch coverage: no testable lines changed.
Overall (
app/,lib/,db/, excluding UI per ADR-0019):Soft thresholds per ADR-0019. Coverage is informational and does not block merge.