Agent Sandbox

Go SDK Reference

Agent Sandbox Go SDK Reference.
import "sigs.k8s.io/agent-sandbox/clients/go/sandbox"

Index

Constants

const (

    // PodNameAnnotation is the deprecated annotation key on a Sandbox resource that identifies the name of the underlying pod.
    // Deprecated: New Sandboxes use their own name for the backing pod while non-empty legacy annotations may still be honored.
    PodNameAnnotation = "agents.x-k8s.io/pod-name"
)

Variables

Span attribute keys in the sandbox.* namespace.

var (
    AttrClaimName         = attribute.Key("sandbox.claim.name")
    AttrCommandExecutable = attribute.Key("sandbox.command.executable")
    AttrExitCode          = attribute.Key("sandbox.exit_code")
    AttrFilePath          = attribute.Key("sandbox.file.path")
    AttrFileSize          = attribute.Key("sandbox.file.size")
    AttrFileCount         = attribute.Key("sandbox.file.count")
    AttrFileExists        = attribute.Key("sandbox.file.exists")
    AttrGatewayName       = attribute.Key("sandbox.gateway.name")
    AttrGatewayNamespace  = attribute.Key("sandbox.gateway.namespace")
    AttrRequestID         = attribute.Key("sandbox.request_id")
)

Sentinel errors returned by the SDK.

var (
    ErrNotReady         = errors.New("sandbox is not ready")
    ErrTimeout          = errors.New("operation timed out")
    ErrClaimFailed      = errors.New("claim creation failed")
    ErrPortForwardDied  = errors.New("port-forward connection lost")
    ErrAlreadyOpen      = errors.New("sandbox is already open; call Close first")
    ErrOrphanedClaim    = errors.New("orphaned claim; call Close() to retry deletion")
    ErrRetriesExhausted = errors.New("retries exhausted")
    ErrSandboxDeleted   = errors.New("sandbox was deleted before becoming ready")
    ErrGatewayDeleted   = errors.New("gateway was deleted during address discovery")
    ErrResponseTooLarge = errors.New("response exceeded 16 MB limit")
    // ErrUnsupportedByRuntime is returned by operations the selected
    // runtime cannot perform (e.g. Delete on the legacy python-runtime).
    ErrUnsupportedByRuntime = errors.New("operation not supported by the sandbox runtime")
)

func NewTracerProvider

func NewTracerProvider(ctx context.Context, serviceName string) (*sdktrace.TracerProvider, error)

NewTracerProvider creates a TracerProvider with an OTLP/gRPC exporter. The endpoint is read from OTEL_EXPORTER_OTLP_ENDPOINT (default: localhost:4317). serviceName becomes the service.name resource attribute. The caller owns the returned provider and must call Shutdown when done.

type CallOption

CallOption configures per-call behavior for SDK operations.

type CallOption func(*callOptions)

func WithMaxAttempts

func WithMaxAttempts(n int) CallOption

WithMaxAttempts sets the maximum number of attempts for an operation. Values ≤0 are ignored and the default is used (1 for Run, 6 for file operations).

result, err := client.Run(ctx, "cat /etc/hostname", sandbox.WithMaxAttempts(6))

func WithTimeout

func WithTimeout(d time.Duration) CallOption

WithTimeout sets the total timeout for a single operation, overriding the default RequestTimeout for that call.

type Client

Client manages sandbox lifecycles and tracks active handles.

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

func NewClient

func NewClient(_ context.Context, opts Options) (*Client, error)

NewClient creates a Client with shared configuration.

func (*Client) CreateSandbox

func (c *Client) CreateSandbox(ctx context.Context, warmPoolName, namespace string) (*Sandbox, error)

CreateSandbox provisions a new sandbox and returns a managed handle. On failure, the orphaned claim is cleaned up.

func (*Client) DeleteAll

func (c *Client) DeleteAll(ctx context.Context)

DeleteAll closes and deletes all tracked sandboxes. Best-effort.

func (*Client) DeleteSandbox

func (c *Client) DeleteSandbox(ctx context.Context, claimName, namespace string) error

DeleteSandbox closes the handle (if tracked) and deletes the claim.

func (*Client) EnableAutoCleanup

func (c *Client) EnableAutoCleanup() (stop func())

