agent

package module
v0.22.0 Latest Latest
Warning

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

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

Documentation

Overview

Package agent provides the Scope Agent Framework execution kernel.

Definition owns immutable behavior and creates serializable Execution values; Engine owns Process lifecycle, Signal delivery, Effect dispatch, child composition, resource bounds, observation, and portable snapshots. Strategy payloads stay opaque to the kernel, and persistence stays a caller responsibility.

Engine and Process operations require a non-nil context. A nil context is a programming error and panics on a valid receiver; use context.TODO when the caller has not yet chosen a context. A canceled non-nil context follows each operation's cancellation contract.

The kernel exists for one purpose: a multi-step agent with children and external side effects must resume after a process restart with a stated meaning for every operation that was in flight. Everything below follows from that.

The execution waist

Every strategy intersects on exactly two interfaces:

type Definition interface {
	Descriptor() Descriptor
	Start(Input) (Execution, error)
	Restore(ExecutionState) (Execution, error)
}

type Execution interface {
	Step(context.Context, []Signal) (Transition, error)
	Snapshot() (ExecutionState, error)
}

The waist is not generic, because the Engine holds heterogeneous definitions homogeneously. Input, Output, Signal, Effect, and ExecutionState cross it as bounded, defensively copied JSON. Generics belong to edge adapters that convert a Go input to raw input and raw output back to a Go output; they never enter the contract the Engine has to hold.

Step

A Step is one cancellable, discardable, purely candidate reduction. It may not call a model, run a tool, perform any other external I/O, hide an unbounded loop, or start an unowned goroutine. An external operation can only be declared as an Effect and executed outside the Step.

These are cooperation contracts for implementations sharing one Go process. Capability checks mediate declared Effects; they do not sandbox arbitrary I/O. Cancellation and kill still depend on in-flight code returning and external operations settling. They cannot forcibly terminate a goroutine.

Three scales explain the kernel: the root tree is the consistency, commit, and recovery unit; a Process is the lifecycle and strategy-state isolation unit; a Step is the concurrency unit. Adding Processes to a tree adds isolated computation and external I/O concurrency, not authoritative commit parallelism. Independent commit throughput means separate root trees.

Each root tree has one private commit owner. Pure computation does not occupy the commit owner: a Process has at most one Step job in flight and siblings run in parallel. Only the owner revalidates and adopts a result. Process state owns local admission rules and deterministic transitions; the tree owner coordinates cross-Process waits, external jobs, durable acknowledgment, and publication. Candidate adoption and wait registration succeed together, or all new registrations are rolled back. When a kill, pause, cancel, or a new incarnation expires an attempt, the result and its error are discarded whole and the Execution is rebuilt from committed Execution state.

The owner services continuously ready control requests, job completions, and queued Processes in bounded scheduling turns. Queries do not wake execution. Pending commits and held freezes still block work that cannot cross those boundaries; a checkpoint still requires a safe tree cut. This is a scheduling guarantee, not a wall-clock deadline: implementations must honor their bounded execution contracts, and the Host owns storage deadlines. A progress checkpoint can acknowledge one Process while unrelated sibling jobs run. Their cut retains committed state and any prepared Effect frontier; their return cannot change that cut until the single commit owner resumes.

Before adopting initial or candidate state, the Engine captures Snapshot and successfully restores it through that Deployment's Definition. An unrestorable candidate cannot advance signal consumption or dispatch Effects. This admission check does not prove exact state equivalence or deterministic continuation: the Definition must establish those properties with conformance cases. Complete tree recovery also validates runtime identities, mailboxes, child ownership, settlements, and the exact Deployment binding. The Engine owns deployment identity; a Definition validates its own opaque state under that matching binding rather than duplicating deployment identity. RestoreTree retains captured authority, limits, budgets, and usage. EngineConfig resource defaults apply to new root trees; the Host must authorize a captured tree before restoring it under current policy. Recovery never silently edits historical grants or repeats initialization admission.

Lifecycle timestamps are observed UTC wall times, not causal ordering proofs. Clock adjustment or a different restoration writer can put a finish before a start, or a child start before its parent. Identities, relations, Step progress, and committed lifecycle facts establish causality; timestamps must be present but need not increase.

Effects and settlement

An Effect is the only way an Execution requests work outside a Step. The Engine derives a stable effect identity from the Process identity, step sequence, and effect index, then freezes the payload. It interprets only its own closed set of framework Effects: RequestWait, StartChild, WaitForChildren, SignalChild, and CancelChild. It hands a strategy effect whole to the dispatcher its Deployment bound. A Deployment without a dispatcher admits only framework Effects, including during recovery. A dispatcher never mutates an Execution; it produces deltas and one settlement Signal.

Dispatcher Effects advance through planned, pending, and settled in declaration order, one at a time:

  1. the owner validates candidate state, signal consumption, budget, capability, and batch identity;
  2. the effect enters pending, and in durable mode the pending boundary commits the whole tree first;
  3. only then does the dispatcher job start, outside the owner;
  4. the result is normalized to a definite or an unknown settlement;
  5. only after the settled boundary succeeds does the owner install the settlement, candidate state, mailbox, and Process transition.

Direct-child controls need no external pending attempt. Their recipient change and definite settlement share one tree commit; the recipient cannot consume newly delivered input before durable acknowledgment.

A planned effect that was never dispatched can never become unknown. Automatic redelivery is allowed only where replaying one effect identity is proven to be the same logical operation; where it is not, an unknown settlement stays observable and awaits explicit adjudication. It is never silently replayed and never assumed successful. Ephemeral mode runs the same state machine without calling the durability port. A prepared batch has one execution frontier: definitely settled Effects precede at most one pending or unknown Effect, followed only by planned Effects. Runtime scheduling and snapshot admission enforce this same order. Terminal intent stops the remaining batch without adopting candidate state or advancing input consumption. The terminal snapshot retains the started prefix's actual settlements and the unstarted planned tail. PreparedEffects usage and published child allocations remain charged; unused Step and settlement-Signal reservations are released. Restoring this terminal evidence neither executes the candidate nor replays its Effects. If installing a settled batch fails, the same boundary retains its actual settlements without adopting the candidate or partially installing waits. A restored pending external attempt becomes Unknown when termination forbids replay. An interrupted child start whose child is absent from the authoritative cut becomes a failed publication; its Host admission may already have run.

Signals and waiting

A Signal is the only runtime input into an Execution. Process.DeliverSignals admits one ordered batch atomically, including a batch with one Signal. Repeated submission of one signal identity produces exactly one logical consumption and never charges the signal budget twice. The same identity with different immutable content is rejected as a conflict. In durable mode, successful admission is acknowledged only after mailbox records and budget charges commit to the authoritative tree head. The consumption cursor advances only when candidate state and transition commit, so a failed Step never permanently swallows input. ProcessSnapshot.SignalReceipts exposes the same admitted identities and committed consumption cursor for delivery reconciliation and input cutover. SignalReceipt.Matches proves external admission, including after consumption. Internal wait-opening and child-wait settlement Signals cannot prove an external delivery even when their identity and payload agree. A terminal Process may retain inputs admitted after its final Signal window. Their original recipient binding and pending payload remain observable. Consumption is bounded by the Signal window delivered to that Step; input admitted while the Step runs belongs to a later window. Once consumed, a mailbox record keeps its identity, addressed wait, arrival order, and normalized payload digest. The payload itself is released with candidate adoption. Recovery retains exact pending inputs and validates wait history from these facts; consumed content is no longer a transcript.

A wait identity is minted by the Engine; an Execution cannot generate an external one. The Execution declares a logical wait through a Transition; the Engine saves the mapping and enqueues an internal Signal carrying the identity; on the next Step the Execution records it and enters Waiting explicitly. That round trip keeps the Execution the single writer of its own state. The Engine wall clock never enters strategy input — business time is submitted as an explicit payload. Wait registration and its opening Signal are one mailbox operation. Restoring history uses the same opening, admission, and consumption rules: an answer closes its wait when consumed, and Process termination closes all remaining waits. Snapshots whose wait facts contradict that history are rejected. Child completions remain queued while their parent is Paused or waiting on another WaitID. Only an answer to the current WaitID releases Waiting; an explicit pause still requires Resume. Unaddressed Strategy input can also queue while Paused or waiting for children without releasing either state. WaitForChildren requires an explicit ChildWaitBoundary. The result boundary counts terminal children. The drained boundary counts children whose entire subtree satisfies Process.Join. All, any, and quorum count those facts in request order; none selects successful business outcomes or cancels losers. ChildWaitSatisfied carries the chosen boundary with the terminal results. Wait registration is nonblocking even when a child already reached its boundary. SignalChild and CancelChild declare controls over an exact direct child. The tree owner records the recipient change and ChildControlResult in one durable Effect settlement. Rejected ownership or mailbox admission is a definite failed receipt. Signals retain their caller-chosen deduplication identity and obey the recipient's safe boundary; cancellation records intent and requires a drained wait to establish resource release.

Each strategy declares its own safe consumption boundary and proves it with contract tests.

Process lifecycle

A Process moves through StatusNotStarted, StatusRunning, and then one of StatusWaiting, StatusPaused, StatusCompleted, StatusFailed, StatusCanceled, StatusTimedOut, or StatusKilled.

A terminal state is decided jointly by the recorded control intent and the Step result, never inferred from error text or from context.Canceled alone. The matrix is matched in priority order: an explicit kill wins; then a reached deadline; then parent or host cancellation; then a contract violation, external failure, or panic; then legal completion. A committed terminal state is first-terminal-wins, so a late cancellation cannot overwrite it. An effect's own cancellation first reaches the strategy as a settlement Signal — a local failure is never promoted to a Process terminal state on its own. Process.RequestCancellation also terminates active descendants through their owned lifecycle. The surviving parent receives the ordinary completion Signal and its Strategy chooses the next transition. Cancellation uses the same checkpoint acknowledgment as every other terminal transition. Once applied, terminal intent cancels active Step, Dispatch, and child-admission contexts throughout the owned subtree without waiting for an ancestor's work to return. The owner still collects started external work. Initialization outcome and durability acknowledgments are not canceled. A late successful child initialization joins the tree under terminal intent before any Step. Process.Await establishes the Process result and immediate bookkeeping. Process.Join additionally waits for owned descendant calls and required acknowledgments in this runtime. It leaves unrelated siblings running and does not release the tree. A runtime failure in the subtree makes Join fail after its local calls return, even if this Process already published a result. Terminal Unknown settlements remain evidence of remote uncertainty after Join. Engine.Run composes Start, Join, and Await as one synchronous operation. It returns the root result only after the subtree finishes, or a RuntimeError if that completion fails. Canceling its context requests termination but does not abandon owned work or required acknowledgments.

A child-completion delivery failure is recorded as pending termination. Accepted external effects settle first, and any unknown identities remain in the terminal result. The pending failure survives tree capture.

A long-lived Engine retains completed trees for diagnostics and capture until the Host calls Engine.ReleaseTree. Release waits for all descendant work to settle, removes the tree from lookup, and leaves existing handles' results and runtime errors readable.

Signal identities, wait history, and descendants remain retained for that lifetime. Finite budgets and snapshot limits bound one execution; the kernel does not prune facts needed for deduplication or extend a tree indefinitely.

Engine.InspectTree is the sole live inspection entry. It composes existing ProcessSnapshot values with current job, commit, and freeze facts, and stays available while storage acknowledgment or a tree freeze blocks execution. Snapshots own lifecycle, usage, wait authority, and Unknown settlements; runtime work may be newer than a durable snapshot. Reports describe one owner turn, never drive execution, and add nothing to the recovery schema. Synchronous EventListener callbacks must not query, control, or Await their tree. Calls that forward the callback context receive ErrListenerReentrancy while that invocation is active. Different tree owners remain independently callable, but callbacks must avoid cyclic waits and return in bounded time. Engine.Close requires every tree's publication, bookkeeping, and owned work to finish in both durable and ephemeral mode. Join or Run establishes this subtree completion; any separately acquired freeze must also be released. Close(ctx) closes admission once and joins Engine-owned observation shutdown; canceling ctx ends only that caller's wait. DeltaListener callbacks must not call Close or FlushDeltas on their Engine because both join Delta delivery. Forwarding an active callback context makes those calls fail with ErrListenerReentrancy.

A durable writer can stop without terminating the logical execution. Storage failures and ownership conflicts reach Process.Await as a RuntimeError with no Result. The error preserves the original cause, the last acknowledged head, and uncertain Effect identities. EventRuntimeStopped describes this instance failure; it never substitutes for EventProcessFinished. Status and usage in durable mode project only acknowledged tree state. The Host reads its authoritative head before reactivation, since a lost commit response or another writer may have advanced it beyond the stopped instance's view.

Recovery

ExecutionState is a discriminated envelope of a kind and an opaque payload. The kernel constrains the envelope and never interprets the payload recursively; each strategy owns and guards its own wire shape. A host may persist the envelope but must not parse it by kind and join strategy control flow. Recovery finds the Definition through an exact DeploymentRef; a global kind-to-factory switch is forbidden.

TreeSnapshot is the canonical recovery state of a complete root tree. It uses one current strict wire shape without a version envelope or migration dispatch; parsing validates the structure and the recorded domain facts. ProcessSnapshot is a single-Process diagnostic value and is not a recovery unit. Events and Delta values record attempts and observations only; they never substitute for an acknowledged TreeSnapshot. Committed events wait for durable acknowledgment. Event sequences describe publication within one runtime activation and restart when a nonterminal Process is restored; they do not change snapshot contents or trigger commits.

Strategies

Built-in strategies live under strategy/. Each concrete package implements the public execution protocol; the directory itself defines no package or runtime contract. Host-defined strategies use the same protocol.

github.com/Tangerg/scope/agent/strategy/interaction implements ReAct-style model and tool loops with working context, delegates, and artifacts. github.com/Tangerg/scope/agent/strategy/planning owns goal-driven planning; its goap subpackage supplies a bounded search implementation selected by the Host. github.com/Tangerg/scope/agent/strategy/workflow implements ordered deterministic stages over a closed vocabulary, composing real child Processes. github.com/Tangerg/scope/agent/strategy/coordination composes bounded input gates, absolute deadlines, and first-success competition through the same child and wait contracts. github.com/Tangerg/scope/agent/strategy/collaboration runs bounded coordinator turns beside background workers. Decisions choose whether to continue while workers run, wait for drained results, or complete. The Strategy retains explicit working state and immutable child bindings; the Engine resolves and runs the children. Workflow child failures and collaboration coordinator failures preserve their original Failure kind, code, and diagnostic.

github.com/Tangerg/scope/agent/messaging delivers intermediate input through a narrow Host-authorized port, retaining the original recipient and Effect-derived Signal identity. Its sender and recipient acknowledge separately; it does not provide the direct-child control's single tree commit.

The Engine never imports or type-switches a concrete strategy. A new strategy is admitted by implementing the waist, state codec, and safe consumption boundary, and binding a dispatcher when it declares external Effects.

Boundaries

A long-lived Host can run successive bounded root trees. The successive episodes example under Engine.Start establishes a completed, joined predecessor, seals input routing, reconciles SignalReceipts, and binds explicit successor state, Deployment, limits, and authority. Its Host transaction links the successor identity with the initial tree checkpoint; a lost start response is reconciled by restoring that identity. Calling Start with equal Input alone does not provide idempotent successor admission. Retained unconsumed inputs keep their predecessor address, and unresolved descendant Effects prevent the example's safe boundary. Production Hosts implement the transaction and retention policy in their own durable storage.

The framework owns definition validation, deployment freezing, the Process state machine, signal ordering and deduplication, effect identity and settlement, budgets, the lifecycle, framework events, and the snapshot and recovery protocol.

The host owns product identity, transports, stores and transactions, permissions and billing, deployment catalogs and routing, provider and model selection, storage acknowledgment, and retention of its own facts. A host depends only on this neutral lifecycle contract and never parses a strategy's snapshot payload.

Production database adapters and their storage-specific integration tests belong to the consuming application or an independently owned adapter. The agenttest package supplies shared durability and Definition conformance suites.

Chat, tools, embeddings, history, and telemetry stay in their own modules. Agent reuses them and duplicates none of them.

Index

Examples

Constants

View Source
const (
	// EventProcessStarted reports initial Process execution.
	EventProcessStarted = "agent.process.started"
	// EventProcessRestored reports execution resumed from a TreeSnapshot.
	EventProcessRestored = "agent.process.restored"
	// EventProcessPaused reports a committed scheduling pause.
	EventProcessPaused = "agent.process.paused"
	// EventProcessResumed reports committed scheduling resumption.
	EventProcessResumed = "agent.process.resumed"
	// EventProcessFinished reports one immutable terminal outcome.
	EventProcessFinished = "agent.process.finished"
	// EventRuntimeStopped reports loss of an active instance without a committed
	// logical terminal result. It never changes the durable Process lifecycle.
	EventRuntimeStopped = "agent.runtime.stopped"
	// EventSignalAccepted reports one newly accepted Signal.
	EventSignalAccepted = "agent.signal.accepted"
	// EventStepStarted reports an Execution.Step call about to begin.
	EventStepStarted = "agent.step.started"
	// EventStepFinished reports an Execution.Step return or failure.
	EventStepFinished = "agent.step.finished"
	// EventStepPrepared reports validated candidate Step state and fixed Effects.
	EventStepPrepared = "agent.step.prepared"
	// EventStepCommitted reports authoritative Step state publication.
	EventStepCommitted = "agent.step.committed"
	// EventEffectStarted reports a Framework or Dispatcher Effect attempt.
	EventEffectStarted = "agent.effect.started"
	// EventEffectFinished reports a definite or unknown attempt settlement.
	EventEffectFinished = "agent.effect.finished"
	// EventDeltaDropped reports best-effort increments lost to backpressure.
	EventDeltaDropped = "agent.delta.dropped"
)
View Source
const MaxPayloadBytes = 64 << 20

MaxPayloadBytes is the maximum encoded JSON size of an individual Agent input, output, Effect, Signal, or settlement payload.

Variables

