This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
fix(plugin-chatbot): render an answer's text and charts in stream order (objectui#13492) - #13500
Merged
Merged
Conversation
mapMessages joined every text part into one `content` and lifted every `data-chart` part into one trailing `charts[]`, so a chart the model drew before writing its analysis still rendered below all of it. Each chart now records where it arrived among the text parts (`textOffset`), and the bubble splits the answer at those points. A message without offsets keeps the old layout. Claude-Session: https://claude.ai/code/session_01VWbYRWtBm3f8J2T8HAt97o Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWbYRWtBm3f8J2T8HAt97o Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contributor
Author
席位核对 — ACCEPT · PR #13500 @
|
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Requested by Elon · project thread
Fixes #13492
Clause-②: no
Metadata-protocol: none
What changed
An assistant answer now renders its text and its charts in the order the stream produced them. A chart the model drew before writing its analysis shows first, so an open-ended analysis in the console's assistant panel puts its chart on the first screen (the acceptance objectstack-ai/cloud#3072 sets). Before,
mapMessagesjoined every text part into onecontentand lifted everydata-chartpart into one trailingcharts[], andChatbotEnhancedrendered the whole text first, so the chart always landed below every paragraph.mapMessages.ts:extractChartsnow records, on each chart, where it arrived among the text parts:textOffset= the length of the text thatextractTextjoined before it. Tool, step and reasoning parts add nothing. Only whencontentIS that join; a legacy stringcontentis not built from the parts, so its charts carry no offset.ChatbotEnhanced.tsx: a new optionalChatChart.textOffset.layoutAnswersplitscontentat the offsets into text runs and chart runs; each text run renders through its ownMessageResponse(so long-answer folding and record links work in every run), and each chart run through the same chart markup as before, now inAnswerCharts. The streaming caret rides the last text run, where it sat before. Charts render in the same tree position whether or not prose has arrived, so a chart drawn before the first word keeps its mounted node when the text streams in.contentandchartskeep their shape. A chart with notextOffset(a host-built message, the legacy string-content shape) or one past the end of the text trails all of it, which is exactly the old layout; a message with no charts renders the same DOM as before.textOffsetis a placement key and never reaches the chart schema handed toSchemaRenderer.The card's acceptance, item by item
data-chart,text: the chart renders before the textdata-chart then text: the chart renders before the analysistext,data-chart,text: the three in that ordertext, data-chart, text: the three render in that orderuseObjectChat.chartOrderRehydrate-13492.test.tsx(API mode, stored message withpartsthrough the hook and into the bubble) andre-mapping a restored message (same parts) yields the same placementobjectui#13032 does not regress: the long analysis after a chart still folds once the stream ends, plus the unchangedchatAnswerLayout-13032.test.tsxobjectui#13037 does not regress: a record link in the text after a chart opens through the host opener, plus the unchangedchatRecordLink-13037.test.tsxNew files:
mapMessages.chartOrder-13492.test.ts(6 tests),ChatbotEnhanced.chartOrder-13492.test.tsx(7, one a CONTROL for the old layout),useObjectChat.chartOrderRehydrate-13492.test.tsx(2).mapMessages.test.tsgains thetextOffsetin the one test that pins a chart's exact shape.Verification (local, head
cb0af96)All runs from the repo root under the shared verify lock.
pnpm exec vitest run --maxWorkers=2 packages/plugin-chatbot/: Test Files 82 passed (82), Tests 787 passed (787).packages/app-shell/srcandapps/console/srcthat import@object-ui/plugin-chatbot(resolved to itssrcby the root config's alias): Test Files 54 passed (54), Tests 582 passed (582).pnpm turbo run type-check --filter=@object-ui/plugin-chatbot(builds the dependency closure, thentsc --noEmit && tsc -p tsconfig.test.json): exit 0 after one fix to the new re-hydrate test (it now hands the hook's messages throughtoRuntimeMessages, as hosts do).eslint --no-inline-configon the six touched source and test files: 0 errors; the 11 warnings are all on lines this PR does not touch.node scripts/check-changeset-presence.mjsandnode scripts/check-changeset-no-major.mjs: pass.pnpm check:new-line-citations: 0 new citations.check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:test-path-roots,check:control-bytes,check:ui-root-lookups,check:unreferenced-sources: all exit 0.ablation-replace.mjswith the fix committed and restore proven (blob equals HEAD,git diff HEADempty):layoutAnswerignorestextOffset(every chart trails the text) ⇒ 6 of the 9 render and re-hydrate tests turn red; the record-link test, the old-layout CONTROL and the mapper tests stay green, as they should.textOffsetspread deleted ⇒ 13 tests red across the four files, including the existing exact-shape test; the legacy no-offset test stays green.pnpm test, repo-widepnpm lint, builds and the remainingcheck:*gates.Acceptance notes
No reload path in this repository restores a chart today, so on reload the chart is missing, not misplaced. The server keeps a conversation as Vercel
ModelMessages (IAIConversationService.addMessagein@objectstack/spec'scontracts/ai-service.ts), which have no data parts. On the way back, app-shell'shydratedMessagesToChatMessagesbuildscontentand tool invocations only, andsanitizeChatMessagesForCachewrites text and tool parts only. Read from code, not measured on staging; outside this card's file surface (packages/plugin-chatbot/src/**). A stored message that does carry itsdata-chartparts keeps its order (pinned above). Whether cloud'svisualize_dataresult carries enough to re-derive the chart on reload is a cloud-side reading this session cannot reach.In an answer that interleaves text and charts, each text run folds on its own (a run taller than two viewport heights folds; a short intro above the chart does not). An answer with no chart, or with its charts after all the text, is one run and folds exactly as before.
Docs: neither
packages/plugin-chatbot/README.mdnorcontent/docs/plugins/plugin-chatbot.mdxdescribes where charts render, so nothing there went stale;textOffsetis documented on theChatCharttype.Adds no product-specific widget, dialog, hook or string (see AGENTS.md › Product-neutral renderer)
Card thread session:
session_01VWbYRWtBm3f8J2T8HAt97o, claimed by thedomain:uiseat 4 (claim comment 6393183623).🤖 Generated with Claude Code
https://claude.ai/code/session_01VWbYRWtBm3f8J2T8HAt97o
Generated by Claude Code