EnableAutoCleanup calls DeleteAll on SIGINT/SIGTERM. Call the returned function to stop the signal handler.

func (*Client) GetSandbox

func (c *Client) GetSandbox(ctx context.Context, claimName, namespace string) (*Sandbox, error)

GetSandbox retrieves an existing sandbox by claim name. Returns the cached handle if connected, otherwise re-attaches.

func (*Client) ListActiveSandboxes

func (c *Client) ListActiveSandboxes() []Key

ListActiveSandboxes returns tracked sandboxes, pruning inactive handles.

func (*Client) ListAllSandboxes

func (c *Client) ListAllSandboxes(ctx context.Context, namespace string) ([]string, error)

ListAllSandboxes lists all SandboxClaim names in the given namespace.

type Commands

Commands provides command execution on a sandbox.

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

func (*Commands) Run

func (c *Commands) Run(ctx context.Context, command string, opts ...CallOption) (*ExecutionResult, error)

Run executes a command in the sandbox and returns the result. The combined JSON response (stdout + stderr + metadata) is limited to 16 MB; commands producing more output will fail with ErrResponseTooLarge.

Because command execution is not idempotent, Run defaults to a single attempt (no retries). For idempotent commands that should retry on transient server errors (502, 503, etc.), use WithMaxAttempts:

result, err := client.Run(ctx, "cat /etc/hostname", sandbox.WithMaxAttempts(6))

WithMaxAttempts applies only to the legacy runtime. With RuntimeSandboxd, Run issues a single gRPC Execute regardless of the configured attempts.

type ConnectionStrategy

ConnectionStrategy defines how the SDK discovers the sandbox-router URL.

type ConnectionStrategy interface {
    Connect(ctx context.Context) (baseURL string, err error)
    Close() error
}

type DirectStrategy

DirectStrategy connects using a pre-configured URL, bypassing all discovery.

type DirectStrategy struct {
    URL string
}

func (*DirectStrategy) Close

func (s *DirectStrategy) Close() error

func (*DirectStrategy) Connect

func (s *DirectStrategy) Connect(_ context.Context) (string, error)

type ExecutionResult

ExecutionResult holds the result of a command execution in the sandbox.

type ExecutionResult struct {
    Stdout   string `json:"stdout"`
    Stderr   string `json:"stderr"`
    ExitCode int    `json:"exit_code"`
}

type FileEntry

FileEntry represents a file or directory entry in the sandbox. It is runtime-neutral: the SDK decodes the legacy wire format (mod_time as a float POSIX timestamp) and the sandboxd wire format (modified_at as an RFC 3339 string, plus mode) into this one shape.

type FileEntry struct {
    Name    string
    Size    int64
    Type    FileType
    ModTime time.Time
    // Mode holds octal permission bits (e.g. "0644"). Only populated by
    // the sandboxd runtime; empty on legacy.
    Mode string
}

type FileType

FileType represents the type of a file entry.

type FileType string

const (
    FileTypeFile      FileType = "file"
    FileTypeDirectory FileType = "directory"
)

type Files

Files provides file operations on a sandbox.

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

func (*Files) Delete

func (f *Files) Delete(ctx context.Context, path string, recursive bool, opts ...CallOption) error

Delete removes a file or directory in the sandbox. When recursive is true, directories are removed with their contents (rm -rf semantics); otherwise deleting a non-empty directory fails with a 409 HTTPError.

Only supported by the sandboxd runtime: the legacy python-runtime has no delete endpoint, and calls return ErrUnsupportedByRuntime.

func (*Files) Exists

func (f *Files) Exists(ctx context.Context, path string, opts ...CallOption) (bool, error)

Exists checks if a file or directory exists at the given path in the sandbox.

func (*Files) List

func (f *Files) List(ctx context.Context, path string, opts ...CallOption) ([]FileEntry, error)

List returns the contents of a directory in the sandbox.

func (*Files) Read

func (f *Files) Read(ctx context.Context, path string, opts ...CallOption) ([]byte, error)

Read downloads a file from the sandbox.

func (*Files) Write

func (f *Files) Write(ctx context.Context, path string, content []byte, opts ...CallOption) error

Write uploads content to the sandbox.

With the legacy runtime the path must be a plain filename without directory separators (e.g., “script.py”, not “dir/script.py”). The sandboxd runtime supports relative paths and creates parent directories automatically.