View Source
var (
	ErrInvalidEngineConfig         = errors.New("agent: invalid engine configuration")
	ErrEngineClosed                = errors.New("agent: engine is closed")
	ErrEngineQuiescenceUnavailable = errors.New("agent: engine cannot become quiescent")
	ErrEngineHasActiveProcesses    = errors.New("agent: engine has active processes")
	ErrProcessAlreadyExists        = errors.New("agent: process identity already exists")
)
View Source
var (
	ErrSignalRejected = errors.New("agent: signal rejected")
	// ErrSignalConflict reports reuse of a SignalID with different immutable
	// content, including the addressed WaitID.
	ErrSignalConflict = errors.New("agent: signal identity conflicts with accepted content")
)
View Source
var (
	ErrProcessFinished       = errors.New("agent: process has finished")
	ErrProcessNotRunning     = errors.New("agent: process is not running")
	ErrEffectNotPending      = errors.New("agent: effect does not require resolution")
	ErrInvalidProcessControl = errors.New("agent: invalid process control request")
)
View Source
var (
	ErrDurabilityConflict      = errors.New("agent: durability boundary conflicts with committed content")
	ErrTreeIncarnationConflict = errors.New("agent: tree incarnation conflict")
	ErrTreeDurabilityMismatch  = errors.New("agent: tree durability mode mismatch")
	ErrTreeCaptureUnavailable  = errors.New("agent: tree capture is unavailable in durable mode")
)
View Source
var (
	ErrInvalidInput  = errors.New("agent: invalid input")
	ErrInvalidOutput = errors.New("agent: invalid output")
)
View Source
var ErrInvalidCapability = errors.New("agent: invalid capability")
View Source
var ErrInvalidChildControl = errors.New("agent: invalid child control")
View Source
var ErrInvalidChildStart = errors.New("agent: invalid child process start")
View Source
var ErrInvalidChildWait = errors.New("agent: invalid child wait")
View Source
var ErrInvalidDelta = errors.New("agent: invalid delta")
View Source
var ErrInvalidDeployment = errors.New("agent: invalid deployment")
View Source
var ErrInvalidDeploymentRef = errors.New("agent: invalid deployment reference")
View Source
var ErrInvalidDescriptor = errors.New("agent: invalid descriptor")
View Source
var ErrInvalidDigest = errors.New("agent: invalid digest")
View Source
var ErrInvalidEffect = errors.New("agent: invalid effect")
View Source
var ErrInvalidEvent = errors.New("agent: invalid event")
View Source
var ErrInvalidExecutionState = errors.New("agent: invalid execution state")
View Source
var ErrInvalidFailure = errors.New("agent: invalid failure")
View Source
var ErrInvalidIdentity = errors.New("agent: invalid identity")
View Source
var ErrInvalidProcessRelation = errors.New("agent: invalid process relation")
View Source
var ErrInvalidSchema = errors.New("agent: invalid schema")
View Source
var ErrInvalidSettlement = errors.New("agent: invalid effect settlement")
View Source
var ErrInvalidSignal = errors.New("agent: invalid signal")
View Source
var ErrInvalidSignalRequest = errors.New("agent: invalid signal request")
View Source
var ErrInvalidSnapshot = errors.New("agent: invalid process snapshot")
View Source
var ErrInvalidStatus = errors.New("agent: invalid status")
View Source
var ErrInvalidTransition = errors.New("agent: invalid transition")
View Source
var ErrInvalidTreeIncarnationID = errors.New("agent: invalid tree incarnation identity")
View Source
var ErrInvalidTreeSnapshot = errors.New("agent: invalid process tree snapshot")
View Source
var ErrListenerReentrancy = errors.New("agent: operation would wait for its active listener")

ErrListenerReentrancy reports an operation that would wait for the active listener carrying its context: an EventListener's tree owner or a DeltaListener's delivery worker. Derived contexts retain this restriction until the callback returns. Replacing the context does not remove the listener's obligation to avoid waiting for itself.

View Source
var ErrProcessAdmissionRejected = errors.New("agent: process admission rejected")

ErrProcessAdmissionRejected marks failure at the policy boundary before execution starts.

View Source
var ErrResourceLimitExceeded = errors.New("agent: resource limit exceeded")

ErrResourceLimitExceeded reports a designed execution bound, not an Engine defect.

Functions

This section is empty.

Types

type Budget

type Budget struct {
	// Steps is the maximum committed Step count allocated to the child.
	Steps uint64 `json:"steps"`
	// Effects is the maximum prepared Effect count allocated to the child.
	Effects uint64 `json:"effects"`
	// Signals is the maximum accepted Signal count allocated to the child.
	Signals uint64 `json:"signals"`
}

Budget is a non-renewable allocation of Framework-owned work units. A child allocation is permanently transferred from its parent's remaining budget; unused units are not silently reclaimed or duplicated. Remaining budget excludes the parent's prepared Step and its future settlement Signals. Construct allocations with named fields; child admission and capability constructors validate the complete allocation before it grants authority.

func (Budget) Valid

func (b Budget) Valid() bool

type Capability

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

Capability is one stable qualified authority name understood by a Deployment's dispatcher or another external boundary. The Framework only enforces possession and attenuation; it does not assign product meaning.

func ParseCapability

func ParseCapability(name string) (Capability, error)

ParseCapability validates a lowercase qualified capability name.

func (Capability) JSONSchemaAlias added in v0.17.0

func (Capability) JSONSchemaAlias() any

func (Capability) MarshalText

func (c Capability) MarshalText() ([]byte, error)

func (Capability) String

func (c Capability) String() string

func (*Capability) UnmarshalText

func (c *Capability) UnmarshalText(text []byte) error

func (Capability) Valid

func (c Capability) Valid() bool

type CapabilitySet

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

CapabilitySet is an immutable, sorted set of authority names. Its zero value is the valid empty set, encoded as an empty JSON array. JSON null is invalid.

func NewCapabilitySet

func NewCapabilitySet(capabilities ...Capability) (CapabilitySet, error)

NewCapabilitySet builds the frozen grant a Process runs under. It is a set rather than a slice because a duplicated or reordered grant must not change authority, and because every child grant must be a subset of its parent's.

func (CapabilitySet) Allows

func (c CapabilitySet) Allows(requested CapabilitySet) bool

Allows reports whether requested is a subset of c.

func (CapabilitySet) Contains

func (c CapabilitySet) Contains(capability Capability) bool

Contains reports whether capability belongs to the set.

func (CapabilitySet) JSONSchemaAlias added in v0.17.0

func (CapabilitySet) JSONSchemaAlias() any

func (CapabilitySet) MarshalJSON

func (c CapabilitySet) MarshalJSON() ([]byte, error)

func (*CapabilitySet) UnmarshalJSON

func (c *CapabilitySet) UnmarshalJSON(data []byte) error

func (CapabilitySet) Valid

func (c CapabilitySet) Valid() bool

func (CapabilitySet) Values

func (c CapabilitySet) Values() []Capability

Values returns an independently owned, sorted capability slice.

type ChildControlResult added in v0.18.0

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

ChildControlResult is a definite tree-local admission result. SignalID is present for every signal attempt, including rejected delivery. Failure preserves rejected authority, wait, or resource admission without failing the sending Strategy implicitly.

func ParseChildControlResult added in v0.18.0

func ParseChildControlResult(signal Signal) (ChildControlResult, error)

ParseChildControlResult decodes an unaddressed Framework control settlement carrying an Engine-owned Signal identity.

func (ChildControlResult) ChildID added in v0.18.0

func (c ChildControlResult) ChildID() ProcessID

func (ChildControlResult) Failure added in v0.18.0

func (c ChildControlResult) Failure() (Failure, bool)

func (ChildControlResult) JSONSchemaAlias added in v0.18.0

func (ChildControlResult) JSONSchemaAlias() any

func (ChildControlResult) MarshalJSON added in v0.18.0

func (c ChildControlResult) MarshalJSON() ([]byte, error)

func (ChildControlResult) Matches added in v0.18.0

func (c ChildControlResult) Matches(effect Effect) bool

Matches checks the operation and concrete recipient of the declared Effect. The enclosing settlement Signal retains the Engine-owned effect identity.

func (ChildControlResult) SignalID added in v0.18.0

func (c ChildControlResult) SignalID() (SignalID, bool)

func (*ChildControlResult) UnmarshalJSON added in v0.18.0

func (c *ChildControlResult) UnmarshalJSON(data []byte) error

func (ChildControlResult) Valid added in v0.18.0

func (c ChildControlResult) Valid() bool

type ChildKey

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

ChildKey is an Execution-owned stable identity for one logical child start. The Engine combines it with the parent Process identity and prepared Effect identity to make retries and restoration idempotent.

func ParseChildKey

func ParseChildKey(value string) (ChildKey, error)

ParseChildKey validates an Execution-owned logical child identity.

func (ChildKey) JSONSchemaAlias added in v0.17.0

func (ChildKey) JSONSchemaAlias() any

func (ChildKey) MarshalText

func (i ChildKey) MarshalText() ([]byte, error)

func (ChildKey) String

func (i ChildKey) String() string

func (*ChildKey) UnmarshalText

func (c *ChildKey) UnmarshalText(text []byte) error

func (ChildKey) Valid

func (i ChildKey) Valid() bool

Valid distinguishes a parsed identity from its invalid zero value. Parsing and text decoding are the only boundaries that can install non-empty text.

type ChildOutcome

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

ChildOutcome pairs a parent's logical ChildKey with the child's immutable terminal Result and the subtree facts established by the wait boundary.

func (ChildOutcome) JSONSchemaAlias added in v0.17.0

func (ChildOutcome) JSONSchemaAlias() any

func (ChildOutcome) Key

func (c ChildOutcome) Key() ChildKey

Key returns the parent-scoped logical child identity.

func (ChildOutcome) MarshalJSON added in v0.17.0

func (c ChildOutcome) MarshalJSON() ([]byte, error)

func (ChildOutcome) Result

func (c ChildOutcome) Result() Result

Result returns the child's immutable terminal result.

func (ChildOutcome) SubtreeUnresolvedEffects added in v0.22.0

func (c ChildOutcome) SubtreeUnresolvedEffects() ([]UnresolvedEffect, bool)

SubtreeUnresolvedEffects returns an independent, ProcessID/EffectID-ordered projection including this child and all descendants. The boolean is true only for a Drained boundary; false must not be interpreted as an empty subtree.

func (*ChildOutcome) UnmarshalJSON added in v0.17.0

func (c *ChildOutcome) UnmarshalJSON(data []byte) error

func (ChildOutcome) Valid

func (c ChildOutcome) Valid() bool

type ChildSpec

type ChildSpec struct {
	// Key is the parent-scoped logical identity of this child start.
	Key ChildKey `json:"key"`
	// DeploymentRef identifies the exact child behavior binding.
	DeploymentRef DeploymentRef `json:"deployment_ref"`
	// Input is the portable input validated by the target Descriptor.
	Input Input `json:"input"`
	// Budget is permanently allocated from the parent to this child.
	Budget Budget `json:"budget"`
	// Capabilities is the attenuated authority granted to this child.
	Capabilities CapabilitySet `json:"capabilities"`
}

ChildSpec is the complete Strategy-declared intent for one child Process. Input is validated by the target Deployment before any Process is created.

func (ChildSpec) Valid

func (c ChildSpec) Valid() bool

type ChildStartResult

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

ChildStartResult is the definite result of one StartChild Effect. Success contains the Engine-created child ProcessID; failure contains a stable Framework Failure and never masquerades as an unknown external outcome.

func ParseChildStartResult

func ParseChildStartResult(signal Signal) (ChildStartResult, error)

ParseChildStartResult decodes a Framework-owned child-start settlement Signal. The Signal must carry an Engine-owned identity and must not address a wait.

func (ChildStartResult) DeploymentRef

func (c ChildStartResult) DeploymentRef() DeploymentRef

DeploymentRef returns the exact child execution binding.

func (ChildStartResult) Failure

func (c ChildStartResult) Failure() (Failure, bool)

Failure returns the definite start failure and true when no child was created.

func (ChildStartResult) JSONSchemaAlias added in v0.17.0

func (ChildStartResult) JSONSchemaAlias() any

func (ChildStartResult) Key

func (c ChildStartResult) Key() ChildKey

Key returns the logical child identity declared by the Execution.

func (ChildStartResult) MarshalJSON added in v0.17.0

func (c ChildStartResult) MarshalJSON() ([]byte, error)

func (ChildStartResult) ProcessID

func (c ChildStartResult) ProcessID() (ProcessID, bool)

ProcessID returns the created child identity and true on success.

func (*ChildStartResult) UnmarshalJSON added in v0.17.0

func (c *ChildStartResult) UnmarshalJSON(data []byte) error

func (ChildStartResult) Valid

func (c ChildStartResult) Valid() bool

type ChildWaitBoundary added in v0.17.0

type ChildWaitBoundary string

ChildWaitBoundary selects the lifecycle fact counted by a child wait.

const (
	ChildWaitBoundaryResult  ChildWaitBoundary = "terminal_result"
	ChildWaitBoundaryDrained ChildWaitBoundary = "subtree_drained"
)

func (ChildWaitBoundary) String added in v0.17.0

func (c ChildWaitBoundary) String() string

func (ChildWaitBoundary) Valid added in v0.17.0

func (c ChildWaitBoundary) Valid() bool

type ChildWaitCondition

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

ChildWaitCondition identifies when a set of child Processes releases its parent. It counts children at the requested boundary; it does not cancel unfinished children or reinterpret child terminal statuses.

func AllChildren

func AllChildren() ChildWaitCondition

AllChildren waits until every named child reaches the requested boundary.

func AnyChild

func AnyChild() ChildWaitCondition

AnyChild waits until at least one named child reaches the requested boundary.

func ChildQuorum

func ChildQuorum(count uint32) (ChildWaitCondition, error)

ChildQuorum waits until count named children reach the requested boundary.

func (ChildWaitCondition) Valid

func (c ChildWaitCondition) Valid() bool

type ChildWaitOpened

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

ChildWaitOpened is the definite acknowledgement that the Engine registered a child wait and minted its WaitID.

func ParseChildWaitOpened

func ParseChildWaitOpened(signal Signal) (ChildWaitOpened, error)

ParseChildWaitOpened decodes the settlement Signal produced by WaitForChildren and verifies its Engine-owned Signal identity and attached WaitID.

func (ChildWaitOpened) Spec

func (c ChildWaitOpened) Spec() ChildWaitSpec

Spec returns the immutable child-wait request acknowledged by Engine.

func (ChildWaitOpened) Valid

func (c ChildWaitOpened) Valid() bool

func (ChildWaitOpened) WaitID

func (c ChildWaitOpened) WaitID() WaitID

WaitID returns the Engine-minted wait identity to store in Execution state.

type ChildWaitSatisfied added in v0.17.0

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

ChildWaitSatisfied is one condition-satisfying, request-ordered child result set. For any or quorum it includes every child at the requested boundary at the atomic satisfaction check, without canceling or omitting based on status.

func ParseChildWaitSatisfied added in v0.17.0

func ParseChildWaitSatisfied(signal Signal) (ChildWaitSatisfied, error)

ParseChildWaitSatisfied decodes an Engine-generated, WaitID-addressed child wait-satisfaction Signal. Caller-owned Signal identities are rejected.

func (ChildWaitSatisfied) Boundary added in v0.17.0

Boundary identifies the lifecycle fact established by this wait.

func (ChildWaitSatisfied) Key added in v0.17.0

func (c ChildWaitSatisfied) Key() WaitKey

Key returns the logical wait key declared by the Execution.

func (ChildWaitSatisfied) Outcomes added in v0.17.0

func (c ChildWaitSatisfied) Outcomes() []ChildOutcome

Outcomes returns terminal children in the original ChildWaitSpec order.

func (ChildWaitSatisfied) Valid added in v0.17.0

func (c ChildWaitSatisfied) Valid() bool

func (ChildWaitSatisfied) WaitID added in v0.17.0

func (c ChildWaitSatisfied) WaitID() WaitID

WaitID returns the addressed wait identity.

type ChildWaitSpec

type ChildWaitSpec struct {
	// Key is the Execution-owned logical identity of this wait request.
	Key WaitKey
	// Children lists direct child identities in result order.
	Children []ProcessID
	// Boundary explicitly selects terminal results or joined subtrees. A joined
	// subtree has completed its owned local work and required acknowledgments in
	// this runtime, as defined by Process.Join; remote uncertainty may remain.
	Boundary ChildWaitBoundary
	// Condition declares how many listed children must reach Boundary.
	Condition ChildWaitCondition
}

ChildWaitSpec names one stable logical wait, its direct children in result order, lifecycle boundary, and count predicate.

func (ChildWaitSpec) Valid

func (c ChildWaitSpec) Valid() bool

type Definition

type Definition interface {
	// Descriptor returns the immutable, portable contract shared by every
	// Execution created from this definition. Repeated and concurrent calls must
	// return an equivalent value; runtime configuration and mutable state do not
	// belong in the descriptor.
	Descriptor() Descriptor
	// Start validates input against Descriptor and creates a fresh, isolated
	// Execution without performing external I/O. The returned Execution has not
	// executed a Step and must not share mutable state with another Process.
	Start(input Input) (Execution, error)
	// Restore reconstructs one Execution from a state previously produced by
	// Snapshot for this exact definition. The caller must supply the matching
	// definition; Engine enforces this with the snapshot's exact DeploymentRef.
	// Restore validates state structure and strategy invariants without replaying
	// external work. Opaque state need not independently identify its deployment.
	Restore(state ExecutionState) (Execution, error)
}

Definition is an immutable Agent behavior definition. Its methods may be called concurrently for different Processes. Implementations create a fresh Execution from validated Input or restore one from their own opaque ExecutionState. Definition methods must not depend on Host product identities, storage protocols, or mutable global registration.

Example

An independently authored Definition binds through the same Deployment and Engine contracts as built-in strategies. TestExternalPackageCanComposeAndRunDefinition checks this implementation with agenttest.RunDefinitionConformance.

package main

import (
	"context"
	"encoding/json"
	jsonv2 "encoding/json/v2"
	"fmt"
	"sync/atomic"

	"github.com/Tangerg/scope/agent"
)

type echoInput struct {
	Value string `json:"value"`
}

type echoOutput struct {
	Value string `json:"value"`
}

type echoDefinition struct {
	descriptor agent.Descriptor
}

type echoState struct {
	Phase string `json:"phase"`
	Value string `json:"value"`
}

func (e echoDefinition) Descriptor() agent.Descriptor { return e.descriptor }

func (e echoDefinition) Start(input agent.Input) (agent.Execution, error) {
	if err := e.descriptor.ValidateInput(input); err != nil {
		return nil, err
	}
	value, err := input.Decode[echoInput]()
	if err != nil {
		return nil, err
	}
	return &echoExecution{state: echoState{Phase: "ready", Value: value.Value}}, nil
}

func (echoDefinition) Restore(state agent.ExecutionState) (agent.Execution, error) {
	if !state.Valid() || state.Kind() != "example.echo" {
		return nil, agent.ErrInvalidExecutionState
	}
	var value echoState
	if err := jsonv2.Unmarshal(state.Payload(), &value, jsonv2.RejectUnknownMembers(true)); err != nil {
		return nil, err
	}
	switch value.Phase {
	case "ready", "awaiting_echo", "completed":
		return &echoExecution{state: value}, nil
	default:
		return nil, agent.ErrInvalidExecutionState
	}
}

