diff --git a/README.md b/README.md index 18c4d3a..43de0fd 100644 --- a/README.md +++ b/README.md @@ -740,10 +740,12 @@ ow + toggle 시각 언어로 통일했습니다. - 이어서 [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs)에 `PrepareExecution(...)`, `NormalizeAssistantContent(...)`를 추가하고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 일반 전송과 재생성이 모두 같은 준비 함수를 타도록 정리했습니다. 이제 실행 모드 판정, 프롬프트 스택 구성, 전송 메시지 조립, 최종 assistant 내용 보정이 한 엔진 축에서 처리됩니다. - 이 변경으로 `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(...)`만 호출합니다. - 검증: `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) --- diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 4d18f6a..542594f 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -4495,4 +4495,7 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎. - 업데이트: 2026-04-05 12:36 (KST) - [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs)에 `FinalizeAssistantTurn(...)`를 추가해, 최종 assistant 텍스트 정규화와 `Cowork/Code`의 `ShowExecutionHistory=false` 처리, assistant 메시지 커밋을 한 메서드에 묶었습니다. - [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 의 `SendMessageAsync()`와 `SendRegenerateAsync()`는 더 이상 직접 `NormalizeAssistantContent(...)`와 `CommitAssistantMessage(...)`를 따로 호출하지 않고, 둘 다 `FinalizeAssistantTurn(...)`으로 마무리합니다. 이로써 AX Agent 채팅 엔진의 “준비 → 실행 → 최종 커밋” 축이 한 단계 더 짧고 일관되게 정리됐습니다. +- 업데이트: 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 채팅 엔진 공통화는 “준비 / 실행 선택 / 최종 커밋”까지 한 덩어리로 거의 맞춰지고 있습니다. - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\` 경고 0 / 오류 0 diff --git a/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs b/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs index 2ceb7ad..261de6d 100644 --- a/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs +++ b/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs @@ -74,6 +74,17 @@ public sealed class AxAgentExecutionEngine return new PreparedExecution(mode, promptStack, preparedTurn.Messages); } + public Task ExecutePreparedAsync( + PreparedExecution prepared, + Func, CancellationToken, Task> agentLoopRunner, + Func, CancellationToken, Task> llmRunner, + CancellationToken cancellationToken) + { + return prepared.Mode.UseAgentLoop + ? agentLoopRunner(prepared.Messages, cancellationToken) + : llmRunner(prepared.Messages, cancellationToken); + } + public PreparedTurn PrepareTurn( ChatConversation conversation, IEnumerable systemPrompts, diff --git a/src/AxCopilot/Views/ChatWindow.xaml.cs b/src/AxCopilot/Views/ChatWindow.xaml.cs index 8b6b0a1..1cf5d1b 100644 --- a/src/AxCopilot/Views/ChatWindow.xaml.cs +++ b/src/AxCopilot/Views/ChatWindow.xaml.cs @@ -8408,20 +8408,14 @@ public partial class ChatWindow : Window } } - if (executionMode.UseAgentLoop) - { - var response = await RunAgentLoopAsync(runTab, originTab, conv, sendMessages, _streamCts!.Token); - assistantContent = response; - StopAiIconPulse(); - _cachedStreamContent = response; - } - else - { - var response = await _llm.SendAsync(sendMessages, _streamCts.Token); - assistantContent = response; - StopAiIconPulse(); - _cachedStreamContent = response; - } + var response = await _chatEngine.ExecutePreparedAsync( + preparedExecution, + (messages, token) => RunAgentLoopAsync(runTab, originTab, conv, messages, token), + (messages, token) => _llm.SendAsync(messages.ToList(), token), + _streamCts.Token); + assistantContent = response; + StopAiIconPulse(); + _cachedStreamContent = response; draftSucceeded = true; } @@ -10981,9 +10975,11 @@ public partial class ChatWindow : Window var executionMode = preparedExecution.Mode; sendMessages = preparedExecution.Messages; - var response = executionMode.UseAgentLoop - ? await RunAgentLoopAsync(runTab, runTab, conv, sendMessages, _streamCts.Token) - : await _llm.SendAsync(sendMessages, _streamCts.Token); + var response = await _chatEngine.ExecutePreparedAsync( + preparedExecution, + (messages, token) => RunAgentLoopAsync(runTab, runTab, conv, messages, token), + (messages, token) => _llm.SendAsync(messages.ToList(), token), + _streamCts.Token); assistantContent = response; StopAiIconPulse(); _cachedStreamContent = response;