- ResetStreamingUiState, FinalizeConversationTurn, FinalizeQueuedDraft를 추가해 전송과 재생성의 완료 후 UI/상태 정리를 같은 경로로 통합함 - 대화 저장, 목록 갱신, 대기열 완료/실패 반영, 다음 작업 시작 흐름을 helper 기준으로 다시 묶음 - 검증: 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:
@@ -741,11 +741,13 @@ ow + toggle 시각 언어로 통일했습니다.
|
||||
- 이 변경으로 `SendMessageAsync()`와 `SendRegenerateAsync()`가 각자 따로 Cowork/Code 시스템 프롬프트와 실행 모드를 계산하던 중복 분기가 줄었고, 이후 Cowork/Code 엔진을 `claw-code` 기준으로 더 밀 때도 준비 로직은 엔진 한 곳만 고치면 되게 정리했습니다.
|
||||
- 이어서 `FinalizeAssistantTurn(...)`를 엔진에 추가해, 최종 assistant 내용 정규화와 Cowork/Code 실행 로그 접힘 처리, assistant 메시지 커밋을 전송/재생성 공통으로 같은 메서드에서 처리하게 바꿨습니다. 이제 채팅 마무리 단계도 UI 코드가 아니라 엔진이 더 많이 책임집니다.
|
||||
- 이번엔 [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs)에 `ExecutePreparedAsync(...)`를 추가해서, 준비된 실행이 `AgentLoop`를 탈지 일반 LLM 호출을 탈지 결정하는 분기까지 엔진이 맡도록 옮겼습니다. [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 일반 전송과 재생성은 이제 둘 다 `ExecutePreparedAsync(...)`만 호출합니다.
|
||||
- 이어서 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 실행 후처리도 `ResetStreamingUiState()`, `FinalizeConversationTurn()`, `FinalizeQueuedDraft()`로 묶었습니다. 전송과 재생성이 같은 정리 경로를 공유하게 해서, 응답 완료 뒤 상태 복구와 대화 저장, 대기열 완료/실패 처리 흐름도 더 한 축으로 정리했습니다.
|
||||
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0
|
||||
- 업데이트: 2026-04-05 12:24 (KST)
|
||||
- 업데이트: 2026-04-05 12:31 (KST)
|
||||
- 업데이트: 2026-04-05 12:36 (KST)
|
||||
- 업데이트: 2026-04-05 12:41 (KST)
|
||||
- 업데이트: 2026-04-05 12:47 (KST)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4498,4 +4498,7 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎.
|
||||
- 업데이트: 2026-04-05 12:41 (KST)
|
||||
- `AgentLoop vs 일반 LLM 호출` 선택 분기까지 엔진으로 옮기기 위해 [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs)에 `ExecutePreparedAsync(...)`를 추가했습니다. 준비된 실행(`PreparedExecution`)과 두 실행 delegate를 넘기면, 엔진이 `UseAgentLoop` 판정에 따라 적절한 실행 경로를 선택합니다.
|
||||
- [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 `SendMessageAsync()`와 `SendRegenerateAsync()`는 이제 직접 `if (executionMode.UseAgentLoop)` 분기를 들고 있지 않고, 둘 다 `ExecutePreparedAsync(...)`를 통해 같은 실행 진입점을 사용합니다. 이 변경으로 AX Agent 채팅 엔진 공통화는 “준비 / 실행 선택 / 최종 커밋”까지 한 덩어리로 거의 맞춰지고 있습니다.
|
||||
- 업데이트: 2026-04-05 12:47 (KST)
|
||||
- [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)에 `ResetStreamingUiState()`, `FinalizeConversationTurn()`, `FinalizeQueuedDraft()`를 추가해, 전송과 재생성에 흩어져 있던 실행 후 UI/상태 정리 로직을 공통화했습니다.
|
||||
- 이 변경으로 응답 완료 후의 `타이머 중지`, `버튼 상태 복원`, `스트림 필드 정리`, `대화 저장`, `대화 목록 갱신`, `대기열 완료/실패 반영`, `다음 큐 작업 시작` 경로가 전송과 재생성에서 같은 helper를 공유하게 됐습니다. 현재 AX Agent 채팅 엔진 공통화는 준비/실행 선택/최종 커밋/후처리까지 대부분 한 축으로 모이는 단계까지 왔습니다.
|
||||
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\` 경고 0 / 오류 0
|
||||
|
||||
@@ -8440,23 +8440,7 @@ public partial class ChatWindow : Window
|
||||
_llm.ClearRouteOverride();
|
||||
UpdateModelLabel();
|
||||
}
|
||||
|
||||
_cursorTimer.Stop();
|
||||
_elapsedTimer.Stop();
|
||||
_typingTimer.Stop();
|
||||
HideStickyProgress(); // 에이전트 프로그레스 바 + 타이머 정리
|
||||
StopRainbowGlow(); // 레인보우 글로우 종료
|
||||
_activeStreamText = null;
|
||||
_elapsedLabel = null;
|
||||
_cachedStreamContent = "";
|
||||
_isStreaming = false;
|
||||
BtnSend.IsEnabled = true;
|
||||
BtnStop.Visibility = Visibility.Collapsed;
|
||||
BtnSend.Visibility = Visibility.Visible;
|
||||
_streamCts?.Dispose();
|
||||
_streamCts = null;
|
||||
_streamRunTab = null;
|
||||
SetStatusIdle();
|
||||
ResetStreamingUiState();
|
||||
}
|
||||
|
||||
lock (_convLock)
|
||||
@@ -8467,38 +8451,8 @@ public partial class ChatWindow : Window
|
||||
conv = _currentConversation!;
|
||||
}
|
||||
|
||||
lock (_convLock)
|
||||
_currentConversation = conv;
|
||||
RenderMessages(preserveViewport: true);
|
||||
AutoScrollIfNeeded();
|
||||
|
||||
try { _storage.Save(conv); } catch (Exception ex) { Services.LogService.Debug($"대화 저장 실패: {ex.Message}"); }
|
||||
ChatSession?.RememberConversation(originTab, conv.Id);
|
||||
SyncTabConversationIdsFromSession();
|
||||
RefreshConversationList();
|
||||
if (!string.IsNullOrWhiteSpace(queuedDraftId))
|
||||
{
|
||||
lock (_convLock)
|
||||
{
|
||||
var session = ChatSession;
|
||||
if (session != null)
|
||||
{
|
||||
if (draftSucceeded)
|
||||
_draftQueueProcessor.Complete(session, originTab, queuedDraftId, _storage, _appState.TaskRuns);
|
||||
else
|
||||
_draftQueueProcessor.HandleFailure(session, originTab, queuedDraftId, draftFailure, draftCancelled, 3, _storage, _appState.TaskRuns);
|
||||
|
||||
_currentConversation = session.CurrentConversation ?? _currentConversation;
|
||||
}
|
||||
|
||||
if (string.Equals(_runningDraftId, queuedDraftId, StringComparison.OrdinalIgnoreCase))
|
||||
_runningDraftId = null;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshDraftQueueUi();
|
||||
if (!draftCancelled && !string.IsNullOrWhiteSpace(queuedDraftId) && string.Equals(originTab, _activeTab, StringComparison.OrdinalIgnoreCase))
|
||||
_ = Dispatcher.BeginInvoke(new Action(() => StartNextQueuedDraftIfAny()), DispatcherPriority.Background);
|
||||
FinalizeConversationTurn(originTab, conv);
|
||||
FinalizeQueuedDraft(originTab, queuedDraftId, draftSucceeded, draftCancelled, draftFailure);
|
||||
}
|
||||
|
||||
private async Task<string> RunAgentLoopAsync(
|
||||
@@ -8577,6 +8531,67 @@ public partial class ChatWindow : Window
|
||||
images);
|
||||
}
|
||||
|
||||
private void ResetStreamingUiState()
|
||||
{
|
||||
_cursorTimer.Stop();
|
||||
_elapsedTimer.Stop();
|
||||
_typingTimer.Stop();
|
||||
HideStickyProgress();
|
||||
StopRainbowGlow();
|
||||
_activeStreamText = null;
|
||||
_elapsedLabel = null;
|
||||
_cachedStreamContent = "";
|
||||
_isStreaming = false;
|
||||
BtnSend.IsEnabled = true;
|
||||
BtnStop.Visibility = Visibility.Collapsed;
|
||||
BtnSend.Visibility = Visibility.Visible;
|
||||
_streamCts?.Dispose();
|
||||
_streamCts = null;
|
||||
_streamRunTab = null;
|
||||
SetStatusIdle();
|
||||
}
|
||||
|
||||
private void FinalizeConversationTurn(string rememberTab, ChatConversation conversation)
|
||||
{
|
||||
lock (_convLock)
|
||||
_currentConversation = conversation;
|
||||
|
||||
RenderMessages(preserveViewport: true);
|
||||
AutoScrollIfNeeded();
|
||||
|
||||
try { _storage.Save(conversation); } catch (Exception ex) { Services.LogService.Debug($"대화 저장 실패: {ex.Message}"); }
|
||||
ChatSession?.RememberConversation(rememberTab, conversation.Id);
|
||||
SyncTabConversationIdsFromSession();
|
||||
RefreshConversationList();
|
||||
}
|
||||
|
||||
private void FinalizeQueuedDraft(string originTab, string? queuedDraftId, bool draftSucceeded, bool draftCancelled, string? draftFailure)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(queuedDraftId))
|
||||
return;
|
||||
|
||||
lock (_convLock)
|
||||
{
|
||||
var session = ChatSession;
|
||||
if (session != null)
|
||||
{
|
||||
if (draftSucceeded)
|
||||
_draftQueueProcessor.Complete(session, originTab, queuedDraftId, _storage, _appState.TaskRuns);
|
||||
else
|
||||
_draftQueueProcessor.HandleFailure(session, originTab, queuedDraftId, draftFailure, draftCancelled, 3, _storage, _appState.TaskRuns);
|
||||
|
||||
_currentConversation = session.CurrentConversation ?? _currentConversation;
|
||||
}
|
||||
|
||||
if (string.Equals(_runningDraftId, queuedDraftId, StringComparison.OrdinalIgnoreCase))
|
||||
_runningDraftId = null;
|
||||
}
|
||||
|
||||
RefreshDraftQueueUi();
|
||||
if (!draftCancelled && string.Equals(originTab, _activeTab, StringComparison.OrdinalIgnoreCase))
|
||||
_ = Dispatcher.BeginInvoke(new Action(() => StartNextQueuedDraftIfAny()), DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
// ─── 코워크 에이전트 지원 ────────────────────────────────────────────
|
||||
|
||||
private string BuildCoworkSystemPrompt()
|
||||
@@ -10996,22 +11011,7 @@ public partial class ChatWindow : Window
|
||||
}
|
||||
finally
|
||||
{
|
||||
_cursorTimer.Stop();
|
||||
_elapsedTimer.Stop();
|
||||
_typingTimer.Stop();
|
||||
HideStickyProgress(); // 에이전트 프로그레스 바 + 타이머 정리
|
||||
StopRainbowGlow(); // 레인보우 글로우 종료
|
||||
_activeStreamText = null;
|
||||
_elapsedLabel = null;
|
||||
_cachedStreamContent = "";
|
||||
_isStreaming = false;
|
||||
BtnSend.IsEnabled = true;
|
||||
BtnStop.Visibility = Visibility.Collapsed;
|
||||
BtnSend.Visibility = Visibility.Visible;
|
||||
_streamCts?.Dispose();
|
||||
_streamCts = null;
|
||||
_streamRunTab = null;
|
||||
SetStatusIdle();
|
||||
ResetStreamingUiState();
|
||||
}
|
||||
|
||||
lock (_convLock)
|
||||
@@ -11021,13 +11021,7 @@ public partial class ChatWindow : Window
|
||||
_currentConversation = session?.CurrentConversation ?? conv;
|
||||
conv = _currentConversation!;
|
||||
}
|
||||
RenderMessages(preserveViewport: true);
|
||||
AutoScrollIfNeeded();
|
||||
|
||||
try { _storage.Save(conv); } catch (Exception ex) { Services.LogService.Debug($"대화 저장 실패: {ex.Message}"); }
|
||||
ChatSession?.RememberConversation(conv.Tab ?? _activeTab, conv.Id);
|
||||
SyncTabConversationIdsFromSession();
|
||||
RefreshConversationList();
|
||||
FinalizeConversationTurn(conv.Tab ?? _activeTab, conv);
|
||||
}
|
||||
|
||||
/// <summary>채팅 본문 폭을 세 탭에서 동일한 기준으로 맞춥니다.</summary>
|
||||
|
||||
Reference in New Issue
Block a user