durable

package
v0.3.0 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	TopicEvents = "events"
	TopicRetry  = "retry"
)

EventLog topics. Temporal Workflow Streams uses the same names.

View Source
const SessionKindSpecialist = "specialist"

SessionKindSpecialist is Status.Kind for spawn_specialist children.

Variables

View Source
var (
	// ErrSessionNotFound is unknown, closed, or already torn down.
	ErrSessionNotFound = errors.New("session not found")
	// ErrSessionExists is CreateSession with an id that is already live.
	ErrSessionExists = errors.New("session already exists")
	// ErrAgentNotFound is Catalog miss.
	ErrAgentNotFound = errors.New("agent not found")
	// ErrStaleCheckpoint is SnapshotStore.Save when expected Revision does not
	// match the row (another writer already saved). Reload and retry.
	ErrStaleCheckpoint = errors.New("stale checkpoint")
)

Functions

This section is empty.

Types

type AgentSpec

type AgentSpec struct {
	Name string
	// Options is the canonical agent definition. SessionID and MountSession
	// must be empty; the runtime injects those per turn.
	Options tacklr.AgentOptions
	// OpenVFS builds the agent /workspace tree (typically vfs.Tree). Nil means no VFS.
	OpenVFS vfs.OpenVFS
	// OpenSkills builds a host-only skills tree (typically vfs.Tree with
	// Union of packs). The agent MountSession never includes this tree.
	// Nil means no skills unless Options.SkillsLoader is set.
	OpenSkills vfs.OpenVFS
	// SkillsRoot is the virtual directory the loader walks on the skills
	// session. Empty means /workspace/skills.
	SkillsRoot string
}

AgentSpec is the immutable agent definition. Runtime injects SessionID and MountSession per turn. Protocol-neutral: no server.Protocol types.

type AuthContext

type AuthContext struct {
	// Bindings are this slice's mounts and/or provider tokens. A binding with
	// an alias upserts the recipe. A binding with only provider+token refreshes
	// every cached recipe for that provider.
	Bindings []vfs.Binding `json:"bindings,omitempty"`
	// Drop removes cached recipes by alias or provider. Applied before Bindings.
	Drop []string `json:"drop,omitempty"`
}

AuthContext is credentials and mount intent for one work item (Prompt, Resume, or a one-shot child workflow). Protocols map their wire auth into this type. Autonomous hosts set it on the payload that queues the work. Tokens are not stored in SnapshotStore or Temporal event history. The Temporal adapter writes them to SecretStorage before signaling.

func (AuthContext) WithoutSecrets added in v0.3.0

func (a AuthContext) WithoutSecrets() AuthContext

WithoutSecrets returns a copy with Credential Token and ExpiresAt cleared. Binding metadata (provider, alias, params, writable) is kept. The input is not modified.

type Catalog

type Catalog interface {
	Lookup(agentID string) (AgentSpec, bool)
	DefaultID() string
	IDs() []string
}

Catalog is the agent lookup table. Hosts construct it and pass it to inprocess.New or temporal.New. There is no backend plugin registry.

type CreateSession

type CreateSession struct {
	AgentID    string
	SessionID  SessionID
	MCPServers []mcp.MCPConfig
	// Mounts seeds the session recipe cache (no secrets). Tokens arrive on Prompt.
	Mounts []MountRecipe
	// Parent, when set, makes this a child session of that parent. The child
	// reuses the same wait loop. Empty MCPServers/Mounts inherit from parent.
	Parent SessionID
	// Specialist selects a Specialist from the parent's catalog spec. Required
	// with Parent for spawn_specialist children. The host does not register the
	// worker as a top-level catalog agent.
	Specialist string
	// State seeds checkpoint userState (JSON-serializable values).
	// Tools read it via HarnessRuntime.StateGet. Canonical copy is
	// Snapshot.Checkpoint, not Temporal workflow variables. No tokens or clients.
	// Child sessions do not inherit this map.
	State map[string]any
}

CreateSession is the typed input for Runtime.CreateSession.

type EventLog

type EventLog interface {
	Append(ctx context.Context, sessionID SessionID, topic string, ev tacklr.StreamEvent) error
	Subscribe(ctx context.Context, sessionID SessionID, after Seq) (<-chan tacklr.StreamEvent, error)
	Head(ctx context.Context, sessionID SessionID) (Seq, error)
	CloseSession(ctx context.Context, sessionID SessionID) error
}