type echoExecution struct {
	state echoState
}

func (e *echoExecution) Step(ctx context.Context, signals []agent.Signal) (agent.Transition, error) {
	if err := ctx.Err(); err != nil {
		return agent.Transition{}, err
	}
	switch e.state.Phase {
	case "ready":
		if len(signals) != 0 {
			return agent.Transition{}, agent.ErrInvalidSignal
		}
		payload, err := json.Marshal(echoInput{Value: e.state.Value})
		if err != nil {
			return agent.Transition{}, err
		}
		effect, err := agent.NewDispatcherEffect(payload)
		if err != nil {
			return agent.Transition{}, err
		}
		e.state.Phase = "awaiting_echo"
		return agent.Continue(0, effect)
	case "awaiting_echo":
		if len(signals) != 1 {
			return agent.Transition{}, agent.ErrInvalidSignal
		}
		var result echoOutput
		if err := jsonv2.Unmarshal(signals[0].Payload(), &result, jsonv2.RejectUnknownMembers(true)); err != nil {
			return agent.Transition{}, err
		}
		output, err := agent.EncodeOutput(result)
		if err != nil {
			return agent.Transition{}, err
		}
		e.state.Phase = "completed"
		return agent.Complete(1, output)
	default:
		return agent.Transition{}, agent.ErrInvalidExecutionState
	}
}

func (e *echoExecution) Snapshot() (agent.ExecutionState, error) {
	payload, err := json.Marshal(e.state)
	if err != nil {
		return agent.ExecutionState{}, err
	}
	return agent.NewExecutionState("example.echo", payload)
}

func newEchoDefinition() (echoDefinition, error) {
	inputSchema, err := agent.SchemaFor[echoInput]()
	if err != nil {
		return echoDefinition{}, err
	}
	outputSchema, err := agent.SchemaFor[echoOutput]()
	if err != nil {
		return echoDefinition{}, err
	}
	descriptor, err := agent.NewDescriptor(agent.DescriptorConfig{
		Name: "example.echo", Description: "Echoes a value through an Engine-managed Effect.",
		InputSchema: inputSchema, OutputSchema: outputSchema,
	})
	if err != nil {
		return echoDefinition{}, err
	}
	return echoDefinition{descriptor: descriptor}, nil
}

// echoDispatcher has no external mutation, so repeating an identity is safe.
type echoDispatcher struct{}

func (echoDispatcher) Dispatch(ctx context.Context, request agent.EffectRequest, emit agent.DeltaEmitter) (agent.Settlement, error) {
	if err := ctx.Err(); err != nil {
		return agent.Settlement{}, err
	}
	payload := request.Effect().Payload()
	if emit != nil {
		emit(payload)
	}
	return agent.NewSettlement(request.ID(), agent.SettlementStatusSucceeded, payload)
}

func (echoDispatcher) ReplayPolicy(agent.Effect) agent.ReplayPolicy {
	return agent.ReplayPolicySameIdentity
}

// countingDispatcher counts attempts, including replay, rather than logical operations.
type countingDispatcher struct {
	next     agent.Dispatcher
	attempts atomic.Int64
}

func (c *countingDispatcher) Dispatch(ctx context.Context, request agent.EffectRequest, emit agent.DeltaEmitter) (agent.Settlement, error) {
	c.attempts.Add(1)
	return c.next.Dispatch(ctx, request, emit)
}

func (c *countingDispatcher) ReplayPolicy(effect agent.Effect) agent.ReplayPolicy {
	return c.next.ReplayPolicy(effect)
}

// An independently authored Definition binds through the same Deployment and
// Engine contracts as built-in strategies. TestExternalPackageCanComposeAndRunDefinition
// checks this implementation with agenttest.RunDefinitionConformance.
func main() {
	ctx := context.Background()
	definition, err := newEchoDefinition()
	if err != nil {
		panic(err)
	}
	dispatcher := &countingDispatcher{next: echoDispatcher{}}
	deployment, err := agent.NewDeployment(agent.DeploymentConfig{
		Definition: definition, Dispatcher: dispatcher,
		ImplementationDigest: agent.ComputeDigest([]byte("example-echo-implementation")),
		ConfigurationDigest:  agent.ComputeDigest([]byte("example-echo-configuration")),
	})
	if err != nil {
		panic(err)
	}
	engine, err := agent.NewEngine(agent.EngineConfig{})
	if err != nil {
		panic(err)
	}
	defer func() {
		if closeErr := engine.Close(ctx); closeErr != nil {
			panic(closeErr)
		}
	}()
	input, err := definition.Descriptor().EncodeInput(echoInput{Value: "hello"})
	if err != nil {
		panic(err)
	}
	process, err := engine.Start(ctx, deployment, input)
	if err != nil {
		panic(err)
	}
	result, err := process.Await(ctx)
	if err != nil {
		panic(err)
	}
	if joinErr := process.Join(ctx); joinErr != nil {
		panic(joinErr)
	}
	output, ok := result.Output()
	if !ok {
		panic("completed Result has no Output")
	}
	value, err := definition.Descriptor().DecodeOutput[echoOutput](output)
	if err != nil {
		panic(err)
	}
	inspection, err := engine.InspectTree(ctx, result.ProcessID())
	if err != nil {
		panic(err)
	}
	report, found := inspection.Process(result.ProcessID())
	if !found {
		panic("completed Process is absent from its tree")
	}
	if err := engine.ReleaseTree(context.Background(), result.ProcessID()); err != nil {
		panic(err)
	}
	fmt.Println(result.Status(), value.Value, dispatcher.attempts.Load())
	fmt.Println("inspected:", report.Snapshot.Status(), report.Snapshot.Usage().PreparedEffects)
}
Output:
completed hello 1
inspected: completed 1

type Delta

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

Delta is a bounded, best-effort stream increment from one Effect attempt. EffectSequence preserves emitter admission order. Delta is never replayed from a snapshot and never contributes to the authoritative final Output.

func (Delta) EffectID

func (d Delta) EffectID() EffectID

EffectID identifies the logical Effect and remains stable across replay attempts.

func (Delta) EffectSequence

func (d Delta) EffectSequence() uint64

EffectSequence returns the one-based emitter admission order within the Effect attempt. Delivered sequences increase; dropped payloads leave gaps.

func (Delta) EmittedAt

func (d Delta) EmittedAt() time.Time

EmittedAt returns when the producer emitted the increment.

func (Delta) MarshalJSON

func (d Delta) MarshalJSON() ([]byte, error)

func (Delta) Payload

func (d Delta) Payload() json.RawMessage

Payload returns an independently owned Strategy-defined increment.

func (Delta) ProcessID

func (d Delta) ProcessID() ProcessID

ProcessID returns the Process that owns the Effect attempt.

func (Delta) TreeIncarnationID

func (d Delta) TreeIncarnationID() (TreeIncarnationID, bool)

TreeIncarnationID returns the active durable writer that emitted this delta. Deltas from ephemeral trees return false.

func (*Delta) UnmarshalJSON

func (d *Delta) UnmarshalJSON(data []byte) error

func (Delta) Valid

func (d Delta) Valid() bool

type DeltaDroppedFact

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

DeltaDroppedFact reports the number of increments rejected during one Effect attempt because validation failed or the bounded observation queue was full.

func (DeltaDroppedFact) Count

func (d DeltaDroppedFact) Count() uint64

func (DeltaDroppedFact) Valid

func (d DeltaDroppedFact) Valid() bool

type DeltaEmitter

type DeltaEmitter func(payload json.RawMessage)

DeltaEmitter accepts Strategy-owned streaming payloads while Dispatch is active. The Engine validates, orders, bounds, and publishes each payload as a best-effort Delta. Concurrent calls are serialized in emitter admission order; delivered EffectSequence values increase, with gaps for dropped payloads. With no DeltaListener the emitter is nil: no observation payload is built, validated, sequenced, or counted as dropped. Dispatchers must guard emission with emit != nil. Their execution validation remains mandatory. It intentionally returns no observer error. A Dispatcher must join concurrent emissions before returning and must not retain or call emit afterward.

type DeltaListener

type DeltaListener interface {
	// OnDelta receives an accepted best-effort increment in queue order. Delivery
	// is sequential per listener but may lag Process execution; slow callbacks can
	// cause later increments to be dropped. It has no acknowledgment authority;
	// Engine.Close and FlushDeltas still wait for accepted callback delivery.
	// Close and FlushDeltas using this context, or a derived context, return
	// [ErrListenerReentrancy] while this invocation is active because both would
	// wait for the worker delivering this callback.
	OnDelta(ctx context.Context, delta Delta)
}

DeltaListener observes best-effort Strategy streaming increments. Panics are isolated; all listeners and trees share one Engine queue and delivery worker. A slow callback delays the other listeners and trees and can cause bounded queue drops. Implementations must return in bounded time without closing or flushing their Engine. Hosts must put network or disk exporters behind their own bounded queue, own its worker and drain lifecycle, and expose its drops. Register independent queues for consumers requiring delivery isolation.

type DeltaListenerFunc

type DeltaListenerFunc func(ctx context.Context, delta Delta)

DeltaListenerFunc adapts a plain function to the delta listener interface. It returns nothing for the same reason as EventListenerFunc, and because a dropped delta must never change execution.

func (DeltaListenerFunc) OnDelta

func (d DeltaListenerFunc) OnDelta(ctx context.Context, delta Delta)

type Deployment

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

Deployment is an immutable binding of one Definition, its optional external Dispatcher, and an exact value reference used by Process snapshots.

func NewDeployment

func NewDeployment(config DeploymentConfig) (Deployment, error)

NewDeployment freezes a Definition and Dispatcher under explicit implementation and configuration digests. That binding lets recovery resolve the exact behavior a snapshot names instead of whatever now answers to the same Definition name.

func (Deployment) Definition

func (d Deployment) Definition() Definition

Definition returns the erased behavior definition bound to this Deployment.

func (Deployment) DeploymentRef

func (d Deployment) DeploymentRef() DeploymentRef

DeploymentRef returns the exact value identity stored in Process snapshots.

func (Deployment) Descriptor

func (d Deployment) Descriptor() Descriptor

Descriptor returns the frozen static Definition contract.

func (Deployment) Valid

func (d Deployment) Valid() bool

Valid checks the frozen binding without invoking user code. The Engine checks the live Definition contract at startup and restoration boundaries.

type DeploymentConfig

type DeploymentConfig struct {
	// Definition owns the Strategy contract and creates per-Process execution.
	Definition Definition

	// Dispatcher interprets this Definition's external Effects. Nil binds a
	// Definition that uses only Framework Effects; a dispatcher-targeted Effect
	// then fails admission before any Effect in its Step can execute.
	Dispatcher Dispatcher

	// ImplementationDigest identifies the exact executable Definition artifact.
	ImplementationDigest Digest

	// ConfigurationDigest identifies all frozen behavior-affecting Definition
	// and Dispatcher configuration.
	ConfigurationDigest Digest
}

DeploymentConfig contains the complete behavior binding of one Deployment. The digests must cover the exact code artifact and all frozen dispatcher or Strategy configuration that can affect execution or restoration.

type DeploymentRef

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

DeploymentRef is the immutable value identity of one exact Definition implementation and frozen execution configuration. It contains no registry pointer and is sufficient to reject restore against a different Deployment.

func (DeploymentRef) ConfigurationDigest

func (d DeploymentRef) ConfigurationDigest() Digest

ConfigurationDigest returns the frozen behavior-affecting configuration identity, including dispatcher configuration.

func (DeploymentRef) ContractDigest

func (d DeploymentRef) ContractDigest() Digest

ContractDigest returns the exact Descriptor contract identity.

func (DeploymentRef) Digest

func (d DeploymentRef) Digest() Digest

Digest returns the complete Deployment value identity.

func (DeploymentRef) ImplementationDigest

func (d DeploymentRef) ImplementationDigest() Digest

ImplementationDigest returns the exact executable implementation identity.

func (DeploymentRef) JSONSchemaAlias added in v0.17.0

func (DeploymentRef) JSONSchemaAlias() any

func (DeploymentRef) MarshalJSON

func (d DeploymentRef) MarshalJSON() ([]byte, error)

func (DeploymentRef) Name

func (d DeploymentRef) Name() string

Name returns the stable Definition name.

func (DeploymentRef) String

func (d DeploymentRef) String() string

func (*DeploymentRef) UnmarshalJSON

func (d *DeploymentRef) UnmarshalJSON(data []byte) error

func (DeploymentRef) Valid

func (d DeploymentRef) Valid() bool

type DeploymentResolver

type DeploymentResolver interface {
	// Resolve returns the immutable binding for exactly reference. It must not
	// fall back by name, perform routing or remote discovery, or retain
	// caller state. Missing and mismatched bindings are errors; concurrent calls
	// must be safe.
	Resolve(reference DeploymentRef) (Deployment, error)
}

DeploymentResolver performs one bounded, deterministic, context-free lookup of an exact immutable Deployment. The Engine accepts only a result whose reference exactly matches the requested reference. Implementations must be safe for concurrent use, must not perform remote I/O, and must not re-enter any Process. Routing and caller-specific selection happen before an exact DeploymentRef reaches this contract.

type Descriptor

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

Descriptor is an immutable Definition contract. It contains no executable behavior or Deployment configuration.

func NewDescriptor

func NewDescriptor(config DescriptorConfig) (Descriptor, error)

NewDescriptor validates the schemas at construction because they enter the Deployment digest. A schema accepted here and rejected later would change a Deployment's identity after Processes had already been started against it.

Example
package main

import (
	"fmt"

	"github.com/Tangerg/scope/agent"
)

func main() {
	schema, err := agent.SchemaFor[string]()
	if err != nil {
		panic(err)
	}
	descriptor, err := agent.NewDescriptor(agent.DescriptorConfig{
		Name:         "example.echo",
		Description:  "Returns the supplied text.",
		InputSchema:  schema,
		OutputSchema: schema,
	})
	if err != nil {
		panic(err)
	}

	fmt.Println(descriptor.Name(), descriptor.Valid())
}
Output:
example.echo true

func (Descriptor) DecodeOutput

func (d Descriptor) DecodeOutput[T any](output Output) (T, error)

DecodeOutput validates output against this Descriptor's authoritative output schema and strictly decodes it into T.

func (Descriptor) Description

func (d Descriptor) Description() string

Description returns the human-readable purpose of the Definition.

func (Descriptor) Digest

func (d Descriptor) Digest() Digest

Digest returns the SHA-256 identity of the complete descriptor contract.

func (Descriptor) EncodeInput

func (d Descriptor) EncodeInput[T any](value T) (Input, error)

EncodeInput converts value into an Input and validates it against this Descriptor's authoritative input schema.

func (Descriptor) InputSchema

func (d Descriptor) InputSchema() Schema

InputSchema returns the immutable schema value.

func (Descriptor) JSONSchemaAlias added in v0.18.0

func (Descriptor) JSONSchemaAlias() any

func (Descriptor) MarshalJSON

func (d Descriptor) MarshalJSON() ([]byte, error)

func (Descriptor) Name

func (d Descriptor) Name() string

Name returns the stable Definition name.

func (Descriptor) OutputSchema

func (d Descriptor) OutputSchema() Schema

OutputSchema returns the immutable schema value.

func (*Descriptor) UnmarshalJSON

func (d *Descriptor) UnmarshalJSON(data []byte) error

func (Descriptor) Valid

func (d Descriptor) Valid() bool

func (Descriptor) ValidateInput

func (d Descriptor) ValidateInput(input Input) error

func (Descriptor) ValidateOutput

func (d Descriptor) ValidateOutput(output Output) error

type DescriptorConfig

type DescriptorConfig struct {
	// Name is a stable lowercase qualified Definition name.
	Name string

	// Description states the Definition's behavior for human and model-facing
	// discovery without execution-specific state.
	Description string

	// InputSchema is the authoritative structural contract for Process input.
	InputSchema Schema

	// OutputSchema is the authoritative structural contract for completed output.
	OutputSchema Schema
}

DescriptorConfig contains the complete static contract of a Definition. Executable implementation and frozen configuration identity belong to a Deployment, not this contract.

type Digest

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

Digest is a canonical SHA-256 content identity. Its zero value is invalid.

func ComputeDigest

func ComputeDigest(data []byte) Digest

ComputeDigest returns the canonical SHA-256 identity of data. Callers that assemble a Deployment use it for reproducible implementation artifacts and canonical frozen configuration bytes.

func ParseDigest

func ParseDigest(value string) (Digest, error)

ParseDigest validates a canonical sha256:<lowercase-hex> identity.

func (Digest) JSONSchemaAlias added in v0.17.0

func (Digest) JSONSchemaAlias() any

func (Digest) MarshalText

func (d Digest) MarshalText() ([]byte, error)

func (Digest) String

func (d Digest) String() string

func (*Digest) UnmarshalText

func (d *Digest) UnmarshalText(text []byte) error

func (Digest) Valid

func (d Digest) Valid() bool

type Dispatcher

type Dispatcher interface {
	// Dispatch performs one frozen Strategy Effect outside Execution.Step.
	// Settlement must address request.ID; a non-nil error means the external
	// outcome is unknown, not definitely failed. emit is valid only during this
	// call. The runtime cancels ctx when it applies terminal intent to this
	// Process or an ancestor. It still collects the returned settlement; ctx
	// cancellation alone proves no external outcome. Host context values are
	// preserved. Implementations honor ctx and may be called concurrently.
	Dispatch(ctx context.Context, request EffectRequest, emit DeltaEmitter) (Settlement, error)
	// ReplayPolicy declares, without I/O or mutable side effects, whether this
	// exact Effect can be repeated under its original EffectID when restoring
	// a pending attempt. A settled Unknown requires explicit adjudication, and
	// terminal intent forbids replay. The answer is deterministic for equivalent
	// Effects.
	ReplayPolicy(effect Effect) ReplayPolicy
}

Dispatcher executes Strategy-owned Effects outside Execution.Step. It must return a Settlement addressed to request.ID. A returned error means the Engine cannot prove the external result and records an unknown settlement. The same Dispatcher may serve Processes concurrently; implementations must be concurrency-safe, return in bounded time, not mutate an Execution, and not start unowned goroutines. ReplayPolicy must be a pure, deterministic declaration for the supplied immutable Effect. The Engine always supplies a non-nil context. Direct callers must do the same; a nil context is a programming error, not an unknown external outcome.

