From 94312d714ab0f6b6d33f3722a5eab11d3e637a58 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 1 Aug 2026 14:06:18 +0800 Subject: [PATCH] fix(webui): capture all-channel chat history and correct input source - handleChat now injects with source=webui so the LLM no longer sees cli as the input channel - subscribe to EventRawInput/EventAgentOutput to persist every conversation turn from all channels (cli/qq/webui), replacing the manual webui-only addChatMsg to avoid duplicates - ChatMsg gains a source field; GUI shows a channel badge for non-webui messages --- cmd/gui/renderer/app.js | 3 +++ cmd/gui/renderer/style.css | 1 + internal/plugins/webui/handler.go | 40 ++++++++++++++++++++++++++++--- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/cmd/gui/renderer/app.js b/cmd/gui/renderer/app.js index 4e6a2ac..38011b0 100644 --- a/cmd/gui/renderer/app.js +++ b/cmd/gui/renderer/app.js @@ -371,6 +371,9 @@ function renderChat() { }); } var body = rc + tcs + '
' + c + '
'; + if (m.source && m.source !== 'webui') { + body = '
' + escHtml(__('通道','Channel')) + ': ' + escHtml(m.source) + '
' + body; + } if (role === 'system') { html += '
' + body + '
'; } else { diff --git a/cmd/gui/renderer/style.css b/cmd/gui/renderer/style.css index 184bd38..fda4088 100644 --- a/cmd/gui/renderer/style.css +++ b/cmd/gui/renderer/style.css @@ -176,6 +176,7 @@ code { font-family:monospace; font-size:12px; color:var(--pre-color) } .msg-system .msg-avatar { background:var(--msg-system-bg); color:var(--msg-system-color) } .msg-content { min-width:0 } .msg-bubble { padding:8px 12px; border-radius:10px; font-size:13px; line-height:1.5; word-break:break-word; position:relative } +.msg-source { font-size:11px; opacity:.55; margin-bottom:4px; color:inherit } .msg-user .msg-bubble { background:var(--msg-user-bg); color:var(--msg-user-color); border-bottom-right-radius:4px } .msg-assistant .msg-bubble { background:var(--msg-assistant-bg); color:var(--msg-assistant-color); border-bottom-left-radius:4px } .msg-system .msg-bubble { background:var(--msg-system-bg); color:var(--msg-system-color); text-align:center; font-size:12px } diff --git a/internal/plugins/webui/handler.go b/internal/plugins/webui/handler.go index 6ea8f48..17a8b93 100644 --- a/internal/plugins/webui/handler.go +++ b/internal/plugins/webui/handler.go @@ -65,6 +65,7 @@ type ChatMsg struct { Role string `json:"role"` Content string `json:"content"` ReasoningContent string `json:"reasoning_content,omitempty"` + Source string `json:"source,omitempty"` Time string `json:"time"` } @@ -136,6 +137,7 @@ func NewHandler(s *sdk.PluginSDK) *Handler { h.loadChatHistory() if s != nil { go h.trackToolEvents() + h.subscribeChatEvents() } return h } @@ -170,6 +172,40 @@ func (h *Handler) trackToolEvents() { }) } +// subscribeChatEvents 捕获所有通道(cli/qq/webui 等)的对话轮次, +// 与 handleChat 的注入一起构成完整的全通道对话历史。 +func (h *Handler) subscribeChatEvents() { + if h.sdk == nil { + return + } + h.sdk.Subscribe(sdk.EventRawInput, func(ev *sdk.Event) { + content, _ := ev.Payload["content"].(string) + source, _ := ev.Payload["source"].(string) + if content == "" { + return + } + h.addChatMsg(ChatMsg{ + Role: "user", + Content: content, + Source: source, + Time: time.Unix(ev.Timestamp, 0).Format(time.RFC3339), + }) + }) + h.sdk.Subscribe(sdk.EventAgentOutput, func(ev *sdk.Event) { + content, _ := ev.Payload["content"].(string) + channel, _ := ev.Payload["channel"].(string) + if content == "" { + return + } + h.addChatMsg(ChatMsg{ + Role: "assistant", + Content: content, + Source: channel, + Time: time.Unix(ev.Timestamp, 0).Format(time.RFC3339), + }) + }) +} + func (h *Handler) handleToolEvent(ev *sdk.Event) { payload := ev.Payload tool, _ := payload["tool"].(string) @@ -942,12 +978,11 @@ func (h *Handler) handleChat(w http.ResponseWriter, r *http.Request) { return } - h.addChatMsg(ChatMsg{Role: "user", Content: body.Message, Time: time.Now().Format(time.RFC3339)}) if h.sdk == nil { writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "agent unavailable"}) return } - resp := h.sdk.InjectTextSync("cli", "cli", body.Message) + resp := h.sdk.InjectTextSync("webui", "webui", body.Message) if resp == nil { writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "agent unavailable"}) return @@ -960,7 +995,6 @@ func (h *Handler) handleChat(w http.ResponseWriter, r *http.Request) { if reasoning != "" { result["reasoning_content"] = reasoning } - h.addChatMsg(ChatMsg{Role: "assistant", Content: content, ReasoningContent: reasoning, Time: time.Now().Format(time.RFC3339)}) writeJSON(w, http.StatusOK, result) }