agentbackend

package
v0.26.0-alpha1 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package agentbackend defines the implementation-neutral contract between Obot's hosted-agent controllers and an agent runtime provider.

Index

Constants

View Source
const (
	// MinSandboxMemoryBytes is the smallest memory reservation a sandbox may be
	// given. Dividing a pool between many sandboxes can produce a share below
	// what any real agent image needs to start, and such a sandbox schedules
	// successfully and then dies immediately, which reads as a broken agent
	// rather than an over-subscribed pool.
	MinSandboxMemoryBytes int64 = 200 << 20 // 200MB

	// MinSandboxCPUVCPUs keeps a reservation from rounding to zero. CPU is
	// compressible, so a small share only means a slow sandbox, but a zero
	// request means no guarantee at all.
	MinSandboxCPUVCPUs = 0.01

	// DefaultMaxSandboxes applies when a pool does not say. It is a capacity
	// planning decision, so there is no good universal answer; this only keeps
	// an unconfigured pool usable.
	DefaultMaxSandboxes = 10
)

Variables

View Source
var ErrDisabled = errors.New("agent runtime backend is disabled")

Functions

This section is empty.

Types

type Backend

type Backend interface {
	InstanceBackend
	PoolBackend
	UtilizationReader
}

Backend is the complete desired-state and observation contract required by hosted agents. Implementations must make every operation idempotent.

type DeleteResult

type DeleteResult struct {
	Complete bool
}

type DesiredInstance

type DesiredInstance struct {
	Ref      InstanceRef
	Pool     PoolRef
	Revision string

	Name        string
	Description string
	Harness     Harness
	Image       string
	Source      Source
	Model       Model
	Env         map[string]string
	Files       []File
	Secrets     []SecretRef

	// Requests is what this sandbox is guaranteed, and Limits is what it may
	// burst to. Both are derived from the pool rather than declared by the
	// agent: a pool is a shared bucket, and an agent has no inherent size.
	//
	// They are carried here, rather than computed by a backend, so that they
	// participate in the desired revision. Resizing a pool therefore changes
	// every sandbox's revision and restarts it, which is the only way a running
	// sandbox picks up new limits.
	Requests InstanceResources
	Limits   InstanceResources

	// Port is the HTTP port the agent serves on. Zero means it serves nothing,
	// and a backend should publish no address for it.
	Port int
	// Terminal asks the backend to keep the sandbox attachable for an
	// interactive session.
	Terminal bool
}

func (DesiredInstance) Redacted

func (d DesiredInstance) Redacted() DesiredInstance

Redacted returns a copy with every secret value cleared, for hashing into the desired revision or for logging. Version still varies with the value, so a rotation changes the revision without the revision ever containing a secret.

type DesiredPool

type DesiredPool struct {
	Ref      PoolRef
	Revision string
	Capacity ResourceQuantity
	// MaxSandboxes bounds how many sandboxes share the pool, and so determines
	// each one's guaranteed share.
	MaxSandboxes int
	Suspended    bool
}

type Disabled

type Disabled struct{}

Disabled is a Backend that consistently reports that hosted-agent runtime management is unavailable. It lets service wiring inject a non-nil backend without giving disabled mode any synthetic behavior.

func (Disabled) DeleteInstance

func (Disabled) DeleteInstance(context.Context, InstanceRef) (DeleteResult, error)

func (Disabled) DeletePool

func (Disabled) GetPoolUtilization

func (Disabled) GetPoolUtilization(context.Context, PoolRef) (UtilizationSnapshot, error)

func (Disabled) ObserveInstance

func (Disabled) ObservePool

func (Disabled) ReconcileInstance

func (Disabled) ReconcilePool

type Event

type Event struct {
	Kind     ResourceKind
	Instance InstanceRef
	Pool     PoolRef
}

type File

type File struct {
	Path    string
	Content []byte
	Mode    uint32
}

type Harness

type Harness struct {
	ID string
	// Interactive asks the backend to allocate a TTY and keep stdin open, the
	// equivalent of `docker run -it`. Without it an image whose entrypoint is a
	// shell exits as soon as it starts.
	Interactive bool
}

type InstanceBackend

type InstanceBackend interface {
	ReconcileInstance(context.Context, DesiredInstance) (InstanceObservation, error)
	ObserveInstance(context.Context, InstanceRef) (InstanceObservation, error)
	DeleteInstance(context.Context, InstanceRef) (DeleteResult, error)
}

type InstanceObservation

type InstanceObservation struct {
	Ref               InstanceRef
	Exists            bool
	ObservedRevision  string
	State             State
	URL               string
	Reason            string
	Message           string
	BackendGeneration int64
}

type InstanceRef

type InstanceRef struct {
	ID        string
	Namespace string
	UserID    string
	BackendID string
}

type InstanceResources

type InstanceResources struct {
	CPUVCPUs    float64
	MemoryBytes int64
}

InstanceResources is a sandbox's share of its pool, in plain units so the contract stays independent of any backend's resource model.

These are plain numbers on purpose. Quantity-style types serialize equal values to different strings ("1" and "1000m"), which would make the desired revision hash unstable and trigger redeploys that change nothing.

func SandboxShare

func SandboxShare(capacity ResourceQuantity, maxSandboxes int) (requests, limits InstanceResources, effectiveMax int)

SandboxShare divides a pool between its sandboxes.

A pool is a shared bucket. Each sandbox reserves an equal fraction of it, so that it can always be scheduled, and may burst to the whole pool when its neighbours are idle. Agents therefore have no size of their own: raising a pool's sandbox count shrinks everyone's guaranteed share and nothing else.

This is an approximation of a single shared cgroup, which Kubernetes cannot express across pods. The difference that remains is that reservations are summed against the node, so a pool cannot be oversubscribed as freely as one cgroup would allow.

