에이전트 선택적 탐색 구조 개선과 경고 정리 반영
Some checks failed
Release Gate / gate (push) Has been cancelled

- claude-code 선택적 탐색 흐름을 참고해 Cowork/Code 시스템 프롬프트에서 folder_map 상시 선행 지시를 완화하고 glob/grep 기반 좁은 탐색을 우선하도록 조정함

- FolderMapTool 기본 depth를 2로, include_files 기본값을 false로 낮추고 MultiReadTool 최대 파일 수를 8개로 줄여 초기 과탐색 폭을 보수적으로 조정함

- AgentLoopExplorationPolicy partial을 추가해 탐색 범위 분류, broad-scan corrective hint, exploration_breadth 성능 로그를 연결함

- AgentLoopService에 탐색 범위 가이드 주입과 실행 중 탐색 폭 추적을 추가하고, 좁은 질문에서 반복적인 folder_map/대량 multi_read를 교정하도록 정리함

- DocxToHtmlConverter nullable 경고를 수정해 Release 빌드 경고 0 / 오류 0 기준을 다시 충족함

- README와 docs/DEVELOPMENT.md에 2026-04-09 10:36 (KST) 기준 개발 이력을 반영함
This commit is contained in:
2026-04-09 14:27:59 +09:00
parent 7931566212
commit 33c1db4dae
119 changed files with 4453 additions and 6943 deletions

View File

@@ -56,7 +56,7 @@ public class DataPivotTool : IAgentTool
public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
{
var sourcePath = args.GetProperty("source_path").GetString() ?? "";
var sourcePath = args.GetProperty("source_path").SafeGetString() ?? "";
var fullPath = FileReadTool.ResolvePath(sourcePath, context.WorkFolder);
if (!context.IsPathAllowed(fullPath))
@@ -81,28 +81,28 @@ public class DataPivotTool : IAgentTool
var originalCount = data.Count;
// 필터 적용
if (args.TryGetProperty("filter", out var filterEl))
if (args.SafeTryGetProperty("filter", out var filterEl))
{
var filterStr = filterEl.GetString() ?? "";
var filterStr = filterEl.SafeGetString() ?? "";
if (!string.IsNullOrWhiteSpace(filterStr))
data = ApplyFilter(data, filterStr);
}
// 그룹화 & 집계
List<Dictionary<string, string>> result;
if (args.TryGetProperty("group_by", out var groupEl) && groupEl.ValueKind == JsonValueKind.Array)
if (args.SafeTryGetProperty("group_by", out var groupEl) && groupEl.ValueKind == JsonValueKind.Array)
{
var groupCols = new List<string>();
foreach (var g in groupEl.EnumerateArray())
groupCols.Add(g.GetString() ?? "");
groupCols.Add(g.SafeGetString() ?? "");
var aggregates = new List<(string Column, string Function)>();
if (args.TryGetProperty("aggregates", out var aggEl) && aggEl.ValueKind == JsonValueKind.Array)
if (args.SafeTryGetProperty("aggregates", out var aggEl) && aggEl.ValueKind == JsonValueKind.Array)
{
foreach (var agg in aggEl.EnumerateArray())
{
var col = agg.TryGetProperty("column", out var c) ? c.GetString() ?? "" : "";
var func = agg.TryGetProperty("function", out var f) ? f.GetString() ?? "count" : "count";
var col = agg.SafeTryGetProperty("column", out var c) ? c.SafeGetString() ?? "" : "";
var func = agg.SafeTryGetProperty("function", out var f) ? f.SafeGetString() ?? "count" : "count";
if (!string.IsNullOrEmpty(col))
aggregates.Add((col, func));
}
@@ -116,19 +116,19 @@ public class DataPivotTool : IAgentTool
}
// 정렬
if (args.TryGetProperty("sort_by", out var sortEl))
if (args.SafeTryGetProperty("sort_by", out var sortEl))
{
var sortBy = sortEl.GetString() ?? "";
var sortBy = sortEl.SafeGetString() ?? "";
if (!string.IsNullOrWhiteSpace(sortBy))
result = ApplySort(result, sortBy);
}
// Top N
if (args.TryGetProperty("top_n", out var topEl) && topEl.TryGetInt32(out var topN) && topN > 0)
if (args.SafeTryGetProperty("top_n", out var topEl) && topEl.TryGetInt32(out var topN) && topN > 0)
result = result.Take(topN).ToList();
// 출력 포맷
var outputFormat = args.TryGetProperty("output_format", out var ofmt) ? ofmt.GetString() ?? "table" : "table";
var outputFormat = args.SafeTryGetProperty("output_format", out var ofmt) ? ofmt.SafeGetString() ?? "table" : "table";
var output = FormatOutput(result, outputFormat);
return Task.FromResult(ToolResult.Ok(
@@ -192,7 +192,7 @@ public class DataPivotTool : IAgentTool
var arr = doc.RootElement.ValueKind == JsonValueKind.Array
? doc.RootElement
: doc.RootElement.TryGetProperty("data", out var d) ? d : doc.RootElement;
: doc.RootElement.SafeTryGetProperty("data", out var d) ? d : doc.RootElement;
if (arr.ValueKind != JsonValueKind.Array) return data;