The entire content is buffered in memory to support retries on transient failures. Content exceeding MaxUploadSize (default 256 MB) is rejected before any network I/O.

func (*Files) WriteReader

func (f *Files) WriteReader(ctx context.Context, path string, content io.Reader, opts ...CallOption) error

WriteReader uploads content read from content without buffering the entire payload in memory. Streaming uploads use a single request attempt because a generic io.Reader cannot be replayed safely after a partial request. Passing WithMaxAttempts with a value greater than 1 returns an error; it is not silently reduced to a single attempt.

With the legacy runtime, path must be a plain filename. The sandboxd runtime accepts relative paths and creates parent directories automatically. For an unknown-length reader, MaxUploadSize is enforced while the request is being streamed; the server may therefore receive a prefix before an oversized upload is rejected. Legacy streaming uploads use HTTP chunked transfer encoding, so compatible runtimes and proxies must accept streaming request bodies without a Content-Length header.

type HTTPError

HTTPError represents a non-OK HTTP response from the sandbox.

type HTTPError struct {
    StatusCode int
    Body       string
    Operation  string
}

func (*HTTPError) Error

func (e *HTTPError) Error() string

type Handle

Handle provides high-level interaction with a sandbox instance. Sandbox implements this interface; consumers should accept Handle in their APIs to enable testing with mocks. For sub-object access (Commands(), Files()), use the concrete *Sandbox type directly.

type Handle interface {
    Open(ctx context.Context) error
    Close(ctx context.Context) error
    Disconnect(ctx context.Context) error
    IsReady() bool

    Run(ctx context.Context, command string, opts ...CallOption) (*ExecutionResult, error)
    Write(ctx context.Context, path string, content []byte, opts ...CallOption) error
    Read(ctx context.Context, path string, opts ...CallOption) ([]byte, error)
    List(ctx context.Context, path string, opts ...CallOption) ([]FileEntry, error)
    Exists(ctx context.Context, path string, opts ...CallOption) (bool, error)
}

type Info

Info provides read-only access to sandbox identity metadata.

type Info interface {
    ClaimName() string
    SandboxName() string
    PodName() string
    PodIP() string
    Annotations() map[string]string
}

type K8sHelper

K8sHelper encapsulates all Kubernetes API interactions for sandbox lifecycle management. It can be shared across multiple Sandbox instances.

type K8sHelper struct {
    AgentsClient     agentsv1beta1.AgentsV1beta1Interface
    ExtensionsClient extensionsv1beta1.ExtensionsV1beta1Interface
    DynamicClient    dynamic.Interface
    CoreClient       corev1client.CoreV1Interface
    DiscoveryClient  discoveryv1client.DiscoveryV1Interface
    RestConfig       *rest.Config

    Log logr.Logger
}

func NewK8sHelper

func NewK8sHelper(restConfig *rest.Config, log logr.Logger) (*K8sHelper, error)

NewK8sHelper creates a K8sHelper by loading kubeconfig and constructing all required clientsets. If restConfig is non-nil it is used directly; otherwise in-cluster config is tried first, then ~/.kube/config.

type Key

Key identifies a tracked sandbox in the registry.

type Key struct {
    Namespace string
    ClaimName string
}

type Options

Options configures a Sandbox instance.

