From c5a06ac16055c13cfa4f0002724cea24f85bcb78 Mon Sep 17 00:00:00 2001 From: Pine Date: Tue, 18 Aug 2026 02:16:46 +0800 Subject: [PATCH] =?UTF-8?q?fix(voice):=20=E4=BF=AE=E5=A4=8D=E8=AF=AD?= =?UTF-8?q?=E9=9F=B3=E9=A1=B5=E9=BB=91=E5=B1=8F=EF=BC=88onToolCall=20TDZ?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit onToolCall 依赖数组引用 pushMessage,但被插在 pushMessage 声明之前 → Cannot access 'pushMessage' before initialization → 渲染崩溃黑屏。 已移到 pushMessage 之后(198→230),与 start/sendGreeting 同类问题一并规避 --- src/pages/VoiceAssistant.jsx | 54 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/pages/VoiceAssistant.jsx b/src/pages/VoiceAssistant.jsx index d6409f4..cfd7b14 100644 --- a/src/pages/VoiceAssistant.jsx +++ b/src/pages/VoiceAssistant.jsx @@ -151,33 +151,6 @@ export default function VoiceAssistant() { console.warn('[vision] 自动问候已发送:', GREETING_TEXT); }, []); - // ── 工具调用执行器:LLM 请求工具 → 转发后端 /api/tools/exec → 结果回传 ── - const onToolCall = useCallback(async (e) => { - const { name, arguments: argsStr, callId } = e?.detail ?? {}; - if (!name || !callId) return; - let args = {}; - try { args = JSON.parse(argsStr || '{}'); } catch { /* 忽略非法参数 */ } - console.warn(`[tools] LLM 调用工具: ${name}`, args); - pushMessage('assistant', `🔧 调用工具:${name}`, false); - let output; - try { - const res = await fetch(`${API_BASE}/api/tools/exec`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name, args }), - }); - const data = await res.json(); - output = data?.result ?? JSON.stringify(data); - } catch (err) { - output = JSON.stringify({ error: String(err) }); - } - const c = clientRef.current; - if (c) { - c.sendToolOutput(callId, output); - c.requestResponse(); - } - }, [pushMessage]); - // ── 右下角气泡渲染(复刻原版 ui/chat.js)─────────────────────────────── // 流程:新气泡插入 → rAF 加 `.in`(淡入)→ 4s 后加 `.out`(淡出)→ 400ms 移除。 // 持续更新的气泡(partial 逐字流)续期 4s;栈上限 8 条,最旧优先淡出, @@ -253,6 +226,33 @@ export default function VoiceAssistant() { setMessages(next); }, [scheduleBubbleDismiss, markLeaving]); + // ── 工具调用执行器:LLM 请求工具 → 转发后端 /api/tools/exec → 结果回传 ── + const onToolCall = useCallback(async (e) => { + const { name, arguments: argsStr, callId } = e?.detail ?? {}; + if (!name || !callId) return; + let args = {}; + try { args = JSON.parse(argsStr || '{}'); } catch { /* 忽略非法参数 */ } + console.warn(`[tools] LLM 调用工具: ${name}`, args); + pushMessage('assistant', `🔧 调用工具:${name}`, false); + let output; + try { + const res = await fetch(`${API_BASE}/api/tools/exec`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name, args }), + }); + const data = await res.json(); + output = data?.result ?? JSON.stringify(data); + } catch (err) { + output = JSON.stringify({ error: String(err) }); + } + const c = clientRef.current; + if (c) { + c.sendToolOutput(callId, output); + c.requestResponse(); + } + }, [pushMessage]); + // 结束会话:淡出全部气泡(原版 teardown 行为) const dismissAllBubbles = useCallback(() => { const ids = messagesRef.current.map((m) => m.id);