From f82cfc4541de2d71d97bebb77bd01aed4a444625 Mon Sep 17 00:00:00 2001 From: lacvet Date: Sun, 5 Apr 2026 12:10:31 +0900 Subject: [PATCH] =?UTF-8?q?AX=20Agent=20=EB=A1=9C=EC=BB=AC=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=EA=B2=BD=EB=A1=9C=EB=A5=BC=20=EB=AA=A8=EB=8D=B8=20?= =?UTF-8?q?=EB=A0=8C=EB=8D=94=20=EC=B6=95=EC=9C=BC=EB=A1=9C=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit claw-code 기준 채팅 엔진 정상화 작업을 이어서 진행했습니다. 수동 컨텍스트 압축 결과와 slash 로컬 응답 경로에서 직접 AddMessageBubble로 UI 버블을 꽂던 흐름을 제거하고 conversation/session에 먼저 커밋한 뒤 RenderMessages로만 다시 그리도록 정리했습니다. 이로써 일반 전송, 재생성, 로컬 응답이 서로 다른 렌더 경로를 타며 순서가 꼬이던 상태를 줄였고 Cowork/Code 전용 엔진 정리에 필요한 공통 렌더 축을 더 맞췄습니다. 검증은 dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ 기준 경고 0개, 오류 0개입니다. --- README.md | 2 ++ docs/DEVELOPMENT.md | 2 ++ src/AxCopilot/Views/ChatWindow.xaml.cs | 26 ++++++++------------------ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 878d88b..b49fedc 100644 --- a/README.md +++ b/README.md @@ -729,8 +729,10 @@ ow + toggle 시각 언어로 통일했습니다. - AX Agent 채팅 엔진 정상화 1차로, [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs) 와 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 의 전송 흐름을 `준비 → 실행 → 최종 assistant 커밋 → 재렌더` 중심으로 다시 정리했습니다. Chat/Cowork/Code 공통으로 임시 assistant 카드와 임시 스트리밍 컨테이너를 먼저 만들지 않도록 바꿔, 토큰은 올라가는데 채팅 본문이 비거나 빈 버블이 남는 증상을 줄였습니다. - 같은 수정에서 에이전트 실행 로그도 화면에 즉시 배너를 직접 꽂지 않고, 대화 모델의 `ExecutionEvents`에 먼저 쌓은 뒤 `RenderMessages()` 기준으로만 다시 그리게 바꿨습니다. 그래서 Cowork/Code에서 실행 로그 문구가 플래시처럼 잔상으로 남거나 중복 표시되던 흐름을 줄이는 쪽으로 정리했습니다. - 재생성 경로도 동일하게 정리해서, 피드백 후 재생성 시 빈 assistant 메시지를 먼저 추가하지 않고 최종 응답만 커밋하도록 맞췄습니다. +- 이어서 `/slash` 로컬 응답과 수동 컨텍스트 압축 결과 경로도 conversation/session에 먼저 커밋한 뒤 `RenderMessages()`로만 다시 그리게 맞췄습니다. 이제 로컬 응답 경로도 직접 `AddMessageBubble(...)`를 꽂지 않아서, Chat/Cowork/Code에서 같은 종류의 중복 버블/순서 어긋남이 덜 발생하도록 정리했습니다. - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0 - 업데이트: 2026-04-05 12:06 (KST) +- 업데이트: 2026-04-05 12:09 (KST) --- diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index b7e5780..95cfc33 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -4479,4 +4479,6 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎. - AX Agent 채팅 엔진 정상화 1차에서 [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs)의 Chat 실행 모드를 `최종 응답 커밋형`으로 고정하고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 `SendMessageAsync()` / `SendRegenerateAsync()`가 임시 assistant 메시지, 임시 스트리밍 컨테이너, 직접 UI 버블 삽입에 의존하지 않도록 다시 정리했습니다. - 현재 흐름은 `사용자 메시지 저장 → 전송 메시지 준비 → LLM 또는 AgentLoop 실행 → 최종 assistant 텍스트 확정 → conversation/session에 커밋 → RenderMessages()` 순서입니다. 이로써 토큰은 집계되지만 본문이 비거나, assistant 빈 버블이 남거나, 재생성 시 메시지 모델과 화면 상태가 어긋나는 증상을 줄이는 쪽으로 맞췄습니다. - `OnAgentEvent(...)`도 직접 `AddAgentEventBanner()`를 바로 꽂는 방식을 중단하고, `AppendConversationExecutionEvent()` 후 `ShowExecutionHistory`가 켜진 경우에만 `RenderMessages(preserveViewport: true)`를 다시 타게 바꿨습니다. 이 수정은 Cowork/Code에서 실행 로그가 플래시처럼 남거나 중복 잔상으로 보이던 문제를 줄이기 위한 것입니다. +- 이어서 수동 컨텍스트 압축 결과와 `/slash` 로컬 응답 경로도 conversation/session에 먼저 반영한 뒤 `RenderMessages()` 기준으로 다시 그리도록 맞췄습니다. 이 변경으로 Chat/Cowork/Code에서 “일반 전송은 모델 렌더, 로컬 응답은 직접 버블 주입”으로 두 경로가 섞여 있던 상태를 더 줄였고, 코워크/코드 엔진 정상화 작업을 계속 진행할 수 있는 공통 렌더 축을 확보했습니다. - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\` 경고 0 / 오류 0 +- 업데이트: 2026-04-05 12:09 (KST) diff --git a/src/AxCopilot/Views/ChatWindow.xaml.cs b/src/AxCopilot/Views/ChatWindow.xaml.cs index 15434ea..35a09aa 100644 --- a/src/AxCopilot/Views/ChatWindow.xaml.cs +++ b/src/AxCopilot/Views/ChatWindow.xaml.cs @@ -6864,9 +6864,9 @@ public partial class ChatWindow : Window _storage.Save(conv); ChatSession?.RememberConversation(runTab, conv.Id); UpdateChatTitle(); - AddMessageBubble("user", commandText); InputBox.Text = ""; EmptyState.Visibility = Visibility.Collapsed; + RenderMessages(preserveViewport: true); ForceScrollToEnd(); var llm = _settings.Settings.Llm; @@ -6895,25 +6895,17 @@ public partial class ChatWindow : Window ? $"컨텍스트 압축을 수행했습니다. 입력 토큰 추정치: {beforeTokens:N0} → {afterTokens:N0}\n- 단계: {compactResult.StageSummary}\n- 절감량: {compactResult.SavedTokens:N0} tokens" : "현재 대화는 압축할 충분한 이전 컨텍스트가 없어 변경 없이 유지했습니다."; - var assistantMsg = new ChatMessage { Role = "assistant", Content = assistantText }; lock (_convLock) { var session = ChatSession; - if (session != null) - { - session.AppendMessage(runTab, assistantMsg); - _currentConversation = session.CurrentConversation; - conv = _currentConversation!; - } - else - { - conv.Messages.Add(assistantMsg); - } + _chatEngine.CommitAssistantMessage(session, conv, runTab, assistantText, _storage); + _currentConversation = session?.CurrentConversation ?? conv; + conv = _currentConversation!; } SaveLastConversations(); _storage.Save(conv); - AddMessageBubble("assistant", assistantText); + RenderMessages(preserveViewport: true); ForceScrollToEnd(); if (StatusTokens != null) StatusTokens.Text = $"컨텍스트 {Services.TokenEstimator.Format(beforeTokens)} → {Services.TokenEstimator.Format(afterTokens)}"; @@ -6934,7 +6926,6 @@ public partial class ChatWindow : Window } var userMsg = new ChatMessage { Role = "user", Content = commandText }; - var assistantMsg = new ChatMessage { Role = "assistant", Content = assistantText }; lock (_convLock) { @@ -6942,14 +6933,14 @@ public partial class ChatWindow : Window if (session != null) { session.AppendMessage(runTab, userMsg, useForTitle: true); - session.AppendMessage(runTab, assistantMsg); + _chatEngine.CommitAssistantMessage(session, conv, runTab, assistantText, _storage); _currentConversation = session.CurrentConversation; conv = _currentConversation!; } else { conv.Messages.Add(userMsg); - conv.Messages.Add(assistantMsg); + _chatEngine.CommitAssistantMessage(null, conv, runTab, assistantText, _storage); } } @@ -6957,10 +6948,9 @@ public partial class ChatWindow : Window _storage.Save(conv); ChatSession?.RememberConversation(runTab, conv.Id); UpdateChatTitle(); - AddMessageBubble("user", commandText); - AddMessageBubble("assistant", assistantText); InputBox.Text = ""; EmptyState.Visibility = Visibility.Collapsed; + RenderMessages(preserveViewport: true); ForceScrollToEnd(); }