The floors mean effectiveMax can be lower than the configured maximum: once a share would fall below a floor, the pool holds fewer sandboxes than asked for. Returning that, rather than silently admitting sandboxes that cannot run, lets the caller bound the pool by a number that is actually true.

func (InstanceResources) IsZero

func (r InstanceResources) IsZero() bool

type InstanceUtilization

type InstanceUtilization struct {
	Ref         InstanceRef
	State       State
	Utilization ResourceUtilization
}

type Model

type Model struct {
	ID       string
	Endpoint string
}

type PoolBackend

type PoolBackend interface {
	ReconcilePool(context.Context, DesiredPool) (PoolObservation, error)
	ObservePool(context.Context, PoolRef) (PoolObservation, error)
	DeletePool(context.Context, PoolRef) (DeleteResult, error)
}

type PoolObservation

type PoolObservation struct {
	Ref               PoolRef
	Exists            bool
	ObservedRevision  string
	State             State
	Schedulable       bool
	Capacity          ResourceQuantity
	Reason            string
	Message           string
	BackendGeneration int64
}

type PoolRef

type PoolRef struct {
	ID        string
	BackendID string
}

type Pressure

type Pressure struct {
	CPU     bool
	Memory  bool
	Storage bool
}

type ResourceKind

type ResourceKind string
const (
	ResourceKindInstance ResourceKind = "instance"
	ResourceKindPool     ResourceKind = "pool"
)

type ResourceQuantity

type ResourceQuantity struct {
	CPUVCPUs     float64
	MemoryBytes  int64
	StorageBytes int64
}

type ResourceUtilization

type ResourceUtilization struct {
	CPUVCPUs     float64
	MemoryBytes  int64
	StorageBytes int64
}

ResourceUtilization is live usage. StorageBytes is only ever set on a pool: sandboxes share one volume separated by subPath, which the kubelet does not measure per directory, so a sandbox's own disk usage is not observable without a node agent.

type SecretRef

type SecretRef struct {
	ID       string
	EnvName  string
	FilePath string

	// Version changes whenever the value behind ID changes. It participates in
	// the desired revision so that a rotated secret restarts the sandbox.
	//
	// Agents read their credentials once at startup and cannot reload them, so
	// a sandbox left running across a rotation would hold a credential that no
	// longer works. Versioning the reference propagates the rotation while
	// keeping the value itself out of desired state, status and the revision.
	Version string

	// Value is the secret itself, passed transiently so a backend can write it
	// wherever that backend keeps secrets. It is excluded from the desired
	// revision by DesiredInstance.Redacted, and must never be persisted to
	// instance spec or status, or logged.
	Value string
}

SecretRef contains routing metadata only. Secret values are managed through the provider's secret channel and must never enter this persisted contract.

type Source

type Source struct {
	URL      string
	Revision string
	Subdir   string
}

type State

type State string
const (
	StatePending  State = "pending"
	StateReady    State = "ready"
	StateError    State = "error"
	StateDeleting State = "deleting"
)

type Subscriber

type Subscriber interface {
	Subscribe(context.Context, func(context.Context, Event) error) error
}

Subscriber is an optional fast path for lifecycle changes. Events are hints; callers must observe the referenced resource before persisting status.

type TerminalBackend

type TerminalBackend interface {
	// AttachTerminal connects to a sandbox's existing console. It attaches to
	// the process the sandbox is already running rather than starting a new
	// one, so an operator sees the same session the agent is driving.
	//
	// This requires the sandbox to have been started with a TTY, which is what
	// a harness marks by being interactive. Attaching to one that was not is an
	// error rather than a silently empty session.
	AttachTerminal(ctx context.Context, ref InstanceRef, size TerminalSize) (TerminalSession, error)
}

TerminalBackend is an optional capability: a backend that can attach an interactive session to a running sandbox.

It is separate from Backend so that a runtime without a console -- or one that has not implemented it yet -- simply does not satisfy it, and callers discover that with a type assertion rather than through a method that returns "unsupported" at runtime.

type TerminalSession

type TerminalSession interface {
	io.ReadWriteCloser

	// Resize tells the sandbox its terminal changed shape. Without it a program
	// drawing a full-screen interface keeps using the size it saw at startup.
	Resize(size TerminalSize) error
}

TerminalSession is a live console.

Read yields console output and Write sends input. A console multiplexes what would otherwise be stdout and stderr onto one stream, because that is what a TTY does: the terminal is the process's controlling terminal, and both descriptors point at it. Callers that distinguish the two are reporting their own errors, not the sandbox's.

type TerminalSize

type TerminalSize struct {
	Rows uint16
	Cols uint16
}

TerminalSize is measured in character cells.

type UtilizationReader

type UtilizationReader interface {
	GetPoolUtilization(context.Context, PoolRef) (UtilizationSnapshot, error)
}

type UtilizationSnapshot

type UtilizationSnapshot struct {
	Timestamp time.Time
	Pool      ResourceUtilization
	Instances []InstanceUtilization
	Pressure  Pressure
	// StorageMeasured reports whether Pool.StorageBytes is a real measurement.
	// A backend that cannot attribute disk usage to this pool alone leaves it
	// false, so a caller can say so rather than draw an empty disk that is
	// really an unknown one.
	StorageMeasured bool
}

UtilizationSnapshot is a live point-in-time sample, not desired state or historical accounting.

Directories

Path Synopsis
Package fake provides a process-local agent backend for development and provider contract tests.
Package fake provides a process-local agent backend for development and provider contract tests.
Package kubernetes implements the agent runtime backend on top of a Kubernetes cluster.
Package kubernetes implements the agent runtime backend on top of a Kubernetes cluster.

Jump to

Keyboard shortcuts

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