From d40b80ee964852163f257086c45abbed7f9d7679 Mon Sep 17 00:00:00 2001 From: lacvet Date: Sun, 5 Apr 2026 00:19:00 +0900 Subject: [PATCH] =?UTF-8?q?compact=20=EC=A7=81=ED=9B=84=20=EB=8F=84?= =?UTF-8?q?=EA=B5=AC=20=EA=B2=B0=EA=B3=BC=20=EC=B6=95=EC=95=BD=EA=B3=BC=20?= =?UTF-8?q?=ED=9B=84=EC=86=8D=20=EB=A3=A8=ED=94=84=20=EB=B3=B4=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - claw-code post-autocompact turn 흐름을 참고해 AX AgentLoop가 compact 직후 첫 턴의 도구 결과를 별도 정책으로 축약하도록 보강함 - process/build_run/test_loop/git/http 계열의 긴 결과는 head/tail 중심 post-compaction 요약으로 피드백해 freshly compacted context가 다시 커지는 현상을 줄임 - compact 로그 축약 건수와 compact 결과 축약 건수를 전체 통계에 반영하고 README.md, docs/DEVELOPMENT.md에 2026-04-05 00:24 (KST) 기준 이력을 추가함 - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ / 경고 0 / 오류 0 --- README.md | 1 + docs/DEVELOPMENT.md | 1 + .../Services/Agent/AgentLoopService.cs | 67 ++++++++++++++++++- .../Agent/AgentLoopTransitions.Execution.cs | 1 + 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5cc682a..eebb135 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Windows 전용 시맨틱 런처 & 워크스페이스 매니저 - 업데이트: 2026-04-05 00:17 (KST) - AX Agent 루프도 `claw-code`의 post-autocompact turn tracking 흐름을 참고해 compact 직후 턴을 별도 상태로 추적하도록 보강했습니다. 이제 compact 직후 첫 턴은 저노이즈 compact pill 중심으로 보이고, 불필요한 `LLM 요청 중`류 Thinking 로그는 자동으로 줄입니다. - 개발자용 전체 통계에는 compact 직후 자동 축약된 Thinking 로그 건수도 함께 표시해, compact 이후 루프가 실제로 얼마나 조용해졌는지 바로 확인할 수 있게 했습니다. +- compact 직후 첫 턴의 `process/build_run/test_loop/git/http` 계열 도구 결과는 head/tail 중심의 post-compaction 요약으로 더 짧게 전달해, 압축 직후 문맥이 다시 길어지는 현상을 줄였습니다. - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0 - 업데이트: 2026-04-04 23:47 (KST) diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index ac43d4d..f125bd1 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -1,6 +1,7 @@ # AX Copilot - 媛쒕컻 臾몄꽌 - Document update: 2026-04-05 00:17 (KST) - Upgraded the AX Agent loop to track the first post-compaction turn explicitly, mirroring claw-code's post-autocompact turn handling so compact-follow-up state now survives into the next loop turn instead of ending at the condenser call. +- Document update: 2026-04-05 00:24 (KST) - Added compact-aware tool result trimming for the first post-compaction turn so heavy `process`, `build_run`, `test_loop`, `git_tool`, `http_tool`, and similar outputs are fed back to the loop as head/tail summaries instead of re-expanding the freshly compacted context. - Document update: 2026-04-05 00:17 (KST) - Added post-compaction thinking suppression for boilerplate loop events (`LLM request`, prompt submit, free-tier wait) during the first compact-follow-up turn, while still surfacing a compact-specific lightweight pill and compact-noise counts in total stats. diff --git a/src/AxCopilot/Services/Agent/AgentLoopService.cs b/src/AxCopilot/Services/Agent/AgentLoopService.cs index 119f32a..6945d49 100644 --- a/src/AxCopilot/Services/Agent/AgentLoopService.cs +++ b/src/AxCopilot/Services/Agent/AgentLoopService.cs @@ -56,6 +56,7 @@ public partial class AgentLoopService private int _runPostCompactionSuppressedThinkingCount; private string _runLastCompactionStageSummary = ""; private int _runLastCompactionSavedTokens; + private int _runPostCompactionToolResultCompactions; /// 일시정지 제어용 세마포어. 1이면 진행, 0이면 대기. private readonly SemaphoreSlim _pauseSemaphore = new(1, 1); @@ -1338,7 +1339,9 @@ public partial class AgentLoopService // 도구 결과를 LLM에 피드백 messages.Add(LlmService.CreateToolResultMessage( - effectiveCall.ToolId, effectiveCall.ToolName, TruncateOutput(result.Output, 4000))); + effectiveCall.ToolId, + effectiveCall.ToolName, + BuildLoopToolResultMessage(effectiveCall, result, runState))); if (TryHandleReadOnlyStagnationTransition( consecutiveReadOnlySuccessTools, @@ -1459,6 +1462,7 @@ public partial class AgentLoopService _runPostCompactionSuppressedThinkingCount = 0; _runLastCompactionStageSummary = ""; _runLastCompactionSavedTokens = 0; + _runPostCompactionToolResultCompactions = 0; // 일시정지 상태 리셋 if (IsPaused) @@ -1503,10 +1507,13 @@ public partial class AgentLoopService var compactNoiseSummary = _runPostCompactionSuppressedThinkingCount > 0 ? $" | compact 로그 축약 {_runPostCompactionSuppressedThinkingCount}건" : ""; + var compactToolResultSummary = _runPostCompactionToolResultCompactions > 0 + ? $" | compact 결과 축약 {_runPostCompactionToolResultCompactions}건" + : ""; var topFailed = BuildTopFailureSummary(failedToolHistogram); var summary = $"📊 전체 통계: LLM {iteration}회 호출 | 도구 {totalToolCalls}회 (성공 {statsSuccessCount}, 실패 {statsFailCount}) | " + $"토큰 {statsInputTokens:N0}→{statsOutputTokens:N0} (합계 {totalTokens:N0}) | " + - $"소요 {durationSec:F1}초 | 재시도 품질 {retryQuality} (복구 {statsRecoveredAfterFailure}, 차단 {statsRepeatedFailureBlocks}){compactNoiseSummary} | " + + $"소요 {durationSec:F1}초 | 재시도 품질 {retryQuality} (복구 {statsRecoveredAfterFailure}, 차단 {statsRepeatedFailureBlocks}){compactNoiseSummary}{compactToolResultSummary} | " + $"실패 상위: {topFailed} | 사용 도구: {toolList}"; EmitEvent(AgentEventType.StepDone, "total_stats", summary); } @@ -4446,6 +4453,7 @@ public partial class AgentLoopService _runPostCompactionTurnCounter = runState.PostCompactionTurnCounter; _runLastCompactionStageSummary = runState.LastCompactionStageSummary ?? ""; _runLastCompactionSavedTokens = runState.LastCompactionSavedTokens; + _runPostCompactionToolResultCompactions = runState.PostCompactionToolResultCompactions; } private bool ShouldSuppressPostCompactionThinking(string summary) @@ -4466,6 +4474,61 @@ public partial class AgentLoopService || summary.StartsWith("컨텍스트 압축 완료", StringComparison.Ordinal); } + private string BuildLoopToolResultMessage(LlmService.ContentBlock call, ToolResult result, RunState runState) + { + var output = result.Output ?? ""; + if (!ShouldCompactToolResultForPostCompactionTurn(runState, call.ToolName, output)) + return TruncateOutput(output, 4000); + + runState.PostCompactionToolResultCompactions++; + SyncRunPostCompactionState(runState); + + var compacted = CompactToolResultForPostCompaction(call.ToolName, output); + var stage = string.IsNullOrWhiteSpace(runState.LastCompactionStageSummary) + ? "compact" + : runState.LastCompactionStageSummary; + return $"[POST_COMPACTION_TOOL_RESULT:{call.ToolName}] {stage}\n{compacted}"; + } + + private static bool ShouldCompactToolResultForPostCompactionTurn(RunState runState, string toolName, string output) + { + if (runState.PostCompactionTurnCounter != 1) + return false; + if (string.IsNullOrWhiteSpace(output)) + return false; + if (output.Length < 900) + return false; + + return toolName is "process" or "build_run" or "test_loop" or "snippet_runner" or "git_tool" or "http_tool" + || output.Length > 1800; + } + + private static string CompactToolResultForPostCompaction(string toolName, string output) + { + var normalized = output.Replace("\r\n", "\n"); + var lines = normalized.Split('\n', StringSplitOptions.None) + .Select(line => line.TrimEnd()) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .ToList(); + + if (lines.Count == 0) + return TruncateOutput(output, 1200); + + var headCount = toolName is "build_run" or "test_loop" or "process" ? 6 : 4; + var tailCount = toolName is "build_run" or "test_loop" or "process" ? 4 : 3; + var kept = new List(); + kept.AddRange(lines.Take(headCount)); + + if (lines.Count > headCount + tailCount) + kept.Add($"...[post-compact snip: {lines.Count - headCount - tailCount:N0}줄 생략]..."); + + if (lines.Count > headCount) + kept.AddRange(lines.Skip(Math.Max(headCount, lines.Count - tailCount))); + + var compacted = string.Join("\n", kept.Distinct(StringComparer.Ordinal)); + return TruncateOutput(compacted, 1400); + } + /// 영향 범위 기반 의사결정 체크. 확인이 필요하면 메시지를 반환, 불필요하면 null. private string? CheckDecisionRequired(LlmService.ContentBlock call, AgentContext context) { diff --git a/src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs b/src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs index e52f428..6f18056 100644 --- a/src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs +++ b/src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs @@ -1511,6 +1511,7 @@ public partial class AgentLoopService public int PostCompactionTurnCounter; public string LastCompactionStageSummary = ""; public int LastCompactionSavedTokens; + public int PostCompactionToolResultCompactions; } }