type Options struct {
    // WarmPoolName is the name of the SandboxWarmPool to use.
    // Required in Options before calling Open() to provision a new sandbox.
    // Optional on Client-level Options; pass the pool name per-sandbox to
    // CreateSandbox instead.
    // Must be a valid Kubernetes DNS subdomain (lowercase, [a-z0-9.-]).
    WarmPoolName string

    // Runtime selects the in-sandbox runtime API. Default: RuntimeLegacyPython.
    // RuntimeSandboxd connects via a pod port-forward, so GatewayName is not
    // supported with it. APIURL remains available as an advanced/testing
    // escape hatch for the REST endpoint.
    Runtime Runtime

    // SandboxdRESTPort is the pod port of sandboxd's Filesystem & Runtime
    // REST API. Only used with RuntimeSandboxd. Default: 8080.
    SandboxdRESTPort int

    // SandboxdGRPCPort is the pod port of sandboxd's gRPC ProcessService.
    // Only used with RuntimeSandboxd. Default: 9090.
    SandboxdGRPCPort int

    // Namespace where the SandboxClaim will be created. Default: "default".
    // Must be a valid Kubernetes DNS label (lowercase, [a-z0-9-]).
    Namespace string

    // GatewayName enables Gateway mode. The client watches this Gateway resource
    // for an external IP, then routes through the sandbox-router.
    // Must be a valid Kubernetes DNS subdomain (lowercase, [a-z0-9.-]).
    GatewayName string

    // GatewayNamespace is where the Gateway lives. Default: "default".
    // Must be a valid Kubernetes DNS label (lowercase, [a-z0-9-]).
    GatewayNamespace string

    // GatewayScheme is the URL scheme used when constructing the base URL
    // from the Gateway's address. Default: "http".
    GatewayScheme string

    // APIURL enables Direct URL mode. The client connects directly to this URL,
    // bypassing gateway discovery. Takes precedence over GatewayName.
    APIURL string

    // ServerPort is the port the sandbox runtime listens on. Default: 8888.
    ServerPort int

    // Env is the list of environment variables to inject into the SandboxClaim.
    // Setting Env forces a cold start from the warm pool template.
    Env []extv1beta1.EnvVar

    // SandboxReadyTimeout is how long to wait for the sandbox to become ready. Default: 180s.
    SandboxReadyTimeout time.Duration

    // GatewayReadyTimeout is how long to wait for the gateway IP. Default: 180s.
    GatewayReadyTimeout time.Duration

    // PortForwardReadyTimeout is how long to wait for port-forward to be established. Default: 30s.
    PortForwardReadyTimeout time.Duration

    // CleanupTimeout is how long to wait for claim deletion during both Open
    // rollback and Close. Uses a detached context so cleanup succeeds even if
    // the caller's context is already cancelled. Default: 30s.
    CleanupTimeout time.Duration

    // RequestTimeout is the total timeout for a single SDK method call
    // (e.g., Run, Read, Write), encompassing all retry attempts and backoff
    // sleeps. Applied only when the caller's context has no deadline.
    // Default: 180s.
    RequestTimeout time.Duration

    // PerAttemptTimeout bounds the time to receive response headers per
    // HTTP attempt. Stopped on success so body reads use RequestTimeout.
    // Default: 60s.
    PerAttemptTimeout time.Duration

    // MaxDownloadSize is the maximum response body size for Read().
    // Run() uses a fixed 16 MB decode limit; List() and Exists() use a
    // fixed 8 MB internal limit. Default: 256 MB.
    MaxDownloadSize int64

    // MaxUploadSize is the maximum content size for Write() and WriteReader().
    // Write rejects oversized content before network I/O; WriteReader enforces
    // the limit while streaming. Default: 256 MB.
    MaxUploadSize int64

    // Logger for structured logging. Defaults to stderr at INFO level.
    // Provide a custom logr.Logger for full control, or set Quiet to
    // suppress output.
    Logger logr.Logger

    // Quiet suppresses the default stderr logger. Has no effect when a
    // custom Logger is provided (non-zero-value).
    Quiet bool

    // K8sHelper provides pre-constructed Kubernetes clients. If nil, a new
    // K8sHelper is created from RestConfig. Use this to share clients
    // across multiple Sandbox instances.
    K8sHelper *K8sHelper

    // RestConfig overrides the Kubernetes REST config. If nil, the client first
    // tries in-cluster config (for pods), then falls back to the default
    // kubeconfig (~/.kube/config or KUBECONFIG env). Ignored when K8sHelper is set.
    RestConfig *rest.Config

    // HTTPTransport overrides the HTTP transport for sandbox operations.
    // If nil, a default transport with sensible timeouts is created.
    // Use this for custom TLS, proxies, or other transport-level settings.
    HTTPTransport http.RoundTripper

    // TraceServiceName is the OpenTelemetry service name used for the tracer's
    // instrumentation scope and the resource's service.name attribute.
    // Default: "sandbox-client".
    TraceServiceName string

    // TracerProvider sets the OpenTelemetry TracerProvider for span creation.
    // If nil, falls back to otel.GetTracerProvider (noop by default).
    TracerProvider trace.TracerProvider

    // DisablePodIPRouting suppresses the X-Sandbox-Pod-IP header even when a
    // pod IP is available. Use in environments with strict network policies,
    // service meshes, or secure overlays where direct pod-to-pod IP routing is
    // restricted but service-based DNS routing works correctly.
    // Note: this only affects router-based transports that send X-Sandbox-* headers.
    // Default: false (header is sent when router headers are enabled and a pod IP is present).
    DisablePodIPRouting bool
}

