using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text.Encodings.Web; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace AxCopilot.Services.Agent; public class SuggestActionsTool : IAgentTool { public string Name => "suggest_actions"; public string Description => "Suggest 2-5 follow-up actions after completing a task. Returns structured JSON that the UI renders as clickable action chips. Each action has a label (display text), command (slash command or natural language prompt), optional icon (Segoe MDL2 Assets code), and priority (high/medium/low)."; public ToolParameterSchema Parameters { get { ToolParameterSchema obj = new ToolParameterSchema { Properties = new Dictionary { ["actions"] = new ToolProperty { Type = "array", Description = "List of action objects. Each object: {\"label\": \"표시 텍스트\", \"command\": \"/slash 또는 자연어\", \"icon\": \"\\uE8A5\" (optional), \"priority\": \"high|medium|low\"}", Items = new ToolProperty { Type = "object", Description = "Action object with label, command, icon, priority" } }, ["context"] = new ToolProperty { Type = "string", Description = "Current task context summary (optional)" } } }; int num = 1; List list = new List(num); CollectionsMarshal.SetCount(list, num); CollectionsMarshal.AsSpan(list)[0] = "actions"; obj.Required = list; return obj; } } public Task ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken)) { try { if (!args.TryGetProperty("actions", out var value) || value.ValueKind != JsonValueKind.Array) { return Task.FromResult(ToolResult.Fail("actions 배열이 필요합니다.")); } List> list = new List>(); foreach (JsonElement item in value.EnumerateArray()) { JsonElement value3; string value2 = (item.TryGetProperty("label", out value3) ? (value3.GetString() ?? "") : ""); JsonElement value5; string value4 = (item.TryGetProperty("command", out value5) ? (value5.GetString() ?? "") : ""); JsonElement value7; string value6 = (item.TryGetProperty("icon", out value7) ? (value7.GetString() ?? "") : ""); JsonElement value9; string value8 = (item.TryGetProperty("priority", out value9) ? (value9.GetString() ?? "medium") : "medium"); if (string.IsNullOrWhiteSpace(value2)) { return Task.FromResult(ToolResult.Fail("각 action에는 label이 필요합니다.")); } if (string.IsNullOrWhiteSpace(value4)) { return Task.FromResult(ToolResult.Fail("각 action에는 command가 필요합니다.")); } string[] source = new string[3] { "high", "medium", "low" }; if (!source.Contains(value8)) { value8 = "medium"; } Dictionary dictionary = new Dictionary { ["label"] = value2, ["command"] = value4, ["priority"] = value8 }; if (!string.IsNullOrEmpty(value6)) { dictionary["icon"] = value6; } list.Add(dictionary); } if (list.Count < 1 || list.Count > 5) { return Task.FromResult(ToolResult.Fail("actions는 1~5개 사이여야 합니다.")); } JsonElement value11; string value10 = (args.TryGetProperty("context", out value11) ? (value11.GetString() ?? "") : ""); Dictionary dictionary2 = new Dictionary { ["type"] = "suggest_actions", ["actions"] = list }; if (!string.IsNullOrEmpty(value10)) { dictionary2["context"] = value10; } string output = JsonSerializer.Serialize(dictionary2, new JsonSerializerOptions { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }); return Task.FromResult(ToolResult.Ok(output)); } catch (Exception ex) { return Task.FromResult(ToolResult.Fail("액션 제안 오류: " + ex.Message)); } } }