sessionregistry

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package sessionregistry defines the immutable registration and authenticated conversation identity consumed by the session registry. The live registry lifecycle is deliberately separate so transports and protocol bridges can share this security boundary without learning workspace paths or secrets.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrExecutionDenied is the sanitized result of policy rejection, failure, a
	// nil permit, or a policy panic. Driver side effects never begin after it.
	ErrExecutionDenied = errors.New("session execution denied")
	// ErrUsageRejected means a turn's cumulative Usage snapshot was malformed,
	// regressed, or rejected by its active execution permit.
	ErrUsageRejected = errors.New("session cumulative usage rejected")
)
View Source
var (
	// ErrInvalidRegistration means a RegistrationSpec is incomplete or unsafe.
	ErrInvalidRegistration = errors.New("sessionregistry: invalid registration")
	// ErrInvalidPrincipal means an authenticated owner or tenant is invalid.
	ErrInvalidPrincipal = errors.New("sessionregistry: invalid principal")
	// ErrInvalidConversation means a conversation reference is invalid.
	ErrInvalidConversation = errors.New("sessionregistry: invalid conversation")
	// ErrInvalidEnvironment means a subprocess environment entry is malformed.
	ErrInvalidEnvironment = errors.New("sessionregistry: invalid environment")
	// ErrEnvironmentUnavailable means the registered environment provider failed,
	// panicked, or returned an invalid environment. The sentinel deliberately has
	// no provider error or panic payload because those values may contain secrets.
	ErrEnvironmentUnavailable = errors.New("sessionregistry: environment unavailable")
)
View Source
var (
	ErrInvalidConfig         = errors.New("invalid session registry configuration")
	ErrInvalidAttach         = errors.New("invalid session attachment")
	ErrInvalidExpiryHandler  = errors.New("invalid session registry expiry handler")
	ErrLiveSession           = errors.New("live session already exists")
	ErrResumeUnavailable     = errors.New("resumable session unavailable")
	ErrCheckpointUnavailable = errors.New("session checkpoint unavailable")
	ErrConsumerClaimed       = errors.New("session registry consumer already claimed")
	ErrExpiryHandlerClaimed  = errors.New("session registry expiry handler already claimed")
)
View Source
var (
	ErrClosed              = errors.New("session registry closed")
	ErrCapacity            = errors.New("session registry capacity reached")
	ErrNoLiveSession       = errors.New("no live session")
	ErrGenerationChanged   = errors.New("session generation changed")
	ErrControlled          = errors.New("session already has a controller")
	ErrControllerStale     = errors.New("session controller superseded")
	ErrCheckpointAmbiguous = errors.New("session checkpoint is not safely resumable")
	ErrTurnActive          = errors.New("session turn already active")
	ErrTurnNotFound        = errors.New("session turn not found")
	ErrTurnIDConflict      = errors.New("session turn id reused with different input")
	ErrTurnHistoryFull     = errors.New("session turn id history reached its limit")
	ErrInvalidTurnInput    = errors.New("session turn input is not JSON-compatible")
	ErrApprovalNotFound    = errors.New("session approval not found")
	ErrInvalidDecision     = errors.New("invalid session approval decision")
	// ErrDeliveryAmbiguous means a driver-facing control call returned after it
	// may already have accepted the command. Callers must not retry the command
	// against a successor session: doing so could duplicate agent side effects.
	ErrDeliveryAmbiguous       = errors.New("session command delivery outcome is ambiguous")
	ErrSessionEnded            = errors.New("session ended")
	ErrInvalidCursor           = errors.New("invalid session event cursor")
	ErrEventTooLarge           = errors.New("session event exceeds ring byte budget")
	ErrReplayCapacity          = errors.New("session registry replay byte budget exhausted")
	ErrReplayUnavailable       = errors.New("ended session replay is no longer available")
	ErrTerminalOutcomeConflict = errors.New("session terminal outcome conflicts with an earlier completion")
	ErrInvalidTerminalOutcome  = errors.New("invalid session terminal outcome")
	ErrEndedReplayReadOnly     = errors.New("ended session replay is read-only")
)
View Source
var (
	// ErrWorkspaceUnavailable means the configured coordinator could not produce
	// or release a valid binding. Provider error text is deliberately hidden: it
	// may contain host paths, container identifiers, or backend details.
	ErrWorkspaceUnavailable = errors.New("session workspace unavailable")
	// ErrWorkspaceLeaseUnavailable means the active turn could not exclusively
	// claim its resolved workspace. No driver side effect occurs before the claim.
	ErrWorkspaceLeaseUnavailable = errors.New("session workspace lease unavailable")
)
View Source
var (
	ErrDecisionConflict = errors.New("approval decision conflicts with an earlier delivery")
)
View Source
var (
	// ErrFileReferenceRejected is deliberately payload-free. It covers the safe
	// default, structural failures, provider errors, panics, and invalid provider
	// behavior without disclosing an inbound URL or provider diagnostics.
	ErrFileReferenceRejected = errors.New("sessionregistry: file reference rejected")
)

Functions

This section is empty.

Types

type ApprovalSnapshot

type ApprovalSnapshot struct {
	Turn        TurnRef
	ID          string
	Kind        string
	Payload     json.RawMessage
	Cursor      Cursor
	RequestedAt time.Time
	Delivering  bool
}

type AttachMode

type AttachMode uint8

AttachMode controls whether Attach may create or resume a live process.

const (
	AttachAuto AttachMode = iota + 1
	AttachExisting
	// AttachFresh deliberately discards resumable continuity and therefore
	// requires mutable Control; an observer must never create this state change.
	AttachFresh
	// AttachResume requires an existing live session or a clean durable
	// checkpoint. Unlike Auto it never opens a blank successor when continuity is
	// unavailable.
	AttachResume
)

