Documentation
¶
Overview ¶
Session storage on disk. One JSON file per session at
<APP_HOME>/sessions/<workdir-slug>/<session-id>.json
The store is intentionally small: Save / Load / List / Delete on straightforward filesystem primitives. List sorts by file mtime descending so the most recently active session lands at the top of the resume picker.
Corrupt files (truncated writes from a crashed evva, JSON drift after a schema bump) are skipped with a warning during List — one broken file must never disable the picker for the whole directory.
Index ¶
- Constants
- func CountTouchedSince(appHome string, since time.Time, excludeID string) (int, error)
- func Delete(appHome, workdirSlug, sessionID string) error
- func FirstUserPromptPreview(msgs []llm.Message) string
- func Save(appHome string, snap *Snapshot) error
- func SessionFilePath(appHome, workdirSlug, sessionID string) string
- func SessionsDir(appHome, workdirSlug string) string
- type ListEntry
- type Session
- func (s *Session) AddUsage(u llm.Usage)
- func (s *Session) Append(msg llm.Message)
- func (s *Session) FullCompact(messages []llm.Message, briefTokens int)
- func (s *Session) GetFullCompactCount() int
- func (s *Session) GetMessages() []llm.Message
- func (s *Session) IsMicroCompacted() bool
- func (s *Session) LastTurnInputTokens() int
- func (s *Session) MicroCompact(messages []llm.Message)
- func (s *Session) RecordTurn(u llm.Usage)
- func (s *Session) SetCompactState(micro bool, fullCount int)
- func (s *Session) SetLastTurnInputTokens(n int)
- func (s *Session) SetUsage(u llm.Usage)
- func (s *Session) ToSnapshot() SessionState
- type SessionState
- type Snapshot
Constants ¶
const PreviewMaxBytes = 200
PreviewMaxBytes caps the persisted first-user-prompt preview. The resume overlay renders only 150 chars, but we store 200 so trailing truncation never produces a half-word in the visible window.
const SessionsSubdir = "sessions"
SessionsSubdir is the directory under APP_HOME that holds every persisted session, organized one level deeper by workdir slug.
const SnapshotVersion = 1
SnapshotVersion is the on-disk schema version. Bump on breaking changes to the JSON layout; older files become unreadable, which the store's List path tolerates by skipping with a warning rather than aborting the picker.
Variables ¶
This section is empty.
Functions ¶
func CountTouchedSince ¶ added in v1.8.0
CountTouchedSince counts persisted sessions across ALL workdir slugs whose file mtime is after `since`, excluding excludeID (the current session, whose mtime is always recent). evva's auto-memory is one global store, so the dream activity-gate counts activity in every project — not just the current workdir — as the signal that enough has accumulated to consolidate.
Cheap and parse-free: one ReadDir per slug + a stat per file (mtime + name are all that matter here; the snapshot JSON is never decoded). A missing sessions root is 0, not an error — that's the normal "no prior sessions" state. An unreadable individual slug dir is skipped, not fatal.
func Delete ¶ added in v1.4.3
Delete removes a single snapshot file. Missing files are not an error (idempotent — second delete is a no-op).
func FirstUserPromptPreview ¶ added in v1.4.3
FirstUserPromptPreview returns up to PreviewMaxBytes from the first RoleUser message's content. Whitespace at both ends is trimmed; CR/LF inside the body are flattened to single spaces so the preview always fits on one line in the resume picker.
Empty result means the session has no user messages yet (rare — typically only when the file is saved between session start and the first user prompt being routed).
func Save ¶ added in v1.4.3
Save serializes snap to <SessionsDir>/<SessionID>.json atomically (temp + rename in the same directory). Creates the parent directory chain if missing. Returns an error only on real I/O failure.
func SessionFilePath ¶ added in v1.4.3
SessionFilePath resolves the snapshot file for one session-id.
func SessionsDir ¶ added in v1.4.3
SessionsDir returns the absolute path of the per-workdir directory holding this workdir's session files. Empty inputs yield "".
Types ¶
type ListEntry ¶ added in v1.4.3
type ListEntry struct {
Snapshot *Snapshot
MTime int64 // unix nano of file mtime; List sorts by this desc
}
ListEntry is one row in the resume picker: the snapshot plus the file mtime List uses to sort. The picker only needs a small subset of the snapshot fields — exposed separately so the picker can stay shallow.
func List ¶ added in v1.4.3
List enumerates every session under <SessionsDir>/<workdir-slug>/, sorted by mtime descending (most recently saved first). Files that fail to parse are skipped — the corresponding error appears in the returned warnings slice so the caller can surface them.
Returns an empty slice (not an error) when the directory does not exist yet — that's the normal "no prior sessions" state.
type Session ¶
type Session struct {
// LLM context payload
Messages []llm.Message
// Usage is the running sum of every turn's reported token usage in this
// session. Compaction is expected to reset Messages but leave Usage as
// the running tab of what the user has already paid for.
Usage llm.Usage
// contains filtered or unexported fields
}
Session holds the live conversation history for a single agent run. The agent appends every message (user, assistant, tool result) here so the LLM always receives the full context on the next turn. tools, agent, llm, tui will use it.
func FromSnapshot ¶ added in v1.4.3
func FromSnapshot(state SessionState) *Session
FromSnapshot returns a fresh *Session rehydrated from the persisted state. The slice is copied so callers can mutate the snapshot's Messages without aliasing into the live session (and vice versa).
func (*Session) AddUsage ¶
AddUsage folds one usage entry into the cumulative session total only. Use this for non-turn usage events whose input-token count does NOT represent the current prompt size — e.g. the LLM call inside full compaction, where InputTokens reflects the size of the conversation we just summarized, not the size of the post-compaction prompt.
func (*Session) FullCompact ¶
FullCompact replaces Messages with the summarization brief and resets the in-flight compaction state. lastTurnInputTokens is set to briefTokens — the brief is now the entirety of the prompt the next turn will send, so callers (the TUI's context bar in particular) can read accurate "current prompt size" without waiting for the next thinking call to land.
Cumulative Usage is also reset: in=briefTokens, out=0. The HUD reads as "fresh context after compact" so the user can visually confirm the bar drop (e.g. 80% → 40%) without the cumulative tail dragging the numbers up. The compaction caller is responsible for logging the pre-reset totals before invoking this — they're gone after.
func (*Session) GetFullCompactCount ¶
func (*Session) GetMessages ¶
func (*Session) IsMicroCompacted ¶
func (*Session) LastTurnInputTokens ¶
LastTurnInputTokens returns the InputTokens from the most recent agent turn (zero before the first turn completes, or right after a full-compact reset). This is the canonical "how full is the prompt right now" signal — preferred over Usage.Total for ratio checks.
func (*Session) MicroCompact ¶
func (*Session) RecordTurn ¶
RecordTurn marks u as the most recent agent-turn usage: it folds u into the cumulative total AND updates lastTurnInputTokens so compaction can measure live prompt pressure. The agent loop calls this after every Complete / Stream that drove a real iteration.
The prompt-size figure sums InputTokens with the cache read/creation counts: Anthropic's input_tokens covers ONLY the uncached suffix of the prompt (the three usage fields are disjoint), so with prompt caching active InputTokens alone collapses to a few hundred tokens per call and the auto-compact threshold would never trigger. Providers without cache reporting leave the cache fields zero and the sum degrades to the old behavior.
func (*Session) SetCompactState ¶ added in v1.4.3
SetCompactState rehydrates the micro/full compaction counters. Used by session.FromSnapshot to round-trip persisted state; not for live use.
func (*Session) SetLastTurnInputTokens ¶ added in v1.4.3
SetLastTurnInputTokens overrides the cached turn-input figure. Used by the resume path to rehydrate a snapshot's previously-recorded value; production code should prefer RecordTurn so the cumulative Usage is kept in sync.
func (*Session) SetUsage ¶ added in v1.4.3
SetUsage overrides the cumulative usage total. Same caveat as SetLastTurnInputTokens: only the resume path should use it. Production turns flow through AddUsage / RecordTurn.
func (*Session) ToSnapshot ¶ added in v1.4.3
func (s *Session) ToSnapshot() SessionState
ToSnapshot copies the live session into a JSON-friendly DTO. The caller fills in the envelope fields (SessionID, Workdir, Profile, etc.) — Session has no view of those.
type SessionState ¶ added in v1.4.3
type SessionState struct {
Messages []llm.Message `json:"messages"`
Usage llm.Usage `json:"usage"`
LastTurnInputTokens int `json:"last_turn_input_tokens"`
MicroCompacted bool `json:"micro_compacted"`
FullCompactCount int `json:"full_compact_count"`
}
SessionState carries the live conversation fields persisted alongside the snapshot envelope. The unexported Session fields are surfaced via the SetCompactState / SetLastTurnInputTokens accessors on rehydrate.
type Snapshot ¶ added in v1.4.3
type Snapshot struct {
Version int `json:"version"`
SessionID string `json:"session_id"`
Workdir string `json:"workdir"`
WorkdirSlug string `json:"workdir_slug"`
Profile string `json:"profile"`
Provider string `json:"provider"`
Model string `json:"model"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
FirstUserPrompt string `json:"first_user_prompt"`
Session SessionState `json:"session"`
}
Snapshot is the JSON shape of one persisted session.
SessionID identifies the file on disk and equals the live agent's UUID at the moment the session was first saved; the agent overwrites its own ID with this value on resume so subsequent writes target the same file.
Profile + Provider + Model capture the agent setup at save time so the resume code can rebuild the right persona and LLM client even if the user's defaults have changed since.