A transparent decorator preserves the context, complete request identity, emitter, Settlement, and error of its wrapped Dispatcher. Its ReplayPolicy must also account for its own behavior: forwarding a SameIdentity claim is valid only when the added work is safe to repeat under the original identity. Observation counters may count dispatch attempts, including replay; they do not count distinct logical external operations. See the Definition example for a concurrency-safe attempt counter around a bound Dispatcher.

type Effect

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

Effect is an immutable request for an operation outside Execution.Step. Payload is frozen before dispatch and interpreted only by Target's owner. EffectID is deliberately absent because the Engine assigns it during prepare.

func CancelChild added in v0.18.0

func CancelChild(childID ProcessID, reason string) (Effect, error)

CancelChild declares cancellation of an exact direct child's subtree. The receipt confirms the recorded intent, not termination or resource release; use a drained child wait before reusing exclusive resources. An already terminal direct child succeeds without changing its result.

func NewDispatcherEffect

func NewDispatcherEffect(payload json.RawMessage, required ...Capability) (Effect, error)

NewDispatcherEffect carries an opaque payload plus the capabilities it requires, so the Engine can refuse an effect the Process was never granted without understanding what the effect does. Keeping the payload opaque is what stops model and tool vocabulary from entering the kernel.

func RequestWait

func RequestWait(key WaitKey, signalPayload json.RawMessage) (Effect, error)

RequestWait creates the Framework Effect that asks the Engine to mint one WaitID for key. signalPayload remains Strategy-owned and is returned unchanged in the internal Signal that carries the minted WaitID back to the Execution.

func SignalChild added in v0.18.0

func SignalChild(childID ProcessID, signal SignalRequest) (Effect, error)

SignalChild declares delivery through the child's ordinary mailbox contract. It cannot release an unrelated wait or preempt in-flight external work. Delivery and the parent Effect settlement share one tree acknowledgment. The exact SignalRequest retains its caller-chosen deduplication identity. Cross-tree delivery remains a Host-authorized messaging operation.

func StartChild

func StartChild(spec ChildSpec) (Effect, error)

StartChild creates a Framework-owned Effect requesting one independently managed child Process. The Engine derives the child ProcessID; Execution code cannot construct or start the Process directly.

func WaitForChildren

func WaitForChildren(spec ChildWaitSpec) (Effect, error)

WaitForChildren creates a Framework Effect that opens an Engine-owned wait over direct children. Dispatch returns immediately with a WaitID; child work never blocks Execution.Step or holds a prepared Step open.

func (Effect) MarshalJSON

func (e Effect) MarshalJSON() ([]byte, error)

func (Effect) Payload

func (e Effect) Payload() json.RawMessage

Payload returns an independently owned copy of the operation intent.

func (Effect) RequiredCapabilities

func (e Effect) RequiredCapabilities() CapabilitySet

RequiredCapabilities returns the immutable authority set the Process must possess before this Dispatcher Effect may be prepared.

func (Effect) Target

func (e Effect) Target() EffectTarget

Target returns the owner responsible for interpreting Payload.

func (*Effect) UnmarshalJSON

func (e *Effect) UnmarshalJSON(data []byte) error

func (Effect) Valid

func (e Effect) Valid() bool

type EffectBoundary

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

EffectBoundary binds an Effect fact to its prospective tree so a Host cannot acknowledge dispatch or settlement independently of recovery state. External dispatch uses a pending permission followed by settlement. Tree-local child controls settle directly, atomically with the recipient's mailbox or intent; they perform no external I/O requiring a pending dispatch permission.

func (EffectBoundary) Kind

func (EffectBoundary) PreviousTreeDigest

func (e EffectBoundary) PreviousTreeDigest() Digest

func (EffectBoundary) Request

func (e EffectBoundary) Request() EffectRequest

func (EffectBoundary) Settlement

func (e EffectBoundary) Settlement() (Settlement, bool)

func (EffectBoundary) TreeSnapshot

func (e EffectBoundary) TreeSnapshot() TreeSnapshot

func (EffectBoundary) Valid

func (e EffectBoundary) Valid() bool

type EffectBoundaryKind

type EffectBoundaryKind string

EffectBoundaryKind is closed because recovery needs a defined continuation for every acknowledged external Effect boundary.

const (
	EffectBoundaryInvalid  EffectBoundaryKind = ""
	EffectBoundaryPending  EffectBoundaryKind = "pending"
	EffectBoundarySettled  EffectBoundaryKind = "settled"
	EffectBoundaryResolved EffectBoundaryKind = "resolved"
)

func (EffectBoundaryKind) String

func (e EffectBoundaryKind) String() string

func (EffectBoundaryKind) Valid

func (e EffectBoundaryKind) Valid() bool

type EffectFinishedFact

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

EffectFinishedFact is the immutable settlement observation for one Effect attempt. It does not replace the durable Effect boundary.

func (EffectFinishedFact) Duration

func (e EffectFinishedFact) Duration() time.Duration

func (EffectFinishedFact) Failure added in v0.18.0

func (e EffectFinishedFact) Failure() (FailureKind, string, bool)

Failure classifies a Dispatcher error that made its outcome Unknown. It contains no diagnostic message and does not change the settlement semantics. An Unknown returned directly by the Dispatcher has no error classification.

func (EffectFinishedFact) SettlementStatus

func (e EffectFinishedFact) SettlementStatus() SettlementStatus

func (EffectFinishedFact) Target

func (e EffectFinishedFact) Target() EffectTarget

func (EffectFinishedFact) Valid

func (e EffectFinishedFact) Valid() bool

type EffectID

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

EffectID identifies one Effect at a stable Process, Step, and batch index.

func ParseEffectID

func ParseEffectID(value string) (EffectID, error)

ParseEffectID validates an externally encoded Effect identity.

func (EffectID) JSONSchemaAlias added in v0.17.0

func (EffectID) JSONSchemaAlias() any

func (EffectID) MarshalText

func (i EffectID) MarshalText() ([]byte, error)

func (EffectID) String

func (i EffectID) String() string

func (*EffectID) UnmarshalText

func (e *EffectID) UnmarshalText(text []byte) error

func (EffectID) Valid

func (i EffectID) Valid() bool

Valid distinguishes a parsed identity from its invalid zero value. Parsing and text decoding are the only boundaries that can install non-empty text.

type EffectRequest

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

EffectRequest is the immutable dispatch context prepared by the Engine.

func (EffectRequest) BatchIndex

func (e EffectRequest) BatchIndex() uint32

BatchIndex returns the zero-based declaration order within the Step Effect batch.

func (EffectRequest) DeploymentRef

func (e EffectRequest) DeploymentRef() DeploymentRef

DeploymentRef returns the exact behavior binding executing the Effect.

func (EffectRequest) Effect

func (e EffectRequest) Effect() Effect

Effect returns an independently owned copy of the frozen intent.

func (EffectRequest) ID

func (e EffectRequest) ID() EffectID

ID returns the stable identity assigned during Step preparation.

func (EffectRequest) ProcessID

func (e EffectRequest) ProcessID() ProcessID

ProcessID returns the Process that owns the Effect.

func (EffectRequest) Relation

func (e EffectRequest) Relation() ProcessRelation

Relation returns the immutable Process tree location executing the Effect.

func (EffectRequest) StepSequence

func (e EffectRequest) StepSequence() uint64

StepSequence returns the one-based Step sequence that declared the Effect.

func (EffectRequest) TreeIncarnationID added in v0.16.0

func (e EffectRequest) TreeIncarnationID() (TreeIncarnationID, bool)

TreeIncarnationID identifies the active durable writer for observation and correlation. Ephemeral requests return false. It does not participate in the Effect's stable idempotency identity, which remains ID across restoration.

func (EffectRequest) Valid

func (e EffectRequest) Valid() bool

Valid reports whether the request contains one complete Engine-minted dispatch identity and immutable Effect.

type EffectStartedFact

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

EffectStartedFact identifies the target of one Effect attempt.

func (EffectStartedFact) Target

func (e EffectStartedFact) Target() EffectTarget

func (EffectStartedFact) Valid

func (e EffectStartedFact) Valid() bool

type EffectTarget

type EffectTarget string

EffectTarget identifies which of the two execution boundaries owns an Effect. Framework Effects are interpreted by the Engine; Dispatcher Effects remain opaque to the Engine and are interpreted by the Deployment-bound dispatcher.

const (
	// EffectTargetInvalid is the invalid zero value.
	EffectTargetInvalid EffectTarget = ""
	// EffectTargetFramework identifies an Engine-interpreted Effect.
	EffectTargetFramework EffectTarget = "framework"
	// EffectTargetDispatcher identifies a Strategy dispatcher Effect.
	EffectTargetDispatcher EffectTarget = "dispatcher"
)

func (EffectTarget) String

func (e EffectTarget) String() string

func (EffectTarget) Valid

func (e EffectTarget) Valid() bool

type Engine

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

Engine keeps admission, publication, and execution under one owner because resource reservations and recoverable tree state must describe the same lifecycle. Construct it with NewEngine; copying an Engine would share its registries while duplicating their synchronization.

func NewEngine

func NewEngine(config EngineConfig) (*Engine, error)

NewEngine validates the whole configuration up front because an Engine owns Process lifecycle: a defect discovered after Processes exist has no safe remedy, since stopping the Engine would abandon in-flight effects whose settlement is still unknown.

func (*Engine) CaptureTree

func (e *Engine) CaptureTree(ctx context.Context, rootID ProcessID) (TreeSnapshot, error)

CaptureTree quiesces one complete Engine-owned tree at Strategy-safe boundaries and captures a consistent portable cut. In-flight Effects settle according to their existing contract before a Process joins the barrier. Cancellation remains available while the active work drains.

func (*Engine) Close

func (e *Engine) Close(ctx context.Context) error

Close rejects pending starts or restorations, Processes whose result publication or parent/child bookkeeping is incomplete, and trees that still own asynchronous work or a freeze. Process.Join or Run establishes subtree completion; callers must finish every tree and release any freeze before closing the Engine. Once closing begins, the Engine drains accepted Delta delivery and stops observation workers. Canceling ctx stops only this caller's wait; it does not interrupt that owned shutdown. A later Close joins the same shutdown. Concurrent callers join the same closure; existing handles retain results and RuntimeErrors for later reads.

func (*Engine) FlushDeltas

func (e *Engine) FlushDeltas(ctx context.Context) error

FlushDeltas provides the ordering barrier needed before publishing a final value that must not overtake accepted streaming observations. Dropped Deltas remain lost because flushing cannot strengthen best-effort delivery. Closing the Engine prevents new flush barriers, even when no listeners are configured.

func (*Engine) InspectTree added in v0.16.0

func (e *Engine) InspectTree(ctx context.Context, rootID ProcessID) (TreeInspection, error)

InspectTree samples a registered root tree without freezing it or waiting for storage acknowledgment. It remains available during a commit, while a freeze is acquired or held, and after the owner stops or Engine.Close returns. ReleaseTree removes the lookup; an overlapping inspection may return its earlier valid sample. ctx bounds both admission and response waiting. The owner never calls user execution code to construct a report. Dependencies must still return in bounded time: synchronous EventListeners must not query or control their own tree. Query failures are returned as errors; runtime failures are reported through ProcessInspection.RuntimeError.

func (*Engine) ObservationFailures

func (e *Engine) ObservationFailures() ObservationFailures

ObservationFailures returns consistent panic counts and the latest bounded diagnostic for each listener kind. Listener failures cannot veto execution.

func (*Engine) Process

func (e *Engine) Process(id ProcessID) (*Process, bool)

func (*Engine) ReleaseTree added in v0.15.0

func (e *Engine) ReleaseTree(ctx context.Context, rootID ProcessID) error

ReleaseTree waits for the complete root tree to settle and removes its in-memory registry entries and execution state. It does not cancel work or delete Host persistence. Capture any required TreeSnapshot before releasing. Existing Process handles retain their Result or RuntimeError; Engine.Process and tree operations no longer find the released identities. Canceling ctx before settlement leaves the tree registered and usable.

func (*Engine) RestoreTree

func (e *Engine) RestoreTree(
	ctx context.Context,
	rootDeployment Deployment,
	snapshot TreeSnapshot,
) (*Process, error)

RestoreTree recreates a complete Process tree from one strict TreeSnapshot. rootDeployment must exactly bind the captured root; same-reference children reuse it, while other exact references are resolved through EngineConfig's DeploymentResolver. Registration is all-or-nothing within this Engine. Committed states and nonterminal prepared candidates must restore through their exact Definition before registration, activation, or Effect dispatch. Interrupted terminal candidates remain inert evidence and are not restored. Both completed and prepared completion outputs must satisfy that Definition's output schema before admission.

Snapshot capabilities, limits, budgets, and usage remain authoritative. Current EngineConfig start defaults do not revoke or rewrite captured grants. The Host must authorize the snapshot before calling RestoreTree; ProcessAdmitter and initialization acknowledgment are not repeated for captured Processes.

func (*Engine) Run

func (e *Engine) Run(ctx context.Context, deployment Deployment, input Input) (Result, error)

Run starts one root Process and joins its entire subtree before returning the root's terminal Result. It keeps waiting after ctx cancellation because owned work and required acknowledgments must finish. A runtime failure anywhere in the subtree returns a RuntimeError and no Result, even when the root already completed; its acknowledged result remains available through Process.Await. Ordinary execution failure returns the root's valid Result and nil error.

func (*Engine) Start

func (e *Engine) Start(ctx context.Context, deployment Deployment, input Input) (*Process, error)

Start keeps ctx attached to the resulting tree so Host cancellation and deadlines reach accepted work. Execution that outlives a request therefore needs a longer-lived context.

Example (SuccessiveEpisodes)

This example keeps continuation in the embedding Host. Its teaching store atomically links successor admission to the initial recoverable tree. A real database must perform those writes in one transaction. Engine.Start itself remains a fresh start; ambiguous creation is reconciled through that record.

package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/Tangerg/scope/agent"
	"github.com/Tangerg/scope/agent/strategy/workflow"
)

type episodeState struct {
	Revision uint32 `json:"revision"`
	Summary  string `json:"summary"`
}

func episodeDeployment() (agent.Deployment, error) {
	stage, err := workflow.Transform("revise", func(_ context.Context, state episodeState) (episodeState, error) {
		if state.Revision >= 3 {
			return episodeState{}, errors.New("episode revision bound reached")
		}
		state.Revision++
		return state, nil
	})
	if err != nil {
		return agent.Deployment{}, err
	}
	definition, err := workflow.NewDefinition(workflow.DefinitionConfig{
		Name: "example.episode", Description: "Advance one bounded revision.", Stages: []workflow.Stage{stage},
	})
	if err != nil {
		return agent.Deployment{}, err
	}
	return episodeBinding(definition)
}

func episodeBinding(definition agent.Definition) (agent.Deployment, error) {
	return agent.NewDeployment(agent.DeploymentConfig{
		Definition:           definition,
		ImplementationDigest: agent.ComputeDigest([]byte("example-episode-implementation")),
		ConfigurationDigest:  agent.ComputeDigest([]byte(definition.Descriptor().Name() + "/revision-bound-3")),
	})
}

// The Host chooses an explicit new allocation; unused predecessor budget is
// never refunded. Request equality freezes state, behavior, limits, and authority.
type successorRequest struct {
	Predecessor   agent.ProcessID     `json:"predecessor"`
	DeploymentRef agent.DeploymentRef `json:"deployment_ref"`
	Input         agent.Input         `json:"input"`
	Limits        agent.Limits        `json:"limits"`
	TreeLimits    agent.TreeLimits    `json:"tree_limits"`
	Capabilities  agent.CapabilitySet `json:"capabilities"`
}

func (s successorRequest) identity() (agent.Digest, error) {
	if !s.Predecessor.Valid() || !s.DeploymentRef.Valid() || !s.Input.Valid() || !s.Limits.Valid() || !s.TreeLimits.Valid() || !s.Capabilities.Valid() {
		return agent.Digest{}, errors.New("invalid successor request")
	}
	encoded, err := agent.EncodeInput(s)
	if err != nil {
		return agent.Digest{}, err
	}
	return agent.ComputeDigest(encoded.JSON()), nil
}

// This example keeps continuation in the embedding Host. Its teaching store
// atomically links successor admission to the initial recoverable tree. A real
// database must perform those writes in one transaction. Engine.Start itself
// remains a fresh start; ambiguous creation is reconciled through that record.
func main() {
	ctx := context.Background()
	store := newEpisodeStore()
	deployment, err := episodeDeployment()
	if err != nil {
		panic(err)
	}
	engine, err := agent.NewEngine(agent.EngineConfig{TreeDurability: store.trees})
	if err != nil {
		panic(err)
	}
	defer func() {
		if closeErr := engine.Close(ctx); closeErr != nil {
			panic(closeErr)
		}
	}()
	initial, err := agent.EncodeInput(episodeState{Summary: "reviewed plan"})
	if err != nil {
		panic(err)
	}
	previous, err := engine.Start(ctx, deployment, initial)
	if err != nil {
		panic(err)
	}
	result, err := store.sealEpisode(ctx, previous)
	if err != nil {
		panic(err)
	}
	output, present := result.Output()
	if !present {
		panic("completed episode has no output")
	}
	state, err := output.Decode[episodeState]()
	if err != nil {
		panic(err)
	}
	transfer, err := agent.EncodeInput(state)
	if err != nil {
		panic(err)
	}
	request := successorRequest{
		Predecessor: previous.ID(), DeploymentRef: deployment.DeploymentRef(), Input: transfer,
		Limits:     agent.Limits{MaxSteps: 8, MaxEffects: 4, MaxSignals: 8, MaxPendingSignals: 8},
		TreeLimits: agent.DefaultTreeLimits(),
	}
	host := &episodeHost{store: store}
	defer func() {
		if closeErr := host.close(ctx); closeErr != nil {
			panic(closeErr)
		}
	}()
	next, err := host.start(ctx, deployment, request)
	if err != nil {
		panic(err)
	}
	duplicate, err := host.start(ctx, deployment, request)
	if err != nil {
		panic(err)
	}
	final, err := next.Await(ctx)
	if err != nil {
		panic(err)
	}
	if joinErr := next.Join(ctx); joinErr != nil {
		panic(joinErr)
	}
	finalOutput, present := final.Output()
	if !present {
		panic("successor has no output")
	}
	nextState, err := finalOutput.Decode[episodeState]()
	if err != nil {
		panic(err)
	}
	fmt.Println("revision:", state.Revision, "->", nextState.Revision)
	fmt.Println("same successor:", next.ID() == duplicate.ID())
	fmt.Println("new allocations:", store.allocations)
}