type AttachRequest

type AttachRequest struct {
	Principal          Principal
	Conversation       ConversationRef
	Mode               AttachMode
	Control            ControlMode
	ControllerID       string
	ExpectedGeneration sessionstore.Generation
	After              Cursor
	// AfterLatest starts observation at the ring tail as part of the attachment
	// linearization point. It is mutually exclusive with an explicit After cursor.
	AfterLatest bool
	// WaitForControl makes a Control attachment wait, with ctx cancellation, for
	// a different controller to release or retire the conversation. It is useful
	// for protocol bridges which serialize separate tasks on one conversation;
	// Takeover remains the explicit epoch-fencing operation.
	WaitForControl bool
}

type Attachment

type Attachment struct {
	// contains filtered or unexported fields
}

Attachment is a generation-scoped view of a Registry entry. Close detaches only this view; the Registry retains the process while a turn/approval or another attachment still needs it.

func (*Attachment) AcceptedOutputModes

func (a *Attachment) AcceptedOutputModes(reference TurnRef) ([]string, error)

AcceptedOutputModes returns the immutable per-request output contract most recently delivered for the exact active turn. Empty means Manifest defaults.

func (*Attachment) BeginInterrupt

func (a *Attachment) BeginInterrupt(ctx context.Context, reference TurnRef) (claim InterruptClaim, resultErr error)

BeginInterrupt claims terminal ownership of reference and atomically marks its exact session generation closing. Once this method returns successfully, neither Existing nor Auto attachment can enter that generation; Auto waits for Complete to finish retirement before it may open a successor.

The caller must invoke Complete on every successful claim, even when its protocol publication fails or its request context is canceled.

func (*Attachment) BeginProjectionRejection

func (a *Attachment) BeginProjectionRejection(
	ctx context.Context,
	reference TurnRef,
) (ProjectionRejectionClaim, error)

BeginProjectionRejection atomically makes the exact session generation unavailable after its output violates a protocol projection contract. If the turn is still active, the returned claim owns the same token-scoped interrupt path as BeginInterrupt. If Done has already won terminal ownership, the claim instead owns (or joins) an unprojected terminal settlement and never calls the driver's InterruptTurn method for the completed token.

The caller must invoke Complete on every successful claim, even when failure publication or its request context fails. A projection rejection is a fail-closed registry invariant: if an injected execution policy prevents the ordinary interrupt path, the exact generation is still retired without delivering an unfenced control call to the driver.

func (*Attachment) Close

func (a *Attachment) Close()

func (*Attachment) Cursor

func (a *Attachment) Cursor() Cursor

Cursor returns the next-read position accepted atomically by Attach. A raw reattach protocol includes this value in its welcome frame so a client which disconnects before the first event can reconnect without repeating AfterLatest and silently skipping events produced in between.

func (*Attachment) Generation

func (a *Attachment) Generation() sessionstore.Generation

func (*Attachment) Interrupt

func (a *Attachment) Interrupt(ctx context.Context, reference TurnRef) error

Interrupt performs BeginInterrupt and Complete without an intervening protocol publication. Callers which need cancellation publication ordering should use the two-phase API directly.

func (*Attachment) Next

func (a *Attachment) Next(ctx context.Context) (StreamItem, error)

Next returns the next event, an explicit replay gap, or a terminal error. It is pull-based: a slow observer creates no goroutine and never blocks the sole session pump.

func (*Attachment) ProjectionCurrent

func (a *Attachment) ProjectionCurrent(item EventItem) bool

ProjectionCurrent reports whether an EventItem is still meaningful at the projection boundary. Immutable output remains current once appended, except for Approval: a decision, interrupt, expiry, or terminal can resolve it while the item is waiting behind output admission. Projectors must not expose that stale approval as a new actionable prompt.

func (*Attachment) ProjectionProgress

func (a *Attachment) ProjectionProgress(cursor Cursor) error

ProjectionProgress records that this controller successfully published all events through cursor to its protocol boundary. Progress is generation- and controller-epoch-fenced and strictly monotonic: replaying an old cursor cannot keep approval or terminal deadlines alive indefinitely.

Pending deadlines are measured from useful ordered progress, not merely from the moment the driver queued an event. This prevents a bounded protocol-output backlog from consuming the human approval window or the terminal settlement window before either event can be observed. With no successful projector the original absolute deadline still expires fail-closed.

func (*Attachment) Respond

func (a *Attachment) Respond(ctx context.Context, request RespondRequest) (resultErr error)

func (*Attachment) RespondElicitation

func (a *Attachment) RespondElicitation(ctx context.Context, request RespondElicitationRequest) (resultErr error)

RespondElicitation settles the one ordinary-input request on an exact turn. The turn token never crosses the Registry boundary, and the turn control gate serializes response, expiry, steering, approval, and interrupt delivery.

func (*Attachment) Snapshot

func (a *Attachment) Snapshot() Snapshot

func (*Attachment) SnapshotBound

func (a *Attachment) SnapshotBound() int64

SnapshotBound returns an allocation-free conservative bound for the current Snapshot's JSON-compatible protocol encoding. The bound is only a point-in-time observation: callers which perform admission before allocating the snapshot must confirm it with SnapshotWithinBound.

func (*Attachment) SnapshotWithBound

func (a *Attachment) SnapshotWithBound() (Snapshot, int64)

SnapshotWithBound returns one independent snapshot and a conservative bound for its JSON-compatible protocol encoding, both derived under the same entry lock. Callers which must bound even the first snapshot copy should instead use SnapshotBound followed by SnapshotWithinBound after admission.

func (*Attachment) SnapshotWithinBound

func (a *Attachment) SnapshotWithinBound(admittedBound int64) (snapshot Snapshot, actualBound int64, ok bool)

