using System.Text.Json; 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 => new() { Properties = new() { ["question"] = new() { Type = "string", Description = "The question to ask the user", }, ["options"] = new() { Type = "array", Description = "Optional list of choices for the user (e.g. ['Option A', 'Option B'])", Items = new() { Type = "string", Description = "Choice option" }, }, ["default_value"] = new() { Type = "string", Description = "Default value if user doesn't specify", }, }, Required = ["question"], }; public async Task ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default) { var question = args.GetProperty("question").GetString() ?? ""; var defaultVal = args.TryGetProperty("default_value", out var dv) ? dv.GetString() ?? "" : ""; var options = new List(); if (args.TryGetProperty("options", out var opts) && opts.ValueKind == JsonValueKind.Array) { foreach (var o in opts.EnumerateArray()) { var s = o.GetString(); if (!string.IsNullOrEmpty(s)) options.Add(s); } } // UserAskCallback 사용 (커스텀 대화 상자) if (context.UserAskCallback != null) { try { var response = await context.UserAskCallback(question, options, defaultVal); if (response == null) return ToolResult.Fail("사용자가 응답을 취소했습니다."); return ToolResult.Ok($"사용자 응답: {response}"); } catch (OperationCanceledException) { return ToolResult.Fail("사용자가 응답을 취소했습니다."); } catch (Exception ex) { return ToolResult.Fail($"사용자 입력 오류: {ex.Message}"); } } // 폴백: UserDecision 콜백 if (context.UserDecision != null) { try { var prompt = question; if (!string.IsNullOrEmpty(defaultVal)) prompt += $"\n(기본값: {defaultVal})"; var effectiveOptions = options.Count > 0 ? options : new List { "확인" }; var response = await context.UserDecision(prompt, effectiveOptions); if (string.IsNullOrEmpty(response) && !string.IsNullOrEmpty(defaultVal)) response = defaultVal; return ToolResult.Ok($"사용자 응답: {response}"); } catch (OperationCanceledException) { return ToolResult.Fail("사용자가 응답을 취소했습니다."); } catch (Exception ex) { return ToolResult.Fail($"사용자 입력 오류: {ex.Message}"); } } return ToolResult.Fail("사용자 입력 콜백이 등록되지 않았습니다."); } }