Documentation
¶
Overview ¶
Package session — prompt stash storage.
StashStore persists draft prompts to ~/.overkill/stash.json so users can save a half-written message and restore it later.
Index ¶
- Constants
- Variables
- func DefaultStashPath() (string, error)
- func EnforceMax(ctx context.Context, store Store, max int) (int, error)
- type Brancher
- type ExportRitual
- type HistoryReader
- type ListOptions
- type PostgresStore
- func (s *PostgresStore) Bind(ctx context.Context, channel, chatKey, thread, sessionID string) error
- func (s *PostgresStore) Branch(ctx context.Context, parentID string, atTurn int) (*Session, error)
- func (s *PostgresStore) Clone(ctx context.Context, parentID string) (*Session, error)
- func (s *PostgresStore) Close() error
- func (s *PostgresStore) Create(ctx context.Context, session *Session) error
- func (s *PostgresStore) Delete(ctx context.Context, id string) error
- func (s *PostgresStore) Follow(ctx context.Context, channel, chatKey, target string) error
- func (s *PostgresStore) List(ctx context.Context, opts ListOptions) ([]*Session, error)
- func (s *PostgresStore) Load(ctx context.Context, id string) (*Session, error)
- func (s *PostgresStore) LoadMessages(ctx context.Context, id string) ([]providers.Message, error)
- func (s *PostgresStore) LoadRuntimeStatus(ctx context.Context, id string) (json.RawMessage, error)
- func (s *PostgresStore) Merge(ctx context.Context, childID string) (*Session, error)
- func (s *PostgresStore) Recent(ctx context.Context, limit int) ([]RouterRow, error)
- func (s *PostgresStore) Resolve(ctx context.Context, channel, chatKey, thread, liveSessionID string) (string, error)
- func (s *PostgresStore) Save(ctx context.Context, session *Session) error
- func (s *PostgresStore) SaveRuntimeStatus(ctx context.Context, id string, data json.RawMessage) error
- func (s *PostgresStore) Touch(ctx context.Context, channel, chatKey, thread string) error
- func (s *PostgresStore) Unbind(ctx context.Context, channel, chatKey, thread string) error
- type RouterRow
- type RuntimeStatusStore
- type Session
- type StashEntry
- type StashStore
- type Store
Constants ¶
const MaxRuntimeStatusBytes = 2 * 1024 * 1024
Variables ¶
var ErrConflict = errors.New("session: concurrent write conflict — reload before retrying")
var ErrExists = errors.New("session: already exists")
var ErrMergeDiverged = fmt.Errorf("session: merge: parent diverged past branch point")
ErrMergeDiverged is returned by Merge when the parent has accumulated messages past the child's branch point.
var ErrNotFound = errors.New("session: not found")
Functions ¶
func DefaultStashPath ¶
DefaultStashPath returns ~/.overkill/stash.json.
func EnforceMax ¶
EnforceMax retains the newest max initially top-level sessions. Sub-sessions are excluded from the snapshot and never selected for pruning; deleting a root retains the store's existing family promotion policy. Nonpositive max means unlimited. Concurrent new roots are considered on a later pass.
PostgreSQL performs selection/deletion atomically. Generic stores are scanned completely before deletion, with bounded pages and a private ID/version disk spool. Their interface cannot make concurrent writes atomic: changed or missing candidates are skipped and a later pass may still be necessary.
Types ¶
type Brancher ¶
type Brancher interface {
Branch(ctx context.Context, parentID string, atTurn int) (*Session, error)
Clone(ctx context.Context, parentID string) (*Session, error)
Merge(ctx context.Context, childID string) (*Session, error)
}
Brancher is the optional store capability that supports tree-structured sessions. PostgresStore satisfies this.
type ExportRitual ¶
type ExportRitual struct {
// contains filtered or unexported fields
}
func NewExportRitual ¶
func NewExportRitual(store Store, exportPath string) *ExportRitual
type HistoryReader ¶
type HistoryReader interface {
LoadMessages(ctx context.Context, id string) ([]providers.Message, error)
}
HistoryReader returns an independently owned snapshot of committed messages. It must be safe during concurrent turns, writes and deletes, and must not expose mutable in-memory agent history or uncommitted database changes. Stores without this capability retain exclusive API admission for history.
type ListOptions ¶
type PostgresStore ¶
type PostgresStore struct {
// contains filtered or unexported fields
}
PostgresStore is a PostgreSQL-backed session store that implements Store, Brancher, and session-router operations on the shared *sql.DB.
func NewPostgresStore ¶
func NewPostgresStore(db *sql.DB) (*PostgresStore, error)
NewPostgresStore creates a PostgresStore backed by the shared DB. The caller owns the DB lifecycle; Close() is a no-op.
func OpenPostgresStore ¶
func OpenPostgresStore(ctx context.Context, connString string) (*PostgresStore, error)
OpenPostgresStore opens and owns its database pool. Close releases the pool. NewPostgresStore instead borrows a pool whose lifecycle belongs to its caller.
func (*PostgresStore) Bind ¶
func (s *PostgresStore) Bind(ctx context.Context, channel, chatKey, thread, sessionID string) error
Bind locks a channel/chat/thread tuple to a session id.
func (*PostgresStore) Branch ¶
Branch creates a new session forked from parentID at message-index atTurn. Loads the parent inside the transaction to prevent TOCTOU races: without this, changes to the parent between Load and BeginTx are silently lost.
func (*PostgresStore) Clone ¶
Clone creates an independent duplicate of parentID with the full message history copied over. Loads the parent inside the transaction to prevent TOCTOU races.
func (*PostgresStore) Close ¶
func (s *PostgresStore) Close() error
Close releases only a pool created by OpenPostgresStore. Borrowed pools remain usable by the other stores that share them.
func (*PostgresStore) Create ¶
func (s *PostgresStore) Create(ctx context.Context, session *Session) error
Create inserts a new session. Returns ErrExists when a session with the same ID already exists.
func (*PostgresStore) Delete ¶
func (s *PostgresStore) Delete(ctx context.Context, id string) error
Delete removes a session, all its session_router bindings, and reassigns any child sessions' ParentID to the deleted session's parent (if any). This avoids dangling ParentID references — children are promoted one level up the tree rather than being orphaned or cascade-deleted.
func (*PostgresStore) Follow ¶
func (s *PostgresStore) Follow(ctx context.Context, channel, chatKey, target string) error
Follow sets a chat's follow target. target="tui" shadows the live TUI session; any other non-empty value pins to that session; empty clears follow mode. Channel is required to scope the follow to a specific gateway (telegram, discord, etc.) — without it different channels sharing the same chatKey would collide on follow state.
func (*PostgresStore) List ¶
func (s *PostgresStore) List(ctx context.Context, opts ListOptions) ([]*Session, error)
List returns sessions matching the optional filters, ordered by updated_at DESC. Limit and Offset are applied server-side.
func (*PostgresStore) Load ¶
Load fetches a session by ID. Returns ErrNotFound if no row matches. Children are populated by a second query.
func (*PostgresStore) LoadMessages ¶
LoadMessages uses one ordinary MVCC read. It neither waits on a turn's row update lock nor observes that turn before commit. JSON decoding owns the returned memory independently of the agent and all other readers.
func (*PostgresStore) LoadRuntimeStatus ¶
func (s *PostgresStore) LoadRuntimeStatus(ctx context.Context, id string) (json.RawMessage, error)
func (*PostgresStore) Merge ¶
Merge fast-forwards a child branch back into its parent. Wrapped in a transaction to prevent lost-update races: concurrent merges on the same parent are serialised by PostgreSQL row locks.
func (*PostgresStore) Resolve ¶
func (s *PostgresStore) Resolve(ctx context.Context, channel, chatKey, thread, liveSessionID string) (string, error)
Resolve looks up the session id for a channel/chat/thread binding. If follow mode points to a pinned session or "tui", that takes priority. Returns the resolved session ID, or empty string if nothing is bound.
func (*PostgresStore) Save ¶
func (s *PostgresStore) Save(ctx context.Context, session *Session) error
Save persists an updated session. The updated_at timestamp is set to NOW().
func (*PostgresStore) SaveRuntimeStatus ¶
func (s *PostgresStore) SaveRuntimeStatus(ctx context.Context, id string, data json.RawMessage) error
type RuntimeStatusStore ¶
type RuntimeStatusStore interface {
SaveRuntimeStatus(context.Context, string, json.RawMessage) error
LoadRuntimeStatus(context.Context, string) (json.RawMessage, error)
}
RuntimeStatusStore persists actual observed evaluation/check state separately from transcript saves, so one writer cannot overwrite the other's metadata.
type Session ¶
type Session struct {
ID string `json:"id"`
Title string `json:"title"`
Folder string `json:"folder"`
ParentID string `json:"parent_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Model string `json:"model"`
Provider string `json:"provider"`
TokenCount int64 `json:"token_count"`
CostUSD float64 `json:"cost_usd"`
TurnCount int `json:"turn_count"`
Metadata map[string]string `json:"metadata,omitempty"`
Status string `json:"status"`
Messages []providers.Message `json:"messages,omitempty"`
// Children lists the session IDs that branched FROM this one
// (Phase 1.5 #3 — tree-structured sessions). Maintained by Branch().
// Empty for leaf sessions; never nil after first branch.
Children []string `json:"children,omitempty"`
// BranchedAtTurn records which turn-index in the parent's history
// was the branch point. Only meaningful when ParentID is set.
// Zero is a valid value (branched from the very start) so we
// distinguish "branched at turn 0" from "not a branch" by the
// ParentID field, not by this value.
BranchedAtTurn int `json:"branched_at_turn,omitempty"`
// contains filtered or unexported fields
}
func NewSession ¶
func (*Session) AutoTitle ¶
AutoTitle sets Title from the first user message, truncated to 72 characters. Only sets when Title is empty — no overwrites.
func (*Session) IsSubSession ¶
type StashEntry ¶
type StashEntry struct {
ID string `json:"id"`
Text string `json:"text"`
SavedAt time.Time `json:"saved_at"`
}
StashEntry is one saved prompt.
type StashStore ¶
type StashStore struct {
// contains filtered or unexported fields
}
StashStore is a file-backed list of stash entries.
func NewStashStore ¶
func NewStashStore(path string) (*StashStore, error)
NewStashStore opens or creates a stash file at path. The directory is created if missing.
func (*StashStore) Delete ¶
func (s *StashStore) Delete(id string) error
Delete removes the entry with the given id. Missing ids return nil.
func (*StashStore) Get ¶
func (s *StashStore) Get(id string) (string, error)
Get returns the text of the entry with the given id.
func (*StashStore) List ¶
func (s *StashStore) List() ([]StashEntry, error)
List returns all stash entries, newest first.
type Store ¶
type Store interface {
Create(ctx context.Context, session *Session) error
Load(ctx context.Context, id string) (*Session, error)
Save(ctx context.Context, session *Session) error
Delete(ctx context.Context, id string) error
List(ctx context.Context, opts ListOptions) ([]*Session, error)
Close() error
}