返回 DeepSeek-Reasonix
transcript_persistence.go
根目录 / internal / control / transcript_persistence.go
1 package control
2
3 import (
4 "errors"
5 "reasonix/internal/agent"
6
7 "reasonix/internal/transcript"
8 "reasonix/internal/turnevent"
9 )
10
11 func (c *Controller) captureTranscriptCheckpoint(ledger *turnevent.Ledger, digest string) {
12 if c.sessionEngineEnabled() {
13 return
14 }
15 if digest == "" {
16 digest, _ = agent.ContentDigestForMessages(c.History())
17 }
18 p, err := c.transcriptProjection()
19 if err != nil {
20 return
21 }
22 state, err := p.Checkpoint(digest)
23 state.ProviderCount = c.HistoryLen()
24 c.turnEvents.mu.Lock()
25 defer c.turnEvents.mu.Unlock()
26 if c.turnEvents.ledger != ledger {
27 return
28 }
29 if err != nil {
30 c.turnEvents.projectionWriteErr = err
31 return
32 }
33 c.turnEvents.pendingCheckpoint = &state
34 }
35
36 // Serializes retries and terminal writes, then reads the latest pending cut.
37 // A delayed retry cannot overwrite a newer successful checkpoint with an old
38 // one. No controller or projection lock is held during disk I/O.
39 func (c *Controller) persistTranscriptCheckpoint(ledger *turnevent.Ledger) error {
40 if c.sessionEngineEnabled() {
41 return nil
42 }
43 c.turnEvents.persistMu.Lock()
44 defer c.turnEvents.persistMu.Unlock()
45 c.turnEvents.mu.RLock()
46 if c.turnEvents.ledger != ledger {
47 c.turnEvents.mu.RUnlock()
48 return errors.New("transcript runtime changed before checkpoint persistence")
49 }
50 state := c.turnEvents.pendingCheckpoint
51 path := c.turnEvents.projectionPath
52 priorErr := c.turnEvents.projectionWriteErr
53 projectionErr := c.turnEvents.projectionErr
54 c.turnEvents.mu.RUnlock()
55 if projectionErr != nil {
56 return projectionErr
57 }
58 if state == nil {
59 return priorErr
60 }
61 err := transcript.SaveCheckpoint(path, *state)
62 c.turnEvents.mu.Lock()
63 defer c.turnEvents.mu.Unlock()
64 if c.turnEvents.ledger == ledger {
65 c.turnEvents.projectionWriteErr = err
66 if err == nil {
67 c.turnEvents.projectionPersistedThrough = state.CoveredThroughSeq
68 if c.turnEvents.pendingCheckpoint == state {
69 c.turnEvents.pendingCheckpoint = nil
70 }
71 }
72 }
73 return err
74 }
75
75 lines GO