SnapshotWithinBound returns an independent snapshot only when its current conservative encoding bound is no larger than admittedBound. A false result means the snapshot grew after admission; no approval payload is copied, and the caller must release the old admission and retry with actualBound.

func (*Attachment) StartPreparedTurn

func (a *Attachment) StartPreparedTurn(ctx context.Context, prepared *PreparedTurn) (result TurnRef, resultErr error)

StartPreparedTurn durably claims an inflight checkpoint before delivering the exact input snapshot authorized by PrepareTurn to the driver.

func (*Attachment) StartTurn

func (a *Attachment) StartTurn(ctx context.Context, request StartTurnRequest) (TurnRef, error)

StartTurn is the single-call Registry API. It preserves idempotent retries by consulting an already-recorded turn before invoking external policy. A protocol bridge which must durably create its task before driver delivery should instead use PrepareTurn followed by StartPreparedTurn.

func (*Attachment) State

func (a *Attachment) State() AttachmentState

State returns allocation-free lifecycle metadata for this attachment's generation. Use Snapshot only when approval contents are actually needed.

func (*Attachment) Steer

func (a *Attachment) Steer(ctx context.Context, request SteerRequest) (resultErr error)

Steer delivers an ordinary same-turn update without consuming the event stream or opening a successor. Only a running exact generation may be steered; interactions must be answered through their dedicated seams.

func (*Attachment) WaitNext

func (a *Attachment) WaitNext(ctx context.Context) (int, error)

WaitNext reports the encoded size of the next immediately readable event without advancing the cursor or copying/decoding its payload. A zero size means the next item is a gap or terminal condition. Protocol projectors use this readiness barrier to acquire transient-output memory before Next clones a potentially large replay event. The size is advisory if another goroutine consumes the same Attachment concurrently; callers should keep one consumer per attachment, as they already must to preserve projection order.

type AttachmentState

type AttachmentState struct {
	Generation       sessionstore.Generation
	Phase            Phase
	Latest           Cursor
	ActiveTurn       bool
	PendingApprovals int
	PendingInput     bool
}

AttachmentState is a lightweight view of the state needed for connection lifecycle decisions. Unlike Snapshot it never includes approval payloads or allocates slices, so polling it cannot amplify a large pending approval.

type Config

type Config struct {
	Store         sessionstore.ResumeStore
	DurableResume bool
	// WorkspaceCoordinator resolves the immutable local binding used by one
	// session generation. Nil selects the Registration's static workspace.
	WorkspaceCoordinator WorkspaceCoordinator
	// WorkspaceLeaseProvider exclusively fences active turns. Nil selects the
	// process-wide local provider, shared across Registry instances.
	WorkspaceLeaseProvider WorkspaceLeaseProvider
	// ExecutionPolicy adds authoritative external admission/accounting without
	// weakening any of the hard limits below. Nil selects the static policy.
	ExecutionPolicy ExecutionPolicy
	// FileReferencePolicy is the sole opt-in boundary for inbound URL-backed A2A
	// File Parts. Nil rejects every URL reference. Core always performs its own
	// structural validation before invoking this caller-owned policy; a policy can
	// authorize a reference but cannot weaken that validation or mutate the Turn.
	FileReferencePolicy FileReferencePolicy
	// Lifecycle receives payload-free advisory transitions through a caller-owned
	// bounded Dispatcher. The Registry never closes it and observation can never
	// alter or delay authoritative state. Nil disables observation.
	Lifecycle      *lifecycle.Dispatcher
	MaxSessions    int
	RingMaxEvents  int
	RingMaxBytes   int
	OpenTimeout    time.Duration
	ControlTimeout time.Duration
	IdleTTL        time.Duration
	// TurnInactivityTTL bounds a running turn which produces no agent events.
	// Approval and elicitation waits are excluded and governed independently by
	// their interaction deadlines.
	TurnInactivityTTL time.Duration
	// MaxTurnDuration is an absolute wall-clock ceiling from successful execution
	// policy/workspace admission through terminal Done, including approval waits.
	// Time spent waiting for that bounded admission is governed by the caller and
	// ControlTimeout. Unlike inactivity timers it is never refreshed by output.
	MaxTurnDuration time.Duration
	// MaxTurnEvents and MaxTurnEventBytes are cumulative source-admission limits
	// for one turn. Ring eviction does not refund them. Done uses the Registry's
	// separate bounded terminal reserve and is not charged to these counters.
	MaxTurnEvents           int
	MaxTurnEventBytes       int64
	ApprovalTTL             time.Duration
	ElicitationTTL          time.Duration
	MaxTurnHistory          int
	MaxApprovalsPerTurn     int
	MaxPendingApprovalBytes int
	MaxDecisionReasonBytes  int
	ReplayMaxBytes          int
	// EndedReplayTTL retains the bounded event ring of a successfully opened,
	// ended generation so an exact-generation observer can recover events lost
	// across a transport disconnect. Retention never keeps the agent process alive.
	EndedReplayTTL time.Duration
	// MaxEndedGenerations bounds retained generation metadata independently of
	// MaxSessions, which counts only live agent processes.
	MaxEndedGenerations int
	// TerminalSettlementTTL is the maximum time an emitted Done may remain
	// unacknowledged by its protocol projector. Expiry fails closed by poisoning
	// continuity and retiring the exact generation.
	TerminalSettlementTTL time.Duration
}

Config controls the process-local registry. A ResumeStore is a checkpoint fence, not a distributed lease: one NamespaceID may have only one live Registry unless an embedding layer supplies a separate authoritative lease.

type ControlMode

type ControlMode uint8

ControlMode controls whether an attachment may mutate the live session.

const (
	Observe ControlMode = iota
	Control
	Takeover
)

type ConversationRef

type ConversationRef struct {
	// contains filtered or unexported fields
}