type Runtime

Runtime identifies the in-sandbox runtime API the SDK speaks.

type Runtime string

const (
    // RuntimeLegacyPython is the python-runtime HTTP API (POST /upload,
    // GET /download|list|exists/{path}, POST /execute on port 8888),
    // reached through the sandbox-router. Default.
    RuntimeLegacyPython Runtime = "legacy-python"
    // RuntimeSandboxd is the sandboxd hybrid API defined by KEP-539.2:
    // REST filesystem (/v1/files/...) on port 8080 plus gRPC
    // ProcessService on port 9090. The SDK connects over a pod port-forward
    // to the sandbox pod.
    RuntimeSandboxd Runtime = "sandboxd"
)

type Sandbox

Sandbox manages the lifecycle of a single agent-sandbox instance. Operations are split across Commands and Files.

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

func New

func New(_ context.Context, opts Options) (*Sandbox, error)

New creates a new Sandbox with the given options. Call Open() to create a sandbox and establish connectivity.

func (*Sandbox) Annotations

func (s *Sandbox) Annotations() map[string]string

func (*Sandbox) ClaimName

func (s *Sandbox) ClaimName() string

func (*Sandbox) Close

func (s *Sandbox) Close(ctx context.Context) error

Close deletes the SandboxClaim and cleans up resources.

func (*Sandbox) Commands

func (s *Sandbox) Commands() *Commands

Commands returns the command execution sub-object.

func (*Sandbox) Delete

func (s *Sandbox) Delete(ctx context.Context, path string, recursive bool, opts ...CallOption) error

Delete removes a file or directory (sandboxd runtime only; the legacy python-runtime returns ErrUnsupportedByRuntime). Not part of the Handle interface to avoid breaking existing implementers.

func (*Sandbox) Disconnect

func (s *Sandbox) Disconnect(ctx context.Context) error

Disconnect closes the transport connection without deleting the SandboxClaim. The sandbox stays alive on the server. Call Open() to reconnect. Disconnect is safe to call concurrently with Open; an in-progress Open is cancelled before the transport is torn down.

func (*Sandbox) Exists

func (s *Sandbox) Exists(ctx context.Context, path string, opts ...CallOption) (bool, error)

func (*Sandbox) Files

func (s *Sandbox) Files() *Files

Files returns the file operations sub-object.

func (*Sandbox) IsReady

func (s *Sandbox) IsReady() bool

IsReady returns true if the sandbox is ready for communication.

func (*Sandbox) List

func (s *Sandbox) List(ctx context.Context, path string, opts ...CallOption) ([]FileEntry, error)

func (*Sandbox) Open

func (s *Sandbox) Open(ctx context.Context) (retErr error)

Open creates a SandboxClaim and waits for the sandbox to become ready, then discovers the API URL based on the configured connection mode. On failure after claim creation, the claim is automatically deleted; if deletion also fails, call Close() to retry.

func (*Sandbox) PodIP

func (s *Sandbox) PodIP() string

func (*Sandbox) PodName

func (s *Sandbox) PodName() string

func (*Sandbox) Read

func (s *Sandbox) Read(ctx context.Context, path string, opts ...CallOption) ([]byte, error)

func (*Sandbox) Run

func (s *Sandbox) Run(ctx context.Context, command string, opts ...CallOption) (*ExecutionResult, error)

func (*Sandbox) SandboxName

func (s *Sandbox) SandboxName() string

func (*Sandbox) Write

func (s *Sandbox) Write(ctx context.Context, path string, content []byte, opts ...CallOption) error

func (*Sandbox) WriteReader

func (s *Sandbox) WriteReader(ctx context.Context, path string, content io.Reader, opts ...CallOption) error

WriteReader streams content from an io.Reader without buffering the entire payload. Streaming uploads use a single request attempt because a generic reader cannot be replayed safely. Passing WithMaxAttempts with a value greater than 1 returns an error; it is not silently reduced to one attempt.

Generated by gomarkdoc

Last modified July 17, 2026: add go and python docs (#780) (e255c39)