Documentation
¶
Overview ¶
Package session persists agent conversation history across runs.
Sessions enable multi-turn conversations: a user runs a task, the agent responds, and the user continues the conversation with "odek continue", picking up the full message history from the previous turn.
Storage: ~/.odek/sessions/<id>.json. Each file is a full conversation transcript including system messages, user turns, assistant responses, tool calls, and tool results. Sessions are loaded by ID for continuation or by listing metadata for browsing.
The Store is intentionally minimal — it's a JSON file manager, not a database. Session struct fields are all public, so callers can mutate the session directly and call Save(). This makes advanced operations (editing, truncating, merging sessions) trivial at the CLI layer.
Index ¶
- func ValidateSessionID(id string) error
- type IndexEntry
- type Session
- type Store
- func (s *Store) Append(id string, newMsgs []llm.Message) error
- func (s *Store) Cleanup(before time.Time) (int, error)
- func (s *Store) Create(messages []llm.Message, model, task string) (*Session, error)
- func (s *Store) Delete(id string) error
- func (s *Store) Dir() string
- func (s *Store) Latest() (*Session, error)
- func (s *Store) List(limit int) ([]Session, error)
- func (s *Store) Load(id string) (*Session, error)
- func (s *Store) Path(id string) string
- func (s *Store) Save(sess *Session) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ValidateSessionID ¶
ValidateSessionID validates that a session ID is safe for filesystem use. Rejects empty strings, path separators, traversal patterns, and dot names.
Types ¶
type IndexEntry ¶
type IndexEntry struct {
ID string `json:"id"`
Title string `json:"title"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Turns int `json:"turns"`
}
IndexEntry holds minimal session metadata for the session index. This avoids loading every session file just to list or find the latest.
type Session ¶
type Session struct {
ID string `json:"id"` // e.g. "20260518-abc123"
CreatedAt time.Time `json:"created_at"` // first message time
UpdatedAt time.Time `json:"updated_at"` // last append time
Model string `json:"model"` // model name used
Turns int `json:"turns"` // number of user turns
Task string `json:"task"` // first user message (label)
Sandbox bool `json:"sandbox"` // was sandboxed — auto-apply on resume
Messages []llm.Message `json:"messages"` // full conversation history
Buffer []string `json:"buffer,omitempty"` // last N turn summaries (memory tier 2)
}
Session represents a single multi-turn conversation with the agent. All fields are exported for direct manipulation at the CLI layer.
func (*Session) GetMessages ¶
GetMessages returns the session's message slice. Nil-safe. Returns an empty (non-nil) slice for a session with no messages.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store manages session files in a directory on disk. Operations are simple file reads/writes — no locking, no caching.
func NewStore ¶
NewStore creates a session store rooted at ~/.odek/sessions/. The directory is created if it doesn't exist.
func (*Store) Append ¶
Append adds new messages to an existing session, updates timestamps and turn counts, and saves the result atomically. The full read-modify-write is serialized by s.mu to prevent both concurrent-write data loss and symlink-swap TOCTOU attacks.
func (*Store) Cleanup ¶
Cleanup deletes all sessions whose UpdatedAt is before the given time. Returns the count of deleted sessions. Idempotent — nonexistent files are skipped silently. Uses the session index for efficient batch operations. Falls back to scanning individual session files when no index exists (backward compat).
func (*Store) Create ¶
Create persists a new session with the given messages and metadata. It generates an ID, sets timestamps, counts user turns, and saves.
func (*Store) Delete ¶
Delete removes a session file from disk and removes its entry from the session index. Returns nil if the file doesn't exist (idempotent delete).
func (*Store) Dir ¶
Dir returns the session store directory path. Exported for testing and debugging.
func (*Store) Latest ¶
Latest returns the most recently updated session, or nil if no sessions exist. Returns an error when no sessions exist. Uses the session index for O(1) lookups. Falls back to scanning individual session files when no index exists (backward compat).
func (*Store) List ¶
List returns session summaries ordered by UpdatedAt descending (most recent first). limit caps the number returned (0 = all). Only metadata fields are populated — Messages is nil to keep listings lightweight. Uses the session index for O(n) reads (n = session count, but no JSON parsing per session). Falls back to loading each session file when no index exists (backward compat).
func (*Store) Load ¶
Load reads a session from disk by ID. Returns an error if the file doesn't exist or can't be parsed.
func (*Store) Path ¶
Path returns the absolute filesystem path for a session file. Exported for testing and debugging.