v0.1.4版本 #2

Merged
PeterZhong merged 70 commits from host into master 2025-06-15 14:42:58 +00:00
21 changed files with 624 additions and 68 deletions
Showing only changes of commit a3cfcb90e3 - Show all commits

View File

@ -25,6 +25,7 @@
<group id="CoreGroup" caption="核心功能" appearsOnAddInTab="false">
<button refID="DialogDockpane_ShowButton" size="large" />
<button refID="Version_Button" size="large" />
<button refID="LinkToolAddin_ui_dockpane_TestDockpane_ShowButton" size="large" />
</group>
<group id="PreferenceGroup" caption="设置项" appearsOnAddInTab="false">
<button refID="Preference_Button" size="large" />
@ -40,11 +41,17 @@
<button id="DialogDockpane_ShowButton" caption="对话面板" className="LinkToolAddin.ui.dockpane.DialogDockpane_ShowButton" loadOnClick="true" smallImage="GenericButtonPurple16" largeImage="GenericButtonPurple32">
<tooltip heading="对话面板">打开AI对话面板<disabledText /></tooltip>
</button>
<button id="LinkToolAddin_ui_dockpane_TestDockpane_ShowButton" caption="测试面板" className="LinkToolAddin.ui.dockpane.TestDockpane_ShowButton" loadOnClick="true" smallImage="GenericButtonPurple16" largeImage="GenericButtonPurple32">
<tooltip heading="测试面板">打开测试面板<disabledText /></tooltip>
</button>
</controls>
<dockPanes>
<dockPane id="DialogDockpane" caption="LinkTool" className="LinkToolAddin.ui.dockpane.DialogDockpaneViewModel" dock="group" dockWith="esri_core_projectDockPane">
<content className="LinkToolAddin.ui.dockpane.DialogDockpaneView" />
</dockPane>
<dockPane id="LinkToolAddin_ui_dockpane_TestDockpane" caption="TestDockpane" className="LinkToolAddin.ui.dockpane.TestDockpaneViewModel" dock="group" dockWith="esri_core_projectDockPane">
<content className="LinkToolAddin.ui.dockpane.TestDockpaneView" />
</dockPane>
</dockPanes>
</insertModule>
</modules>

View File

@ -99,7 +99,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="resource\" />
<Folder Include="server\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Esri.ArcGISPro.Extensions30" Version="3.4.1.55405" />

View File

