Documentation
¶
Overview ¶
Package api defines the agentsessions contracts: the Sessions control-plane API, the Harness BYOH SPI, and the Runtime compute SPI.
The .proto files in this directory are the wire format; these Go types are the hand-written SPI used by hosts and backends (to be reconciled with generated code).
Design rule: the core is vendor-neutral. Producers (GitHub, Foundry, custom apps) plug in on top as adapters; compute backends (pod, Kata, Cloud Hypervisor, substrate) plug in underneath via Runtime. No producer- or backend-specific fields in the core — specifics ride in Origin, annotations, and ComputeRef.Attributes.
Index ¶
- Variables
- func IsParkUnwind(err error, ref ApprovalRef) bool
- type Action
- type ApprovalDecision
- type ApprovalParkedError
- type ApprovalRef
- type ApprovalRequest
- type ApprovalResult
- type AuthorizationRequest
- type Authorizer
- type CallerIdentity
- type Capabilities
- type ComputeRef
- type ComputeState
- type DeletionState
- type Delta
- type Descriptor
- type Error
- type Event
- type EventKind
- type EventSink
- type ExecState
- type ExecutionStart
- type FilePart
- type ForkOpts
- type Harness
- type HarnessEnd
- type IdentityContext
- type IdentityRef
- type Incarnation
- type InstanceRestorer
- type Lifecycle
- type LifecycleKind
- type Mediation
- type Message
- type ModelCall
- type ModelPolicy
- type ModelRequest
- type ModelResponse
- type Origin
- type OwnerAllowlistAuthorizer
- type OwnerAuthorizer
- type Part
- type ReasoningPart
- type Resumability
- type Runtime
- type RuntimeCapabilities
- type Session
- type SessionSpec
- type SnapshotKind
- type SnapshotRef
- type Start
- type TextPart
- type TokenMinter
- type ToolCall
- type ToolChoice
- type ToolChoiceMode
- type ToolDefinition
- type ToolResult
- type ToolResultCode
- type ToolSpec
- type Usage
Constants ¶
This section is empty.
Variables ¶
var ErrApprovalParked = errors.New("approval parked")
ErrApprovalParked distinguishes a host-requested approval park from execution failure. A transport uses ApprovalParkedError.Ref, never error-string matching, for the park exchange.
var ErrCheckpointPending = errors.New("runtime: checkpoint upload is pending")
ErrCheckpointPending reports that a checkpoint's durable copy is still uploading. No usable checkpoint is returned and nothing is journaled; the upload may complete without operator intervention. The session service reports it as UNAVAILABLE, unlike an invalid checkpoint.
var ErrComputeBusy = errors.New("runtime: compute is busy with another operation")
ErrComputeBusy reports that the session's compute is in the middle of another operation (another host resuming or suspending it, say), so the backend could not place onto it or act on it right now. Nothing was journaled, and the state settles on its own, so the session service reports it as ABORTED and the caller retries. A stateful Fork also returns it when another caller replaced or captured the child compute it just created before it could resume it: no child is created, and the parent keeps the SUSPEND the fork took and its snapshot, so a retried Fork clones a new child.
var ErrInvalidCallerIdentity = errors.New("api: caller identity requires issuer and subject")
ErrInvalidCallerIdentity reports an incomplete owner passed to owned creation or an empty/incomplete owner filter passed to a session listing.
var ErrInvalidCheckpoint = errors.New("runtime: checkpoint does not meet the required contract")
ErrInvalidCheckpoint reports that a runtime cannot produce or resume a checkpoint with the required durable handle and fidelity. Capture may already have suspended compute; no usable ref is returned, and callers must inspect/correct the runtime evidence before retrying. The session service reports it as FAILED_PRECONDITION, not an internal transport failure.
var ErrInvalidModelPolicy = errors.New("model policy requires an explicit allowed default and nonempty model IDs")
ErrInvalidModelPolicy rejects host policy without an explicit, allowed default or with empty IDs.
var ErrMemoryStateLost = errors.New("runtime: session's in-memory harness state is lost")
ErrMemoryStateLost reports that a backend cannot give a session whose harness keeps its state only in RAM (REQUIRES_MEMORY_SNAPSHOT) the compute that held that state, because the compute is gone or came back without that state. Create returns it rather than create fresh compute when the journal already records a started turn on that harness (SessionSpec.StartedTurns). Restore returns it for any such session whose compute no longer exists, whatever the journal records, since the snapshot it would restore went with the compute; the recorded compute, still there after a failed restore, keeps the restore error whatever snapshot it holds (see InstanceRestorer). A backend also returns it from Create, Restore, Fork and Snapshot when the compute is there but did not get back the memory its snapshot held (substrate resuming it on a worker that restored only its files). The host returns it when the compute a turn or a Resume was placed on reports another Incarnation.ComputeInstance than the journal recorded: the compute was replaced under the same name. Snapshot returns it when the compute behind Incarnation.ID is not the instance the caller required (a stateful fork). A backend whose compute can hold a snapshot the journal never recorded returns it from Create, Restore and Snapshot when the compute holds one other than the checkpoint the journal last recorded (SessionSpec.RecordedCheckpoint, Incarnation.RecordedCheckpoint, Restore's ref), before it resumes the compute or, from Create and Restore, after, on what the resume reports. The journal cannot rebuild the state (I4), so fresh compute would continue the journal with a harness that has forgotten it. Retrying does not fix it, except when the missing record is still being written or was written after the caller read it: another host's Snapshot between its capture and its SUSPEND append is refused until that append lands, and Restore's check after the resume refuses a SUSPEND another host recorded after Restore's ref was read, which a retry reads. The session service reports it as FAILED_PRECONDITION.
var ErrModelNotAllowed = errors.New("model is not allowed by the host policy")
ErrModelNotAllowed rejects a session default, declared model, or mediated request outside the host's allowed set. A mediated rejection is execution-fatal even if the harness handles it.
var ErrPermissionDenied = errors.New("api: permission denied")
ErrPermissionDenied is returned by OwnerAuthorizer when the caller does not own the session, either identity is incomplete, the session UID is missing, or the action is not an ordinary owner action (including create, approve and mint).
var ErrSnapshotSuperseded = errors.New("runtime: fork source snapshot was superseded")
ErrSnapshotSuperseded reports that a fork's source snapshot is no longer the one the parent holds, because the parent was resumed (and possibly checkpointed again) after the snapshot was taken. The fork cannot clone it without pairing the children's journal prefix with different RAM; the caller can retry the fork at the parent's new head.
Functions ¶
func IsParkUnwind ¶
func IsParkUnwind(err error, ref ApprovalRef) bool
IsParkUnwind reports whether err contains only wrapped or joined parks for ref, with no independent failure elsewhere in the error tree. A matching park alone does not prove that the host has checkpointed compute or durably recorded a successful pause.
Types ¶
type Action ¶ added in v0.3.0
type Action string
Action identifies a permission independently of the RPC or transport.
const ( ActionRead Action = "read" ActionExec Action = "exec" ActionFork Action = "fork" ActionSuspend Action = "suspend" ActionResume Action = "resume" ActionDelete Action = "delete" ActionCancel Action = "cancel" ActionCreate Action = "create" ActionApprove Action = "approve" ActionMint Action = "mint" ActionList Action = "list" ActionRegistryRead Action = "registry.read" ActionRegistryList Action = "registry.list" ActionRegistryRegister Action = "registry.register" ActionRegistryRetire Action = "registry.retire" )
type ApprovalDecision ¶
type ApprovalDecision struct {
ExecutionID string
ToolCallID string
RequestSeq int64
Approved bool
Reason string
Identity IdentityRef
}
ApprovalDecision is a caller's decision for one request. Identity records provenance only; it is not an authorization credential. The wire request uses explicit Approved presence so an omitted decision can be rejected; this domain value represents a supplied decision.
type ApprovalParkedError ¶
type ApprovalParkedError struct {
Ref ApprovalRef
}
ApprovalParkedError carries the request correlation for a parked Run. It does not commit a request or decision; durable approval state belongs to the host's journal.
func (*ApprovalParkedError) Error ¶
func (e *ApprovalParkedError) Error() string
func (*ApprovalParkedError) Unwrap ¶
func (e *ApprovalParkedError) Unwrap() error
type ApprovalRef ¶
ApprovalRef identifies one host-owned approval request within the enclosing session. RequestSeq is the positive journal sequence, not a harness-chosen correlation number.
type ApprovalRequest ¶
ApprovalRequest asks a human or policy engine to allow a tool call.
type ApprovalResult ¶
type ApprovalResult struct {
ToolCallID string
Approved bool
Reason string
RequestSeq int64 `json:",omitempty"` // sequence of the host-owned APPROVAL_REQUEST; zero for legacy decisions
}
ApprovalResult answers an ApprovalRequest (sent by the host).
type AuthorizationRequest ¶ added in v0.3.0
type AuthorizationRequest struct {
Caller CallerIdentity
Action Action
SessionUID string
Owner CallerIdentity
// Method is the full originating RPC name, for example
// "/agentsessions.v1.Sessions/Exec" (Sessions_Exec_FullMethodName in genpb).
// All checks for that RPC retain this value, including compound permissions,
// auto-creation and recovery. Direct Go handler calls populate it too.
// OwnerAuthorizer and OwnerAllowlistAuthorizer decide by Action, not Method.
Method string
}
AuthorizationRequest carries the verified caller and trusted stored owner of one session. Owner is empty for legacy unbound sessions and global actions; policies may authorize legacy history, but OwnerAuthorizer denies an empty owner. It is not a request-supplied ownership assignment. Stateful Fork requires a separate suspend check; Resume that drives effects also requires exec.
type Authorizer ¶ added in v0.3.0
type Authorizer interface {
Authorize(context.Context, AuthorizationRequest) error
}
Authorizer decides one resource permission. A denial must precede disclosure or effects. Listing needs an authorized storage query, not post-filtered pages. Sessions and HarnessRegistry invoke it when their authorization option is set. Return ErrPermissionDenied (possibly wrapped) for denial; other errors are host failures, not policy denials. The policy owns logging and metrics for its own failures: services sanitize them without logging the original policy error.
type CallerIdentity ¶ added in v0.3.0
CallerIdentity is the exact issuer/subject pair of a caller verified by a trusted host. It is not IdentityRef (agent provenance), and constructing it performs no cryptographic verification. Do not populate it from caller-supplied metadata.
func (CallerIdentity) Valid ¶ added in v0.3.0
func (c CallerIdentity) Valid() bool
Valid reports whether both parts of the authority key are present. No trimming, case folding or issuer-prefix mapping is performed.
type Capabilities ¶
type Capabilities struct {
Resumability Resumability
ForkSafe bool // no un-replayable side effects mid-turn -> fork via replay is safe
RequiresGPU bool
Streaming bool
// ReasoningReplay: the harness persists and replays opaque provider reasoning parts
// verbatim via the provider's stateless path (not previous_response_id / server lineage).
// This keeps a reasoning harness on STATELESS_REPLAY — it adds NO snapshot edge. Verified
// across Anthropic/OpenAI/Gemini in the Track A reasoning-continuity spike.
ReasoningReplay bool
}
Capabilities is what a harness needs from the runtime and how it may be moved.
type ComputeRef ¶
type ComputeRef struct {
Runtime string
Worker string // pod/worker id when live/warm; empty when cold
Snapshot *SnapshotRef
Capabilities RuntimeCapabilities
Attributes map[string]string // backend-specific, e.g. substrate actor/atespace
}
ComputeRef describes the session's current incarnation.
type ComputeState ¶
type ComputeState string
ComputeState is the incarnation (compute/sandbox) axis of a session's lifecycle.
const ( ComputeNone ComputeState = "NONE" // no incarnation ComputeLive ComputeState = "LIVE" // running ComputeWarm ComputeState = "WARM" // paused: resident, worker held ComputeCold ComputeState = "COLD" // suspended: snapshot in storage, worker freed ComputeTerminated ComputeState = "TERMINATED" )
type DeletionState ¶
type DeletionState string
DeletionState is the permanent-deletion axis, independent of execution and compute. Pending acknowledges durable intent only; retained resources have not been reclaimed. Any other value is unrecognized and fails closed: it is treated as deleted, never as ACTIVE.
const ( DeletionActive DeletionState = "ACTIVE" DeletionPending DeletionState = "PENDING" )
type Delta ¶
Delta is an ephemeral streaming chunk. It is transport only: never appended to the log, never hash-chained, and never produced on replay. Chunks coalesce into the finalized EVENT_OUTPUT the log does record, so the journal is identical whether or not anyone was watching the turn.
type Descriptor ¶
type Descriptor struct {
ID string
Version string // stable author-owned replay version; empty is supported as unknown
Models []string // supported/required IDs; a subset of explicit host policy, never its default
Tools []ToolSpec
Capabilities Capabilities
}
Descriptor is a harness's static contract.
type Event ¶
type Event struct {
// ExecutionID, timestamp, and content live on the Event; ordering (seq) and integrity
// (prev_hash / content_hash) are host-assigned and live on the log-record envelope
// (eventlog.Record / proto LogRecord), not on the harness-emitted Event.
ExecutionID string
Timestamp time.Time
SchemaVersion int32 // versions the event body; replay survives schema skew
Kind EventKind
// typed body (exactly one set)
Message *Message
ModelCall *ModelCall
ToolCall *ToolCall
Result *ToolResult
Approval *ApprovalRequest
ApprovalResult *ApprovalResult
Usage *Usage
Lifecycle *Lifecycle
End *HarnessEnd
Err *Error
ExecutionStart *ExecutionStart
Parked *ApprovalRef `json:",omitempty"` // transport only, excluded from durable history
Actor IdentityRef // emitter principal -> provenance on every action
}
Event is the shared unit of the session log and the harness stream. The host assigns the authoritative Seq on append. Ordering + integrity + identity live on the envelope; typed content lives in the body.
type EventKind ¶
type EventKind string
EventKind classifies an Event. Typed events (vs opaque messages) are what make provenance, audit, cost, and tool-approval first-class.
const ( EventInput EventKind = "INPUT" EventModelCall EventKind = "MODEL_CALL" EventOutput EventKind = "OUTPUT" EventToolCall EventKind = "TOOL_CALL" EventToolResult EventKind = "TOOL_RESULT" EventApprovalRequest EventKind = "APPROVAL_REQUEST" EventApprovalResult EventKind = "APPROVAL_RESULT" EventUsage EventKind = "USAGE" EventLifecycle EventKind = "LIFECYCLE" EventEnd EventKind = "END" EventError EventKind = "ERROR" EventExecutionStart EventKind = "EXECUTION_START" EventParked EventKind = "PARKED" // transport-only approval park acknowledgement; never journaled )
type EventSink ¶
type EventSink interface {
// Model performs a model call and returns the completion. Live: the host invokes the
// model and records the result. Replay: the host serves the recorded result from the
// journal and does not invoke the model. Because the result flows back through this
// mediated call, the harness never touches a provider SDK directly — the load-bearing
// replay rule. Reasoning parts ride in the returned ModelResponse.Message and are
// recorded verbatim for replay/fork continuity (I2). The completion is recorded as the
// turn's output by the host; do not also emit the same content via Output (double-record).
//
// ctx carries the execution's cancellation and deadline through to the provider call, so
// a cancelled turn stops an in-flight completion instead of orphaning it. Pass the ctx
// from Run, or one derived from it.
Model(ctx context.Context, req ModelRequest) (ModelResponse, error)
// Output streams assistant output (a delta or a full message).
Output(ctx context.Context, delta string) error
// ToolCall emits a tool call and returns its result. For CONTROLLER_MEDIATED or
// REQUIRES_APPROVAL tools it blocks until the host returns a result; for
// IN_HARNESS_REPORTED tools the author executes the tool and calls Report instead.
// ctx bounds that wait: a cancelled ctx unblocks it rather than hanging on a host that
// never replies.
ToolCall(ctx context.Context, tc ToolCall) (ToolResult, error)
// Report records the result of a tool the harness executed itself.
Report(ctx context.Context, tr ToolResult) error
// Usage records token/cost accounting. To record a model call's usage, pass the
// ModelResponse.Usage that Model returned: Replay and Resume serve the recorded usage with
// the recorded completion, so the same call matches the record.
Usage(ctx context.Context, u Usage) error
}
EventSink is the harness author's handle for emitting events. The SDK hides the gRPC stream, sequence assignment, and the emit -> wait-for-host round-trip.
type ExecState ¶
type ExecState string
ExecState is the execution/turn axis of a session's lifecycle — the event-log axis. It is modeled separately from ComputeState (the incarnation axis) rather than flattened into a single enum, matching the durable-log & replay contract (§6). Both axes are authoritative and are reported independently on the wire.
type ExecutionStart ¶
type ExecutionStart struct {
// Model is the effective default under an explicit host policy. Empty keeps pre-policy
// semantics, including unvalidated model requests. Omit it to preserve old journal hashes.
Model string `json:",omitempty"`
Config []byte
ResumeFromSeq int64
InputCount *int64
Harness string // resolved registry name; empty legacy values use the session harness
HarnessVersion string // advertised opaque version; empty is unknown and retains legacy behavior
// ComputeInstance is Incarnation.ComputeInstance of the compute the turn was placed on; empty when
// the backend set none (a stateless harness, or a backend that cannot tell instances apart).
ComputeInstance string
}
ExecutionStart is host-owned invocation state, recorded before the harness runs. Config is opaque and preserved verbatim; ResumeFromSeq is the harness's cursor, not the log's CAS cursor. InputCount records the expected number of INPUT events; zero explicitly permits inputless turns. A nil count cannot establish completeness and is rejected when reconstructing this invocation. Executions without this event reconstruct with empty config and a zero cursor (legacy defaults).
type FilePart ¶
type FilePart struct {
MIME string
Bytes []byte
URI string
Digest string // content digest of the URI target, so the hash-chain covers externalized bytes
Name string
}
FilePart carries media inline or by URI (A2A file part; MCP resource_link).
type Harness ¶
type Harness interface {
// Describe returns the static contract, used to match the harness to a Runtime.
Describe(ctx context.Context) (Descriptor, error)
// Run drives exactly one execution (turn). It reads the Start, emits events via
// sink, and returns nil on COMPLETED or an error on FAILED. Cancellation via ctx.
Run(ctx context.Context, s *Start, sink EventSink) error
}
Harness is the Bring-Your-Own-Harness SPI. A Microsoft Agent Framework (MAF) agent, a GitHub Copilot agent, or a custom agent implements it via a thin adapter. The host drives one execution per Run; the harness runs inside the sandbox provided by a Runtime.
The wire contract is api/harness.proto (Harness.Connect / Harness.Describe); an SDK adapts between them and hides sequence numbers and the tool-mediation round-trip.
type HarnessEnd ¶
HarnessEnd is the terminal state of one execution.
type IdentityContext ¶
type IdentityContext struct {
Principal IdentityRef
MintToken TokenMinter // nil when identity is not configured (dev)
}
IdentityContext carries the session principal and, optionally, a minter so the harness can obtain scoped, delegated tokens (Transaction Tokens) for tool calls rather than passing the raw principal downstream.
type IdentityRef ¶
IdentityRef is the bound agent principal. It is OIDC-neutral: an Entra Agent ID is one issuer; a SPIFFE ID or a GitHub App identity are others. Carried on every event.
type Incarnation ¶
type Incarnation struct {
ID string
Worker string // pod/worker id
Address string // where the harness server listens, or the ingress that routes to it
Runtime string // "pod" | "kata" | "clh" | "substrate"
FenceToken int64 // monotonic; the log rejects appends from a superseded incarnation
// CallMetadata is request metadata the host must attach to every call it makes to the harness at
// Address. A backend whose harness sits behind a shared ingress uses it to name the target
// sandbox (substrate: ate-target-actor); a backend that hands out a direct address leaves it
// empty. It is routing, not authentication: nothing here proves the caller's identity.
CallMetadata map[string]string
// ComputeInstance is an opaque identity of the compute instance behind ID that differs between two
// instances reusing one ID (substrate: the actor's server-assigned UID, while ID is the actor
// name). A backend sets it only when the harness keeps its state in that instance's memory
// (REQUIRES_MEMORY_SNAPSHOT). The host records it in the turn's EXECUTION_START and refuses a turn
// or a Resume placed on an instance other than the latest one the journal recorded for that
// harness since the session's FORK marker, or the clone that marker recorded from Fork's
// incarnation (ErrMemoryStateLost): a replacement holds none of the state. Suspend and a stateful
// fork pass that recorded instance to Snapshot, which refuses another one.
// Empty records nothing and skips the check.
ComputeInstance string
// RecordedCheckpoint, on the Incarnation passed to Snapshot, is the checkpoint the session's
// journal last recorded for the session (see SessionSpec.RecordedCheckpoint); the zero value
// means none. Suspend and a stateful fork set it. A backend whose compute can hold a snapshot
// the journal never recorded (substrate: a capture a memory-tier Snapshot refused) refuses with
// ErrMemoryStateLost, before capturing, compute that holds another one: capturing it again
// would record state that is not the session's. Create, Restore and Fork leave it empty.
RecordedCheckpoint SnapshotRef
}
Incarnation is a live compute instance of a session (a sandbox).
type InstanceRestorer ¶ added in v0.3.0
type InstanceRestorer interface {
RestoreInstance(ctx context.Context, ref SnapshotRef, recorded func() (string, error)) (Incarnation, error)
}
InstanceRestorer is an optional extension of Runtime for a backend that sets Incarnation.ComputeInstance. RestoreInstance is Restore with a way to read the compute instance the journal last recorded for the session's harness, so the backend can distinguish that instance from a replacement before reattaching, and classify permanent loss after a failed restore. recorded returns "" when no instance is recorded. The backend may call it during admission and again after a failed restore; each call must read current journal state, so another host's intervening turn is seen. A read failure can refuse admission before any resume. A backend reports ErrMemoryStateLost from RestoreInstance only when it can show the recorded instance gone or replaced or, with none recorded, finds an instance it cannot tell from a replacement, and otherwise returns the restore error: an instance that is still there may fail a restore for another reason. The host calls RestoreInstance in place of Restore when the backend implements it.
type Lifecycle ¶
type Lifecycle struct {
Kind LifecycleKind
Detail string
Snapshot *SnapshotRef // captured state, set on SUSPEND (§5.1)
// ComputeInstance is set only on FORK: Incarnation.ComputeInstance of the compute the child was
// cloned onto. The child's turns are compared with it until the child records its own; empty
// (a stateless fork, or a marker written before the field existed) compares nothing.
ComputeInstance string
}
Lifecycle marks a compute/session transition in the log (§7). Baseline is a replay / compaction checkpoint (§1).
type LifecycleKind ¶
type LifecycleKind string
LifecycleKind enumerates the lifecycle transitions recorded in the log.
const ( LifecycleSuspend LifecycleKind = "SUSPEND" LifecycleResume LifecycleKind = "RESUME" LifecycleFork LifecycleKind = "FORK" LifecycleBaseline LifecycleKind = "BASELINE" LifecycleCancel LifecycleKind = "CANCEL" LifecycleDelete LifecycleKind = "DELETE" // host-owned permanent intent, not compute teardown )
type Mediation ¶
type Mediation string
Mediation controls how a tool call is executed.
const ( // MediationInHarnessReported: the harness executes the tool in-sandbox and reports // the result as an event for audit. Default; fastest. MediationInHarnessReported Mediation = "IN_HARNESS_REPORTED" // MediationControllerMediated: the harness emits the call; the host/gateway executes // it (authz + policy + audit) and returns the result. MediationControllerMediated Mediation = "CONTROLLER_MEDIATED" // MediationRequiresApproval: the call pauses for human or policy approval. MediationRequiresApproval Mediation = "REQUIRES_APPROVAL" )
type Message ¶
type Message struct {
Role string // system | user | assistant (A2A calls this "agent") | tool
Parts []Part
}
Message is a role-tagged sequence of content parts (A2A Message = role + Part[]).
func TextMessage ¶
TextMessage constructs a single-text-part message.
type ModelCall ¶
type ModelCall struct {
Model string
Params map[string]string
InputHash string // required for STATELESS_REPLAY so the §9.1 I0 check can run
ID string // correlation id for the served ModelResult (proto ModelCall.id)
}
ModelCall records a call to a model (model-agnostic) for audit and cost.
type ModelPolicy ¶ added in v0.3.0
ModelPolicy is host-owned, opt-in model admission for one harness route. It is configured through the embedder Go API, never supplied by a Sessions client or inferred from Descriptor.Models. IDs are opaque. Default must be nonempty and present in Allowed; empty Allowed IDs are invalid. Without a policy the host retains its existing model behavior.
func (ModelPolicy) Resolve ¶ added in v0.3.0
func (p ModelPolicy) Resolve(model string) (string, error)
Resolve validates the policy and returns model, or the explicit default when model is empty.
func (ModelPolicy) ValidateDescriptor ¶ added in v0.3.0
func (p ModelPolicy) ValidateDescriptor(desc Descriptor) error
ValidateDescriptor requires every declared model to be allowed. An empty declaration is valid; it never widens the host policy or supplies its default.
type ModelRequest ¶
type ModelRequest struct {
// Model may override Start.Model within host policy. Empty resolves to that default only
// for policy-aware invocations; old invocations retain their original requests and hashes.
Model string
Messages []Message // context (history + new input) sent to the model
Params map[string]string
// Tools are the definitions offered to the model on this call. Order is significant.
Tools []ToolDefinition `json:",omitempty"`
// ToolChoice constrains whether and which tool the model calls. Nil means the provider default.
ToolChoice *ToolChoice `json:",omitempty"`
}
ModelRequest is a model call: the message context + model selection.
The controller hashes the JSON encoding of ModelRequest for the I0 check, so fields added after the first three carry `json:",omitempty"`: a request that does not use them hashes exactly as it did before they existed, and logs recorded earlier keep replaying.
type ModelResponse ¶
ModelResponse is the model's completion: an assistant message (which may carry text, opaque reasoning, and tool call parts) plus usage.
type Origin ¶
type Origin struct {
Source string // e.g. "github.com/acme/repo", "foundry/project-x"
Subject string // e.g. "issues/42", "threads/abc"
URI string // optional link
Attributes map[string]string // adapter-specific extras; well-known keys via profiles
}
Origin is the neutral external context a session is tied to: where it came from and what it is about. Producer adapters (GitHub, Foundry, custom apps) fill it; the core defines no producer-specific fields. Modeled on CloudEvents source/subject.
type OwnerAllowlistAuthorizer ¶ added in v0.3.0
type OwnerAllowlistAuthorizer struct {
Allow map[Action][]CallerIdentity
}
OwnerAllowlistAuthorizer composes ordinary owner permissions with explicit exact-caller allowlists for create, list, approve and registry operator actions. Approve RPCs check read separately: an approver must also own the session with this policy. Allowlists cannot override owner checks or enable mint/unknown actions. Configure Allow before serving and do not mutate it during use. Global actions use an empty SessionUID and Owner. This policy interprets no grants or identity/provenance supplied in requests.
func (OwnerAllowlistAuthorizer) Authorize ¶ added in v0.3.0
func (p OwnerAllowlistAuthorizer) Authorize(ctx context.Context, r AuthorizationRequest) error
type OwnerAuthorizer ¶ added in v0.3.0
type OwnerAuthorizer struct{}
OwnerAuthorizer is the first owner/grants policy implementation. It supports owner checks only; no grants are interpreted. Approval decisions, audience minting and creation require separate policy and are denied even to owners. ActionFork authorizes the parent only; it does not assign child ownership. The current fork path creates unbound children. Enforcing hosts need a separate owned-child reservation/publication primitive before exposing owned forks.
func (OwnerAuthorizer) Authorize ¶ added in v0.3.0
func (OwnerAuthorizer) Authorize(ctx context.Context, r AuthorizationRequest) error
type Part ¶
type Part struct {
Text *TextPart
File *FilePart
Data map[string]any
Reasoning *ReasoningPart
// ToolCall is a model's request to call a tool, carried in an assistant message. Mediation
// and IdempotencyKey are unset on a model output. To execute the call, copy it, set them on
// the copy, and pass the copy to EventSink.ToolCall: the returned message can share this
// pointer with the recorded completion, so changing it in place alters a hashed event.
ToolCall *ToolCall `json:",omitempty"`
// ToolResult is a tool's result fed back to the model, carried in a message with role
// "tool". ToolResult.ID is the ID of the ToolCall it answers.
ToolResult *ToolResult `json:",omitempty"`
}
Part is one unit of content: text, file (inline or URI), structured data, an opaque reasoning block, a model's tool call, or a tool's result. Aligned with A2A Part + MCP content. Exactly one field is set.
Fields added after the first four carry `json:",omitempty"`: the controller's model input hash (I0) is computed over the JSON encoding of ModelRequest, so a new field that encoded as null would change the hash of every request recorded before it existed.
type ReasoningPart ¶
type ReasoningPart struct {
Provider string // "anthropic" | "openai" | "google"
ModelID string
Opaque []byte // set, OR OpaqueURI when externalized
OpaqueURI string
OpaqueDigest string // content digest of OpaqueURI target (hash-chain covers externalized bytes)
Summary []Part // optional, non-authoritative, compaction-droppable
ItemID string
Ordinal int32
ValidityScope string // = execution id (turn)
}
ReasoningPart is an opaque, provider-tagged reasoning block replayed verbatim to preserve reasoning continuity within a turn (I2). agentsessions never interprets Opaque; provider specifics live inside it. One part type across all providers (Track A spike: no per-provider sub-shapes, no memory-snapshot edge).
type Resumability ¶
type Resumability string
Resumability declares how a harness survives suspend/resume/fork.
const ( // ResumabilityStatelessReplay: the harness holds no durable in-memory state beyond // the event log. On resume/fork the host replays history via Start.History. Runs on // any runtime, including a plain pod. Default. ResumabilityStatelessReplay Resumability = "STATELESS_REPLAY" // ResumabilityRequiresMemorySnapshot: the harness holds in-process state (a REPL, a // browser, a long-running process). The host only schedules it on a runtime whose // RuntimeCapabilities.MemorySnapshot is true. ResumabilityRequiresMemorySnapshot Resumability = "REQUIRES_MEMORY_SNAPSHOT" )
type Runtime ¶
type Runtime interface {
// Create starts a cold incarnation (sandbox) for a session and returns a handle
// including the address where the harness server listens.
Create(ctx context.Context, s *SessionSpec) (Incarnation, error)
// Snapshot captures the incarnation's state. SnapshotLocal (warm/pause) keeps it
// node-resident. SnapshotExternal owns the cold transition: it captures required state,
// releases dedicated per-incarnation compute where applicable, and preserves the state
// and any backend handles Restore needs. A backend without memory snapshots may return
// a filesystem/journal handle; without dedicated per-session compute, its shared harness
// server may remain running.
//
// A non-empty in.ComputeInstance is the instance the caller requires behind in.ID (the
// latest one the journal recorded). A backend that sets ComputeInstance refuses with
// ErrMemoryStateLost when another instance is there, or none is, before it captures anything
// if it can tell, and in any case before returning a ref: a snapshot of a replacement would
// hand its callers compute that holds none of the session's state. in.RecordedCheckpoint is
// the checkpoint the journal last recorded; a backend may refuse, with ErrMemoryStateLost,
// compute that holds another one (see Incarnation.RecordedCheckpoint).
Snapshot(ctx context.Context, in Incarnation, kind SnapshotKind) (SnapshotRef, error)
// Restore brings an incarnation back from a snapshot. Sub-second on memory-capable
// backends; a filesystem-only backend restores the workspace and relies on the host
// replaying the event log.
Restore(ctx context.Context, ref SnapshotRef) (Incarnation, error)
// Fork creates a child incarnation. A backend with MemorySnapshot clones ref's captured state so
// the child continues from the parent's RAM; a filesystem-only backend returns a fresh incarnation
// and relies on the host replaying the child's copied log prefix. Implementations must not leak a
// partially-provisioned child: on any failure after the child exists, tear it down before returning.
// A backend that finds ref no longer held by the parent returns an error wrapping
// ErrSnapshotSuperseded. The host records the returned ComputeInstance on the child's FORK
// marker, and compares the child's compute with it until the child's first turn records one.
Fork(ctx context.Context, ref SnapshotRef, opts ForkOpts) (Incarnation, error)
// Stop is destructive teardown: it destroys the incarnation and frees its dedicated compute.
// Callers must not assume a captured SnapshotRef remains restorable after Stop.
Stop(ctx context.Context, in Incarnation) error
// Status reports the incarnation's compute-lifecycle state.
Status(ctx context.Context, in Incarnation) (ComputeState, error)
// Capabilities reports what this backend supports.
Capabilities() RuntimeCapabilities
}
Runtime is the compute/sandbox SPI. Pod, Kata Pod Sandboxing, Cloud Hypervisor, Dragonball, Hyperlight, and agent-substrate all implement it. There is no gVisor requirement — backends are interchangeable, and the host reads Capabilities to place harnesses and degrade honestly.
This is the seam that lets "different folks on top" (via producer adapters + the Sessions API) run on "substrate underneath" (or pod, Kata, ...) with no API change.
type RuntimeCapabilities ¶
type RuntimeCapabilities struct {
MemorySnapshot bool // can capture/restore RAM+process (pod: false, kata/clh: true)
CoWFork bool // copy-on-write fork
Attest bool // attestation on restore (confidential)
GPUState bool // accelerator state capture
}
RuntimeCapabilities is what a backend can do. The host matches these against a harness's Capabilities before scheduling.
type Session ¶
type Session struct {
UID string
Project string // tenant / namespace
Name string
Harness string
Model string // model-agnostic id, e.g. "azure-openai/gpt-x", "anthropic/..."
Exec ExecState // execution/turn axis (the event-log axis)
ComputeState ComputeState // incarnation axis
LastSeq int64 // event-log cursor = the resume/replay point
ParentUID string // set iff this session was forked
ForkSeq int64 // parent event seq forked at
Identity IdentityRef
Compute *ComputeRef // current incarnation; nil when SUSPENDED/TERMINATED
Origin *Origin // neutral external context; filled by a producer adapter
Labels map[string]string
Annotations map[string]string // free-form adapter metadata (K8s-style)
}
Session is the durable unit: a conversation (event log) plus zero-or-one live compute incarnation. Unifying the two into one resource is what makes fork, provenance, and identity first-class.
type SessionSpec ¶
type SessionSpec struct {
SessionUID string
Image string
Harness string
Identity IdentityRef
// StartedTurns counts the turns the session's journal records as started (an EXECUTION_START) on
// the harness being placed, whether they completed, failed or were interrupted: any of them may
// have changed that harness's in-memory state. For a forked child it counts the turns of the copied
// prefix that ran on this harness. A turn another harness ran (an ExecRequest.harness override) is
// not counted, since it left no state in this harness's compute; a turn the host cannot attribute
// (no recorded harness name, or a name it does not serve) is.
//
// A backend uses it to refuse creating fresh compute for a REQUIRES_MEMORY_SNAPSHOT session that
// already has state only its old compute held (ErrMemoryStateLost). It is a function rather than a
// number so that the backend counts only after it has seen the compute is missing: a turn is
// journaled before it runs, so every turn that ran on the lost compute is then visible, including
// one another host sharing the journal recorded while this call was being placed. A backend that
// does not need it does not call it. Nil declares a session with no started turns on this harness.
StartedTurns func() (int, error)
// RecordedCheckpoint reads the checkpoint the session's journal last recorded for this session:
// the SnapshotRef of its latest SUSPEND whose Local names the session, or a zero SnapshotRef
// (ExternalURI "") when there is none, as for a session never suspended or a fork child before
// its first Suspend (a parent's SUSPEND in a child's copied prefix is not the child's).
//
// A backend whose compute can hold a snapshot the journal never recorded (substrate: a capture a
// memory-tier Snapshot refused stays on the actor) compares it with the snapshot the existing
// compute holds before attaching to or resuming it, and refuses another with
// ErrMemoryStateLost. Like StartedTurns it is a function, so the backend reads the journal only
// after it has read the compute, and sees a SUSPEND another host recorded in between. A backend
// that does not need it does not call it. Nil declares no recorded checkpoint.
RecordedCheckpoint func() (SnapshotRef, error)
}
SessionSpec is what a Runtime needs to create an incarnation.
type SnapshotKind ¶
type SnapshotKind string
SnapshotKind selects local (warm/pause) vs external (cold/suspend) storage.
const ( // SnapshotLocal keeps the captured state warm and node-resident. SnapshotLocal SnapshotKind = "LOCAL" // SnapshotExternal transitions to cold, releasing dedicated compute while retaining restore state. SnapshotExternal SnapshotKind = "EXTERNAL" )
type SnapshotRef ¶
type SnapshotRef struct {
Local string // node/handle-local ref, or (filesystem-only) the session handle to replay
ExternalURI string // external blob (cold/suspend)
Memory bool // RAM/process captured? kata/clh: true, pod: false
Sealed bool // encrypted + attested (confidential)
}
SnapshotRef points at a captured incarnation state. This Go SPI type is the canonical, WIRED representation: Runtime backends produce/consume it, and the durable log carries it inline on the SUSPEND Lifecycle event (api.Lifecycle.Snapshot -> proto Lifecycle.snapshot_* fields). The proto message agentsessions.v1.SnapshotRef (session.proto, used by ComputeRef) is a SEPARATE, not-yet- wired session-status shape — see its TODO. Unlike that oneof, this holds both Local and ExternalURI (a substrate ref sets both).
type Start ¶
type Start struct {
// ExecutionID identifies this Run on the wire. Modern runs share it with journal events;
// legacy runs use a session-scoped legacy- compatibility token that is never journaled.
ExecutionID string
// SessionUID carries the ControllerFrame session envelope for tool/approval correlation.
// Model-only callers that do not use that envelope may leave it empty.
// Model is the host-resolved default for a policy-enabled execution. Empty retains the
// harness's existing default. Replay/resume restore the recorded value, not today's policy.
Model string `json:",omitempty"`
SessionUID string `json:",omitempty"`
Config []byte // opaque per-execution config; journaled verbatim and restored on replay/resume
History []Event // every event before this execution's start, also after a memory restore
Inputs []Message // invocation inputs; originals are restored on controller replay/resume
Identity IdentityContext
ResumeFromSeq int64 // opaque harness cursor, journaled with Config; distinct from the append CAS cursor
}
Start is the per-execution invocation the host sends to the harness.
type TokenMinter ¶
TokenMinter returns a scoped token for a downstream audience.
type ToolCall ¶
type ToolCall struct {
ID string
Tool string // tool name / MCP method
Args map[string]any
Mediation Mediation
IdempotencyKey string // dedups a retried side-effecting call tool-side (§3/I3)
}
ToolCall is a tool invocation. Its shape aligns with an MCP tool call (name + structured arguments) so MCP tools map onto it directly.
type ToolChoice ¶
type ToolChoice struct {
Mode ToolChoiceMode
Name string
}
ToolChoice constrains whether and which tool the model calls. An empty Mode is the provider default. Name forces one specific tool and is meaningful only with ToolChoiceRequired.
type ToolChoiceMode ¶
type ToolChoiceMode string
ToolChoiceMode constrains whether the model calls a tool.
const ( // ToolChoiceAuto: the model decides whether to call a tool. ToolChoiceAuto ToolChoiceMode = "AUTO" // ToolChoiceNone: the model must not call a tool. ToolChoiceNone ToolChoiceMode = "NONE" // ToolChoiceRequired: the model must call at least one tool. ToolChoiceRequired ToolChoiceMode = "REQUIRED" )
type ToolDefinition ¶
type ToolDefinition struct {
Name string
Description string
InputSchema map[string]any // JSON Schema object; JSON-shaped values only (see package wire)
}
ToolDefinition is a tool offered to a model on one call, aligned with an MCP Tool. ToolSpec declares a tool and its default mediation to the host; ToolDefinition is what the model sees.
type ToolResult ¶
type ToolResult struct {
ID string
Output map[string]any
OutputURI string // externalized large output (MCP resource_link); else inline Output
OutputDigest string // content digest of OutputURI target (hash-chain covers externalized bytes)
IsError bool
Error string
// Content is the model-facing result (MCP CallToolResult.content). A harness records on the
// TOOL_RESULT event the same ToolResult it feeds back as a tool_result part, so history rebuilt
// from the log can give the model what it saw live.
Content []Part `json:",omitempty"`
// Additive durable receipt fields are omitted at zero to preserve old model-input hashes.
Code ToolResultCode `json:",omitempty"`
ApprovalRequestSeq int64 `json:",omitempty"`
ApprovalDecisionSeq int64 `json:",omitempty"`
// Approval carries a host decision to a direct sink caller. It is transient: neither Go JSON
// nor wire conversion includes it in a receipt or model history. The durable decision is a
// separate APPROVAL_RESULT event; the receipt binds it by sequence above.
Approval *ApprovalResult `json:"-"`
}
ToolResult is the outcome of a ToolCall.
type ToolResultCode ¶
type ToolResultCode int32
ToolResultCode is the machine-readable receipt status, matching common.proto ToolResult.Code. Zero preserves legacy receipts and also denotes a successful result when IsError is false.
const ( ToolResultCodeUnspecified ToolResultCode = 0 ToolResultCodeApprovalDenied ToolResultCode = 1 ToolResultCodeExecutorError ToolResultCode = 2 )