返回 DeepSeek-Reasonix
session_config_delta.go
根目录 / internal / acp / session_config_delta.go
1 package acp
2
3 // sessionConfigDelta names exactly one config axis a caller asked to change
4 // (tool approval never rebuilds the controller, so it has no delta here).
5 // rebuildSession queues these — instead of a fully resolved SessionConfigState
6 // — while a turn or rebuild is in flight, one queue entry per axis, and
7 // applyPendingSessionConfig re-resolves the queued set against the session's
8 // live baseline once the session is idle. That way a queued change to one axis
9 // can never restore a stale value on another axis that changed in the
10 // meantime, whether that axis rebuilt already or is queued alongside.
11 type sessionConfigDelta struct {
12 axis string
13 model string
14 effortOverride *string
15 }
16
17 func (d sessionConfigDelta) clone() sessionConfigDelta {
18 d.effortOverride = cloneStringPtr(d.effortOverride)
19 return d
20 }
21
22 // mergePendingConfig queues delta with last-write-wins per axis: it replaces a
23 // queued entry for the same axis and appends otherwise, so a change queued for
24 // one axis can never restore stale intent on another. A replacement model
25 // change follows older effort intent so applyTo clears it. Callers hold sess.mu.
26 func mergePendingConfig(queue []sessionConfigDelta, delta sessionConfigDelta) []sessionConfigDelta {
27 for i := range queue {
28 if queue[i].axis == delta.axis {
29 if delta.axis == "model" && queue[i].model != delta.model {
30 queue = append(queue[:i], queue[i+1:]...)
31 return append(queue, delta.clone())
32 }
33 queue[i] = delta.clone()
34 return queue
35 }
36 }
37 return append(queue, delta.clone())
38 }
39
40 // removePendingAxes drops the queue entries whose axis a rebuild is applying,
41 // keeping entries other requests queued in the meantime so the post-maintenance
42 // drain still applies them. Callers hold sess.mu.
43 func removePendingAxes(queue, applied []sessionConfigDelta) []sessionConfigDelta {
44 if len(queue) == 0 {
45 return nil
46 }
47 kept := queue[:0]
48 for _, q := range queue {
49 drop := false
50 for _, d := range applied {
51 if q.axis == d.axis {
52 drop = true
53 break
54 }
55 }
56 if !drop {
57 kept = append(kept, q)
58 }
59 }
60 if len(kept) == 0 {
61 return nil
62 }
63 return kept
64 }
65
66 func clonePendingConfig(queue []sessionConfigDelta) []sessionConfigDelta {
67 if len(queue) == 0 {
68 return nil
69 }
70 out := make([]sessionConfigDelta, len(queue))
71 for i := range queue {
72 out[i] = queue[i].clone()
73 }
74 return out
75 }
76
77 func (d sessionConfigDelta) applyTo(p *SessionConfigStateParams) {
78 switch d.axis {
79 case "model":
80 if p.Model != d.model {
81 p.EffortOverride = nil
82 }
83 p.Model = d.model
84 case "thought_level":
85 p.EffortOverride = cloneStringPtr(d.effortOverride)
86 }
87 }
88
88 lines GO