EventLog is the portable progress stream. Temporal implements it with Workflow Streams. In-process uses a memory channel. Topics are TopicEvents and TopicRetry (activity attempt > 1).

type MemoryCatalog

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

MemoryCatalog is an in-process Catalog.

func NewCatalog

func NewCatalog(defaultID string) *MemoryCatalog

NewCatalog returns an empty catalog. defaultID may be empty.

func (*MemoryCatalog) DefaultID

func (c *MemoryCatalog) DefaultID() string

DefaultID implements Catalog.

func (*MemoryCatalog) IDs

func (c *MemoryCatalog) IDs() []string

IDs implements Catalog.

func (*MemoryCatalog) Lookup

func (c *MemoryCatalog) Lookup(agentID string) (AgentSpec, bool)

Lookup implements Catalog.

func (*MemoryCatalog) Register

func (c *MemoryCatalog) Register(agentID string, spec AgentSpec)

Register adds or replaces an agent. Panics on invalid spec (host misconfig).

type MemorySecretStorage added in v0.3.0

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

MemorySecretStorage is an in-memory SecretStorage for tests and single-process workers. Client and worker must share the same instance.

func NewMemorySecretStorage added in v0.3.0

func NewMemorySecretStorage() *MemorySecretStorage

func (*MemorySecretStorage) Delete added in v0.3.0

func (s *MemorySecretStorage) Delete(_ context.Context, sessionID SessionID) error

func (*MemorySecretStorage) Get added in v0.3.0

func (s *MemorySecretStorage) Get(_ context.Context, sessionID SessionID) (Secrets, error)

func (*MemorySecretStorage) Put added in v0.3.0

func (s *MemorySecretStorage) Put(_ context.Context, sessionID SessionID, secrets Secrets) error

type MountRecipe

type MountRecipe struct {
	Provider  string            `json:"provider"`
	Alias     string            `json:"alias"`
	Params    map[string]string `json:"params,omitempty"`
	SourceIDs []string          `json:"sourceIds,omitempty"`
	Writable  bool              `json:"writable,omitempty"`
}

MountRecipe is secret-free VFS context remembered across turns. It records where a mount came from (provider, alias, backend ids). File contents are never stored; providers lazy-load on open/read.

type Prompt

type Prompt struct {
	Text        string
	UserMessage *tacklr.Message
	// AgentID, when set, selects the catalog agent for this turn slice.
	AgentID string
	// MCPServers, when non-nil, replaces session-scoped MCP configs for this turn.
	MCPServers []mcp.MCPConfig
	Auth       AuthContext
	// State merges into checkpoint userState for this turn after restore.
	// JSON-serializable values only. No tokens or clients.
	State map[string]any
}

Prompt is the typed input for Runtime.Prompt.

type Resume

type Resume struct {
	Responses map[string][]byte
	Auth      AuthContext
	// State merges into checkpoint userState when the parked turn continues.
	State map[string]any
}

Resume is the typed input for Runtime.Resume (HITL answer plus optional auth).

type Revision

type Revision string

Revision is the SnapshotStore compare-and-swap token for one session row. The zero value means no row exists yet; the next Save creates it.

type Runtime

type Runtime interface {
	CreateSession(ctx context.Context, req CreateSession) (SessionID, error)
	Prompt(ctx context.Context, sessionID SessionID, msg Prompt) error
	Resume(ctx context.Context, sessionID SessionID, resume Resume) error
	// Cancel aborts the in-flight turn and stops child sessions. The parent
	// session stays open for a later Prompt. Client stop (session/cancel and
	// cancelling the original Prompt/Resume context) uses this.
	Cancel(ctx context.Context, sessionID SessionID) error
	// Close destroys the session and recursively stops children.
	Close(ctx context.Context, sessionID SessionID) error
	// Head is the current EventLog offset. Protocol pumps pass it to Subscribe
	// to tail from now (skip events from prior turns).
	Head(ctx context.Context, sessionID SessionID) (Seq, error)
	Subscribe(ctx context.Context, sessionID SessionID, after Seq) (Subscription, error)
	// Children returns child session ids of parent, in start order.
	Children(ctx context.Context, parent SessionID) ([]SessionID, error)
	// Status is running, complete, failed, or unknown. A child waiting on HITL
	// stays running until that interrupt is resolved.
	Status(ctx context.Context, id SessionID) (SessionStatus, error)
}

Runtime is the only session kernel API. Protocol handlers and hosts call it. Backends: in-process (goroutine wait loop) or Temporal (one workflow per session).

