Uh oh!
There was an error while loading. Please reload this page.
feat(ai-build): always show a "Build it" button after propose + friendlier design wait - #2036
Merged
Merged
Conversation
…lier design wait Two UX fixes for the AI Build chat (plugin-chatbot + the two surfaces that drive it, AiChatPage and ConsoleFloatingChatbot). 1. propose_blueprint always yields an explicit confirm gate. The "Proposed plan" card (with Build it / Adjust) only renders when the tool result parses into a structured `proposedPlan` (status:'blueprint_proposed' with ≥1 nameable object). When propose_blueprint finished but returned a thin/oddly-shaped envelope — or proposed in prose — `detectProposedPlan` returned undefined, the step collapsed into a "Propose blueprint · Completed" chip, and the user was left with only the assistant's text telling them to reply "确认" (guess-the-phrase, no button). Now an unstructured-but-finished proposal routes to the detailed body and renders a FALLBACK confirm card with the same explicit Build it / Adjust buttons and the same #432 built-state collapse. The rich card still wins whenever the plan parses (no double card). 2. A friendlier "we're designing" wait for the long propose_blueprint call. propose_blueprint is one atomic LLM request (no token stream), so the bare elapsed timer felt stuck. While it runs, the summary strip (and the detailed header) now show a "Designing your app…" lead-in plus a hint that rotates every 3.5s (mapping data → shaping objects → connecting records → planning views → pulling it together), beside the live timer — so the wait visibly moves. Rotation is presentational only (not real sub-step progress) and is fully localizable; an empty hints array disables it. All copy is label-driven (English defaults in plugin-chatbot; zh/en wired in both surfaces). plugin-chatbot tests 133 → 142 (fallback routing/button/built collapse + hint rotation). app-shell 938 tests green. Both packages type-check and build (DTS) 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.
What
Two UX fixes for the AI Build chat (the magic flow: describe an app → AI proposes a plan → you confirm → AI builds & publishes). Changes live in
plugin-chatbot(the chat component) plus the two surfaces that drive it: the full-pageAiChatPageand the floatingConsoleFloatingChatbot.1 ·
propose_blueprintnow ALWAYS gives an explicit "Build it" buttonBefore (the bug): the "Proposed plan" card — with its one-click Build it / Adjust gate — only renders when the tool result parses into a structured
proposedPlan(i.e.detectProposedPlan()findsstatus:'blueprint_proposed'and at least one nameable object). Whenpropose_blueprintfinished but returned a thin / oddly-shaped envelope, or the model proposed in prose,detectProposedPlanreturnedundefined, so:shouldRenderDetailedTool()was false → the step collapsed into a "Propose blueprint · Completed" summary chip, andFix: a finished-but-unstructured
propose_blueprint(isUnstructuredBuildProposal) now routes to the detailed body and renders a fallback confirm card with the same explicit Build it / Adjust buttons, the same approve/adjust handlers, and the same #432 built-state collapse (turns into an inert "Built" badge onceapply_blueprintruns). The rich plan card still wins whenever the plan parses — no double card. When the host hasn't wiredonSendMessage, it degrades to the same static hint the rich card uses.2 · A friendlier "we're designing" wait during
propose_blueprintpropose_blueprintis a single long, atomic LLM call (no token stream / partial results), so the previous bare elapsed timer made the UI look stuck for tens of seconds. While it runs, the activity summary strip (and the detailed-tool header, for parity) now show a "Designing your app…" lead-in plus a hint that rotates every 3.5s — Mapping out the data → Shaping objects and their fields → Connecting related records → Planning the screens and views → Pulling the plan together — beside the live count-up timer. So the wait visibly moves.This is the pragmatic option from the brief: the rotation is presentational reassurance only (it does not claim real sub-step progress — there's no partial stream to show), it's fully localizable, and an empty hints array disables it. No backend/protocol changes.
Why #1 used to degrade to plain text
The card↔chip routing is gated entirely on
tool.proposedPlanbeing truthy, and that field is only populated bydetectProposedPlan(), which is strict (needs the exact envelope status + ≥1 parseable object). Any propose result the detector can't lift — a lean envelope, a differently-shapedblueprint, or a model that answered in prose instead of the tool — fell through to the generic "Completed" chip with no confirm affordance. The fix decouples "show a confirm gate" from "did the rich plan parse": a completed build-proposal step always earns at least the minimal gate.Copy / i18n
All strings are label-driven. English defaults live in
plugin-chatbot; both surfaces wire zh + en (AiChatPageviat()per-string,ConsoleFloatingChatbotvia its locale object). Note: the floating-chat fallback button still sends the existing确认-anchored approve message, so it matches the cloud confirm-gate regex (service-ai-studioconfirm-gate.ts) and isn't inert.Verification
plugin-chatbot133 → 142 tests. New tests cover, for Implement visual designer for Object UI schemas #1: fallback card renders (not just prose), "Build it" sends the plain approve message, static-hint fallback with noonSendMessage, collapse to "Built" afterapply_blueprint, not shown while still running, and the rich card preferred when the plan parses; for Add automated testing infrastructure and CI/CD workflows #2: the designing indicator (lead-in + rotating hint + timer) shows for a running proposal, rotates on the interval, and a non-proposal running tool keeps the plain timer."Proposed plan"+"The plan is ready. Build it now, or tell me what to adjust."+ Build it + Adjust; running hint cycledMapping… → Shaping… → Connecting…with0:00 / 0:03 / 0:07.plugin-chatbotandapp-shellbothtsc --noEmitclean and build (incl. DTS) clean. (Pre-existing, unrelatedplugin-viewDTSrootDirwarnings were present on the baseline and are untouched by this change.)examples/app-showcaseis a framework data/back-end example and does not mountplugin-chatbotor run the AI build flow, so these two surfaces can't be reproduced there. Reproducing them live needs the full cloud + objectos stack (an AI-enabled tenant env), which is out of scope here. Verification is therefore code + compile + unit/DOM (real component render), not a screenshotted end-to-end session.Deploy note (for a human, later)
This is objectui-only. To reach the running stack it needs a framework
.objectui-shabump + a cloud pin bump after merge — intentionally not bumped here; leave the timing to a human.🤖 Generated with Claude Code