Compare commits
2 Commits
6bd8d5bb2c
...
36a9af8210
| Author | SHA1 | Date | |
|---|---|---|---|
| 36a9af8210 | |||
| d24c1f9edc |
15
README.md
15
README.md
@@ -7,6 +7,21 @@ Windows 전용 시맨틱 런처 & 워크스페이스 매니저
|
|||||||
개발 참고: Claw Code 동등성 작업 추적 문서
|
개발 참고: Claw Code 동등성 작업 추적 문서
|
||||||
`docs/claw-code-parity-plan.md`
|
`docs/claw-code-parity-plan.md`
|
||||||
|
|
||||||
|
- 업데이트: 2026-04-10 08:47 (KST)
|
||||||
|
- 계획 확인 UI를 AX Agent 테마에 맞춰 다시 정리했습니다. 채팅 안 승인 카드는 `LauncherBackground`/`ItemBackground`/`BorderColor`/`AccentColor`를 기준으로 표면, 버튼 모서리, 입력 패널 간격을 통일해 기본 컨트롤 느낌을 줄였습니다.
|
||||||
|
- 플랜 뷰어 창의 하단 승인 영역도 같은 시각 언어로 손봤습니다. 승인 전 안내 카드를 추가하고, 수정 입력 패널은 테마 배경과 테두리를 쓰도록 바꿨으며, 액션 버튼 호버도 `ItemHoverBackground` 중심으로 정리했습니다.
|
||||||
|
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0
|
||||||
|
|
||||||
|
- 업데이트: 2026-04-10 00:08 (KST)
|
||||||
|
- `claude-code`와 비교했을 때 AX에 남아 있던 계획 선행과 후속 권유 톤을 더 줄였습니다. 기본 Cowork/Code 루프 안에 남아 있던 plan prelude/승인용 죽은 코드를 제거해, 별도 계획 생성 단계를 끼우지 않고 바로 모델+도구 실행으로 들어갑니다.
|
||||||
|
- Code 최종 보고 재강제도 review 작업과 고영향 변경으로 좁혔습니다. 일반 수정은 변경 내용과 검증 근거가 충분하면 후속 계획이나 남은 리스크를 덧붙이도록 다시 유도하지 않고 마무리할 수 있습니다.
|
||||||
|
- Cowork/Code 시스템 프롬프트도 같은 방향으로 정리했습니다. Cowork는 새 문서 생성 시 `document_plan`을 기본 선행 단계처럼 밀지 않고 필요할 때만 쓰게 했고, Code는 마지막 보고에서 미해결 사항이 있을 때만 리스크를 언급하게 바꿨습니다.
|
||||||
|
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0
|
||||||
|
|
||||||
|
- 업데이트: 2026-04-10 00:15 (KST)
|
||||||
|
- Virtual DOM Diff 렌더 구현 완료: React reconciliation 방식의 키 기반 diff를 WPF에 적용. 렌더 체인이 StreamingAppend → Incremental → **DiffRender** → FullRender 4단계로 확장되어, prefix-match 실패 시에도 전체 재빌드 없이 변경분만 반영합니다.
|
||||||
|
- 검증: `dotnet build` 경고 0 / 오류 0
|
||||||
|
|
||||||
- 업데이트: 2026-04-09 23:02 (KST)
|
- 업데이트: 2026-04-09 23:02 (KST)
|
||||||
- IBM/Qwen 후속 호환을 한 단계 더 보강했습니다. 이제 IBM 배포형 응답에서 `generated_text`, `output_text`, `message.content`, `reasoning_content`가 문자열뿐 아니라 배열/블록 형태로 와도 텍스트를 추출하고, `content` 배열 안의 `tool_use/tool_call` 블록도 직접 읽어 도구 호출로 복구합니다.
|
- IBM/Qwen 후속 호환을 한 단계 더 보강했습니다. 이제 IBM 배포형 응답에서 `generated_text`, `output_text`, `message.content`, `reasoning_content`가 문자열뿐 아니라 배열/블록 형태로 와도 텍스트를 추출하고, `content` 배열 안의 `tool_use/tool_call` 블록도 직접 읽어 도구 호출로 복구합니다.
|
||||||
- 활성 도구 노출 순서도 다시 정리했습니다. `file_read/file_edit/glob/grep/lsp_code_intel/build_run/document_plan` 같은 기본 도구를 먼저 보여주고, `document_review/format_convert/tool_search/code_search`는 그 다음, `mcp_*`, `spawn_agent`, `wait_agents`, `task_*`는 더 뒤로 미뤄 `claude-code`처럼 기본 작업 도구가 먼저 선택되도록 했습니다.
|
- 활성 도구 노출 순서도 다시 정리했습니다. `file_read/file_edit/glob/grep/lsp_code_intel/build_run/document_plan` 같은 기본 도구를 먼저 보여주고, `document_review/format_convert/tool_search/code_search`는 그 다음, `mcp_*`, `spawn_agent`, `wait_agents`, `task_*`는 더 뒤로 미뤄 `claude-code`처럼 기본 작업 도구가 먼저 선택되도록 했습니다.
|
||||||
|
|||||||
@@ -1,6 +1,22 @@
|
|||||||
# AX Copilot - 媛쒕컻 臾몄꽌
|
# AX Copilot - 媛쒕컻 臾몄꽌
|
||||||
|
|
||||||
|
|
||||||
|
## 계획 승인 UI 테마 정렬
|
||||||
|
|
||||||
|
- 업데이트: 2026-04-10 08:47 (KST)
|
||||||
|
- `ChatWindow.AgentStatusPresentation`의 계획 승인 카드를 AX Agent 테마 리소스 기반으로 다시 정리했습니다. 승인/수정/취소 버튼의 라운드, 간격, 입력 패널 배경을 `LauncherBackground`, `ItemBackground`, `BorderColor`, `AccentColor` 축으로 통일해 채팅 본문과 더 자연스럽게 이어지도록 조정했습니다.
|
||||||
|
- `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식 계획/후속 권유 최소화
|
||||||
|
|
||||||
|
- 업데이트: 2026-04-10 00:08 (KST)
|
||||||
|
- `AgentLoopService`에서 과거 plan mode 잔재로 남아 있던 prelude/승인용 실행 계획 블록을 제거했습니다. 기본 Cowork/Code 루프는 이제 별도 “계획만 먼저 생성” 단계 없이 바로 메인 모델+도구 반복으로 들어갑니다. 사용자가 명시적으로 계획을 원할 때만 응답 텍스트 수준에서 계획을 제시하고, 루프 자체는 `claude-code`처럼 실행 중심으로 유지합니다.
|
||||||
|
- `AgentLoopTransitions.Verification`의 `FinalReportGate`는 review 작업 또는 고영향 변경일 때만 구조화된 재정리를 요구합니다. 일반 수정은 변경 내용과 검증 근거만 충분하면 “remaining risk / next action”을 추가로 다시 쓰게 하지 않습니다.
|
||||||
|
- `BuildFinalReportQualityPrompt`도 같은 기준으로 완화했습니다. 남은 리스크/추가 확인은 실제로 미해결 사항이 남아 있을 때만 적도록 바꾸고, 후속 권유는 기본이 아니라 조건부 정보로 낮췄습니다.
|
||||||
|
- `ChatWindow.SystemPromptBuilder`의 Cowork/Code 프롬프트도 조정했습니다. Cowork는 새 문서 생성 시 `document_plan`을 기본 선행 단계처럼 밀지 않고 “필요할 때만” 사용하게 했고, Code의 REPORT 단계는 “변경 내용과 검증 요약”을 기본으로 하며 미해결 리스크만 선택적으로 언급하게 바꿨습니다.
|
||||||
|
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0
|
||||||
|
|
||||||
## claude-code식 후속 호환/선택성 보강
|
## claude-code식 후속 호환/선택성 보강
|
||||||
|
|
||||||
- 업데이트: 2026-04-09 23:02 (KST)
|
- 업데이트: 2026-04-09 23:02 (KST)
|
||||||
|
|||||||
@@ -239,9 +239,6 @@ public partial class AgentLoopService
|
|||||||
var recentTaskRetryQuality = TryGetRecentTaskRetryQuality(taskPolicy.TaskType);
|
var recentTaskRetryQuality = TryGetRecentTaskRetryQuality(taskPolicy.TaskType);
|
||||||
maxRetry = ComputeQualityAwareMaxRetry(maxRetry, recentTaskRetryQuality, taskPolicy.TaskType);
|
maxRetry = ComputeQualityAwareMaxRetry(maxRetry, recentTaskRetryQuality, taskPolicy.TaskType);
|
||||||
|
|
||||||
// 플랜 prelude는 현재 정책상 비활성
|
|
||||||
var shouldGeneratePlanPrelude = false;
|
|
||||||
|
|
||||||
var context = BuildContext();
|
var context = BuildContext();
|
||||||
InjectTaskTypeGuidance(messages, taskPolicy);
|
InjectTaskTypeGuidance(messages, taskPolicy);
|
||||||
InjectExplorationScopeGuidance(messages, explorationState.Scope);
|
InjectExplorationScopeGuidance(messages, explorationState.Scope);
|
||||||
@@ -340,148 +337,6 @@ public partial class AgentLoopService
|
|||||||
workFolder = context.WorkFolder
|
workFolder = context.WorkFolder
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// ── 과거 plan mode 잔재. 현재 정책상 비활성 ──
|
|
||||||
if (shouldGeneratePlanPrelude)
|
|
||||||
{
|
|
||||||
iteration++;
|
|
||||||
EmitEvent(AgentEventType.Thinking, "", "실행 계획 생성 중...");
|
|
||||||
|
|
||||||
// 계획 생성 전용 시스템 지시를 임시 추가
|
|
||||||
var planInstruction = new ChatMessage
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Content = "[System] 도구를 호출하지 마세요. 먼저 실행 계획을 번호 매긴 단계로 작성하세요. " +
|
|
||||||
"각 단계에 사용할 도구와 대상을 구체적으로 명시하세요. " +
|
|
||||||
"계획만 제시하고 실행은 하지 마세요."
|
|
||||||
};
|
|
||||||
messages.Add(planInstruction);
|
|
||||||
|
|
||||||
// 도구 없이 텍스트만 요청
|
|
||||||
string planText;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
planText = await _llm.SendAsync(messages, ct);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
EmitEvent(AgentEventType.Error, "", $"LLM 오류: {ex.Message}");
|
|
||||||
return $"⚠ LLM 오류: {ex.Message}";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 계획 지시 메시지 제거 (실제 실행 시 혼란 방지)
|
|
||||||
messages.Remove(planInstruction);
|
|
||||||
|
|
||||||
// 계획 추출
|
|
||||||
planSteps = TaskDecomposer.ExtractSteps(planText);
|
|
||||||
planExtracted = true;
|
|
||||||
|
|
||||||
if (planSteps.Count > 0)
|
|
||||||
{
|
|
||||||
EmitEvent(AgentEventType.Planning, "", $"작업 계획: {planSteps.Count}단계",
|
|
||||||
steps: planSteps);
|
|
||||||
|
|
||||||
// 사용자 승인 대기
|
|
||||||
if (UserDecisionCallback != null)
|
|
||||||
{
|
|
||||||
EmitEvent(
|
|
||||||
AgentEventType.Decision,
|
|
||||||
"",
|
|
||||||
$"계획 확인 대기 · {planSteps.Count}단계",
|
|
||||||
steps: planSteps);
|
|
||||||
|
|
||||||
var decision = await UserDecisionCallback(
|
|
||||||
planText,
|
|
||||||
new List<string> { "승인", "수정 요청", "취소" });
|
|
||||||
EmitPlanDecisionResultEvent(decision, planSteps);
|
|
||||||
|
|
||||||
if (decision == "취소")
|
|
||||||
{
|
|
||||||
EmitEvent(AgentEventType.Complete, "", "작업이 중단되었습니다");
|
|
||||||
return "작업이 중단되었습니다.";
|
|
||||||
}
|
|
||||||
else if (TryParseApprovedPlanDecision(decision, out var approvedPlanText, out var approvedPlanSteps))
|
|
||||||
{
|
|
||||||
planText = approvedPlanText;
|
|
||||||
planSteps = approvedPlanSteps;
|
|
||||||
}
|
|
||||||
else if (decision != null && decision != "승인")
|
|
||||||
{
|
|
||||||
// 수정 요청 — 피드백으로 계획 재생성
|
|
||||||
messages.Add(new ChatMessage { Role = "assistant", Content = planText });
|
|
||||||
messages.Add(new ChatMessage { Role = "user", Content = decision + "\n위 피드백을 반영하여 실행 계획을 다시 작성하세요." });
|
|
||||||
|
|
||||||
// 재생성 루프 (최대 3회)
|
|
||||||
for (int retry = 0; retry < 3; retry++)
|
|
||||||
{
|
|
||||||
try { planText = await _llm.SendAsync(messages, ct); }
|
|
||||||
catch { break; }
|
|
||||||
|
|
||||||
planSteps = TaskDecomposer.ExtractSteps(planText);
|
|
||||||
if (planSteps.Count > 0)
|
|
||||||
{
|
|
||||||
EmitEvent(AgentEventType.Planning, "", $"수정된 계획: {planSteps.Count}단계",
|
|
||||||
steps: planSteps);
|
|
||||||
}
|
|
||||||
|
|
||||||
EmitEvent(
|
|
||||||
AgentEventType.Decision,
|
|
||||||
"",
|
|
||||||
$"수정 계획 확인 대기 · {planSteps.Count}단계",
|
|
||||||
steps: planSteps);
|
|
||||||
|
|
||||||
decision = await UserDecisionCallback(
|
|
||||||
planText,
|
|
||||||
new List<string> { "승인", "수정 요청", "취소" });
|
|
||||||
EmitPlanDecisionResultEvent(decision, planSteps);
|
|
||||||
|
|
||||||
if (decision == "취소")
|
|
||||||
{
|
|
||||||
EmitEvent(AgentEventType.Complete, "", "작업이 중단되었습니다");
|
|
||||||
return "작업이 중단되었습니다.";
|
|
||||||
}
|
|
||||||
if (TryParseApprovedPlanDecision(decision, out var revisedPlanText, out var revisedPlanSteps))
|
|
||||||
{
|
|
||||||
planText = revisedPlanText;
|
|
||||||
planSteps = revisedPlanSteps;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (decision == null || decision == "승인") break;
|
|
||||||
|
|
||||||
// 재수정
|
|
||||||
messages.Add(new ChatMessage { Role = "assistant", Content = planText });
|
|
||||||
messages.Add(new ChatMessage { Role = "user", Content = decision + "\n위 피드백을 반영하여 실행 계획을 다시 작성하세요." });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 승인된 계획을 컨텍스트에 포함하여 실행 유도
|
|
||||||
// 도구 호출을 명확히 강제하여 텍스트 응답만 반환하는 경우 방지
|
|
||||||
messages.Add(new ChatMessage { Role = "assistant", Content = planText });
|
|
||||||
|
|
||||||
// 1차 계획의 단계들을 document_plan의 sections_hint로 전달하도록 지시
|
|
||||||
// → BuildSections() 하드코딩 대신 LLM이 잡은 섹션 구조가 문서에 반영됨
|
|
||||||
var planSectionsHint = planSteps.Count > 0
|
|
||||||
? string.Join(", ", planSteps)
|
|
||||||
: "";
|
|
||||||
var sectionInstruction = !string.IsNullOrEmpty(planSectionsHint)
|
|
||||||
? $"document_plan 도구를 호출할 때 sections_hint 파라미터에 위 계획의 섹션/단계를 그대로 넣으세요: \"{planSectionsHint}\""
|
|
||||||
: "";
|
|
||||||
|
|
||||||
messages.Add(new ChatMessage { Role = "user",
|
|
||||||
Content = "계획이 승인되었습니다. 지금 즉시 1단계부터 도구(tool)를 호출하여 실행을 시작하세요. " +
|
|
||||||
"텍스트로 설명하지 말고 반드시 도구를 호출하세요." +
|
|
||||||
(string.IsNullOrEmpty(sectionInstruction) ? "" : "\n" + sectionInstruction) });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 계획 추출 실패 — assistant 응답으로 추가하고 일반 모드로 진행
|
|
||||||
if (!string.IsNullOrEmpty(planText))
|
|
||||||
messages.Add(new ChatMessage { Role = "assistant", Content = planText });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (iteration < maxIterations && !ct.IsCancellationRequested)
|
while (iteration < maxIterations && !ct.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
iteration++;
|
iteration++;
|
||||||
@@ -3538,8 +3393,8 @@ public partial class AgentLoopService
|
|||||||
private static string BuildFinalReportQualityPrompt(TaskTypePolicy taskPolicy, bool highImpact)
|
private static string BuildFinalReportQualityPrompt(TaskTypePolicy taskPolicy, bool highImpact)
|
||||||
{
|
{
|
||||||
var taskLine = taskPolicy.FinalReportTaskLine;
|
var taskLine = taskPolicy.FinalReportTaskLine;
|
||||||
var riskLine = highImpact
|
var riskLine = taskPolicy.IsReviewTask || highImpact
|
||||||
? "고영향 변경이므로 남은 리스크나 추가 확인 필요 사항도 반드시 적으세요.\n"
|
? "남은 리스크나 추가 확인 필요 사항이 실제로 남아 있을 때만 짧게 적으세요.\n"
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
return "[System:FinalReportQuality] 최종 답변을 더 구조적으로 정리하세요.\n" +
|
return "[System:FinalReportQuality] 최종 답변을 더 구조적으로 정리하세요.\n" +
|
||||||
@@ -3551,7 +3406,7 @@ public partial class AgentLoopService
|
|||||||
"6. review 작업이면 이슈별로 수정 완료/미수정 상태를 분리해 적으세요\n" +
|
"6. review 작업이면 이슈별로 수정 완료/미수정 상태를 분리해 적으세요\n" +
|
||||||
taskLine +
|
taskLine +
|
||||||
riskLine +
|
riskLine +
|
||||||
"가능하면 짧고 명확하게 요약하세요.";
|
"후속 권유는 실제 미해결 위험이나 추가 확인이 남았을 때만 포함하세요. 가능하면 짧고 명확하게 요약하세요.";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string BuildFinalReportQualityPrompt(string taskType, bool highImpact)
|
private static string BuildFinalReportQualityPrompt(string taskType, bool highImpact)
|
||||||
|
|||||||
@@ -55,9 +55,11 @@ public partial class AgentLoopService
|
|||||||
var hasDiffEvidence = HasDiffEvidenceAfterLastModification(messages);
|
var hasDiffEvidence = HasDiffEvidenceAfterLastModification(messages);
|
||||||
var hasRecentBuildOrTestEvidence = HasBuildOrTestEvidenceAfterLastModification(messages);
|
var hasRecentBuildOrTestEvidence = HasBuildOrTestEvidenceAfterLastModification(messages);
|
||||||
var hasSuccessfulBuildAndTestEvidence = HasSuccessfulBuildAndTestAfterLastModification(messages);
|
var hasSuccessfulBuildAndTestEvidence = HasSuccessfulBuildAndTestAfterLastModification(messages);
|
||||||
|
var hasLightweightCompletionEvidence = hasCodeVerificationEvidence
|
||||||
|
|| hasDiffEvidence
|
||||||
|
|| hasRecentBuildOrTestEvidence;
|
||||||
if (executionPolicy.CodeVerificationGateMaxRetries > 0
|
if (executionPolicy.CodeVerificationGateMaxRetries > 0
|
||||||
&& !hasCodeVerificationEvidence
|
&& !(requireHighImpactCodeVerification ? hasCodeVerificationEvidence : hasLightweightCompletionEvidence)
|
||||||
&& !(hasDiffEvidence && hasRecentBuildOrTestEvidence && !requireHighImpactCodeVerification)
|
|
||||||
&& runState.CodeVerificationGateRetry < executionPolicy.CodeVerificationGateMaxRetries)
|
&& runState.CodeVerificationGateRetry < executionPolicy.CodeVerificationGateMaxRetries)
|
||||||
{
|
{
|
||||||
runState.CodeVerificationGateRetry++;
|
runState.CodeVerificationGateRetry++;
|
||||||
@@ -93,9 +95,12 @@ public partial class AgentLoopService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasBlockingCodeEvidenceGap = !hasCodeVerificationEvidence
|
var hasBlockingCodeEvidenceGap = !(requireHighImpactCodeVerification ? hasCodeVerificationEvidence : hasLightweightCompletionEvidence)
|
||||||
|| (requireHighImpactCodeVerification && !hasSuccessfulBuildAndTestEvidence);
|
|| (requireHighImpactCodeVerification && !hasSuccessfulBuildAndTestEvidence);
|
||||||
|
var shouldRequestStructuredFinalReport =
|
||||||
|
taskPolicy.IsReviewTask || requireHighImpactCodeVerification;
|
||||||
if (executionPolicy.FinalReportGateMaxRetries > 0
|
if (executionPolicy.FinalReportGateMaxRetries > 0
|
||||||
|
&& shouldRequestStructuredFinalReport
|
||||||
&& !hasBlockingCodeEvidenceGap
|
&& !hasBlockingCodeEvidenceGap
|
||||||
&& !HasSufficientFinalReportEvidence(textResponse, taskPolicy, requireHighImpactCodeVerification, messages)
|
&& !HasSufficientFinalReportEvidence(textResponse, taskPolicy, requireHighImpactCodeVerification, messages)
|
||||||
&& runState.FinalReportGateRetry < executionPolicy.FinalReportGateMaxRetries)
|
&& runState.FinalReportGateRetry < executionPolicy.FinalReportGateMaxRetries)
|
||||||
|
|||||||
1586
src/AxCopilot/Views/ChatWindow.AgentStatusPresentation.cs
Normal file
1586
src/AxCopilot/Views/ChatWindow.AgentStatusPresentation.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -61,10 +61,10 @@ public partial class ChatWindow
|
|||||||
sb.AppendLine($"Today's date: {DateTime.Now:yyyy년 M월 d일} ({DateTime.Now:yyyy-MM-dd}, {DateTime.Now:dddd}).");
|
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("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 when the task is too ambiguous to execute safely.");
|
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 real artifact.");
|
||||||
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("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 document_plan when helpful, then immediately call the creation tool such as docx_create, html_create, markdown_create, excel_create, or document_assemble.");
|
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.");
|
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("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("When adapting external references, rewrite names/structure/comments to AX Copilot style. Avoid clone-like outputs.");
|
||||||
@@ -239,7 +239,7 @@ public partial class ChatWindow
|
|||||||
sb.AppendLine("3. IMPLEMENT: Apply the smallest safe edit. Use file_edit for existing files and file_write for new files.");
|
sb.AppendLine("3. IMPLEMENT: Apply the smallest safe edit. Use file_edit for existing files and file_write for new files.");
|
||||||
sb.AppendLine("4. VERIFY: Run build_run/test_loop when the change affects buildable or testable behavior, or when the user explicitly asks for verification.");
|
sb.AppendLine("4. VERIFY: Run build_run/test_loop when the change affects buildable or testable behavior, or when the user explicitly asks for verification.");
|
||||||
sb.AppendLine(" - Use git_tool(diff) when it helps confirm the final change set or explain what changed.");
|
sb.AppendLine(" - Use git_tool(diff) when it helps confirm the final change set or explain what changed.");
|
||||||
sb.AppendLine("5. REPORT: Summarize what changed, what was verified, and any remaining risk.");
|
sb.AppendLine("5. REPORT: Summarize what changed and what was verified. Mention remaining risk only when something is actually unresolved.");
|
||||||
|
|
||||||
sb.AppendLine("\n## Development Environment");
|
sb.AppendLine("\n## Development Environment");
|
||||||
sb.AppendLine("Use dev_env_detect to check installed IDEs, runtimes, and build tools before running commands.");
|
sb.AppendLine("Use dev_env_detect to check installed IDEs, runtimes, and build tools before running commands.");
|
||||||
|
|||||||
@@ -859,11 +859,30 @@ internal sealed class PlanViewerWindow : Window
|
|||||||
_btnPanel.Children.Clear();
|
_btnPanel.Children.Clear();
|
||||||
var accentBrush = Application.Current.TryFindResource("AccentColor") as Brush
|
var accentBrush = Application.Current.TryFindResource("AccentColor") as Brush
|
||||||
?? new SolidColorBrush(Color.FromRgb(0x4B, 0x5E, 0xFC));
|
?? new SolidColorBrush(Color.FromRgb(0x4B, 0x5E, 0xFC));
|
||||||
|
var secondaryText = Application.Current.TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||||
|
var accentColor = accentBrush is SolidColorBrush accentSolid ? accentSolid.Color : Color.FromRgb(0x4B, 0x5E, 0xFC);
|
||||||
|
|
||||||
var approveLabel = _uiExpressionLevel == "simple" ? "승인" : "승인 후 실행";
|
var approveLabel = _uiExpressionLevel == "simple" ? "승인" : "승인 후 실행";
|
||||||
var editLabel = _uiExpressionLevel == "simple" ? "수정" : "수정 피드백";
|
var editLabel = _uiExpressionLevel == "simple" ? "수정" : "수정 피드백";
|
||||||
var rejectLabel = _uiExpressionLevel == "simple" ? "취소" : "거부";
|
var rejectLabel = _uiExpressionLevel == "simple" ? "취소" : "거부";
|
||||||
|
|
||||||
|
_btnPanel.Children.Add(new Border
|
||||||
|
{
|
||||||
|
Background = new SolidColorBrush(Color.FromArgb(0x16, accentColor.R, accentColor.G, accentColor.B)),
|
||||||
|
BorderBrush = new SolidColorBrush(Color.FromArgb(0x40, accentColor.R, accentColor.G, accentColor.B)),
|
||||||
|
BorderThickness = new Thickness(1),
|
||||||
|
CornerRadius = new CornerRadius(10),
|
||||||
|
Padding = new Thickness(12, 8, 12, 8),
|
||||||
|
Margin = new Thickness(0, 0, 12, 0),
|
||||||
|
Child = new TextBlock
|
||||||
|
{
|
||||||
|
Text = "검토가 끝나면 바로 실행하거나 방향만 짧게 남길 수 있습니다.",
|
||||||
|
FontSize = 11.5,
|
||||||
|
Foreground = secondaryText,
|
||||||
|
TextWrapping = TextWrapping.Wrap,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var approveBtn = CreateActionButton("\uE73E", approveLabel, accentBrush, Brushes.White, true);
|
var approveBtn = CreateActionButton("\uE73E", approveLabel, accentBrush, Brushes.White, true);
|
||||||
approveBtn.MouseLeftButtonUp += (_, _) =>
|
approveBtn.MouseLeftButtonUp += (_, _) =>
|
||||||
{
|
{
|
||||||
@@ -904,20 +923,31 @@ internal sealed class PlanViewerWindow : Window
|
|||||||
|
|
||||||
private void ShowEditInput()
|
private void ShowEditInput()
|
||||||
{
|
{
|
||||||
|
var itemBackground = Application.Current.TryFindResource("ItemBackground") as Brush
|
||||||
|
?? new SolidColorBrush(Color.FromRgb(0x2A, 0x2B, 0x40));
|
||||||
|
var launcherBackground = Application.Current.TryFindResource("LauncherBackground") as Brush
|
||||||
|
?? new SolidColorBrush(Color.FromRgb(0x1A, 0x1B, 0x2E));
|
||||||
|
var primaryText = Application.Current.TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||||
|
var secondaryText = Application.Current.TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||||
|
var borderBrush = Application.Current.TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
||||||
|
var accentBrush = Application.Current.TryFindResource("AccentColor") as Brush
|
||||||
|
?? new SolidColorBrush(Color.FromRgb(0x4B, 0x5E, 0xFC));
|
||||||
|
|
||||||
var editPanel = new Border
|
var editPanel = new Border
|
||||||
{
|
{
|
||||||
Margin = new Thickness(20, 0, 20, 12),
|
Margin = new Thickness(20, 0, 20, 12),
|
||||||
Padding = new Thickness(12, 8, 12, 8),
|
Padding = new Thickness(14, 12, 14, 12),
|
||||||
CornerRadius = new CornerRadius(10),
|
CornerRadius = new CornerRadius(12),
|
||||||
Background = Application.Current.TryFindResource("ItemBackground") as Brush
|
Background = itemBackground,
|
||||||
?? new SolidColorBrush(Color.FromRgb(0x2A, 0x2B, 0x40)),
|
BorderBrush = borderBrush,
|
||||||
|
BorderThickness = new Thickness(1),
|
||||||
};
|
};
|
||||||
var editStack = new StackPanel();
|
var editStack = new StackPanel();
|
||||||
editStack.Children.Add(new TextBlock
|
editStack.Children.Add(new TextBlock
|
||||||
{
|
{
|
||||||
Text = "수정 사항을 입력하세요:",
|
Text = "어떤 방향으로 바꾸면 좋을지 짧게 남겨주세요.",
|
||||||
FontSize = 11.5,
|
FontSize = 11.5,
|
||||||
Foreground = Application.Current.TryFindResource("SecondaryText") as Brush ?? Brushes.Gray,
|
Foreground = secondaryText,
|
||||||
Margin = new Thickness(0, 0, 0, 6),
|
Margin = new Thickness(0, 0, 0, 6),
|
||||||
});
|
});
|
||||||
var textBox = new TextBox
|
var textBox = new TextBox
|
||||||
@@ -927,29 +957,32 @@ internal sealed class PlanViewerWindow : Window
|
|||||||
AcceptsReturn = true,
|
AcceptsReturn = true,
|
||||||
TextWrapping = TextWrapping.Wrap,
|
TextWrapping = TextWrapping.Wrap,
|
||||||
FontSize = 13,
|
FontSize = 13,
|
||||||
Background = Application.Current.TryFindResource("LauncherBackground") as Brush
|
Background = launcherBackground,
|
||||||
?? new SolidColorBrush(Color.FromRgb(0x1A, 0x1B, 0x2E)),
|
Foreground = primaryText,
|
||||||
Foreground = Application.Current.TryFindResource("PrimaryText") as Brush ?? Brushes.White,
|
CaretBrush = primaryText,
|
||||||
CaretBrush = Application.Current.TryFindResource("PrimaryText") as Brush ?? Brushes.White,
|
BorderBrush = borderBrush,
|
||||||
BorderBrush = Application.Current.TryFindResource("BorderColor") as Brush ?? Brushes.Gray,
|
|
||||||
BorderThickness = new Thickness(1),
|
BorderThickness = new Thickness(1),
|
||||||
Padding = new Thickness(10, 8, 10, 8),
|
Padding = new Thickness(10, 8, 10, 8),
|
||||||
};
|
};
|
||||||
editStack.Children.Add(textBox);
|
editStack.Children.Add(textBox);
|
||||||
|
|
||||||
var accentBrush = Application.Current.TryFindResource("AccentColor") as Brush
|
var actionRow = new StackPanel
|
||||||
?? new SolidColorBrush(Color.FromRgb(0x4B, 0x5E, 0xFC));
|
{
|
||||||
|
Orientation = Orientation.Horizontal,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Right,
|
||||||
|
Margin = new Thickness(0, 8, 0, 0),
|
||||||
|
};
|
||||||
|
|
||||||
var sendBtn = new Border
|
var sendBtn = new Border
|
||||||
{
|
{
|
||||||
Background = accentBrush,
|
Background = accentBrush,
|
||||||
CornerRadius = new CornerRadius(8),
|
CornerRadius = new CornerRadius(8),
|
||||||
Padding = new Thickness(14, 6, 14, 6),
|
Padding = new Thickness(14, 6, 14, 6),
|
||||||
Margin = new Thickness(0, 8, 0, 0),
|
Margin = new Thickness(0, 0, 8, 0),
|
||||||
Cursor = Cursors.Hand,
|
Cursor = Cursors.Hand,
|
||||||
HorizontalAlignment = HorizontalAlignment.Right,
|
|
||||||
Child = new TextBlock
|
Child = new TextBlock
|
||||||
{
|
{
|
||||||
Text = "전송", FontSize = 12.5, FontWeight = FontWeights.SemiBold, Foreground = Brushes.White,
|
Text = "수정 요청 보내기", FontSize = 12.5, FontWeight = FontWeights.SemiBold, Foreground = Brushes.White,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
sendBtn.MouseEnter += (s, _) => ((Border)s).Opacity = 0.85;
|
sendBtn.MouseEnter += (s, _) => ((Border)s).Opacity = 0.85;
|
||||||
@@ -960,7 +993,36 @@ internal sealed class PlanViewerWindow : Window
|
|||||||
if (string.IsNullOrEmpty(feedback)) return;
|
if (string.IsNullOrEmpty(feedback)) return;
|
||||||
_tcs?.TrySetResult(feedback);
|
_tcs?.TrySetResult(feedback);
|
||||||
};
|
};
|
||||||
editStack.Children.Add(sendBtn);
|
actionRow.Children.Add(sendBtn);
|
||||||
|
|
||||||
|
var closeBtn = new Border
|
||||||
|
{
|
||||||
|
Background = Brushes.Transparent,
|
||||||
|
BorderBrush = borderBrush,
|
||||||
|
BorderThickness = new Thickness(1),
|
||||||
|
CornerRadius = new CornerRadius(8),
|
||||||
|
Padding = new Thickness(14, 6, 14, 6),
|
||||||
|
Cursor = Cursors.Hand,
|
||||||
|
Child = new TextBlock
|
||||||
|
{
|
||||||
|
Text = "닫기",
|
||||||
|
FontSize = 12.5,
|
||||||
|
FontWeight = FontWeights.SemiBold,
|
||||||
|
Foreground = secondaryText,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
closeBtn.MouseEnter += (s, _) => ((Border)s).Background = itemBackground;
|
||||||
|
closeBtn.MouseLeave += (s, _) => ((Border)s).Background = Brushes.Transparent;
|
||||||
|
closeBtn.MouseLeftButtonUp += (_, _) =>
|
||||||
|
{
|
||||||
|
if (editPanel.Parent is Grid grid)
|
||||||
|
{
|
||||||
|
grid.Children.Remove(editPanel);
|
||||||
|
_btnPanel.Margin = new Thickness(20, 12, 20, 16);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
actionRow.Children.Add(closeBtn);
|
||||||
|
editStack.Children.Add(actionRow);
|
||||||
editPanel.Child = editStack;
|
editPanel.Child = editStack;
|
||||||
|
|
||||||
if (_btnPanel.Parent is Grid parentGrid)
|
if (_btnPanel.Parent is Grid parentGrid)
|
||||||
@@ -1008,10 +1070,12 @@ internal sealed class PlanViewerWindow : Window
|
|||||||
Brush textColor, bool filled)
|
Brush textColor, bool filled)
|
||||||
{
|
{
|
||||||
var color = ((SolidColorBrush)borderColor).Color;
|
var color = ((SolidColorBrush)borderColor).Color;
|
||||||
|
var hoverBg = Application.Current?.TryFindResource("ItemHoverBackground") as Brush
|
||||||
|
?? new SolidColorBrush(Color.FromArgb(0x18, 0xFF, 0xFF, 0xFF));
|
||||||
var btn = new Border
|
var btn = new Border
|
||||||
{
|
{
|
||||||
CornerRadius = new CornerRadius(12),
|
CornerRadius = new CornerRadius(14),
|
||||||
Padding = new Thickness(16, 8, 16, 8),
|
Padding = new Thickness(16, 9, 16, 9),
|
||||||
Margin = new Thickness(4, 0, 4, 0),
|
Margin = new Thickness(4, 0, 4, 0),
|
||||||
Cursor = Cursors.Hand,
|
Cursor = Cursors.Hand,
|
||||||
Background = filled ? borderColor
|
Background = filled ? borderColor
|
||||||
@@ -1033,8 +1097,20 @@ internal sealed class PlanViewerWindow : Window
|
|||||||
Foreground = filled ? Brushes.White : textColor,
|
Foreground = filled ? Brushes.White : textColor,
|
||||||
});
|
});
|
||||||
btn.Child = sp;
|
btn.Child = sp;
|
||||||
btn.MouseEnter += (s, _) => ((Border)s).Opacity = 0.85;
|
btn.MouseEnter += (s, _) =>
|
||||||
btn.MouseLeave += (s, _) => ((Border)s).Opacity = 1.0;
|
{
|
||||||
|
var border = (Border)s;
|
||||||
|
border.Opacity = 0.96;
|
||||||
|
if (!filled)
|
||||||
|
border.Background = hoverBg;
|
||||||
|
};
|
||||||
|
btn.MouseLeave += (s, _) =>
|
||||||
|
{
|
||||||
|
var border = (Border)s;
|
||||||
|
border.Opacity = 1.0;
|
||||||
|
if (!filled)
|
||||||
|
border.Background = new SolidColorBrush(Color.FromArgb(0x18, color.R, color.G, color.B));
|
||||||
|
};
|
||||||
return btn;
|
return btn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user