diff --git a/internal/plugins/webui/dashboard.html b/internal/plugins/webui/dashboard.html index 41dda63..5199fc5 100644 --- a/internal/plugins/webui/dashboard.html +++ b/internal/plugins/webui/dashboard.html @@ -3593,12 +3593,10 @@ background: btn.textContent = ""; rerenderChat(true); // 触发式 POST:短超时仅确认受理;回复靠 SSE 流式渲染(对齐 GUI 行为)。 - // 长 LLM 工具链不再因同步等全量响应而 60s 超时报错。 try { var ctrl = new AbortController(); - var acked = false; // 受理确认是否在超时内返回 var ackTimer = setTimeout(function () { - if (!acked) ctrl.abort(); + ctrl.abort(); }, 15000); var r = null; try { @@ -3607,40 +3605,46 @@ background: body: JSON.stringify({ message: text }), signal: ctrl.signal, }); - acked = true; } catch (ackErr) { - if (acked) throw ackErr; - // 受理确认超时:agent 已在后台处理,保持 loading 等待 SSE 流式回包 - console.log("[sendChat] ack timeout (15s), waiting for SSE stream"); - state.chatStage = __("AI 处理中...(长任务,请稍候)", "AI processing... (long task)"); - return; // 保持 chatLoading=true;SSE 完成事件负责收尾 + // 同步超时/失败:不阻塞 UI,等 SSE 兑底;明确提示"可能已发送" + console.warn("[sendChat] trigger failed: " + ackErr.message); + toast( + __( + "请求超时(可能已发送,请稍候或在收到回复前勿重复发送)", + "Request timeout (may have been sent; wait for reply before resending)", + ), + true, + ); + r = null; } finally { clearTimeout(ackTimer); } - state.chatStage = ""; + state.chatStage = __("AI 回复中...", "AI replying..."); var last = state.messages[state.messages.length - 1]; - if (last && last.role === "assistant" && last._streaming) { - last.content = r.response || __("(无响应)", "(no response)"); - last._grow = true; - if (!last.reasoning_content) { - last.reasoning_content = r.reasoning_content || ""; + if (r && r.response) { + if (last && last.role === "assistant" && last._streaming) { + last.content = r.response || __("(无响应)", "(no response)"); + last._grow = true; + if (!last.reasoning_content) { + last.reasoning_content = r.reasoning_content || ""; + } + last._final = true; + delete last._streaming; + } else { + state.messages.push({ + role: "assistant", + content: r.response || __("(无响应)", "(no response)"), + reasoning_content: r.reasoning_content, + tool_calls: + last && last.role === "assistant" && last.tool_calls + ? last.tool_calls + : [], + _final: true, + _grow: true, + }); } - last._final = true; - delete last._streaming; - } else { - state.messages.push({ - role: "assistant", - content: r.response || __("(无响应)", "(no response)"), - reasoning_content: r.reasoning_content, - tool_calls: - last && last.role === "assistant" && last.tool_calls - ? last.tool_calls - : [], - _final: true, - _grow: true, - }); + state.chatFinalIdx = state.messages.length - 1; } - state.chatFinalIdx = state.messages.length - 1; rerenderChat(true); } catch (e) { // 真实错误(非受理超时):展示错误信息