// Each Host owns its runtime instances. A replacement Host has no live handles
// and restores the already admitted tree; it does not create another successor.
type episodeHost struct {
	store   *episodeStore
	engines []*agent.Engine
}

func (e *episodeHost) start(ctx context.Context, deployment agent.Deployment, request successorRequest) (*agent.Process, error) {
	if deployment.DeploymentRef() != request.DeploymentRef {
		return nil, agent.ErrInvalidDeployment
	}
	if err := deployment.Descriptor().ValidateInput(request.Input); err != nil {
		return nil, err
	}
	attempt, existing, err := e.store.claim(request)
	if err != nil {
		return nil, err
	}
	if existing.Valid() {
		for _, engine := range e.engines {
			if process, present := engine.Process(existing); present {
				return process, nil
			}
		}
	}
	return e.activate(ctx, deployment, request, attempt, existing)
}

func (e *episodeHost) activate(ctx context.Context, deployment agent.Deployment, request successorRequest, attempt *episodeAttempt, existing agent.ProcessID) (*agent.Process, error) {
	engine, err := agent.NewEngine(agent.EngineConfig{
		TreeDurability: attempt, ProcessAdmitter: attempt,
		Limits: request.Limits, TreeLimits: request.TreeLimits, Capabilities: request.Capabilities,
	})
	if err != nil {
		return nil, err
	}
	e.engines = append(e.engines, engine)
	if !existing.Valid() {
		return engine.Start(ctx, deployment, request.Input)
	}
	head, present, err := e.store.trees.LoadTree(ctx, existing)
	if err != nil {
		return nil, err
	}
	if !present {
		return nil, errors.New("successor record has no committed tree")
	}
	return engine.RestoreTree(ctx, deployment, head)
}

func (e *episodeHost) close(ctx context.Context) error {
	var failures []error
	for _, engine := range e.engines {
		failures = append(failures, engine.Close(ctx))
	}
	return errors.Join(failures...)
}
Output:
revision: 1 -> 2
same successor: true
new allocations: 1

type EngineConfig

type EngineConfig struct {
	// TreeDurability makes publication wait for acknowledgment of a recoverable
	// tree. Nil selects ephemeral execution without storage acknowledgment.
	TreeDurability TreeDurability

	// ProcessInitializationOutcomeAcknowledger optionally accepts initialization outcomes
	// before publication. Its acknowledgment is separate from TreeDurability;
	// nil omits this Host acceptance step.
	ProcessInitializationOutcomeAcknowledger ProcessInitializationOutcomeAcknowledger

	// Exact local bindings prevent restoration from silently selecting different
	// behavior. Same-Deployment recursion needs no resolver.
	DeploymentResolver DeploymentResolver

	// ProcessAdmitter optionally applies Host policy before root or child
	// initialization. Nil admits every start that satisfies Engine constraints.
	ProcessAdmitter ProcessAdmitter

	// EventListeners receive synchronous Framework facts. An empty slice disables
	// delivery. Callbacks must be bounded and must not query or control their tree.
	EventListeners []EventListener

	// DeltaListeners receive queued, best-effort Strategy increments. An empty
	// slice disables delivery. Callbacks run serially and must return so Engine
	// shutdown can drain the queue and join its delivery worker.
	DeltaListeners []DeltaListener

	// A bounded queue prevents slow listeners from retaining unlimited Deltas.
	// Zero selects the library default; negative capacities are invalid.
	DeltaBufferCapacity int

	// Zero fields inherit DefaultLimits so partial overrides still produce
	// complete per-Process resource bounds.
	Limits Limits

	// TreeLimits bounds descendant count, depth, and active children. Zero fields
	// inherit DefaultTreeLimits independently of per-Process Limits.
	TreeLimits TreeLimits

	// Capabilities grants authority to new roots. Children receive only subsets
	// of their parent's captured authority, including after restoration.
	Capabilities CapabilitySet
}

EngineConfig keeps scheduling and authority policy outside Deployments so a strategy cannot change its constraints through its behavior binding. Limits, TreeLimits, and Capabilities apply to newly started root trees. RestoreTree retains their captured values; the Host authorizes snapshots before recovery.

type Event

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

Event is an immutable, ordered fact published by the Framework. Observers may project or instrument it, but observer failure never changes Process state. Payload is descriptive data, never a Signal or state mutation command.

func (Event) DeltaDropped

func (e Event) DeltaDropped() (DeltaDroppedFact, bool)

DeltaDropped returns the typed loss fact for EventDeltaDropped.

func (Event) DeploymentRef

func (e Event) DeploymentRef() DeploymentRef

DeploymentRef returns the exact execution binding that emitted the fact.

func (Event) EffectFinished

func (e Event) EffectFinished() (EffectFinishedFact, bool)

EffectFinished returns the typed settlement fact for EventEffectFinished.

func (Event) EffectID

func (e Event) EffectID() (EffectID, bool)

EffectID returns the related Effect identity and true when this is an Effect fact.

func (Event) EffectStarted

func (e Event) EffectStarted() (EffectStartedFact, bool)

EffectStarted returns the typed target fact for EventEffectStarted.

func (Event) MarshalJSON

func (e Event) MarshalJSON() ([]byte, error)

func (Event) Name

func (e Event) Name() string

Name returns the stable Framework fact name.

func (Event) OccurredAt

func (e Event) OccurredAt() time.Time

OccurredAt returns when the fact occurred.

func (Event) Payload

func (e Event) Payload() json.RawMessage

Payload returns an independently owned descriptive payload.

func (Event) Phase

func (e Event) Phase() EventPhase

Phase returns whether the fact describes an attempt or committed state.

func (Event) ProcessFinished

func (e Event) ProcessFinished() (ProcessFinishedFact, bool)

ProcessFinished returns the typed terminal fact for EventProcessFinished.

func (Event) ProcessID

func (e Event) ProcessID() ProcessID

ProcessID returns the Process whose fact is described.

func (Event) ProcessSequence

func (e Event) ProcessSequence() uint64

ProcessSequence returns the Process-local publication order within one tree runtime activation, starting at one. Restoration starts a new sequence; publication progress is observation state and is not part of a TreeSnapshot.

func (Event) Relation

func (e Event) Relation() ProcessRelation

Relation returns the Process tree location that emitted the fact.

func (Event) RuntimeStopped added in v0.16.0

func (e Event) RuntimeStopped() (RuntimeStoppedFact, bool)

RuntimeStopped returns the typed instance failure for EventRuntimeStopped.

func (Event) SignalAccepted

func (e Event) SignalAccepted() (SignalAcceptedFact, bool)

SignalAccepted returns the typed delivery fact for EventSignalAccepted.

func (Event) StepCommitted

func (e Event) StepCommitted() (StepCommittedFact, bool)

StepCommitted returns the typed state fact for EventStepCommitted.

func (Event) StepFinished

func (e Event) StepFinished() (StepFinishedFact, bool)

StepFinished returns the typed attempt fact for EventStepFinished.

func (Event) StepSequence

func (e Event) StepSequence() (uint64, bool)

StepSequence returns the one-based Step sequence and true, or zero and false for a Process fact outside a Step.

func (Event) TreeIncarnationID

func (e Event) TreeIncarnationID() (TreeIncarnationID, bool)

TreeIncarnationID returns the active durable writer that emitted this event. Events from ephemeral trees return false.

func (*Event) UnmarshalJSON

func (e *Event) UnmarshalJSON(data []byte) error

func (Event) Valid

func (e Event) Valid() bool

type EventListener

type EventListener interface {
	// OnEvent receives one committed or attempted Framework fact in increasing
	// ProcessSequence for its Process within one tree runtime activation. A
	// restored nonterminal Process starts with EventProcessRestored; durable
	// activations also carry distinct TreeIncarnationIDs. Different tree runtimes
	// may call the listener concurrently. It runs synchronously on the
	// observed tree's owner, so it must return in bounded time without querying or
	// controlling that tree, or calling Process.Await on it. Calls using this
	// context, or a derived context, return [ErrListenerReentrancy] while the
	// callback is active. The restriction ends when this invocation returns,
	// including after a panic. Calls to other trees must still return in bounded
	// time; distinct owners do not prevent cyclic waits between callbacks.
	// The listener has no veto or acknowledgment authority.
	OnEvent(ctx context.Context, event Event)
}

EventListener observes ordered Framework facts. Panics are isolated from Process execution and never alter committed state. Implementations must return in bounded time and must not query or control the observed tree.

type EventListenerFunc

type EventListenerFunc func(ctx context.Context, event Event)

EventListenerFunc adapts a plain function to the event listener interface. A listener observes and must not steer execution, so the signature returns nothing to make that boundary hard to violate by accident.

func (EventListenerFunc) OnEvent

func (e EventListenerFunc) OnEvent(ctx context.Context, event Event)

type EventPhase

type EventPhase string

EventPhase distinguishes runtime observations from facts supported by authoritative Process state. Durable trees publish committed facts only after TreeDurability acknowledges the resulting tree state. Attempt facts do not assert a committed Process state change.

const (
	// EventPhaseInvalid is the invalid zero value.
	EventPhaseInvalid EventPhase = ""
	// EventPhaseAttempt identifies runtime work without a state commit guarantee.
	EventPhaseAttempt EventPhase = "attempt"
	// EventPhaseCommitted identifies a fact whose resulting state is acknowledged.
	EventPhaseCommitted EventPhase = "committed"
)

func (EventPhase) String

func (e EventPhase) String() string

func (EventPhase) Valid

func (e EventPhase) Valid() bool

type Execution

type Execution interface {
	// Step reduces the current private state and the supplied ordered Signal
	// prefix into one candidate Transition. It must honor ctx for bounded CPU
	// work, perform no I/O, consume no hidden input, and never retain signals.
	// The Engine serializes calls for one Execution.
	Step(ctx context.Context, signals []Signal) (Transition, error)
	// Snapshot returns a complete, independently owned state from
	// which Definition.Restore can reproduce the current Execution exactly. It
	// must fail rather than omit state required for deterministic continuation.
	Snapshot() (ExecutionState, error)
}

Execution is the single Strategy-owned state machine inside one Process. Step must be a bounded, deterministic state reduction over the current state and the supplied Signal prefix. It must not perform external I/O, read clock, random or global state, or start ownerless goroutines. External operations are returned as Effects. Snapshot must fail rather than return partial state.

The Engine is the sole caller and never invokes Step concurrently for the same Execution. If Step or Snapshot fails, the instance is discarded and may only be rebuilt from the committed ExecutionState. The Engine always supplies a non-nil Step context.

type ExecutionState

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

ExecutionState is an immutable envelope owned by one Execution Strategy. The Engine persists and returns Payload without interpreting it. Its zero value is invalid.

func NewExecutionState

func NewExecutionState(kind string, payload json.RawMessage) (ExecutionState, error)

NewExecutionState pairs a strategy kind with an opaque payload. The kind exists so a snapshot can be rejected when restored into the wrong strategy; the payload stays opaque so adding a strategy never widens the kernel.

func (ExecutionState) Kind

func (e ExecutionState) Kind() string

Kind returns the Strategy that exclusively interprets Payload.

func (ExecutionState) MarshalJSON

func (e ExecutionState) MarshalJSON() ([]byte, error)

func (ExecutionState) Payload

func (e ExecutionState) Payload() json.RawMessage

Payload returns an independently owned copy of the opaque Strategy state.

func (*ExecutionState) UnmarshalJSON

func (e *ExecutionState) UnmarshalJSON(data []byte) error

func (ExecutionState) Valid

func (e ExecutionState) Valid() bool

type Failure

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

Failure separates stable codes from diagnostic text so wording changes cannot alter control flow. Its bounded UTF-8 message must survive snapshot JSON and must exclude secrets.

func NewFailure

func NewFailure(kind FailureKind, code, message string) (Failure, error)

NewFailure requires a kind and code alongside the message so callers classify failures programmatically. Matching on message text is what makes error handling break on wording changes, and it does not survive the snapshot round trip. Message must be trimmed, valid UTF-8 and contain at most 4096 bytes.

func (Failure) Code

func (f Failure) Code() string

func (Failure) JSONSchemaAlias added in v0.17.0

func (Failure) JSONSchemaAlias() any

func (Failure) Kind

func (f Failure) Kind() FailureKind

func (Failure) MarshalJSON

func (f Failure) MarshalJSON() ([]byte, error)

func (Failure) Message

func (f Failure) Message() string

func (*Failure) UnmarshalJSON

func (f *Failure) UnmarshalJSON(data []byte) error

func (Failure) Valid

func (f Failure) Valid() bool

type FailureKind

type FailureKind string

FailureKind stays independent of retryability so classifying a failure cannot silently select a recovery or business policy.

const (
	FailureKindInvalid   FailureKind = ""
	FailureKindExecution FailureKind = "execution"
	FailureKindContract  FailureKind = "contract"
	FailureKindExternal  FailureKind = "external"
	FailureKindPanic     FailureKind = "panic"
)

func (FailureKind) String

func (f FailureKind) String() string

func (FailureKind) Valid

func (f FailureKind) Valid() bool

type Input

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

Input is the immutable JSON value used to start a Process. Its zero value is invalid. ParseInput and EncodeInput take ownership by copying and normalizing their input.

func EncodeInput

func EncodeInput[T any](value T) (Input, error)

EncodeInput strictly encodes a typed value into an independently owned Input. Invalid UTF-8 and duplicate JSON names are rejected, including custom codec output. Custom codecs are responsible for preserving their source values.

Example
package main

import (
	"fmt"

	"github.com/Tangerg/scope/agent"
)

func main() {
	type request struct {
		Topic string `json:"topic"`
	}

	input, err := agent.EncodeInput(request{Topic: "agent runtimes"})
	if err != nil {
		panic(err)
	}
	decoded, err := input.Decode[request]()
	if err != nil {
		panic(err)
	}

	fmt.Println(decoded.Topic, input.Valid())
}
Output:
agent runtimes true

func ParseInput

func ParseInput(data json.RawMessage) (Input, error)

ParseInput validates one JSON value and returns an independently owned Input.

func (Input) Decode

func (i Input) Decode[T any]() (T, error)

Decode strictly decodes i into a typed value. Unknown object fields are rejected when T is a struct.

func (Input) JSON

func (i Input) JSON() json.RawMessage

JSON returns an independently owned JSON representation.

func (Input) JSONSchemaAlias added in v0.17.0

func (Input) JSONSchemaAlias() any

func (Input) MarshalJSON

func (i Input) MarshalJSON() ([]byte, error)

func (*Input) UnmarshalJSON

func (i *Input) UnmarshalJSON(data []byte) error

func (Input) Valid

func (i Input) Valid() bool

type Limits

type Limits struct {
	// MaxSteps bounds committed Steps.
	MaxSteps uint64 `json:"max_steps"`

	// MaxEffects bounds Effects prepared across all Steps.
	MaxEffects uint64 `json:"max_effects"`

	// MaxSignals bounds all accepted external and Engine-generated Signals.
	MaxSignals uint64 `json:"max_signals"`

	// MaxPendingSignals bounds the current unconsumed mailbox suffix and the
	// suffix after the prepared Step consumes inputs and appends settlements.
	// Every arriving Signal preserves both bounds regardless of its source.
	MaxPendingSignals uint64 `json:"max_pending_signals"`
}

Limits bounds Framework-owned execution growth. Zero-valued fields in EngineConfig inherit DefaultLimits; ProcessSnapshot stores effective non-zero values so restoration preserves the same execution contract.

func DefaultLimits

func DefaultLimits() Limits

DefaultLimits returns conservative hard bounds for one Process.

func (Limits) Valid

func (l Limits) Valid() bool

type ListenerPanic added in v0.18.0

type ListenerPanic struct {
	ListenerIndex int
	ListenerType  string
	ProcessID     ProcessID
	Message       string
	Stack         string
}

ListenerPanic identifies one isolated listener failure. ListenerIndex is the zero-based position in EngineConfig.EventListeners or DeltaListeners, and ListenerType is its Go type. Message retains at most 4 KiB of the formatted panic value; Stack retains at most 64 KiB of the failing goroutine's stack.

type ObservationFailures added in v0.18.0

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

ObservationFailures is an immutable snapshot of listener panics isolated by one Engine. Counts are monotonic and saturate at math.MaxUint64. Only the latest event-listener panic and delta-listener panic are retained.

func (ObservationFailures) DeltaListenerPanics added in v0.18.0

func (o ObservationFailures) DeltaListenerPanics() uint64

func (ObservationFailures) EventListenerPanics added in v0.18.0

func (o ObservationFailures) EventListenerPanics() uint64

func (ObservationFailures) LastDeltaPanic added in v0.18.0

func (o ObservationFailures) LastDeltaPanic() (ListenerPanic, bool)

LastDeltaPanic reports the latest failure in the delta-listener list.

func (ObservationFailures) LastEventPanic added in v0.18.0

func (o ObservationFailures) LastEventPanic() (ListenerPanic, bool)

LastEventPanic reports the latest failure in the event-listener list.

type Output

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

Output is the immutable final semantic result of a completed Process. Its zero value is invalid and it never represents streamed Delta content.

func EncodeOutput

func EncodeOutput[T any](value T) (Output, error)

EncodeOutput strictly encodes a typed value into an independently owned Output. It uses the same lossless encoding contract as EncodeInput.

func ParseOutput

func ParseOutput(data json.RawMessage) (Output, error)

ParseOutput validates one JSON value and returns an independently owned Output.

func (Output) Decode

func (o Output) Decode[T any]() (T, error)

Decode strictly decodes o into a typed value. Unknown object fields are rejected when T is a struct.

func (Output) JSON

func (o Output) JSON() json.RawMessage

JSON returns an independently owned JSON representation.

func (Output) JSONSchemaAlias added in v0.17.0

func (Output) JSONSchemaAlias() any

func (Output) MarshalJSON

func (o Output) MarshalJSON() ([]byte, error)

func (*Output) UnmarshalJSON

func (o *Output) UnmarshalJSON(data []byte) error

func (Output) Valid

func (o Output) Valid() bool

type Process

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

Process is an Engine-issued handle to one managed execution. Its fields and construction remain private so a caller cannot create a second lifecycle owner. Identity and allocation are immutable; Engine.InspectTree owns live inspection. The zero value and nil receiver are invalid; methods require an Engine-issued handle and may panic otherwise. A finished Process remains a valid handle. Control methods submit requests to the owning tree runtime. Except for RequestCancellation, ctx bounds both submission and response waiting. Once a command enters the runtime queue, canceling ctx does not revoke it. A context already canceled before submission never admits a command.

func (*Process) Await

func (p *Process) Await(ctx context.Context) (Result, error)