ConversationRef is the protocol-neutral identity resolved from an A2A request. Owner, tenant, workspace, and registration scope are deliberately not caller-populable fields.

func NewConversationRef

func NewConversationRef(contextID string) (ConversationRef, error)

NewConversationRef validates a context ID without exposing it in errors.

func (ConversationRef) ContextID

func (r ConversationRef) ContextID() string

ContextID returns the protocol conversation identity.

type Cursor

type Cursor struct {
	Generation sessionstore.Generation
	Seq        uint64
}

Cursor identifies the event position within one live session incarnation.

type Descriptor

type Descriptor struct {
	NamespaceID    string `json:"namespaceId"`
	RegistrationID string `json:"registrationId"`
	ContinuityID   string `json:"continuityId"`
	DriverID       string `json:"driverId"`
	WorkspaceID    string `json:"workspaceId"`
}

Descriptor is the complete non-sensitive view of a Registration.

type ElicitationSnapshot

type ElicitationSnapshot struct {
	Turn        TurnRef
	ID          string
	Cursor      Cursor
	RequestedAt time.Time
	Delivering  bool
}

ElicitationSnapshot identifies the one ordinary-input request which currently pauses a turn. Prompt/schema remain in the replay event; the mutable snapshot carries only the bounded identity required for exact continuation.

type EnvironmentProvider

type EnvironmentProvider interface {
	ResolveEnvironment(context.Context, Principal) (SecretEnv, error)
}

EnvironmentProvider resolves the environment for an already-authenticated principal during session open. Implementations may read a secret manager or return a static SecretEnv.

Implementations must be safe for concurrent use, check an already-canceled context before doing work, and return promptly after ctx is canceled. They must construct results with NewSecretEnv, return detached state, keep errors payload-free, and must not call back into the Registry. The Registry never closes a provider.

The Registry invokes providers through a fixed-size managed lane. Synchronous panics and non-context provider errors become ErrEnvironmentUnavailable; panic and error payloads are never propagated. A call which ignores ctx does not hold a session generation past Config.OpenTimeout, but it continues to occupy its lane until the implementation actually returns. This bounds goroutine growth instead of starting unbounded replacement calls.

type EventItem

type EventItem struct {
	Cursor Cursor
	Turn   TurnRef
	Event  agent.Event
	// Terminal is a non-forgeable settlement capability on a controller's Done
	// delivery. A protocol projector must complete it exactly once: Projected
	// makes the staged resume checkpoint clean before admitting a successor;
	// Unprojected poisons continuity and retires the exact generation. Observers
	// and nonterminal events receive nil.
	Terminal TerminalClaim
}

type ExecutionOperation

type ExecutionOperation string

ExecutionOperation identifies one Registry admission boundary.

const (
	ExecutionAttach    ExecutionOperation = "attach"
	ExecutionOpen      ExecutionOperation = "open"
	ExecutionStartTurn ExecutionOperation = "start-turn"
	ExecutionRespond   ExecutionOperation = "respond"
	ExecutionElicit    ExecutionOperation = "respond-elicitation"
	ExecutionSteer     ExecutionOperation = "steer"
	ExecutionInterrupt ExecutionOperation = "interrupt"
)

type ExecutionOutcome

type ExecutionOutcome struct {
	Result ExecutionResult
	Usage  agent.Usage
}

ExecutionOutcome completes one permit. Usage is the last successfully accepted cumulative session snapshot for a StartTurn permit, not a sum.

type ExecutionPermit

type ExecutionPermit interface {
	ObserveUsage(context.Context, agent.Usage) error
	Complete(context.Context, ExecutionOutcome) error
}

ExecutionPermit is the lifetime returned by ExecutionPolicy. ObserveUsage is called serially only for a StartTurn permit and receives cumulative snapshots which must replace, never add to, the prior value. Complete is called exactly once by core with a bounded cleanup context; implementations must nevertheless make it safe and idempotent for concurrent repetition so network retries can use the same implementation. Neither method may call back into the Registry. Panic, error, or a usage rejection fails closed. Core retains its Config hard limits regardless of which policy is injected.

type ExecutionPolicy

type ExecutionPolicy interface {
	AdmitExecution(context.Context, ExecutionRequest) (ExecutionPermit, error)
}

ExecutionPolicy admits authoritative Registry operations. Implementations may enforce external quotas, queues, accounting, or fairness. They must be safe for concurrent use, honor ctx, return a distinct non-nil permit for each successful call, and must not call back into the Registry. The Registry never closes the policy. Panic and nil permits fail closed.

Attach permits cover one Attach call; Open permits cover creation of one driver session; Respond and Interrupt permits cover one driver-facing control delivery. A StartTurn permit remains owned by the Registry through approvals until terminal and receives cumulative Usage snapshots.

func NewStaticExecutionPolicy

func NewStaticExecutionPolicy() ExecutionPolicy

NewStaticExecutionPolicy returns the built-in permissive admission layer. Safety remains backed by immutable Registry Config limits (sessions, turn time/events/bytes, approvals, replay, and control timeouts); replacing this policy cannot disable those limits.

type ExecutionRequest

type ExecutionRequest struct {
	Operation    ExecutionOperation
	Registration Descriptor
	Principal    Principal
	Conversation ConversationRef
	Generation   sessionstore.Generation
	Turn         TurnRef
	ApprovalID   string
	WorkspaceID  string
}

ExecutionRequest is a bounded, payload-free policy input. It intentionally excludes turns, approval decisions, events, environment, resume tokens, and workspace paths. Generation, Turn, ApprovalID, and WorkspaceID are populated only where meaningful for Operation.

type ExecutionResult

type ExecutionResult string

ExecutionResult is the payload-free completion classification reported to a permit. It is not an A2A task state and never enters the wire.

