agents

package
v0.138.3 Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

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

View Source
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.

View Source
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.

View Source
const (
	RemoteDispatch = "dispatch"
	RemoteStatus   = "status"
	RemoteAwait    = "await"
	RemoteList     = "list"
	RemoteLogs     = "logs"
	RemoteStop     = "stop"
)

Remote operations, one per local command that can address another machine.

View Source
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.

View Source
const DefaultTimeout = 30 * time.Minute

DefaultTimeout bounds a dispatched run when the caller names no bound.

View Source
const DirName = "agents"

DirName is the directory under WB's home that holds dispatched agent runs.

View Source
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.

View Source
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.

View Source
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.

View Source
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.

View Source
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

func BoundResult(message string) string

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

func IsRequestError(err error) bool

IsRequestError reports whether an error refused the invocation.

func IsUnknownAgent

func IsUnknownAgent(err error) bool

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 NewID

func NewID() (string, error)

NewID mints a fresh agent run ID.

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

func OwnerCLI(arguments []string, deps OwnerDeps) int

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

func ReadCredentialFile(path string) (string, error)

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

func RecentActions(reader io.Reader, limit int) []string

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

func RunOwner(ctx context.Context, store Store, agentID string, deps OwnerDeps) error

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

func SpawnOwner(runDir string, executable func() (string, error)) (int, error)

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

func SplitAgentRef(reference string) (machine, agentID string, err error)

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

func StripAgentID(reference string) string

StripAgentID returns the bare run ID from a possibly machine-qualified reference.

func SummaryLine

func SummaryLine(task string) string

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

type Config struct {
	Providers map[string]Provider
	Profiles  map[string]Profile
}

Config is the resolved user agent configuration.

func LoadConfigFile

func LoadConfigFile(path string) (Config, error)

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".

func (Config) Resolve

func (config Config) Resolve(name string) (Resolved, error)

Resolve turns a requested profile name into an executable configuration, failing closed on anything it cannot execute.

type Credential

type Credential struct {
	EnvName string
	Value   string
}

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
}

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.

func StopRun

func StopRun(store Store, agentID string) (Record, error)

StopRun terminates a running worker's process group. The owner is left alive deliberately: it observes the non-zero exit and records the terminal state, so a stopped run reports a real outcome instead of vanishing into "abandoned".

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

type RemoteTarget struct {
	Machine string
	Host    string
	User    string
	WBPath  string
}

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 State

type State string

State is the closed lifecycle vocabulary of one dispatched run.

const (
	StateRunning   State = "running"
	StateCompleted State = "completed"
	StateFailed    State = "failed"
	StateTimeout   State = "timeout"
	StateAbandoned State = "abandoned"
)

func (State) Terminal

func (state State) Terminal() bool

Terminal reports whether a state is final. Exactly one state — running — is not terminal, so a caller can never mistake a stalled run for a finished one.

type Store

type Store struct {
	Root string
}

Store persists agent run records under one root directory.

func NewStore

func NewStore(home string) Store

NewStore returns the store for a WB home directory.

func (Store) Create

func (store Store) Create(record Record) error

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) Dir

func (store Store) Dir(agentID string) string

Dir is the private directory holding one run's record and artefacts.

func (Store) HarnessHomePath

func (store Store) HarnessHomePath(agentID string) string

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

func (store Store) LastMessagePath(agentID string) string

LastMessagePath is where the harness is asked to write its final message.

func (Store) List

func (store Store) List() ([]Record, error)

List returns every run record, newest first. A directory that cannot be read is reported rather than silently skipped.

func (Store) Load

func (store Store) Load(agentID string) (Record, error)

Load reads one run record, failing actionably when it does not exist.

func (Store) LogPath

func (store Store) LogPath(agentID string) string

LogPath is the captured harness event stream for one agent ID.

func (Store) RecordPath

func (store Store) RecordPath(agentID string) string

RecordPath is the persisted run record for one agent ID.

func (Store) Render

func (store Store) Render(record Record) Result

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.

func (Store) Save

func (store Store) Save(record Record) error

Save atomically replaces the record, so a reader never observes a partially written run.

type UnknownAgentError

type UnknownAgentError struct {
	AgentID string
	Root    string
}

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.

Jump to

Keyboard shortcuts

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