Documentation
¶
Overview ¶
Package workersdk is the client half of the Worker protocol: leasing jobs of named types from a running atlas, reporting how each ended, answering the form lookups a Worker Type serves, and asking before acting where the server governs the Worker (ADR-0007, ADR-0168, ADR-0473, ADR-0475).
It is the seed of the Worker SDK of ADR-0535: what a Worker Type built outside this repository depends on. That is why it imports nothing of the engine — not job, not state, not compiler — and a test holds it to that (sdk_deps_test.go). The built-in Worker Types in package worker are written against it; package worker keeps its old names as aliases, so nothing that worked against worker.New stops working.
The contract for a model-authored job type's code is the one the script worker established: the job arrives as JSON on stdin, and whatever JSON object the command writes to stdout becomes the variables the job completes with (CmdExec). A non-zero exit fails the job, carrying the command's stderr as the message an operator reads on the incident.
Index ¶
- Constants
- Variables
- func DefaultRetryBackoff(retriesLeft int32) int64
- func DocumentID(v any) string
- func Refused() error
- func UploadDocument(ctx context.Context, name, contentType string, data []byte) (map[string]any, error)
- type Authorization
- type BPMNError
- type CmdExec
- type CompletingExec
- type CompletingExecFunc
- type ConfiguredWorker
- type ConnectorPayload
- type DecisionReport
- type Document
- type Exec
- type ExecFunc
- type Identity
- type Job
- type Options
- type Outcome
- type QueryFunc
- type ToolCallReport
- type Worker
- func (w *Worker) AnswerQueriesOnce(ctx context.Context, wait time.Duration) error
- func (w *Worker) AuthorizingContext(ctx context.Context, j Job) context.Context
- func (w *Worker) DocumentContext(ctx context.Context, j Job) context.Context
- func (w *Worker) Run(ctx context.Context) error
- func (w *Worker) RunOnce(ctx context.Context) error
Constants ¶
const ( // EnvServer is the base URL of the atlas the instance works for. EnvServer = "ATLAS_SERVER_URL" // EnvWorkerID is the instance's id in the Workers view. EnvWorkerID = "ATLAS_WORKER_ID" // EnvToken is the bearer credential the instance authenticates with. EnvToken = "ATLAS_TOKEN" // EnvTypeID, EnvTypeVersion and EnvTypeDigest are the installed release the // supervisor verified before it started this process: the handshake's identity. EnvTypeID = "ATLAS_WORKER_TYPE_ID" EnvTypeVersion = "ATLAS_WORKER_TYPE_VERSION" EnvTypeDigest = "ATLAS_WORKER_TYPE_DIGEST" // EnvConfig is the instance's configured Workers as JSON, // {"workers":[{"name":"…","config":{…}}]}: each configuration with its secrets // resolved and checked against the Worker Type's schema (ADR-0535 §4). Absent when // nothing is configured. EnvConfig = "ATLAS_WORKER_CONFIG" )
The launch contract: what atlas hands a Worker Type executable it launches from an installed artifact (ADR-0535 §2). The executable is started with no arguments and this environment, and nothing else of the server's; it reads its own configuration from what it is given here and from the Worker protocol.
const ( DefaultLease = 5 * time.Minute DefaultWait = 30 * time.Second DefaultMaxJobs = 1 DefaultRetry = 5 * time.Second // DefaultMaxQueries is higher than DefaultMaxJobs on purpose: a query is one short // read that a person is waiting on, and a second person searching should not wait // for the first. DefaultMaxQueries = 4 )
Defaults, chosen so an unconfigured worker is safe rather than surprising: it takes one job at a time, holds it for five minutes, and parks for thirty seconds per poll.
const EventPollFailed = "worker.poll_failed"
EventPollFailed is the event name the worker's own warnings carry under the key "event": a poll that failed and will be retried, or a query answer the server did not take. It is atlas's registered event worker.poll_failed (ADR-0142); a test in package worker holds the two equal, because this package may not import atlas's catalogue.
const ProtocolVersion = 1
ProtocolVersion is the major version of the Worker protocol this client speaks (docs/contracts/worker-protocol). It is sent on every poll; a server that does not accept it refuses the poll with 400, naming the versions it does accept, and the worker logs that and keeps retrying, so an upgrade of either side is visible rather than silent.
Variables ¶
var ErrNoDocuments = errors.New("workersdk: no document access here: documents are read and stored for a job a worker runs")
ErrNoDocuments is what ReadDocument and UploadDocument answer outside a job a worker runs — a handler called directly in a test, say — where there is no lease to read under and no server to store to.
Functions ¶
func DefaultRetryBackoff ¶
DefaultRetryBackoff is the delay the server's in-process runner waits before it retries a failed job (ADR-0111, amendment 2026-11-04): a job with one retry left waits a minute, one with more left waits fifteen seconds, one with none raises its incident at once. It is the server's policy restated here, because this package may not import the runner that owns it; a test in package worker holds the two equal.
func DocumentID ¶
DocumentID returns the id a value names when it is a document reference, and "" for anything else: a decoded JSON object or its JSON text.
Types ¶
type Authorization ¶
type Authorization struct {
// Enforcement is "off" for a Worker without an identity policy, else "shadow" or
// "enforce".
Enforcement string `json:"enforcement"`
Permitted bool `json:"permitted"`
Enforced bool `json:"enforced"`
ReasonCode string `json:"reasonCode"`
DecisionKey uint64 `json:"decisionKey"`
// Job is the parameters the decision covers. A handler acts on these and not on
// what it was handed at lease time.
Job map[string]any `json:"job"`
Credential *struct {
Type string `json:"type"`
AccessToken string `json:"accessToken"`
ExpiresAt int64 `json:"expiresAt"`
} `json:"credential"`
}
Authorization is the server's answer.
func Authorize ¶
func Authorize(ctx context.Context) (*Authorization, error)
Authorize asks the server whether the job in ctx may act. It returns nil, nil when there is nobody to ask — a handler run outside a worker, or against a server built before this step existed — which a handler treats as the legacy answer.
func (*Authorization) Governed ¶
func (a *Authorization) Governed() bool
Governed reports whether the answer came from a decision at all.
type BPMNError ¶
BPMNError is how a handler ends a job in a BPMN error instead of a result (ADR-0089): return one — wrapped or not — and the worker throws Code rather than failing the job. An error boundary or error event subprocess matching Code catches it and the instance takes the error path, with no retry spent. With none in reach the job waits on an incident naming Code and Message until an operator resolves it.
It is for an answer the process has a path for — a card declined, a recipient that does not exist — not for a fault: anything else a handler returns fails the job and is retried as before.
The engine's in-process runner uses this same type under its own name (job.BPMNError is an alias of it), so a handler shared by both paths — a script task's run — throws the same error on either. It is defined here rather than there because this package may depend on nothing of the engine.
type CmdExec ¶
type CmdExec struct {
Name string
Args []string
// Env is added to the process's own environment.
Env []string
}
CmdExec runs an operating-system command per job: the job arrives as JSON on stdin, and the JSON object the command writes to stdout becomes the variables the job completes with (no output completes with none). A non-zero exit fails the job and carries the command's stderr, which is what an operator reads on the incident.
type CompletingExec ¶
CompletingExec is the widest exec shape: work that completes with more than variables. Exec is the decision-less special case, and the ladder is deliberately the one the job package already has (Handler / OutputHandler / CompletingHandler) so the two sides of the protocol are described the same way.
A handler implementing both is used as a CompletingExec.
type CompletingExecFunc ¶
CompletingExecFunc adapts a function to CompletingExec.
func (CompletingExecFunc) Run ¶
Run implements Exec by discarding the decision half, so a CompletingExecFunc can stand wherever an Exec is required.
func (CompletingExecFunc) RunCompleting ¶
RunCompleting implements CompletingExec.
type ConfiguredWorker ¶
ConfiguredWorker is one configured Worker an instance serves.
func LaunchConfig ¶
func LaunchConfig(getenv func(string) string) ([]ConfiguredWorker, error)
LaunchConfig reads the configured Workers of the launch contract from getenv. None configured is an empty list, not an error; a value that is not the contract's shape is an error, because serving on a misread configuration is worse than not starting.
type ConnectorPayload ¶
ConnectorPayload is a resolved task: what to do, with no engine concepts in it.
type DecisionReport ¶
type DecisionReport struct {
DecisionID string `json:"decisionId"`
Inputs map[string]any `json:"inputs,omitempty"`
Outputs map[string]any `json:"outputs,omitempty"`
Trace string `json:"trace,omitempty"`
}
DecisionReport is a worker's account of a decision it evaluated: which decision, the inputs it was handed, the outputs it got and the service's trace.
It is an account, not a record. The engine stamps which element instance it belongs to from the job's own lease, so a report cannot attach itself to a task other than the one it holds.
type Document ¶
Document describes a document read with ReadDocument.
type Exec ¶
Exec does one job's work and returns the variables it completed with, or an error that fails the job.
type Identity ¶
type Identity struct {
ID string `json:"id"`
Version string `json:"version"`
Digest string `json:"digest,omitempty"`
}
Identity names a Worker Type the way its manifest does: a stable reverse-DNS id, a semantic version, and the sha256 digest of the artifact when the instance knows it ("sha256:" and 64 hex digits).
type Job ¶
type Job struct {
JobKey uint64 `json:"jobKey"`
Type string `json:"type"`
ProcessInstanceKey uint64 `json:"processInstanceKey"`
ElementInstanceKey uint64 `json:"elementInstanceKey"`
ProcessDefKey uint64 `json:"processDefKey"`
ElementID string `json:"elementId"`
Retries int32 `json:"retries"`
LeaseToken uint64 `json:"leaseToken"`
// IdempotencyKey is the same for every delivery of this task execution and
// unique to it: hand it to a target that filters duplicates, or check by it before
// acting, so a job delivered twice does its effect once.
IdempotencyKey string `json:"idempotencyKey"`
Variables map[string]any `json:"variables"`
// Worker is a task the engine resolved into plain values, present
// only for a kind the server no longer serves itself (ADR-0168). Nil for a plain
// job-worker task, whose work is the customer's own command.
Connector *ConnectorPayload `json:"connector,omitempty"`
}
Job is one leased job as the engine hands it over.
type Options ¶
type Options struct {
// Server is the base URL of the Atlas to work for, e.g. http://localhost:8080.
Server string
// ID names this worker. It rides on every lease and every report, and it is what
// the Workers view shows — so give each deployment its own.
ID string
// Token, when set, is sent as a bearer credential on every request.
Token string
// BrokerKey, when set, is presented when this worker asks whether it may act
// (Authorize). A server supervising this worker hands it over (ATLAS_BROKER_KEY)
// only to the process serving a Worker whose credential it brokers per job; without
// it, the server releases no person's token to this process.
BrokerKey string
// Handlers is what this worker serves, keyed by job type. A worker with none is a
// misconfiguration rather than a process that polls forever over nothing.
Handlers map[string]Exec
// Lease is how long the engine holds a job for this worker. It must comfortably
// exceed how long the work takes: an elapsed lease puts the job back on offer, and
// the report that finally arrives is fenced out.
Lease time.Duration
// Wait is how long a poll may block waiting for work before coming back empty.
Wait time.Duration
// Retry is how long to wait after a failed poll before trying again. A worker
// must not exit because the server was restarting, or because the process using
// its job type is not deployed yet — both are ordinary and both resolve.
Retry time.Duration
// MaxJobs is how many jobs of one type this worker runs at once. A poll leases
// only as many as there are free places for, so every leased job starts the
// moment it arrives: leased work nobody is running is work nobody else can take
// either, and its lease runs down while it waits (ADR-0440).
MaxJobs int
// Workers are the worker names this worker holds credentials for, reported
// to the engine on every poll. Only the worker knows them — once a kind is
// offloaded the engine holds no credential for it — and the Workers view
// subtracts them from what deployed models reference to show which names are
// configured nowhere (ADR-0168). Empty for a worker that serves only plain job
// types, which need no credential of their own.
Connectors []string
// Endpoints are where those workers connect, reduced to scheme, host and port and
// keyed by worker name — what lets an architecture sketch draw the system a worker
// reaches when the engine holds no configuration for it (ADR-0471). Reported beside
// Connectors on every poll; a name with no entry is drawn as holding its endpoint
// itself.
Endpoints map[string]string
// Queries are the form lookups this worker answers, keyed by the job type of the
// Worker Type answering them (ADR-0473). A query is not a
// job: nothing about it is durable, and it is polled on a path of its own beside the
// job poll, under the same identity and for the same Workers.
Queries map[string]QueryFunc
// MaxQueries is how many queries of one type this worker answers at once.
MaxQueries int
// RetryBackoff is how long a job this worker failed waits before it is offered
// again, given the attempts it has left after the failure, in nanoseconds; nil means
// [DefaultRetryBackoff], the delay the server's in-process runner waits too
// (ADR-0111, amendment 2026-11-04). A Worker Type that runs out here meets the same
// replication delays as one that runs inside the server — a group Microsoft Graph
// created a moment earlier is not yet found — so it waits as long before it raises
// an incident. NoRetryBackoff retries at once.
RetryBackoff func(retriesLeft int32) int64
// NoRetryBackoff offers a failed job again at once, as before the amendment; tests
// that drive a failing job to its incident use it.
NoRetryBackoff bool
// HTTP is the client to use; nil means a default one bounded by Lease + Wait.
HTTP *http.Client
// Identity is the Worker Type this instance runs, reported on every poll as part of
// the protocol handshake (ADR-0535 §3) and shown in the server's Workers view. Nil
// reports none, which a server accepts: an instance an operator runs by hand may
// not be a packaged Worker Type at all.
Identity *Identity
// Logger receives the few lines the worker writes itself — a poll that failed and
// will be retried, a query answer the server did not take. Each carries the event
// name under the key "event" ([EventPollFailed]), so an operator can alert on it
// whatever logger a Worker Type uses. Nil means [slog.Default]; atlas's own worker
// leaves it nil, so these lines go through the handler `atlas worker` installs.
Logger *slog.Logger
}
Options configures a Worker.
type Outcome ¶
type Outcome struct {
Variables map[string]any
Decision *DecisionReport
// ToolCalls is a worker's account of what an agent chose to run next
// (ADR-0253/ADR-0254). It is the second thing in the sentence above: a round's
// answer is usually not variables at all, it is a choice of activities, and a
// worker deciding the round is the only one who knows what the model said.
//
// Empty is an answer, not an omission — the agent saying the run is finished —
// so a round that ends completes with variables like any other job.
ToolCalls []ToolCallReport
}
Outcome is everything a job's work produced: the variables it completes with, and — for a central business rule task — the decision evaluation to retain.
It mirrors the in-process runner's job.Completion, and for the same reason: a decision's record is durable (ADR-0066), so once the evaluation happens on a worker the worker has to be able to report it. Every other kind completes with variables alone, which is why Exec stays the ordinary shape.
func RunHandler ¶
RunHandler runs one job through whichever shape its handler implements. A handler that only knows variables is the ordinary case and stays untouched; one that can report a decision is asked for the wider outcome. The worker calls it for every job; it is exported so a Worker Type can test its handler through the same door.
type QueryFunc ¶
QueryFunc answers one form lookup for the Worker named connector: a page of records or the *lookup.Error it failed with (ADR-0473). Any other error is reported as the provider being unavailable — and only as that, because an error's text is the one place a search term could leave this process.
type ToolCallReport ¶
type ToolCallReport struct {
Tool string `json:"tool"`
CallId string `json:"callId,omitempty"`
Arguments map[string]any `json:"arguments,omitempty"`
}
ToolCallReport is a worker's account of one tool an agent chose for the next round: which of the container's tools to run, the model's own id for the call, and the arguments it supplied for that tool's declared parameters.
Like a DecisionReport it is an account, not a record — and the difference matters more here, because a tool call does not describe work that happened, it *causes* work to happen. So the engine reads which container this is from the leased job, and resolves Tool against that container's compiled tool index before anything is activated. A worker cannot name an activity the model does not carry and have it run; naming one it does not carry raises the incident ADR-0253 already defines.
type Worker ¶
type Worker struct {
// contains filtered or unexported fields
}
Worker leases jobs of the types it handles and reports what happened. Build one with New.
func (*Worker) AnswerQueriesOnce ¶
AnswerQueriesOnce polls every query type once, waiting up to wait for a query, and answers whatever it is given before it returns. It is what a test drives; a zero wait is an idle poll, which makes this worker present for its Workers.
func (*Worker) AuthorizingContext ¶
AuthorizingContext puts the question for j within reach of its handler: Authorize called with the context it returns asks the server about j. The worker does this for every job it runs; it is exported so a handler run outside the poll loop — in a Worker Type's own test — can be asked the same way.
func (*Worker) DocumentContext ¶
DocumentContext puts the document store within reach of j's handler. The worker does this for every job it runs; it is exported so a handler run outside the poll loop can be given the same access.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package lookup is the wire shape of a form lookup: what the server asks a Worker Type when a person searches a remote data source from a task form, and what the Worker Type answers (ADR-0473).
|
Package lookup is the wire shape of a form lookup: what the server asks a Worker Type when a person searches a remote data source from a task form, and what the Worker Type answers (ADR-0473). |