From 514d02d4d4f10279200b562b95c20a4414a0f9e9 Mon Sep 17 00:00:00 2001 From: PeterZhong Date: Tue, 29 Jul 2025 22:18:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=BF=9E=E7=BB=AD=E5=AF=B9?= =?UTF-8?q?=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- host/Gateway.cs | 326 +++++++++-------------------- ui/dockpane/DialogDockpane.xaml | 8 +- ui/dockpane/DialogDockpane.xaml.cs | 28 ++- ui/dockpane/TestDockpane.xaml.cs | 11 +- ui/message/MessageListItem.cs | 3 +- 5 files changed, 135 insertions(+), 241 deletions(-) diff --git a/host/Gateway.cs b/host/Gateway.cs index a9d7de2..a2cf0a7 100644 --- a/host/Gateway.cs +++ b/host/Gateway.cs @@ -43,175 +43,19 @@ public class Gateway { private static ILog log = LogManager.GetLogger(typeof(Gateway)); private static bool goOn = true; + private static DialogDockpaneView dockpaneView = null; + + public static void SetDockpaneView(DialogDockpaneView view) + { + dockpaneView = view; + } public static void StopConversation() { goOn = false; - } - - public static async void SendMessage(string message, string model, string gdbPath, Action callback) - { - Llm bailian = new Bailian + if (dockpaneView != null) { - api_key = "sk-db177155677e438f832860e7f4da6afc" - }; - List messages = new List(); - string toolInfos = await GetToolInfos(new McpServerList(),callback); - log.Info(SystemPrompt.SysPrompt(gdbPath, toolInfos)); - messages.Add(new Message - { - Role = "system", - Content = SystemPrompt.SysPrompt(gdbPath, toolInfos) - }); - messages.Add(new Message - { - Role = "user", - Content = message - }); - bool goOn = true; - string pattern = "^[\\s\\S]*?<\\/tool_use>$"; - string promptPattern = "^[\\s\\S]*?<\\/prompt>$"; - McpServerList mcpServerList = new McpServerList(); - while (goOn) - { - string reponse = await bailian.SendChatAsync(new LlmJsonContent() - { - Model = model, - Messages = messages, - Temperature = 0.3, - TopP = 0.6, - TopK = 25, - MaxTokens = 1024, - ThinkingBudget = 1024 - }); - long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - log.Info(reponse); - messages.Add(new Message - { - Role = "assistant", - Content = reponse - }); - if (Regex.IsMatch(reponse, pattern)) - { - //工具类型的消息 - XElement toolUse = XElement.Parse(reponse); - string fullToolName = toolUse.Element("name")?.Value; - string toolArgs = toolUse.Element("arguments")?.Value; - Dictionary toolParams = JsonConvert.DeserializeObject>(toolArgs); - string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName; - string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName; - McpServer mcpServer = mcpServerList.GetServer(serverName); - if (mcpServer is SseMcpServer) - { - SseMcpServer sseMcpServer = mcpServer as SseMcpServer; - SseMcpClient client = new SseMcpClient(sseMcpServer.BaseUrl); - CallToolResponse toolResponse = await client.CallToolAsync(toolName,toolParams); - MessageListItem toolMessageItem = new ToolMessageItem - { - toolName = toolName, - toolParams = toolParams, - type = MessageType.TOOL_MESSAGE, - status = toolResponse.IsError ? "fail" : "success", - content = JsonConvert.SerializeObject(toolResponse), - id = timestamp.ToString() - }; - messages.Add(new Message - { - Role = "user", - Content = toolResponse.IsError ? SystemPrompt.ErrorPrompt(JsonConvert.SerializeObject(toolResponse)) : SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(toolResponse)) - }); - callback?.Invoke(toolMessageItem); - }else if (mcpServer is StdioMcpServer) - { - StdioMcpServer stdioMcpServer = mcpServer as StdioMcpServer; - StdioMcpClient client = new StdioMcpClient(stdioMcpServer.Command, stdioMcpServer.Args); - CallToolResponse toolResponse = await client.CallToolAsync(toolName,toolParams); - MessageListItem toolMessageItem = new ToolMessageItem - { - toolName = toolName, - toolParams = toolParams, - type = MessageType.TOOL_MESSAGE, - status = toolResponse.IsError ? "fail" : "success", - content = JsonConvert.SerializeObject(toolResponse), - id = timestamp.ToString() - }; - messages.Add(new Message - { - Role = "user", - Content = toolResponse.IsError ? SystemPrompt.ErrorPrompt(JsonConvert.SerializeObject(toolResponse)) : SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(toolResponse)) - }); - callback?.Invoke(toolMessageItem); - }else if (mcpServer is InnerMcpServer) - { - Type type = Type.GetType("LinkToolAddin.client.tool."+serverName); - MethodInfo method = type.GetMethod(toolName,BindingFlags.Public | BindingFlags.Static); - var task = method.Invoke(null, toolParams.Values.ToArray()) as Task; - JsonRpcResultEntity innerResult = await task; - if (innerResult is JsonRpcErrorEntity) - { - MessageListItem toolMessageItem = new ToolMessageItem - { - toolName = toolName, - toolParams = toolParams, - type = MessageType.TOOL_MESSAGE, - status = "fail", - content = JsonConvert.SerializeObject(innerResult) - }; - messages.Add(new Message - { - Role = "user", - Content = SystemPrompt.ErrorPrompt(JsonConvert.SerializeObject(innerResult)) - }); - callback?.Invoke(toolMessageItem); - }else if (innerResult is JsonRpcSuccessEntity) - { - MessageListItem toolMessageItem = new ToolMessageItem - { - toolName = toolName, - toolParams = toolParams, - type = MessageType.TOOL_MESSAGE, - status = "success", - content = JsonConvert.SerializeObject(innerResult) - }; - messages.Add(new Message - { - Role = "user", - Content = SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(innerResult)) - }); - callback?.Invoke(toolMessageItem); - } - } - } - else if (Regex.IsMatch(reponse, promptPattern)) - { - XElement prompt = XElement.Parse(reponse); - string fullPromptName = prompt.Element("name")?.Value; - string promptArgs = prompt.Element("arguments")?.Value; - Dictionary promptParams = JsonConvert.DeserializeObject>(promptArgs); - string serverName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[0] : fullPromptName; - string promptName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[1] : fullPromptName; - string promptRes = DynamicPrompt.GetPrompt(promptName, null); - messages.Add(new Message - { - Role = "user", - Content = promptRes - }); - } - else - { - MessageListItem chatMessageListItem = new ChatMessageItem() - { - content = reponse, - role = "assistant", - type = MessageType.CHAT_MESSAGE, - id = timestamp.ToString() - }; - callback?.Invoke(chatMessageListItem); - } - if (reponse.EndsWith("[DONE]")) - { - goOn = false; - } + dockpaneView.hideProgressBar(); } } @@ -236,11 +80,41 @@ public class Gateway return (matched, remaining); } - public static async void SendMessageStream(string message, string model, string gdbPath, Action callback) + public static async void SendMessageStream(string message, string model, string gdbPath, List historyMessages, Action> callback) { Llm modelObj = new Bailian(); List bailianModels = ["Moonshot-Kimi-K2-Instruct","deepseek-r1","deepseek-v3","qwen3-235b-a22b","qwen3-32b","qwen-plus","qwen-turbo","abab6.5s-chat"]; List dmxModels = ["grok-3-mini","o4-mini","claude-3-5-haiku-20241022","claude-sonnet-4-20250514-thinking","claude-3-7-sonnet-20250219-thinking","grok-4-ssvip","gemini-2.5-pro-ssvip","gemini-2.5-flash-ssvip","o3-pro","gpt-4.1","gpt-4o"]; + List messages = null; + string toolInfos = ""; + if (historyMessages.IsNullOrEmpty()) + { + messages = new List(); + try + { + toolInfos = await GetToolInfos(new McpServerList(),messages,callback); + messages.Add(new Message + { + Role = "system", + Content = SystemPrompt.SysPrompt(gdbPath, toolInfos) + }); + }catch (Exception ex) + { + log.Error(ex); + MessageListItem endMessageListItem2 = new ChatMessageItem + { + type = MessageType.WARNING, + content = $"MCP列表读取失败{ex.Message}", + id = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(), + role = "system", + }; + callback?.Invoke(endMessageListItem2,messages); + } + } + else + { + messages = historyMessages; + } if (bailianModels.Contains(model)) { modelObj = new Bailian @@ -263,7 +137,7 @@ public class Gateway id = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(), role = "system" }; - callback?.Invoke(endMessageListItem2); + callback?.Invoke(endMessageListItem2,messages); MessageListItem endMessageListItem1 = new ChatMessageItem { type = MessageType.END_TAG, @@ -271,46 +145,14 @@ public class Gateway id = (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + 3).ToString(), role = "assistant" }; - callback?.Invoke(endMessageListItem1); + callback?.Invoke(endMessageListItem1,messages); return; } - - List messages = new List(); - string toolInfos = ""; - try + messages.Add(new Message { - toolInfos = await GetToolInfos(new McpServerList(),callback); - messages.Add(new Message - { - Role = "system", - Content = SystemPrompt.SysPrompt(gdbPath, toolInfos) - }); - messages.Add(new Message - { - Role = "user", - Content = message - }); - }catch (Exception ex) - { - log.Error(ex); - MessageListItem endMessageListItem2 = new ChatMessageItem - { - type = MessageType.WARNING, - content = $"MCP列表读取失败{ex.Message}", - id = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(), - role = "system" - }; - callback?.Invoke(endMessageListItem2); - MessageListItem endMessageListItem1 = new ChatMessageItem - { - type = MessageType.END_TAG, - content = "", - id = (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + 3).ToString(), - role = "assistant" - }; - callback?.Invoke(endMessageListItem1); - // MessageBox.Show(ex.Message,"获取MCP列表失败"); - } + Role = "user", + Content = message + }); goOn = true; long accTokens = 0; string toolPattern = "([\\s\\S]*?)([\\s\\S]*?)<\\/name>([\\s\\S]*?)([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/tool_use>"; @@ -334,7 +176,7 @@ public class Gateway id = timestamp.ToString(), role = "system" }; - callback?.Invoke(endMessageListItem2); + callback?.Invoke(endMessageListItem2,messages); MessageListItem endMessageListItem1 = new ChatMessageItem { type = MessageType.END_TAG, @@ -342,8 +184,16 @@ public class Gateway id = (timestamp + 3).ToString(), role = "assistant" }; - callback?.Invoke(endMessageListItem1); + callback?.Invoke(endMessageListItem1,messages); // MessageBox.Show("达到最大循环次数", "退出循环"); + MessageListItem endAllMsgItem = new ChatMessageItem + { + type = MessageType.END_ALL, + content = "", + id = (timestamp + 4).ToString(), + role = "assistant" + }; + callback?.Invoke(endAllMsgItem,messages); break; } LlmJsonContent jsonContent = new LlmJsonContent() @@ -369,7 +219,15 @@ public class Gateway id = (timestamp + 3).ToString(), role = "assistant" }; - callback?.Invoke(endMessageListItem1); + callback?.Invoke(endMessageListItem1,messages); + MessageListItem endAllMsgItem = new ChatMessageItem + { + type = MessageType.END_ALL, + content = "", + id = (timestamp + 4).ToString(), + role = "assistant" + }; + callback?.Invoke(endAllMsgItem,messages); break; } @@ -386,7 +244,15 @@ public class Gateway id = (timestamp+3).ToString(), role = "assistant" }; - callback?.Invoke(endMessageListItem2); + callback?.Invoke(endMessageListItem2,messages); + MessageListItem endAllMsgItem = new ChatMessageItem + { + type = MessageType.END_ALL, + content = "", + id = (timestamp + 4).ToString(), + role = "assistant" + }; + callback?.Invoke(endAllMsgItem,messages); break; } try @@ -401,7 +267,7 @@ public class Gateway }; Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(reasonMessageListItem); + callback?.Invoke(reasonMessageListItem,messages); }); messageContent = chunk; var (matched, remaining) = ExtractMatchedPart(chunk, toolPattern); @@ -420,7 +286,7 @@ public class Gateway }; Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(chatMessageListItem); + callback?.Invoke(chatMessageListItem,messages); }); } else @@ -433,7 +299,7 @@ public class Gateway type = MessageType.CHAT_MESSAGE, id = timestamp.ToString() }; - callback?.Invoke(chatMessageListItem); + callback?.Invoke(chatMessageListItem,messages); XElement promptUse = XElement.Parse(matchedPrompt); string promptKey = promptUse.Element("name")?.Value; string promptArgs = promptUse.Element("arguments")?.Value; @@ -467,7 +333,7 @@ public class Gateway }; Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(chatMessageListItem); + callback?.Invoke(chatMessageListItem,messages); }); if (!executedTool) { @@ -484,7 +350,7 @@ public class Gateway }; Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(toolMessageListItem); + callback?.Invoke(toolMessageListItem,messages); }); } mcpToolRequests = new List(); @@ -513,7 +379,7 @@ public class Gateway id = timestamp.ToString(), role = "system" }; - callback?.Invoke(endMessageListItem2); + callback?.Invoke(endMessageListItem2,messages); MessageListItem endMessageListItem1 = new ChatMessageItem { type = MessageType.END_TAG, @@ -521,8 +387,16 @@ public class Gateway id = (timestamp + 3).ToString(), role = "assistant" }; - callback?.Invoke(endMessageListItem1); + callback?.Invoke(endMessageListItem1,messages); // MessageBox.Show(e.Message, "请求大模型出错"); + MessageListItem endAllMsgItem = new ChatMessageItem + { + type = MessageType.END_ALL, + content = "", + id = (timestamp + 4).ToString(), + role = "assistant" + }; + callback?.Invoke(endAllMsgItem,messages); break; } if (messageContent != "") @@ -567,7 +441,7 @@ public class Gateway }); Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(toolMessageItem1); + callback?.Invoke(toolMessageItem1,messages); }); } else if (mcpServer is StdioMcpServer) @@ -595,7 +469,7 @@ public class Gateway }); Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(toolMessageItem1); + callback?.Invoke(toolMessageItem1,messages); }); } else if (mcpServer is InnerMcpServer) @@ -626,7 +500,7 @@ public class Gateway }); Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(toolMessageItem); + callback?.Invoke(toolMessageItem,messages); }); queriedKnowledge = true; } @@ -651,7 +525,7 @@ public class Gateway }); Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(toolMessageItem); + callback?.Invoke(toolMessageItem,messages); }); } continue; @@ -702,7 +576,7 @@ public class Gateway }); Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(toolMessageItem1); + callback?.Invoke(toolMessageItem1,messages); }); } else if (innerResult is JsonRpcSuccessEntity) @@ -725,7 +599,7 @@ public class Gateway }); Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(toolMessageItem1); + callback?.Invoke(toolMessageItem1,messages); }); } } @@ -761,7 +635,7 @@ public class Gateway }; Application.Current.Dispatcher.Invoke(() => { - callback?.Invoke(toolMessageItem); + callback?.Invoke(toolMessageItem,messages); }); } catch (Exception e) @@ -777,13 +651,11 @@ public class Gateway id = (timestamp+3).ToString(), role = "assistant" }; - callback?.Invoke(endMessageListItem); + callback?.Invoke(endMessageListItem,messages); } - - MessageBox.Show("本轮回复完成", "结束提示"); } - private static async Task GetToolInfos(McpServerList mcpServerList,Action callback) + private static async Task GetToolInfos(McpServerList mcpServerList,List historyMessages,Action> callback) { long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); StringBuilder toolInfos = new StringBuilder(); @@ -894,10 +766,10 @@ public class Gateway { type = MessageType.WARNING, content = $"读取失败的MCP服务有:{JsonConvert.SerializeObject(failedMcpString)}", - id = timestamp.ToString(), + id = (timestamp-2).ToString(), role = "system" }; - callback?.Invoke(endMessageListItem2); + callback?.Invoke(endMessageListItem2,historyMessages); // MessageBox.Show($"读取失败的MCP服务有:{JsonConvert.SerializeObject(failedMcpString)}","MCP读取错误"); } return toolInfos.ToString(); diff --git a/ui/dockpane/DialogDockpane.xaml b/ui/dockpane/DialogDockpane.xaml index 7a80d84..4aceb4f 100644 --- a/ui/dockpane/DialogDockpane.xaml +++ b/ui/dockpane/DialogDockpane.xaml @@ -23,7 +23,7 @@ - + @@ -66,5 +66,11 @@ + \ No newline at end of file diff --git a/ui/dockpane/DialogDockpane.xaml.cs b/ui/dockpane/DialogDockpane.xaml.cs index 2777168..8a55823 100644 --- a/ui/dockpane/DialogDockpane.xaml.cs +++ b/ui/dockpane/DialogDockpane.xaml.cs @@ -54,12 +54,14 @@ namespace LinkToolAddin.ui.dockpane private List idList = new List(); private ConcurrentDictionary messageDict = new ConcurrentDictionary(); private ConcurrentDictionary borderItemsDict = new ConcurrentDictionary(); + private List historyMessages = new List(); public DialogDockpaneView() { InitLogger(); InitializeComponent(); DataContext = this; + Gateway.SetDockpaneView(this); } private async void TestServer_OnClick(object sender, RoutedEventArgs e) @@ -105,6 +107,7 @@ namespace LinkToolAddin.ui.dockpane private void SendButton_OnClick(object sender, RoutedEventArgs e) { StatusTextBlock.Text = "正在读取用户输入和工具列表"; + IndeterminateProgressBar.Visibility = Visibility.Visible; string question = QuestionTextbox.Text; string defaultGdbPath = Project.Current.DefaultGeodatabasePath; string gdbPath = @""; @@ -128,7 +131,12 @@ namespace LinkToolAddin.ui.dockpane model = ShowInputBox("自定义模型", "请输入模型名称:", ""); } ScrollViewer.ScrollToBottom(); - Gateway.SendMessageStream(question,model,defaultGdbPath,NewMessage_Recall); + Gateway.SendMessageStream(question,model,defaultGdbPath,historyMessages,NewMessage_Recall); + } + + public void hideProgressBar() + { + IndeterminateProgressBar.Visibility = Visibility.Hidden; } private string ShowInputBox(string title, string message, string defaultValue = "") @@ -171,7 +179,13 @@ namespace LinkToolAddin.ui.dockpane return textBox.Text; } - public void NewMessage_Recall(MessageListItem msg) + public void NewMessage_Recall(MessageListItem msg, List historyMessages) + { + this.historyMessages = historyMessages; + NewMessage_Recall(msg); + } + + private void NewMessage_Recall(MessageListItem msg) { string msgId = msg.id; log.Info(msg.content); @@ -187,6 +201,10 @@ namespace LinkToolAddin.ui.dockpane if (msg.type == MessageType.END_TAG) { StatusTextBlock.Text = ""; + }else if (msg.type == MessageType.END_ALL) + { + StatusTextBlock.Text = ""; + IndeterminateProgressBar.Visibility = Visibility.Hidden; } return; } @@ -250,6 +268,10 @@ namespace LinkToolAddin.ui.dockpane if (msg.type == MessageType.END_TAG) { StatusTextBlock.Text = ""; + }else if (msg.type == MessageType.END_ALL) + { + StatusTextBlock.Text = ""; + IndeterminateProgressBar.Visibility = Visibility.Hidden; } ChatHistoryStackPanel.Children.Remove(borderItemsDict[msgId]); borderItemsDict.TryRemove(msgId, out Border border); @@ -309,6 +331,7 @@ namespace LinkToolAddin.ui.dockpane Grid grid = borderItem.Child as Grid; TextBox textBox = grid.Children[1] as TextBox; textBox.Text = msg.content; + StatusTextBlock.Text = "出现错误信息"; } } } @@ -647,6 +670,7 @@ namespace LinkToolAddin.ui.dockpane borderItemsDict.Clear(); ChatHistoryStackPanel.Children.Clear(); QuestionTextbox.Clear(); + historyMessages.Clear(); StatusTextBlock.Text = ""; } diff --git a/ui/dockpane/TestDockpane.xaml.cs b/ui/dockpane/TestDockpane.xaml.cs index 5985146..5f0af69 100644 --- a/ui/dockpane/TestDockpane.xaml.cs +++ b/ui/dockpane/TestDockpane.xaml.cs @@ -201,16 +201,7 @@ namespace LinkToolAddin.ui.dockpane private async void PromptTestButton_OnClick(object sender, RoutedEventArgs e) { - string userPrompt = PromptTestTextBox.Text; - // model可选值:qwen3-235b-a22b,qwen-max,deepseek-r1 - try - { - await Task.Run(() => Gateway.SendMessageStream(userPrompt,"qwen3-235b-a22b", "F:\\secondsemester\\linktool\\test\\LinkTool0604\\LinkTool0604.gdb", AddReplyStream)); - } - catch (Exception exception) - { - log.Error(exception.Message); - } + throw new NotImplementedException(); } public async void AddReplyStream(MessageListItem msg) diff --git a/ui/message/MessageListItem.cs b/ui/message/MessageListItem.cs index 32eba23..a006ae0 100644 --- a/ui/message/MessageListItem.cs +++ b/ui/message/MessageListItem.cs @@ -7,7 +7,8 @@ public enum MessageType REASON_MESSAGE, END_TAG, WARNING, - ERROR + ERROR, + END_ALL } public interface MessageListItem