fix: normalize double-escaped LaTeX backslashes and HTML entities (#14564)

Fixes #14562

## Problem
LLMs like DeepSeek V4 Flash and Qwen3-MAX return \\( and \\[ 
(double backslash) in LaTeX output. The preprocessLaTeX() function 
only handled single backslash delimiters, so equations showed as raw
text.
HTML entities like < and > were also not decoded.

## Solution
Added normalization step before existing delimiter conversion:
- \\( → \(  and  \\[ → \[
- &lt; → <  and  &gt; → >  and  &amp; → &

---------

Co-authored-by: Vivek <viveksantoshkumardubey@email.com>
This commit is contained in:
Vivek Dubey
2026-05-06 16:44:34 +05:30
committed by GitHub
parent c9513e5ecb
commit 33d8320ce8
2 changed files with 38 additions and 1 deletions

View File

@@ -56,14 +56,25 @@ const BLOCK_MATH_RE = /\\\[([\s\S]*?)(?<![a-zA-Z])\\\]/g;
const INLINE_MATH_RE = /\\\(([\s\S]*?)(?<![a-zA-Z])\\\)/g;
export const preprocessLaTeX = (content: string) => {
const blockProcessedContent = content.replace(
const normalizedContent = content
.replace(/\\\\\[/g, '\\[')
.replace(/\\\\\(/g, '\\(')
.replace(/\\\\\]/g, '\\]')
.replace(/\\\\\)/g, '\\)')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&');
const blockProcessedContent = normalizedContent.replace(
BLOCK_MATH_RE,
(_, equation) => `$$${equation}$$`,
);
const inlineProcessedContent = blockProcessedContent.replace(
INLINE_MATH_RE,
(_, equation) => `$${equation}$`,
);
return inlineProcessedContent;
};

View File

@@ -0,0 +1,26 @@
import { preprocessLaTeX } from '../chat';
test('handles double-escaped inline LaTeX', () => {
const result = preprocessLaTeX('\\\\(\\\\Delta = b^2\\\\)');
expect(result).toBe('$\\Delta = b^2$');
});
test('handles double-escaped block LaTeX', () => {
const result = preprocessLaTeX('\\\\[E = mc^2\\\\]');
expect(result).toBe('$$E = mc^2$$');
});
test('decodes HTML entities', () => {
const result = preprocessLaTeX('a &lt; b &amp; c &gt; d');
expect(result).toBe('a < b & c > d');
});
test('handles mixed double-escaped delimiters with HTML entities', () => {
const result = preprocessLaTeX('\\\\(x &lt; y\\\\)');
expect(result).toBe('$x < y$');
});
test('passes through already correct single-escaped delimiters unchanged', () => {
const result = preprocessLaTeX('\\(x = 1\\)');
expect(result).toBe('$x = 1$');
});