const (
	ExecutionSucceeded ExecutionResult = "succeeded"
	ExecutionFailed    ExecutionResult = "failed"
	ExecutionCanceled  ExecutionResult = "canceled"
)

type ExpiryKind

type ExpiryKind string

ExpiryKind identifies the fixed Registry governor which terminated a turn. Values are protocol data: callers should compare them with the exported constants instead of depending on free-form terminal text.

const (
	ApprovalDeadline    ExpiryKind = "approval-deadline"
	ElicitationDeadline ExpiryKind = "elicitation-deadline"
	TurnDuration        ExpiryKind = "turn-duration"
	TurnInactivity      ExpiryKind = "turn-inactivity"
)

type FileReferencePolicy

type FileReferencePolicy interface {
	AuthorizeFileReference(context.Context, Principal, agent.Part) error
}

FileReferencePolicy is the explicit opt-in boundary for URL-backed inbound A2A File Parts. Implementations receive an immutable authenticated Principal and a detached Part copy. Mutating or retaining the Part cannot alter the Turn delivered to the driver.

Implementations must be safe for concurrent use, honor ctx, return promptly after cancellation, avoid putting URLs or credentials in errors, and must not call back into the Registry. The Registry never closes a policy.

Core rejects every URL unless a policy is installed. Even with a policy, only bounded, valid absolute HTTP(S) references without userinfo or fragments can reach this callback. The callback therefore grants authority; it does not replace core structural validation or perform fetching on core's behalf.

type FileReferencePolicyFunc

type FileReferencePolicyFunc func(context.Context, Principal, agent.Part) error

FileReferencePolicyFunc adapts a function to FileReferencePolicy.

func (FileReferencePolicyFunc) AuthorizeFileReference

func (f FileReferencePolicyFunc) AuthorizeFileReference(ctx context.Context, principal Principal, part agent.Part) error

type GapItem

type GapItem struct {
	Reason        GapReason
	Requested     Cursor
	AvailableFrom Cursor
}

type GapReason

type GapReason string
const (
	GapEvicted           GapReason = "evicted"
	GapGenerationChanged GapReason = "generation-changed"
	// GapSuperseded advances over an approval which was resolved while waiting
	// for protocol output admission. It makes the skipped cursor explicit without
	// resurrecting an actionable prompt.
	GapSuperseded GapReason = "superseded"
)

type InterruptClaim

type InterruptClaim interface {
	Complete(context.Context) error
	// contains filtered or unexported methods
}

InterruptClaim is an opaque terminal owner for one exact generation-scoped turn. BeginInterrupt atomically makes the generation unavailable before returning it; Complete must then be called to interrupt the driver and publish the registry terminal. Complete is safe to call repeatedly and concurrently.

Keeping this operation two-phase lets a protocol bridge fence the agent turn, publish its own canceled terminal, and only then wait on driver teardown. A claim deliberately exposes no registry key, principal, or resumable token. The unexported marker makes claims non-forgeable and, importantly, prevents a value copy from duplicating its sync.Once terminal owner.

type Phase

type Phase string
const (
	PhaseOpening          Phase = "opening"
	PhaseIdle             Phase = "idle"
	PhaseStarting         Phase = "starting"
	PhaseRunning          Phase = "running"
	PhaseAwaitingApproval Phase = "awaiting-approval"
	PhaseAwaitingInput    Phase = "awaiting-input"
	PhaseInterrupting     Phase = "interrupting"
	PhaseTerminalPending  Phase = "terminal-pending"
	PhaseClosing          Phase = "closing"
	PhaseEnded            Phase = "ended"
)

type PreparedTurn

type PreparedTurn struct {
	// contains filtered or unexported fields
}

PreparedTurn is an opaque, immutable authorization ticket for one exact principal, conversation, turn ID, and cloned input value. PrepareTurn creates it before a protocol task is persisted; StartPreparedTurn consumes that exact snapshot after persistence succeeds, so policy validation and driver delivery cannot observe different inputs.

Callers cannot construct or inspect a valid ticket. A ticket is bound to the Registry which created it and may only be used by an Attachment for the same principal and conversation. Reusing it is safe only as an idempotent retry of the same turn ID.

type Principal

type Principal struct {
	// contains filtered or unexported fields
}

Principal is an immutable authenticated owner and authorized tenant. The fields are private so request decoders cannot populate them accidentally; the trusted authentication layer constructs one with NewPrincipal.

func NewPrincipal

func NewPrincipal(owner, tenant string) (Principal, error)

NewPrincipal validates a stable authenticated owner and optional authorized tenant. Values are never included in errors.

func (Principal) OwnerID

func (p Principal) OwnerID() string

OwnerID returns the stable authenticated owner for trusted policy providers.

func (Principal) TenantID

func (p Principal) TenantID() string

TenantID returns the tenant authorized by the authentication layer.

type ProjectionRejectionClaim

type ProjectionRejectionClaim interface {
	Complete(context.Context) error
	// contains filtered or unexported methods
}

ProjectionRejectionClaim is an opaque, exactly-once finalizer for rejecting output from one exact generation-scoped turn. BeginProjectionRejection seals the generation before returning. Complete then either interrupts a still-live turn or settles an already-admitted Done as unprojected; it never sends an interrupt for a token which has already completed.

Keeping rejection two-phase lets a protocol bridge publish its own failure after fencing the generation but before waiting for driver teardown or a durable poison checkpoint. Complete must be called for every successful claim and is safe to call repeatedly and concurrently.

type Registration

type Registration struct {
	// contains filtered or unexported fields
}

Registration is an immutable driver registration. All fields are private so consumers cannot mutate policy or retrieve its workspace path/environment. Future registry lifecycle code in this package is the sole consumer of those sensitive fields.

func NewRegistration

func NewRegistration(spec RegistrationSpec) (*Registration, error)

