AX Agent loop 정책을 분리하고 transcript 가상화·성능 계측 구조를 강화한다
Some checks failed
Release Gate / gate (push) Has been cancelled

- AgentLoop 검증/문서/compact 정책 메서드를 partial 파일로 분리해 loop 본문의 책임을 줄임
- transcript 렌더에 cache pruning과 deferred scrolling을 적용해 긴 세션의 UI 부담을 낮춤
- AgentPerformanceLogService를 추가해 transcript 렌더와 agent loop 실행 요약을 perf 로그로 남김
- README와 DEVELOPMENT 문서에 2026-04-09 10:08 (KST) 기준 구조 개선 및 계측 이력을 반영함
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ 검증 결과 경고 0개 오류 0개
This commit is contained in:
2026-04-09 00:57:38 +09:00
parent 594d38e4a9
commit 0ceca202e9
11 changed files with 682 additions and 494 deletions

View File

@@ -0,0 +1,72 @@
using System.Text;
using System.Text.Json;
using System.IO;
namespace AxCopilot.Services;
public static class AgentPerformanceLogService
{
private static readonly string PerfDir;
private static readonly object _lock = new();
private static readonly JsonSerializerOptions _jsonOptions = new()
{
WriteIndented = false,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
};
static AgentPerformanceLogService()
{
PerfDir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"AxCopilot",
"perf");
try { Directory.CreateDirectory(PerfDir); } catch { }
}
public static void LogMetric(
string area,
string name,
string conversationId,
string tab,
long durationMs,
object? detail = null)
{
try
{
var fileName = $"performance-{DateTime.Now:yyyy-MM-dd}.json";
var filePath = Path.Combine(PerfDir, fileName);
var json = JsonSerializer.Serialize(new AgentPerformanceEntry
{
Timestamp = DateTime.Now,
Area = area,
Name = name,
ConversationId = conversationId ?? "",
Tab = tab ?? "",
DurationMs = durationMs,
Detail = detail == null ? "" : JsonSerializer.Serialize(detail, _jsonOptions),
}, _jsonOptions);
lock (_lock)
{
File.AppendAllText(filePath, json + Environment.NewLine, Encoding.UTF8);
}
}
catch
{
// 성능 로그 실패는 런타임에 영향 주지 않음
}
}
public static string GetPerformanceFolder() => PerfDir;
}
public sealed class AgentPerformanceEntry
{
public DateTime Timestamp { get; init; }
public string Area { get; init; } = "";
public string Name { get; init; } = "";
public string ConversationId { get; init; } = "";
public string Tab { get; init; } = "";
public long DurationMs { get; init; }
public string Detail { get; init; } = "";
}