fix(markdown): render LaTeX math in chat with KaTeX - #3409
Merged
Conversation
OpenWork rendered Markdown but had no math engine, so $...$, $$...$$, \(...\) and \[...\] all showed up as raw LaTeX source in technical conversations (reported against v0.18.12). - Add a markdown-math marked extension: marked-katex-extension covers the standard dollar delimiters (same approach as upstream opencode web), plus local block/inline extensions for the \(...\) and \[...\] pairs models commonly emit, which markdown would otherwise swallow as escapes. - Register it on both the sync and Shiki-highlighted parsers so formulas do not flicker when a message with a code block upgrades. - Allow <semantics>/<annotation> through DOMPurify; they are not in its default MathML allowlist, so the accessible MathML branch (and copy-as-TeX) was being stripped. - Wrap every math renderer so malformed LaTeX degrades to visible source instead of throwing out of the React render and blanking the message. - Skip .katex when applying find-in-conversation highlights. - Import katex CSS and keep formulas at the surrounding text size. Tests: apps/app/tests/markdown-math.test.ts covers all four delimiters, MathML survival through sanitization, graceful failure, currency amounts, code spans, both parsers and both presentations.
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Member
Author
…zation' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
benjaminshafii
enabled auto-merge (squash)
August 1, 2026 07:50
src-opn
approved these changes
Aug 1, 2026
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.




What
OpenWork renders Markdown but had no math engine, so
$...$,$$...$$,\(...\)and\[...\]all displayed as raw LaTeX source — making technical/physics conversations hard to read.Reported by Daniel Kovner (kovnerd@gmail.com) against v0.18.12 via in-app feedback.
Addresses all three asks from the report:
$...$/$$...$$with KaTeX, viamarked-katex-extension(the upstream opencode web approach).\(...\)/\[...\], which models commonly emit.How
apps/app/src/components/markdown/markdown-math.ts(new) — one marked extension.marked-katex-extensionhandles the dollar delimiters; local block + inline extensions handle\(...\)/\[...\], which markdown would otherwise swallow as backslash escapes. Kept the standard (notnonStandard) dollar rule so$5 and $10stays prose.<semantics>/<annotation>. They are not in DOMPurify's default MathML allowlist, so the accessible MathML branch (and copy-as-TeX) was being silently stripped.throwOnError: falseonly catches KaTeXParseError; anything else would throw straight out of the synchronous React render and blank the whole message. Fallback shows the original LaTeX.text-highlights.ts: skip.katexso find-in-conversation cannot inject<mark>into formula layout spans.katex/dist/katex.min.css; keep formulas at surrounding text size and let long display math scroll.Tests
pnpm --filter @openwork/app typecheckbun test --isolate tests/(apps/app)pnpm --filter @openwork/app buildpnpm fraimz --flow markdown-mathpnpm fraimz --flow markdown-primitiveThe 2 unit failures (
message-list-loading.test.tsx) are pre-existing — baselineorigin/devgives an identical 574 pass / 2 fail, and the file passes in isolation on both.markdown-primitivestep 4 times out mounting the Browser panel; verified identical on baselineorigin/devin the same sandbox, so it is a sandbox limitation, not a regression. Steps 1-3 (chat markdown, code blocks, search highlighting) pass on both.New unit tests in
apps/app/tests/markdown-math.test.tscover all four delimiters, MathML survival through sanitization, graceful failure, currency amounts, code spans, both parsers and both presentations.Proof
fraimz run driving the real Electron app on Daytona — full artifact posted below.