feat(chat): render Astra's habit-list card on web + mobile — Stage 2 clients - #300
Conversation
Adds the cross-platform contract for Astra's structured habit-list card: habitListCardSchema (scope + flat items with depth/status) on chatResponse and chatMessage, plus stripHabitListDirective to remove the [[orbit:habits:...]] token from streamed content (the server strips the final message; deltas still carry it mid-flight). i18n badge labels added to en + pt-BR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both chat surfaces now signal supportsHabitListCard in clientContext and render the structured habitList payload Astra returns as a native card (emoji, title, indented hierarchy, status badge) instead of a re-typed text list - the user- visible half of the lost-in-the-middle fix. The [[orbit:habits:...]] directive is stripped from streamed content via the shared util so it never flickers mid-stream. New HabitListCard component mirrored across apps/web (semantic tokens) and apps/mobile (createTokensV2), wired into each message-bubble after the markdown. Falls back to plain text when no payload, so nothing changes for old responses. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
There was a problem hiding this comment.
PR Review: APPROVE (0 Critical, 0 High, 2 Medium). No blocking issues. Medium findings: (1) Web HabitListCard missing empty-state test in message-bubble.test.tsx - add test for habitList with empty items array. (2) C# enum serialization risk in orbit-api (unverifiable in CI) - verify JsonStringEnumConverter on HabitListCardItemDto.Status and HabitListCardDto.Scope in orbit-api PR 238 before deploying. Backward-compat PASS - all shared type changes additive. Perfect cross-platform parity, correct token usage, behavior-focused tests, i18n in both locales. Both mediums are non-blocking. The stated deploy order (orbit-api first) is correct.



Stage 2 (client half) of the Astra habit-listing fix
The user-visible cure for Astra dropping habits when listing. Instead of a re-typed text list (which the model mangles mid-list), the chat now renders the structured
habitListpayload the API returns (orbit-api #238) as a native card.Changes (cross-platform parity)
packages/shared:habitListCardSchemaonchatResponse+chatMessage;stripHabitListDirectiveto remove the[[orbit:habits:...]]token from streamed content (the server strips the final message; deltas still carry it mid-flight);chat.habitList.*i18n in en + pt-BR.supportsHabitListCardinclientContext, maphabitListonto the message, and render a newHabitListCard(emoji · title · indented hierarchy · status badge) after the markdown bubble — web with semantic tokens, mobile withcreateTokensV2. Falls back to plain text when there's no payload.Backward compatibility
Purely additive. With an old API (no
habitList), the card simply never renders — chat behaves exactly as before. The capability flag is opt-in; nothing breaks if the API ignores it.Deploy order
Merge/deploy orbit-api #238 first (it must understand the flag and return the payload), then this. Web picks it up on the next Vercel deploy; mobile when the next Play build ships (older mobile builds keep the text path — and Stage 1's numbering — until they update).
Tests
Shared strip-util tests; web + mobile message-bubble tests (card renders items + badges, directive stripped from content, no card for user messages). Web 1600 passed, mobile 603 passed, shared 1014 passed.
Cross-repo
Backend contract + builder: orbit-api #238 (Stage 2 backend, stacked on #236). Stage 1 (server-side duplicate fix): orbit-api #236.
🤖 Generated with Claude Code