NewRegistration validates spec and snapshots its immutable configuration. A nil Environment means an empty overlay. Registration IDs and ContinuityID must remain stable across restarts; bump ContinuityID whenever resuming an old driver token under changed credentials or policy would be unsafe.

func (*Registration) DeriveKey

func (r *Registration) DeriveKey(principal Principal, conversation ConversationRef) (sessionstore.Key, error)

DeriveKey combines immutable registration scope with an authenticated principal and context reference. No caller supplies individual store-key dimensions, and the continuity epoch prevents token reuse after a deliberate registration security-domain change.

func (*Registration) Descriptor

func (r *Registration) Descriptor() Descriptor

Descriptor returns a value-only non-sensitive registration description.

func (Registration) Format

func (r Registration) Format(state fmt.State, _ rune)

Format prevents generic formatting from traversing Registration's private driver, provider, workspace path, profile, or environment state.

func (Registration) GoString

func (r Registration) GoString() string

GoString formats only the non-sensitive Descriptor.

func (Registration) MarshalJSON

func (r Registration) MarshalJSON() ([]byte, error)

MarshalJSON exposes exactly Descriptor and no sensitive registration state.

func (Registration) String

func (r Registration) String() string

String formats only the non-sensitive Descriptor.

type RegistrationSpec

type RegistrationSpec struct {
	NamespaceID    string
	RegistrationID string
	ContinuityID   string
	Driver         agent.Driver
	Workspace      WorkspaceSpec
	Profile        agent.Profile
	Environment    EnvironmentProvider
}

RegistrationSpec is the trusted machine-owner input to NewRegistration. Its maps and path are copied into private immutable registration state.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry is the sole owner and event consumer for every live Session in one immutable Registration.

func New

func New(registration *Registration, config Config) (*Registry, error)

New creates an empty Registry for one immutable Registration.

func (*Registry) Attach

func (r *Registry) Attach(ctx context.Context, request AttachRequest) (attachment *Attachment, resultErr error)

Attach attaches to, creates, or resumes the exact logical conversation.

func (*Registry) Capabilities

func (r *Registry) Capabilities() (agent.Caps, bool)

Capabilities returns the immutable capability snapshot activated by a successful Probe. Protocol assemblies use the boolean to distinguish an all-false Manifest from a Registry which has not yet crossed its Probe boundary; unprobed registries must not expose caller-visible operations based on guessed capabilities.

func (*Registry) ClaimConsumer

func (r *Registry) ClaimConsumer(name string) (func(), error)

ClaimConsumer reserves one process-local projection lane. A protocol bridge which turns replayable registry events into side effects (for example A2A task-store updates) must have a single owner; independent Attachments are observers and would otherwise replay and publish the same event twice. The returned release function is idempotent.

func (*Registry) ClaimExpiryHandler

func (r *Registry) ClaimExpiryHandler(name string, handler func(TurnExpiry)) (func(), error)

ClaimExpiryHandler installs the Registry's single timer-terminal consumer. The handler receives only opaque scope and exact generation/turn/cursor fences; it never receives task identity or user-controlled content.

Calls are serialized on a dedicated bounded worker and never execute on a session pump or timer goroutine. The handler must return promptly and must not call its own release function or Registry.Close: both drain the callback which is presently running and are therefore intentionally non-reentrant. release is idempotent, prevents new handoffs, and waits for every already-accepted callback before returning. A new handler may be claimed after release completes.

func (*Registry) Close

func (r *Registry) Close(ctx context.Context) error

Close drains the registry boundary. It rejects new attachments, cancels opens and control calls, closes each exact session once, and waits until no old process remains mapped. It never closes the injected store or driver.

func (*Registry) ControlTimeout

func (r *Registry) ControlTimeout() time.Duration

ControlTimeout returns the immutable driver-control and injected-seam bound selected when the Registry was constructed. Protocol assemblies may use it to reject conflicting endpoint options; it does not expose the mutable Config value or permit reconfiguration of a running Registry.

func (*Registry) Descriptor

func (r *Registry) Descriptor() Descriptor

Descriptor returns the non-sensitive identity of the immutable registration owned by this Registry. Embedding layers use it to verify that discovery and execution are assembled around the same driver without gaining access to the workspace path, environment, profile, or resume state.

func (*Registry) DurableResumeEnabled

func (r *Registry) DurableResumeEnabled() bool

DurableResumeEnabled reports the Registry's actual checkpoint policy. It is intentionally distinct from Caps.Resume: a driver may support resume while a particular Registry has no durable store configured.

func (*Registry) Key

func (r *Registry) Key(principal Principal, conversation ConversationRef) (sessionstore.Key, error)

Key derives the opaque storage scope from trusted registration and principal state. It never accepts owner/tenant/workspace/driver dimensions separately.

func (*Registry) LifecycleDispatcher

func (r *Registry) LifecycleDispatcher() *lifecycle.Dispatcher

LifecycleDispatcher returns the caller-owned dispatcher used by this Registry, or nil when observation is disabled. It exists so a higher-level assembly can reject a conflicting observer instead of silently leaving some execution paths unobserved. Callers must not close the returned dispatcher until Registry.Close has completed.

func (*Registry) MaxReplayEventBytes

func (r *Registry) MaxReplayEventBytes() int

MaxReplayEventBytes reports the configured upper bound for one encoded agent.Event in the Registry ring. Protocol projectors use it only to verify their own frame limit at assembly time; it exposes no session state.

func (*Registry) MaxSnapshotBytes

func (r *Registry) MaxSnapshotBytes() int64

MaxSnapshotBytes reports a conservative serialized upper bound for one Registry Snapshot under the configured pending-approval limits. Protocol servers compare it with their frame limit before accepting connections; a reconnect must never discover only after attachment that its authoritative approval snapshot cannot be represented.

