모델 프로파일 기반 Cowork/Code 루프와 진행 UX 고도화 반영
- 등록 모델 실행 프로파일을 검증 게이트, 문서 fallback, post-tool verification까지 확장 적용 - Cowork/Code 진행 카드에 계획/도구/검증/압축/폴백/재시도 단계 메타를 추가해 대기 상태 가시성 강화 - OpenAI/vLLM tool 요청에 병렬 도구 호출 힌트를 추가하고 회귀 프롬프트 문서를 프로파일 기준으로 전면 정리 - 검증: 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:
@@ -147,7 +147,19 @@ public sealed class AxAgentExecutionEngine
|
||||
|
||||
if (session != null)
|
||||
{
|
||||
session.AppendMessage(tab, assistant, storage);
|
||||
// session.CurrentConversation이 전달된 conversation과 다른 경우 (새 대화 시작 등),
|
||||
// session을 통하지 않고 conversation에 직접 추가하여 새 대화가 오염되지 않도록 함.
|
||||
if (session.CurrentConversation == null ||
|
||||
string.Equals(session.CurrentConversation.Id, conversation.Id, StringComparison.Ordinal))
|
||||
{
|
||||
session.AppendMessage(tab, assistant, storage);
|
||||
}
|
||||
else
|
||||
{
|
||||
conversation.Messages.Add(assistant);
|
||||
conversation.UpdatedAt = DateTime.Now;
|
||||
try { storage?.Save(conversation); } catch { }
|
||||
}
|
||||
return assistant;
|
||||
}
|
||||
|
||||
@@ -197,23 +209,7 @@ public sealed class AxAgentExecutionEngine
|
||||
if (!string.IsNullOrWhiteSpace(content))
|
||||
return content;
|
||||
|
||||
var latestEventSummary = conversation.ExecutionEvents?
|
||||
.Where(evt => !string.IsNullOrWhiteSpace(evt.Summary))
|
||||
.OrderByDescending(evt => evt.Timestamp)
|
||||
.Select(evt => evt.Summary.Trim())
|
||||
.FirstOrDefault();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(latestEventSummary))
|
||||
{
|
||||
return runTab switch
|
||||
{
|
||||
"Cowork" => $"코워크 작업이 완료되었습니다.\n\n{latestEventSummary}",
|
||||
"Code" => $"코드 작업이 완료되었습니다.\n\n{latestEventSummary}",
|
||||
_ => latestEventSummary,
|
||||
};
|
||||
}
|
||||
|
||||
return "(빈 응답)";
|
||||
return BuildFallbackCompletionMessage(conversation, runTab);
|
||||
}
|
||||
|
||||
public FinalizedContent FinalizeExecutionContent(string? currentContent, Exception? error = null, bool cancelled = false)
|
||||
@@ -276,23 +272,59 @@ public sealed class AxAgentExecutionEngine
|
||||
if (!string.IsNullOrWhiteSpace(content))
|
||||
return content;
|
||||
|
||||
var latestEventSummary = conversation.ExecutionEvents?
|
||||
.Where(evt => !string.IsNullOrWhiteSpace(evt.Summary))
|
||||
return BuildFallbackCompletionMessage(conversation, runTab);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LLM 응답이 비어있을 때 실행 이벤트에서 의미 있는 완료 메시지를 구성합니다.
|
||||
/// UserPromptSubmit/Paused/Resumed 같은 내부 운영 이벤트는 제외합니다.
|
||||
/// </summary>
|
||||
private static string BuildFallbackCompletionMessage(ChatConversation conversation, string runTab)
|
||||
{
|
||||
static bool IsSignificantEventType(string t)
|
||||
=> !string.Equals(t, "UserPromptSubmit", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(t, "Paused", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(t, "Resumed", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(t, "SessionStart", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var completionLine = runTab switch
|
||||
{
|
||||
"Cowork" => "코워크 작업이 완료되었습니다.",
|
||||
"Code" => "코드 작업이 완료되었습니다.",
|
||||
_ => null,
|
||||
};
|
||||
|
||||
// 파일 경로가 있는 이벤트를 최우선으로 — 산출물 파일을 명시적으로 표시
|
||||
var artifactEvent = conversation.ExecutionEvents?
|
||||
.Where(evt => !string.IsNullOrWhiteSpace(evt.FilePath) && IsSignificantEventType(evt.Type))
|
||||
.OrderByDescending(evt => evt.Timestamp)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (artifactEvent != null)
|
||||
{
|
||||
var fileLine = string.IsNullOrWhiteSpace(artifactEvent.Summary)
|
||||
? $"생성된 파일: {artifactEvent.FilePath}"
|
||||
: $"{artifactEvent.Summary}\n경로: {artifactEvent.FilePath}";
|
||||
return completionLine != null
|
||||
? $"{completionLine}\n\n{fileLine}"
|
||||
: fileLine;
|
||||
}
|
||||
|
||||
// 파일 없으면 가장 최근 의미 있는 이벤트 요약 사용
|
||||
var latestSummary = conversation.ExecutionEvents?
|
||||
.Where(evt => !string.IsNullOrWhiteSpace(evt.Summary) && IsSignificantEventType(evt.Type))
|
||||
.OrderByDescending(evt => evt.Timestamp)
|
||||
.Select(evt => evt.Summary.Trim())
|
||||
.FirstOrDefault();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(latestEventSummary))
|
||||
if (!string.IsNullOrWhiteSpace(latestSummary))
|
||||
{
|
||||
return runTab switch
|
||||
{
|
||||
"Cowork" => $"코워크 작업이 완료되었습니다.\n\n{latestEventSummary}",
|
||||
"Code" => $"코드 작업이 완료되었습니다.\n\n{latestEventSummary}",
|
||||
_ => latestEventSummary,
|
||||
};
|
||||
return completionLine != null
|
||||
? $"{completionLine}\n\n{latestSummary}"
|
||||
: latestSummary;
|
||||
}
|
||||
|
||||
return "(빈 응답)";
|
||||
return completionLine ?? "(빈 응답)";
|
||||
}
|
||||
|
||||
private static ChatMessage CloneMessage(ChatMessage source)
|
||||
|
||||
Reference in New Issue
Block a user