코워크 문서 계획/생성 흐름을 claw-code 기준으로 복구
- 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)
This commit is contained in:
@@ -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<ChatMessage> messages, TaskTypePolicy taskPolicy)
|
||||
{
|
||||
if (messages.Any(m => m.Role == "user" && m.Content.StartsWith("[System:TaskType]", StringComparison.OrdinalIgnoreCase)))
|
||||
|
||||
@@ -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 ---"),
|
||||
("<!-- body start marker -->", "<!-- body end marker -->"),
|
||||
};
|
||||
|
||||
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(
|
||||
|
||||
@@ -155,7 +155,9 @@ public class DocumentPlannerTool : IAgentTool
|
||||
output.AppendLine("(주석의 '활용 가능 요소'는 참고용이며, 내용에 맞게 다른 요소를 써도 됩니다)");
|
||||
output.AppendLine();
|
||||
output.AppendLine("--- body 시작 ---");
|
||||
output.AppendLine("<!-- body start marker -->");
|
||||
output.Append(bodySb);
|
||||
output.AppendLine("<!-- body end marker -->");
|
||||
output.AppendLine("--- body 끝 ---");
|
||||
output.AppendLine();
|
||||
output.AppendLine("⚠ html_create를 지금 즉시 호출하세요. 모든 섹션에 충분한 실제 내용을 작성하세요.");
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user