sessnap

package
v0.14.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package sessnap provides a stable, JSON-friendly serialization ("snapshot") of a session.Session that the store adapters (memstore, jsonlstore) share.

The Session aggregate exposes its lifecycle data through exported fields (ID, State, Mode, Conversation, Limits, Counters, EnvironmentRef, CreatedAt) and through the PendingAsk accessor. Two pieces of its state are unexported and not directly addressable from outside the session package:

  • pending *PendingAsk — readable via Session.PendingAsk() (only while StateAwaiting) and restorable via Session.PauseForApproval() (only from StateRunning). The snapshot round-trips it for the awaiting case.
  • stop StopReason — the recorded terminal stop reason. It is captured faithfully via Session.RecordedStopReason() (which performs no limit derivation) and restored via the matching terminal transition Complete/Stop/Cancel/Fail. Capturing the recorded value directly means the snapshot no longer has to infer the reason from the conflated Session.StopReason(), so terminal round-trips are exact.

Index

Constants

This section is empty.

Variables

View Source
var ErrNilSession = errors.New("sessnap: nil session")

ErrNilSession is returned by Of when given a nil session.

Functions

func Marshal

func Marshal(s *session.Session) ([]byte, error)

Marshal encodes the snapshot of s as a single JSON line (no trailing newline).

func RestoreState

func RestoreState(
	s *session.Session,
	state session.State,
	stop session.StopReason,
	pending *session.PendingAsk,
	counters session.Counters,
	usage session.Usage,
	permanent bool,
	lastError string,
) error

RestoreState drives a freshly-constructed (StateIdle) Session through the state machine to the target lifecycle state, seeding the running totals (counters) and cumulative usage. It is the SINGLE place the terminal/awaiting transition vocabulary lives, shared by Snapshot.Restore (snapshot rehydration) and the event-sourced fold (engine/adapter/eventsource) so the state-driving logic is never copy-pasted.

