AI scenarios
Long conversations
Bit.BlazorUI.AI Scripted transportFive hundred messages with code, tables, tool calls, and citations, rendered through a virtualized list.
Live demo
Scroll to the top and back, then send something: new content follows the view only while you are already at the bottom.
How it works
Up to a threshold every message is rendered, which is both simpler and faster. Past it
(BitAiUiOptions.VirtualizeThreshold, sixty messages here) only the newest sixty are: scroll up
and the older ones come in thirty at a time above what you are reading, which stays where it is, and once you
are back at the newest message they are let go of again. Nothing is estimated - every message drawn is drawn
at its own height - so the content never jumps and the view never goes blank. The conversation is
deliberately varied - a thousand identical paragraphs would prove nothing; the hard case is mixed content
with wildly different heights.
The five hundred messages are built in code (AiDemoConversations.Long) - a
BitAiConversation filled with AddMessage, each answer a
BitAiMessage of parts: text, Markdown, a tool call with its result, a table with a citation - and
handed to the session factory (SessionFactory.Create(conversation)), so new messages go to the
transport registered for the site, which echoes them. A conversation restored from storage is handed over
the same way (see Conversations).
Where the render budget goes:
- A part subscribes to itself, so a token re-renders the part it went into - not its message, nor the transcript. The chat around it renders as a turn starts and as it ends.
-
Each of those views renders at most once per 50 ms
(
BitAiUiOptions.RenderInterval), however many tokens arrive in that time - coalesced by aBitAiRenderScheduler, which an app's own component listening to a stream can use too (see Streaming). -
Bursts of text are evened out before they reach the conversation: the session paces the deltas
(
BitAiChatSessionOptions.Pacing), so a paragraph arriving at once is drawn over a few frames rather than in one. - Text accumulates in a builder, so appending stays linear.
- Markdown before the last block boundary is parsed once and reused.
Components used
BitAiMessageList- the transcript, drawing only its newest messages past the threshold, with auto-scroll that follows only a reader at the newest message.BitAiScrollToLatest- the way back down once the reader has scrolled away.BitAiMessagePartView- one part, re-rendered only when it changes.
Feedback
Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.