[Phase 17-B] TaskState Working Memory + 이벤트 로그 완전 통합
AgentLoopService.TaskState.cs (신규, 96줄):
- InitTaskStateAsync(): 세션 시작 시 TaskStateService 초기화, 현재 작업 기록
- TrackToolFile(): 도구 성공 시 파일 경로 참조 목록 추가 (fire-and-forget)
- InjectTaskStateContext(): 압축 전 Working Memory를 시스템 메시지에 in-place 주입
(## 현재 작업 상태 마커로 기존 섹션 탐지·교체 → 중복 방지)
- UpdateTaskStateSummaryAsync(): 압축 완료 후 컨텍스트 요약 갱신 (fire-and-forget)
AgentLoopService.cs:
- userQuery 선언 후 UserMessage 이벤트 기록 + InitTaskStateAsync() 호출
- 압축 블록: InjectTaskStateContext() 호출 (압축 전 Working Memory 주입)
- 기본 압축 완료 시: CompactionCompleted 이벤트 + UpdateTaskStateSummaryAsync()
- 적극적 압축 트리거 시: CompactionTriggered 이벤트 (usagePct 포함)
- LLM 텍스트 응답 후: AssistantMessage 이벤트 기록 (length, hasToolCalls)
AgentLoopService.Execution.cs:
- 도구 성공(state.ConsecutiveErrors = 0) 직후 TrackToolFile(result.FilePath) 호출
이벤트 커버리지: SessionStart/End·UserMessage·AssistantMessage·
ToolRequest·ToolResult·CompactionTriggered·CompactionCompleted 전 구간 기록
저장: %APPDATA%\AxCopilot\sessions\{sessionId}\{task_state.json, events.jsonl}
빌드: 경고 0, 오류 0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -162,6 +162,7 @@ public partial class AgentLoopService
|
||||
_ = _eventLog.AppendAsync(AgentEventLogType.SessionStart,
|
||||
JsonSerializer.Serialize(new { tab = activeTabSnapshot, model = llm.Model ?? "" }));
|
||||
}
|
||||
|
||||
var baseMax = llm.MaxAgentIterations > 0 ? llm.MaxAgentIterations : Defaults.MaxIterations;
|
||||
var maxIterations = baseMax;
|
||||
var maxRetry = llm.MaxRetryOnError > 0 ? llm.MaxRetryOnError : Defaults.MaxRetryOnError;
|
||||
@@ -169,6 +170,12 @@ public partial class AgentLoopService
|
||||
|
||||
// 사용자 원본 요청 캡처 (문서 생성 폴백 판단용)
|
||||
var userQuery = messages.LastOrDefault(m => m.Role == "user")?.Content ?? "";
|
||||
|
||||
// Phase 17-B: UserMessage 이벤트 기록 + TaskState Working Memory 초기화
|
||||
if (!string.IsNullOrWhiteSpace(userQuery))
|
||||
_ = _eventLog?.AppendAsync(AgentEventLogType.UserMessage,
|
||||
JsonSerializer.Serialize(new { length = userQuery.Length }));
|
||||
await InitTaskStateAsync(userQuery, _sessionId);
|
||||
var consecutiveErrors = 0; // Self-Reflection: 연속 오류 카운터
|
||||
var totalToolCalls = 0; // 복잡도 추정용
|
||||
|
||||
@@ -339,10 +346,18 @@ public partial class AgentLoopService
|
||||
// 2단계: 사용량 임계치 초과 시 적극적 압축 (목표 60%)
|
||||
if (llm.MaxContextTokens > 0)
|
||||
{
|
||||
// Phase 17-B: 압축 전 TaskState Working Memory 주입 — 압축 후에도 작업 상태 유지
|
||||
InjectTaskStateContext(messages);
|
||||
|
||||
var condensed = await ContextCondenser.CondenseIfNeededAsync(
|
||||
messages, _llm, llm.MaxContextTokens, ct);
|
||||
if (condensed)
|
||||
{
|
||||
EmitEvent(AgentEventType.Thinking, "", "컨텍스트 압축 완료 — 입력 토큰을 절감했습니다");
|
||||
_ = _eventLog?.AppendAsync(AgentEventLogType.CompactionCompleted,
|
||||
JsonSerializer.Serialize(new { messageCount = messages.Count }));
|
||||
UpdateTaskStateSummaryAsync("컨텍스트 압축 완료");
|
||||
}
|
||||
|
||||
// 임계치 기반 적극적 압축 (이전 LLM 호출의 토큰 사용량 기준)
|
||||
if (!condensed && _llm.LastTokenUsage != null)
|
||||
@@ -357,11 +372,18 @@ public partial class AgentLoopService
|
||||
_llm.LastTokenUsage.PromptTokens, llm.MaxContextTokens);
|
||||
EmitEvent(AgentEventType.Thinking, "",
|
||||
$"⚠ 컨텍스트 사용량 {usagePct}% — 적극적 컴팩션 실행");
|
||||
_ = _eventLog?.AppendAsync(AgentEventLogType.CompactionTriggered,
|
||||
JsonSerializer.Serialize(new { aggressive = true, usagePct }));
|
||||
var targetTokens = (int)(llm.MaxContextTokens * Defaults.ContextCompressionTargetRatio);
|
||||
var compacted = await ContextCondenser.CondenseIfNeededAsync(
|
||||
messages, _llm, targetTokens, ct);
|
||||
if (compacted)
|
||||
{
|
||||
EmitEvent(AgentEventType.Thinking, "", "적극적 컴팩션 완료");
|
||||
_ = _eventLog?.AppendAsync(AgentEventLogType.CompactionCompleted,
|
||||
JsonSerializer.Serialize(new { aggressive = true, messageCount = messages.Count }));
|
||||
UpdateTaskStateSummaryAsync($"적극적 컴팩션 완료 (이전 컨텍스트 사용량 {usagePct}%)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -496,6 +518,11 @@ public partial class AgentLoopService
|
||||
// 텍스트 부분
|
||||
var textResponse = string.Join("\n", textParts);
|
||||
|
||||
// Phase 17-B: AssistantMessage 이벤트 기록
|
||||
if (!string.IsNullOrWhiteSpace(textResponse))
|
||||
_ = _eventLog?.AppendAsync(AgentEventLogType.AssistantMessage,
|
||||
JsonSerializer.Serialize(new { length = textResponse.Length, hasToolCalls = toolCalls.Count > 0 }));
|
||||
|
||||
// Task Decomposition: 첫 번째 텍스트 응답에서 계획 단계 추출
|
||||
if (!planExtracted && !string.IsNullOrEmpty(textResponse))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user