| 1 | package agent |
| 2 | |
| 3 | import "reasonix/internal/fileops" |
| 4 | |
| 5 | // InheritFileObservationsFrom is for an idle, same-session runtime rebuild. |
| 6 | // Resume, fork and rewind intentionally use SetSession without this transfer. |
| 7 | func (a *Agent) InheritFileObservationsFrom(previous *Agent) { |
| 8 | if previous != nil && a != previous { |
| 9 | a.fileObservations = previous.fileObservations.Clone() |
| 10 | } |
| 11 | } |
| 12 | |
| 13 | // Session returns the agent's current conversation, useful for persistence |
| 14 | // hooks that need to read the message log between turns. sessMu serialises this |
| 15 | // pointer read against SetSession, so a frontend (serve's concurrent /history and |
| 16 | // /new handlers) can't race the swap. The run loop touches a.session directly and |
| 17 | // only swaps it via SetSession while idle, so its reads need no lock. |
| 18 | func (a *Agent) Session() *Session { |
| 19 | a.sess.mu.Lock() |
| 20 | defer a.sess.mu.Unlock() |
| 21 | return a.sess.conversation |
| 22 | } |
| 23 | |
| 24 | // SetSession replaces the agent's conversation wholesale. Used by |
| 25 | // `reasonix --resume` to load a saved JSONL transcript before the first turn, |
| 26 | // so the model picks up exactly where it left off. Callers serialise it against a |
| 27 | // running turn (it only fires while idle); sessMu guards the pointer swap itself. |
| 28 | func (a *Agent) SetSession(s *Session) { |
| 29 | a.sess.reset(s) |
| 30 | // Observations are live capabilities tied to the exact session instance and |
| 31 | // execution environment. Never reconstruct or carry them across resume, |
| 32 | // rewind, fork, or a wholesale session replacement. |
| 33 | a.fileObservations = fileops.NewStore() |
| 34 | a.resetPinnedContextState() |
| 35 | // sessionRuntime.reset clears turn-local Todo state. A resume, fork, rewind |
| 36 | // or wholesale replacement never reconstructs it from tool messages. |
| 37 | } |
| 38 |