pkg

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: BSD-2-Clause Imports: 9 Imported by: 0

Documentation

Overview

Package pkg holds the controller's backend-independent control API: the request and response shapes a caller speaks over A2A, and the single interface every backend implements. Nothing in this package names a backend — that is the point of it.

Index

Constants

View Source
const A2APath = "/a2a"

A2APath is the route the A2A JSON-RPC binding is served at.

View Source
const AgentCardPath = a2asrv.WellKnownAgentCardPath

AgentCardPath is the well-known path the Agent Card is served at, as the A2A spec defines it. It is the SDK's own constant, re-exported so the service's wiring reads both A2A routes from one place.

Variables

This section is empty.

Functions

func NewA2AExecutor added in v0.2.0

func NewA2AExecutor(provider BackendProvider, backend Backend) a2asrv.AgentExecutor

NewA2AExecutor creates the A2A executor for the control API.

provider resolves a backend name to the WorkerBackend that serves it; backend is the name the controller was configured with. Both are injected — the executor reads no global and no environment — so the same executor serves any backend, and a test drives it with a stub through the real selection wiring.

func NewA2AHandler added in v0.2.0

func NewA2AHandler(executor a2asrv.AgentExecutor) http.Handler

NewA2AHandler serves the A2A JSON-RPC binding over the given executor. The body is capped before the SDK handler sees it.

func NewAgentCard added in v0.2.0

func NewAgentCard(config AgentCardConfig) *a2a.AgentCard

NewAgentCard builds the Agent Card this service advertises. Its single supported interface is the JSON-RPC binding at config.PublicURL, which is the externally reachable address supplied as configuration — never the listen address and never a value derived from a request. The card carries no credential.

func NewAgentCardHandler added in v0.2.0

func NewAgentCardHandler(card *a2a.AgentCard) http.Handler

NewAgentCardHandler serves the Agent Card. The card is public by design: it advertises the endpoint and skills and carries no credential.

Types

type AgentCardConfig added in v0.2.0

type AgentCardConfig struct {
	// Name names the deployed agent in the Agent Card.
	Name string
	// PublicURL is the externally reachable A2A endpoint the card advertises verbatim.
	// It is never derived from the listen address or a request header.
	PublicURL string
}

AgentCardConfig is what the A2A Agent Card advertises about this service.

type Backend

type Backend string

Backend names the implementation that serves workers. Its value space belongs to the backend implementations and to the selection wiring, never to this schema: a constant naming a backend here would put that backend's identity above the seam this package exists to hold, and a second backend would have to edit the shared schema to become selectable.

const (
	// BackendDocker runs each worker as a container on the local host.
	BackendDocker Backend = "docker"
	// BackendKubernetes runs each worker as a workload in the cluster.
	BackendKubernetes Backend = "k8s"
)

The backend names. They live here and nowhere else: this file is the one place above the seam that names a backend, so a backend becomes selectable by editing this selection wiring alone. The shared schema (types.go) names none of them, which is what keeps a backend's identity from becoming part of the control API.

type BackendProvider added in v0.2.0

type BackendProvider interface {
	// Get returns the backend serving the named backend, or an error when the name is
	// not one the controller knows or its implementation is not wired.
	Get(ctx context.Context, backend Backend) (WorkerBackend, error)
}

BackendProvider resolves a backend name to the WorkerBackend that serves it.

func NewBackendProvider added in v0.2.0

func NewBackendProvider(docker WorkerBackend, kubernetes WorkerBackend) BackendProvider

NewBackendProvider creates the backend selection wiring.

docker and kubernetes are the implementations of the two backends the controller supports, in the order their names are declared above. Either may be nil while its implementation is not yet wired; Get then refuses that backend rather than handing back a nil seam that would fail on first use.

type ControlRequest

type ControlRequest struct {
	Operation Operation `json:"operation"`
	// Create is set when Operation is OperationCreate.
	Create *CreateRequest `json:"create,omitempty"`
	// Stop is set when Operation is OperationStop.
	Stop *StopRequest `json:"stop,omitempty"`
}

ControlRequest is one control-API call. Exactly one operation-specific field is set and it matches Operation; a request that sets none, or more than one, is refused rather than guessed at.

type ControlResponse

type ControlResponse struct {
	Operation Operation       `json:"operation"`
	Create    *CreateResponse `json:"create,omitempty"`
	List      *ListResponse   `json:"list,omitempty"`
	Stop      *StopResponse   `json:"stop,omitempty"`
}

ControlResponse is the controller's reply to one ControlRequest. Exactly one operation-specific field is set and it matches Operation.

type CreateRequest

type CreateRequest struct {
	Task TaskName `json:"task"`
}

CreateRequest asks for a worker serving one task.

type CreateResponse

