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개입니다.
This commit is contained in:
@@ -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 카드와 임시 스트리밍 컨테이너를 먼저 만들지 않도록 바꿔, 토큰은 올라가는데 채팅 본문이 비거나 빈 버블이 남는 증상을 줄였습니다.
|
- 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에서 실행 로그 문구가 플래시처럼 잔상으로 남거나 중복 표시되던 흐름을 줄이는 쪽으로 정리했습니다.
|
- 같은 수정에서 에이전트 실행 로그도 화면에 즉시 배너를 직접 꽂지 않고, 대화 모델의 `ExecutionEvents`에 먼저 쌓은 뒤 `RenderMessages()` 기준으로만 다시 그리게 바꿨습니다. 그래서 Cowork/Code에서 실행 로그 문구가 플래시처럼 잔상으로 남거나 중복 표시되던 흐름을 줄이는 쪽으로 정리했습니다.
|
||||||
- 재생성 경로도 동일하게 정리해서, 피드백 후 재생성 시 빈 assistant 메시지를 먼저 추가하지 않고 최종 응답만 커밋하도록 맞췄습니다.
|
- 재생성 경로도 동일하게 정리해서, 피드백 후 재생성 시 빈 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
|
- 검증: `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:06 (KST)
|
||||||
|
- 업데이트: 2026-04-05 12:09 (KST)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -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 버블 삽입에 의존하지 않도록 다시 정리했습니다.
|
- 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 빈 버블이 남거나, 재생성 시 메시지 모델과 화면 상태가 어긋나는 증상을 줄이는 쪽으로 맞췄습니다.
|
- 현재 흐름은 `사용자 메시지 저장 → 전송 메시지 준비 → LLM 또는 AgentLoop 실행 → 최종 assistant 텍스트 확정 → conversation/session에 커밋 → RenderMessages()` 순서입니다. 이로써 토큰은 집계되지만 본문이 비거나, assistant 빈 버블이 남거나, 재생성 시 메시지 모델과 화면 상태가 어긋나는 증상을 줄이는 쪽으로 맞췄습니다.
|
||||||
- `OnAgentEvent(...)`도 직접 `AddAgentEventBanner()`를 바로 꽂는 방식을 중단하고, `AppendConversationExecutionEvent()` 후 `ShowExecutionHistory`가 켜진 경우에만 `RenderMessages(preserveViewport: true)`를 다시 타게 바꿨습니다. 이 수정은 Cowork/Code에서 실행 로그가 플래시처럼 남거나 중복 잔상으로 보이던 문제를 줄이기 위한 것입니다.
|
- `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
|
- 검증: `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)
|
||||||
|
|||||||
@@ -6864,9 +6864,9 @@ public partial class ChatWindow : Window
|
|||||||
_storage.Save(conv);
|
_storage.Save(conv);
|
||||||
ChatSession?.RememberConversation(runTab, conv.Id);
|
ChatSession?.RememberConversation(runTab, conv.Id);
|
||||||
UpdateChatTitle();
|
UpdateChatTitle();
|
||||||
AddMessageBubble("user", commandText);
|
|
||||||
InputBox.Text = "";
|
InputBox.Text = "";
|
||||||
EmptyState.Visibility = Visibility.Collapsed;
|
EmptyState.Visibility = Visibility.Collapsed;
|
||||||
|
RenderMessages(preserveViewport: true);
|
||||||
ForceScrollToEnd();
|
ForceScrollToEnd();
|
||||||
|
|
||||||
var llm = _settings.Settings.Llm;
|
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"
|
? $"컨텍스트 압축을 수행했습니다. 입력 토큰 추정치: {beforeTokens:N0} → {afterTokens:N0}\n- 단계: {compactResult.StageSummary}\n- 절감량: {compactResult.SavedTokens:N0} tokens"
|
||||||
: "현재 대화는 압축할 충분한 이전 컨텍스트가 없어 변경 없이 유지했습니다.";
|
: "현재 대화는 압축할 충분한 이전 컨텍스트가 없어 변경 없이 유지했습니다.";
|
||||||
|
|
||||||
var assistantMsg = new ChatMessage { Role = "assistant", Content = assistantText };
|
|
||||||
lock (_convLock)
|
lock (_convLock)
|
||||||
{
|
{
|
||||||
var session = ChatSession;
|
var session = ChatSession;
|
||||||
if (session != null)
|
_chatEngine.CommitAssistantMessage(session, conv, runTab, assistantText, _storage);
|
||||||
{
|
_currentConversation = session?.CurrentConversation ?? conv;
|
||||||
session.AppendMessage(runTab, assistantMsg);
|
|
||||||
_currentConversation = session.CurrentConversation;
|
|
||||||
conv = _currentConversation!;
|
conv = _currentConversation!;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
conv.Messages.Add(assistantMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveLastConversations();
|
SaveLastConversations();
|
||||||
_storage.Save(conv);
|
_storage.Save(conv);
|
||||||
AddMessageBubble("assistant", assistantText);
|
RenderMessages(preserveViewport: true);
|
||||||
ForceScrollToEnd();
|
ForceScrollToEnd();
|
||||||
if (StatusTokens != null)
|
if (StatusTokens != null)
|
||||||
StatusTokens.Text = $"컨텍스트 {Services.TokenEstimator.Format(beforeTokens)} → {Services.TokenEstimator.Format(afterTokens)}";
|
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 userMsg = new ChatMessage { Role = "user", Content = commandText };
|
||||||
var assistantMsg = new ChatMessage { Role = "assistant", Content = assistantText };
|
|
||||||
|
|
||||||
lock (_convLock)
|
lock (_convLock)
|
||||||
{
|
{
|
||||||
@@ -6942,14 +6933,14 @@ public partial class ChatWindow : Window
|
|||||||
if (session != null)
|
if (session != null)
|
||||||
{
|
{
|
||||||
session.AppendMessage(runTab, userMsg, useForTitle: true);
|
session.AppendMessage(runTab, userMsg, useForTitle: true);
|
||||||
session.AppendMessage(runTab, assistantMsg);
|
_chatEngine.CommitAssistantMessage(session, conv, runTab, assistantText, _storage);
|
||||||
_currentConversation = session.CurrentConversation;
|
_currentConversation = session.CurrentConversation;
|
||||||
conv = _currentConversation!;
|
conv = _currentConversation!;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
conv.Messages.Add(userMsg);
|
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);
|
_storage.Save(conv);
|
||||||
ChatSession?.RememberConversation(runTab, conv.Id);
|
ChatSession?.RememberConversation(runTab, conv.Id);
|
||||||
UpdateChatTitle();
|
UpdateChatTitle();
|
||||||
AddMessageBubble("user", commandText);
|
|
||||||
AddMessageBubble("assistant", assistantText);
|
|
||||||
InputBox.Text = "";
|
InputBox.Text = "";
|
||||||
EmptyState.Visibility = Visibility.Collapsed;
|
EmptyState.Visibility = Visibility.Collapsed;
|
||||||
|
RenderMessages(preserveViewport: true);
|
||||||
ForceScrollToEnd();
|
ForceScrollToEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user