s MUST be a fresh StateIdle session (e.g. straight from session.New) with its conversation already seeded; RestoreState only advances the lifecycle. stop is the recorded terminal stop reason (used for the completed-vs-stop distinction); pending is the parked ask (used only for StateAwaiting). counters seed the running totals (preserved across the BeginTurn that running/awaiting restore performs); usage seeds the cumulative budget figure; permanent records a permanence flag on StateFailed (meaningful only when state==StateFailed and permanent==true); lastError records the terminal failure cause on StateFailed (the Permanent-analog for the failure detail, issue #332 — meaningful only when state==StateFailed and lastError!=""). It returns an error on an unknown state or a transition the aggregate rejects.

func Unmarshal

func Unmarshal(line []byte) (*session.Session, error)

Unmarshal decodes a JSON snapshot line and restores it into a Session.

func ValidatePersistedAuthority

func ValidatePersistedAuthority(authority *session.Authority) error

ValidatePersistedAuthority rejects an authority claim that cannot represent a usable derived capability set. Callers must distinguish a nil authority pointer caused by a genuinely absent legacy field before calling it.

Types

type Snapshot

type Snapshot struct {
	ID          session.SessionID      `json:"id"`
	State       session.State          `json:"state"`
	Mode        session.PermissionMode `json:"mode"`
	Limits      session.Limits         `json:"limits"`
	Counters    session.Counters       `json:"counters"`
	CreatedAt   time.Time              `json:"created_at"`
	Incarnation session.IncarnationID  `json:"incarnation,omitempty"`
	Messages    []messageDTO           `json:"messages"`
	Pending     *session.PendingAsk    `json:"pending,omitempty"`
	StopReason  session.StopReason     `json:"stop_reason,omitempty"`
	// Kind and Relationship are the validated producer taxonomy from ADR 0217.
	// A missing kind is legacy data and restores as unknown (fail-closed).
	Kind         session.SessionKind         `json:"kind,omitempty"`
	Relationship session.SessionRelationship `json:"relationship,omitzero"`
	// Profile is the session's opaque tool-surface profile label. omitempty keeps a
	// v1 snapshot with no "profile" key decoding to "" (the default profile) —
	// purely additive, no format-tag bump (the same precedent as ProviderPhase /
	// Parts).
	Profile string `json:"profile,omitempty"`
	// ProviderID and ModelID are the session's opaque neutral provider+model
	// selector pair. omitempty keeps a v1 snapshot with no key decoding to the empty
	// pair ("server default") — additive, no version bump. Persisting them lets a
	// restarted process re-derive the SAME per-session engine via the factory.
	ProviderID string `json:"provider_id,omitempty"`
	ModelID    string `json:"model_id,omitempty"`
	// ReasoningEffort is the session's opaque neutral reasoning-effort token (ADR
	// 0055). omitempty keeps a pre-0055 snapshot with no key decoding to "" (unset)
	// — additive, no version bump. Persisting it lets a restarted process re-mint the
	// SAME per-session engine (the same-effort adapter) via the factory.
	ReasoningEffort string `json:"reasoning_effort,omitempty"`
	// DebugMCPServers names only the configured server-global MCP servers selected
	// for a debug session. DebugMCPTools is the exact direct-tool ceiling captured
	// at creation; neither field contains URLs, headers, or connection details.
	DebugMCPServers []string `json:"debug_mcp_servers,omitempty"`
	DebugMCPTools   []string `json:"debug_mcp_tools,omitempty"`
	// DebugTargetFingerprint is the non-projectable target-incarnation binding.
	DebugTargetFingerprint string `json:"debug_target_fingerprint,omitempty"`
	// Title is the session's human-readable label seeded from the first genuine
	// user prompt. omitempty keeps a pre-Title snapshot with no "title" key
	// decoding to "" — additive, no format-tag bump (the same precedent as
	// Profile / ProviderID / Parts). Persisting it lets a restarted process show
	// the label without re-deriving it. It is an inert stored label (like
	// Profile), restored by direct assignment, NOT a state transition.
	Title           string                  `json:"title,omitempty"`
	TitleProvenance session.TitleProvenance `json:"title_provenance,omitempty"`
	// Usage is the cumulative run-token accounting, a POINTER for true omitempty
	// (matching the Pending precedent): a zero Usage marshals nothing and a v1
	// snapshot with no "usage" key decodes to a nil pointer => the zero Usage on
	// restore. It is what the MaxRunTokens budget brake is evaluated against, so
	// persisting it lets the budget survive restart.
	Usage *session.Usage `json:"usage,omitempty"`
	// Permanent records whether a StateFailed session's failure was flagged as
	// permanent (session.RecordFailurePermanence). omitempty keeps a pre-flag
	// snapshot with no "permanent" key decoding to false — purely additive, no
	// format-tag bump.
	Permanent bool `json:"permanent,omitempty"`
	// RetryDisposition and StreamProgress are the typed terminal facts for a failed
	// model stream. Missing legacy fields decode conservatively to unknown.
	RetryDisposition session.RetryDisposition `json:"retry_disposition,omitempty"`
	StreamProgress   session.StreamProgress   `json:"stream_progress,omitempty"`
	// RetryPending persists the consumed failed-step retry intent across the crash window
	// between preparation and terminal completion. Its metadata remains separate
	// from failed-state metadata because the prepared aggregate is idle/running.
	RetryPending            bool                     `json:"retry_pending,omitempty"`
	RetryPendingDisposition session.RetryDisposition `json:"retry_pending_disposition,omitempty"`
	RetryPendingProgress    session.StreamProgress   `json:"retry_pending_progress,omitempty"`
	// LastError records a StateFailed session's terminal failure CAUSE
	// (session.RecordLastError, the Permanent-analog for the failure detail).
	// omitempty keeps a pre-#332 snapshot with no "last_error" key decoding to ""
	// — purely additive, no format-tag bump (the same precedent as Permanent). It
	// is normalised at stamp time (one line, rune-clamped), mirroring the
	// event-side subagentCausePayload so the snapshot and the subagent.end event
	// carry the same persisted cause.
	LastError string `json:"last_error,omitempty"`
	// RunID is the opaque, host-minted identity of the run this session is
	// currently driving or most recently drove (ADR 0249). Persisting it is what
	// makes an awaiting-approval resume continue THE SAME run across a process
	// restart: the resume path reads it back and reuses it instead of minting a
	// new one.
	//
	// omitempty keeps a pre-0245 snapshot with no "run_id" key decoding to "" —
	// purely additive, no format-tag bump (the Profile/ProviderID/Usage
	// precedent). A legacy session restores with no run id and is stamped on its
	// next run; there is no migration sweep.
	RunID string `json:"run_id,omitempty"`
	// Owner is the verified caller the session is attributed to (ADR 0204). A
	// POINTER for true omitempty: an ownerless session emits no "owner" key, so a
	// pre-ship snapshot decodes to a nil owner and an ownerless snapshot stays
	// byte-identical to a pre-ship one — purely additive, no format-tag bump.
	// Restored via the write-once aggregate method Session.RestoreLabels, NOT a
	// RestoreState parameter (widening that signature would be a Changed/breaking
	// entry under engine/COMPATIBILITY.md; a direct-assignment field is
	// Added/minor).
	Owner *session.Principal `json:"owner,omitempty"`
	// Authority is the plain, derived capability payload. A nil pointer is a
	// genuinely pre-feature legacy record; a present payload must decode to the
	// one governance.CapabilitySet representation or restore fails closed.
	Authority *session.Authority `json:"authority,omitempty"`
	// EnvironmentRef is the sole durable execution-environment identity. It is
	// required and must contain the exact provider revision used for reattachment.
	EnvironmentRef session.EnvironmentRef `json:"environment_ref"`
	// Placement is safe display-only metadata and is never used for reattachment.
	Placement session.PlacementMetadata `json:"placement,omitempty"`
}

Snapshot is the on-the-wire form of a session.Session. It is a plain data struct with JSON tags so it serializes deterministically regardless of the (untagged) layout of the domain types.

func Of

func Of(s *session.Session) (Snapshot, error)

Of builds a Snapshot from a live Session, reading everything reachable through the Session's public surface.

func (Snapshot) Restore

func (snap Snapshot) Restore() (*session.Session, error)

Restore reconstructs a Session from a Snapshot by driving the session state machine through its public constructors and transitions, so all invariants hold on the rebuilt aggregate.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL