feat: built-in markdown with streaming polish and chat view API changes - #18
Merged
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit add5fea. Configure here.
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 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.

Summary
Roadmap row 25 plus the chat view API decisions that fell out of dogfooding the live example. Five commits, reviewable in order.
Markdown —
FlowMarkdown, assistant prose typeset by a built-in parser (no new dependency). The dialect is what assistants emit: ATX headings on the existing type ramp, emphasis, inline code, fenced code rendered byFlowCodeBlock(sharing theFlowCodePartcopy contract),[label](href)links plus bare-URL autolinks with GFM's trimming rules (balance-aware parens, trailing punctuation,www.prepending), nested lists, quotes, rules, and pipe tables with alignment and overflow scroll. Inline code paints as a rounded chip under the glyphs, so a wrapped chip keeps only its outer corners rounded and the streaming reveal runs straight through it. Links report intent viaonLinkTapand render as plain prose when no handler is wired. Assistant text parts render markdown by default (markdown: falseopts out); user and system turns stay plain.Streaming motion — the reveal runs through one sequenced frontier: nothing renders below the animating block, fences and tables ease in with height and opacity, line growth is eased in layout, and pacing keeps the frontier inside the reveal's lag bound on fast streams. The parser tolerates input that ends mid-construct, and restyles ride source-offset fade stamps so nothing re-fades. Also fixes a first-reply flicker loop (the fit-mode flip is frozen while streaming) and debounces the jump-to-latest button.
Breaking (pre-1.0), each called out in the CHANGELOG: assistant text parts render markdown by default;
FlowChatView.composeris now required (still nullable, and an all-null construction asserts instead of rendering a blank surface);FlowComposer.placeholderdefaults to 'How can I help you today?'; a conversation that fits its viewport reads from the top.Also: tap-to-dismiss and scroll-to-dismiss for the keyboard; the example is now a runnable streaming Gemini chat (platform runners checked in, key via a gitignored
env.g.dart, link taps surfaced in a snackbar).Notes for review:
Screenshots
How this was verified
flutter analyzeclean in the package root,example/, andplayground/;dart format .applied; docs site builds with the new markdown page. A scratch widget-test harness (kept outside the repo per the no-tests policy) replays a Gemini-shaped stream with semantics enabled, irregular delta bursts, a mid-stream drag, and a regenerate, asserting the reveal never collapses. Headless-Chrome captures of the playground web build verify: the typeset document in both themes, the frontier never rendering below the animating block, fences fading in at their turn, every autolink trimming rule (including the parenthesized Wikipedia URL), and a wrapped chip keeping only its outer corners rounded. The live example was exercised end to end against Gemini on the iOS simulator, including the first-reply flicker scenario this PR fixes.Checklist
flutter analyze libandflutter analyzeinexample/andplayground/are cleandart format .applieddependencies:inpubspec.yaml(Flutter SDK and flutter.dev packages only)lib/flow_ui.dartand documented indocs/and the README tableCHANGELOG.mdupdated for user-facing changes, with breaking changes called outfeat:,fix:,refactor:,docs:,chore:)Note
Medium Risk
Large new parser/renderer and several breaking chat APIs (markdown-by-default, required composer, placeholder default, top-aligned short threads) can change host rendering and call sites. The example now talks to Gemini over HTTP with a gitignored key.
Overview
Ships
FlowMarkdown: a built-in, no-dependency parser/renderer for assistant prose (headings, emphasis, lists, quotes, tables, GFM autolinks, fences viaFlowCodeBlock). Assistant text parts render markdown by default; hosts passmarkdown: falsefor literal text. Streaming uses a sequenced frontier (eased line growth, fences/tables fade in, mid-construct input tolerated, reduced-motion static).Chat surface: short threads read from the top until they overflow; keyboard dismisses on surface tap and thread drag;
messageFooterfills the default message footer without replacing the whole turn. Breaking:FlowChatView.composeris required (still nullable),FlowComposer.placeholderdefaults to'How can I help you today?'.The example is now a live Gemini host (stop/retry/copy/feedback, gitignored
env.g.dart, checked-in platform runners). CI stubs the missing key file so analyze still runs.Reviewed by Cursor Bugbot for commit 08cf414. Bugbot is set up for automated code reviews on this repo. Configure here.