Uh oh!
There was an error while loading. Please reload this page.
fix(console-ai): keep draft/plan cards across cache-fallback reload + remap server tool-call type - #1877
Merged
Merged
Conversation
… remap server tool-call type Two reload regressions on the AI chat surface, both in app-shell's useChatConversation.ts: 1. sanitizeChatMessagesForCache rebuilt cached tool parts WITHOUT the tool `output`. On the readMessageCache fallback (server returns no/partial messages), mapMessages.detectDraftResult / detectProposedPlan had nothing to parse, so the "Review N changes / Publish" card, the ADR-0038 verification chip, and the #1875 "Proposed plan" card silently vanished — only the bare tool header survived. Fix (lean): re-serialize the already-derived draftReview / proposedPlan into a COMPACT, re-parseable `output` envelope — dropping the heavy blueprint (object `fields` / `failed` are materialized only to the length the detectors count). Stored as `output` (a first-class SDK tool-part field, not a custom key) because the AI SDK preserves `output` through useChat init — exactly as the server-backed mergeToolResultsInto path relies on. No mapMessages change: the existing detectors re-parse the compact envelope. 2. toUIMessages passed the server's ModelMessage assistant tool-call part `type:'tool-call'` through verbatim. In the ConsoleFloatingChatbot path (hydratedHistory = uiMessagesToChatMessages, which derives toolName from the part type) this humanized the step title to "Call" instead of "Apply blueprint" / "Propose blueprint". Remap `tool-call` (with a toolName) to `tool-<toolName>`; the result-merge and detectors are unaffected (they key off toolCallId / output). AiChatPage's own mapper reads the toolName field and was already immune. Adds 4 regression tests (round-trip live -> cache -> reload through sanitizeChatMessagesForCache + uiMessageToChatMessage; tool-call remap), verified to fail without the fix. app-shell (576) + plugin-chatbot (118) suites green; type-check + lint clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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 freeto 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.
Problem
Two independent reload regressions on the AI chat surface, both in app-shell's
useChatConversation.ts:Cache-fallback strips the affordance cards.
sanitizeChatMessagesForCacherebuilt cached tool parts without the tooloutput. When the loader falls back toreadMessageCache(server transiently returns no/partial messages, or offline),mapMessages.detectDraftResult/detectProposedPlanhad nothing to parse → the draft "Review N changes / Publish" card, the ADR-0038 verification chip, and the feat(console-ai): reviewable "Proposed plan" card before build #1875"Proposed plan" card silently vanished. Only the bare tool header remained.Server
tool-call→ "Call" title.toUIMessagespassed the server's ModelMessage assistant tool-call parttype:'tool-call'through verbatim. In theConsoleFloatingChatbotpath (hydratedHistory = uiMessagesToChatMessages, which derivestoolNamefrom the part type) this humanized the tool step to "Call" instead of "Apply blueprint" / "Propose blueprint" after a clean server-backed reload.Fix
Compact
output(lean). Sanitize now re-serializes the already-deriveddraftReview/proposedPlaninto a minimal, re-parseableoutputenvelope — dropping the heavy blueprint JSON (objectfields/failedare materialized only to the length the detectors count). Stored asoutput— a first-class SDK tool-part field, not a custom part key — because the AI SDK preservesoutputthroughuseChatinit exactly as the server-backedmergeToolResultsIntopath already relies on (custom keys risk being stripped). NomapMessageschange: the existing detectors re-parse the compact envelope.Remap in
toUIMessages. Assistanttype:'tool-call'(with atoolName) →tool-<toolName>. The result-merge and detectors are unaffected (they key offtoolCallId/output).AiChatPage's own hydration mapper reads thetoolNamefield directly and was already immune — the remap is harmless to it.Verification
useChatConversation.test.tsx: a full live → cache →localStorage(JSON) → reload round-trip throughsanitizeChatMessagesForCache+uiMessageToChatMessageassertingdraftReview/proposedPlan(all fields) survive, a leanness check (no field defs in the cached plan), and thetool-callremap. Confirmed they fail without the fix.🤖 Generated with Claude Code