Await waits for the immutable terminal result and the Engine's immediate parent/child bookkeeping for that termination. Canceling ctx stops only the wait; Process cancellation is explicit or follows the context passed to Start. A durability failure stops this instance and returns a RuntimeError with no Result. A failed logical execution returns a valid Result and nil error. Descendants may still be settling after this Process's result is ready.

func (*Process) Budget

func (p *Process) Budget() Budget

Budget returns the fixed non-renewable allocation assigned to this Process.

func (*Process) Capabilities

func (p *Process) Capabilities() CapabilitySet

Capabilities returns the immutable authority set assigned to this Process.

func (*Process) DeliverSignals

func (p *Process) DeliverSignals(ctx context.Context, requests ...SignalRequest) (accepted bool, err error)

DeliverSignals submits one or more immutable Strategy inputs as an ordered, atomic batch. Unaddressed input queues for the next Strategy-safe Step, including while Paused or waiting for child completion. It never resumes either state by itself. An externally addressable wait requires an answer. An addressed answer while Waiting must name the current WaitID; any other external wait answer returns ErrSignalRejected. The batch is accepted or the mailbox remains unchanged. Reusing a SignalID with different normalized payload bytes or a different WaitID returns ErrSignalConflict. If any SignalID repeats with identical content, accepted is false with nil error and the whole batch is unchanged, including resource usage. Engine-reserved SignalIDs are invalid SignalRequests. A batch exceeding mailbox, work-budget, Process snapshot, or tree snapshot capacity returns ErrResourceLimitExceeded before changing the mailbox. In durable mode, accepted is true only after the mailbox and budget changes commit to the authoritative tree head. A caller timeout does not revoke an admitted command; retry the identical batch to reconcile uncertain delivery.

func (*Process) DeploymentRef

func (p *Process) DeploymentRef() DeploymentRef

DeploymentRef returns the exact Definition and dispatcher binding identity.

func (*Process) ID

func (p *Process) ID() ProcessID

ID returns the stable Process identity.

func (*Process) Join added in v0.17.0

func (p *Process) Join(ctx context.Context) error

Join waits for this Process and every descendant to finish their owned work and required acknowledgments in this runtime. It does not cancel execution or release registry entries. Canceling ctx stops only this wait. Ordinary execution failure and terminal Unknown settlements do not prevent a successful join; Await reports the Process result. A runtime failure in this subtree returns a RuntimeError after its local jobs have returned, even when this Process published its result before a descendant failed. Join makes no claim that a remote operation or a previous writer has stopped. Strategies wait without blocking a Dispatcher through WaitForChildren.

func (*Process) Kill

func (p *Process) Kill(ctx context.Context, reason string) error

Kill records the Engine control plane's highest-priority terminal intent. It signals owned work throughout the subtree and collects in-flight Effects before termination. It cannot force a goroutine or a remote operation to stop. A nil error acknowledges the local intent. Await establishes whether the resulting termination committed or this instance stopped with a RuntimeError.

func (*Process) Pause

func (p *Process) Pause(ctx context.Context, reason string) error

Pause requests a scheduling pause at the next safe Step boundary. An in-flight Effect is allowed to settle before the pause becomes visible. An accepted pause discards an unadopted Wait candidate without consuming its Signals; Resume recomputes that Step from committed state. A nil error acknowledges the local control intent, not its durable publication or completion; Engine.InspectTree reports StatusPaused only after a tree commit acknowledges the paused state in durable mode.

func (*Process) Relation

func (p *Process) Relation() ProcessRelation

Relation returns the immutable parent/root/depth location assigned by the Engine. It is a root relation for Processes created through Engine.Start.

func (*Process) RequestCancellation

func (p *Process) RequestCancellation(ctx context.Context, reason string) error

RequestCancellation submits a caller-owned cancellation intent. A nil error means the request entered the owning tree runtime's queue; it does not mean the Process has reached a safe boundary or become terminal. Once submitted, ctx cancellation cannot revoke the request. The first committed cancellation intent maps to StatusCanceled with a host-cancellation cause. A pending tree commit must finish before the owner can apply this queued intent. Storage acknowledgment latency therefore also delays cancellation of owned contexts; submission alone does not interrupt an in-flight commit. Applying the intent cancels owned Step, Dispatch, and child-admission contexts throughout the subtree before waiting for their results. Already started external work still settles; remaining planned Effects do not start. Required initialization and persistence acknowledgments retain independent contexts. A surviving parent receives the ordinary child-completion Signal and its Strategy decides how to continue. Await reports this Process's acknowledged terminal result; every descendant retains its own settlement.

func (*Process) ResolveUnknownEffect

func (p *Process) ResolveUnknownEffect(ctx context.Context, settlement Settlement) error

ResolveUnknownEffect supplies a definite result after an Effect attempt became unknown. The Engine never converts unknown into retry or success implicitly. A definite result exceeding Process or tree snapshot capacity returns ErrResourceLimitExceeded without changing the Unknown record or durable head; the caller can then supply a smaller result. Terminal intent or a committed terminal result returns ErrProcessFinished; retained interrupted-batch evidence cannot resume a terminated execution.

func (*Process) Resume

func (p *Process) Resume(ctx context.Context) error

Resume makes an explicitly Paused Process schedulable again. External waits require an answer addressed to their WaitID; child waits require Framework child completion. Resume does not satisfy either wait. A nonterminal Process that is not Paused returns ErrInvalidProcessControl. A nil error acknowledges local resumption. Subsequent durable boundaries publish the resumed state before reporting their own acknowledgments.

func (*Process) StartedAt

func (p *Process) StartedAt() time.Time

StartedAt returns the observed UTC lifecycle start time recorded before initialization, retained when the Process is published.

type ProcessAdmission

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

ProcessAdmission is the immutable Framework-owned information supplied to a ProcessAdmitter immediately before one root or child Process starts. It does not expose Input, Execution, Dispatcher, product identity, or Host state.

func (ProcessAdmission) Budget

func (p ProcessAdmission) Budget() Budget

Budget returns the prospective Process's fixed non-renewable allocation.

func (ProcessAdmission) Capabilities

func (p ProcessAdmission) Capabilities() CapabilitySet

Capabilities returns the prospective Process's immutable authority set.

func (ProcessAdmission) DeploymentRef

func (p ProcessAdmission) DeploymentRef() DeploymentRef

DeploymentRef returns the exact prospective Deployment identity.

func (ProcessAdmission) Descriptor

func (p ProcessAdmission) Descriptor() Descriptor

Descriptor returns the prospective Definition's static contract.

func (ProcessAdmission) Relation

func (p ProcessAdmission) Relation() ProcessRelation

Relation returns the prospective Process identity and tree location.

func (ProcessAdmission) Valid

func (p ProcessAdmission) Valid() bool

type ProcessAdmitter

type ProcessAdmitter interface {
	// Admit decides whether the immutable prospective Process may initialize.
	// Returning nil accepts only the supplied identity and resources; it cannot
	// enlarge Budget or Capabilities. Returning an error prevents initialization
	// and publication. Implementations honor ctx, are bounded and concurrency-
	// safe, and must tolerate the same prospective identity after recovery.
	Admit(ctx context.Context, admission ProcessAdmission) error
}

ProcessAdmitter decides whether one prospective root or child Process may initialize. Implementations may coordinate caller-owned external admission work, but must not create a Process, mutate the admission, or allocate Framework resources. A prepared Step may replay the same child admission with the same prospective Process identity after recovery. The runtime cancels an active child admission when its parent terminates; an accepted admission still receives its required initialization outcome.

Implementations must respect ctx, return in bounded time, be safe for concurrent calls when shared, and must not re-enter the Engine or a Process. Framework identity is stable, but persistence, transactionality, charging, and business idempotency remain implementation responsibilities. Returning an error rejects only this prospective Process. Budget allocation, capability attenuation, and tree limits remain Engine invariants and cannot be changed by an admitter. Every accepted admission concludes with exactly one ProcessInitializationOutcome when an acknowledger is configured. Restore repeats neither admission nor its outcome for a captured Process.

type ProcessAdmitterFunc

type ProcessAdmitterFunc func(ctx context.Context, admission ProcessAdmission) error

ProcessAdmitterFunc adapts a plain function to the admitter interface, so a host quota or policy check does not require a named type.

func (ProcessAdmitterFunc) Admit

func (p ProcessAdmitterFunc) Admit(ctx context.Context, admission ProcessAdmission) error

type ProcessFinishedFact

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

ProcessFinishedFact is the immutable terminal fact carried by a finished Process Event. Usage is the authoritative Framework-owned terminal usage.

func (ProcessFinishedFact) Cause

func (ProcessFinishedFact) Failure

func (p ProcessFinishedFact) Failure() (FailureKind, string, bool)

func (ProcessFinishedFact) Status

func (p ProcessFinishedFact) Status() Status

func (ProcessFinishedFact) Usage

func (p ProcessFinishedFact) Usage() Usage

func (ProcessFinishedFact) Valid

func (p ProcessFinishedFact) Valid() bool

type ProcessID

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

ProcessID is the stable identity of one Engine-owned Process.

func ParseProcessID

func ParseProcessID(value string) (ProcessID, error)

ParseProcessID validates an externally encoded Process identity.

func (ProcessID) JSONSchemaAlias added in v0.17.0

func (ProcessID) JSONSchemaAlias() any

func (ProcessID) MarshalText

func (i ProcessID) MarshalText() ([]byte, error)

func (ProcessID) String

func (i ProcessID) String() string

func (*ProcessID) UnmarshalText

func (p *ProcessID) UnmarshalText(text []byte) error

func (ProcessID) Valid

func (i ProcessID) Valid() bool

Valid distinguishes a parsed identity from its invalid zero value. Parsing and text decoding are the only boundaries that can install non-empty text.

type ProcessInitializationOutcome added in v0.19.0

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

ProcessInitializationOutcome separates initialization acceptance from publication: persistence can still fail after an initialized outcome is accepted.

func (ProcessInitializationOutcome) Admission added in v0.19.0

func (ProcessInitializationOutcome) Failure added in v0.19.0

func (p ProcessInitializationOutcome) Failure() (Failure, bool)

func (ProcessInitializationOutcome) StartedAt added in v0.19.0

func (p ProcessInitializationOutcome) StartedAt() (time.Time, bool)

StartedAt returns the observed UTC lifecycle start time recorded before initialization. It is available only after successful initialization and does not identify the later Process publication boundary.

func (ProcessInitializationOutcome) Status added in v0.19.0

func (ProcessInitializationOutcome) Valid added in v0.19.0

type ProcessInitializationOutcomeAcknowledger added in v0.19.0

type ProcessInitializationOutcomeAcknowledger interface {
	// AcknowledgeProcessInitializationOutcome must return before publication so a Host
	// can reject initialization without exposing a usable Process.
	AcknowledgeProcessInitializationOutcome(ctx context.Context, outcome ProcessInitializationOutcome) error
}

ProcessInitializationOutcomeAcknowledger lets a Host close each accepted admission even when initialization fails before a Process exists. Rejecting an initialized outcome prevents publication; accepting it does not guarantee later persistence. Implementations must be bounded, concurrency-safe, idempotent by admission identity, and must not re-enter Engine or Process, because initialization waits for this call. Restore produces no outcome because it does not initialize. ctx retains Host values but excludes cancellation and deadlines so an accepted admission can finish acknowledgment even when its parent is terminating. The Host must apply an independent bounded deadline and reconcile an uncertain acknowledgment by admission identity; timeout alone does not prove rejection.

type ProcessInitializationOutcomeAcknowledgerFunc added in v0.19.0

type ProcessInitializationOutcomeAcknowledgerFunc func(
	ctx context.Context,
	outcome ProcessInitializationOutcome,
) error

func (ProcessInitializationOutcomeAcknowledgerFunc) AcknowledgeProcessInitializationOutcome added in v0.19.0

func (p ProcessInitializationOutcomeAcknowledgerFunc) AcknowledgeProcessInitializationOutcome(
	ctx context.Context,
	outcome ProcessInitializationOutcome,
) error

type ProcessInitializationOutcomeStatus added in v0.19.0

type ProcessInitializationOutcomeStatus string
const (
	ProcessInitializationOutcomeStatusInvalid     ProcessInitializationOutcomeStatus = ""
	ProcessInitializationOutcomeStatusInitialized ProcessInitializationOutcomeStatus = "initialized"
	ProcessInitializationOutcomeStatusFailed      ProcessInitializationOutcomeStatus = "failed"
)

func (ProcessInitializationOutcomeStatus) String added in v0.19.0

func (ProcessInitializationOutcomeStatus) Valid added in v0.19.0

type ProcessInspection added in v0.16.0

type ProcessInspection struct {
	Snapshot     ProcessSnapshot
	Work         ProcessWork
	Stale        bool
	EffectID     EffectID
	RuntimeError *RuntimeError
}

ProcessInspection combines an existing execution capture with current work. A stale job is still draining but cannot publish its result. RuntimeError reports an instance failure; its unresolved Effects may exceed the Unknown settlements already present in Snapshot.

type ProcessRelation

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

ProcessRelation is the immutable location of one Process in an Engine-owned tree. Roots identify themselves as RootID at depth zero. Children have one parent and one stable ChildKey; a Process never has multiple parents.

func (ProcessRelation) ChildKey

func (p ProcessRelation) ChildKey() (ChildKey, bool)

ChildKey returns the parent-scoped logical child identity and true for a child, or zero and false for a root.

func (ProcessRelation) Depth

func (p ProcessRelation) Depth() uint32

Depth returns zero for a root and parent depth plus one for every child.

func (ProcessRelation) IsRoot

func (p ProcessRelation) IsRoot() bool

IsRoot reports whether p identifies the root of its tree.

func (ProcessRelation) ParentID

func (p ProcessRelation) ParentID() (ProcessID, bool)

ParentID returns the direct parent and true for a child, or zero and false for a root.

func (ProcessRelation) ProcessID

func (p ProcessRelation) ProcessID() ProcessID

ProcessID returns the Process located by this relation.

func (ProcessRelation) RootID

func (p ProcessRelation) RootID() ProcessID

RootID returns the stable root identity shared by the complete Process tree.

func (ProcessRelation) Valid

func (p ProcessRelation) Valid() bool

type ProcessSnapshot

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

ProcessSnapshot is an immutable diagnostic capture of one Engine-owned Process. Strategy state and Effect payloads remain opaque. A ProcessSnapshot is not a recovery unit; only a complete TreeSnapshot can be restored. An interrupted terminal Process retains its prepared batch as evidence: settled operations keep their actual results, planned operations never run, and the candidate state and input cursor were not adopted. Parsing validates the captured state, not storage acknowledgment. Engine.InspectTree identifies the acknowledged head of its durable captures.

func ParseProcessSnapshot

func ParseProcessSnapshot(data json.RawMessage) (ProcessSnapshot, error)

ParseProcessSnapshot strictly validates one Process snapshot wire value, including single-answer wait history and an open, unanswered current wait when the Process is Waiting. Prepared Effects must fit the captured Process capability grant. Terminal prepared batches contain no pending attempt and their unknown identities must exactly match the Termination.

func (ProcessSnapshot) Budget

func (p ProcessSnapshot) Budget() Budget

Budget returns the Process work allocation captured by this snapshot.

func (ProcessSnapshot) Capabilities

func (p ProcessSnapshot) Capabilities() CapabilitySet

Capabilities returns the Process authority set captured by this snapshot.

func (ProcessSnapshot) CommittedExecutionState

func (p ProcessSnapshot) CommittedExecutionState() ExecutionState

CommittedExecutionState returns the latest committed opaque Strategy state. A prepared candidate, when present, remains an uncommitted Engine detail. Only the owning Definition or its typed inspection helpers may interpret the returned state's payload.

func (ProcessSnapshot) DeploymentRef

func (p ProcessSnapshot) DeploymentRef() DeploymentRef

DeploymentRef returns the exact execution binding required for restoration.

func (ProcessSnapshot) EffectDiagnostic added in v0.22.0

func (p ProcessSnapshot) EffectDiagnostic(id EffectID) (Failure, bool)

EffectDiagnostic returns the bounded diagnostic retained for an uncertain dispatch attempt while its prepared Step remains captured, including after restoration or explicit resolution. It does not establish failure of the external operation or authorize replay.

func (ProcessSnapshot) JSON

func (p ProcessSnapshot) JSON() json.RawMessage

JSON returns an independently owned snapshot representation.

func (ProcessSnapshot) MarshalJSON

func (p ProcessSnapshot) MarshalJSON() ([]byte, error)

func (ProcessSnapshot) ProcessID

func (p ProcessSnapshot) ProcessID() ProcessID

ProcessID returns the captured Process identity.

func (ProcessSnapshot) Relation

func (p ProcessSnapshot) Relation() ProcessRelation

Relation returns the immutable parent/root/depth location captured with the Process.

func (ProcessSnapshot) SignalReceipts added in v0.17.0

func (p ProcessSnapshot) SignalReceipts() []SignalReceipt

SignalReceipts returns admitted Signal facts in mailbox arrival order. The committed cursor distinguishes consumption from admission, including inputs accepted after a final Step obtained its Signal window. These facts have the same acknowledgment boundary as this snapshot; absence in an older capture does not prove rejection. No mailbox or consumption authority is transferred.

func (ProcessSnapshot) Status

func (p ProcessSnapshot) Status() Status

Status returns the captured common lifecycle state.

func (ProcessSnapshot) UnknownEffectIDs added in v0.16.0

func (p ProcessSnapshot) UnknownEffectIDs() []EffectID

UnknownEffectIDs returns Effects whose captured settlement requires explicit resolution. RuntimeError separately owns outcomes an instance could not confirm. A terminal capture retains unresolved evidence; its Process cannot resume or accept further resolution commands.

func (*ProcessSnapshot) UnmarshalJSON

func (p *ProcessSnapshot) UnmarshalJSON(data []byte) error

func (ProcessSnapshot) Usage added in v0.16.0

func (p ProcessSnapshot) Usage() Usage

Usage returns the Framework counters recorded in this capture.

func (ProcessSnapshot) Valid

func (p ProcessSnapshot) Valid() bool

func (ProcessSnapshot) WaitID

func (p ProcessSnapshot) WaitID() (WaitID, bool)

WaitID returns the current Engine-minted wait identity and true when the captured Process is Waiting.

func (ProcessSnapshot) WaitKind added in v0.16.0

func (p ProcessSnapshot) WaitKind() (WaitKind, bool)

WaitKind distinguishes Host input from Framework child completion while the captured Process is Waiting. It derives from the existing wait authority.

type ProcessWork added in v0.16.0