func (*Registry) PrepareTurn

func (r *Registry) PrepareTurn(
	ctx context.Context,
	principal Principal,
	conversation ConversationRef,
	request StartTurnRequest,
) (*PreparedTurn, error)

PrepareTurn takes an ownership-safe snapshot and authorizes every inbound URL reference before a session is opened or a driver side effect can occur. A2A bridges use this phase before persisting SUBMITTED, then pass the returned ticket to StartPreparedTurn only after task persistence succeeds.

func (*Registry) Probe

func (r *Registry) Probe(ctx context.Context) (agent.Manifest, error)

Probe reports capabilities from the exact immutable driver registration that opens this Registry's sessions. Server assembly uses this instead of probing a second same-ID Driver value whose model, environment, or binary may differ.

func (*Registry) SessionLimit

func (r *Registry) SessionLimit() int

SessionLimit returns the immutable maximum number of simultaneously mapped live agent sessions. Embedding layers use it to size one-session-per-terminal queues without duplicating Registry configuration or weakening its bound.

func (*Registry) Stats

func (r *Registry) Stats() RegistryStats

Stats returns an approximate point-in-time aggregate. Entries may advance phase while the snapshot is collected, but every field is race-safe and the result owns its map independently of the Registry.

type RegistryStats

type RegistryStats struct {
	Closed                 bool
	LiveSessions           int
	EndedGenerations       int
	Attachments            int
	AttachWaiters          int
	ActiveTurns            int
	PendingApprovals       int
	ReplayBytes            int64
	ReplayLimitBytes       int64
	ExpiryHandlerClaimed   bool
	ExpiryCallbacksPending int
	ExpiryHandlerPanics    uint64
	SessionsByPhase        map[Phase]int
}

RegistryStats is a bounded, payload-free point-in-time view for embedding metrics and health adapters. It never exposes keys, principals, workspace paths, resume tokens, approval payloads, or event contents.

type RespondElicitationRequest

type RespondElicitationRequest struct {
	Turn      TurnRef
	RequestID string
	Response  agent.ElicitationResponse
}

RespondElicitationRequest answers one ordinary-input request on the exact active turn. RequestID is the opaque driver identity; the Registry resolves the adapter-owned TurnToken internally so protocol bridges never handle it.

type RespondRequest

type RespondRequest struct {
	Turn       TurnRef
	ApprovalID string
	Decision   agent.Decision
}

type SecretEnv

type SecretEnv struct {
	// contains filtered or unexported fields
}

SecretEnv is an immutable, redacted subprocess environment overlay. Values can be copied out only by code in this package when opening a registered session; formatting and JSON serialization never disclose keys or values.

func NewSecretEnv

func NewSecretEnv(values map[string]string) (SecretEnv, error)

NewSecretEnv validates and copies values. Subsequent mutations of the input map cannot change the returned environment. Neither invalid keys nor values are included in errors.

func (SecretEnv) Format

func (SecretEnv) Format(state fmt.State, _ rune)

Format redacts the environment for every fmt verb, flag, width, and precision.

func (SecretEnv) GoString

func (SecretEnv) GoString() string

GoString implements fmt.GoStringer without exposing the environment.

func (SecretEnv) MarshalJSON

func (SecretEnv) MarshalJSON() ([]byte, error)

MarshalJSON prevents Registration or provider results from disclosing subprocess credentials through generic JSON logging.

func (SecretEnv) String

func (SecretEnv) String() string

String implements fmt.Stringer without exposing the environment.

func (*SecretEnv) UnmarshalJSON

func (*SecretEnv) UnmarshalJSON([]byte) error

UnmarshalJSON refuses a lossy redacted representation. Trusted callers must construct environments explicitly with NewSecretEnv.

type Snapshot

type Snapshot struct {
	Generation  sessionstore.Generation
	Phase       Phase
	Oldest      Cursor
	Latest      Cursor
	Active      *TurnSnapshot
	Pending     []ApprovalSnapshot
	Elicitation *ElicitationSnapshot
}

type StartTurnRequest

type StartTurnRequest struct {
	ID    TurnID
	Input agent.Turn
}

type SteerRequest

type SteerRequest struct {
	Turn   TurnRef
	Update agent.Turn
}

SteerRequest augments one exact running turn without opening a successor. Steering is deliberately unavailable while the turn is paused on approval or elicitation because those states have their own unambiguous continuation.

type StreamItem

type StreamItem interface {
	// contains filtered or unexported methods
}

type TerminalClaim

type TerminalClaim interface {
	Complete(context.Context, TerminalOutcome) error
	// contains filtered or unexported methods
}

TerminalClaim is a non-forgeable, exactly-once settlement capability for a Done event. The first valid outcome wins. Repeating that outcome is idempotent; trying the opposite outcome returns ErrTerminalOutcomeConflict.

Once Complete claims an outcome, finalization is not abandoned when ctx is canceled. Registry checkpoint operations remain bounded by ControlTimeout.

type TerminalOutcome

type TerminalOutcome uint8

TerminalOutcome records whether the protocol boundary durably accepted a terminal event. A terminal checkpoint is deliberately kept non-resumable until this outcome is known.

const (
	// TerminalProjected means the protocol boundary accepted the Done event. A
	// resumable terminal may now advance its checkpoint to clean.
	TerminalProjected TerminalOutcome = iota + 1
	// TerminalUnprojected means the Done event was not accepted. Continuity is
	// poisoned and the exact live generation is retired.
	TerminalUnprojected
)

type TurnExpiry

type TurnExpiry struct {
	Scope             sessionstore.Digest
	Turn              TurnRef
	ApprovalID        string
	ApprovalCursor    Cursor
	ElicitationID     string
	ElicitationCursor Cursor
	TerminalCursor    Cursor
	Kind              ExpiryKind
}

