Files
Agent-System/internal/server/task_finalize.go
T
weichen a9c9a9182e refactor(server): remove 24 mirrored Runtime fields via nil-safe accessors; fix Shutdown-vs-background-loop DATA RACE and goose 00071 duplicate version
- Server no longer mirrors app.Runtime services (gov/svc/pwSvc/...): 574 call sites now use accessors in runtime_accessors.go
- backgroundLoop (mutex+sync.Once) stops sweeper/publisher/reminder/wsGC goroutines race-free (baseline 44161d2a reproduced DATA RACE; now green under -race)
- goose 00071 duplicate (dialogue merge 1da17a28 brought two 00071): context-conflict-adjudications renumbered to 00072; dev DB applied only through 00070 so zero data migration
- task_finalize tests build minimal app.Runtime; test injection via serverTestOverrides + setOverride* (explicit-nil markers for fail-closed cases)
2026-09-25 13:17:22 +00:00

120 lines
3.3 KiB
Go

package server
import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"chat-agent-system/internal/bizdev"
"chat-agent-system/internal/squad"
"chat-agent-system/internal/taskrun"
"chat-agent-system/internal/workspace"
)
// FinalizeTaskRunProjection 将任务执行结果投影到 workflow_runs 与聊天助手消息(供回填/管理命令使用)。
func (s *Server) FinalizeTaskRunProjection(ctx context.Context, record *taskrun.RunRecord, result *bizdev.TaskRunResult) (string, error) {
return s.finalizeTaskRun(ctx, record, result)
}
// finalizeTaskRun 是薄适配:产物哈希在事务外经 workspace.Capability 读取,终态命令交给 taskrun.Commands。
func (s *Server) finalizeTaskRun(ctx context.Context, record *taskrun.RunRecord, result *bizdev.TaskRunResult) (string, error) {
if record == nil || result == nil {
return "failed", fmt.Errorf("finalize: missing record or result")
}
if result.DocRecord != nil && result.DocRecord.ContentSHA256 == "" {
if hexSum := s.hashDeliverable(ctx, record, result); hexSum != "" {
result.DocRecord.ContentSHA256 = hexSum
}
}
cmds := s.taskCommands()
if s != nil {
cmds.PW = s.pwSvc()
cmds.Ctx = s.ctxMgr()
}
status, err := cmds.Finalize(ctx, record, result)
if err != nil {
return status, err
}
if status == "completed" && record.AssistantMsgID > 0 {
summaryContent := result.CompletionSummary()
s.ingestAssistantReply(ctx, record, summaryContent, status)
}
return status, nil
}
func (s *Server) taskCommands() *taskrun.Commands {
if s != nil && s.cmds() != nil {
return s.cmds()
}
cmds := &taskrun.Commands{
PW: s.pwSvc(),
Env: "test",
}
if s != nil && s.cfg != nil {
cmds.Env = s.cfg.Env
cmds.StorageIdentity = "env:" + s.cfg.Env
}
if s != nil {
cmds.Ctx = s.ctxMgr()
}
return cmds
}
func (s *Server) hashDeliverable(ctx context.Context, record *taskrun.RunRecord, result *bizdev.TaskRunResult) string {
if s == nil || s.wsCap() == nil || record == nil {
return ""
}
id := workspace.OpaqueID(result.WorkDir, record.WorkspaceID)
if id == "" {
return ""
}
env := ""
if s.cfg != nil {
env = s.cfg.Env
}
ref := workspace.WorkspaceRef{
ID: id,
SchemaVersion: workspace.SchemaVersion,
ProjectScope: record.ProjectID,
RunID: record.RunID,
Environment: env,
}
body, err := s.wsCap().ReadArtifact(ctx, ref, workspace.DeliverableKey)
if err != nil || len(body) == 0 {
return ""
}
sum := sha256.Sum256(body)
return hex.EncodeToString(sum[:])
}
func resolveTerminalStatus(result *bizdev.TaskRunResult) string {
return result.TerminalStatus()
}
func buildTaskCompletionSummary(result *bizdev.TaskRunResult, terminalStatus string) string {
_ = terminalStatus
return result.CompletionSummary()
}
func squadResultToTaskRun(res *squad.SquadRunResult, taskKey string) *bizdev.TaskRunResult {
if res == nil {
return nil
}
return &bizdev.TaskRunResult{
TaskKey: res.TaskKey,
ArtifactTitle: res.ArtifactTitle,
MarkdownBody: res.MarkdownBody,
ExtractedData: res.ExtractedData,
Attachments: res.Attachments,
WorkDir: res.WorkDir,
BackendUsed: res.BackendUsed,
Duration: res.Duration,
Success: res.Success,
ErrorReason: res.ErrorReason,
QualityReport: res.QualityReport,
Manifest: res.Manifest,
AdvisorBrief: res.AdvisorBrief,
}
}