using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace AxCopilot.Services.Agent; public class UserAskTool : IAgentTool { public string Name => "user_ask"; public string Description => "Ask the user a question and wait for their response. Use when you need clarification, confirmation, or a choice from the user. Optionally provide predefined options for the user to pick from. The user can select from options OR type a custom response."; public ToolParameterSchema Parameters { get { ToolParameterSchema obj = new ToolParameterSchema { Properties = new Dictionary { ["question"] = new ToolProperty { Type = "string", Description = "The question to ask the user" }, ["options"] = new ToolProperty { Type = "array", Description = "Optional list of choices for the user (e.g. ['Option A', 'Option B'])", Items = new ToolProperty { Type = "string", Description = "Choice option" } }, ["default_value"] = new ToolProperty { Type = "string", Description = "Default value if user doesn't specify" } } }; int num = 1; List list = new List(num); CollectionsMarshal.SetCount(list, num); CollectionsMarshal.AsSpan(list)[0] = "question"; obj.Required = list; return obj; } } public async Task ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken)) { string question = args.GetProperty("question").GetString() ?? ""; JsonElement dv; string defaultVal = (args.TryGetProperty("default_value", out dv) ? (dv.GetString() ?? "") : ""); List options = new List(); if (args.TryGetProperty("options", out var opts) && opts.ValueKind == JsonValueKind.Array) { foreach (JsonElement item in opts.EnumerateArray()) { string s = item.GetString(); if (!string.IsNullOrEmpty(s)) { options.Add(s); } } } if (context.UserAskCallback != null) { try { string response = await context.UserAskCallback(question, options, defaultVal); if (response == null) { return ToolResult.Fail("사용자가 응답을 취소했습니다."); } return ToolResult.Ok("사용자 응답: " + response); } catch (OperationCanceledException) { return ToolResult.Fail("사용자가 응답을 취소했습니다."); } catch (Exception ex2) { return ToolResult.Fail("사용자 입력 오류: " + ex2.Message); } } if (context.UserDecision != null) { try { string prompt = question; if (!string.IsNullOrEmpty(defaultVal)) { prompt = prompt + "\n(기본값: " + defaultVal + ")"; } List effectiveOptions = ((options.Count > 0) ? options : new List { "확인" }); string response2 = await context.UserDecision(prompt, effectiveOptions); if (string.IsNullOrEmpty(response2) && !string.IsNullOrEmpty(defaultVal)) { response2 = defaultVal; } return ToolResult.Ok("사용자 응답: " + response2); } catch (OperationCanceledException) { return ToolResult.Fail("사용자가 응답을 취소했습니다."); } catch (Exception ex4) { return ToolResult.Fail("사용자 입력 오류: " + ex4.Message); } } return ToolResult.Fail("사용자 입력 콜백이 등록되지 않았습니다."); } }