Documentation
¶
Overview ¶
Package agents dispatches one bounded coding task to one configured agent harness running inside an isolated WB worktree, and reports the execution facts of that run to whoever asks later.
It is deliberately the deterministic execution layer only: it resolves an agent profile, creates or resolves a worktree through WB's existing worktree service, launches the harness as a detached child, and records what happened. It never judges whether the work is correct. A PASS/FAIL/ESCALATE verdict on a diff is a semantic decision that belongs to the supervisor above WB, not to WB.
Index ¶
- Constants
- func BoundResult(message string) string
- func CodexArgv(options HarnessOptions) ([]string, error)
- func IsRequestError(err error) bool
- func IsUnknownAgent(err error) bool
- func LoadRemoteTargets(configPath string) (map[string]RemoteTarget, error)
- func NewID() (string, error)
- func NormalizeState(result *Result)
- func OwnerCLI(arguments []string, deps OwnerDeps) int
- func ReadCredentialFile(path string) (string, error)
- func RecentActions(reader io.Reader, limit int) []string
- func RunOwner(ctx context.Context, store Store, agentID string, deps OwnerDeps) error
- func SpawnOwner(runDir string, executable func() (string, error)) (int, error)
- func SplitAgentRef(reference string) (machine, agentID string, err error)
- func StripAgentID(reference string) string
- func SummaryLine(task string) string
- func WorkerEnvironment(credential Credential) []string
- type ChangeSummary
- type Config
- type Credential
- type DispatchDeps
- type DispatchRequest
- type HarnessOptions
- type HarnessSummary
- type OwnerDeps
- type Profile
- type Provider
- type Record
- type RemoteDeps
- type RemoteRequest
- type RemoteResponse
- type RemoteTarget
- type RequestError
- type Resolved
- type Result
- type State
- type Store
- func (store Store) Create(record Record) error
- func (store Store) Dir(agentID string) string
- func (store Store) HarnessHomePath(agentID string) string
- func (store Store) LastMessagePath(agentID string) string
- func (store Store) List() ([]Record, error)
- func (store Store) Load(agentID string) (Record, error)
- func (store Store) LogPath(agentID string) string
- func (store Store) RecordPath(agentID string) string
- func (store Store) Render(record Record) Result
- func (store Store) Save(record Record) error
- type UnknownAgentError
- type Usage
Constants ¶
const ( ModeNew = "new" ModeExisting = "existing" )
Worktree modes. Exactly one is required: creating a new isolated workspace and modifying an existing one have materially different intent, so they stay two explicit options rather than one ambiguous --worktree.
const ( WireAPIResponses = "responses" WireAPIChat = "chat" )
Wire protocols the Codex harness can speak. The set is closed because it is the harness's own contract, not a user extension point.
const ( RemoteDispatch = "dispatch" RemoteStatus = "status" RemoteAwait = "await" RemoteList = "list" RemoteLogs = "logs" RemoteStop = "stop" )
Remote operations, one per local command that can address another machine.
const ( DefaultRemoteTimeout = 10 * time.Minute // MaxRemoteLogBytes bounds a remote transcript fetch. `wb agent logs --raw` // over a link is the one operation that could pull an entire run into a // caller's context, so it is refused past this rather than truncated. MaxRemoteLogBytes = 2 << 20 )
Remote bounds and limits. A remote reply is a small protocol document, so the caps are generous for it and deliberately not generous for a transcript.
const DefaultTimeout = 30 * time.Minute
DefaultTimeout bounds a dispatched run when the caller names no bound.
const DirName = "agents"
DirName is the directory under WB's home that holds dispatched agent runs.
const HarnessCodex = "codex"
Harness names a coding-agent environment and tool loop. The MVP supports exactly one; the field exists so provider and model are not collapsed into the harness name.
const IDPrefix = "agt-"
IDPrefix begins every agent run ID. The shape follows WB's existing random session-ID convention rather than a timestamp, so an ID never encodes — and therefore never leaks — when or where the work happened.
const OwnerArgument = "--wb-internal-agent-run"
OwnerArgument selects the private, detached run-owner command. It is handled before normal command dispatch, following WB's existing self-exec convention for internal child processes: the dispatching process re-invokes its own executable with this argument rather than depending on a daemon.
const ProviderCredentialEnv = "WB_AGENT_PROVIDER_CREDENTIAL"
ProviderCredentialEnv is the environment variable WB synthesises when a provider supplies its credential as a file. The harness is told this name — never a value — so the same per-process mechanism serves both sources.
const RemoteArgument = "--wb-internal-agent-remote"
RemoteArgument selects the private remote entry point. It is handled before normal command dispatch on the target machine, so the request can only be a validated protocol value read from stdin — never text the remote shell parsed.
Variables ¶
This section is empty.
Functions ¶
func BoundResult ¶
BoundResult trims the worker's final message so the one free-text artefact of a run cannot become the transcript it exists to replace.
func CodexArgv ¶
func CodexArgv(options HarnessOptions) ([]string, error)
CodexArgv builds the exact non-interactive Codex invocation.
The task is deliberately absent: it is delivered on stdin (a trailing "-"), so task text never appears in the process table. Values are JSON-encoded because the harness parses each override value as TOML, where a bare word and a quoted string are different things.
func IsRequestError ¶
IsRequestError reports whether an error refused the invocation.
func IsUnknownAgent ¶
IsUnknownAgent reports whether an error is a lookup miss rather than a corrupt record. A miss is a finding — the invocation was admitted and the named run does not exist — so the CLI can use the findings exit code instead of pretending the caller mistyped.
func LoadRemoteTargets ¶
func LoadRemoteTargets(configPath string) (map[string]RemoteTarget, error)
LoadRemoteTargets reads the configured machines WB may dispatch to.
It reuses WB's session_move target map on purpose. A machine and its courier address are one fact about the fleet; a second list would be a second place to be wrong, and the operator would have to keep them in step by hand.
func NormalizeState ¶
func NormalizeState(result *Result)
NormalizeState makes this process's closed state vocabulary authoritative for a result that arrived from somewhere else. A remote answer carries a state; whether that state is terminal is WB's rule, so it is derived here rather than trusted from the wire, where a version skew could disagree.
func OwnerCLI ¶
OwnerCLI runs the private owner command line:
wb --wb-internal-agent-run --run-dir <absolute run directory>
It is called from main before cobra parses anything, so the owner can never be affected by, or accidentally honour, a user-facing flag contract.
func ReadCredentialFile ¶
ReadCredentialFile reads a credential file, refusing anything that is not a private regular file WB itself would have written.
The permission check is deliberate: a credential readable by another account on the machine is not a credential, and discovering that at dispatch time is far better than discovering it in a log.
func RecentActions ¶
RecentActions condenses the harness event stream into the last few things the worker actually did. It exists so `wb agent logs` can show a human something useful without printing an entire run into a caller's context.
func RunOwner ¶
RunOwner executes one dispatched run to completion and records its terminal state. It is the process that outlives the dispatching CLI, so everything a later `status` or `await` can learn about the run is written here.
func SpawnOwner ¶
SpawnOwner starts the detached run owner for a persisted run and returns without waiting for it. The owner is this same WB executable re-invoked with the private owner argument, so a dispatched run needs no daemon and survives the dispatching CLI exiting.
func SplitAgentRef ¶
SplitAgentRef accepts either a bare agent run ID or the machine-qualified form a remote dispatch prints, so a supervisor can pass back exactly what it was given. An agent ID contains only the prefix and hexadecimal, so the colon is unambiguous.
func StripAgentID ¶
StripAgentID returns the bare run ID from a possibly machine-qualified reference.
func SummaryLine ¶
SummaryLine is the one-line non-sensitive description stored beside the private task so listings and cross-machine checks can name the work without republishing it.
func WorkerEnvironment ¶
func WorkerEnvironment(credential Credential) []string
WorkerEnvironment builds the child harness environment.
It is an allowlist, following WB's existing detached-worker convention: a delegated worker gets the variables it genuinely needs and nothing else. That is a stronger guarantee than any deny-list, because a secret this machine happens to export tomorrow is excluded by default rather than by pattern.
Neither a whole-environment copy nor an ambient-agent-variable inheritance is acceptable here: the first hands a model-driven process every credential on the machine, and the second would make a dispatched worker look like the parent session it must not disturb.
Types ¶
type ChangeSummary ¶
type ChangeSummary struct {
FilesChanged int `json:"files_changed"`
Files []string `json:"files,omitempty"`
Insertions int `json:"insertions,omitempty"`
Deletions int `json:"deletions,omitempty"`
Commits int `json:"commits,omitempty"`
Truncated bool `json:"files_truncated,omitempty"`
}
ChangeSummary is a cheap, deterministic description of what the worker left behind in its worktree.
func SummarizeChanges ¶
func SummarizeChanges(ctx context.Context, worktreeDir, baseSHA string) *ChangeSummary
SummarizeChanges derives a cheap, deterministic description of what a worker left behind in its worktree. It reads Git state only; it never reads file contents, so it cannot grow into a transcript and cannot be mistaken for a review of the change.
A failure to read Git state yields no summary rather than a failed run: the worktree is the artefact and a missing diff stat must not hide it.
type Config ¶
Config is the resolved user agent configuration.
func LoadConfigFile ¶
LoadConfigFile reads the agent configuration from a wb.yaml document. A missing file is not an error: it yields the built-in provider registry and no profiles, so "no such profile" stays the actionable message rather than "no such file".
type Credential ¶
Credential is a resolved provider credential: the environment variable name the harness must read it from, and the value WB injects under that name. The value never leaves the child's environment.
func ResolveCredential ¶
func ResolveCredential(provider Provider) (Credential, error)
ResolveCredential reads the credential a provider names, from whichever source that provider configured. It fails closed with a message naming the exact source, because a missing credential is the single most likely reason a dispatch cannot start.
type DispatchDeps ¶
type DispatchDeps struct {
ConfigPath string
LoadConfig func() (Config, error)
ProjectsRoot string
Home string
// BeforeCreate refreshes managed hooks in the canonical clones, exactly as
// `wb worktree create` does before it creates anything.
BeforeCreate func(repositories []string) error
// AfterCreate writes the checkout marker exactly as `wb worktree create`
// does after creation. It MUST be best-effort: a marker WB could not write
// does not make a checkout unusable.
AfterCreate func(repositories []string, results []worktrees.CreateResult)
// CreateWorktree, ListWorktrees, and OriginSlug default to WB's own
// worktree service. They are injectable only so the orchestration above them
// can be exercised without a live fleet; production never replaces them.
CreateWorktree func(context.Context, []string, worktrees.CreateOptions) ([]worktrees.CreateResult, error)
ListWorktrees func(context.Context, worktrees.ListOptions) ([]worktrees.ListResult, error)
OriginSlug func(context.Context, string) (string, error)
// SpawnOwner starts the detached run owner for a persisted run and returns
// its process ID. The PID is returned rather than left to the owner to
// record, so a record a later process reads always names the process that
// owns it — which is what makes "the owner is gone" conclusive evidence
// instead of a guess about a run that has not started yet.
SpawnOwner func(agentID string) (int, error)
Now func() time.Time
}
DispatchDeps are the seams dispatch needs from the command layer. Only the things internal/agents cannot know about — WB's CLI-layer worktree side effects, and how a detached owner is started — are injected; everything else is reused directly.
type DispatchRequest ¶
type DispatchRequest struct {
Mode string
Worktree string
Profile string
Task string
// Repository is owner/repository. Empty means "derive it from the invoking
// checkout's origin", exactly as `wb worktree create` does.
Repository string
// Branch and Base are optional pass-throughs to WB's existing worktree
// naming policy; empty leaves that policy in charge.
Branch string
Base string
Timeout time.Duration
}
DispatchRequest is one requested offload.
type HarnessOptions ¶
type HarnessOptions struct {
WorktreeDir string
Model string
Reasoning string
// ProviderName keys the provider registry entry, and Provider carries the
// routing. The credential itself is never here — only the environment
// variable name the harness must read it from.
ProviderName string
Provider Provider
// LastMessagePath asks the harness to write its final message there, which
// is the one bounded, non-transcript result channel.
LastMessagePath string
}
HarnessOptions is everything the Codex harness needs that is not in the process environment. It exists so every harness-specific flag and configuration-key spelling lives in exactly one file: a harness version change is a one-file change.
type HarnessSummary ¶
type HarnessSummary struct {
TurnCompleted bool
TurnFailed bool
Usage *Usage
ToolCalls int
Diagnostics []string
// MalformedLines counts lines that look like harness events but could not
// be decoded. Ordinary non-JSON lines are the harness's own stderr sharing
// the file and are expected; a malformed *event* is not, and must be
// retained as a diagnosis rather than silently dropped.
MalformedLines int
}
HarnessSummary is what the run owner extracts from the harness event stream. It is execution metadata only; it deliberately carries nothing that judges whether the work is correct.
func SummarizeEvents ¶
func SummarizeEvents(reader io.Reader) HarnessSummary
SummarizeEvents parses the harness's JSONL event stream.
type OwnerDeps ¶
type OwnerDeps struct {
// LookPath resolves the harness executable. Resolving it by name through
// PATH is what lets a test substitute a fake harness without a production
// override flag.
LookPath func(string) (string, error)
// Now is the clock, injected for deterministic tests.
Now func() time.Time
// Sleep is StopRun's grace-period poll seam, injected for deterministic
// tests. A test exercising a worker that ignores termination shrinks
// StopGrace/StopPollInterval instead of leaving Sleep real, because that
// path genuinely waits on a real OS process; every other test replaces
// Sleep with a recorder.
Sleep func(time.Duration)
// StopGrace and StopPollInterval configure StopRun's escalation wait.
// Both are struct fields, not package-level mutable vars, so a test
// cannot leave shared package state mutated for another test running in
// parallel. StopRun does not default a zero OwnerDeps -- every caller
// (production and test) builds on DefaultOwnerDeps, which already
// populates every field, so StopRun trusts deps as given.
StopGrace time.Duration
StopPollInterval time.Duration
}
OwnerDeps are the seams the run owner needs. They are injected so the whole owner can be exercised deterministically against a fake harness.
func DefaultOwnerDeps ¶
func DefaultOwnerDeps() OwnerDeps
DefaultOwnerDeps returns the production seams.
type Profile ¶
type Profile struct {
Harness string `yaml:"harness" json:"harness"`
Provider string `yaml:"provider" json:"provider"`
Model string `yaml:"model" json:"model"`
Reasoning string `yaml:"reasoning,omitempty" json:"reasoning,omitempty"`
}
Profile is a named agent execution configuration. It is intentionally this small: harness + provider + model + optional reasoning, and nothing else.
type Provider ¶
type Provider struct {
BaseURL string `yaml:"base_url" json:"base_url"`
// CredentialEnv is the *name* of the environment variable holding the
// credential. The value is read from the process environment at launch and
// never persisted.
CredentialEnv string `yaml:"credential_env,omitempty" json:"credential_env,omitempty"`
// CredentialFile is an absolute path to a private file holding the
// credential, following WB's existing credential-file convention (a path in
// configuration, the secret in a 0600 file under
// ~/.config/wb/credentials). It exists because a dispatched worker needs its
// credential in the harness's environment, and a remote machine reachable
// only over non-interactive SSH has no reliable place to export one.
CredentialFile string `yaml:"credential_file,omitempty" json:"credential_file,omitempty"`
WireAPI string `yaml:"wire_api" json:"wire_api"`
}
Provider is one entry in the provider registry: where inference lives, which environment variable carries its credential, and which wire protocol the harness must use. It never carries the credential itself.
type Record ¶
type Record struct {
SchemaVersion int `json:"schema_version"`
AgentID string `json:"agent_id"`
State State `json:"state"`
// RequestedProfile is what the caller asked for. Resolved is what actually
// ran; keeping both is what makes a later profile edit harmless.
RequestedProfile string `json:"requested_profile"`
Resolved Resolved `json:"resolved"`
// Task is the exact originating request. It is private: it is never
// rendered by status or await, only persisted here.
Task string `json:"task"`
// TaskSummary is a bounded, single-line form of Task for a human reading
// the record. It is derived from the task, so it is private for exactly the
// same reason Task is, and is likewise never rendered.
TaskSummary string `json:"task_summary,omitempty"`
Repository string `json:"repository"`
WorktreeMode string `json:"worktree_mode"`
Worktree string `json:"worktree"`
WorktreeDir string `json:"worktree_dir,omitempty"`
Branch string `json:"branch,omitempty"`
Base string `json:"base,omitempty"`
BaseSHA string `json:"base_sha,omitempty"`
// WorkLogClaimPath links this run to the immutable Work Log claim the
// worktree service already publishes, so one dispatch never produces two
// unreferenced records of the same piece of work.
WorkLogClaimPath string `json:"work_log_claim_path,omitempty"`
WorkLogRunID string `json:"work_log_run_id,omitempty"`
// TimeoutMS bounds the run. It is persisted because the owner, not the
// dispatcher, enforces it.
TimeoutMS int64 `json:"timeout_ms,omitempty"`
StartedAt time.Time `json:"started_at"`
FinishedAt time.Time `json:"finished_at,omitempty"`
DurationMS int64 `json:"duration_ms,omitempty"`
OwnerPID int `json:"owner_pid,omitempty"`
WorkerPID int `json:"worker_pid,omitempty"`
ExitCode *int `json:"exit_code,omitempty"`
Failure string `json:"failure,omitempty"`
Result string `json:"result,omitempty"`
ToolCalls int `json:"tool_calls,omitempty"`
Usage *Usage `json:"usage,omitempty"`
Changes *ChangeSummary `json:"changes,omitempty"`
HarnessEvents []string `json:"harness_diagnostics,omitempty"`
LogPath string `json:"log_path,omitempty"`
}
Record is the durable description of one dispatched run. It is private: it holds the original task, which never travels back out through status or await.
func Dispatch ¶
func Dispatch(ctx context.Context, request DispatchRequest, deps DispatchDeps) (Record, error)
Dispatch admits one run, creates or resolves its worktree, persists the run, and starts the detached owner. It returns as soon as the owner is started: the caller is never attached to the worker's stdout and never waits for it.
type RemoteDeps ¶
type RemoteDeps struct {
// LookPath resolves the local ssh executable.
LookPath func(string) (string, error)
// Runner executes it. Replacement is for tests only.
Runner remotessh.Runner
// Timeout bounds one remote call when the operation has no bound of its own.
Timeout time.Duration
}
RemoteDeps are the seams the local side needs to reach another machine.
func DefaultRemoteDeps ¶
func DefaultRemoteDeps() RemoteDeps
DefaultRemoteDeps returns the production seams.
type RemoteRequest ¶
type RemoteRequest struct {
SchemaVersion int `json:"schema_version"`
Operation string `json:"operation"`
// dispatch
Mode string `json:"mode,omitempty"`
Worktree string `json:"worktree,omitempty"`
Profile string `json:"profile,omitempty"`
Task string `json:"task,omitempty"`
Repository string `json:"repository,omitempty"`
Branch string `json:"branch,omitempty"`
Base string `json:"base,omitempty"`
TimeoutMS int64 `json:"timeout_ms,omitempty"`
// status, await, logs, stop
AgentID string `json:"agent_id,omitempty"`
WaitTimeoutMS int64 `json:"wait_timeout_ms,omitempty"`
Raw bool `json:"raw,omitempty"`
Tail int `json:"tail,omitempty"`
}
RemoteRequest is the exact request a local WB sends to a remote WB. The remote validates it with the same code that validates local flags, so a request can never reach a state a local invocation could not.
func (RemoteRequest) Validate ¶
func (request RemoteRequest) Validate() error
Validate refuses a request that is not a well-formed WB agent protocol value. It is deliberately independent of the local flag parser: a hand-written request must satisfy exactly the same constraints.
type RemoteResponse ¶
type RemoteResponse struct {
SchemaVersion int `json:"schema_version"`
Operation string `json:"operation"`
Result *Result `json:"result,omitempty"`
// Results deliberately has no omitempty: an empty inventory must travel as
// an empty list, not disappear into a null the caller has to special-case.
Results []Result `json:"results"`
Logs string `json:"logs,omitempty"`
Failure string `json:"failure,omitempty"`
}
RemoteResponse is the exact reply a remote WB sends back. A refusal on the remote side travels as Failure rather than as a transport error, so the caller can tell "the remote refused" apart from "the remote was unreachable".
func CallRemote ¶
func CallRemote(ctx context.Context, target RemoteTarget, request RemoteRequest, deps RemoteDeps) (RemoteResponse, error)
CallRemote performs one remote WB agent operation over SSH and returns the decoded reply. A non-empty reply Failure is returned as an error: the remote ran and refused, which is a finding rather than a transport failure.
type RemoteTarget ¶
RemoteTarget is one configured machine WB can dispatch to. It is derived from WB's existing session_move target map, so there is one host list rather than a second one that can drift from it.
func ResolveRemoteTarget ¶
func ResolveRemoteTarget(configPath, machine string) (RemoteTarget, error)
ResolveRemoteTarget looks up one configured machine, naming the alternatives when it is unknown so a typo is one command away from being fixed.
func (RemoteTarget) Validate ¶
func (target RemoteTarget) Validate() error
Validate refuses a target whose configured address could be reinterpreted by OpenSSH. The values come from WB configuration, but the remote command line is the one place a configuration typo could become a remote shell command.
type RequestError ¶
type RequestError struct {
// contains filtered or unexported fields
}
RequestError marks a refusal of the invocation itself: the caller asked for something WB cannot even attempt, such as an unconfigured profile. It is deliberately distinguishable from a run that started and then failed, because the two need different exit codes and different caller responses.
func (*RequestError) Error ¶
func (err *RequestError) Error() string
type Resolved ¶
type Resolved struct {
Profile string `json:"profile"`
Harness string `json:"harness"`
Provider string `json:"provider"`
Model string `json:"model"`
Reasoning string `json:"reasoning,omitempty"`
// Routing is the provider registry entry the harness will be configured
// with. It carries no credential, only the name of the variable holding it.
Routing Provider `json:"routing"`
}
Resolved is one profile after resolution: the requested name plus what will actually execute, snapshotted so a later edit to the profile cannot rewrite what a finished run did.
type Result ¶
type Result struct {
AgentID string `json:"agent_id"`
// Machine names the machine that holds this run's record and worktree. It
// is empty for a run dispatched by this machine and is stamped by the caller
// that asked another machine, so a result always says where its artefact
// lives.
Machine string `json:"machine,omitempty"`
State State `json:"state"`
Terminal bool `json:"terminal"`
RequestedProfile string `json:"profile"`
Resolved Resolved `json:"resolved"`
Repository string `json:"repository"`
WorktreeMode string `json:"worktree_mode"`
Worktree string `json:"worktree"`
WorktreeDir string `json:"worktree_dir,omitempty"`
Branch string `json:"branch,omitempty"`
Base string `json:"base,omitempty"`
BaseSHA string `json:"base_sha,omitempty"`
StartedAt time.Time `json:"started_at"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
DurationMS int64 `json:"duration_ms,omitempty"`
OwnerPID int `json:"owner_pid,omitempty"`
WorkerPID int `json:"worker_pid,omitempty"`
OwnerAlive bool `json:"owner_alive"`
WorkerAlive bool `json:"worker_alive"`
ExitCode *int `json:"exit_code,omitempty"`
Failure string `json:"failure,omitempty"`
Result string `json:"result,omitempty"`
ToolCalls int `json:"tool_calls,omitempty"`
Usage *Usage `json:"usage,omitempty"`
Changes *ChangeSummary `json:"changes,omitempty"`
HarnessDiagnostics []string `json:"harness_diagnostics,omitempty"`
LogPath string `json:"log_path,omitempty"`
}
Result is the rendered projection of a Record, and the machine-readable document `status` and `await` emit. It is written out field by field rather than derived by embedding, so the private task can never reach a caller by accident: adding a field to Record does not add it here.
type Store ¶
type Store struct {
Root string
}
Store persists agent run records under one root directory.
func (Store) Create ¶
Create prepares the run directory and persists the initial record before any process is started, so a launch that fails still leaves something to diagnose.
func (Store) HarnessHomePath ¶
HarnessHomePath is the private per-run harness home. Pointing the harness at its own home is what keeps a dispatched worker from reading or writing the user's harness state while the parent harness keeps running normally.
func (Store) LastMessagePath ¶
LastMessagePath is where the harness is asked to write its final message.
func (Store) List ¶
List returns every run record, newest first. A directory that cannot be read is reported rather than silently skipped.
func (Store) RecordPath ¶
RecordPath is the persisted run record for one agent ID.
func (Store) Render ¶
Render projects a record for output, resolving a run whose owner vanished without recording a terminal state to the honest answer: abandoned. A run is never reported as completed merely because nothing contradicted it.
Abandoned is derived from the owner, not the worker: the owner is the only process that will ever record a terminal state, so once it is gone the run has no outcome and reporting it "running" indefinitely would be a lie. A worker that outlived its owner is still surfaced, through WorkerAlive, so a caller knows a stray process exists and can stop it.
type UnknownAgentError ¶
UnknownAgentError is returned when a named run does not exist.
func (*UnknownAgentError) Error ¶
func (err *UnknownAgentError) Error() string
type Usage ¶
type Usage struct {
InputTokens int `json:"input_tokens"`
CachedInputTokens int `json:"cached_input_tokens,omitempty"`
CacheWriteInputTokens int `json:"cache_write_input_tokens,omitempty"`
OutputTokens int `json:"output_tokens"`
ReasoningOutputTokens int `json:"reasoning_output_tokens,omitempty"`
}
Usage is what the harness reported about the run. Every field is copied verbatim from the harness; a field the harness did not report stays absent rather than being estimated.