type CreateResponse struct {
	Worker Worker `json:"worker"`
	// Token is the worker's own bearer credential. It must never be logged, echoed into a
	// transcript, or written to a file.
	Token string `json:"token"`
}

CreateResponse is the reply to a create. It is the only place a worker's token is ever returned: the controller keeps no copy it depends on, so a caller that loses this reply stops the worker and creates another rather than asking the controller to repeat it.

type ListResponse

type ListResponse struct {
	Workers []Worker `json:"workers"`
}

ListResponse is the reply to a list.

type Operation

type Operation string

Operation names one control-API operation. It travels as a plain string so a caller written against this schema needs no shared Go type to address the controller.

const (
	// OperationCreate asks the controller for a worker serving one task.
	OperationCreate Operation = "create"
	// OperationList asks the controller for every worker it owns.
	OperationList Operation = "list"
	// OperationStop asks the controller to stop and remove one worker.
	OperationStop Operation = "stop"
)

type StopRequest

type StopRequest struct {
	WorkerID WorkerID `json:"worker_id"`
}

StopRequest names the worker to stop and remove.

type StopResponse

type StopResponse struct {
	Worker Worker `json:"worker"`
}

StopResponse is the reply to a stop. It carries the stopped worker so a caller can confirm which one the controller acted on.

type StubWorkerBackend added in v0.2.0

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

StubWorkerBackend is a throwaway in-memory WorkerBackend. It exists for two reasons.

It makes the executor testable with no container, no cluster and no credential: a test drives the real executor and the real selection wiring against it. And it is the second implementation of WorkerBackend, which is what proves the seam — the executor drives it through the same interface it drives a real backend through, without knowing which one it holds.

It is absent from the selection wiring in backend-provider.go: no Backend value resolves to it. It is therefore reachable only by tests and by explicit construction, and can never serve a production request.

func NewStubWorkerBackend added in v0.2.0

func NewStubWorkerBackend() *StubWorkerBackend

NewStubWorkerBackend creates an empty in-memory backend.

func (*StubWorkerBackend) Create added in v0.2.0

Create records a worker for the requested task and returns it with a token derived from its id. A task that already has a worker returns the existing one, matching the contract the real backends keep, so a repeated create never starts a second worker.

func (*StubWorkerBackend) List added in v0.2.0

List returns every worker the stub holds, in no particular order.

func (*StubWorkerBackend) Stop added in v0.2.0

Stop removes the named worker and returns it, reporting it as stopped. A worker the stub does not hold is refused rather than silently ignored.

type TaskName

type TaskName string

TaskName is the vault task a worker serves. It names the work, not the worker — a task has at most one worker, and a second create for a task that already has one returns the existing worker rather than starting another.

type Worker

type Worker struct {
	WorkerID WorkerID    `json:"worker_id"`
	Task     TaskName    `json:"task"`
	A2AURL   string      `json:"a2a_url"`
	Backend  Backend     `json:"backend"`
	State    WorkerState `json:"state"`
}

Worker is one worker as the control API reports it. It deliberately carries no token: a worker's token is returned once by create and never again, so no listing, no log and no restart can leak one.

type WorkerBackend added in v0.2.0

type WorkerBackend interface {
	// Create starts one worker serving the requested task and returns it together with
	// its own bearer token. A task that already has a worker returns the existing one
	// rather than starting a second.
	Create(ctx context.Context, req CreateRequest) (*CreateResponse, error)

	// List returns every worker the backend owns. It is rebuilt from the backend's own
	// resource state on every call, never from controller memory, so a controller
	// restart loses nothing.
	List(ctx context.Context) (*ListResponse, error)

	// Stop stops and removes the named worker and returns it.
	Stop(ctx context.Context, req StopRequest) (*StopResponse, error)
}

WorkerBackend is the single seam every backend implements. It is expressible with the control-API schema alone: it takes the schema's request shapes and returns its response shapes, so nothing above the seam names a backend and a new backend needs no change to the schema, to the executor or to the HTTP surface.

type WorkerID

type WorkerID string

WorkerID identifies one worker the controller created. It is the value a caller passes back to stop a worker and the value list reports, so it stays stable across a controller restart: it is read back from the worker's own labels rather than minted per request and held in memory.

type WorkerState

type WorkerState string

WorkerState is what list reports about a worker's lifecycle.

const (
	// WorkerStateRunning means the worker exists and answers on its own A2A URL.
	WorkerStateRunning WorkerState = "running"
	// WorkerStateStopped means the worker no longer exists. It appears only in the reply to
	// the stop that removed it; list never returns it.
	WorkerStateStopped WorkerState = "stopped"
	// WorkerStateUnknown means the worker's backing resource exists but the controller
	// cannot classify it, so a caller must not read it as running.
	WorkerStateUnknown WorkerState = "unknown"
)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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