Skip to content

Commit 5f9d8f2

Browse files
bloveclaudegithub-actions[bot]
authored
feat(chat): render LaTeX/math via lazy KaTeX (#726)
* docs(spec+plan): chat math rendering — correct sequencing (A.0 release prereq) Verification against the PUBLISHED @cacheplane/partial-markdown (0.3.2) showed it has NO math support — the math handler lives unreleased in cacheplane source at 0.4.1. So Part A's premise "ships independently using existing library support" was false. Corrects the spec to add A.0 (release the already-built math 0.4.1 to npm) as the one prerequisite, and that the chat dep-bump + math view must co-ship (md-children renders nothing for an unregistered node type, so bumping alone would blank out math). Adds the Part A implementation plan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(plan): KaTeX CSS self-hosted (no CDN) per decision * feat(chat): lazy KaTeX loader for markdown math rendering * feat(chat): render LaTeX/math via lazy KaTeX Math nodes (math-inline/math-display) from @cacheplane/partial-markdown@0.4.x now render through a MarkdownMathComponent that lazy-loads KaTeX, fixing the raw "$…$" leak in the chat stream. KaTeX is an optional peer dep (mirrors marked): zero base-bundle cost; invalid LaTeX or a missing KaTeX falls back to the raw "$…$" source — never blank, never a crash. CSS is self-hosted by the consumer (no runtime CDN); example apps import katex.min.css. - MarkdownMathComponent + katex-loader (lazy import, katexReady signal) - register math-inline/math-display in cacheplaneMarkdownViews; export the view - bump partial-markdown ^0.3.0 → ^0.4.1; add optional katex peer - streaming integration test: $e^{iπ}+1=0$ → KaTeX, not raw $ - README math note; example styles import katex.min.css NOT YET MERGEABLE: lockfile sync is deferred until @cacheplane/partial-markdown 0.4.1 is published to npm (blocked on npm trusted-publishing setup). Two lint errors (@nx/dependency-checks: partial-markdown version + katex unused) are lockfile-state artifacts that clear once `npm install` runs post-publish. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * build(chat): sync lockfile for partial-markdown 0.4.1 + katex Now that @cacheplane/partial-markdown@0.4.1 is published, sync the lockfile (adds katex + @types/katex, bumps partial-markdown 0.3.0 → 0.4.1). Clears the two @nx/dependency-checks lint errors. No platform bindings dropped. * chore(docs): regenerate api docs * chore(docs): regenerate api docs * fix(chat): render raw HTML nodes as escaped text (0.4.x consumption) Bumping @cacheplane/partial-markdown to 0.4.1 (for math) also pulled in raw HTML parsing, so `<script>…</script>` and other markup now tokenize as html-block / html-inline nodes. The markdown view registry had no renderer for them, so they rendered as nothing — dropping the literal text and breaking the markdown-surfaces e2e XSS-safety assertion. Add MarkdownHtmlComponent rendering node.raw as ESCAPED text (Angular interpolation), registered for html-block + html-inline. Restores the pre-0.4 behavior (HTML shown as literal text, never executed) and keeps the chat XSS-safe. Updates the registry-count test (24 → 26) and exports the component. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(docs): regenerate api docs --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent a8ee48f commit 5f9d8f2

20 files changed

Lines changed: 1132 additions & 18 deletions

apps/website/content/docs/chat/api/api-docs.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5001,6 +5001,28 @@
50015001
],
50025002
"methods": []
50035003
},
5004+
{
5005+
"name": "MarkdownHtmlComponent",
5006+
"kind": "class",
5007+
"description": "Renders a `html-block` / `html-inline` markdown node as **escaped text** —\nthe raw HTML is shown literally (Angular interpolation auto-escapes it),\nnever injected as live markup. This preserves the pre-0.4 behavior where\nraw HTML was plain text, and keeps the chat XSS-safe: model-emitted\n`<script>`, `<iframe>`, etc. are displayed as text and never executed.",
5008+
"params": [],
5009+
"examples": [],
5010+
"properties": [
5011+
{
5012+
"name": "node",
5013+
"type": "InputSignal<MarkdownHtmlBlockNode | MarkdownHtmlInlineNode>",
5014+
"description": "",
5015+
"optional": false
5016+
},
5017+
{
5018+
"name": "raw",
5019+
"type": "Signal<string>",
5020+
"description": "",
5021+
"optional": false
5022+
}
5023+
],
5024+
"methods": []
5025+
},
50045026
{
50055027
"name": "MarkdownImageComponent",
50065028
"kind": "class",
@@ -5087,6 +5109,40 @@
50875109
],
50885110
"methods": []
50895111
},
5112+
{
5113+
"name": "MarkdownMathComponent",
5114+
"kind": "class",
5115+
"description": "Renders a `math-inline` / `math-display` markdown node as KaTeX. KaTeX is\nlazy-loaded (see katex-loader); until it resolves, or if the LaTeX is\ninvalid, the raw `$…$` source is shown — never blank, never a crash.",
5116+
"params": [],
5117+
"examples": [],
5118+
"properties": [
5119+
{
5120+
"name": "display",
5121+
"type": "Signal<boolean>",
5122+
"description": "",
5123+
"optional": false
5124+
},
5125+
{
5126+
"name": "html",
5127+
"type": "Signal<SafeHtml | null>",
5128+
"description": "",
5129+
"optional": false
5130+
},
5131+
{
5132+
"name": "node",
5133+
"type": "InputSignal<MathNode>",
5134+
"description": "",
5135+
"optional": false
5136+
},
5137+
{
5138+
"name": "raw",
5139+
"type": "Signal<string>",
5140+
"description": "",
5141+
"optional": false
5142+
}
5143+
],
5144+
"methods": []
5145+
},
50905146
{
50915147
"name": "MarkdownParagraphComponent",
50925148
"kind": "class",

0 commit comments

Comments
 (0)