type ProcessWork string

ProcessWork describes work owned by the current runtime, independently of the lifecycle state in its last acknowledged snapshot. Queued means waiting for an owner turn; a commit or freeze can still block it. Idle means no queued work or job, not a terminal Process or a successful execution.

const (
	ProcessWorkIdle       ProcessWork = "idle"
	ProcessWorkQueued     ProcessWork = "queued"
	ProcessWorkStep       ProcessWork = "step"
	ProcessWorkRestore    ProcessWork = "restore"
	ProcessWorkDispatch   ProcessWork = "dispatch"
	ProcessWorkChildStart ProcessWork = "child_start"
)

type ReplayPolicy

type ReplayPolicy string

ReplayPolicy states whether a Dispatcher can prove that repeating an Effect with the same EffectID is the same logical external operation. It does not claim transactionality or allow replay under a different identity.

const (
	// ReplayPolicyInvalid is the invalid zero value.
	ReplayPolicyInvalid ReplayPolicy = ""
	// ReplayPolicyNever forbids automatic replay of a restored pending Effect.
	ReplayPolicyNever ReplayPolicy = "never"
	// ReplayPolicySameIdentity permits replay only with the original EffectID.
	ReplayPolicySameIdentity ReplayPolicy = "same_identity"
)

func (ReplayPolicy) String

func (r ReplayPolicy) String() string

func (ReplayPolicy) Valid

func (r ReplayPolicy) Valid() bool

type Result

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

Result is the immutable terminal outcome of one Process. A failed or canceled execution is represented by Termination, not by Await's error.

func (Result) FinishedAt

func (r Result) FinishedAt() time.Time

FinishedAt returns the observed UTC time of committed termination. Wall-clock adjustments and restoration on another writer can make it earlier than StartedAt.

func (Result) Output

func (r Result) Output() (Output, bool)

Output returns the final semantic result only for StatusCompleted.

func (Result) ProcessID

func (r Result) ProcessID() ProcessID

ProcessID returns the completed Process identity.

func (Result) StartedAt

func (r Result) StartedAt() time.Time

StartedAt returns the observed UTC lifecycle start time.

func (Result) Status

func (r Result) Status() Status

Status returns the terminal lifecycle state.

func (Result) Termination

func (r Result) Termination() Termination

Termination returns the stable terminal cause and optional Failure.

func (Result) Usage

func (r Result) Usage() Usage

Usage returns the final Framework-owned resource counters.

func (Result) Valid

func (r Result) Valid() bool

type RuntimeError added in v0.16.0

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

RuntimeError reports that the active writer stopped without establishing the requested Process result or subtree completion. A result acknowledged before a descendant failed remains available through Process.Await. The Host may reconcile storage and restore its authoritative tree head in another Engine. This error does not terminate the durable execution or authorize replay of an uncertain Effect. Engine constructs these errors; the zero value carries no runtime identity. Process methods and tree reports return independent RuntimeError values; Unwrap preserves the original cause.

func (*RuntimeError) Error added in v0.16.0

func (r *RuntimeError) Error() string

func (*RuntimeError) HeadDigest added in v0.16.0

func (r *RuntimeError) HeadDigest() Digest

HeadDigest identifies the last tree head acknowledged to this instance. The store may have advanced further if a commit response was lost or a new writer acquired ownership; recovery must read the store's authoritative head.

func (*RuntimeError) IncarnationID added in v0.16.0

func (r *RuntimeError) IncarnationID() TreeIncarnationID

IncarnationID identifies the durable writer that stopped.

func (*RuntimeError) ProcessID added in v0.16.0

func (r *RuntimeError) ProcessID() ProcessID

ProcessID identifies the affected Process handle in the stopped instance.

func (*RuntimeError) UnresolvedEffectIDs added in v0.16.0

func (r *RuntimeError) UnresolvedEffectIDs() []EffectID

UnresolvedEffectIDs returns the sorted, distinct identities whose external outcomes this instance could not establish durably. Pending Effects that were never dispatched by this instance are not added solely for a failed pending-boundary acknowledgment.

func (*RuntimeError) Unwrap added in v0.16.0

func (r *RuntimeError) Unwrap() error

Unwrap preserves the durability failure, including ownership and content conflicts, for errors.Is and errors.As.

type RuntimeStoppedFact added in v0.16.0

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

RuntimeStoppedFact describes an instance failure, not a logical Process termination. It contains only the failure classification, never storage error messages or application payloads. Event carries the Process and incarnation.

func (RuntimeStoppedFact) FailureCode added in v0.16.0

func (r RuntimeStoppedFact) FailureCode() string

func (RuntimeStoppedFact) FailureKind added in v0.16.0

func (r RuntimeStoppedFact) FailureKind() FailureKind

func (RuntimeStoppedFact) Valid added in v0.16.0

func (r RuntimeStoppedFact) Valid() bool

type Schema

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

Schema is an immutable, resolved JSON Schema used by Framework input and output contracts. Its zero value is invalid.

func ParseSchema

func ParseSchema(data json.RawMessage) (Schema, error)

ParseSchema validates and resolves one JSON Schema.

func SchemaFor

func SchemaFor[T any]() (Schema, error)

SchemaFor derives and resolves a JSON Schema for T. Named types contribute package-qualified schema names, so relocating them can change Descriptor digests and exact Deployment bindings even when their JSON fields stay equal.

func (Schema) JSON

func (s Schema) JSON() json.RawMessage

JSON returns an independently owned JSON representation.

func (Schema) MarshalJSON

func (s Schema) MarshalJSON() ([]byte, error)

func (*Schema) UnmarshalJSON

func (s *Schema) UnmarshalJSON(data []byte) error

func (Schema) Valid

func (s Schema) Valid() bool

func (Schema) ValidateInput

func (s Schema) ValidateInput(input Input) error

func (Schema) ValidateOutput

func (s Schema) ValidateOutput(output Output) error

type Settlement

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

Settlement is the immutable final fact for one EffectID. Payload is owned by the Effect target and becomes opaque Signal data for the next Step. The Engine uses Status only to preserve definite versus unknown execution facts.

func NewSettlement

func NewSettlement(effectID EffectID, status SettlementStatus, payload json.RawMessage) (Settlement, error)

NewSettlement binds a result to the exact effect identity it settles, so a dispatcher cannot close an effect other than the one it was given. Ordering by completion time instead would let a slow settlement overwrite a newer one.

func (Settlement) EffectID

func (s Settlement) EffectID() EffectID

EffectID returns the Effect this result settles.

func (Settlement) MarshalJSON

func (s Settlement) MarshalJSON() ([]byte, error)

func (Settlement) Payload

func (s Settlement) Payload() json.RawMessage

Payload returns an independently owned owner-defined result.

func (Settlement) Status

func (s Settlement) Status() SettlementStatus

Status returns whether the external result is definite or unknown.

func (*Settlement) UnmarshalJSON

func (s *Settlement) UnmarshalJSON(data []byte) error

func (Settlement) Valid

func (s Settlement) Valid() bool

type SettlementStatus

type SettlementStatus string

SettlementStatus records whether an Effect definitely succeeded, definitely failed, or has an unknown external result. Unknown never implies safe retry.

const (
	// SettlementStatusInvalid is the invalid zero value.
	SettlementStatusInvalid SettlementStatus = ""
	// SettlementStatusSucceeded records a definite successful outcome.
	SettlementStatusSucceeded SettlementStatus = "succeeded"
	// SettlementStatusFailed records a definite failed outcome.
	SettlementStatusFailed SettlementStatus = "failed"
	// SettlementStatusUnknown records an externally indeterminate outcome.
	SettlementStatusUnknown SettlementStatus = "unknown"
)

func (SettlementStatus) String

func (s SettlementStatus) String() string

func (SettlementStatus) Valid

func (s SettlementStatus) Valid() bool

type Signal

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

Signal is the immutable input envelope delivered by the Engine to an Execution. Dispatcher and ordinary wait payloads belong exclusively to the Strategy; Framework composition payloads are decoded only through their public typed helpers. SignalID identifies delivery, while an optional WaitID identifies the Engine-created wait target.

func (Signal) EngineOwned added in v0.22.0

func (s Signal) EngineOwned() bool

EngineOwned reports whether the Engine produced this Signal as execution evidence. Ordinary delivery cannot use this authority. Like all restored execution facts, a decoded Signal is trustworthy only from trusted storage.

func (Signal) ID

func (s Signal) ID() SignalID

ID returns the stable delivery and deduplication identity.

func (Signal) JSONSchemaAlias added in v0.17.0

func (Signal) JSONSchemaAlias() any

func (Signal) MarshalJSON

func (s Signal) MarshalJSON() ([]byte, error)

func (Signal) Payload

func (s Signal) Payload() json.RawMessage

Payload returns an independently owned copy. Strategy-owned payloads are interpreted only by their Strategy; Framework-owned payloads should be read through the corresponding typed parser rather than decoded ad hoc.

func (*Signal) UnmarshalJSON

func (s *Signal) UnmarshalJSON(data []byte) error

func (Signal) Valid

func (s Signal) Valid() bool

func (Signal) WaitID

func (s Signal) WaitID() (WaitID, bool)

WaitID returns the addressed wait and true, or a zero WaitID and false for a Signal queued at the next Strategy-safe boundary.

type SignalAcceptedFact

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

SignalAcceptedFact is the immutable delivery identity carried by an accepted Signal Event. WaitID is present only for a wait-addressed Signal.

func (SignalAcceptedFact) SignalID

func (s SignalAcceptedFact) SignalID() SignalID

func (SignalAcceptedFact) Valid

func (s SignalAcceptedFact) Valid() bool

func (SignalAcceptedFact) WaitID

func (s SignalAcceptedFact) WaitID() (WaitID, bool)

type SignalID

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

SignalID is the stable identity used to deduplicate one Signal delivery.

func ParseSignalID

func ParseSignalID(value string) (SignalID, error)

ParseSignalID validates an externally supplied Signal delivery identity. Parsing does not accept or deliver the Signal. The signal:engine: namespace is reserved for Engine-generated delivery and cannot be used in SignalRequest.

func (SignalID) JSONSchemaAlias added in v0.17.0

func (SignalID) JSONSchemaAlias() any

func (SignalID) MarshalText

func (i SignalID) MarshalText() ([]byte, error)

func (SignalID) String

func (i SignalID) String() string

func (*SignalID) UnmarshalText

func (s *SignalID) UnmarshalText(text []byte) error

func (SignalID) Valid

func (i SignalID) Valid() bool

Valid distinguishes a parsed identity from its invalid zero value. Parsing and text decoding are the only boundaries that can install non-empty text.

type SignalReceipt added in v0.17.0

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

SignalReceipt is an immutable admission and consumption fact from a ProcessSnapshot. Consumed payload bytes are released while their normalized digest and recipient WaitID remain available for duplicate reconciliation. Its Process owner and durability boundary are supplied by that snapshot.

func (SignalReceipt) ArrivalSequence added in v0.17.0

func (s SignalReceipt) ArrivalSequence() uint64

func (SignalReceipt) Consumed added in v0.17.0

func (s SignalReceipt) Consumed() bool

Consumed reports committed consumption, not delivery to a candidate Step.

func (SignalReceipt) ID added in v0.17.0

func (s SignalReceipt) ID() SignalID

func (SignalReceipt) Matches added in v0.17.0

func (s SignalReceipt) Matches(request SignalRequest) bool

Matches reports whether this receipt proves admission of the external request. Internal wait-opening and child-wait settlement Signals cannot prove external admission. A different WaitID or normalized payload remains an identity conflict.

func (SignalReceipt) PayloadDigest added in v0.17.0

func (s SignalReceipt) PayloadDigest() Digest

func (SignalReceipt) PendingSignal added in v0.17.0

func (s SignalReceipt) PendingSignal() (Signal, bool)

PendingSignal returns the retained input only while it remains unconsumed.

func (SignalReceipt) WaitID added in v0.17.0

func (s SignalReceipt) WaitID() (WaitID, bool)

type SignalRequest

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

SignalRequest is an immutable request to deliver Strategy-owned input to a Process. ID supplies caller-stable deduplication. WaitID is zero for ordinary next-boundary input and Engine-minted for an external wait answer.

func NewSignalRequest

func NewSignalRequest(id SignalID, waitID WaitID, payload json.RawMessage) (SignalRequest, error)

NewSignalRequest rejects the reserved signal:engine: namespace and requires a caller-chosen signal identity so that resubmitting the same delivery is exactly one logical consumption. Without it, a host retry after an ambiguous network failure would be indistinguishable from a second answer.

func (SignalRequest) ID

func (s SignalRequest) ID() SignalID

ID returns the stable delivery and deduplication identity.

func (SignalRequest) JSONSchemaAlias added in v0.18.0

func (SignalRequest) JSONSchemaAlias() any

func (SignalRequest) MarshalJSON added in v0.18.0

func (s SignalRequest) MarshalJSON() ([]byte, error)

func (SignalRequest) Payload

func (s SignalRequest) Payload() json.RawMessage

Payload returns an independently owned Strategy-defined value.

func (*SignalRequest) UnmarshalJSON added in v0.18.0

func (s *SignalRequest) UnmarshalJSON(data []byte) error

func (SignalRequest) Valid

func (s SignalRequest) Valid() bool

func (SignalRequest) WaitID

func (s SignalRequest) WaitID() (WaitID, bool)

WaitID returns the addressed wait and true, or a zero WaitID and false.

type Status

type Status string

Status is the complete common lifecycle state of a Process. Strategy-specific conditions such as a Planning no-plan result do not add common statuses.

const (
	// StatusInvalid is the invalid zero value.
	StatusInvalid Status = ""
	// StatusNotStarted identifies a Process before execution begins.
	StatusNotStarted Status = "not_started"
	// StatusRunning identifies a Process eligible to advance.
	StatusRunning Status = "running"
	// StatusWaiting identifies a Process awaiting a WaitID-addressed Signal.
	StatusWaiting Status = "waiting"
	// StatusPaused identifies an explicitly suspended Process.
	StatusPaused Status = "paused"
	// StatusCompleted identifies successful semantic completion.
	StatusCompleted Status = "completed"
	// StatusFailed identifies terminal execution failure.
	StatusFailed Status = "failed"
	// StatusCanceled identifies cooperative cancellation.
	StatusCanceled Status = "canceled"
	// StatusTimedOut identifies deadline termination.
	StatusTimedOut Status = "timed_out"
	// StatusKilled identifies an explicit Engine kill.
	StatusKilled Status = "killed"
)

func (Status) MarshalText

func (s Status) MarshalText() ([]byte, error)

func (Status) String

func (s Status) String() string

func (Status) Terminal

func (s Status) Terminal() bool

Terminal reports whether the Process may never transition again.

func (*Status) UnmarshalText

func (s *Status) UnmarshalText(text []byte) error

func (Status) Valid

func (s Status) Valid() bool

type StepCommittedFact

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

StepCommittedFact is the Process status installed by one committed Step.

func (StepCommittedFact) Status

func (s StepCommittedFact) Status() Status

func (StepCommittedFact) Valid

func (s StepCommittedFact) Valid() bool

type StepFinishedFact

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

StepFinishedFact closes one physical attempt, including discarded candidates. WorkDuration covers Step, Snapshot, and Restore in the worker. AdoptionDelay covers completion delivery and waiting for the tree owner, including barriers. Both use monotonic elapsed time, independent of lifecycle wall-clock stamps. Attempts with the same logical StepSequence are paired in activation-local event order; the previous attempt finishes before another starts.

func (StepFinishedFact) AdoptionDelay added in v0.21.0

func (s StepFinishedFact) AdoptionDelay() time.Duration

func (StepFinishedFact) Status

func (s StepFinishedFact) Status() StepStatus

func (StepFinishedFact) Valid

func (s StepFinishedFact) Valid() bool

func (StepFinishedFact) WorkDuration added in v0.21.0

func (s StepFinishedFact) WorkDuration() time.Duration

type StepStatus

type StepStatus string

StepStatus reports whether one Step reduction succeeded, and is deliberately narrower than Status: a failed Step does not by itself terminate a Process, because the terminal decision also depends on recorded control intent.

const (
	StepStatusSucceeded StepStatus = "succeeded"
	StepStatusFailed    StepStatus = "failed"
	StepStatusDiscarded StepStatus = "discarded"
)

Step status is separate from Process status because a failed Step does not by itself terminate a Process; the terminal decision also weighs recorded control intent.

func (StepStatus) String

func (s StepStatus) String() string

func (StepStatus) Valid

func (s StepStatus) Valid() bool

type Termination

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

Termination is the immutable result of applying the terminal priority matrix.

func (Termination) Cause

func (t Termination) Cause() TerminationCause

Cause returns the stable machine-readable terminal category.

func (Termination) Failure

func (t Termination) Failure() (Failure, bool)

Failure returns the classified failure for StatusFailed.

func (Termination) JSONSchemaAlias added in v0.17.0

func (Termination) JSONSchemaAlias() any

func (Termination) MarshalJSON

func (t Termination) MarshalJSON() ([]byte, error)

func (Termination) Reason

func (t Termination) Reason() string

Reason returns a bounded diagnostic reason. Completion has an empty reason.

func (Termination) Status

func (t Termination) Status() Status

Status returns the resolved terminal Process status.

func (*Termination) UnmarshalJSON

func (t *Termination) UnmarshalJSON(data []byte) error

func (Termination) UnresolvedEffectIDs

func (t Termination) UnresolvedEffectIDs() []EffectID

UnresolvedEffectIDs returns the canonical identities of external operations that may have occurred but were not durably resolved when the tree stopped.

func (Termination) Valid

func (t Termination) Valid() bool

type TerminationCause

type TerminationCause string

TerminationCause is the stable reason category of a terminal Process.

const (
	// TerminationCauseInvalid is the invalid zero value.
	TerminationCauseInvalid TerminationCause = ""
	// TerminationCauseCompletion identifies successful semantic completion.
	TerminationCauseCompletion TerminationCause = "completion"
	// TerminationCauseEngineKill identifies an explicit Engine kill.
	TerminationCauseEngineKill TerminationCause = "engine_kill"
	// TerminationCauseProcessDeadline identifies the Process's own deadline.
	TerminationCauseProcessDeadline TerminationCause = "process_deadline"
	// TerminationCauseParentDeadline identifies deadline propagation from a parent.
	TerminationCauseParentDeadline TerminationCause = "parent_deadline"
	// TerminationCauseHostDeadline identifies expiry of the Host context.
	TerminationCauseHostDeadline TerminationCause = "host_deadline"
	// TerminationCauseParentCancellation identifies cancellation by a parent Process.
	TerminationCauseParentCancellation TerminationCause = "parent_cancellation"
	// TerminationCauseHostCancellation identifies cancellation by the Host context.
	TerminationCauseHostCancellation TerminationCause = "host_cancellation"
	// TerminationCauseExecutionFailure identifies an ordinary Strategy failure.
	TerminationCauseExecutionFailure TerminationCause = "execution_failure"
	// TerminationCauseContractFailure identifies a contract violation.
	TerminationCauseContractFailure TerminationCause = "contract_failure"
	// TerminationCauseExternalFailure identifies failed external infrastructure.
	TerminationCauseExternalFailure TerminationCause = "external_failure"
	// TerminationCausePanic identifies a recovered execution-boundary panic.
	TerminationCausePanic TerminationCause = "panic"
)