TurnExpiry is the payload-free identity of a turn terminated by a Registry timer. Scope is the opaque digest of the trusted registration/principal/ conversation key. ApprovalID and ApprovalCursor are populated only for an approval deadline. TerminalCursor identifies the exact failed Done appended before this notification was handed off.

It deliberately contains no task ID, owner, tenant, workspace path, user input, approval payload, resume token, or free-form failure text. Embedding layers may use the opaque scope and exact turn/cursor fences to settle their own durable projection.

type TurnID

type TurnID string

type TurnRef

type TurnRef struct {
	ID         TurnID
	Generation sessionstore.Generation
}

TurnRef fences a logical turn to the exact live session incarnation which accepted it.

type TurnSnapshot

type TurnSnapshot struct {
	Turn      TurnRef
	StartedAt time.Time
}

type WorkspaceBinding

type WorkspaceBinding struct {
	// contains filtered or unexported fields
}

WorkspaceBinding is the immutable result of workspace resolution. ID is a stable non-secret identity suitable for an external lease key; Path is the canonical local path passed to agent.Driver.Open. Generic formatting and JSON serialization expose only ID so accidental logging cannot disclose host layout. Trusted coordinator and lease implementations may call Path.

func NewWorkspaceBinding

func NewWorkspaceBinding(id, path string) (WorkspaceBinding, error)

NewWorkspaceBinding validates and snapshots one resolved local workspace. The path is made absolute and clean at this ownership-transfer boundary.

func (WorkspaceBinding) Format

func (b WorkspaceBinding) Format(state fmt.State, _ rune)

func (WorkspaceBinding) GoString

func (b WorkspaceBinding) GoString() string

func (WorkspaceBinding) ID

func (b WorkspaceBinding) ID() string

ID returns the stable non-secret identity chosen by the coordinator.

func (WorkspaceBinding) MarshalJSON

func (b WorkspaceBinding) MarshalJSON() ([]byte, error)

MarshalJSON exposes only the stable ID, never the host path.

func (WorkspaceBinding) Path

func (b WorkspaceBinding) Path() string

Path returns the canonical local path. Callers must treat it as sensitive host topology and must not include it in logs, metrics, errors, or wire data.

func (WorkspaceBinding) String

func (b WorkspaceBinding) String() string

type WorkspaceCoordinator

type WorkspaceCoordinator interface {
	ResolveWorkspace(context.Context, WorkspaceRequest) (WorkspaceBinding, error)
	ReleaseWorkspace(context.Context, WorkspaceBinding) error
}

WorkspaceCoordinator resolves one stable binding before Driver.Open.

Implementations must be safe for concurrent use, honor ctx, and return the same binding ID and path for the same request while the registration's ContinuityID is unchanged. A successful ResolveWorkspace transfers one binding reference to the Registry; ReleaseWorkspace is called exactly once after the session has closed (including open failure). Implementations must not call back into the Registry from either method. The Registry does not close the coordinator itself. A panic is contained and fails the open closed.

func NewStaticWorkspaceCoordinator

func NewStaticWorkspaceCoordinator(spec WorkspaceSpec) (WorkspaceCoordinator, error)

NewStaticWorkspaceCoordinator returns the built-in resolver for a fixed local path. It is concurrency-safe and allocates no per-resolution resources.

type WorkspaceLease

type WorkspaceLease interface {
	Release(context.Context) error
}

WorkspaceLease is the exclusive active-turn claim returned by a provider. Release must be safe for concurrent and repeated calls, must honor ctx for remote cleanup, and must never call back into the Registry. Core also wraps it with exactly-once ownership. A canceled ctx does not authorize abandoning a process-local lock; implementations should release locally owned state before returning the context error. Panic is contained and retires the session.

type WorkspaceLeaseProvider

type WorkspaceLeaseProvider interface {
	AcquireWorkspaceLease(context.Context, WorkspaceLeaseRequest) (WorkspaceLease, error)
}

WorkspaceLeaseProvider acquires an exclusive claim before Session.SendTurn and keeps it through every approval response and interrupt until terminal. It must be safe for concurrent use and honor ctx while waiting. The Registry owns every successfully returned non-nil lease, but never closes the provider. A panic or a nil lease fails closed before driver side effects.

func NewProcessLocalWorkspaceLeaseProvider

func NewProcessLocalWorkspaceLeaseProvider() WorkspaceLeaseProvider

NewProcessLocalWorkspaceLeaseProvider returns an exclusive provider whose lock key is the canonical workspace path. Share one instance across every Registry which may address the same files. It has no goroutines and requires no Close; empty lock records are reclaimed after the final waiter releases.

type WorkspaceLeaseRequest

type WorkspaceLeaseRequest struct {
	Registration Descriptor
	Principal    Principal
	Conversation ConversationRef
	Turn         TurnRef
	Binding      WorkspaceBinding
}

WorkspaceLeaseRequest identifies one active turn and its resolved binding. It is payload-free and safe to retain for accounting or lock ownership.

type WorkspaceRequest

type WorkspaceRequest struct {
	Registration Descriptor
	Principal    Principal
	Conversation ConversationRef
}

WorkspaceRequest is the payload-free identity supplied to a coordinator. Values are immutable snapshots; implementations may retain them. It contains no input, event, approval, environment, resume token, or workspace path.

type WorkspaceSpec

type WorkspaceSpec struct {
	ID   string
	Path string
}

WorkspaceSpec binds a stable, non-secret identity to a local path. ID enters the durable key; Path is canonicalized at registration and is never exposed by Registration or Descriptor.

Directories

Path Synopsis
Package registrytest provides hermetic contract harnesses for implementations injected into sessionregistry.
Package registrytest provides hermetic contract harnesses for implementations injected into sessionregistry.

Jump to

Keyboard shortcuts

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