From 5511c620de1e4b1666e9d39087c6541ec678d4d6 Mon Sep 17 00:00:00 2001 From: lacvet Date: Fri, 10 Apr 2026 09:00:10 +0900 Subject: [PATCH] =?UTF-8?q?AX=20Agent=EC=9D=98=20Cowork=C2=B7Code=20?= =?UTF-8?q?=EA=B0=95=EC=A0=9C=20=EB=A1=9C=EC=A7=81=EC=9D=84=20claude-code?= =?UTF-8?q?=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EC=99=84=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cowork·Code 프롬프트의 text-only 완료 조건을 완화하고, 실제 산출물 생성이나 코드 수정이 필요한 경우에만 도구 재강제를 걸도록 AgentLoopService를 조정했다. Code 검증 게이트는 diff 또는 최근 build/test 근거가 있으면 중복 재검증을 덜 하도록 줄였고, docs 정책은 creation tool 우선 + document_plan 선택형으로 정리했으며 folder_map 노출 우선순위를 한 단계 낮췄다. README.md와 docs/DEVELOPMENT.md에 2026-04-10 09: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 | 10 ++++++++++ .../Services/Agent/AgentLoopService.cs | 20 ++++++++++++++----- .../AgentLoopTransitions.Verification.cs | 14 +++++++++---- .../Services/Agent/TaskTypePolicy.cs | 19 +++++++++++------- src/AxCopilot/Services/Agent/ToolRegistry.cs | 4 ++-- .../Views/ChatWindow.SystemPromptBuilder.cs | 8 ++++---- 7 files changed, 59 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 4d1ce80..31bac08 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,12 @@ Windows 전용 시맨틱 런처 & 워크스페이스 매니저 개발 참고: Claw Code 동등성 작업 추적 문서 `docs/claw-code-parity-plan.md` +- 업데이트: 2026-04-10 09:02 (KST) +- `claude-code` 기준으로 Cowork/Code의 남은 차이를 더 줄였습니다. Cowork/Code 프롬프트의 텍스트-only 완료 조건을 완화해, 작업이 이미 끝났거나 충분한 근거가 있을 때는 불필요한 도구 호출을 더 강제하지 않도록 정리했습니다. +- 에이전트 루프도 같이 손봤습니다. 텍스트-only 재시도는 이제 실제 산출물 생성이나 코드 수정처럼 구체적인 실행이 필요한 경우에만 다시 도구를 강제하고, 문서 생성 fallback도 같은 범위로 좁혔습니다. +- Code 검증 게이트는 `diff` 또는 최근 build/test 근거가 이미 있으면 추가 재검증을 덜 하도록 줄였고, `folder_map`은 기본 노출 우선순위에서 한 단계 내려 보조 탐색 도구로 배치했습니다. +- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0 + - 업데이트: 2026-04-10 08:47 (KST) - 계획 확인 UI를 AX Agent 테마에 맞춰 다시 정리했습니다. 채팅 안 승인 카드는 `LauncherBackground`/`ItemBackground`/`BorderColor`/`AccentColor`를 기준으로 표면, 버튼 모서리, 입력 패널 간격을 통일해 기본 컨트롤 느낌을 줄였습니다. - 플랜 뷰어 창의 하단 승인 영역도 같은 시각 언어로 손봤습니다. 승인 전 안내 카드를 추가하고, 수정 입력 패널은 테마 배경과 테두리를 쓰도록 바꿨으며, 액션 버튼 호버도 `ItemHoverBackground` 중심으로 정리했습니다. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 659021f..f34812d 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -8,6 +8,16 @@ - `PlanViewerWindow`의 승인 단계 UI도 같은 방향으로 손봤습니다. 승인 버튼 영역 앞에 검토 안내 카드를 추가하고, 수정 피드백 입력 패널은 테마 배경/테두리를 사용하며, 액션 버튼 호버는 단순 opacity 대신 `ItemHoverBackground` 계열로 반응하도록 바꿨습니다. - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0 +## claude-code식 Cowork/Code 강제 로직 추가 완화 + +- 업데이트: 2026-04-10 09:02 (KST) +- `ChatWindow.SystemPromptBuilder`에서 Cowork/Code의 text-only 완료 조건을 더 현실적으로 완화했습니다. 작업이 이미 완료됐거나 충분한 근거가 확보된 경우에는 불필요한 도구 호출을 더 강제하지 않도록 정리했고, 새 문서 생성 시에도 `document_plan`은 선택적 구조 보조 단계로만 남겼습니다. +- `AgentLoopService`의 no-tool recovery와 `ForceToolCallAfterPlan`도 `claude-code` 기준에 맞춰 축소했습니다. 이제 Cowork는 실제 문서 생성 요청, Code는 bugfix/feature/refactor처럼 구체 수정이 필요한 경우에만 다시 도구를 강제하고, 분석형/설명형 응답은 불필요하게 재루프시키지 않습니다. +- 문서 fallback도 같은 기준으로 좁혔습니다. `document_plan` 이후 `html_create` 재유도나 앱 직접 생성 fallback은 실제 산출물 생성이 필요한 경우에만 작동합니다. +- `AgentLoopTransitions.Verification`은 일반 Code 완료 조건을 더 얇게 바꿨습니다. 최근 `build/test` 또는 `git diff` 근거가 이미 있으면 `CodeDiffGate`, `RecentExecutionGate`, `ExecutionSuccessGate`가 중복 발동하지 않도록 줄였습니다. +- `TaskTypePolicy`의 docs 가이드와 `ToolRegistry`의 노출 우선순위도 정리했습니다. docs는 `document_plan first` 고정에서 벗어나 creation tool 우선 + `document_plan` 선택형으로 바뀌었고, `folder_map`은 최상위 기본 도구에서 한 단계 내려 보조 탐색 도구로 재배치했습니다. +- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0 + ## claude-code식 계획/후속 권유 최소화 - 업데이트: 2026-04-10 00:08 (KST) diff --git a/src/AxCopilot/Services/Agent/AgentLoopService.cs b/src/AxCopilot/Services/Agent/AgentLoopService.cs index d64f6b4..4115b91 100644 --- a/src/AxCopilot/Services/Agent/AgentLoopService.cs +++ b/src/AxCopilot/Services/Agent/AgentLoopService.cs @@ -718,7 +718,13 @@ public partial class AgentLoopService // 도구 호출이 없으면 루프 종료 — 단, 문서 생성 요청인데 파일이 미생성이면 자동 저장 if (toolCalls.Count == 0) { - if (totalToolCalls == 0 + var requiresConcreteArtifactOrEdit = + string.Equals(ActiveTab, "Code", StringComparison.OrdinalIgnoreCase) + ? taskPolicy.TaskType is "bugfix" or "feature" or "refactor" + : IsDocumentCreationRequest(userQuery); + + if (requiresConcreteArtifactOrEdit + && totalToolCalls == 0 && consecutiveNoToolResponses >= noToolResponseThreshold && runState.NoToolCallLoopRetry < noToolRecoveryMaxRetries) { @@ -763,7 +769,8 @@ public partial class AgentLoopService // 계획이 있고 도구가 아직 한 번도 실행되지 않은 경우 → LLM이 도구 대신 텍스트로만 응답한 것 // "계획이 승인됐으니 도구를 호출하라"는 메시지를 추가하여 재시도 (최대 2회) - if (executionPolicy.ForceToolCallAfterPlan + if (requiresConcreteArtifactOrEdit + && executionPolicy.ForceToolCallAfterPlan && planSteps.Count > 0 && totalToolCalls == 0 && planExecutionRetry < planExecutionRetryMax) @@ -796,7 +803,8 @@ public partial class AgentLoopService } // 문서 생성 우선 프로파일은 재시도보다 빠른 fallback을 우선합니다. - if (documentPlanCalled + if (requiresConcreteArtifactOrEdit + && documentPlanCalled && executionPolicy.PreferAggressiveDocumentFallback && !string.IsNullOrEmpty(documentPlanScaffold) && !_docFallbackAttempted) @@ -805,7 +813,8 @@ public partial class AgentLoopService } // document_plan은 호출됐지만 terminal 문서 도구(html_create 등)가 미호출인 경우 → 프로파일 기준 재시도 - if (documentPlanCalled && postDocumentPlanRetry < documentPlanRetryMax) + if (requiresConcreteArtifactOrEdit + && documentPlanCalled && postDocumentPlanRetry < documentPlanRetryMax) { postDocumentPlanRetry++; if (!string.IsNullOrEmpty(textResponse)) @@ -820,7 +829,8 @@ public partial class AgentLoopService } // 재시도도 모두 소진 → 앱이 직접 본문 생성 후 html_create 강제 실행 - if (documentPlanCalled && !string.IsNullOrEmpty(documentPlanScaffold) && !_docFallbackAttempted) + if (requiresConcreteArtifactOrEdit + && documentPlanCalled && !string.IsNullOrEmpty(documentPlanScaffold) && !_docFallbackAttempted) { _docFallbackAttempted = true; EmitEvent(AgentEventType.Thinking, "", "LLM이 html_create를 호출하지 않아 앱에서 직접 문서를 생성합니다..."); diff --git a/src/AxCopilot/Services/Agent/AgentLoopTransitions.Verification.cs b/src/AxCopilot/Services/Agent/AgentLoopTransitions.Verification.cs index 82db6cf..38cadbc 100644 --- a/src/AxCopilot/Services/Agent/AgentLoopTransitions.Verification.cs +++ b/src/AxCopilot/Services/Agent/AgentLoopTransitions.Verification.cs @@ -55,9 +55,9 @@ public partial class AgentLoopService var hasDiffEvidence = HasDiffEvidenceAfterLastModification(messages); var hasRecentBuildOrTestEvidence = HasBuildOrTestEvidenceAfterLastModification(messages); var hasSuccessfulBuildAndTestEvidence = HasSuccessfulBuildAndTestAfterLastModification(messages); - var hasLightweightCompletionEvidence = hasCodeVerificationEvidence - || hasDiffEvidence - || hasRecentBuildOrTestEvidence; + var hasLightweightCompletionEvidence = requireHighImpactCodeVerification + ? hasCodeVerificationEvidence + : hasDiffEvidence || hasRecentBuildOrTestEvidence || hasCodeVerificationEvidence; if (executionPolicy.CodeVerificationGateMaxRetries > 0 && !(requireHighImpactCodeVerification ? hasCodeVerificationEvidence : hasLightweightCompletionEvidence) && runState.CodeVerificationGateRetry < executionPolicy.CodeVerificationGateMaxRetries) @@ -132,7 +132,7 @@ public partial class AgentLoopService if (executionPolicy.CodeDiffGateMaxRetries <= 0 || runState.CodeDiffGateRetry >= executionPolicy.CodeDiffGateMaxRetries) return false; - if (HasDiffEvidenceAfterLastModification(messages)) + if (HasDiffEvidenceAfterLastModification(messages) || HasBuildOrTestEvidenceAfterLastModification(messages)) return false; runState.CodeDiffGateRetry++; @@ -160,6 +160,9 @@ public partial class AgentLoopService if (executionPolicy.RecentExecutionGateMaxRetries <= 0 || runState.RecentExecutionGateRetry >= executionPolicy.RecentExecutionGateMaxRetries) return false; + if (HasDiffEvidenceAfterLastModification(messages)) + return false; + if (!HasAnyBuildOrTestEvidence(messages)) return false; @@ -191,6 +194,9 @@ public partial class AgentLoopService if (executionPolicy.ExecutionSuccessGateMaxRetries <= 0 || runState.ExecutionSuccessGateRetry >= executionPolicy.ExecutionSuccessGateMaxRetries) return false; + if (HasDiffEvidenceAfterLastModification(messages)) + return false; + if (!HasAnyBuildOrTestAttempt(messages)) return false; diff --git a/src/AxCopilot/Services/Agent/TaskTypePolicy.cs b/src/AxCopilot/Services/Agent/TaskTypePolicy.cs index 6b53f72..c54fdd9 100644 --- a/src/AxCopilot/Services/Agent/TaskTypePolicy.cs +++ b/src/AxCopilot/Services/Agent/TaskTypePolicy.cs @@ -22,7 +22,7 @@ internal sealed class TaskTypePolicy TaskType = "bugfix", GuidanceMessage = "[System:TaskType] This is a bug-fix task. Prioritize reproduction evidence, root cause linkage, smallest safe fix, and regression verification. " + - "Preferred tool order: file_read -> grep/glob -> build_run/test_loop -> file_edit -> build_run/test_loop.", + "Preferred tool order: targeted file_read or grep/glob/lsp -> file_edit -> build_run/test_loop as needed -> git_tool(diff) when it helps confirm the final change.", FailurePatternFocus = "재현 조건과 원인 연결을 먼저 확인하세요. Check reproduction conditions and root-cause linkage first.", FollowUpTaskLine = "작업 유형: bugfix. Task type: bugfix. Verify the fix is directly linked to the symptom and confirm non-regression.\n", FailureInvestigationTaskLine = "추가 점검: 재현 조건 기준으로 증상이 재현되지 않는지와 원인 연결이 타당한지 확인하세요. Extra check: confirm the symptom is no longer reproducible and root-cause linkage is valid.\n", @@ -33,7 +33,8 @@ internal sealed class TaskTypePolicy TaskType = "feature", GuidanceMessage = "[System:TaskType] This is a feature task. Prioritize affected interfaces/callers, data flow, validation paths, and test/documentation needs. " + - "Preferred tool order: folder_map -> file_read -> grep/glob -> file_edit -> build_run/test_loop.", + "Preferred tool order: targeted file_read or grep/glob/lsp -> file_edit/file_write -> build_run/test_loop as needed -> git_tool(diff). " + + "Use folder_map only when the user explicitly needs folder structure or file listing.", FailurePatternFocus = "Check new behavior flow and caller linkage first.", FollowUpTaskLine = "작업 유형: feature. Task type: feature. Verify behavior flow, input/output path, caller impact, and test additions.\n", FailureInvestigationTaskLine = "추가 점검: 새 기능 경로와 호출부 연결이 의도대로 동작하는지 확인하세요. Extra check: confirm feature path and caller linkage behave as intended.\n", @@ -44,7 +45,7 @@ internal sealed class TaskTypePolicy TaskType = "refactor", GuidanceMessage = "[System:TaskType] This is a refactor task. Prioritize behavior preservation, reference impact, diff review, and non-regression evidence. " + - "Preferred tool order: file_read -> grep/glob -> git_tool(diff) -> file_edit -> build_run/test_loop.", + "Preferred tool order: targeted file_read or grep/glob/lsp -> file_edit -> build_run/test_loop as needed -> git_tool(diff).", FailurePatternFocus = "Check behavior preservation and impact scope first.", FollowUpTaskLine = "작업 유형: refactor. Task type: refactor. Prioritize behavior-preservation evidence over cosmetic cleanup.\n", FailureInvestigationTaskLine = "추가 점검: 동작 보존 관점에서 기존 호출 흐름이 동일하게 유지되는지 확인하세요. Extra check: validate existing call flow remains behavior-compatible.\n", @@ -56,7 +57,7 @@ internal sealed class TaskTypePolicy GuidanceMessage = "[System:TaskType] This is a review task. Prioritize concrete defects, regressions, risky assumptions, and missing tests before summaries. " + "Report findings with P0-P3 severity and file evidence, then separate Fixed vs Unfixed status. " + - "Preferred tool order: file_read -> grep/glob -> git_tool(diff) -> evidence-first findings.", + "Preferred tool order: targeted file_read or grep/glob/lsp -> git_tool(diff) when available -> evidence-first findings.", FailurePatternFocus = "Review focus: severity accuracy (P0-P3), file-grounded evidence, and unresolved-risk clarity.", FollowUpTaskLine = "작업 유형: review-follow-up. Task type: review-follow-up. For each finding, state status as Fixed or Unfixed with verification evidence.\n", FailureInvestigationTaskLine = "추가 점검: 리뷰에서 지적된 위험은 반드시 수정 근거나 미해결 사유/영향을 남기세요. Extra check: every risk must have either a concrete fix or an explicit unresolved rationale and impact.\n", @@ -67,8 +68,12 @@ internal sealed class TaskTypePolicy { TaskType = "docs", GuidanceMessage = - "[System:TaskType] This is a document/content task. Prioritize source evidence, completeness, consistency, and self-review. " + - "Preferred tool order: folder_map -> document_read/file_read -> drafting tool -> self-review.", + "[System:TaskType] This is a document/content task. " + + "If the user asks you to CREATE/WRITE a new document, skip file exploration entirely — " + + "go directly to the creation tool (docx_create, html_create, excel_create, etc.) and use document_plan only when it materially helps structure a multi-section document. " + + "to produce a REAL FILE on disk. Do NOT respond with text only — the output MUST be a file. " + + "If the user asks you to READ/ANALYZE existing documents, use: glob/grep -> document_read/file_read -> analysis. " + + "Use folder_map only when the user explicitly asks for folder contents or directory structure.", FailurePatternFocus = "Check source evidence and document completeness first.", FollowUpTaskLine = "", FailureInvestigationTaskLine = "", @@ -77,7 +82,7 @@ internal sealed class TaskTypePolicy _ => new TaskTypePolicy { TaskType = "general", - GuidanceMessage = "[System:TaskType] Use a cautious analyze -> implement -> verify workflow and do not finish without concrete evidence.", + GuidanceMessage = "[System:TaskType] Use a cautious analyze -> selective discovery -> implement -> verify workflow. Prefer targeted file_read, grep/glob, or lsp_code_intel before broad scans, and do not finish without concrete evidence.", FailurePatternFocus = "Check recent failure patterns first.", FollowUpTaskLine = "", FailureInvestigationTaskLine = "", diff --git a/src/AxCopilot/Services/Agent/ToolRegistry.cs b/src/AxCopilot/Services/Agent/ToolRegistry.cs index 4e3b9c3..dc571c4 100644 --- a/src/AxCopilot/Services/Agent/ToolRegistry.cs +++ b/src/AxCopilot/Services/Agent/ToolRegistry.cs @@ -92,11 +92,11 @@ public class ToolRegistry : IDisposable { return tool.Name switch { - "file_read" or "file_write" or "file_edit" or "glob" or "grep" or "folder_map" or "document_read" + "file_read" or "file_write" or "file_edit" or "glob" or "grep" or "document_read" or "process" or "dev_env_detect" or "build_run" or "git_tool" or "lsp_code_intel" or "document_plan" or "document_assemble" or "docx_create" or "html_create" or "markdown_create" or "excel_create" or "csv_create" or "pptx_create" or "chart_create" => 0, - "document_review" or "format_convert" or "tool_search" or "code_search" => 1, + "folder_map" or "document_review" or "format_convert" or "tool_search" or "code_search" => 1, "mcp_list_resources" or "mcp_read_resource" or "spawn_agent" or "wait_agents" => 2, _ when tool.Name.StartsWith("task_", StringComparison.OrdinalIgnoreCase) => 3, _ => 1 diff --git a/src/AxCopilot/Views/ChatWindow.SystemPromptBuilder.cs b/src/AxCopilot/Views/ChatWindow.SystemPromptBuilder.cs index a3b1dc2..cda5e0a 100644 --- a/src/AxCopilot/Views/ChatWindow.SystemPromptBuilder.cs +++ b/src/AxCopilot/Views/ChatWindow.SystemPromptBuilder.cs @@ -27,7 +27,7 @@ public partial class ChatWindow sb.AppendLine("모든 응답에는 반드시 하나 이상의 도구 호출이 포함되어야 합니다."); sb.AppendLine("텍스트만 있고 도구 호출이 없는 응답은 무효이며 즉시 거부됩니다."); sb.AppendLine("Use tools whenever they materially advance the task. Do not answer with text only when inspection, file creation, editing, or verification is still needed."); - sb.AppendLine("A text-only response is fine once the requested artifact already exists or enough evidence has been gathered."); + sb.AppendLine("A text-only response is fine once the requested artifact already exists, the requested analysis is complete, or enough evidence has been gathered."); sb.AppendLine("출력의 첫 번째 항목은 반드시 도구 호출이어야 합니다. 텍스트로 시작하는 것은 금지입니다."); sb.AppendLine("When a tool is clearly useful, call it promptly without a long preamble. Do not force an unnecessary tool call if the task is already complete."); sb.AppendLine(""); @@ -62,7 +62,7 @@ public partial class ChatWindow 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("\nOnly present a step-by-step plan when the user explicitly asks for a plan or a short execution outline is required to unblock the task safely."); - sb.AppendLine("For ordinary Cowork requests, proceed directly with the work and focus on producing the real artifact."); + sb.AppendLine("For ordinary Cowork requests, proceed directly with the work and focus on producing the requested result."); sb.AppendLine("If the user asks for a brand-new report, proposal, analysis, manual, or other document and does not explicitly ask to reference workspace files, do NOT start with glob, grep, document_read, or folder_map."); sb.AppendLine("In that case, go straight to the creation tool. Use document_plan only when it materially improves a multi-section document."); sb.AppendLine("After creating files, summarize what was created and include the actual output path."); @@ -126,7 +126,7 @@ public partial class ChatWindow case "active": sb.AppendLine("IMPORTANT: Folder Data Usage = ACTIVE. You have 'document_read' and 'folder_map' tools available."); sb.AppendLine("Use workspace exploration only when the user explicitly asks to reference existing materials, provides a file/path hint, or asks about folder contents."); - sb.AppendLine("For brand-new document creation requests, skip glob/grep/document_read/folder_map and proceed directly to document_plan plus the creation tool."); + sb.AppendLine("For brand-new document creation requests, skip glob/grep/document_read/folder_map and proceed directly to the creation tool. Use document_plan only when structure work materially improves the output."); sb.AppendLine("[CRITICAL] FILE SELECTION STRATEGY — DO NOT READ ALL FILES:"); sb.AppendLine(" 1. Identify candidate files by filename or topic keywords first."); sb.AppendLine(" 2. Read ONLY files that clearly match the user's topic. Skip unrelated topics."); @@ -184,7 +184,7 @@ public partial class ChatWindow sb.AppendLine("모든 응답에는 반드시 하나 이상의 도구 호출이 포함되어야 합니다."); sb.AppendLine("텍스트만 있고 도구 호출이 없는 응답은 무효이며 즉시 거부됩니다."); sb.AppendLine("Use tools whenever they materially advance the task. Do not answer with text only when code inspection, editing, diff review, or verification is still needed."); - sb.AppendLine("A text-only response is fine once the requested code change is complete or enough evidence has been gathered."); + sb.AppendLine("A text-only response is fine once the requested code work is complete or enough evidence has been gathered."); sb.AppendLine("출력의 첫 번째 항목은 반드시 도구 호출이어야 합니다. 텍스트로 시작하는 것은 금지입니다."); sb.AppendLine("When a tool is clearly useful, call it promptly without a long preamble. Do not force an unnecessary tool call if the task is already complete."); sb.AppendLine("");