受控小队任务服务端启用修复预算;否定性自检引用不再误报;quality_failed 保持失败且不激活未过门禁稿。 Co-authored-by: Cursor <cursoragent@cursor.com>
155 lines
4.8 KiB
Go
155 lines
4.8 KiB
Go
package bizdev
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
"chat-agent-system/internal/squad"
|
||
)
|
||
|
||
// Terminal task statuses projected to chat / workflow_runs.
|
||
const (
|
||
TaskStatusCompleted = "completed"
|
||
TaskStatusFailed = "failed"
|
||
TaskStatusQualityFailed = "quality_failed"
|
||
TaskStatusPendingAuthorConfirmation = "pending_author_confirmation"
|
||
)
|
||
|
||
// AwaitsAgentConfirmation reports high/critical revision candidate awaiting author decision.
|
||
// Distinct from DocGov change-proposal intercept (PendingProposal).
|
||
func (r *TaskRunResult) AwaitsAgentConfirmation() bool {
|
||
return r != nil && r.PendingAgentCandidateID > 0
|
||
}
|
||
|
||
// IsProposalIntercept reports claimed-document DocGov change-proposal interception.
|
||
func (r *TaskRunResult) IsProposalIntercept() bool {
|
||
return r != nil && r.PendingProposal != nil && r.RequiresAuthorApproval
|
||
}
|
||
|
||
// TerminalStatus maps TaskRunResult to a conversation/workflow terminal status.
|
||
// Pending agent confirmation is never "completed" until commit+projection.
|
||
// Quality failure stays quality_failed even when Success was cleared to block Materialize.
|
||
func (r *TaskRunResult) TerminalStatus() string {
|
||
if r == nil {
|
||
return TaskStatusFailed
|
||
}
|
||
if r.QualityReport != nil && !r.QualityReport.Passed {
|
||
return TaskStatusQualityFailed
|
||
}
|
||
if !r.Success {
|
||
return TaskStatusFailed
|
||
}
|
||
if r.AwaitsAgentConfirmation() {
|
||
return TaskStatusPendingAuthorConfirmation
|
||
}
|
||
return TaskStatusCompleted
|
||
}
|
||
|
||
// CompletionSummary builds the assistant-visible completion text for sync and async finalizers.
|
||
func (r *TaskRunResult) CompletionSummary() string {
|
||
if r == nil {
|
||
return "任务执行失败。"
|
||
}
|
||
title := r.ArtifactTitle
|
||
if title == "" && r.TaskKey != "" {
|
||
title = squad.TaskArtifactTitle(r.TaskKey)
|
||
}
|
||
if title == "" {
|
||
title = "交付文档"
|
||
}
|
||
|
||
status := r.TerminalStatus()
|
||
var b strings.Builder
|
||
|
||
switch status {
|
||
case TaskStatusPendingAuthorConfirmation:
|
||
fmt.Fprintf(&b, "《%s》文档候选已生成,待编制人确认。\n\n", title)
|
||
b.WriteString("当前状态:**待编制人确认**")
|
||
if r.PendingRiskLevel != "" {
|
||
fmt.Fprintf(&b, "(风险:%s)", r.PendingRiskLevel)
|
||
}
|
||
b.WriteString("\n正式正文仍为账本当前 head;候选正文仅保留在不可变快照中。请打开文档「待确认报告」确认提交或拒绝后,正式正文才会更新。")
|
||
if r.PendingConfirmationNote != "" {
|
||
fmt.Fprintf(&b, "\n%s", r.PendingConfirmationNote)
|
||
}
|
||
fmt.Fprintf(&b, "\n候选 ID:%d", r.PendingAgentCandidateID)
|
||
if r.PendingChangeReportID > 0 {
|
||
fmt.Fprintf(&b, " · 变更报告:%d", r.PendingChangeReportID)
|
||
}
|
||
case TaskStatusQualityFailed:
|
||
fmt.Fprintf(&b, "《%s》已生成。\n\n", title)
|
||
b.WriteString("当前状态:**质量检查未通过,待整改**")
|
||
if r.QualityReport != nil {
|
||
fmt.Fprintf(&b, "\n质量评分:%.0f/100", r.QualityReport.Score)
|
||
if len(r.QualityReport.Violations) > 0 {
|
||
fmt.Fprintf(&b, "\n主要问题:%s", strings.Join(r.QualityReport.Violations, ";"))
|
||
}
|
||
}
|
||
case TaskStatusCompleted:
|
||
fmt.Fprintf(&b, "《%s》已生成。\n\n", title)
|
||
b.WriteString("当前状态:**已完成**")
|
||
if r.QualityReport != nil && r.QualityReport.Passed {
|
||
fmt.Fprintf(&b, "\n质量评分:%.0f/100", r.QualityReport.Score)
|
||
}
|
||
default:
|
||
fmt.Fprintf(&b, "《%s》未成功落盘。\n\n", title)
|
||
if r.ErrorReason != "" {
|
||
fmt.Fprintf(&b, "执行未成功:%s", r.ErrorReason)
|
||
} else {
|
||
b.WriteString("任务执行失败。")
|
||
}
|
||
}
|
||
|
||
if r.DocRecord != nil && r.DocRecord.DocID != "" {
|
||
fmt.Fprintf(&b, "\n\n📄 受控文档:`%s`", r.DocRecord.DocID)
|
||
}
|
||
return b.String()
|
||
}
|
||
|
||
// ArtifactMetadata returns chat metadata fields for a clickable document entry.
|
||
func (r *TaskRunResult) ArtifactMetadata() map[string]any {
|
||
if r == nil {
|
||
return nil
|
||
}
|
||
docID := ""
|
||
if r.DocRecord != nil {
|
||
docID = r.DocRecord.DocID
|
||
}
|
||
if docID == "" {
|
||
return nil
|
||
}
|
||
title := r.ArtifactTitle
|
||
if title == "" && r.TaskKey != "" {
|
||
title = squad.TaskArtifactTitle(r.TaskKey)
|
||
}
|
||
out := map[string]any{
|
||
"doc_id": docID,
|
||
"title": title,
|
||
"task_key": r.TaskKey,
|
||
}
|
||
if r.WorkDir != "" {
|
||
out["workspace_id"] = r.WorkDir
|
||
}
|
||
if r.DocRecord != nil && r.DocRecord.ContentSHA256 != "" {
|
||
out["sha256"] = r.DocRecord.ContentSHA256
|
||
}
|
||
if r.QualityReport != nil {
|
||
out["quality_passed"] = r.QualityReport.Passed
|
||
out["quality_score"] = r.QualityReport.Score
|
||
if len(r.QualityReport.Violations) > 0 {
|
||
out["quality_violations"] = r.QualityReport.Violations
|
||
}
|
||
}
|
||
if r.AwaitsAgentConfirmation() {
|
||
out["pending_agent_candidate_id"] = r.PendingAgentCandidateID
|
||
if r.PendingChangeReportID > 0 {
|
||
out["pending_change_report_id"] = r.PendingChangeReportID
|
||
}
|
||
if r.PendingRiskLevel != "" {
|
||
out["pending_risk_level"] = r.PendingRiskLevel
|
||
}
|
||
out["awaiting_author_confirmation"] = true
|
||
}
|
||
return out
|
||
}
|