返回 DeepSeek-Reasonix
claim_live.go
根目录 / internal / agent / claim_live.go
1 package agent
2
3 // liveClaim is one active writer slot: the declared capability bound plus the
4 // paths actually reserved at runtime.
5 type liveClaim struct {
6 id int64
7 writer bool
8 declared WritePathSet
9 realized []string
10 opaque bool
11 // callerParentClaim is the parent claim this claim runs inside, which it
12 // does not conflict with.
13 callerParentClaim int64
14 }
15
16 func (c liveClaim) reservation() WritePathSet {
17 if c.opaque {
18 return wholeReservation(c.declared.WorkspaceRoot)
19 }
20 if len(c.realized) > 0 {
21 return fileReservation(c.declared.WorkspaceRoot, c.realized)
22 }
23 if c.declared.WholeWorkspace {
24 return c.declared
25 }
26 if c.dirOnlyDeclared() {
27 return WritePathSet{}
28 }
29 return c.declared
30 }
31
32 func (c liveClaim) dirOnlyDeclared() bool {
33 if c.declared.WholeWorkspace || len(c.declared.Paths) == 0 {
34 return false
35 }
36 for i := range c.declared.Paths {
37 if c.declared.kindAt(i) != pathKindDir {
38 return false
39 }
40 }
41 return true
42 }
43
44 func wholeReservation(root string) WritePathSet {
45 return WritePathSet{WholeWorkspace: true, WorkspaceRoot: root}
46 }
47
48 func fileReservation(root string, paths []string) WritePathSet {
49 out := WritePathSet{WorkspaceRoot: root, Paths: append([]string(nil), paths...)}
50 out.Kinds = make([]pathKind, len(paths))
51 return out
52 }
53
54 func mergeRealized(existing []string, add WritePathSet) []string {
55 capacity := max(len(existing), len(add.Paths))
56 seen := make(map[string]bool, capacity)
57 out := make([]string, 0, capacity)
58 for _, p := range existing {
59 key := foldPathKey(p)
60 if seen[key] {
61 continue
62 }
63 seen[key] = true
64 out = append(out, p)
65 }
66 for _, p := range add.Paths {
67 key := foldPathKey(p)
68 if seen[key] {
69 continue
70 }
71 seen[key] = true
72 out = append(out, p)
73 }
74 return out
75 }
76
77 // canStartIncomingLocked keeps a queued whole-workspace writer ahead of later
78 // writers. Directory claims have an empty reservation before their first write,
79 // so canStartLocked alone would otherwise let a steady stream bypass it.
80 func (s *SubagentScheduler) canStartIncomingLocked(req AcquireRequest) (bool, string) {
81 if req.Writer && !s.holdsParentClaimLocked(req.callerParentClaim) {
82 for _, waiter := range s.waiters {
83 if waiter.req.Writer && waiter.req.WritePaths.WholeWorkspace {
84 return false, "queued whole-workspace writer has priority"
85 }
86 }
87 }
88 return s.canStartLocked(req)
89 }
90
91 // parentWriteClaim is a write claim a depth-0 tool call holds for its Execute.
92 // Work that call delegates runs inside it: every queued writer that overlaps is
93 // blocked by the claim until Execute returns, so the delegate may not wait on
94 // the claim or queue behind such a writer.
95 type parentWriteClaim struct {
96 id int64
97 paths WritePathSet
98 }
99
100 func (s *SubagentScheduler) holdsParentClaimLocked(id int64) bool {
101 if id == 0 {
102 return false
103 }
104 for _, parent := range s.parentClaims {
105 if parent.id == id {
106 return true
107 }
108 }
109 return false
110 }
111
111 lines GO