Files
Agent-System/internal/bizdev/task_result_status.go
T
weichenandCursor 4f5a6188a7 fix(docgov): defer fact-source update until high-risk commit
Materialize needs_confirmation restores ledger head to output.md and
document_records hash; only committed heads update DocGov. Decision
handler projects after commit or reject. Stage gates DocGov proposals
via PendingProposal, not bare RequiresAuthorApproval.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-13 09:51:15 +00:00

151 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
func (r *TaskRunResult) TerminalStatus() string {
if r == nil || !r.Success {
return TaskStatusFailed
}
if r.AwaitsAgentConfirmation() {
return TaskStatusPendingAuthorConfirmation
}
if r.QualityReport != nil && !r.QualityReport.Passed {
return TaskStatusQualityFailed
}
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
}