A later Restate/DBOS/custom-log adapter plugs in here. It must supply:

  • start a session process (workflow / durable handler)
  • signals: prompt, resume, cancel, close, child-waiting
  • named steps with heartbeat + retry: Inference; Tool (one call; the wait loop still schedules a batch)
  • start a child session process (same machine, overlay specialist)
  • query: status, children
  • append to EventLog (the adapter wakes the loop)

Leftover-tool and HITL rules live in tacklr.Next. Do not fork them.

Prompt and Resume signal the session; they do not return a harness. Subscribe yields StreamEvent values (message, tool, yield, error, complete).

VFS credentials travel on Prompt / Resume / CreateSession.Mounts — not as separate kernel bind RPCs. Protocols map wire auth into AuthContext.

type SecretStorage added in v0.3.0

type SecretStorage interface {
	// Put replaces Auth when secrets.Auth.Bindings is non-empty.
	// Empty Bindings (including drop-only) is a no-op on the bag.
	Put(ctx context.Context, sessionID SessionID, secrets Secrets) error
	// Get returns the last Put bag. Missing session: zero Secrets, nil error.
	Get(ctx context.Context, sessionID SessionID) (Secrets, error)
	Delete(ctx context.Context, sessionID SessionID) error
}

SecretStorage holds Secrets for Temporal activities. Runtime client and worker must share one instance. It is not SnapshotStore.

type Secrets added in v0.3.0

type Secrets struct {
	Auth AuthContext
}

Secrets is the session-scoped secret bag that must not enter Temporal history or SnapshotStore. Auth holds VFS credentials. Add fields here when more work-item secrets need the same path.

type Seq

type Seq uint64

Seq is a monotonically increasing EventLog offset for one session.

type SessionID

type SessionID string

SessionID is the durable agent session identifier.

func ChildSessionID

func ChildSessionID(parent SessionID, specialist, callID string) SessionID

ChildSessionID is the stable id for a spawn_specialist child session.

type SessionState

type SessionState string

SessionState is parent-facing session/job state. Child HITL does not change this from running until the interrupt is resolved and the child completes, fails, or is cancelled.

const (
	SessionRunning  SessionState = "running"
	SessionComplete SessionState = "complete"
	SessionFailed   SessionState = "failed"
	SessionUnknown  SessionState = "unknown"
)

type SessionStatus

type SessionStatus struct {
	ID         SessionID
	Parent     SessionID
	State      SessionState
	Specialist string
	Kind       string
	Result     string
	Err        error
	// Waiting is true while the session is parked for HITL. Parent-facing
	// State stays running until that interrupt is resolved.
	Waiting bool
}

SessionStatus is a value type returned by Runtime.Status. Not an interface.

type Snapshot

type Snapshot struct {
	AgentID    string
	Specialist string
	Parent     SessionID
	// Children are child session ids in start order (no handles, no tokens).
	Children   []SessionID
	Checkpoint tacklr.SessionCheckpoint
	Mounts     []MountRecipe
}

Snapshot is the session record in SnapshotStore. Both runtimes write the same shape. Wait-loop fields (leftover Temporal tool calls, MCP overlay, child futures) stay on the loop, not here.

type SnapshotStore

type SnapshotStore interface {
	Save(ctx context.Context, sessionID SessionID, snap Snapshot, expected Revision) (Revision, error)
	Load(ctx context.Context, sessionID SessionID) (Snapshot, Revision, error)
	Delete(ctx context.Context, sessionID SessionID) error
}

SnapshotStore is the session record: what the harness needs to think again after HITL or a worker recycle. It is not the wait loop and not credentials.

Frozen contents: SessionCheckpoint (window, plan, parked interrupt, userState), MountRecipe topology, and session identity (agent, parent, specialist, child ids). Tokens, file bytes, leftover unstarted Temporal tool calls, MCP env and headers, and child workflow futures never go here.

Save's expected Revision must match the last Load (zero if no row). Mismatch means another writer already saved — reload and retry.

type Subscription

type Subscription interface {
	Events() <-chan tacklr.StreamEvent
	Close() error
}

Subscription is one consumer of a session EventLog.

Directories

Path Synopsis
Package adapter is the Runtime wait-loop glue.
Package adapter is the Runtime wait-loop glue.
Package temporal is the Temporal adapter for durable.Runtime.
Package temporal is the Temporal adapter for durable.Runtime.

Jump to

Keyboard shortcuts

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