Skip to content

V2 chat shows TeX, Mermaid diagrams and chart payloads as raw text #1376

Description

@paullizer

Problem

Three kinds of block that SimpleChat already produces are rendered as raw text in the V2 React chat (application/v2_ui).

1. Mermaid diagrams

This is the least obvious and arguably the most impactful. Azure Content Understanding already extracts document figures as Mermaid and writes them into page content as fenced blocks:

# application/single_app/functions_content_understanding.py:330
if figure_kind == 'mermaid' and isinstance(figure_content, str) and figure_content.strip():
    diagram_block = f"```mermaid\n{figure_content.strip()}\n```"

So a user who uploads a document containing a flowchart and asks about it gets diagram source pasted into the middle of the answer. Nothing renders it in either interface.

2. TeX

Models emit \( ... \), \[ ... \] and $$ ... $$. None of it renders, so any answer involving mathematics arrives as unreadable markup.

3. SimpleChart

The built-in chart action emits ```simplechart fences (functions_chart_operations.py:191). The classic interface renders these via static/js/chat/chat-inline-charts.js; V2 shows the raw JSON payload — often several kilobytes of it — in the middle of the reply.

Scope

V2 React UI only. The classic interface is unchanged.

Constraints

  • No new remote browser code. Third-party browser libraries must be downloaded and committed to the repository so the bytes the browser executes are pinned and any change to them is a reviewable commit rather than a silent substitution. This rules out resolving them from npm at build time as well as loading them from a CDN at run time.
  • The Content-Security-Policy in config.py (default-src 'self', script-src 'self', font-src 'self') must not be relaxed.
  • Diagram and equation source is untrusted model output, so anything rendered from it needs an explicit sanitizer boundary — V2 currently uses dangerouslySetInnerHTML nowhere.
  • A single $...$ must not be treated as inline maths, or ordinary prose about money ("costs $5 to $10 per user") renders as an equation.

Acceptance criteria

  • $$...$$, \[...\] and \(...\) render as maths; a lone $ does not
  • ```mermaid fences render as diagrams
  • ```simplechart fences render as charts, with the underlying data reachable and an image download
  • Fenced and inline code containing these delimiters is left untouched
  • A reply that is still streaming does not repeatedly hand the renderer a half-written fence
  • Diagrams and charts follow the light/dark theme
  • Copying a message does not paste a raw chart payload
  • All third-party browser code is committed under version control, with licences and pinned versions
  • The CSP is unchanged

Resolution

Implemented in v0.261.019.

  • Libraries vendored under application/v2_ui/public/vendor/<library>-<version>/: KaTeX 0.18.4, Mermaid 11.17.2, Chart.js 4.5.1, DOMPurify 3.4.14. All files verified against the registry's published SHA-256, licences preserved, and loaded on demand so a conversation with no maths, diagram or chart downloads none of them. No npm dependencies were added.
  • remark-math was deliberately not used: CommonMark treats a backslash before ASCII punctuation as an escape, so \(x\) is already the literal text (x) by the time an mdast node exists and a post-parse plugin cannot see the delimiters. Maths instead reuses the placeholder mechanism the renderer already has for citations and masks.
  • KaTeX runs with trust: false; Mermaid with securityLevel: 'strict', htmlLabels: false, no autostart and no icon packs. Both pass through DOMPurify before injection — the only two dangerouslySetInnerHTML sites in the SPA, enforced by test.
  • The markdown renderer moved from MessageList.tsx into its own AssistantMarkdown.tsx.

Verified in a real browser across light and dark themes. Covered by functional_tests/test_v2_rich_rendering.py; the full V2 suite (18 files) passes.

Documentation: docs/explanation/features/REACT_V2_UI.md, docs/explanation/release_notes.md.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions