Repository navigation
Add a code fence renderer plugin slot and rebuild inline-vis on it - #5387
Merged
Merged
Conversation
… fence Changes the experimental_codeFenceRenderer contract and how the app hosts it: - `status: "streaming" | "closed" | "unclosed"` replaces `complete`, so a renderer can tell a block that is still being written from one the reply never closed. - The component for a fence is mounted once and kept for the whole reply. The Markdown tree renders a placeholder; a host around the message's Markdown owns the component and portals it into a container that follows the placeholder from the streaming tail to the settled region. Where the browser has Element.moveBefore, an iframe inside it is not reloaded. - A fence is identified by the source offset of its opening delimiter, so the settled text is no longer re-parsed to number fences. `index` is computed at the message level. - A language claimed by two plugins renders BB's code block. - A throw affects one fence, and the component is tried again when that fence's code or status changes. PluginSlotMount gains a crash reset key. Bumps @get-bb/plugin-sdk to 0.6.40 and updates the plugin guide, authoring skill, and audit entry. Co-Authored-By: Claude Code <noreply@anthropic.com>
…n card - An HTML file shown with the directive is now a borderless sandboxed frame on the thread background that fits the page's height and follows bb's theme, with a hover action to open the file. - A fenced `inline-vis` code block whose body is an HTML page renders the same way through the code fence renderer slot, with no file. A status line shows while the block streams, and a hover action reveals the source. - A Markdown file shows in a card with its file name, copy and open actions, and a preview that expands in place instead of scrolling inside the card. The header-only collapse and its remembered preference are removed. - `height` accepts 80 to 2000: a cap for HTML, the preview height for Markdown. Co-Authored-By: Claude Code <noreply@anthropic.com>
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.
Human comments
What was wrong
Plugins had no supported way to render a multi-line block inside an assistant reply.
messageDirectiveis single-line leaf syntax and stays literal until it closes, so a plugin that wanted generative UI had to scrape renderedpre > codeelements and overlay its own UI (#5268). Separately, the built-ininline-visplugin showed HTML in a fixed 224px card and Markdown in a box that scrolled inside the thread.What changed
New slot:
app.slots.experimental_codeFenceRenderer({ id, languages, component }). A plugin claims fence languages and renders those fenced code blocks in assistant and nested-agent message Markdown. The first two commits are @ComicBit's prototype from #5268 (registration validation, slot store, plugin guide card, test harness support). The third commit rebuilds the rendering side, and the contract differs from the issue's proposal:status: "streaming" | "closed" | "unclosed"replacescomplete, so a renderer can tell a block that is still being written from one the reply never closed.CodeFenceRendererHost) owns the component and portals it into a container that follows the placeholder from the streaming tail to the settled region. Where the browser hasElement.moveBefore, an iframe inside the component is not reloaded by that move; elsewhere component state survives and the iframe reloads once.index(ordinal among fences of the same language) is computed at the message level.messageDirective.codeorstatuschanges, so a renderer that fails on a half-streamed body recovers on the next chunk.PluginSlotMountgainscrashResetKeyfor this; slots that do not pass it behave as before.mermaidstays a core special case insideOriginal, because it renders on every Markdown surface and this slot is scoped to messages.@get-bb/plugin-sdkgoes to 0.6.40. The plugin guide card, the authoring skill references,bb-guide-plugins.md, and thedocs/api_to_audit.mdentry describe the new contract and list what to audit before stabilizing. No server/daemon wire fields change.inline-vis (fourth commit):
::inline-vis{file="…"}is now a borderless sandboxed frame on the thread background that fits the page's height and follows bb's theme variables live, with a hover action to open the file.preparePreviewreturns the file'scontentandsha256for this.inline-viscode block whose body is an HTML page renders the same way through the new slot, with no file. A status line shows while the block streams, and a hover action reveals the source.Behaviour changes for existing users of the directive:
heightis a cap.heightaccepts 80–2000 (was 120–1200). For Markdown it is the preview height, 256px by default (was a 224px scrolling box).bb.inline-vis.collapsedpreference, are removed.How you verified
pnpm exec turbo run typecheck lint --filter='...[origin/main]' --continue: 137 tasks pass.pnpm exec turbo run testfor@bb/app,@get-bb/plugin-sdk,bb-plugin-inline-vis,bb-plugin-plugin-api-docs,@bb/templates,@bb/domain,bb-plugin-bb-guide: all pass (5,731 app tests, 369 SDK, 51 inline-vis, 73 plugin guide, 47 templates, 230 domain, 7 bb-guide).builtin-registry,plugin-app-bundle,bb-official-generator,sdk-compat,plugin-authoring-docs): pass.node apps/app/scripts/check-bundle-budget.mjsafter building@bb/app,node .github/workflows/check-plugin-sdk-version.mjs, andnode packages/plugin-sdk/scripts/check-npm-version-guard.mjs: pass.markdown-code-fence-renderers.test.tsxcover: one component instance and its state kept from the first streamed line through the tail-to-settled move to the finished reply;indexacross the two streaming regions;statusfor unclosed, closed, list-nested, blockquoted, tilde, and over-indented fences; a crash isolated to one fence and retried when its code changes; a contested language falling back to BB's code block; and claims surviving the sanitized HTML pipeline.inline-visblock, an HTML file directive, and Markdown file directives rendered in light and dark themes and at phone width. During a streamed reply the status line showed, the page's iframe was inserted once, moved from the streaming tail to the settled region without being disconnected, and kept its document to the end of the reply.Not verified: Safari and the mobile WebView (no
moveBefore, so an iframe reloads once when its block settles), and clicking the copy and open-in-sidebar actions in the live app (tests cover both).Fixes #5268
🤖 Generated with Claude Code