From 9fafcd01921a34339f183c08c8ce0c4898c76445 Mon Sep 17 00:00:00 2001 From: lacvet Date: Sun, 5 Apr 2026 14:05:18 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BD=94=EC=9B=8C=ED=81=AC=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EA=B3=84=ED=9A=8D/=EC=83=9D=EC=84=B1=20=ED=9D=90?= =?UTF-8?q?=EB=A6=84=EC=9D=84=20claw-code=20=EA=B8=B0=EC=A4=80=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - document_plan 결과에서 body 골격과 후속 생성 도구를 안정적으로 추출하도록 AgentLoop 분기를 수정 - 코워크 문서형 작업은 planMode=off여도 계획 선행(always) 경로를 타도록 보정 - 코워크 시스템 프롬프트를 강화해 계획만 제시하고 끝나지 않고 실제 문서 파일 생성까지 이어지게 조정 - README와 DEVELOPMENT 문서에 2026-04-05 16:02 (KST) 기준 변경 이력 반영 - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ (경고 0 / 오류 0) --- README.md | 6 ++ docs/DEVELOPMENT.md | 3 + .../Services/Agent/AgentLoopService.cs | 20 ++++- .../Agent/AgentLoopTransitions.Execution.cs | 79 +++++++++++++++---- .../Services/Agent/DocumentPlannerTool.cs | 2 + src/AxCopilot/Views/ChatWindow.xaml.cs | 4 +- 6 files changed, 98 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 14880ce..9e92d70 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,12 @@ Windows 전용 시맨틱 런처 & 워크스페이스 매니저 개발 참고: Claw Code 동등성 작업 추적 문서 `docs/claw-code-parity-plan.md` +- 업데이트: 2026-04-05 16:02 (KST) +- `document_plan` 후속 실행 분기를 `claw-code` 기준으로 다시 보강했습니다. 이제 문서 플래너 출력에서 body 골격과 즉시 실행 지시를 깨진 문자열 비교에 의존하지 않고 안정적으로 추출해, `html_create / document_assemble / docx_create / markdown_create` 후속 호출 유도가 실제로 이어집니다. +- 코워크 문서형 작업은 설정이 `planMode=off`여도 내부적으로 `always` 플랜 경로를 타도록 보정했습니다. 그래서 문서/보고서/제안서 요청은 먼저 계획을 세우고, 그 계획을 바탕으로 실제 문서 생성 단계까지 이어가도록 정리했습니다. +- 코워크 시스템 프롬프트도 강화해 문서 작업은 계획만 제시하고 끝내지 말고 실제 산출물 파일 경로까지 만들어야 완료로 판단하도록 바꿨습니다. +- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0 + - 업데이트: 2026-04-05 15:42 (KST) - AX Agent 엔진 공통화 1차로, Cowork/Code 실행 이벤트와 Agent run 기록을 탭별 현재 대화에 누적한 뒤 원래 활성 탭 대화를 복원하는 로직을 `ChatWindow`에서 `AxAgentExecutionEngine` helper로 옮겼습니다. - 이제 실행 이벤트/최근 run 기록 반영 시 창 코드가 직접 교차 탭 복원 경로를 중복 처리하지 않고, 엔진의 공통 세션 mutation 경로를 사용합니다. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 3048c44..2ad432a 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -1,5 +1,8 @@ # AX Copilot - 媛쒕컻 臾몄꽌 +- Document update: 2026-04-05 16:02 (KST) - Fixed the Cowork document execution handoff around `document_plan`. The loop no longer depends on broken localized marker strings to detect the scaffold/body block or the immediate-next-step hint; it now extracts body markers robustly and resolves the correct follow-up tool (`html_create`, `document_assemble`, `docx_create`, `markdown_create`) before re-prompting the model. +- Document update: 2026-04-05 16:02 (KST) - Added `ResolveEffectivePlanMode(...)` so Cowork document/content tasks automatically use the `always` plan path even when the persisted plan mode is `off`. This brings Cowork closer to the `claw-code` expectation of plan-first execution for document-heavy work. +- Document update: 2026-04-05 16:02 (KST) - Strengthened `BuildCoworkSystemPrompt()` so document/report/proposal/manual requests must produce an execution plan first and are not considered complete until a real output file path has been created or updated. - Document update: 2026-04-05 15:34 (KST) - Rebased the AX Agent improvement plan on actual `claw-code` runtime files instead of prior AX snapshots. The active reference spine is `src/bootstrap/state.ts -> src/bridge/initReplBridge.ts -> src/bridge/sessionRunner.ts -> src/screens/REPL.tsx -> src/components/Messages.tsx -> src/components/StatusLine.tsx`. - Document update: 2026-04-05 15:34 (KST) - Locked the AX implementation order to the same quality sequence used by that spine: runtime state canonicalization, prepared execution unification, loop event normalization, timeline render parity, composer/status strip simplification, and recovery/resume validation. - Document update: 2026-04-05 15:42 (KST) - Moved the cross-tab conversation restoration path for execution events and agent-run history from `ChatWindow.xaml.cs` into `AxAgentExecutionEngine`. `AppendExecutionEvent` and `AppendAgentRun` now go through one engine-owned session mutation helper, which preserves the active tab conversation while updating the target tab timeline. diff --git a/src/AxCopilot/Services/Agent/AgentLoopService.cs b/src/AxCopilot/Services/Agent/AgentLoopService.cs index 6945d49..94b0bea 100644 --- a/src/AxCopilot/Services/Agent/AgentLoopService.cs +++ b/src/AxCopilot/Services/Agent/AgentLoopService.cs @@ -200,7 +200,7 @@ public partial class AgentLoopService maxRetry = ComputeQualityAwareMaxRetry(maxRetry, recentTaskRetryQuality, taskPolicy.TaskType); // 플랜 모드 설정 - var planMode = llm.PlanMode ?? "off"; // off | always | auto + var planMode = ResolveEffectivePlanMode(llm.PlanMode, ActiveTab, taskPolicy.TaskType); // off | always | auto var context = BuildContext(); InjectTaskTypeGuidance(messages, taskPolicy); @@ -2096,6 +2096,24 @@ public partial class AgentLoopService return string.Equals(activeTab, "Code", StringComparison.OrdinalIgnoreCase) ? "feature" : "general"; } + internal static string ResolveEffectivePlanMode(string? configuredPlanMode, string? activeTab, string? taskType) + { + var normalizedPlanMode = (configuredPlanMode ?? "off").Trim().ToLowerInvariant(); + if (normalizedPlanMode is not ("off" or "auto" or "always")) + normalizedPlanMode = "off"; + + if (string.Equals(activeTab, "Cowork", StringComparison.OrdinalIgnoreCase) + && string.Equals(taskType, "docs", StringComparison.OrdinalIgnoreCase) + && normalizedPlanMode == "off") + { + // claw-code 레퍼런스처럼 문서형 코워크는 실행 전에 구조를 먼저 세우고, + // 그 계획을 바탕으로 실제 산출물 생성 단계까지 이어가도록 기본값을 보정합니다. + return "always"; + } + + return normalizedPlanMode; + } + private static void InjectTaskTypeGuidance(List messages, TaskTypePolicy taskPolicy) { if (messages.Any(m => m.Role == "user" && m.Content.StartsWith("[System:TaskType]", StringComparison.OrdinalIgnoreCase))) diff --git a/src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs b/src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs index 6f18056..6ef5331 100644 --- a/src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs +++ b/src/AxCopilot/Services/Agent/AgentLoopTransitions.Execution.cs @@ -1327,31 +1327,82 @@ public partial class AgentLoopService return; documentPlanCalled = true; - var po = result.Output; + var po = result.Output ?? string.Empty; var pm = System.Text.RegularExpressions.Regex.Match(po, @"path:\s*""([^""]+)"""); if (pm.Success) documentPlanPath = pm.Groups[1].Value; var tm = System.Text.RegularExpressions.Regex.Match(po, @"title:\s*""([^""]+)"""); if (tm.Success) documentPlanTitle = tm.Groups[1].Value; - var bs = po.IndexOf("--- body ?쒖옉 ---", StringComparison.Ordinal); - var be = po.IndexOf("--- body ??---", StringComparison.Ordinal); - if (bs >= 0 && be > bs) - documentPlanScaffold = po[(bs + "--- body ?쒖옉 ---".Length)..be].Trim(); + documentPlanScaffold = ExtractDocumentPlanScaffold(po); - if (!result.Output.Contains("利됱떆 ?ㅽ뻾:", StringComparison.Ordinal)) + if (!ContainsDocumentPlanFollowUpInstruction(po)) return; - var toolHint = result.Output.Contains("html_create", StringComparison.OrdinalIgnoreCase) ? "html_create" : - result.Output.Contains("document_assemble", StringComparison.OrdinalIgnoreCase) ? "document_assemble" : - result.Output.Contains("file_write", StringComparison.OrdinalIgnoreCase) ? "file_write" : "html_create"; + var toolHint = ResolveDocumentPlanFollowUpTool(po); messages.Add(new ChatMessage { Role = "user", - Content = $"document_plan???꾨즺?섏뿀?듬땲?? " + - $"??寃곌낵??body/sections??[?댁슜...] 遺€遺꾩쓣 ?ㅼ젣 ?곸꽭 ?댁슜?쇰줈 紐⑤몢 梨꾩썙??" + - $"{toolHint} ?꾧뎄瑜?吏€湲?利됱떆 ?몄텧?섏꽭?? " + - $"媛??뱀뀡留덈떎 諛섎뱶??異⑸텇???댁슜???묒꽦?섍퀬, ?ㅻ챸 ?놁씠 ?꾧뎄瑜?諛붾줈 ?몄텧?섏꽭??" + Content = + "document_plan이 완료되었습니다. " + + "방금 생성된 골격의 [내용...] 자리와 각 섹션 내용을 실제 상세 본문으로 모두 채운 뒤 " + + $"{toolHint} 도구를 지금 즉시 호출하세요. " + + "설명만 하지 말고 실제 문서 생성 도구 호출로 바로 이어가세요." }); - EmitEvent(AgentEventType.Thinking, "", $"臾몄꽌 媛쒖슂 ?꾩꽦 ??{toolHint} ?몄텧 以?.."); + EmitEvent(AgentEventType.Thinking, "", $"문서 개요 완료 · {toolHint} 실행 유도"); + } + + private static string? ExtractDocumentPlanScaffold(string output) + { + if (string.IsNullOrWhiteSpace(output)) + return null; + + var markers = new (string Start, string End)[] + { + ("--- body 시작 ---", "--- body 끝 ---"), + ("--- body start ---", "--- body end ---"), + ("", ""), + }; + + foreach (var (startMarker, endMarker) in markers) + { + var start = output.IndexOf(startMarker, StringComparison.OrdinalIgnoreCase); + if (start < 0) + continue; + + var contentStart = start + startMarker.Length; + var end = output.IndexOf(endMarker, contentStart, StringComparison.OrdinalIgnoreCase); + if (end <= contentStart) + continue; + + var scaffold = output[contentStart..end].Trim(); + if (!string.IsNullOrWhiteSpace(scaffold)) + return scaffold; + } + + return null; + } + + private static bool ContainsDocumentPlanFollowUpInstruction(string output) + { + if (string.IsNullOrWhiteSpace(output)) + return false; + + return output.Contains("즉시 실행", StringComparison.OrdinalIgnoreCase) + || output.Contains("immediate next step", StringComparison.OrdinalIgnoreCase) + || output.Contains("call html_create", StringComparison.OrdinalIgnoreCase) + || output.Contains("call document_assemble", StringComparison.OrdinalIgnoreCase); + } + + private static string ResolveDocumentPlanFollowUpTool(string output) + { + if (output.Contains("document_assemble", StringComparison.OrdinalIgnoreCase)) + return "document_assemble"; + if (output.Contains("docx_create", StringComparison.OrdinalIgnoreCase)) + return "docx_create"; + if (output.Contains("markdown_create", StringComparison.OrdinalIgnoreCase)) + return "markdown_create"; + if (output.Contains("file_write", StringComparison.OrdinalIgnoreCase)) + return "file_write"; + return "html_create"; } private void ApplyCodeQualityFollowUpTransition( diff --git a/src/AxCopilot/Services/Agent/DocumentPlannerTool.cs b/src/AxCopilot/Services/Agent/DocumentPlannerTool.cs index 5bf0fca..c3d3c9c 100644 --- a/src/AxCopilot/Services/Agent/DocumentPlannerTool.cs +++ b/src/AxCopilot/Services/Agent/DocumentPlannerTool.cs @@ -155,7 +155,9 @@ public class DocumentPlannerTool : IAgentTool output.AppendLine("(주석의 '활용 가능 요소'는 참고용이며, 내용에 맞게 다른 요소를 써도 됩니다)"); output.AppendLine(); output.AppendLine("--- body 시작 ---"); + output.AppendLine(""); output.Append(bodySb); + output.AppendLine(""); output.AppendLine("--- body 끝 ---"); output.AppendLine(); output.AppendLine("⚠ html_create를 지금 즉시 호출하세요. 모든 섹션에 충분한 실제 내용을 작성하세요."); diff --git a/src/AxCopilot/Views/ChatWindow.xaml.cs b/src/AxCopilot/Views/ChatWindow.xaml.cs index 2206b16..8736273 100644 --- a/src/AxCopilot/Views/ChatWindow.xaml.cs +++ b/src/AxCopilot/Views/ChatWindow.xaml.cs @@ -8735,7 +8735,8 @@ public partial class ChatWindow : Window sb.AppendLine("You are AX Copilot Agent. You can read, write, and edit files using the provided tools."); sb.AppendLine($"Today's date: {DateTime.Now:yyyy년 M월 d일} ({DateTime.Now:yyyy-MM-dd}, {DateTime.Now:dddd})."); sb.AppendLine("Available skills: excel_create (.xlsx), docx_create (.docx), csv_create (.csv), markdown_create (.md), html_create (.html), script_create (.bat/.ps1), document_review (품질 검증), format_convert (포맷 변환)."); - sb.AppendLine("Always explain your plan step by step BEFORE executing tools. After creating files, summarize what was created."); + sb.AppendLine("Always produce a concrete execution plan before major Cowork tasks. For document/report/proposal/manual requests, create a 3-7 step plan first, then execute it."); + sb.AppendLine("After creating files, summarize what was created and include the actual output path."); sb.AppendLine("Do not stop after a single step. Continue autonomously until the request is completed or a concrete blocker (permission denial, missing dependency, hard error) is encountered."); sb.AppendLine("When adapting external references, rewrite names/structure/comments to AX Copilot style. Avoid clone-like outputs."); sb.AppendLine("IMPORTANT: When creating documents with dates, always use today's actual date above. Never use placeholder or fictional dates."); @@ -8746,6 +8747,7 @@ public partial class ChatWindow : Window sb.AppendLine(" 3. Then immediately call html_create (or docx_create/file_write) using the scaffold from document_plan."); sb.AppendLine(" 4. Write actual detailed content for EVERY section — no skipping, no placeholders, no minimal content."); sb.AppendLine(" 5. Do NOT call html_create directly without document_plan for multi-section documents."); + sb.AppendLine(" 6. Do not finish with a plan only. The task is complete only after the document file has actually been created or updated."); // 문서 품질 검증 루프 sb.AppendLine("\n## Document Quality Review");