Documentation
¶
Overview ¶
Package session is the operator-facing read/inspect surface over ADK's session store (docs/durable-execution-design.md, "Operator-facing surface"). It answers the questions durability raises for an operator: which sessions exist, which are paused waiting for input, on what interrupt, and with what response schema.
The pause model it inspects is the one verified in spike 2 (docs/spike-findings.md): a paused session carries an event with a non-nil RequestedInput; the matching resume is a later user turn whose FunctionResponse.ID equals that RequestedInput's InterruptID. A RequestedInput with no such later FunctionResponse is therefore a *pending* interrupt, and a session with pending interrupts is paused.
State labels are derived strictly from what the store can prove:
- StatePaused: at least one pending (unresolved) RequestedInput.
- StateAborted: an operator abort marker is present in session state (written by Store.Abort; see its doc for the semantics contract).
- StateIdle: everything else. The store cannot distinguish "a turn is in flight right now" from "the last turn completed" — that is in-process runner state, not event-log state — so this package deliberately does not claim "running" or "completed".
Index ¶
Constants ¶
const ( StatePaused = "paused" StateAborted = "aborted" StateIdle = "idle" )
Session states derived from the event log. See the package doc for why there is no "running" or "completed".
Variables ¶
var ErrAlreadyAborted = errors.New("session already aborted")
ErrAlreadyAborted reports that an abort marker is already present.
var ErrNotFound = errors.New("session not found")
ErrNotFound reports that no session with the requested ID exists in the store (under the store's app name).
Functions ¶
This section is empty.
Types ¶
type Detail ¶
type Detail struct {
Summary
EventCount int `json:"event_count"`
Pending []PendingInput `json:"pending,omitempty"`
}
Detail is the show-view projection: Summary plus event count and the full pending-interrupt records.
type PendingInput ¶
type PendingInput struct {
// InterruptID is the resume correlation key: the resume turn's
// FunctionResponse.ID must equal it (spike-2 verified contract).
InterruptID string `json:"interrupt_id"`
// Message is the human-readable prompt from the pausing node.
Message string `json:"message,omitempty"`
// Author is the agent that raised the interrupt.
Author string `json:"author,omitempty"`
// RaisedAt is the timestamp of the pausing event.
RaisedAt time.Time `json:"raised_at"`
// ResponseSchema, when non-nil, is the JSON schema the resume
// response payload must conform to.
ResponseSchema *jsonschema.Schema `json:"response_schema,omitempty"`
// Payload is optional context the pausing node attached.
Payload any `json:"payload,omitempty"`
}
PendingInput is a RequestedInput interrupt that has not been resolved by a later matching FunctionResponse. It carries everything an operator needs to script a resume.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store wraps an ADK session.Service with the operator-facing projections. It works over any Service implementation — the SQLite / Postgres database service and the in-memory service alike.
func NewStore ¶
func NewStore(svc adksession.Service, appName string) *Store
NewStore wraps an already-open session service (the path the daemon uses: same service instance the runner writes through).
func Open ¶
Open opens the SQLite session DB at path read-through (the path the CLI uses: `mast sessions list/show --session-db=...` against a DB a daemon owns or owned). The file must already exist — opening a missing path would silently create an empty store and report zero sessions for what is actually an operator typo.
func (*Store) Abort ¶
Abort appends a durable operator-abort marker to the session.
Semantics contract (minimal and honest — read before relying on it):
- Abort is a marker, not preemption. It does NOT cancel a turn that is in flight in some daemon process; it appends an event whose StateDelta records the abort reason and time in session state.
- ADK's workflow reconstruction does not read the marker: as far as the engine is concerned, a pending RequestedInput is still resumable. It is mast's surface that treats the marker as terminal — List/Get report StateAborted with pending interrupts cleared, and the daemon's /resume handler refuses aborted sessions (cmd/mast). A real engine-level terminal state is the v0.2 programmatic-pause/abort work (docs/durable-execution-design.md, Phasing).
- Idempotency: a second Abort returns ErrAlreadyAborted rather than stacking markers.
func (*Store) Get ¶
Get returns the detail view for one session. An empty userID is resolved by scanning List for the session ID (the CLI knows session IDs, not the daemon-internal user ID).
func (*Store) List ¶
List returns summaries for all sessions under the store's app name, most recent last-event first. userID narrows to one user; empty lists all users.
Note: ADK's Service.List returns sessions without events, and paused state is an event-log property, so List issues one Get per session. Fine at operator-CLI scale; a paged/indexed path is a v0.2+ concern alongside the eventlog query surface (docs/fork-design.md P1.3).
type Summary ¶
type Summary struct {
ID string `json:"id"`
AppName string `json:"app_name"`
UserID string `json:"user_id"`
LastEventTime time.Time `json:"last_event_time"`
State string `json:"state"`
// PendingInterruptIDs are the unresolved interrupt IDs (empty
// unless State is StatePaused).
PendingInterruptIDs []string `json:"pending_interrupt_ids,omitempty"`
// AbortReason is set when State is StateAborted.
AbortReason string `json:"abort_reason,omitempty"`
}
Summary is the list-view projection of one session.