func (TerminationCause) String

func (t TerminationCause) String() string

func (TerminationCause) Valid

func (t TerminationCause) Valid() bool

type Transition

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

Transition is an immutable candidate lifecycle intent. The Engine validates ConsumedSignals against the delivered Signal window, captures the candidate ExecutionState, and assigns EffectID values before committing anything.

func Complete

func Complete(consumedSignals uint32, output Output) (Transition, error)

Complete supplies the final semantic Output. The Engine must validate it against the Definition Descriptor before committing Completed.

func Continue

func Continue(consumedSignals uint32, effects ...Effect) (Transition, error)

Continue keeps the Process schedulable after consuming the stated Signal prefix. Effects are dispatched only after the Engine prepares the Step.

func Fail

func Fail(consumedSignals uint32, failure Failure) (Transition, error)

Fail supplies a stable Strategy-declared failure without making the Execution instance untrusted. A Step error follows the separate discard path.

func Pause

func Pause(consumedSignals uint32, reason string) (Transition, error)

Pause requests an explicit scheduling pause with a bounded diagnostic reason.

func Wait

func Wait(consumedSignals uint32, waitID WaitID) (Transition, error)

Wait moves the Process to Waiting for an Engine-minted WaitID already stored in the candidate ExecutionState.

func (Transition) ConsumedSignals

func (t Transition) ConsumedSignals() uint32

ConsumedSignals returns the length of the delivered Signal prefix to commit.

func (Transition) Effects

func (t Transition) Effects() []Effect

Effects returns independently owned operation intents in declaration order.

func (Transition) Failure

func (t Transition) Failure() (Failure, bool)

Failure returns the terminal failure for a Fail transition.

func (Transition) Kind

func (t Transition) Kind() TransitionKind

Kind returns the requested lifecycle intent.

func (Transition) MarshalJSON

func (t Transition) MarshalJSON() ([]byte, error)

func (Transition) Output

func (t Transition) Output() (Output, bool)

Output returns the final result for a Complete transition.

func (Transition) Reason

func (t Transition) Reason() (string, bool)

Reason returns the pause reason for a Pause transition.

func (*Transition) UnmarshalJSON

func (t *Transition) UnmarshalJSON(data []byte) error

func (Transition) Valid

func (t Transition) Valid() bool

func (Transition) WaitID

func (t Transition) WaitID() (WaitID, bool)

WaitID returns the wait target for a Wait transition.

type TransitionKind

type TransitionKind string

TransitionKind is the lifecycle intent produced by one bounded Step.

const (
	// TransitionKindInvalid is the invalid zero value.
	TransitionKindInvalid TransitionKind = ""
	// TransitionKindContinue advances to another runnable Step.
	TransitionKindContinue TransitionKind = "continue"
	// TransitionKindWait enters an Engine-minted wait.
	TransitionKindWait TransitionKind = "wait"
	// TransitionKindPause enters an explicit scheduling pause.
	TransitionKindPause TransitionKind = "pause"
	// TransitionKindComplete commits a validated semantic Output.
	TransitionKindComplete TransitionKind = "complete"
	// TransitionKindFail commits a classified failure.
	TransitionKindFail TransitionKind = "fail"
)

func (TransitionKind) String

func (t TransitionKind) String() string

func (TransitionKind) Valid

func (t TransitionKind) Valid() bool

type TreeActivation

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

TreeActivation changes writer identity and recovery state together so the previous Engine cannot continue committing after restoration takes ownership.

func (TreeActivation) IncarnationID

func (t TreeActivation) IncarnationID() TreeIncarnationID

func (TreeActivation) PreviousIncarnationID

func (t TreeActivation) PreviousIncarnationID() TreeIncarnationID

func (TreeActivation) PreviousTreeDigest

func (t TreeActivation) PreviousTreeDigest() Digest

func (TreeActivation) TreeSnapshot

func (t TreeActivation) TreeSnapshot() TreeSnapshot

func (TreeActivation) Valid

func (t TreeActivation) Valid() bool

type TreeCheckpoint

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

TreeCheckpoint keeps child publication, input acceptance, and execution progress on the same head so recovery cannot observe partially accepted work. Input, child, and progress cuts can coexist with sibling jobs because those jobs expose only committed Execution state or already recorded Effect intent.

func (TreeCheckpoint) Kind

func (TreeCheckpoint) PreviousTreeDigest

func (t TreeCheckpoint) PreviousTreeDigest() Digest

func (TreeCheckpoint) TreeSnapshot

func (t TreeCheckpoint) TreeSnapshot() TreeSnapshot

func (TreeCheckpoint) Valid

func (t TreeCheckpoint) Valid() bool

type TreeCheckpointKind

type TreeCheckpointKind string

TreeCheckpointKind distinguishes absent-head creation from writer-fenced updates, and stable owner cuts from fully parked or terminal trees.

const (
	TreeCheckpointInvalid  TreeCheckpointKind = ""
	TreeCheckpointStart    TreeCheckpointKind = "start"
	TreeCheckpointChild    TreeCheckpointKind = "child"
	TreeCheckpointInput    TreeCheckpointKind = "input"
	TreeCheckpointProgress TreeCheckpointKind = "progress"
	TreeCheckpointParked   TreeCheckpointKind = "parked"
	TreeCheckpointTerminal TreeCheckpointKind = "terminal"
)

func (TreeCheckpointKind) String

func (t TreeCheckpointKind) String() string

func (TreeCheckpointKind) Valid

func (t TreeCheckpointKind) Valid() bool

type TreeDurability

type TreeDurability interface {
	// ActivateTree must fence the previous writer before restored work can run.
	ActivateTree(ctx context.Context, activation TreeActivation) error
	// CommitEffect must keep the Effect fact and tree head atomic so recovery
	// cannot disagree with the dispatch or settlement that was acknowledged.
	CommitEffect(ctx context.Context, boundary EffectBoundary) error
	// CommitCheckpoint must compare an absent head for start, or the current
	// head otherwise, to prevent publication from overwriting another writer.
	CommitCheckpoint(ctx context.Context, checkpoint TreeCheckpoint) error
}

TreeDurability keeps all recoverable state on one authoritative head so a restored writer cannot race its predecessor. Every commit must atomically compare and advance that head; accepting a duplicate requires identical content and a head that still matches the proposal. Hosts own storage, deadlines, and reconciliation when a commit response is lost. The supplied context retains Host values but removes cancellation and deadlines. Hosts must apply an independent bounded storage deadline; a timeout does not prove that the authoritative head was unchanged and requires reconciliation.

A start checkpoint requires an absent head and a zero PreviousTreeDigest. Other checkpoints and Effects require the current incarnation and digest. Activation must replace both together to fence the previous writer before restoration can publish a Process. Initialization acknowledgment is separate because failed root initialization has no execution tree to persist.

type TreeFreezePhase added in v0.16.0

type TreeFreezePhase string

TreeFreezePhase describes the current scheduling barrier. Acquiring blocks scheduling while in-flight Effects settle. Held also stops completion adoption; an in-flight Step may still be computing against its isolated state.

const (
	TreeFreezeNone      TreeFreezePhase = "none"
	TreeFreezeAcquiring TreeFreezePhase = "acquiring"
	TreeFreezeHeld      TreeFreezePhase = "held"
)

type TreeIncarnationID

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

TreeIncarnationID identifies the one active writer generation of a durable Process tree. Its zero value is invalid.

func ParseTreeIncarnationID

func ParseTreeIncarnationID(value string) (TreeIncarnationID, error)

ParseTreeIncarnationID validates the canonical wire representation of a tree incarnation identity.

func (TreeIncarnationID) MarshalText

func (t TreeIncarnationID) MarshalText() ([]byte, error)

func (TreeIncarnationID) String

func (t TreeIncarnationID) String() string

func (*TreeIncarnationID) UnmarshalText

func (t *TreeIncarnationID) UnmarshalText(text []byte) error

func (TreeIncarnationID) Valid

func (t TreeIncarnationID) Valid() bool

type TreeInspection added in v0.16.0

type TreeInspection struct {
	RootID        ProcessID
	IncarnationID TreeIncarnationID
	HeadDigest    Digest
	CommitPending bool
	Freeze        TreeFreezePhase
	Stopped       bool
	Processes     []ProcessInspection
}

TreeInspection is a caller-owned report from one runtime owner turn. In durable mode, snapshots and HeadDigest come only from the last head this instance acknowledged. A lost response or a replacement writer may have advanced storage further. Recovery must load the authoritative stored tree. IncarnationID and HeadDigest are zero in ephemeral mode. Work and barriers describe the sampling turn and may be newer than the acknowledged snapshots. Stopped means the owner has exited after draining its work. Reports contain no recovery or scheduling authority and are not a persistence schema.

func (TreeInspection) Process added in v0.16.0

func (t TreeInspection) Process(processID ProcessID) (ProcessInspection, bool)

Process finds a published Process in the report's canonical depth/ID order.

type TreeLimits

type TreeLimits struct {
	// MaxDepth bounds the root-relative depth of any Process.
	MaxDepth uint32 `json:"max_depth"`
	// MaxChildren bounds the lifetime child count of one Process.
	MaxChildren uint32 `json:"max_children"`
	// MaxActiveChildren bounds concurrent non-terminal children of one Process.
	MaxActiveChildren uint32 `json:"max_active_children"`
	// MaxTreeProcesses bounds the lifetime Process count of one tree.
	MaxTreeProcesses uint32 `json:"max_tree_processes"`
}

TreeLimits bounds structural expansion independently of per-Process work limits. Every zero field in EngineConfig inherits DefaultTreeLimits.

func DefaultTreeLimits

func DefaultTreeLimits() TreeLimits

DefaultTreeLimits returns conservative structured-concurrency bounds.

func (TreeLimits) Valid

func (t TreeLimits) Valid() bool

type TreeSnapshot

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

TreeSnapshot is an immutable, portable capture of one complete Process tree. It owns Framework execution facts, a canonical content digest, and the optional active-writer identity of durable state. Persistence, transactions, revisions, and cleanup policy remain Host responsibilities.

func ParseTreeSnapshot

func ParseTreeSnapshot(data json.RawMessage) (TreeSnapshot, error)

ParseTreeSnapshot validates the current wire shape and domain constraints of one complete Process tree. Unknown members are rejected. Every active child wait must have a registration belonging to its Process and matching its opening Signal. Pending satisfaction Signals must agree with that boundary and the terminal results in the captured tree. A retained successful child-start settlement must identify a captured child matching the complete start request.

func (TreeSnapshot) Digest

func (t TreeSnapshot) Digest() Digest

Digest returns the canonical content identity of this complete tree state.

func (TreeSnapshot) IncarnationID

func (t TreeSnapshot) IncarnationID() (TreeIncarnationID, bool)

IncarnationID returns the active writer identity carried by a durable tree. Ephemeral snapshots return false.

func (TreeSnapshot) JSON

func (t TreeSnapshot) JSON() json.RawMessage

JSON returns an independently owned tree snapshot representation.

func (TreeSnapshot) MarshalJSON

func (t TreeSnapshot) MarshalJSON() ([]byte, error)

func (TreeSnapshot) ProcessSnapshots

func (t TreeSnapshot) ProcessSnapshots() []ProcessSnapshot

ProcessSnapshots returns immutable captures ordered by depth and ProcessID.

func (TreeSnapshot) RootID

func (t TreeSnapshot) RootID() ProcessID

RootID returns the identity of the tree's root Process.

func (*TreeSnapshot) UnmarshalJSON

func (t *TreeSnapshot) UnmarshalJSON(data []byte) error

func (TreeSnapshot) Valid

func (t TreeSnapshot) Valid() bool

type UnresolvedEffect added in v0.22.0

type UnresolvedEffect struct {
	ProcessID ProcessID `json:"process_id"`
	EffectID  EffectID  `json:"effect_id"`
}

UnresolvedEffect identifies an unsettled external effect at a drained subtree boundary. It is an observation; only the owning Process can settle the Effect.

func (UnresolvedEffect) Valid added in v0.22.0

func (u UnresolvedEffect) Valid() bool

type Usage

type Usage struct {
	// CommittedSteps counts finalized Steps.
	CommittedSteps uint64 `json:"committed_steps"`

	// PreparedEffects counts stable logical Effect identities, not replay attempts.
	PreparedEffects uint64 `json:"prepared_effects"`

	// AcceptedSignals counts external and Engine-generated mailbox entries.
	AcceptedSignals uint64 `json:"accepted_signals"`

	// DroppedDeltas counts increments rejected by validation or the bounded queue.
	DroppedDeltas uint64 `json:"dropped_deltas"`
}

Usage contains monotonic Framework-owned counters. It deliberately excludes provider pricing and Strategy-specific concepts such as tokens or tool calls.

type WaitID

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

WaitID identifies one Engine-created wait target owned by a Process. Parsing a WaitID does not create a wait; the Engine rejects identities it did not mint.

func ParseWaitID

func ParseWaitID(value string) (WaitID, error)

ParseWaitID validates the wire representation of a Wait identity.

func (WaitID) JSONSchemaAlias added in v0.17.0

func (WaitID) JSONSchemaAlias() any

func (WaitID) MarshalText

func (i WaitID) MarshalText() ([]byte, error)

func (WaitID) String

func (i WaitID) String() string

func (*WaitID) UnmarshalText

func (w *WaitID) UnmarshalText(text []byte) error

func (WaitID) Valid

func (i WaitID) Valid() bool

Valid distinguishes a parsed identity from its invalid zero value. Parsing and text decoding are the only boundaries that can install non-empty text.

type WaitKey

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

WaitKey is an Execution-owned logical key used to associate a requested wait with the WaitID later minted by the Engine.

func ParseWaitKey

func ParseWaitKey(value string) (WaitKey, error)

ParseWaitKey validates an Execution-owned logical wait key.

func (WaitKey) JSONSchemaAlias added in v0.17.0

func (WaitKey) JSONSchemaAlias() any

func (WaitKey) MarshalText

func (i WaitKey) MarshalText() ([]byte, error)

func (WaitKey) String

func (i WaitKey) String() string

func (*WaitKey) UnmarshalText

func (w *WaitKey) UnmarshalText(text []byte) error

func (WaitKey) Valid

func (i WaitKey) Valid() bool

Valid distinguishes a parsed identity from its invalid zero value. Parsing and text decoding are the only boundaries that can install non-empty text.

type WaitKind added in v0.16.0

type WaitKind string

WaitKind identifies who may answer the current wait.

const (
	WaitKindExternal WaitKind = "external"
	WaitKindChildren WaitKind = "children"
)

Directories

Path Synopsis
Package agenttest provides deterministic consumer-side fixtures and reusable conformance suites for the Agent Framework's public execution boundaries.
Package agenttest provides deterministic consumer-side fixtures and reusable conformance suites for the Agent Framework's public execution boundaries.
examples
autonomous command
Command autonomous demonstrates an Interaction in which the model chooses a Tool from environment feedback and decides when to stop.
Command autonomous demonstrates an Interaction in which the model chooses a Tool from environment feedback and decides when to stop.
composition command
Command composition demonstrates that direct Engine embedding and a cross-Strategy composed Agent use the same Definition/Execution/Process contracts.
Command composition demonstrates that direct Engine embedding and a cross-Strategy composed Agent use the same Definition/Execution/Process contracts.
direct_vs_managed command
Command direct_vs_managed contrasts a direct model call with the same model capability managed as a recoverable agent Process.
Command direct_vs_managed contrasts a direct model call with the same model capability managed as a recoverable agent Process.
evaluator_optimizer command
Command evaluator_optimizer demonstrates bounded evaluator-optimizer composition with exact managed child Processes.
Command evaluator_optimizer demonstrates bounded evaluator-optimizer composition with exact managed child Processes.
orchestrator_workers command
Command orchestrator_workers demonstrates model-directed task decomposition, deterministic managed worker fan-out, and model synthesis without a collaboration Strategy.
Command orchestrator_workers demonstrates model-directed task decomposition, deterministic managed worker fan-out, and model synthesis without a collaboration Strategy.
workflow command
Command workflow demonstrates an ordered managed Workflow whose Call and Fork Stages create independently recoverable child Processes.
Command workflow demonstrates an ordered managed Workflow whose Call and Fork Stages create independently recoverable child Processes.
workflow_patterns command
Command workflow_patterns demonstrates prompt chaining, routing, parallel sectioning, and parallel voting through one managed Workflow.
Command workflow_patterns demonstrates prompt chaining, routing, parallel sectioning, and parallel voting through one managed Workflow.
internal
conformancetest
Package conformancetest captures real Engine boundaries for built-in Strategy tests.
Package conformancetest captures real Engine boundaries for built-in Strategy tests.
Package messaging delivers intermediate input through ordinary Dispatcher Effects.
Package messaging delivers intermediate input through ordinary Dispatcher Effects.
strategy
collaboration
Package collaboration provides bounded, decision-driven multi-agent work.
Package collaboration provides bounded, decision-driven multi-agent work.
coordination
Package coordination provides bounded coordination through ordinary Agent Definitions.
Package coordination provides bounded coordination through ordinary Agent Definitions.
interaction
Package interaction provides the model-directed execution Strategy for the Agent Framework.
Package interaction provides the model-directed execution Strategy for the Agent Framework.
internal/childcall
Package childcall owns Framework child response correlation and recoverable single-child handshake progress.
Package childcall owns Framework child response correlation and recoverable single-child handshake progress.
planning
Package planning provides goal-directed state planning as an Agent execution strategy.
Package planning provides goal-directed state planning as an Agent execution strategy.
planning/goap
Package goap provides deterministic goal-oriented action planning over immutable planning.WorldState values.
Package goap provides deterministic goal-oriented action planning over immutable planning.WorldState values.
workflow
Package workflow provides deterministic orchestration of Framework-managed child Processes.
Package workflow provides deterministic orchestration of Framework-managed child Processes.

Jump to

Keyboard shortcuts

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