From f8baea24f5218a2c5cfbc2da1c81788f3d7b513c Mon Sep 17 00:00:00 2001 From: lacvet Date: Tue, 7 Apr 2026 08:21:05 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BD=94=EC=9B=8C=ED=81=AC=EC=99=80=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B5=9C=EC=A2=85=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=20=ED=83=80=EC=9D=B4=ED=95=91=20?= =?UTF-8?q?=ED=94=84=EB=A6=AC=EB=B7=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Cowork/Code 에이전트 루프 완료 후 최종 답변이 한 번에 붙지 않도록 라이브 타이핑 프리뷰를 추가함\n- 처리 중에는 기존 진행 로그를 유지하고, 최종 응답 구간만 스트리밍 컨테이너를 거쳐 자연스럽게 이어지도록 정리함\n- README와 DEVELOPMENT 문서에 2026-04-07 02:31 (KST) 기준 변경 이력 반영\n- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ (경고 0 / 오류 0) --- README.md | 3 +++ docs/DEVELOPMENT.md | 1 + src/AxCopilot/Views/ChatWindow.xaml.cs | 33 ++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/README.md b/README.md index e5446e3..8dd956e 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ Windows 전용 시맨틱 런처 & 워크스페이스 매니저 - AX Agent 직접 대화(Chat 탭) 경로에 실제 스트리밍 응답 연결을 복구했습니다. LLM 서비스는 원래 SSE/스트리밍을 지원하고 있었지만 UI 실행 경로가 최종 문자열만 받아 한 번에 붙이던 상태였고, 이제 설정상 스트리밍이 켜져 있으면 채팅 응답이 타자 치듯 점진적으로 표시됩니다. - Cowork/Code는 기존처럼 agent loop 진행 메시지 중심을 유지하고, 직접 대화 재생성은 같은 스트리밍 경로를 공유하도록 정리했습니다. +- 업데이트: 2026-04-07 02:31 (KST) +- Cowork/Code도 에이전트 루프가 끝난 뒤 최종 답변을 한 번에 붙이지 않고, 짧은 라이브 타이핑 프리뷰를 거친 다음 정식 메시지로 확정되도록 보강했습니다. 처리 중에는 진행 로그를 유지하고, 최종 응답 구간만 자연스럽게 이어지도록 정리했습니다. + - 업데이트: 2026-04-07 02:03 (KST) - Cowork 진행 표시가 오래 비거나 완료 후 실패처럼 깜박이던 흐름을 정리했습니다. 진행 힌트는 작업 시작 직후부터 즉시 보이게 하고, 중간 이벤트가 들어와도 불필요하게 사라지지 않도록 유지 로직을 조정했습니다. - 프리셋/입력창/진행 카드에 남아 있던 깨진 한글을 복구했고, 내부 실행 게이트 문구도 정상 한국어로 정리해 Cowork 루프가 잘못된 안내 문구에 끌리지 않도록 보강했습니다. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 4b6178f..9c41129 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -5286,3 +5286,4 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎. - Document update: 2026-04-07 02:23 (KST) - Reconnected the AX Agent direct-chat execution path to the existing SSE/streaming transport in `LlmService`. Chat replies no longer wait for the final full string before rendering; when streaming is enabled they now advance through the existing streaming container and typing-timer path. - Document update: 2026-04-07 02:23 (KST) - Updated `AxAgentExecutionEngine.ResolveExecutionMode()` so non-agent chat can opt into streaming transport, and wired `ChatWindow.ExecutePreparedTurnAsync()` to consume `LlmService.StreamAsync(...)` for direct conversations while keeping Cowork/Code on the agent-loop progress-feed path. +- Document update: 2026-04-07 02:31 (KST) - Added a typed final-response preview for Cowork/Code agent-loop completions. Those tabs still use progress-feed execution during the loop, but once a final assistant answer is available it now passes through the same streaming container/typing presentation before the final transcript message is committed. diff --git a/src/AxCopilot/Views/ChatWindow.xaml.cs b/src/AxCopilot/Views/ChatWindow.xaml.cs index 09ad1d0..df65c07 100644 --- a/src/AxCopilot/Views/ChatWindow.xaml.cs +++ b/src/AxCopilot/Views/ChatWindow.xaml.cs @@ -5653,7 +5653,13 @@ public partial class ChatWindow : Window draftSucceeded = true; if (streamingContainer != null && streamingText != null) + { FinalizeStreamingContainer(streamingContainer, streamingText, assistantContent); + } + else if (preparedExecution.Mode.UseAgentLoop && !string.IsNullOrWhiteSpace(assistantContent)) + { + await ShowTypedAssistantPreviewAsync(assistantContent, _streamCts.Token); + } } catch (OperationCanceledException) { @@ -5699,6 +5705,33 @@ public partial class ChatWindow : Window return new PreparedTurnOutcome(conversation, assistantContent, draftSucceeded, draftCancelled, draftFailure); } + private async Task ShowTypedAssistantPreviewAsync(string finalContent, CancellationToken ct) + { + if (string.IsNullOrWhiteSpace(finalContent) || MessagePanel == null) + return; + + var container = CreateStreamingContainer(out var streamText); + _activeStreamText = streamText; + _cachedStreamContent = finalContent; + _displayedLength = 0; + _cursorVisible = true; + MessagePanel.Children.Add(container); + ForceScrollToEnd(); + _cursorTimer.Start(); + _typingTimer.Start(); + streamText.Text = _cursorVisible ? "\u258c" : " "; + + var deadline = DateTime.UtcNow.AddMilliseconds(Math.Clamp(finalContent.Length * 6, 500, 1800)); + while (_displayedLength < _cachedStreamContent.Length && DateTime.UtcNow < deadline && !ct.IsCancellationRequested) + await Task.Delay(30, ct); + + _displayedLength = _cachedStreamContent.Length; + if (_activeStreamText != null) + _activeStreamText.Text = _cachedStreamContent; + + FinalizeStreamingContainer(container, streamText, finalContent); + } + private void ScheduleExecutionHistoryRender(bool autoScroll = true) { _pendingExecutionHistoryAutoScroll |= autoScroll;