@ -2,7 +2,11 @@
"profiles": {
"LinkToolAddin": {
"commandName": "Executable",
"executablePath": "C:\\Program Files\\ArcGIS\\Pro\\bin\\ArcGISPro.exe"
"executablePath": "C:\\Program Files\\ArcGIS\\Pro\\bin\\ArcGISPro.exe",
"applicationUrl": "https://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace LinkToolAddin.client.prompt;
public class DynamicPrompt
{
public static string GetPrompt(string name,Dictionary<string,object> args)
{
PromptTemplates promptTemplate = new PromptTemplates();
string template = promptTemplate.GetPrompt(name);
foreach (KeyValuePair<string,object> pair in args)
{
string replaceKey = "{{"+pair.Key+"}}";
template.Replace(replaceKey, pair.Value.ToString());
}
return template;
}
}

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
namespace LinkToolAddin.client.prompt;
public class PromptTemplates
{
private Dictionary<string, string> prompts = new Dictionary<string, string>();
public PromptTemplates()
{
prompts.Add("plan", "请根据用户所提问题进行工具规划");
prompts.Add("param", "根据帮助文档填写工具参数");
prompts.Add("code", "现在需要生成代码,要求语法正确");
}
public string GetPrompt(string name)
{
return prompts[name];
}
}

146
host/Gateway.cs Normal file
View File

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using LinkToolAddin.client;
using LinkToolAddin.client.prompt;
using LinkToolAddin.host.llm;
using LinkToolAddin.host.llm.entity;
using LinkToolAddin.host.mcp;
using LinkToolAddin.host.prompt;
using LinkToolAddin.message;
using ModelContextProtocol.Protocol.Types;
using Newtonsoft.Json;
namespace LinkToolAddin.host;
public class Gateway
{
public static async void SendMessage(string message, string model, string gdbPath, Action<MessageListItem> callback)
{
Llm bailian = new Bailian
{
api_key = "sk-db177155677e438f832860e7f4da6afc"
};
List<Message> messages = new List<Message>();
messages.Add(new Message
{
Role = "system",
Content = SystemPrompt.SysPromptTemplate
});
messages.Add(new Message
{
Role = "user",
Content = message
});
bool goOn = true;
string pattern = "<tool_use>[\\s\\S]*?<\\/tool_use>";
string promptPattern = "<prompt>[\\s\\S]*?<\\/prompt>";
Dictionary<string,McpServer> servers = new Dictionary<string, McpServer>();
while (goOn)
{
string reponse = await bailian.SendChatAsync(new LlmJsonContent()
{
Model = model,
Messages = messages,
Temperature = 0.7,
TopP = 1,
MaxTokens = 1000,
});
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<string, object> toolParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(toolArgs);
string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName;
string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName;
McpServer mcpServer = servers[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 = toolResponse.Content.ToString()
};
messages.Add(new Message
{
Role = "user",
Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePromptTemplate
});
messages.Add(new Message
{
Role = "user",
Content = 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 = toolResponse.Content.ToString()
};
messages.Add(new Message
{
Role = "user",
Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePromptTemplate
});
messages.Add(new Message
{
Role = "user",
Content = JsonConvert.SerializeObject(toolResponse)
});
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<string, object> promptParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(promptArgs);
string serverName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[0] : fullPromptName;
string promptName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[1] : fullPromptName;
string promptRes = DynamicPrompt.GetPrompt(promptName, promptParams);
messages.Add(new Message
{
Role = "user",
Content = promptRes
});
}
else
{
MessageListItem chatMessageListItem = new ChatMessageItem()
{
content = reponse,
role = "assistant",
type = MessageType.CHAT_MESSAGE
};
callback?.Invoke(chatMessageListItem);
}
if (reponse == "[DONE]")
{
goOn = false;
}
}
}
}

6
host/ToolRequest.cs Normal file
View File

@ -0,0 +1,6 @@
namespace LinkToolAddin.host;
public class ToolRequest
{
}

24
host/mcp/McpServer.cs Normal file
View File

@ -0,0 +1,24 @@
namespace LinkToolAddin.host.mcp
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class McpServer
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("isActive")]
public bool IsActive { get; set; }
}
}

30
host/mcp/SseMcpServer.cs Normal file
View File

@ -0,0 +1,30 @@
namespace LinkToolAddin.host.mcp
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class SseMcpServer : McpServer
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("isActive")]
public bool IsActive { get; set; }
[JsonProperty("baseUrl")]
public string BaseUrl { get; set; }
[JsonProperty("headers")]
public Dictionary<string,string> Headers { get; set; }
}
}

View File

@ -0,0 +1,30 @@
namespace LinkToolAddin.host.mcp
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class StdioMcpServer : McpServer
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("isActive")]
public bool IsActive { get; set; }
[JsonProperty("registryUrl")]
public string RegistryUrl { get; set; }
[JsonProperty("command")]
public string Command { get; set; }
[JsonProperty("args")]
public List<string> Args { get; set; }
}
}

View File

@ -0,0 +1,11 @@
namespace LinkToolAddin.host.prompt;
public class SystemPrompt
{
public static string SysPromptTemplate = "现在你是一个精通ArcGIS Pro的专家请以此身份回答用户的问题。";
public static string ContinuePromptTemplate = "上一个工具执行的结果如下,请据此继续执行";
public static string ErrorPromptTemplate = "执行上一个工具的时候出现以下错误,请根据报错信息重试";
}

View File

@ -0,0 +1,6 @@
namespace LinkToolAddin.host.prompt;
public class UserPrompt
{
}

View File

