ui: Mermaid Diagrams in chat + interactive preview#24032
Conversation
There was a problem hiding this comment.
Pull request overview
Adds initial Mermaid diagram rendering support to the UI markdown renderer by transforming Mermaid code blocks into Mermaid-compatible <pre class="mermaid"> nodes and running Mermaid client-side after markdown updates.
Changes:
- Introduces a new
rehypeMermaidPreplugin to convertlanguage-mermaidcode blocks into<pre class="mermaid">…</pre>. - Adds lazy-loaded Mermaid rendering in
MarkdownContent.svelte, plus styling and special handling for streaming Mermaid blocks. - Adds
mermaidas a UI dependency (and updates the lockfile accordingly).
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tools/ui/src/lib/components/app/content/MarkdownContent/plugins/rehype/mermaid-pre.ts | New rehype transform to convert Mermaid code fences into Mermaid-renderable <pre> nodes. |
| tools/ui/src/lib/components/app/content/MarkdownContent/MarkdownContent.svelte | Runs Mermaid rendering after markdown updates and adds Mermaid-specific styling/streaming UI. |
| tools/ui/package.json | Adds Mermaid dependency. |
| tools/ui/package-lock.json | Lockfile updates for Mermaid and its transitive dependencies. |
Files not reviewed (1)
- tools/ui/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
2a8f56e to
531c6d1
Compare
4200215 to
36716a3
Compare
| function createButton( | ||
| className: string, | ||
| title: string, | ||
| iconSvg: string, | ||
| mermaidId: string | ||
| ): Element { | ||
| return { | ||
| type: 'element', | ||
| tagName: 'button', | ||
| properties: { | ||
| className: [className], | ||
| 'data-mermaid-id': mermaidId, | ||
| title, | ||
| type: 'button' | ||
| }, | ||
| children: [createIconElement(iconSvg)] | ||
| }; | ||
| } | ||
|
|
||
| function createCopyButton(mermaidId: string): Element { | ||
| return createButton(COPY_CODE_BTN_CLASS, 'Copy mermaid syntax', COPY_ICON_SVG, mermaidId); | ||
| } | ||
|
|
||
| function createPreviewButton(mermaidId: string): Element { | ||
| return createButton(PREVIEW_CODE_BTN_CLASS, 'Preview diagram', PREVIEW_ICON_SVG, mermaidId); | ||
| } | ||
|
|
||
| function createHeader(mermaidId: string): Element { | ||
| return { | ||
| type: 'element', | ||
| tagName: 'div', | ||
| properties: { className: [CODE_BLOCK_HEADER_CLASS] }, | ||
| children: [ | ||
| { | ||
| type: 'element', | ||
| tagName: 'span', | ||
| properties: { className: [CODE_LANGUAGE_CLASS] }, | ||
| children: [{ type: 'text', value: 'mermaid' }] | ||
| }, | ||
| { | ||
| type: 'element', | ||
| tagName: 'div', | ||
| properties: { className: [CODE_BLOCK_ACTIONS_CLASS] }, | ||
| children: [createCopyButton(mermaidId), createPreviewButton(mermaidId)] | ||
| } | ||
| ] | ||
| }; | ||
| } |
There was a problem hiding this comment.
This is the same stuff as we have for Code blocks. let's DRY the code for generating the kind of wrappers for enhanced code blocks as well as mermaid blocks
1c8ac20 to
d8423ac
Compare
d8423ac to
4627f4f
Compare
|
It's a must-have, I'm going to test it on my server before you merge it. |
|
In addition, we can follow-up for raw SVG blocks if we want another time:) I haven't seen any regressions or edge cases. |
@ServeurpersoCom nit sure if there's an issue for that already. If not - can u please create it? |
I've already written the code because you've already done most of the work inside this PR, but the models have a tendency to use an XML block, but if you ask it "put it in an SVG block" it does.
|
|
In addition, I'm looking into whether we can do real-time SVG rendering as the tokens are generated, but it's really an optional fun feature. |
|
Happy to see this landed the day i returned to my computer! Worth noting - statically loading mermaid adds ~5MB to the bundle size; Would have been nice to get credited in some way for it aswell but nevertheless. Good work! |
|
@allozaur I am observing following error in build. Should I open an issue ? Build Error
vite v7.3.2 building ssr environment for production...
transforming...
✓ 3885 modules transformed.
-- UI: npm run build failed (1)
-- stderr: ✗ Build failed in 6.39s
error during build:
[vite]: Rollup failed to resolve import "mermaid" from "/home/tipu/Development/GH/llama.cpp/tools/ui/src/lib/components/app/content/MarkdownContent/MarkdownContent.svelte".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
at viteLog (file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/vite/dist/node/chunks/config.js:33639:57)
at file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/vite/dist/node/chunks/config.js:33673:73
at onwarn (file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/@sveltejs/kit/src/exports/vite/index.js:963:10)
at file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/vite/dist/node/chunks/config.js:33673:28
at onRollupLog (file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/vite/dist/node/chunks/config.js:33668:63)
at onLog (file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/vite/dist/node/chunks/config.js:33471:4)
at file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/rollup/dist/es/shared/node-entry.js:21369:32
at Object.logger [as onLog] (file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/rollup/dist/es/shared/node-entry.js:23364:9)
at ModuleLoader.handleInvalidResolvedId (file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/rollup/dist/es/shared/node-entry.js:22108:26)
at ModuleLoader.resolveDynamicImport (file:///home/tipu/Development/GH/llama.cpp/tools/ui/node_modules/rollup/dist/es/shared/node-entry.js:22166:58)
|
Deleting existing llama.cpp/tools/ui/package-lock.json and node_modules folder resolved the issue. |
|
Yeah, @ggerganov sent me that error yesterday, will push a fix later today |
|
Can you kindly confirm what does the following do. It does not seem to do anything for me. If I start server with reason either off or on. Reasoning budget button overrides it. What does this option add? |
yeah, it's a deprecated setting, should be removed |
hey! I was almost certain we were both authors of the first commit in this PR, but somehow it got lost! sorry for this! |
(cherry picked from commit ee4cf70)

Overview
Close #23477
Features
MermaidPreviewcomponent that renders diagrams as SVGDialogMermaidPreviewcomponent allowing to zoom in/out, move around the diagram and download the SVGDemo
mermaid-demo.mp4
Downloaded SVG File
Requirements