fix(desktop): 修复搜索结果排版 — stripToolNarration 保留 markdown 结构
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

根因: stripToolNarration 按句子切分再用空格拼接,破坏了所有 markdown
格式(标题/列表/段落/代码块),导致搜索结果显示为纯文本墙。

修复: 改为按行处理,只过滤匹配叙述模式的行,保留 markdown 结构行
(标题/列表/空行/引用/代码/表格)。关键变化:
- 保留空行(markdown 段落分隔符)
- 保留以 #/-/*/数字/>/```/| 开头的结构行
- 仅过滤 LLM 内部叙述("让我执行..."、"Let me..."等)
This commit is contained in:
iven
2026-04-22 16:24:40 +08:00
parent 5816f56039
commit 81005c39f9

View File

@@ -643,10 +643,14 @@ export function ChatArea({ compact, onOpenDetail }: { compact?: boolean; onOpenD
* and Chinese ("让我执行...", "让我尝试..."). These are internal thoughts, not user-facing content. * and Chinese ("让我执行...", "让我尝试..."). These are internal thoughts, not user-facing content.
*/ */
function stripToolNarration(content: string): string { function stripToolNarration(content: string): string {
const sentences = content.split(/(?<=[。!?.!?])\s*/); // Process line-by-line to preserve markdown structure (headings, lists, paragraphs)
const filtered = sentences.filter(s => { const lines = content.split('\n');
const t = s.trim(); const filtered = lines.filter(line => {
if (!t) return false; const t = line.trim();
// Keep empty lines (paragraph breaks in markdown)
if (!t) return true;
// Keep markdown structural lines (headings, list items, horizontal rules, blockquotes, code)
if (/^(#{1,6}\s|[-*+]\s|\d+\.\s|>|\s*```|---|\|)/.test(t)) return true;
// English narration patterns // English narration patterns
if (/^(?:Now )?[Ll]et me\s/i.test(t)) return false; if (/^(?:Now )?[Ll]et me\s/i.test(t)) return false;
if (/^I\s+(?:need to|keep getting|should|will try|have to|can try|must)\s/i.test(t)) return false; if (/^I\s+(?:need to|keep getting|should|will try|have to|can try|must)\s/i.test(t)) return false;
@@ -656,8 +660,8 @@ function stripToolNarration(content: string): string {
if (/^好的,让我为您/.test(t)) return false; if (/^好的,让我为您/.test(t)) return false;
return true; return true;
}); });
const result = filtered.join(' ').replace(/\s{2,}/g, ' ').trim(); const result = filtered.join('\n');
return result || content; // Fallback: if everything was stripped, show original return result || content;
} }
function MessageBubble({ message, onRetry }: { message: Message; setInput?: (text: string) => void; onRetry?: () => void }) { function MessageBubble({ message, onRetry }: { message: Message; setInput?: (text: string) => void; onRetry?: () => void }) {