@ -0,0 +1,37 @@
using System;
using System.ComponentModel;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
namespace LinkToolAddin.server;
public class ArcGISProMcpServer
{
public static async void TestMcpServer()
{
var builder = WebApplication.CreateBuilder();
builder.Logging.AddConsole(options =>
{
options.LogToStandardErrorThreshold = LogLevel.Trace;
});;
builder.Services.AddMcpServer().WithHttpTransport().WithToolsFromAssembly();
var app = builder.Build();
app.MapMcp("/sse");
app.MapGet("/", () => "MCP Server is running!");
Console.WriteLine("About to start server...");
await app.RunAsync();
}
}
[McpServerToolType]
public static class EchoTool
{
[McpServerTool, Description("Echoes the message back to the client.")]
public static string Echo(string message)
{
Console.WriteLine($"received message: {message}");
return $"hello {message}";
}
}

View File

@ -17,6 +17,7 @@ using LinkToolAddin.client;
using LinkToolAddin.host.llm;
using LinkToolAddin.host.llm.entity;
using LinkToolAddin.resource;
using LinkToolAddin.server;
using log4net;
using log4net.Appender;
using log4net.Config;
@ -41,71 +42,9 @@ namespace LinkToolAddin.ui.dockpane
InitializeComponent();
}
public void CallBack(string str,object obj)
{
log.Info($"CallBack {str}");
}
private async void TestServer_OnClick(object sender, RoutedEventArgs e)
{
log.Info("TestServer Clicked");
List<string> args = new List<string>();
args.Add("mcp-server-time");
args.Add("--local-timezone=America/New_York");
McpClient stdioMcpClient = new StdioMcpClient("uvx",args);
IList<McpClientTool> tools = await stdioMcpClient.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
log.Info(tool.JsonSchema.ToString());
}
CallToolResponse response = await stdioMcpClient.CallToolAsync("get_current_time",
new Dictionary<string, object> { { "timezone", "America/New_York" } });
log.Info(JsonConvert.SerializeObject(response));
}
private async void SseMcp_test()
{
SseMcpClient client = new SseMcpClient("https://mcp.amap.com/sse?key=ed418512c94ade8f83d42c37b77d2bb2");
IList<McpClientTool> tools = await client.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
log.Info(tool.JsonSchema.ToString());
}
}
private async void Retrieve_Test()
{
log.Info("TestServer Clicked");
// string jsonRpcString = @"{""jsonrpc"":""2.0"",""method"":""CallArcGISPro.CallArcGISProTool"",""params"":{""toolName"":""analysis.Buffer"",""toolParams"":""[\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流\"",\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流buffer\"",\""100\""]""},""id"":1}";
DocDb docDb = new DocDb("sk-db177155677e438f832860e7f4da6afc", DocDb.KnowledgeBase.ArcGISProHelpDoc);
string query = "缓冲区";
KnowledgeResult knowledgeResult = await docDb.Retrieve(query);
log.Info(JsonConvert.SerializeObject(knowledgeResult.ChunkList));
}
private async void Request_Bailian_Test()
{
Llm bailian = new Bailian
{
api_key = "sk-db177155677e438f832860e7f4da6afc",
app_id = "6a77c5a68de64f469b79fcdcde9d5001",
};
string reponse = await bailian.SendChatAsync(new LlmJsonContent()
{
Model = "qwen-max",
Messages = new List<Message>()
{
new Message()
{
Role = "user",
Content = "你是谁"
}
},
Temperature = 0.7,
TopP = 1,
MaxTokens = 1000,
});
log.Info(reponse);
}
protected void InitLogger()
@ -121,7 +60,7 @@ namespace LinkToolAddin.ui.dockpane
// 2. 创建文件滚动输出器(按大小滚动)
var fileAppender = new RollingFileAppender
{
File = Path.Combine("Logs", "linktool_app.log"), // 日志文件路径
File = Path.Combine("Logs", "D:\\linktool_app.log"), // 日志文件路径
AppendToFile = true, // 追加模式
RollingStyle = RollingFileAppender.RollingMode.Size, // 按文件大小滚动
MaxSizeRollBackups = 10, // 保留 10 个历史文件

View File

@ -0,0 +1,28 @@
<UserControl x:Class="LinkToolAddin.ui.dockpane.TestDockpaneView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ui="clr-namespace:LinkToolAddin.ui.dockpane"
xmlns:extensions="clr-namespace:ArcGIS.Desktop.Extensions;assembly=ArcGIS.Desktop.Extensions"
xmlns:controls="clr-namespace:ArcGIS.Desktop.Framework.Controls;assembly=ArcGIS.Desktop.Framework"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
d:DataContext="{Binding Path=ui.TestDockpaneViewModel}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<extensions:DesignOnlyResourceDictionary Source="pack://application:,,,/ArcGIS.Desktop.Framework;component\Themes\Default.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" LastChildFill="true" KeyboardNavigation.TabNavigation="Local" Height="30">
<Button Content="Test Workflow" Name="TestWorkflow" Click="TestWorkflow_OnClick"></Button>
</DockPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,157 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using LinkToolAddin.client;
using LinkToolAddin.host;
using LinkToolAddin.host.llm;
using LinkToolAddin.host.llm.entity;
using LinkToolAddin.message;
using LinkToolAddin.resource;
using LinkToolAddin.server;
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Layout;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Types;
using Newtonsoft.Json;
namespace LinkToolAddin.ui.dockpane
{
/// <summary>
/// Interaction logic for TestDockpaneView.xaml
/// </summary>
public partial class TestDockpaneView : UserControl
{
private static ILog log = LogManager.GetLogger(typeof(TestDockpaneView));
public TestDockpaneView()
{
InitLogger();
InitializeComponent();
}
protected void InitLogger()
{
// 1. 创建控制台输出器Appender
var consoleAppender = new ConsoleAppender
{
Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline"),
Threshold = log4net.Core.Level.Info // 仅输出 Info 及以上级别
};
consoleAppender.ActivateOptions(); // 激活配置
// 2. 创建文件滚动输出器(按大小滚动)
var fileAppender = new RollingFileAppender
{
File = System.IO.Path.Combine("Logs", "linktool_app.log"), // 日志文件路径
AppendToFile = true, // 追加模式
RollingStyle = RollingFileAppender.RollingMode.Size, // 按文件大小滚动
MaxSizeRollBackups = 10, // 保留 10 个历史文件
MaximumFileSize = "1MB", // 单个文件最大 1MB
StaticLogFileName = true, // 固定文件名(否则自动追加序号)
Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline"),
Threshold = log4net.Core.Level.Info // 仅输出 Info 及以上级别
};
fileAppender.ActivateOptions(); // 激活配置
// 3. 直接通过 BasicConfigurator 注册 Appender
BasicConfigurator.Configure(consoleAppender, fileAppender);
log = LogManager.GetLogger(typeof(DialogDockpaneView));
// 测试日志输出
log.Debug("Debug 日志(控制台可见)");
log.Info("Info 日志(控制台和文件可见)");
log.Error("Error 日志(严重问题)");
}
public void CallBack(string str,object obj)
{
log.Info($"CallBack {str}");
}
private async void TestServer_OnClick(object sender, RoutedEventArgs e)
{
log.Info("TestServer Clicked");
ArcGISProMcpServer.TestMcpServer();
}
private async void StdioMcp_test()
{
List<string> args = new List<string>();
args.Add("mcp-server-time");
args.Add("--local-timezone=America/New_York");
McpClient stdioMcpClient = new StdioMcpClient("uvx",args);
IList<McpClientTool> tools = await stdioMcpClient.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
log.Info(tool.JsonSchema.ToString());
}
CallToolResponse response = await stdioMcpClient.CallToolAsync("get_current_time",
new Dictionary<string, object> { { "timezone", "America/New_York" } });
log.Info(JsonConvert.SerializeObject(response));
}
private async void SseMcp_test()
{
SseMcpClient client = new SseMcpClient("https://mcp.amap.com/sse?key=ed418512c94ade8f83d42c37b77d2bb2");
IList<McpClientTool> tools = await client.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
log.Info(tool.JsonSchema.ToString());
}
}
private async void Retrieve_Test()
{
log.Info("TestServer Clicked");
// string jsonRpcString = @"{""jsonrpc"":""2.0"",""method"":""CallArcGISPro.CallArcGISProTool"",""params"":{""toolName"":""analysis.Buffer"",""toolParams"":""[\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流\"",\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流buffer\"",\""100\""]""},""id"":1}";
DocDb docDb = new DocDb("sk-db177155677e438f832860e7f4da6afc", DocDb.KnowledgeBase.ArcGISProHelpDoc);
string query = "缓冲区";
KnowledgeResult knowledgeResult = await docDb.Retrieve(query);
log.Info(JsonConvert.SerializeObject(knowledgeResult.ChunkList));
}
private async void Request_Bailian_Test()
{
Llm bailian = new Bailian
{
api_key = "sk-db177155677e438f832860e7f4da6afc",
app_id = "6a77c5a68de64f469b79fcdcde9d5001",
};
string reponse = await bailian.SendChatAsync(new LlmJsonContent()
{
Model = "qwen-max",
Messages = new List<Message>()
{
new Message()
{
Role = "user",
Content = "你是谁"
}
},
Temperature = 0.7,
TopP = 1,
MaxTokens = 1000,
});
log.Info(reponse);
}
private void TestButton_OnClick(object sender, RoutedEventArgs e)
{
throw new System.NotImplementedException();
}
private void TestWorkflow_OnClick(object sender, RoutedEventArgs e)
{
Gateway.SendMessage("你好","qwen-max","test.gdb",ShowMessage);
}
public void ShowMessage(MessageListItem msg)
{
log.Info(msg.content);
}
}
}

