返回 DeepSeek-Reasonix
save_tool_checkpoint.go
根目录 / internal / agent / save_tool_checkpoint.go
1 package agent
2
3 import (
4 "crypto/sha256"
5 "log/slog"
6
7 "reasonix/internal/provider"
8 )
9
10 // SaveToolCheckpoint commits the canonical transcript, CAS revision and event
11 // index before execution continues. Listing and display indexes are derived;
12 // rebuilding them for every tool receipt belongs to the normal snapshot path.
13 func (s *Session) SaveToolCheckpoint(path string, rewrite bool) error {
14 mode := sessionSaveToolCheckpoint
15 if rewrite {
16 // Rewrites invalidate old indexed prefixes and must publish that change.
17 mode = sessionSaveRewrite
18 }
19 return s.saveObserved(path, mode)
20 }
21
22 func refreshCheckpointDisplayIndex(path string, msgs []provider.Message, digest [sha256.Size]byte, revision int64, appendFrom int, deferred bool) error {
23 if deferred {
24 return nil
25 }
26 return refreshSessionDisplayIndex(path, msgs, digest, revision, appendFrom)
27 }
28
29 func (s *Session) markCheckpointPersisted(path string, digest [sha256.Size]byte, version uint64, revision int64, rewriteVersion int, msgs []provider.Message, deferred bool) {
30 if !deferred {
31 s.markPersistedWithListing(path, digest, version, revision, rewriteVersion, msgs)
32 return
33 }
34 s.setPersistedBaseline(path, digest, version, revision, true, true, rewriteVersion, msgs)
35 s.mu.Lock()
36 s.persisted.projectionPending = true
37 s.mu.Unlock()
38 }
39
40 // Checkpoint modes share ordinary CAS and rewrite rules, but defer projections.
41 func (mode sessionSaveMode) defersProjection() bool {
42 return mode == sessionSaveToolCheckpoint
43 }
44
45 func (mode sessionSaveMode) allowsOwnedRewrite() bool {
46 return mode == sessionSaveRewrite || mode == sessionSaveRewriteCompact
47 }
48
49 func (s *Session) refreshPendingCheckpointProjection(path string, msgs []provider.Message, digest [sha256.Size]byte, revision int64, deferred bool) {
50 state := s.persistState(path)
51 if deferred || (!state.projectionPending && state.saveVerified) {
52 return
53 }
54 if err := refreshSessionDisplayIndex(path, msgs, digest, revision, -1); err != nil {
55 // Match normal saves: a derived index cannot invalidate a durable receipt.
56 slog.Warn("session: keeping save after display index write failure", "path", path, "err", err)
57 }
58 }
59
60 func (mode sessionSaveMode) eventReason() string {
61 switch mode {
62 case sessionSaveSnapshot, sessionSaveToolCheckpoint:
63 return "snapshot"
64 case sessionSaveRewrite:
65 return "rewrite"
66 case sessionSaveRewriteCompact:
67 return "rewrite-compact"
68 default:
69 return "save"
70 }
71 }
72
72 lines GO