From f462a9d85acc0511d28020e196f64a41e0e01879 Mon Sep 17 00:00:00 2001 From: PandaMan Date: Tue, 24 Feb 2026 12:30:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(web):=20prevent=20LaTeX=20from=20being=20cu?= =?UTF-8?q?t=20at=20\right]=20or=20\big)=20in=20agent=20o=E2=80=A6=20(#131?= =?UTF-8?q?55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What problem does this PR solve? - Use negative lookbehind (? { + it('converts block \\[ \\] to $$ $$', () => { + expect(preprocessLaTeX('\\[ x + y \\]')).toBe('$$x + y$$'); + }); + + it('converts inline \\( \\) to $ $', () => { + expect(preprocessLaTeX('\\( a \\)')).toBe('$a$'); + }); + + it('does not cut block math at \\right] (Closes #13134)', () => { + const content = '\\[ C_{seq}(y|x) = \\frac{1}{|y|} \\sum_{t=1}^{|y|} \\right] \\]'; + const result = preprocessLaTeX(content); + expect(result).toContain('\\right]'); + expect(result).toContain('\\frac{1}{|y|}'); + expect(result).toBe( + '$$ C_{seq}(y|x) = \\frac{1}{|y|} \\sum_{t=1}^{|y|} \\right] $$', + ); + }); + + it('does not cut inline math at \\big) or nested parens', () => { + const content = '\\( f(x) + \\big) \\)'; + const result = preprocessLaTeX(content); + expect(result).toContain('\\big)'); + expect(result).toBe('$ f(x) + \\big) $'); + }); + + it('handles multiple block equations', () => { + const content = 'First \\[ a \\] then \\[ b \\right] c \\]'; + const result = preprocessLaTeX(content); + expect(result).toBe('First $$a$$ then $$ b \\right] c $$'); + }); +}); diff --git a/web/src/utils/chat.ts b/web/src/utils/chat.ts index 39c91d6693..3ffd884556 100644 --- a/web/src/utils/chat.ts +++ b/web/src/utils/chat.ts @@ -39,14 +39,24 @@ export const buildMessageUuidWithRole = ( // Preprocess LaTeX equations to be rendered by KaTeX // ref: https://github.com/remarkjs/react-markdown/issues/785 +// +// Delimiter matching: we only treat \] and \) as block/inline endings when they +// are not part of a LaTeX command (e.g. \right], \big), \left)). Use a negative +// lookbehind (? { const blockProcessedContent = content.replace( - /\\\[([\s\S]*?)\\\]/g, + BLOCK_MATH_RE, (_, equation) => `$$${equation}$$`, ); const inlineProcessedContent = blockProcessedContent.replace( - /\\\(([\s\S]*?)\\\)/g, + INLINE_MATH_RE, (_, equation) => `$${equation}$`, ); return inlineProcessedContent;