Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/alex5527467_deepseekchat.json
T

1 line
208 KiB
JSON
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "alex5527467/deepseekchat", "files": {"DeepSeekChat/Services/API/ToolApiService.cs": {"e0efb5d901d4cccf80032360bcc4107a4bbf4553": {"t": 1785746212.8690596, "n": 27568, "h": "908f9f5e8f15cceb", "c": "// ToolApiService.cs - 专门处理工具调用\r\nusing DeepSeekChat.Models;\r\nusing Newtonsoft.Json;\r\nusing Newtonsoft.Json.Serialization;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Linq;\r\nusing System.Net.Http;\r\nusing System.Text;\r\nusing System.Threading;\r\nusing System.Threading.Tasks;\r\nusing static DeepSeekChat.Services.ToolApiService;\r\n\r\nnamespace DeepSeekChat.Services\r\n{\r\n public class ToolApiService : IToolApiService\r\n {\r\n // 工具服务名称常量定义\r\n public static class ToolServices\r\n {\r\n public const string FileRead = \"FileRead\";\r\n public const string FileCreate = \"FileCreate\";\r\n public const string FileWrite = \"FileWrite\";\r\n public const string FileSystem = \"FileSystem\";\r\n public const string Compile = \"Compile\";\r\n public const string FolderBrowser = \"FolderBrowser\";\r\n public const string CommandLine = \"CommandLine\";\r\n }\r\n\r\n private readonly HttpClient _httpClient;\r\n private readonly string _logFilePath;\r\n private const string ApiUrl = \"https://api.deepseek.com/chat/completions\";\r\n\r\n public ToolApiService(string apiKey, string logFilePath = null)\r\n {\r\n _httpClient = new HttpClient()\r\n {\r\n Timeout = TimeSpan.FromMinutes(10)\r\n };\r\n _httpClient.DefaultRequestHeaders.Add(\"Authorization\", $\"Bearer {apiKey}\");\r\n _httpClient.DefaultRequestHeaders.Add(\"Accept\", \"application/json\");\r\n\r\n // 设置日志文件路径\r\n _logFilePath = logFilePath ?? GetDefaultLogFilePath();\r\n\r\n // 确保日志目录存在\r\n EnsureLogDirectory();\r\n\r\n LogInfo($\"ToolApiService 初始化完成,日志文件: {_logFilePath}\");\r\n }\r\n\r\n public async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, List<string> toolServices)\r\n {\r\n LogInfo($\"开始处理工具调用请求\");\r\n LogInfo($\"传入的工具服务: {string.Join(\", \", toolServices ?? new List<string>())}\");\r\n LogInfo($\"对话历史消息数: {conversationHistory?.Count ?? 0}\");\r\n\r\n // 如果没有指定工具服务,返回空工具列表\r\n if (toolServices == null || toolServices.Count == 0)\r\n {\r\n LogInfo(\"未指定工具服务,使用空工具列表\");\r\n return await SendToolRequestAsync(conversationHistory, new List<object>());\r\n }\r\n\r\n // 收集所有选择的工具\r\n var allTools = new List<object>();\r\n\r\n foreach (var toolService in toolServices.Distinct())\r\n {\r\n var tools = GetToolsByService(toolService);\r\n if (tools != null)\r\n {\r\n allTools.AddRange(tools);\r\n LogInfo($\"添加工具服务 '{toolService}',包含 {tools.Count} 个工具\");\r\n }\r\n else\r\n {\r\n LogWarning($\"未找到工具服务: {toolService}\");\r\n }\r\n }\r\n\r\n LogInfo($\"总计添加 {allTools.Count} 个工具\");\r\n return await SendToolRequestAsync(conversationHistory, allTools);\r\n }\r\n\r\n // 私有方法:使用具体的工具列表发送请求\r\n private async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, List<object> tools)\r\n {\r\n LogInfo($\"开始发送API请求,工具数量: {tools.Count}\");\r\n\r\n var requestData = new ChatRequest\r\n {\r\n Messages = conversationHistory,\r\n MaxTokens = 5000,\r\n Temperature = 0.3,\r\n Tools = tools,\r\n ToolChoice = tools.Count > 0 ? \"auto\" : \"none\"\r\n };\r\n\r\n var settings = new JsonSerializerSettings\r\n {\r\n ContractResolver = new DefaultContractResolver\r\n {\r\n NamingStrategy = new SnakeCaseNamingStrategy()\r\n },\r\n NullValueHandling = NullValueHandling.Ignore,\r\n Formatting = Formatting.Indented // 为日志美化JSON\r\n };\r\n\r\n var jsonContent = JsonConvert.SerializeObject(requestData, settings);\r\n\r\n // 记录发送给API的请求内容\r\n LogRequest(jsonContent, tools.Count > 0);\r\n\r\n var content = new StringContent(jsonContent, Encoding.UTF8, \"application/json\");\r\n\r\n try\r\n {\r\n LogInfo($\"正在发送请求到 DeepSeek API: {ApiUrl}\");\r\n using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));\r\n\r\n var response = await _httpClient.PostAsync(ApiUrl, content, cts.Token);\r\n\r\n LogInfo($\"收到API响应,状态码: {(int)response.StatusCode} {response.StatusCode}\");\r\n response.EnsureSuccessStatusCode();\r\n\r\n var responseJson = await response.Content.ReadAsStringAsync();\r\n\r\n // 记录API返回的内容\r\n LogResponse(responseJson, (int)response.StatusCode);\r\n\r\n var apiResponse = JsonConvert.DeserializeObject<ApiResponse>(responseJson);\r\n\r\n var result = new ToolCallResponse();\r\n\r\n if (apiResponse?.Choices?.Count > 0)\r\n {\r\n var message = apiResponse.Choices[0].Message;\r\n\r\n result.Content = message.Content ?? string.Empty;\r\n result.ToolCalls = message.ToolCalls;\r\n result.HasToolCalls = message.ToolCalls != null && message.ToolCalls.Count > 0;\r\n result.Success = true;\r\n\r\n if (result.HasToolCalls)\r\n {\r\n // 提取工具调用信息\r\n result.ToolCalls = message.ToolCalls;\r\n LogInfo($\"API返回了 {message.ToolCalls.Count} 个工具调用\");\r\n for (int i = 0; i < message.ToolCalls.Count; i++)\r\n {\r\n var toolCall = message.ToolCalls[i];\r\n LogInfo($\"工具调用 #{i + 1}: {toolCall.Function?.Name}\");\r\n }\r\n }\r\n else\r\n {\r\n LogInfo($\"API返回了文本回复,长度: {result.Content.Length} 字符\");\r\n }\r\n }\r\n else\r\n {\r\n result.Content = \"没有生成有效的回复。\";\r\n result.Success = false;\r\n LogWarning(\"API返回了空响应或无有效选择\");\r\n }\r\n\r\n return result;\r\n }\r\n catch (HttpRequestException ex)\r\n {\r\n LogError($\"工具调用请求失败: {ex.Message}\");\r\n return new ToolCallResponse\r\n {\r\n Content = $\"工具调用请求失败: {ex.Message}\",\r\n Success = false\r\n };\r\n }\r\n catch (Exception ex)\r\n {\r\n LogError($\"处理API响应时发生错误: {ex.Message}\");\r\n return new ToolCallResponse\r\n {\r\n Content = $\"处理API响应时发生错误: {ex.Message}\",\r\n Success = false\r\n };\r\n }\r\n }\r\n\r\n // 根据服务名称获取对应的工具列表\r\n private List<object> GetToolsByService(string toolService)\r\n {\r\n LogDebug($\"获取工具服务: {toolService}\");\r\n return toolService switch\r\n {\r\n ToolServices.FileRead => GetFileReadTools(),\r\n ToolServices.FileCreate => GetFileCreateTools(),\r\n ToolServices.FileWrite => GetFileWriteTools(),\r\n ToolServices.FolderBrowser => GetFolderBrowserTools(),\r\n ToolServices.CommandLine => GetCommandLineTools(),\r\n _ => null\r\n };\r\n }\r\n\r\n public List<string> GetToolsNameByService(string toolService)\r\n {\r\n LogDebug($\"获取工具名称: {toolService}\");\r\n return toolService switch\r\n {\r\n ToolServices.FileRead => [\"read_file\"],\r\n ToolServices.FileCreate => [\"create_file\"],\r\n ToolServices.FileWrite => [\"write_file\"],\r\n ToolServices.FolderBrowser => [\"get_folder_structure_description\"],\r\n ToolServices.CommandLine => [\"execute_command\"],\r\n _ => [\"\"]\r\n };\r\n }\r\n\r\n #region 日志记录方法\r\n\r\n private string GetDefaultLogFilePath()\r\n {\r\n var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);\r\n var logDir = Path.Combine(appDataPath, \"DeepSeekChat\", \"Logs\");\r\n var timestamp = DateTime.Now.ToString(\"yyyyMMdd\");\r\n return Path.Combine(logDir, $\"tool_api_{timestamp}.log\");\r\n }\r\n\r\n private void EnsureLogDirectory()\r\n {\r\n var logDir = Path.GetDirectoryName(_logFilePath);\r\n if (!string.IsNullOrEmpty(logDir) && !Directory.Exists(logDir))\r\n {\r\n Directory.CreateDirectory(logDir);\r\n }\r\n }\r\n\r\n private void LogRequest(string jsonContent, bool hasTools)\r\n {\r\n try\r\n {\r\n var logEntry = new StringBuilder();\r\n logEntry.AppendLine(\"=\".PadRight(80, '='));\r\n logEntry.AppendLine($\"请求时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}\");\r\n logEntry.AppendLine($\"目标URL: {ApiUrl}\");\r\n logEntry.AppendLine($\"包含工具: {(hasTools ? \"是\" : \"否\")}\");\r\n logEntry.AppendLine(\"请求内容:\");\r\n logEntry.AppendLine(jsonContent);\r\n logEntry.AppendLine();\r\n\r\n File.AppendAllText(_logFilePath, logEntry.ToString());\r\n }\r\n catch (Exception ex)\r\n {\r\n Console.WriteLine($\"无法写入日志文件: {ex.Message}\");\r\n }\r\n }\r\n\r\n private void LogResponse(string jsonContent, int statusCode)\r\n {\r\n try\r\n {\r\n var logEntry = new StringBuilder();\r\n logEntry.AppendLine($\"响应时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}\");\r\n logEntry.AppendLine($\"状态码: {statusCode}\");\r\n logEntry.AppendLine(\"响应内容:\");\r\n\r\n // 尝试美化JSON响应\r\n try\r\n {\r\n var jsonObject = JsonConvert.DeserializeObject(jsonContent);\r\n var formattedJson = JsonConvert.SerializeObject(jsonObject, Formatting.Indented);\r\n logEntry.AppendLine(formattedJson);\r\n }\r\n catch\r\n {\r\n logEntry.AppendLine(jsonContent);\r\n }\r\n\r\n logEntry.AppendLine(\"=\".PadRight(80, '='));\r\n logEntry.AppendLine();\r\n\r\n File.AppendAllText(_logFilePath, logEntry.ToString());\r\n }\r\n catch (Exception ex)\r\n {\r\n Console.WriteLine($\"无法写入日志文件: {ex.Message}\");\r\n }\r\n }\r\n\r\n private void LogInfo(string message)\r\n {\r\n WriteLog(\"INFO\", message);\r\n }\r\n\r\n private void LogWarning(string message)\r\n {\r\n WriteLog(\"WARN\", message);\r\n }\r\n\r\n private void LogError(string message)\r\n {\r\n WriteLog(\"ERROR\", message);\r\n }\r\n\r\n private void LogDebug(string message)\r\n {\r\n WriteLog(\"DEBUG\", message);\r\n }\r\n\r\n private void WriteLog(string level, string message)\r\n {\r\n try\r\n {\r\n var timestamp = DateTime.Now.ToString(\"yyyy-MM-dd HH:mm:ss.fff\");\r\n var logMessage = $\"{timestamp} [{level}] {message}\";\r\n\r\n File.AppendAllText(_logFilePath, logMessage + Environment.NewLine);\r\n\r\n // 同时输出到控制台以便调试\r\n Console.WriteLine(logMessage);\r\n }\r\n catch (Exception ex)\r\n {\r\n Console.WriteLine($\"无法写入日志文件: {ex.Message}\");\r\n }\r\n }\r\n\r\n #endregion\r\n\r\n #region 工具定义方法\r\n\r\n private List<object> GetFolderInfoTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"get_folder_info\",\r\n description = \"获取文件夹详细信息,包括文件数量、大小统计、常见文件类型等\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n folder_path = new\r\n {\r\n type = \"string\",\r\n description = \"要获取信息的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\r\n }\r\n },\r\n required = new[] { \"folder_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> DeleteFileTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"delete_file\",\r\n description = \"删除文件\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要删除的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_delete.txt\"\r\n }\r\n },\r\n required = new[] { \"file_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFileCreateTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"create_file\",\r\n description = \"创建新文件\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\r\n },\r\n content = new\r\n {\r\n type = \"string\",\r\n description = \"文件内容,默认为空字符串\"\r\n },\r\n overwrite = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否覆盖已存在的文件,默认为false\"\r\n }\r\n },\r\n required = new[] { \"file_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFileReadTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"read_file\",\r\n description = \"读取文件内容\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\r\n },\r\n encoding = new\r\n {\r\n type = \"string\",\r\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\r\n },\r\n max_size_bytes = new\r\n {\r\n type = \"integer\",\r\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\r\n }\r\n },\r\n required = new[] { \"file_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFileWriteTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"write_file\",\r\n description = \"写入文件内容\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要写入的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_write.txt\"\r\n },\r\n content = new\r\n {\r\n type = \"string\",\r\n description = \"要写入的文件内容\"\r\n },\r\n encoding = new\r\n {\r\n type = \"string\",\r\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\r\n },\r\n mode = new\r\n {\r\n type = \"string\",\r\n description = \"写入模式:create=仅创建新文件(文件存在则失败)、overwrite=覆盖文件(文件存在则覆盖)、append=在文件末尾追加内容,默认为create\",\r\n @enum = new[] { \"create\", \"overwrite\", \"append\" }\r\n }\r\n },\r\n required = new[] { \"file_path\", \"content\" ,\"mode\"}\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFolderBrowserTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"get_folder_structure_description\",\r\n description = \"浏览本地文件夹,获取文件列表,可以过滤特定文件类型并排除指定文件夹\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n folder_path = new\r\n {\r\n type = \"string\",\r\n description = \"要浏览的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\r\n },\r\n include_subdirectories = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否包含子目录,默认为false\"\r\n },\r\n filter_extensions = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"要过滤的文件扩展名列表,如:['.txt', '.pdf', '.jpg'],只返回这些扩展名的文件\"\r\n },\r\n exclude_paths = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"要排除的文件夹名称或路径列表,如:['node_modules', 'bin', 'obj', '.git']。这些文件夹及其所有内容将被忽略\"\r\n }\r\n },\r\n required = new[] { \"folder_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n private List<object> GetCompileTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"compile_csharp\",\r\n description = \"编译C#代码并可选地执行程序。支持生成可执行文件或在内存中直接执行代码。\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n code = new\r\n {\r\n type = \"string\",\r\n description = \"要编译的C#源代码。必须是完整的程序,包含Main方法或入口点。\"\r\n },\r\n outputPath = new\r\n {\r\n type = \"string\",\r\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译。示例:C:\\\\Output\\\\Program.dll\"\r\n },\r\n execute = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否在编译后立即执行程序。如果为true,将在内存中执行并返回执行结果。默认为false。\"\r\n },\r\n includeReferences = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"额外的程序集引用路径列表。示例:[\\\"Newtonsoft.Json.dll\\\", \\\"System.Data.dll\\\"]\"\r\n },\r\n targetFramework = new\r\n {\r\n type = \"string\",\r\n description = \"目标框架版本。支持:net8.0。默认为当前运行时版本。\"\r\n }\r\n },\r\n required = new[] { \"code\" }\r\n }\r\n }\r\n },\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"compile_and_execute\",\r\n description = \"编译C#代码并立即执行,返回执行结果。适用于快速测试代码片段。\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n code = new\r\n {\r\n type = \"string\",\r\n description = \"要编译执行的C#源代码。必须包含Main方法。示例:'using System; class Program { static void Main() { Console.WriteLine(\\\"Hello\\\"); } }'\"\r\n },\r\n output_path = new\r\n {\r\n type = \"string\",\r\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译和执行。示例:C:\\\\Temp\\\\MyProgram.dll\"\r\n },\r\n arguments = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"传递给Main方法的命令行参数。示例:[\\\"arg1\\\", \\\"arg2\\\"]\"\r\n }\r\n },\r\n required = new[] { \"code\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetCommandLineTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"execute_command\",\r\n description = \"执行Windows命令行程序或系统命令。注意:show_window参数只在wait_for_exit为false时有效,当wait_for_exit为true时始终不显示窗口\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n command = new\r\n {\r\n type = \"string\",\r\n description = \"要执行的命令,如:ipconfig、dir、ping 127.0.0.1 等\"\r\n },\r\n arguments = new\r\n {\r\n type = \"string\",\r\n description = \"命令行参数,默认为空字符串\"\r\n },\r\n working_directory = new\r\n {\r\n type = \"string\",\r\n description = \"命令执行的工作目录,默认为当前程序运行目录\"\r\n },\r\n wait_for_exit = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否等待命令执行完成并获取输出。如果为true,则必须等待执行完成并捕获输出信息(此时不会显示控制台窗口);如果为false,则立即返回进程ID(此时可以通过show_window控制是否显示窗口)\",\r\n @default = true\r\n },\r\n timeout_seconds = new\r\n {\r\n type = \"number\",\r\n description = \"命令执行超时时间(秒),默认为300秒。仅在wait_for_exit为true时有效\",\r\n @default = 300\r\n },\r\n show_window = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否显示控制台窗口。仅在wait_for_exit为false时有效:为true时显示窗口,为false时后台运行。当wait_for_exit为true时此参数无效,始终不显示窗口\",\r\n @default = false\r\n }\r\n },\r\n required = new[] { \"command\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n #endregion\r\n\r\n public void Dispose()\r\n {\r\n LogInfo(\"ToolApiService 正在释放资源\");\r\n _httpClient?.Dispose();\r\n }\r\n }\r\n\r\n public interface IToolApiService : IDisposable\r\n {\r\n Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, List<string> toolServices);\r\n }\r\n}"}, "97d4f59dbc06f3e86f41d7f9dd376c4d58fece26": {"t": 1785760656.5190375, "n": 27568, "h": "908f9f5e8f15cceb", "c": "// ToolApiService.cs - 专门处理工具调用\r\nusing DeepSeekChat.Models;\r\nusing Newtonsoft.Json;\r\nusing Newtonsoft.Json.Serialization;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Linq;\r\nusing System.Net.Http;\r\nusing System.Text;\r\nusing System.Threading;\r\nusing System.Threading.Tasks;\r\nusing static DeepSeekChat.Services.ToolApiService;\r\n\r\nnamespace DeepSeekChat.Services\r\n{\r\n public class ToolApiService : IToolApiService\r\n {\r\n // 工具服务名称常量定义\r\n public static class ToolServices\r\n {\r\n public const string FileRead = \"FileRead\";\r\n public const string FileCreate = \"FileCreate\";\r\n public const string FileWrite = \"FileWrite\";\r\n public const string FileSystem = \"FileSystem\";\r\n public const string Compile = \"Compile\";\r\n public const string FolderBrowser = \"FolderBrowser\";\r\n public const string CommandLine = \"CommandLine\";\r\n }\r\n\r\n private readonly HttpClient _httpClient;\r\n private readonly string _logFilePath;\r\n private const string ApiUrl = \"https://api.deepseek.com/chat/completions\";\r\n\r\n public ToolApiService(string apiKey, string logFilePath = null)\r\n {\r\n _httpClient = new HttpClient()\r\n {\r\n Timeout = TimeSpan.FromMinutes(10)\r\n };\r\n _httpClient.DefaultRequestHeaders.Add(\"Authorization\", $\"Bearer {apiKey}\");\r\n _httpClient.DefaultRequestHeaders.Add(\"Accept\", \"application/json\");\r\n\r\n // 设置日志文件路径\r\n _logFilePath = logFilePath ?? GetDefaultLogFilePath();\r\n\r\n // 确保日志目录存在\r\n EnsureLogDirectory();\r\n\r\n LogInfo($\"ToolApiService 初始化完成,日志文件: {_logFilePath}\");\r\n }\r\n\r\n public async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, List<string> toolServices)\r\n {\r\n LogInfo($\"开始处理工具调用请求\");\r\n LogInfo($\"传入的工具服务: {string.Join(\", \", toolServices ?? new List<string>())}\");\r\n LogInfo($\"对话历史消息数: {conversationHistory?.Count ?? 0}\");\r\n\r\n // 如果没有指定工具服务,返回空工具列表\r\n if (toolServices == null || toolServices.Count == 0)\r\n {\r\n LogInfo(\"未指定工具服务,使用空工具列表\");\r\n return await SendToolRequestAsync(conversationHistory, new List<object>());\r\n }\r\n\r\n // 收集所有选择的工具\r\n var allTools = new List<object>();\r\n\r\n foreach (var toolService in toolServices.Distinct())\r\n {\r\n var tools = GetToolsByService(toolService);\r\n if (tools != null)\r\n {\r\n allTools.AddRange(tools);\r\n LogInfo($\"添加工具服务 '{toolService}',包含 {tools.Count} 个工具\");\r\n }\r\n else\r\n {\r\n LogWarning($\"未找到工具服务: {toolService}\");\r\n }\r\n }\r\n\r\n LogInfo($\"总计添加 {allTools.Count} 个工具\");\r\n return await SendToolRequestAsync(conversationHistory, allTools);\r\n }\r\n\r\n // 私有方法:使用具体的工具列表发送请求\r\n private async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, List<object> tools)\r\n {\r\n LogInfo($\"开始发送API请求,工具数量: {tools.Count}\");\r\n\r\n var requestData = new ChatRequest\r\n {\r\n Messages = conversationHistory,\r\n MaxTokens = 5000,\r\n Temperature = 0.3,\r\n Tools = tools,\r\n ToolChoice = tools.Count > 0 ? \"auto\" : \"none\"\r\n };\r\n\r\n var settings = new JsonSerializerSettings\r\n {\r\n ContractResolver = new DefaultContractResolver\r\n {\r\n NamingStrategy = new SnakeCaseNamingStrategy()\r\n },\r\n NullValueHandling = NullValueHandling.Ignore,\r\n Formatting = Formatting.Indented // 为日志美化JSON\r\n };\r\n\r\n var jsonContent = JsonConvert.SerializeObject(requestData, settings);\r\n\r\n // 记录发送给API的请求内容\r\n LogRequest(jsonContent, tools.Count > 0);\r\n\r\n var content = new StringContent(jsonContent, Encoding.UTF8, \"application/json\");\r\n\r\n try\r\n {\r\n LogInfo($\"正在发送请求到 DeepSeek API: {ApiUrl}\");\r\n using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));\r\n\r\n var response = await _httpClient.PostAsync(ApiUrl, content, cts.Token);\r\n\r\n LogInfo($\"收到API响应,状态码: {(int)response.StatusCode} {response.StatusCode}\");\r\n response.EnsureSuccessStatusCode();\r\n\r\n var responseJson = await response.Content.ReadAsStringAsync();\r\n\r\n // 记录API返回的内容\r\n LogResponse(responseJson, (int)response.StatusCode);\r\n\r\n var apiResponse = JsonConvert.DeserializeObject<ApiResponse>(responseJson);\r\n\r\n var result = new ToolCallResponse();\r\n\r\n if (apiResponse?.Choices?.Count > 0)\r\n {\r\n var message = apiResponse.Choices[0].Message;\r\n\r\n result.Content = message.Content ?? string.Empty;\r\n result.ToolCalls = message.ToolCalls;\r\n result.HasToolCalls = message.ToolCalls != null && message.ToolCalls.Count > 0;\r\n result.Success = true;\r\n\r\n if (result.HasToolCalls)\r\n {\r\n // 提取工具调用信息\r\n result.ToolCalls = message.ToolCalls;\r\n LogInfo($\"API返回了 {message.ToolCalls.Count} 个工具调用\");\r\n for (int i = 0; i < message.ToolCalls.Count; i++)\r\n {\r\n var toolCall = message.ToolCalls[i];\r\n LogInfo($\"工具调用 #{i + 1}: {toolCall.Function?.Name}\");\r\n }\r\n }\r\n else\r\n {\r\n LogInfo($\"API返回了文本回复,长度: {result.Content.Length} 字符\");\r\n }\r\n }\r\n else\r\n {\r\n result.Content = \"没有生成有效的回复。\";\r\n result.Success = false;\r\n LogWarning(\"API返回了空响应或无有效选择\");\r\n }\r\n\r\n return result;\r\n }\r\n catch (HttpRequestException ex)\r\n {\r\n LogError($\"工具调用请求失败: {ex.Message}\");\r\n return new ToolCallResponse\r\n {\r\n Content = $\"工具调用请求失败: {ex.Message}\",\r\n Success = false\r\n };\r\n }\r\n catch (Exception ex)\r\n {\r\n LogError($\"处理API响应时发生错误: {ex.Message}\");\r\n return new ToolCallResponse\r\n {\r\n Content = $\"处理API响应时发生错误: {ex.Message}\",\r\n Success = false\r\n };\r\n }\r\n }\r\n\r\n // 根据服务名称获取对应的工具列表\r\n private List<object> GetToolsByService(string toolService)\r\n {\r\n LogDebug($\"获取工具服务: {toolService}\");\r\n return toolService switch\r\n {\r\n ToolServices.FileRead => GetFileReadTools(),\r\n ToolServices.FileCreate => GetFileCreateTools(),\r\n ToolServices.FileWrite => GetFileWriteTools(),\r\n ToolServices.FolderBrowser => GetFolderBrowserTools(),\r\n ToolServices.CommandLine => GetCommandLineTools(),\r\n _ => null\r\n };\r\n }\r\n\r\n public List<string> GetToolsNameByService(string toolService)\r\n {\r\n LogDebug($\"获取工具名称: {toolService}\");\r\n return toolService switch\r\n {\r\n ToolServices.FileRead => [\"read_file\"],\r\n ToolServices.FileCreate => [\"create_file\"],\r\n ToolServices.FileWrite => [\"write_file\"],\r\n ToolServices.FolderBrowser => [\"get_folder_structure_description\"],\r\n ToolServices.CommandLine => [\"execute_command\"],\r\n _ => [\"\"]\r\n };\r\n }\r\n\r\n #region 日志记录方法\r\n\r\n private string GetDefaultLogFilePath()\r\n {\r\n var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);\r\n var logDir = Path.Combine(appDataPath, \"DeepSeekChat\", \"Logs\");\r\n var timestamp = DateTime.Now.ToString(\"yyyyMMdd\");\r\n return Path.Combine(logDir, $\"tool_api_{timestamp}.log\");\r\n }\r\n\r\n private void EnsureLogDirectory()\r\n {\r\n var logDir = Path.GetDirectoryName(_logFilePath);\r\n if (!string.IsNullOrEmpty(logDir) && !Directory.Exists(logDir))\r\n {\r\n Directory.CreateDirectory(logDir);\r\n }\r\n }\r\n\r\n private void LogRequest(string jsonContent, bool hasTools)\r\n {\r\n try\r\n {\r\n var logEntry = new StringBuilder();\r\n logEntry.AppendLine(\"=\".PadRight(80, '='));\r\n logEntry.AppendLine($\"请求时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}\");\r\n logEntry.AppendLine($\"目标URL: {ApiUrl}\");\r\n logEntry.AppendLine($\"包含工具: {(hasTools ? \"是\" : \"否\")}\");\r\n logEntry.AppendLine(\"请求内容:\");\r\n logEntry.AppendLine(jsonContent);\r\n logEntry.AppendLine();\r\n\r\n File.AppendAllText(_logFilePath, logEntry.ToString());\r\n }\r\n catch (Exception ex)\r\n {\r\n Console.WriteLine($\"无法写入日志文件: {ex.Message}\");\r\n }\r\n }\r\n\r\n private void LogResponse(string jsonContent, int statusCode)\r\n {\r\n try\r\n {\r\n var logEntry = new StringBuilder();\r\n logEntry.AppendLine($\"响应时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}\");\r\n logEntry.AppendLine($\"状态码: {statusCode}\");\r\n logEntry.AppendLine(\"响应内容:\");\r\n\r\n // 尝试美化JSON响应\r\n try\r\n {\r\n var jsonObject = JsonConvert.DeserializeObject(jsonContent);\r\n var formattedJson = JsonConvert.SerializeObject(jsonObject, Formatting.Indented);\r\n logEntry.AppendLine(formattedJson);\r\n }\r\n catch\r\n {\r\n logEntry.AppendLine(jsonContent);\r\n }\r\n\r\n logEntry.AppendLine(\"=\".PadRight(80, '='));\r\n logEntry.AppendLine();\r\n\r\n File.AppendAllText(_logFilePath, logEntry.ToString());\r\n }\r\n catch (Exception ex)\r\n {\r\n Console.WriteLine($\"无法写入日志文件: {ex.Message}\");\r\n }\r\n }\r\n\r\n private void LogInfo(string message)\r\n {\r\n WriteLog(\"INFO\", message);\r\n }\r\n\r\n private void LogWarning(string message)\r\n {\r\n WriteLog(\"WARN\", message);\r\n }\r\n\r\n private void LogError(string message)\r\n {\r\n WriteLog(\"ERROR\", message);\r\n }\r\n\r\n private void LogDebug(string message)\r\n {\r\n WriteLog(\"DEBUG\", message);\r\n }\r\n\r\n private void WriteLog(string level, string message)\r\n {\r\n try\r\n {\r\n var timestamp = DateTime.Now.ToString(\"yyyy-MM-dd HH:mm:ss.fff\");\r\n var logMessage = $\"{timestamp} [{level}] {message}\";\r\n\r\n File.AppendAllText(_logFilePath, logMessage + Environment.NewLine);\r\n\r\n // 同时输出到控制台以便调试\r\n Console.WriteLine(logMessage);\r\n }\r\n catch (Exception ex)\r\n {\r\n Console.WriteLine($\"无法写入日志文件: {ex.Message}\");\r\n }\r\n }\r\n\r\n #endregion\r\n\r\n #region 工具定义方法\r\n\r\n private List<object> GetFolderInfoTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"get_folder_info\",\r\n description = \"获取文件夹详细信息,包括文件数量、大小统计、常见文件类型等\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n folder_path = new\r\n {\r\n type = \"string\",\r\n description = \"要获取信息的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\r\n }\r\n },\r\n required = new[] { \"folder_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> DeleteFileTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"delete_file\",\r\n description = \"删除文件\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要删除的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_delete.txt\"\r\n }\r\n },\r\n required = new[] { \"file_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFileCreateTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"create_file\",\r\n description = \"创建新文件\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\r\n },\r\n content = new\r\n {\r\n type = \"string\",\r\n description = \"文件内容,默认为空字符串\"\r\n },\r\n overwrite = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否覆盖已存在的文件,默认为false\"\r\n }\r\n },\r\n required = new[] { \"file_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFileReadTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"read_file\",\r\n description = \"读取文件内容\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\r\n },\r\n encoding = new\r\n {\r\n type = \"string\",\r\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\r\n },\r\n max_size_bytes = new\r\n {\r\n type = \"integer\",\r\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\r\n }\r\n },\r\n required = new[] { \"file_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFileWriteTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"write_file\",\r\n description = \"写入文件内容\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要写入的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_write.txt\"\r\n },\r\n content = new\r\n {\r\n type = \"string\",\r\n description = \"要写入的文件内容\"\r\n },\r\n encoding = new\r\n {\r\n type = \"string\",\r\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\r\n },\r\n mode = new\r\n {\r\n type = \"string\",\r\n description = \"写入模式:create=仅创建新文件(文件存在则失败)、overwrite=覆盖文件(文件存在则覆盖)、append=在文件末尾追加内容,默认为create\",\r\n @enum = new[] { \"create\", \"overwrite\", \"append\" }\r\n }\r\n },\r\n required = new[] { \"file_path\", \"content\" ,\"mode\"}\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFolderBrowserTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"get_folder_structure_description\",\r\n description = \"浏览本地文件夹,获取文件列表,可以过滤特定文件类型并排除指定文件夹\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n folder_path = new\r\n {\r\n type = \"string\",\r\n description = \"要浏览的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\r\n },\r\n include_subdirectories = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否包含子目录,默认为false\"\r\n },\r\n filter_extensions = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"要过滤的文件扩展名列表,如:['.txt', '.pdf', '.jpg'],只返回这些扩展名的文件\"\r\n },\r\n exclude_paths = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"要排除的文件夹名称或路径列表,如:['node_modules', 'bin', 'obj', '.git']。这些文件夹及其所有内容将被忽略\"\r\n }\r\n },\r\n required = new[] { \"folder_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n private List<object> GetCompileTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"compile_csharp\",\r\n description = \"编译C#代码并可选地执行程序。支持生成可执行文件或在内存中直接执行代码。\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n code = new\r\n {\r\n type = \"string\",\r\n description = \"要编译的C#源代码。必须是完整的程序,包含Main方法或入口点。\"\r\n },\r\n outputPath = new\r\n {\r\n type = \"string\",\r\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译。示例:C:\\\\Output\\\\Program.dll\"\r\n },\r\n execute = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否在编译后立即执行程序。如果为true,将在内存中执行并返回执行结果。默认为false。\"\r\n },\r\n includeReferences = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"额外的程序集引用路径列表。示例:[\\\"Newtonsoft.Json.dll\\\", \\\"System.Data.dll\\\"]\"\r\n },\r\n targetFramework = new\r\n {\r\n type = \"string\",\r\n description = \"目标框架版本。支持:net8.0。默认为当前运行时版本。\"\r\n }\r\n },\r\n required = new[] { \"code\" }\r\n }\r\n }\r\n },\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"compile_and_execute\",\r\n description = \"编译C#代码并立即执行,返回执行结果。适用于快速测试代码片段。\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n code = new\r\n {\r\n type = \"string\",\r\n description = \"要编译执行的C#源代码。必须包含Main方法。示例:'using System; class Program { static void Main() { Console.WriteLine(\\\"Hello\\\"); } }'\"\r\n },\r\n output_path = new\r\n {\r\n type = \"string\",\r\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译和执行。示例:C:\\\\Temp\\\\MyProgram.dll\"\r\n },\r\n arguments = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"传递给Main方法的命令行参数。示例:[\\\"arg1\\\", \\\"arg2\\\"]\"\r\n }\r\n },\r\n required = new[] { \"code\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetCommandLineTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"execute_command\",\r\n description = \"执行Windows命令行程序或系统命令。注意:show_window参数只在wait_for_exit为false时有效,当wait_for_exit为true时始终不显示窗口\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n command = new\r\n {\r\n type = \"string\",\r\n description = \"要执行的命令,如:ipconfig、dir、ping 127.0.0.1 等\"\r\n },\r\n arguments = new\r\n {\r\n type = \"string\",\r\n description = \"命令行参数,默认为空字符串\"\r\n },\r\n working_directory = new\r\n {\r\n type = \"string\",\r\n description = \"命令执行的工作目录,默认为当前程序运行目录\"\r\n },\r\n wait_for_exit = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否等待命令执行完成并获取输出。如果为true,则必须等待执行完成并捕获输出信息(此时不会显示控制台窗口);如果为false,则立即返回进程ID(此时可以通过show_window控制是否显示窗口)\",\r\n @default = true\r\n },\r\n timeout_seconds = new\r\n {\r\n type = \"number\",\r\n description = \"命令执行超时时间(秒),默认为300秒。仅在wait_for_exit为true时有效\",\r\n @default = 300\r\n },\r\n show_window = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否显示控制台窗口。仅在wait_for_exit为false时有效:为true时显示窗口,为false时后台运行。当wait_for_exit为true时此参数无效,始终不显示窗口\",\r\n @default = false\r\n }\r\n },\r\n required = new[] { \"command\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n #endregion\r\n\r\n public void Dispose()\r\n {\r\n LogInfo(\"ToolApiService 正在释放资源\");\r\n _httpClient?.Dispose();\r\n }\r\n }\r\n\r\n public interface IToolApiService : IDisposable\r\n {\r\n Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, List<string> toolServices);\r\n }\r\n}"}, "0a160f150320c8d6c21c1866d32b00a31d6374a6": {"t": 1785760658.1865559, "n": 27361, "h": "c6fa8ce9deac3a34", "c": "// ToolApiService.cs - 专门处理工具调用\r\nusing DeepSeekChat.Models;\r\nusing Newtonsoft.Json;\r\nusing Newtonsoft.Json.Serialization;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Linq;\r\nusing System.Net.Http;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\nusing static DeepSeekChat.Services.ToolApiService;\r\n\r\nnamespace DeepSeekChat.Services\r\n{\r\n public class ToolApiService : IToolApiService\r\n {\r\n // 工具服务名称常量定义\r\n public static class ToolServices\r\n {\r\n public const string FileRead = \"FileRead\";\r\n public const string FileCreate = \"FileCreate\";\r\n public const string FileWrite = \"FileWrite\";\r\n public const string FileSystem = \"FileSystem\";\r\n public const string Compile = \"Compile\";\r\n public const string FolderBrowser = \"FolderBrowser\";\r\n public const string CommandLine = \"CommandLine\";\r\n }\r\n\r\n private readonly HttpClient _httpClient;\r\n private readonly string _logFilePath;\r\n private const string ApiUrl = \"https://api.deepseek.com/chat/completions\";\r\n\r\n public ToolApiService(string apiKey, string logFilePath = null)\r\n {\r\n _httpClient = new HttpClient();\r\n _httpClient.DefaultRequestHeaders.Add(\"Authorization\", $\"Bearer {apiKey}\");\r\n _httpClient.DefaultRequestHeaders.Add(\"Accept\", \"application/json\");\r\n\r\n // 设置日志文件路径\r\n _logFilePath = logFilePath ?? GetDefaultLogFilePath();\r\n\r\n // 确保日志目录存在\r\n EnsureLogDirectory();\r\n\r\n LogInfo($\"ToolApiService 初始化完成,日志文件: {_logFilePath}\");\r\n }\r\n\r\n public async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, List<string> toolServices)\r\n {\r\n LogInfo($\"开始处理工具调用请求\");\r\n LogInfo($\"传入的工具服务: {string.Join(\", \", toolServices ?? new List<string>())}\");\r\n LogInfo($\"对话历史消息数: {conversationHistory?.Count ?? 0}\");\r\n\r\n // 如果没有指定工具服务,返回空工具列表\r\n if (toolServices == null || toolServices.Count == 0)\r\n {\r\n LogInfo(\"未指定工具服务,使用空工具列表\");\r\n return await SendToolRequestAsync(conversationHistory, new List<object>());\r\n }\r\n\r\n // 收集所有选择的工具\r\n var allTools = new List<object>();\r\n\r\n foreach (var toolService in toolServices.Distinct())\r\n {\r\n var tools = GetToolsByService(toolService);\r\n if (tools != null)\r\n {\r\n allTools.AddRange(tools);\r\n LogInfo($\"添加工具服务 '{toolService}',包含 {tools.Count} 个工具\");\r\n }\r\n else\r\n {\r\n LogWarning($\"未找到工具服务: {toolService}\");\r\n }\r\n }\r\n\r\n LogInfo($\"总计添加 {allTools.Count} 个工具\");\r\n return await SendToolRequestAsync(conversationHistory, allTools);\r\n }\r\n\r\n // 私有方法:使用具体的工具列表发送请求\r\n private async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, List<object> tools)\r\n {\r\n LogInfo($\"开始发送API请求,工具数量: {tools.Count}\");\r\n\r\n var requestData = new ChatRequest\r\n {\r\n Messages = conversationHistory,\r\n MaxTokens = 5000,\r\n Temperature = 0.3,\r\n Tools = tools,\r\n ToolChoice = tools.Count > 0 ? \"auto\" : \"none\"\r\n };\r\n\r\n var settings = new JsonSerializerSettings\r\n {\r\n ContractResolver = new DefaultContractResolver\r\n {\r\n NamingStrategy = new SnakeCaseNamingStrategy()\r\n },\r\n NullValueHandling = NullValueHandling.Ignore,\r\n Formatting = Formatting.Indented // 为日志美化JSON\r\n };\r\n\r\n var jsonContent = JsonConvert.SerializeObject(requestData, settings);\r\n\r\n // 记录发送给API的请求内容\r\n LogRequest(jsonContent, tools.Count > 0);\r\n\r\n var content = new StringContent(jsonContent, Encoding.UTF8, \"application/json\");\r\n\r\n try\r\n {\r\n LogInfo($\"正在发送请求到 DeepSeek API: {ApiUrl}\");\r\n var response = await _httpClient.PostAsync(ApiUrl, content);\r\n\r\n LogInfo($\"收到API响应,状态码: {(int)response.StatusCode} {response.StatusCode}\");\r\n response.EnsureSuccessStatusCode();\r\n\r\n var responseJson = await response.Content.ReadAsStringAsync();\r\n\r\n // 记录API返回的内容\r\n LogResponse(responseJson, (int)response.StatusCode);\r\n\r\n var apiResponse = JsonConvert.DeserializeObject<ApiResponse>(responseJson);\r\n\r\n var result = new ToolCallResponse();\r\n\r\n if (apiResponse?.Choices?.Count > 0)\r\n {\r\n var message = apiResponse.Choices[0].Message;\r\n\r\n result.Content = message.Content ?? string.Empty;\r\n result.ToolCalls = message.ToolCalls;\r\n result.HasToolCalls = message.ToolCalls != null && message.ToolCalls.Count > 0;\r\n result.Success = true;\r\n\r\n if (result.HasToolCalls)\r\n {\r\n // 提取工具调用信息\r\n result.ToolCalls = message.ToolCalls;\r\n LogInfo($\"API返回了 {message.ToolCalls.Count} 个工具调用\");\r\n for (int i = 0; i < message.ToolCalls.Count; i++)\r\n {\r\n var toolCall = message.ToolCalls[i];\r\n LogInfo($\"工具调用 #{i + 1}: {toolCall.Function?.Name}\");\r\n }\r\n }\r\n else\r\n {\r\n LogInfo($\"API返回了文本回复,长度: {result.Content.Length} 字符\");\r\n }\r\n }\r\n else\r\n {\r\n result.Content = \"没有生成有效的回复。\";\r\n result.Success = false;\r\n LogWarning(\"API返回了空响应或无有效选择\");\r\n }\r\n\r\n return result;\r\n }\r\n catch (HttpRequestException ex)\r\n {\r\n LogError($\"工具调用请求失败: {ex.Message}\");\r\n return new ToolCallResponse\r\n {\r\n Content = $\"工具调用请求失败: {ex.Message}\",\r\n Success = false\r\n };\r\n }\r\n catch (Exception ex)\r\n {\r\n LogError($\"处理API响应时发生错误: {ex.Message}\");\r\n return new ToolCallResponse\r\n {\r\n Content = $\"处理API响应时发生错误: {ex.Message}\",\r\n Success = false\r\n };\r\n }\r\n }\r\n\r\n // 根据服务名称获取对应的工具列表\r\n private List<object> GetToolsByService(string toolService)\r\n {\r\n LogDebug($\"获取工具服务: {toolService}\");\r\n return toolService switch\r\n {\r\n ToolServices.FileRead => GetFileReadTools(),\r\n ToolServices.FileCreate => GetFileCreateTools(),\r\n ToolServices.FileWrite => GetFileWriteTools(),\r\n ToolServices.FolderBrowser => GetFolderBrowserTools(),\r\n ToolServices.CommandLine => GetCommandLineTools(),\r\n _ => null\r\n };\r\n }\r\n\r\n public List<string> GetToolsNameByService(string toolService)\r\n {\r\n LogDebug($\"获取工具名称: {toolService}\");\r\n return toolService switch\r\n {\r\n ToolServices.FileRead => [\"read_file\"],\r\n ToolServices.FileCreate => [\"create_file\"],\r\n ToolServices.FileWrite => [\"write_file\"],\r\n ToolServices.FolderBrowser => [\"get_folder_structure_description\"],\r\n ToolServices.CommandLine => [\"execute_command\"],\r\n _ => [\"\"]\r\n };\r\n }\r\n\r\n #region 日志记录方法\r\n\r\n private string GetDefaultLogFilePath()\r\n {\r\n var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);\r\n var logDir = Path.Combine(appDataPath, \"DeepSeekChat\", \"Logs\");\r\n var timestamp = DateTime.Now.ToString(\"yyyyMMdd\");\r\n return Path.Combine(logDir, $\"tool_api_{timestamp}.log\");\r\n }\r\n\r\n private void EnsureLogDirectory()\r\n {\r\n var logDir = Path.GetDirectoryName(_logFilePath);\r\n if (!string.IsNullOrEmpty(logDir) && !Directory.Exists(logDir))\r\n {\r\n Directory.CreateDirectory(logDir);\r\n }\r\n }\r\n\r\n private void LogRequest(string jsonContent, bool hasTools)\r\n {\r\n try\r\n {\r\n var logEntry = new StringBuilder();\r\n logEntry.AppendLine(\"=\".PadRight(80, '='));\r\n logEntry.AppendLine($\"请求时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}\");\r\n logEntry.AppendLine($\"目标URL: {ApiUrl}\");\r\n logEntry.AppendLine($\"包含工具: {(hasTools ? \"是\" : \"否\")}\");\r\n logEntry.AppendLine(\"请求内容:\");\r\n logEntry.AppendLine(jsonContent);\r\n logEntry.AppendLine();\r\n\r\n File.AppendAllText(_logFilePath, logEntry.ToString());\r\n }\r\n catch (Exception ex)\r\n {\r\n Console.WriteLine($\"无法写入日志文件: {ex.Message}\");\r\n }\r\n }\r\n\r\n private void LogResponse(string jsonContent, int statusCode)\r\n {\r\n try\r\n {\r\n var logEntry = new StringBuilder();\r\n logEntry.AppendLine($\"响应时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}\");\r\n logEntry.AppendLine($\"状态码: {statusCode}\");\r\n logEntry.AppendLine(\"响应内容:\");\r\n\r\n // 尝试美化JSON响应\r\n try\r\n {\r\n var jsonObject = JsonConvert.DeserializeObject(jsonContent);\r\n var formattedJson = JsonConvert.SerializeObject(jsonObject, Formatting.Indented);\r\n logEntry.AppendLine(formattedJson);\r\n }\r\n catch\r\n {\r\n logEntry.AppendLine(jsonContent);\r\n }\r\n\r\n logEntry.AppendLine(\"=\".PadRight(80, '='));\r\n logEntry.AppendLine();\r\n\r\n File.AppendAllText(_logFilePath, logEntry.ToString());\r\n }\r\n catch (Exception ex)\r\n {\r\n Console.WriteLine($\"无法写入日志文件: {ex.Message}\");\r\n }\r\n }\r\n\r\n private void LogInfo(string message)\r\n {\r\n WriteLog(\"INFO\", message);\r\n }\r\n\r\n private void LogWarning(string message)\r\n {\r\n WriteLog(\"WARN\", message);\r\n }\r\n\r\n private void LogError(string message)\r\n {\r\n WriteLog(\"ERROR\", message);\r\n }\r\n\r\n private void LogDebug(string message)\r\n {\r\n WriteLog(\"DEBUG\", message);\r\n }\r\n\r\n private void WriteLog(string level, string message)\r\n {\r\n try\r\n {\r\n var timestamp = DateTime.Now.ToString(\"yyyy-MM-dd HH:mm:ss.fff\");\r\n var logMessage = $\"{timestamp} [{level}] {message}\";\r\n\r\n File.AppendAllText(_logFilePath, logMessage + Environment.NewLine);\r\n\r\n // 同时输出到控制台以便调试\r\n Console.WriteLine(logMessage);\r\n }\r\n catch (Exception ex)\r\n {\r\n Console.WriteLine($\"无法写入日志文件: {ex.Message}\");\r\n }\r\n }\r\n\r\n #endregion\r\n\r\n #region 工具定义方法\r\n\r\n private List<object> GetFolderInfoTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"get_folder_info\",\r\n description = \"获取文件夹详细信息,包括文件数量、大小统计、常见文件类型等\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n folder_path = new\r\n {\r\n type = \"string\",\r\n description = \"要获取信息的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\r\n }\r\n },\r\n required = new[] { \"folder_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> DeleteFileTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"delete_file\",\r\n description = \"删除文件\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要删除的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_delete.txt\"\r\n }\r\n },\r\n required = new[] { \"file_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFileCreateTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"create_file\",\r\n description = \"创建新文件\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\r\n },\r\n content = new\r\n {\r\n type = \"string\",\r\n description = \"文件内容,默认为空字符串\"\r\n },\r\n overwrite = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否覆盖已存在的文件,默认为false\"\r\n }\r\n },\r\n required = new[] { \"file_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFileReadTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"read_file\",\r\n description = \"读取文件内容\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\r\n },\r\n encoding = new\r\n {\r\n type = \"string\",\r\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\r\n },\r\n max_size_bytes = new\r\n {\r\n type = \"integer\",\r\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\r\n }\r\n },\r\n required = new[] { \"file_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFileWriteTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"write_file\",\r\n description = \"写入文件内容\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n file_path = new\r\n {\r\n type = \"string\",\r\n description = \"要写入的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_write.txt\"\r\n },\r\n content = new\r\n {\r\n type = \"string\",\r\n description = \"要写入的文件内容\"\r\n },\r\n encoding = new\r\n {\r\n type = \"string\",\r\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\r\n },\r\n mode = new\r\n {\r\n type = \"string\",\r\n description = \"写入模式:create=仅创建新文件(文件存在则失败)、overwrite=覆盖文件(文件存在则覆盖)、append=在文件末尾追加内容,默认为create\",\r\n @enum = new[] { \"create\", \"overwrite\", \"append\" }\r\n }\r\n },\r\n required = new[] { \"file_path\", \"content\" ,\"mode\"}\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetFolderBrowserTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"get_folder_structure_description\",\r\n description = \"浏览本地文件夹,获取文件列表,可以过滤特定文件类型并排除指定文件夹\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n folder_path = new\r\n {\r\n type = \"string\",\r\n description = \"要浏览的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\r\n },\r\n include_subdirectories = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否包含子目录,默认为false\"\r\n },\r\n filter_extensions = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"要过滤的文件扩展名列表,如:['.txt', '.pdf', '.jpg'],只返回这些扩展名的文件\"\r\n },\r\n exclude_paths = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"要排除的文件夹名称或路径列表,如:['node_modules', 'bin', 'obj', '.git']。这些文件夹及其所有内容将被忽略\"\r\n }\r\n },\r\n required = new[] { \"folder_path\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n private List<object> GetCompileTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"compile_csharp\",\r\n description = \"编译C#代码并可选地执行程序。支持生成可执行文件或在内存中直接执行代码。\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n code = new\r\n {\r\n type = \"string\",\r\n description = \"要编译的C#源代码。必须是完整的程序,包含Main方法或入口点。\"\r\n },\r\n outputPath = new\r\n {\r\n type = \"string\",\r\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译。示例:C:\\\\Output\\\\Program.dll\"\r\n },\r\n execute = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否在编译后立即执行程序。如果为true,将在内存中执行并返回执行结果。默认为false。\"\r\n },\r\n includeReferences = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"额外的程序集引用路径列表。示例:[\\\"Newtonsoft.Json.dll\\\", \\\"System.Data.dll\\\"]\"\r\n },\r\n targetFramework = new\r\n {\r\n type = \"string\",\r\n description = \"目标框架版本。支持:net8.0。默认为当前运行时版本。\"\r\n }\r\n },\r\n required = new[] { \"code\" }\r\n }\r\n }\r\n },\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"compile_and_execute\",\r\n description = \"编译C#代码并立即执行,返回执行结果。适用于快速测试代码片段。\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n code = new\r\n {\r\n type = \"string\",\r\n description = \"要编译执行的C#源代码。必须包含Main方法。示例:'using System; class Program { static void Main() { Console.WriteLine(\\\"Hello\\\"); } }'\"\r\n },\r\n output_path = new\r\n {\r\n type = \"string\",\r\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译和执行。示例:C:\\\\Temp\\\\MyProgram.dll\"\r\n },\r\n arguments = new\r\n {\r\n type = \"array\",\r\n items = new { type = \"string\" },\r\n description = \"传递给Main方法的命令行参数。示例:[\\\"arg1\\\", \\\"arg2\\\"]\"\r\n }\r\n },\r\n required = new[] { \"code\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n private List<object> GetCommandLineTools()\r\n {\r\n return new List<object>\r\n {\r\n new\r\n {\r\n type = \"function\",\r\n function = new\r\n {\r\n name = \"execute_command\",\r\n description = \"执行Windows命令行程序或系统命令。注意:show_window参数只在wait_for_exit为false时有效,当wait_for_exit为true时始终不显示窗口\",\r\n parameters = new\r\n {\r\n type = \"object\",\r\n properties = new\r\n {\r\n command = new\r\n {\r\n type = \"string\",\r\n description = \"要执行的命令,如:ipconfig、dir、ping 127.0.0.1 等\"\r\n },\r\n arguments = new\r\n {\r\n type = \"string\",\r\n description = \"命令行参数,默认为空字符串\"\r\n },\r\n working_directory = new\r\n {\r\n type = \"string\",\r\n description = \"命令执行的工作目录,默认为当前程序运行目录\"\r\n },\r\n wait_for_exit = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否等待命令执行完成并获取输出。如果为true,则必须等待执行完成并捕获输出信息(此时不会显示控制台窗口);如果为false,则立即返回进程ID(此时可以通过show_window控制是否显示窗口)\",\r\n @default = true\r\n },\r\n timeout_seconds = new\r\n {\r\n type = \"number\",\r\n description = \"命令执行超时时间(秒),默认为300秒。仅在wait_for_exit为true时有效\",\r\n @default = 300\r\n },\r\n show_window = new\r\n {\r\n type = \"boolean\",\r\n description = \"是否显示控制台窗口。仅在wait_for_exit为false时有效:为true时显示窗口,为false时后台运行。当wait_for_exit为true时此参数无效,始终不显示窗口\",\r\n @default = false\r\n }\r\n },\r\n required = new[] { \"command\" }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n #endregion\r\n\r\n public void Dispose()\r\n {\r\n LogInfo(\"ToolApiService 正在释放资源\");\r\n _httpClient?.Dispose();\r\n }\r\n }\r\n\r\n public interface IToolApiService : IDisposable\r\n {\r\n Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, List<string> toolServices);\r\n }\r\n}"}, "1e2abe5d1fdf6b45407cf666aeb86165754be59a": {"t": 1785760659.7249336, "n": 28414, "h": "2be8306f19368bd6", "c": "// ToolApiService.cs - 专门处理工具调用\nusing DeepSeekChat.Models;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Serialization;\nusing System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\nusing static DeepSeekChat.Services.ToolApiService;\n\nnamespace DeepSeekChat.Services\n{\n public class ToolApiService : IToolApiService\n {\n public enum ToolApiType\n {\n FileRead,\n FileCreate,\n FileWrite,\n FileSystem,\n TaskManager,\n Compile,\n UserNeedsAnalysis\n }\n private readonly HttpClient _httpClient;\n private const string ApiUrl = \"https://api.deepseek.com/chat/completions\";\n\n public ToolApiService(string apiKey)\n {\n _httpClient = new HttpClient();\n _httpClient.DefaultRequestHeaders.Add(\"Authorization\", $\"Bearer {apiKey}\");\n _httpClient.DefaultRequestHeaders.Add(\"Accept\", \"application/json\");\n }\n\n public async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, ToolApiType toolApiType)\n {\n List<Object> tools = new List<Object>();\n switch(toolApiType)\n {\n case ToolApiType.FileRead:\n tools = GetFileReadTools();\n break;\n case ToolApiType.FileCreate:\n tools = GetFileCreateTools();\n break;\n case ToolApiType.FileWrite:\n tools = GetFileWriteTools();\n break;\n case ToolApiType.TaskManager:\n tools = GetTaskCreationTools();\n break;\n case ToolApiType.Compile:\n tools = GetCompileTools();\n break;\n case ToolApiType.UserNeedsAnalysis:\n tools = GetHandleUserNeedsTools();\n break;\n default:\n break;\n }\n var requestData = new ChatRequest\n {\n Messages = conversationHistory,\n MaxTokens = 5000,\n Temperature = 0.3,\n Tools = tools,\n ToolChoice = \"auto\"\n };\n\n var settings = new JsonSerializerSettings\n {\n ContractResolver = new DefaultContractResolver\n {\n NamingStrategy = new SnakeCaseNamingStrategy()\n },\n NullValueHandling = NullValueHandling.Ignore\n };\n\n var jsonContent = JsonConvert.SerializeObject(requestData, settings);\n var content = new StringContent(jsonContent, Encoding.UTF8, \"application/json\");\n\n try\n {\n var response = await _httpClient.PostAsync(ApiUrl, content);\n response.EnsureSuccessStatusCode();\n\n var responseJson = await response.Content.ReadAsStringAsync();\n var apiResponse = JsonConvert.DeserializeObject<ApiResponse>(responseJson);\n\n var result = new ToolCallResponse();\n\n if (apiResponse?.Choices?.Count > 0)\n {\n var message = apiResponse.Choices[0].Message;\n\n result.Content = message.Content ?? string.Empty;\n result.ToolCalls = message.ToolCalls;\n result.HasToolCalls = message.ToolCalls != null && message.ToolCalls.Count > 0;\n result.Success = true;\n\n if (result.HasToolCalls)\n {\n // 提取工具调用信息\n result.ToolCallInfos = ExtractToolCallInfos(message.ToolCalls);\n }\n }\n else\n {\n result.Content = \"没有生成有效的回复。\";\n result.Success = false;\n }\n\n return result;\n }\n catch (HttpRequestException ex)\n {\n return new ToolCallResponse\n {\n Content = $\"工具调用请求失败: {ex.Message}\",\n Success = false\n };\n }\n }\n\n private List<ToolCallInfo> ExtractToolCallInfos(List<ToolCall> toolCalls)\n {\n var infos = new List<ToolCallInfo>();\n\n foreach (var toolCall in toolCalls)\n {\n var info = new ToolCallInfo\n {\n Id = toolCall.Id,\n FunctionName = toolCall.Function?.Name,\n Arguments = toolCall.Function?.Arguments\n };\n infos.Add(info);\n }\n\n return infos;\n }\n\n private List<object> GetFileSystemTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"browse_local_folder\",\n description = \"浏览本地文件夹,获取文件列表\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n folder_path = new\n {\n type = \"string\",\n description = \"要浏览的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\n },\n include_subdirectories = new\n {\n type = \"boolean\",\n description = \"是否包含子目录,默认为false\"\n },\n filter_extensions = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"要过滤的文件扩展名列表,如:[.txt, .pdf, .jpg]\"\n }\n },\n required = new[] { \"folder_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"get_folder_info\",\n description = \"获取文件夹详细信息,包括文件数量、大小统计、常见文件类型等\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n folder_path = new\n {\n type = \"string\",\n description = \"要获取信息的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\n }\n },\n required = new[] { \"folder_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"create_file\",\n description = \"创建新文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"文件内容,默认为空字符串\"\n },\n overwrite = new\n {\n type = \"boolean\",\n description = \"是否覆盖已存在的文件,默认为false\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"delete_file\",\n description = \"删除文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要删除的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_delete.txt\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"read_file\",\n description = \"读取文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n max_size_bytes = new\n {\n type = \"integer\",\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"write_file\",\n description = \"写入文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要写入的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_write.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"要写入的文件内容\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n append = new\n {\n type = \"boolean\",\n description = \"是否以追加模式写入,true=在文件末尾追加内容,false=覆盖整个文件,默认为false\"\n }\n },\n required = new[] { \"file_path\", \"content\" }\n }\n }\n }\n };\n }\n\n private List<object> GetFileCreateTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"create_file\",\n description = \"创建新文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"文件内容,默认为空字符串\"\n },\n overwrite = new\n {\n type = \"boolean\",\n description = \"是否覆盖已存在的文件,默认为false\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n }\n };\n }\n\n private List<object> GetFileReadTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"read_file\",\n description = \"读取文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n max_size_bytes = new\n {\n type = \"integer\",\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n }\n };\n }\n\n private List<object> GetFileWriteTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"write_file\",\n description = \"写入文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要写入的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_write.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"要写入的文件内容\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n mode = new\n {\n type = \"string\",\n description = \"写入模式:create=仅创建新文件(文件存在则失败)、overwrite=覆盖文件(文件存在则覆盖)、append=在文件末尾追加内容,默认为create\",\n @enum = new[] { \"create\", \"overwrite\", \"append\" }\n }\n },\n required = new[] { \"file_path\", \"content\" ,\"mode\"}\n }\n }\n }\n };\n }\n \n private List<object> GetCompileTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"compile_csharp\",\n description = \"编译C#代码并可选地执行程序。支持生成可执行文件或在内存中直接执行代码。\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n code = new\n {\n type = \"string\",\n description = \"要编译的C#源代码。必须是完整的程序,包含Main方法或入口点。\"\n },\n outputPath = new\n {\n type = \"string\",\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译。示例:C:\\\\Output\\\\Program.dll\"\n },\n execute = new\n {\n type = \"boolean\",\n description = \"是否在编译后立即执行程序。如果为true,将在内存中执行并返回执行结果。默认为false。\"\n },\n includeReferences = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"额外的程序集引用路径列表。示例:[\\\"Newtonsoft.Json.dll\\\", \\\"System.Data.dll\\\"]\"\n },\n targetFramework = new\n {\n type = \"string\",\n description = \"目标框架版本。支持:net8.0。默认为当前运行时版本。\"\n }\n },\n required = new[] { \"code\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"compile_and_execute\",\n description = \"编译C#代码并立即执行,返回执行结果。适用于快速测试代码片段。\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n code = new\n {\n type = \"string\",\n description = \"要编译执行的C#源代码。必须包含Main方法。示例:'using System; class Program { static void Main() { Console.WriteLine(\\\"Hello\\\"); } }'\"\n },\n output_path = new\n {\n type = \"string\",\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译和执行。示例:C:\\\\Temp\\\\MyProgram.dll\"\n },\n arguments = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"传递给Main方法的命令行参数。示例:[\\\"arg1\\\", \\\"arg2\\\"]\"\n }\n },\n required = new[] { \"code\" }\n }\n }\n }\n };\n }\n\n\n public List<object> GetTaskCreationTools()\n {\n // 构建 TaskDefinition 的 JSON Schema 属性\n var taskDefinitionProperties = new Dictionary<string, object>\n {\n [\"task_id\"] = new\n {\n type = \"string\",\n description = \"任务ID,建议使用GUID\"\n },\n [\"project_name\"] = new\n {\n type = \"string\",\n description = \"工程文件名\"\n },\n [\"file_name\"] = new\n {\n type = \"string\",\n description = \"文件名\"\n },\n [\"file_path\"] = new\n {\n type = \"string\",\n description = \"文件路径\"\n },\n [\"function\"] = new\n {\n type = \"string\",\n description = \"文件功能描述\"\n },\n [\"dependencies\"] = new\n {\n type = \"array\",\n description = \"依赖的文件名列表\",\n items = new { type = \"string\" }\n },\n [\"requirements\"] = new\n {\n type = \"string\",\n description = \"创建该文件的具体要求\"\n },\n [\"estimated_complexity\"] = new\n {\n type = \"string\",\n description = \"估计复杂度\",\n @enum = new[] { \"low\", \"medium\", \"high\" }\n },\n [\"technology_requirements\"] = new\n {\n type = \"array\",\n description = \"技术需求列表\",\n items = new { type = \"string\" }\n },\n [\"testing_requirements\"] = new\n {\n type = \"string\",\n description = \"测试要求\"\n },\n [\"status\"] = new\n {\n type = \"string\",\n description = \"任务状态\",\n @default = \"pending\"\n },\n [\"assigned_to\"] = new\n {\n type = \"string\",\n description = \"分配给谁\",\n @default = \"CodingAgent\"\n }\n };\n\n // 任务定义所需的必填字段\n var requiredTaskProperties = new[] {\n \"task_id\",\"project_name\", \"file_name\", \"file_path\", \"function\", \"requirements\"\n };\n\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"distribute_coding_tasks\",\n description = \"将文件创建和编码任务分配给CodingAgent,输入为任务列表\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n tasks = new\n {\n type = \"array\",\n description = \"任务定义列表,符合TaskDefinition格式\",\n items = new\n {\n type = \"object\",\n properties = taskDefinitionProperties,\n required = requiredTaskProperties\n }\n },\n distribution_strategy = new\n {\n type = \"string\",\n description = \"分配策略\",\n @enum = new[] {\n \"sequential_by_dependency\",\n \"parallel_when_possible\",\n \"complexity_based\",\n \"priority_based\"\n },\n @default = \"sequential_by_dependency\"\n },\n execution_order = new\n {\n type = \"boolean\",\n description = \"是否返回任务执行顺序建议\",\n @default = true\n },\n batch_size = new\n {\n type = \"integer\",\n description = \"批次大小,一次分配多少个任务给CodingAgent\",\n @default = 1,\n minimum = 1,\n maximum = 10\n }\n },\n required = new[] { \"tasks\" }\n }\n }\n }\n };\n }\n\n public List<object> GetHandleUserNeedsTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"send_to_agent\",\n description = \"路由用户请求:需求分析 -> RequirementAnalysisAgent,代码审查 -> ReviewAgent,其他 -> 返回User并说明原因\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n agent_name = new\n {\n type = \"string\",\n description = \"目标接收方:'RequirementAnalysisAgent'、'ReviewAgent'或'User'\",\n @enum = new[] {\n \"RequirementAnalysisAgent\",\n \"ReviewAgent\",\n \"User\"\n }\n },\n to_agent_content = new\n {\n type = \"string\",\n description = \"发送给接收方的消息内容\"\n }\n },\n required = new[] { \"agent_name\", \"to_agent_content\" }\n }\n }\n }\n };\n }\n\n public void Dispose()\n {\n _httpClient?.Dispose();\n }\n }\n\n public interface IToolApiService : IDisposable\n {\n Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, ToolApiType toolApiType);\n }\n\n // 工具调用响应模型\n public class ToolCallResponse\n {\n public string Content { get; set; }\n public List<ToolCall> ToolCalls { get; set; }\n public List<ToolCallInfo> ToolCallInfos { get; set; }\n public bool HasToolCalls { get; set; }\n public bool Success { get; set; }\n }\n\n public class ToolCallInfo\n {\n public string Id { get; set; }\n public string FunctionName { get; set; }\n public string Arguments { get; set; }\n }\n}"}, "9ba98cb9c72c380d85bcd66580947b9be8b33bda": {"t": 1785760661.3131373, "n": 26344, "h": "a974d0f8bf165b8d", "c": "// ToolApiService.cs - 专门处理工具调用\nusing DeepSeekChat.Models;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Serialization;\nusing System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\nusing static DeepSeekChat.Services.ToolApiService;\n\nnamespace DeepSeekChat.Services\n{\n public class ToolApiService : IToolApiService\n {\n public enum ToolApiType\n {\n FileRead,\n FileCreate,\n FileSystem,\n TaskManager,\n Compile,\n UserNeedsAnalysis\n }\n private readonly HttpClient _httpClient;\n private const string ApiUrl = \"https://api.deepseek.com/chat/completions\";\n\n public ToolApiService(string apiKey)\n {\n _httpClient = new HttpClient();\n _httpClient.DefaultRequestHeaders.Add(\"Authorization\", $\"Bearer {apiKey}\");\n _httpClient.DefaultRequestHeaders.Add(\"Accept\", \"application/json\");\n }\n\n public async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, ToolApiType toolApiType)\n {\n List<Object> tools = new List<Object>();\n switch(toolApiType)\n {\n case ToolApiType.FileRead:\n tools = GetFileReadTools();\n break;\n case ToolApiType.FileCreate:\n tools = GetFileCreateTools();\n break;\n case ToolApiType.TaskManager:\n tools = GetTaskCreationTools();\n break;\n case ToolApiType.Compile:\n tools = GetCompileTools();\n break;\n case ToolApiType.UserNeedsAnalysis:\n tools = GetHandleUserNeedsTools();\n break;\n default:\n break;\n }\n var requestData = new ChatRequest\n {\n Messages = conversationHistory,\n MaxTokens = 5000,\n Temperature = 0.3,\n Tools = tools,\n ToolChoice = \"auto\"\n };\n\n var settings = new JsonSerializerSettings\n {\n ContractResolver = new DefaultContractResolver\n {\n NamingStrategy = new SnakeCaseNamingStrategy()\n },\n NullValueHandling = NullValueHandling.Ignore\n };\n\n var jsonContent = JsonConvert.SerializeObject(requestData, settings);\n var content = new StringContent(jsonContent, Encoding.UTF8, \"application/json\");\n\n try\n {\n var response = await _httpClient.PostAsync(ApiUrl, content);\n response.EnsureSuccessStatusCode();\n\n var responseJson = await response.Content.ReadAsStringAsync();\n var apiResponse = JsonConvert.DeserializeObject<ApiResponse>(responseJson);\n\n var result = new ToolCallResponse();\n\n if (apiResponse?.Choices?.Count > 0)\n {\n var message = apiResponse.Choices[0].Message;\n\n result.Content = message.Content ?? string.Empty;\n result.ToolCalls = message.ToolCalls;\n result.HasToolCalls = message.ToolCalls != null && message.ToolCalls.Count > 0;\n result.Success = true;\n\n if (result.HasToolCalls)\n {\n // 提取工具调用信息\n result.ToolCallInfos = ExtractToolCallInfos(message.ToolCalls);\n }\n }\n else\n {\n result.Content = \"没有生成有效的回复。\";\n result.Success = false;\n }\n\n return result;\n }\n catch (HttpRequestException ex)\n {\n return new ToolCallResponse\n {\n Content = $\"工具调用请求失败: {ex.Message}\",\n Success = false\n };\n }\n }\n\n private List<ToolCallInfo> ExtractToolCallInfos(List<ToolCall> toolCalls)\n {\n var infos = new List<ToolCallInfo>();\n\n foreach (var toolCall in toolCalls)\n {\n var info = new ToolCallInfo\n {\n Id = toolCall.Id,\n FunctionName = toolCall.Function?.Name,\n Arguments = toolCall.Function?.Arguments\n };\n infos.Add(info);\n }\n\n return infos;\n }\n\n private List<object> GetFileSystemTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"browse_local_folder\",\n description = \"浏览本地文件夹,获取文件列表\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n folder_path = new\n {\n type = \"string\",\n description = \"要浏览的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\n },\n include_subdirectories = new\n {\n type = \"boolean\",\n description = \"是否包含子目录,默认为false\"\n },\n filter_extensions = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"要过滤的文件扩展名列表,如:[.txt, .pdf, .jpg]\"\n }\n },\n required = new[] { \"folder_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"get_folder_info\",\n description = \"获取文件夹详细信息,包括文件数量、大小统计、常见文件类型等\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n folder_path = new\n {\n type = \"string\",\n description = \"要获取信息的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\n }\n },\n required = new[] { \"folder_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"create_file\",\n description = \"创建新文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"文件内容,默认为空字符串\"\n },\n overwrite = new\n {\n type = \"boolean\",\n description = \"是否覆盖已存在的文件,默认为false\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"delete_file\",\n description = \"删除文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要删除的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_delete.txt\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"read_file\",\n description = \"读取文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n max_size_bytes = new\n {\n type = \"integer\",\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"write_file\",\n description = \"写入文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要写入的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_write.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"要写入的文件内容\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n append = new\n {\n type = \"boolean\",\n description = \"是否以追加模式写入,true=在文件末尾追加内容,false=覆盖整个文件,默认为false\"\n }\n },\n required = new[] { \"file_path\", \"content\" }\n }\n }\n }\n };\n }\n\n private List<object> GetFileCreateTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"create_file\",\n description = \"创建新文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"文件内容,默认为空字符串\"\n },\n overwrite = new\n {\n type = \"boolean\",\n description = \"是否覆盖已存在的文件,默认为false\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n }\n };\n }\n\n private List<object> GetFileReadTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"read_file\",\n description = \"读取文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n max_size_bytes = new\n {\n type = \"integer\",\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n }\n };\n }\n\n private List<object> GetCompileTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"compile_csharp\",\n description = \"编译C#代码并可选地执行程序。支持生成可执行文件或在内存中直接执行代码。\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n code = new\n {\n type = \"string\",\n description = \"要编译的C#源代码。必须是完整的程序,包含Main方法或入口点。\"\n },\n outputPath = new\n {\n type = \"string\",\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译。示例:C:\\\\Output\\\\Program.dll\"\n },\n execute = new\n {\n type = \"boolean\",\n description = \"是否在编译后立即执行程序。如果为true,将在内存中执行并返回执行结果。默认为false。\"\n },\n includeReferences = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"额外的程序集引用路径列表。示例:[\\\"Newtonsoft.Json.dll\\\", \\\"System.Data.dll\\\"]\"\n },\n targetFramework = new\n {\n type = \"string\",\n description = \"目标框架版本。支持:net8.0。默认为当前运行时版本。\"\n }\n },\n required = new[] { \"code\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"compile_and_execute\",\n description = \"编译C#代码并立即执行,返回执行结果。适用于快速测试代码片段。\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n code = new\n {\n type = \"string\",\n description = \"要编译执行的C#源代码。必须包含Main方法。示例:'using System; class Program { static void Main() { Console.WriteLine(\\\"Hello\\\"); } }'\"\n },\n output_path = new\n {\n type = \"string\",\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译和执行。示例:C:\\\\Temp\\\\MyProgram.dll\"\n },\n arguments = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"传递给Main方法的命令行参数。示例:[\\\"arg1\\\", \\\"arg2\\\"]\"\n }\n },\n required = new[] { \"code\" }\n }\n }\n }\n };\n }\n\n\n public List<object> GetTaskCreationTools()\n {\n // 构建 TaskDefinition 的 JSON Schema 属性\n var taskDefinitionProperties = new Dictionary<string, object>\n {\n [\"task_id\"] = new\n {\n type = \"string\",\n description = \"任务ID,建议使用GUID\"\n },\n [\"project_name\"] = new\n {\n type = \"string\",\n description = \"工程文件名\"\n },\n [\"file_name\"] = new\n {\n type = \"string\",\n description = \"文件名\"\n },\n [\"file_path\"] = new\n {\n type = \"string\",\n description = \"文件路径\"\n },\n [\"function\"] = new\n {\n type = \"string\",\n description = \"文件功能描述\"\n },\n [\"dependencies\"] = new\n {\n type = \"array\",\n description = \"依赖的文件名列表\",\n items = new { type = \"string\" }\n },\n [\"requirements\"] = new\n {\n type = \"string\",\n description = \"创建该文件的具体要求\"\n },\n [\"estimated_complexity\"] = new\n {\n type = \"string\",\n description = \"估计复杂度\",\n @enum = new[] { \"low\", \"medium\", \"high\" }\n },\n [\"technology_requirements\"] = new\n {\n type = \"array\",\n description = \"技术需求列表\",\n items = new { type = \"string\" }\n },\n [\"testing_requirements\"] = new\n {\n type = \"string\",\n description = \"测试要求\"\n },\n [\"status\"] = new\n {\n type = \"string\",\n description = \"任务状态\",\n @default = \"pending\"\n },\n [\"assigned_to\"] = new\n {\n type = \"string\",\n description = \"分配给谁\",\n @default = \"CodingAgent\"\n }\n };\n\n // 任务定义所需的必填字段\n var requiredTaskProperties = new[] {\n \"task_id\",\"project_name\", \"file_name\", \"file_path\", \"function\", \"requirements\"\n };\n\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"distribute_coding_tasks\",\n description = \"将文件创建和编码任务分配给CodingAgent,输入为任务列表\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n tasks = new\n {\n type = \"array\",\n description = \"任务定义列表,符合TaskDefinition格式\",\n items = new\n {\n type = \"object\",\n properties = taskDefinitionProperties,\n required = requiredTaskProperties\n }\n },\n distribution_strategy = new\n {\n type = \"string\",\n description = \"分配策略\",\n @enum = new[] {\n \"sequential_by_dependency\",\n \"parallel_when_possible\",\n \"complexity_based\",\n \"priority_based\"\n },\n @default = \"sequential_by_dependency\"\n },\n execution_order = new\n {\n type = \"boolean\",\n description = \"是否返回任务执行顺序建议\",\n @default = true\n },\n batch_size = new\n {\n type = \"integer\",\n description = \"批次大小,一次分配多少个任务给CodingAgent\",\n @default = 1,\n minimum = 1,\n maximum = 10\n }\n },\n required = new[] { \"tasks\" }\n }\n }\n }\n };\n }\n\n public List<object> GetHandleUserNeedsTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"send_to_agent\",\n description = \"路由用户请求:需求分析 -> RequirementAnalysisAgent,代码审查 -> ReviewAgent,其他 -> 返回User并说明原因\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n agent_name = new\n {\n type = \"string\",\n description = \"目标接收方:'RequirementAnalysisAgent'、'ReviewAgent'或'User'\",\n @enum = new[] {\n \"RequirementAnalysisAgent\",\n \"ReviewAgent\",\n \"User\"\n }\n },\n to_agent_content = new\n {\n type = \"string\",\n description = \"发送给接收方的消息内容\"\n }\n },\n required = new[] { \"agent_name\", \"to_agent_content\" }\n }\n }\n }\n };\n }\n\n public void Dispose()\n {\n _httpClient?.Dispose();\n }\n }\n\n public interface IToolApiService : IDisposable\n {\n Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, ToolApiType toolApiType);\n }\n\n // 工具调用响应模型\n public class ToolCallResponse\n {\n public string Content { get; set; }\n public List<ToolCall> ToolCalls { get; set; }\n public List<ToolCallInfo> ToolCallInfos { get; set; }\n public bool HasToolCalls { get; set; }\n public bool Success { get; set; }\n }\n\n public class ToolCallInfo\n {\n public string Id { get; set; }\n public string FunctionName { get; set; }\n public string Arguments { get; set; }\n }\n}"}, "b22720737b876cc8ec2cab71396420391840c56b": {"t": 1785760663.1681724, "n": 24865, "h": "f0265e9fac3a74b1", "c": "// ToolApiService.cs - 专门处理工具调用\nusing DeepSeekChat.Models;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Serialization;\nusing System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\nusing static DeepSeekChat.Services.ToolApiService;\n\nnamespace DeepSeekChat.Services\n{\n public class ToolApiService : IToolApiService\n {\n public enum ToolApiType\n {\n FileRead,\n FileCreate,\n FileSystem,\n TaskManager,\n Compile\n }\n private readonly HttpClient _httpClient;\n private const string ApiUrl = \"https://api.deepseek.com/chat/completions\";\n\n public ToolApiService(string apiKey)\n {\n _httpClient = new HttpClient();\n _httpClient.DefaultRequestHeaders.Add(\"Authorization\", $\"Bearer {apiKey}\");\n _httpClient.DefaultRequestHeaders.Add(\"Accept\", \"application/json\");\n }\n\n public async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, ToolApiType toolApiType)\n {\n List<Object> tools = new List<Object>();\n switch(toolApiType)\n {\n case ToolApiType.FileRead:\n tools = GetFileReadTools();\n break;\n case ToolApiType.FileCreate:\n tools = GetFileCreateTools();\n break;\n case ToolApiType.TaskManager:\n tools = GetTaskCreationTools();\n break;\n case ToolApiType.Compile:\n tools = GetCompileTools();\n break;\n default:\n break;\n }\n var requestData = new ChatRequest\n {\n Messages = conversationHistory,\n MaxTokens = 5000,\n Temperature = 0.3,\n Tools = tools,\n ToolChoice = \"auto\"\n };\n\n var settings = new JsonSerializerSettings\n {\n ContractResolver = new DefaultContractResolver\n {\n NamingStrategy = new SnakeCaseNamingStrategy()\n },\n NullValueHandling = NullValueHandling.Ignore\n };\n\n var jsonContent = JsonConvert.SerializeObject(requestData, settings);\n var content = new StringContent(jsonContent, Encoding.UTF8, \"application/json\");\n\n try\n {\n var response = await _httpClient.PostAsync(ApiUrl, content);\n response.EnsureSuccessStatusCode();\n\n var responseJson = await response.Content.ReadAsStringAsync();\n var apiResponse = JsonConvert.DeserializeObject<ApiResponse>(responseJson);\n\n var result = new ToolCallResponse();\n\n if (apiResponse?.Choices?.Count > 0)\n {\n var message = apiResponse.Choices[0].Message;\n\n result.Content = message.Content ?? string.Empty;\n result.ToolCalls = message.ToolCalls;\n result.HasToolCalls = message.ToolCalls != null && message.ToolCalls.Count > 0;\n result.Success = true;\n\n if (result.HasToolCalls)\n {\n // 提取工具调用信息\n result.ToolCallInfos = ExtractToolCallInfos(message.ToolCalls);\n }\n }\n else\n {\n result.Content = \"没有生成有效的回复。\";\n result.Success = false;\n }\n\n return result;\n }\n catch (HttpRequestException ex)\n {\n return new ToolCallResponse\n {\n Content = $\"工具调用请求失败: {ex.Message}\",\n Success = false\n };\n }\n }\n\n private List<ToolCallInfo> ExtractToolCallInfos(List<ToolCall> toolCalls)\n {\n var infos = new List<ToolCallInfo>();\n\n foreach (var toolCall in toolCalls)\n {\n var info = new ToolCallInfo\n {\n Id = toolCall.Id,\n FunctionName = toolCall.Function?.Name,\n Arguments = toolCall.Function?.Arguments\n };\n infos.Add(info);\n }\n\n return infos;\n }\n\n private List<object> GetFileSystemTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"browse_local_folder\",\n description = \"浏览本地文件夹,获取文件列表\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n folder_path = new\n {\n type = \"string\",\n description = \"要浏览的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\n },\n include_subdirectories = new\n {\n type = \"boolean\",\n description = \"是否包含子目录,默认为false\"\n },\n filter_extensions = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"要过滤的文件扩展名列表,如:[.txt, .pdf, .jpg]\"\n }\n },\n required = new[] { \"folder_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"get_folder_info\",\n description = \"获取文件夹详细信息,包括文件数量、大小统计、常见文件类型等\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n folder_path = new\n {\n type = \"string\",\n description = \"要获取信息的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\n }\n },\n required = new[] { \"folder_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"create_file\",\n description = \"创建新文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"文件内容,默认为空字符串\"\n },\n overwrite = new\n {\n type = \"boolean\",\n description = \"是否覆盖已存在的文件,默认为false\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"delete_file\",\n description = \"删除文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要删除的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_delete.txt\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"read_file\",\n description = \"读取文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n max_size_bytes = new\n {\n type = \"integer\",\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"write_file\",\n description = \"写入文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要写入的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_write.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"要写入的文件内容\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n append = new\n {\n type = \"boolean\",\n description = \"是否以追加模式写入,true=在文件末尾追加内容,false=覆盖整个文件,默认为false\"\n }\n },\n required = new[] { \"file_path\", \"content\" }\n }\n }\n }\n };\n }\n\n private List<object> GetFileCreateTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"create_file\",\n description = \"创建新文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"文件内容,默认为空字符串\"\n },\n overwrite = new\n {\n type = \"boolean\",\n description = \"是否覆盖已存在的文件,默认为false\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n }\n };\n }\n\n private List<object> GetFileReadTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"read_file\",\n description = \"读取文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n max_size_bytes = new\n {\n type = \"integer\",\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n }\n };\n }\n\n private List<object> GetCompileTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"compile_csharp\",\n description = \"编译C#代码并可选地执行程序。支持生成可执行文件或在内存中直接执行代码。\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n code = new\n {\n type = \"string\",\n description = \"要编译的C#源代码。必须是完整的程序,包含Main方法或入口点。\"\n },\n outputPath = new\n {\n type = \"string\",\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译。示例:C:\\\\Output\\\\Program.dll\"\n },\n execute = new\n {\n type = \"boolean\",\n description = \"是否在编译后立即执行程序。如果为true,将在内存中执行并返回执行结果。默认为false。\"\n },\n includeReferences = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"额外的程序集引用路径列表。示例:[\\\"Newtonsoft.Json.dll\\\", \\\"System.Data.dll\\\"]\"\n },\n targetFramework = new\n {\n type = \"string\",\n description = \"目标框架版本。支持:net8.0。默认为当前运行时版本。\"\n }\n },\n required = new[] { \"code\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"compile_and_execute\",\n description = \"编译C#代码并立即执行,返回执行结果。适用于快速测试代码片段。\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n code = new\n {\n type = \"string\",\n description = \"要编译执行的C#源代码。必须包含Main方法。示例:'using System; class Program { static void Main() { Console.WriteLine(\\\"Hello\\\"); } }'\"\n },\n output_path = new\n {\n type = \"string\",\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译和执行。示例:C:\\\\Temp\\\\MyProgram.dll\"\n },\n arguments = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"传递给Main方法的命令行参数。示例:[\\\"arg1\\\", \\\"arg2\\\"]\"\n }\n },\n required = new[] { \"code\" }\n }\n }\n }\n };\n }\n\n\n public List<object> GetTaskCreationTools()\n {\n // 构建 TaskDefinition 的 JSON Schema 属性\n var taskDefinitionProperties = new Dictionary<string, object>\n {\n [\"task_id\"] = new\n {\n type = \"string\",\n description = \"任务ID,建议使用GUID\"\n },\n [\"project_name\"] = new\n {\n type = \"string\",\n description = \"工程文件名\"\n },\n [\"file_name\"] = new\n {\n type = \"string\",\n description = \"文件名\"\n },\n [\"file_path\"] = new\n {\n type = \"string\",\n description = \"文件路径\"\n },\n [\"function\"] = new\n {\n type = \"string\",\n description = \"文件功能描述\"\n },\n [\"dependencies\"] = new\n {\n type = \"array\",\n description = \"依赖的文件名列表\",\n items = new { type = \"string\" }\n },\n [\"requirements\"] = new\n {\n type = \"string\",\n description = \"创建该文件的具体要求\"\n },\n [\"estimated_complexity\"] = new\n {\n type = \"string\",\n description = \"估计复杂度\",\n @enum = new[] { \"low\", \"medium\", \"high\" }\n },\n [\"technology_requirements\"] = new\n {\n type = \"array\",\n description = \"技术需求列表\",\n items = new { type = \"string\" }\n },\n [\"testing_requirements\"] = new\n {\n type = \"string\",\n description = \"测试要求\"\n },\n [\"status\"] = new\n {\n type = \"string\",\n description = \"任务状态\",\n @default = \"pending\"\n },\n [\"assigned_to\"] = new\n {\n type = \"string\",\n description = \"分配给谁\",\n @default = \"CodingAgent\"\n }\n };\n\n // 任务定义所需的必填字段\n var requiredTaskProperties = new[] {\n \"task_id\",\"project_name\", \"file_name\", \"file_path\", \"function\", \"requirements\"\n };\n\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"distribute_coding_tasks\",\n description = \"将文件创建和编码任务分配给CodingAgent,输入为任务列表\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n tasks = new\n {\n type = \"array\",\n description = \"任务定义列表,符合TaskDefinition格式\",\n items = new\n {\n type = \"object\",\n properties = taskDefinitionProperties,\n required = requiredTaskProperties\n }\n },\n distribution_strategy = new\n {\n type = \"string\",\n description = \"分配策略\",\n @enum = new[] {\n \"sequential_by_dependency\",\n \"parallel_when_possible\",\n \"complexity_based\",\n \"priority_based\"\n },\n @default = \"sequential_by_dependency\"\n },\n execution_order = new\n {\n type = \"boolean\",\n description = \"是否返回任务执行顺序建议\",\n @default = true\n },\n batch_size = new\n {\n type = \"integer\",\n description = \"批次大小,一次分配多少个任务给CodingAgent\",\n @default = 1,\n minimum = 1,\n maximum = 10\n }\n },\n required = new[] { \"tasks\" }\n }\n }\n }\n };\n }\n public void Dispose()\n {\n _httpClient?.Dispose();\n }\n }\n\n public interface IToolApiService : IDisposable\n {\n Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, ToolApiType toolApiType);\n }\n\n // 工具调用响应模型\n public class ToolCallResponse\n {\n public string Content { get; set; }\n public List<ToolCall> ToolCalls { get; set; }\n public List<ToolCallInfo> ToolCallInfos { get; set; }\n public bool HasToolCalls { get; set; }\n public bool Success { get; set; }\n }\n\n public class ToolCallInfo\n {\n public string Id { get; set; }\n public string FunctionName { get; set; }\n public string Arguments { get; set; }\n }\n}"}, "37466c9f24e16ff187981cbd9db9f846c2ca02d4": {"t": 1785760664.7319808, "n": 24865, "h": "00529c6f2978cc15", "c": "// ToolApiService.cs - 专门处理工具调用\nusing DeepSeekChat.Models;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Serialization;\nusing System;\nusing System.Collections.Generic;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\nusing static DeepSeekChat.Services.ToolApiService;\n\nnamespace DeepSeekChat.Services\n{\n public class ToolApiService : IToolApiService\n {\n public enum ToolApiType\n {\n FileRead,\n FileCreate,\n FileSystem,\n TaskManager,\n Compile\n }\n private readonly HttpClient _httpClient;\n private const string ApiUrl = \"https://api.deepseek.com/chat/completions\";\n\n public ToolApiService(string apiKey)\n {\n _httpClient = new HttpClient();\n _httpClient.DefaultRequestHeaders.Add(\"Authorization\", $\"Bearer {apiKey}\");\n _httpClient.DefaultRequestHeaders.Add(\"Accept\", \"application/json\");\n }\n\n public async Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, ToolApiType toolApiType)\n {\n List<Object> tools = new List<Object>();\n switch(toolApiType)\n {\n case ToolApiType.FileRead:\n tools = GetFileReadTools();\n break;\n case ToolApiType.FileCreate:\n tools = GetFileCreateTools();\n break;\n case ToolApiType.TaskManager:\n tools = GetTaskCreationTools();\n break;\n case ToolApiType.Compile:\n tools = GetCompileTools();\n break;\n default:\n break;\n }\n var requestData = new ChatRequest\n {\n Messages = conversationHistory,\n MaxTokens = 5000,\n Temperature = 0.7,\n Tools = tools,\n ToolChoice = \"auto\"\n };\n\n var settings = new JsonSerializerSettings\n {\n ContractResolver = new DefaultContractResolver\n {\n NamingStrategy = new SnakeCaseNamingStrategy()\n },\n NullValueHandling = NullValueHandling.Ignore\n };\n\n var jsonContent = JsonConvert.SerializeObject(requestData, settings);\n var content = new StringContent(jsonContent, Encoding.UTF8, \"application/json\");\n\n try\n {\n var response = await _httpClient.PostAsync(ApiUrl, content);\n response.EnsureSuccessStatusCode();\n\n var responseJson = await response.Content.ReadAsStringAsync();\n var apiResponse = JsonConvert.DeserializeObject<ApiResponse>(responseJson);\n\n var result = new ToolCallResponse();\n\n if (apiResponse?.Choices?.Count > 0)\n {\n var message = apiResponse.Choices[0].Message;\n\n result.Content = message.Content ?? string.Empty;\n result.ToolCalls = message.ToolCalls;\n result.HasToolCalls = message.ToolCalls != null && message.ToolCalls.Count > 0;\n result.Success = true;\n\n if (result.HasToolCalls)\n {\n // 提取工具调用信息\n result.ToolCallInfos = ExtractToolCallInfos(message.ToolCalls);\n }\n }\n else\n {\n result.Content = \"没有生成有效的回复。\";\n result.Success = false;\n }\n\n return result;\n }\n catch (HttpRequestException ex)\n {\n return new ToolCallResponse\n {\n Content = $\"工具调用请求失败: {ex.Message}\",\n Success = false\n };\n }\n }\n\n private List<ToolCallInfo> ExtractToolCallInfos(List<ToolCall> toolCalls)\n {\n var infos = new List<ToolCallInfo>();\n\n foreach (var toolCall in toolCalls)\n {\n var info = new ToolCallInfo\n {\n Id = toolCall.Id,\n FunctionName = toolCall.Function?.Name,\n Arguments = toolCall.Function?.Arguments\n };\n infos.Add(info);\n }\n\n return infos;\n }\n\n private List<object> GetFileSystemTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"browse_local_folder\",\n description = \"浏览本地文件夹,获取文件列表\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n folder_path = new\n {\n type = \"string\",\n description = \"要浏览的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\n },\n include_subdirectories = new\n {\n type = \"boolean\",\n description = \"是否包含子目录,默认为false\"\n },\n filter_extensions = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"要过滤的文件扩展名列表,如:[.txt, .pdf, .jpg]\"\n }\n },\n required = new[] { \"folder_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"get_folder_info\",\n description = \"获取文件夹详细信息,包括文件数量、大小统计、常见文件类型等\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n folder_path = new\n {\n type = \"string\",\n description = \"要获取信息的文件夹完整路径,如:C:\\\\Users\\\\Username\\\\Documents\"\n }\n },\n required = new[] { \"folder_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"create_file\",\n description = \"创建新文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"文件内容,默认为空字符串\"\n },\n overwrite = new\n {\n type = \"boolean\",\n description = \"是否覆盖已存在的文件,默认为false\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"delete_file\",\n description = \"删除文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要删除的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_delete.txt\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"read_file\",\n description = \"读取文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n max_size_bytes = new\n {\n type = \"integer\",\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"write_file\",\n description = \"写入文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要写入的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_write.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"要写入的文件内容\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n append = new\n {\n type = \"boolean\",\n description = \"是否以追加模式写入,true=在文件末尾追加内容,false=覆盖整个文件,默认为false\"\n }\n },\n required = new[] { \"file_path\", \"content\" }\n }\n }\n }\n };\n }\n\n private List<object> GetFileCreateTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"create_file\",\n description = \"创建新文件\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要创建的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\new_file.txt\"\n },\n content = new\n {\n type = \"string\",\n description = \"文件内容,默认为空字符串\"\n },\n overwrite = new\n {\n type = \"boolean\",\n description = \"是否覆盖已存在的文件,默认为false\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n }\n };\n }\n\n private List<object> GetFileReadTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"read_file\",\n description = \"读取文件内容\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n file_path = new\n {\n type = \"string\",\n description = \"要读取的文件完整路径,如:C:\\\\Users\\\\Username\\\\Documents\\\\file_to_read.txt\"\n },\n encoding = new\n {\n type = \"string\",\n description = \"文件编码格式,支持:UTF-8、ASCII、Unicode、UTF-32、UTF-7、BigEndianUnicode、Default,默认为UTF-8\"\n },\n max_size_bytes = new\n {\n type = \"integer\",\n description = \"最大读取文件大小(字节),超过此大小的文件将不会被读取,默认为10MB (10485760字节)\"\n }\n },\n required = new[] { \"file_path\" }\n }\n }\n }\n };\n }\n\n private List<object> GetCompileTools()\n {\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"compile_csharp\",\n description = \"编译C#代码并可选地执行程序。支持生成可执行文件或在内存中直接执行代码。\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n code = new\n {\n type = \"string\",\n description = \"要编译的C#源代码。必须是完整的程序,包含Main方法或入口点。\"\n },\n outputPath = new\n {\n type = \"string\",\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译。示例:C:\\\\Output\\\\Program.dll\"\n },\n execute = new\n {\n type = \"boolean\",\n description = \"是否在编译后立即执行程序。如果为true,将在内存中执行并返回执行结果。默认为false。\"\n },\n includeReferences = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"额外的程序集引用路径列表。示例:[\\\"Newtonsoft.Json.dll\\\", \\\"System.Data.dll\\\"]\"\n },\n targetFramework = new\n {\n type = \"string\",\n description = \"目标框架版本。支持:net8.0。默认为当前运行时版本。\"\n }\n },\n required = new[] { \"code\" }\n }\n }\n },\n new\n {\n type = \"function\",\n function = new\n {\n name = \"compile_and_execute\",\n description = \"编译C#代码并立即执行,返回执行结果。适用于快速测试代码片段。\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n code = new\n {\n type = \"string\",\n description = \"要编译执行的C#源代码。必须包含Main方法。示例:'using System; class Program { static void Main() { Console.WriteLine(\\\"Hello\\\"); } }'\"\n },\n output_path = new\n {\n type = \"string\",\n description = \"编译输出的程序集文件路径。如果不指定,则仅在内存中编译和执行。示例:C:\\\\Temp\\\\MyProgram.dll\"\n },\n arguments = new\n {\n type = \"array\",\n items = new { type = \"string\" },\n description = \"传递给Main方法的命令行参数。示例:[\\\"arg1\\\", \\\"arg2\\\"]\"\n }\n },\n required = new[] { \"code\" }\n }\n }\n }\n };\n }\n\n\n public List<object> GetTaskCreationTools()\n {\n // 构建 TaskDefinition 的 JSON Schema 属性\n var taskDefinitionProperties = new Dictionary<string, object>\n {\n [\"task_id\"] = new\n {\n type = \"string\",\n description = \"任务ID,建议使用GUID\"\n },\n [\"project_name\"] = new\n {\n type = \"string\",\n description = \"工程文件名\"\n },\n [\"file_name\"] = new\n {\n type = \"string\",\n description = \"文件名\"\n },\n [\"file_path\"] = new\n {\n type = \"string\",\n description = \"文件路径\"\n },\n [\"function\"] = new\n {\n type = \"string\",\n description = \"文件功能描述\"\n },\n [\"dependencies\"] = new\n {\n type = \"array\",\n description = \"依赖的文件名列表\",\n items = new { type = \"string\" }\n },\n [\"requirements\"] = new\n {\n type = \"string\",\n description = \"创建该文件的具体要求\"\n },\n [\"estimated_complexity\"] = new\n {\n type = \"string\",\n description = \"估计复杂度\",\n @enum = new[] { \"low\", \"medium\", \"high\" }\n },\n [\"technology_requirements\"] = new\n {\n type = \"array\",\n description = \"技术需求列表\",\n items = new { type = \"string\" }\n },\n [\"testing_requirements\"] = new\n {\n type = \"string\",\n description = \"测试要求\"\n },\n [\"status\"] = new\n {\n type = \"string\",\n description = \"任务状态\",\n @default = \"pending\"\n },\n [\"assigned_to\"] = new\n {\n type = \"string\",\n description = \"分配给谁\",\n @default = \"CodingAgent\"\n }\n };\n\n // 任务定义所需的必填字段\n var requiredTaskProperties = new[] {\n \"task_id\",\"project_name\", \"file_name\", \"file_path\", \"function\", \"requirements\"\n };\n\n return new List<object>\n {\n new\n {\n type = \"function\",\n function = new\n {\n name = \"distribute_coding_tasks\",\n description = \"将文件创建和编码任务分配给CodingAgent,输入为任务列表\",\n parameters = new\n {\n type = \"object\",\n properties = new\n {\n tasks = new\n {\n type = \"array\",\n description = \"任务定义列表,符合TaskDefinition格式\",\n items = new\n {\n type = \"object\",\n properties = taskDefinitionProperties,\n required = requiredTaskProperties\n }\n },\n distribution_strategy = new\n {\n type = \"string\",\n description = \"分配策略\",\n @enum = new[] {\n \"sequential_by_dependency\",\n \"parallel_when_possible\",\n \"complexity_based\",\n \"priority_based\"\n },\n @default = \"sequential_by_dependency\"\n },\n execution_order = new\n {\n type = \"boolean\",\n description = \"是否返回任务执行顺序建议\",\n @default = true\n },\n batch_size = new\n {\n type = \"integer\",\n description = \"批次大小,一次分配多少个任务给CodingAgent\",\n @default = 1,\n minimum = 1,\n maximum = 10\n }\n },\n required = new[] { \"tasks\" }\n }\n }\n }\n };\n }\n public void Dispose()\n {\n _httpClient?.Dispose();\n }\n }\n\n public interface IToolApiService : IDisposable\n {\n Task<ToolCallResponse> SendToolRequestAsync(List<ChatMessage> conversationHistory, ToolApiType toolApiType);\n }\n\n // 工具调用响应模型\n public class ToolCallResponse\n {\n public string Content { get; set; }\n public List<ToolCall> ToolCalls { get; set; }\n public List<ToolCallInfo> ToolCallInfos { get; set; }\n public bool HasToolCalls { get; set; }\n public bool Success { get; set; }\n }\n\n public class ToolCallInfo\n {\n public string Id { get; set; }\n public string FunctionName { get; set; }\n public string Arguments { get; set; }\n }\n}"}}}}