返回 DeepSeek-Reasonix
subagent_store_terminal.go
根目录 / internal / agent / subagent_store_terminal.go
1 package agent
2
3 import (
4 "errors"
5 "fmt"
6 "time"
7 )
8
9 func (s *SubagentStore) SaveCompleted(run *SubagentRun) error {
10 return s.SaveOutcome(run, SubagentOutcome{Ref: runRef(run), Status: SubagentOutcomeCompleted})
11 }
12
13 func (s *SubagentStore) SaveFailed(run *SubagentRun) error {
14 return s.SaveOutcome(run, SubagentOutcome{Ref: runRef(run), Status: SubagentOutcomeFailed})
15 }
16
17 func (s *SubagentStore) SaveOutcome(run *SubagentRun, outcome SubagentOutcome) error {
18 if s == nil || run == nil || run.Ref == "" || s.parentDestroyed(run) {
19 return nil
20 }
21 if run.terminalPersisted {
22 if terminalOutcomeAlreadyRecorded(run.Meta, outcome) {
23 return nil
24 }
25 return fmt.Errorf("subagent %q already has a persisted terminal outcome", run.Ref)
26 }
27 if terminalOutcomeAlreadyRecorded(run.Meta, outcome) {
28 return nil
29 }
30 branchErr := s.ensureBranchCreatedAt(run)
31 var sessionErr error
32 if run.Session != nil {
33 sessionErr = run.Session.Save(s.sessionPath(run.Ref))
34 }
35 meta := run.Meta
36 switch outcome.Status {
37 case SubagentOutcomeCompleted:
38 meta.Status = SubagentCompleted
39 case SubagentOutcomeCancelled:
40 meta.Status = SubagentInterrupted
41 default:
42 meta.Status = SubagentFailed
43 }
44 meta.Outcome = string(outcome.Status)
45 meta.Retryable = outcome.Retryable
46 meta.ErrorCode = outcome.ErrorCode
47 meta.UpdatedAt = time.Now().UTC()
48 run.Meta = meta
49 err := errors.Join(branchErr, sessionErr, s.saveMeta(meta))
50 if err == nil {
51 run.terminalPersisted = true
52 }
53 return err
54 }
55
56 func terminalOutcomeAlreadyRecorded(meta SubagentMeta, outcome SubagentOutcome) bool {
57 if meta.Outcome == "" {
58 return false
59 }
60 if meta.Outcome != string(outcome.Status) || meta.Retryable != outcome.Retryable || meta.ErrorCode != outcome.ErrorCode {
61 return false
62 }
63 switch outcome.Status {
64 case SubagentOutcomeCompleted:
65 return meta.Status == SubagentCompleted
66 case SubagentOutcomeCancelled:
67 return meta.Status == SubagentInterrupted
68 case SubagentOutcomePartial, SubagentOutcomeFailed:
69 return meta.Status == SubagentFailed
70 default:
71 return false
72 }
73 }
74
75 func runRef(run *SubagentRun) string {
76 if run == nil {
77 return ""
78 }
79 return run.Ref
80 }
81
81 lines GO