View File

@ -0,0 +1,62 @@
using ArcGIS.Core.CIM;
using ArcGIS.Core.Data;
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Catalog;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Editing;
using ArcGIS.Desktop.Extensions;
using ArcGIS.Desktop.Framework;
using ArcGIS.Desktop.Framework.Contracts;
using ArcGIS.Desktop.Framework.Dialogs;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.KnowledgeGraph;
using ArcGIS.Desktop.Layouts;
using ArcGIS.Desktop.Mapping;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LinkToolAddin.ui.dockpane
{
internal class TestDockpaneViewModel : DockPane
{
private const string _dockPaneID = "LinkToolAddin_ui_dockpane_TestDockpane";
protected TestDockpaneViewModel() { }
/// <summary>
/// Show the DockPane.
/// </summary>
internal static void Show()
{
DockPane pane = FrameworkApplication.DockPaneManager.Find(_dockPaneID);
if (pane == null)
return;
pane.Activate();
}
/// <summary>
/// Text shown near the top of the DockPane.
/// </summary>
private string _heading = "My DockPane";
public string Heading
{
get => _heading;
set => SetProperty(ref _heading, value);
}
}
/// <summary>
/// Button implementation to show the DockPane.
/// </summary>
internal class TestDockpane_ShowButton : Button
{
protected override void OnClick()
{
TestDockpaneViewModel.Show();
}
}
}

View File

@ -0,0 +1,9 @@
namespace LinkToolAddin.message;
public class ChatMessageItem : MessageListItem
{
public string id { get; set; }
public string role { get; set; }
public string content { get; set; }
public MessageType type { get; set; }
}

View File

@ -1,7 +1,15 @@
namespace LinkToolAddin.message;
public enum MessageType
{
TOOL_MESSAGE,
CHAT_MESSAGE,
}
public interface MessageListItem
{
string id { get; set; }
string role { get; set; }
string content { get; set; }
MessageType type { get; set; }
}

View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace LinkToolAddin.message;
public class ToolMessageItem : MessageListItem
{
public string id { get; set; }
public string role { get; set; }
public string content { get; set; }
public string toolName { get; set; }
public Dictionary<string,object> toolParams { get; set; }
public MessageType type { get; set; }
public string status { get; set; }
public string result { get; set; }
}