95 lines
4.1 KiB
Python
95 lines
4.1 KiB
Python
|
|
import sys
|
|||
|
|
|
|||
|
|
# ─── 修改主 sendMessage SSE 循环 ───
|
|||
|
|
# 在 "const evt = JSON.parse(payload);" 后添加工具状态处理
|
|||
|
|
# 以及在循环后渲染工具调用汇总
|
|||
|
|
|
|||
|
|
OLD_MAIN = (
|
|||
|
|
" try {\n"
|
|||
|
|
" const evt = JSON.parse(payload);\n"
|
|||
|
|
" // Anthropic 格式\n"
|
|||
|
|
" if (evt.type === 'content_block_delta' && evt.delta?.text) {\n"
|
|||
|
|
" fullText += evt.delta.text;\n"
|
|||
|
|
" }\n"
|
|||
|
|
" // OpenAI 格式\n"
|
|||
|
|
" if (evt.choices?.[0]?.delta?.content) {\n"
|
|||
|
|
" fullText += evt.choices[0].delta.content;\n"
|
|||
|
|
" }\n"
|
|||
|
|
" } catch {}"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
NEW_MAIN = (
|
|||
|
|
" try {\n"
|
|||
|
|
" const evt = JSON.parse(payload);\n"
|
|||
|
|
" // 工具执行状态通知 (tool_status)\n"
|
|||
|
|
" if (evt.type === 'tool_status') {\n"
|
|||
|
|
" if (evt.status === 'running') {\n"
|
|||
|
|
" const label = (typeof TOOL_LABELS !== 'undefined' && TOOL_LABELS[evt.tool]) || { icon: '🔧', action: evt.tool };\n"
|
|||
|
|
" const detail = evt.args && evt.args.path ? escapeHtml(evt.args.path) : '';\n"
|
|||
|
|
" const statusHtml = '<div class=\"tool-running-indicator\" id=\"tool-run-' + escapeHtml(evt.tool) + '\">' +\n"
|
|||
|
|
" '<span class=\"tool-step-icon\">' + label.icon + '</span>' +\n"
|
|||
|
|
" '<span class=\"tool-step-action\">' + escapeHtml(label.action) + (detail ? ': ' + detail : '') + '</span>' +\n"
|
|||
|
|
" '<span class=\"tool-running-dots\"><span>.</span><span>.</span><span>.</span></span>' +\n"
|
|||
|
|
" '</div>';\n"
|
|||
|
|
" contentEl.innerHTML = statusHtml;\n"
|
|||
|
|
" }\n"
|
|||
|
|
" // done 状态由 tool_calls_summary 统一渲染,此处仅清除 running 指示器\n"
|
|||
|
|
" }\n"
|
|||
|
|
" // 工具调用汇总 (tool_calls_summary) — 暂存,循环结束后渲染在 fullText 前\n"
|
|||
|
|
" if (evt.type === 'tool_calls_summary') {\n"
|
|||
|
|
" _toolCallsHtml = renderToolCalls(evt.calls);\n"
|
|||
|
|
" }\n"
|
|||
|
|
" // Anthropic 格式\n"
|
|||
|
|
" if (evt.type === 'content_block_delta' && evt.delta?.text) {\n"
|
|||
|
|
" fullText += evt.delta.text;\n"
|
|||
|
|
" }\n"
|
|||
|
|
" // OpenAI 格式\n"
|
|||
|
|
" if (evt.choices?.[0]?.delta?.content) {\n"
|
|||
|
|
" fullText += evt.choices[0].delta.content;\n"
|
|||
|
|
" }\n"
|
|||
|
|
" } catch {}"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 在 "let fullText = '';" 后添加 _toolCallsHtml 变量初始化
|
|||
|
|
OLD_VARS = (
|
|||
|
|
" let fullText = '';\n"
|
|||
|
|
" let _renderPending = false;\n"
|
|||
|
|
" let _lastRenderLen = 0;"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
NEW_VARS = (
|
|||
|
|
" let fullText = '';\n"
|
|||
|
|
" let _renderPending = false;\n"
|
|||
|
|
" let _lastRenderLen = 0;\n"
|
|||
|
|
" let _toolCallsHtml = ''; // 工具调用汇总 HTML,由 tool_calls_summary 事件填充"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 渲染最终内容时,在 fullText 前插入工具调用汇总
|
|||
|
|
OLD_RENDER = " contentEl.innerHTML = renderMarkdownWithSandbox(fullText);\n // 添加重新生成按钮"
|
|||
|
|
NEW_RENDER = (
|
|||
|
|
" // 工具调用汇总 + 最终文本\n"
|
|||
|
|
" if (_toolCallsHtml) {\n"
|
|||
|
|
" contentEl.innerHTML = _toolCallsHtml + renderMarkdownWithSandbox(fullText);\n"
|
|||
|
|
" } else {\n"
|
|||
|
|
" contentEl.innerHTML = renderMarkdownWithSandbox(fullText);\n"
|
|||
|
|
" }\n"
|
|||
|
|
" // 添加重新生成按钮"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
with open('/opt/bookworm-web/public/index.html', 'r', encoding='utf-8') as f:
|
|||
|
|
content = f.read()
|
|||
|
|
|
|||
|
|
# 验证唯一性
|
|||
|
|
assert content.count(OLD_MAIN) == 1, f'OLD_MAIN not unique: {content.count(OLD_MAIN)}'
|
|||
|
|
assert content.count(OLD_VARS) == 1, f'OLD_VARS not unique: {content.count(OLD_VARS)}'
|
|||
|
|
assert content.count(OLD_RENDER) == 1, f'OLD_RENDER not unique: {content.count(OLD_RENDER)}'
|
|||
|
|
|
|||
|
|
content = content.replace(OLD_MAIN, NEW_MAIN, 1)
|
|||
|
|
content = content.replace(OLD_VARS, NEW_VARS, 1)
|
|||
|
|
content = content.replace(OLD_RENDER, NEW_RENDER, 1)
|
|||
|
|
|
|||
|
|
with open('/opt/bookworm-web/public/index.html', 'w', encoding='utf-8') as f:
|
|||
|
|
f.write(content)
|
|||
|
|
|
|||
|
|
print('index.html main SSE loop updated OK')
|