From c4f0fb5a3d131bdb00e1156f78c4e1482fcbf4e8 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Sun, 18 Jan 2026 13:36:53 +0000 Subject: [PATCH] =?UTF-8?q?feat(ai-assistant):=20=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E8=BF=9E=E7=BB=AD=E5=B7=A5=E5=85=B7=E4=BD=BF=E7=94=A8=E7=9A=84?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 Markdown 渲染前预处理文本,将连续的 tool-use 标签合并为一行显示: - 连续相同工具显示计数(如 get_page_context x 2) - 不同工具用逗号分隔 - 工具间的空行不会打断合并 --- resources/assets/js/utils/markdown.js | 77 +++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/resources/assets/js/utils/markdown.js b/resources/assets/js/utils/markdown.js index c8dea2090..34e0a2c76 100644 --- a/resources/assets/js/utils/markdown.js +++ b/resources/assets/js/utils/markdown.js @@ -268,6 +268,82 @@ const MarkdownPluginUtils = { export {MarkdownPluginUtils} +/** + * 合并连续的工具使用 + * 例如: + * > Tool: a + * > Tool: b + * > Tool: b + * 合并为: + * > Tool: a, b x 2 + * + * @param {string} text + * @returns {string} + */ +function mergeConsecutiveToolUse(text) { + const toolUsePattern = /^>\s*Tool:\s*([^<]+)<\/tool-use>\s*$/; + const lines = text.split('\n'); + const result = []; + let toolGroup = []; + + const formatToolGroup = (tools) => { + if (tools.length === 0) return ''; + if (tools.length === 1) return `> Tool: ${tools[0]}`; + + // 合并连续相同的工具 + const merged = []; + let currentTool = tools[0]; + let count = 1; + + for (let i = 1; i < tools.length; i++) { + if (tools[i] === currentTool) { + count++; + } else { + merged.push(count > 1 ? `${currentTool} x ${count}` : currentTool); + currentTool = tools[i]; + count = 1; + } + } + merged.push(count > 1 ? `${currentTool} x ${count}` : currentTool); + + return `> Tool: ${merged.join(', ')}`; + }; + + let pendingEmptyLines = []; // 暂存空行 + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const match = line.match(toolUsePattern); + + if (match) { + // 工具使用行,丢弃暂存的空行,继续收集 + pendingEmptyLines = []; + toolGroup.push(match[1].trim()); + } else if (line.trim() === '' && toolGroup.length > 0) { + // 空行且已有工具组,暂存空行 + pendingEmptyLines.push(line); + } else { + // 非工具使用的非空行,结束当前工具组 + if (toolGroup.length > 0) { + result.push(formatToolGroup(toolGroup)); + toolGroup = []; + } + // 输出暂存的空行 + result.push(...pendingEmptyLines); + pendingEmptyLines = []; + result.push(line); + } + } + + if (toolGroup.length > 0) { + result.push(formatToolGroup(toolGroup)); + } + // 输出末尾暂存的空行 + result.push(...pendingEmptyLines); + + return result.join('\n'); +} + export function MarkdownConver(text) { if (text === '...') { return '' @@ -292,6 +368,7 @@ export function MarkdownConver(text) { MarkdownPluginUtils.initReasoningPlugin(MarkdownUtils.mdi); } text = MarkdownPluginUtils.clearEmptyReasoning(text); + text = mergeConsecutiveToolUse(text); text = MarkdownUtils.mdi.render(text); return MarkdownUtils.formatMsg(text) }