Files
AX-Copilot-Codex/src/AxCopilot/Services/Agent/UserAskTool.cs

105 lines
3.7 KiB
C#

using System.Text.Json;
namespace AxCopilot.Services.Agent;
/// <summary>에이전트가 사용자에게 질문하고 응답을 대기하는 도구.</summary>
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<ToolResult> 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<string>();
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<string> { "확인" };
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("사용자 입력 콜백이 등록되지 않았습니다.");
}
}