Documentation
¶
Overview ¶
Package runner is ynf's runner port (ADR-012): what a lane's inner loop is. ynh is one provider and any command is another; the core only ever sees ynf's own outcome vocabulary.
Index ¶
- Constants
- Variables
- func AtLeast(have, want string) bool
- func CoAuthorAddress(r Result) string
- func Narrows(declared, scope string) error
- type CommandRunner
- type Detection
- type Focus
- type Harness
- type HarnessSource
- type Installed
- type Resolved
- type Result
- type Runner
- type Spec
- type Usage
- type YnhRunner
Constants ¶
const ( // FeatureHarnessPath is `ynh agent run --harness <path>`: a folder runs without an install. FeatureHarnessPath = "agent-run-harness-path" // FeatureFetchesIncludes is a run fetching the harness's includes at setup. FeatureFetchesIncludes = "agent-run-fetches-includes" )
The ynh features ynf uses.
const ( Converged = "converged" Budget = "budget" Stuck = "stuck" Tamper = "tamper" OperatorError = "operator_error" Error = "error" Aborted = "aborted" )
Outcomes are ynf's vocabulary (ADR-012). Lane rules branch on these, never on exit codes.
const MinYnhCapabilities = "0.9.0"
MinYnhCapabilities is the first ynh capabilities version ynf supports as a detected runner: the one with `--auto-approve`, which the lanes ynf ships use (ADR-012).
const Ynh = "ynh"
Ynh is the ynh ynf asks and runs: whatever `ynh` resolves to on the PATH ynf was given, as a shell would find it. There is no other lookup (ADR-012).
Variables ¶
var CoAuthorAddresses = map[string]string{
"claude": "noreply@anthropic.com",
}
CoAuthorAddresses are the addresses for a commit's Co-Authored-By trailer, by vendor. ynf adds an address only when it knows the vendor's own convention; a vendor not listed gets no trailer.
var ModelHosts = map[string][]string{
"claude": {"api.anthropic.com"},
"codex": {"api.openai.com"},
"cursor": {"api2.cursor.sh"},
"copilot": {"api.githubcopilot.com", "api.github.com"},
}
ModelHosts are the API hosts each vendor's CLI needs. The egress proxy allows the lane's vendor's without the lane listing them (ADR-007).
Functions ¶
func CoAuthorAddress ¶
CoAuthorAddress is the Co-Authored-By address for a result: by its backend, else the vendor named before the slash in its model. It is empty when ynf does not know the vendor's address.
func Narrows ¶
Narrows reports why scope is not the declared sensor command narrowed, or nil when it is. Both are split into words with shell quoting rules and not evaluated. The words must match one for one and in order, except that a path word of the declared command may be replaced by one or more path words beneath it (`./...` by `./x/...`, `.` by any relative path); a declared command with no path word may have path words appended at the end. The scope may hold no shell operator or expansion. The declared command's leading NAME=value assignments are kept exactly as written, expansions included, and the scope may not add, drop, reorder or change one.
Types ¶
type CommandRunner ¶
CommandRunner runs any command: exit 0 is converged, anything else an error, unless the command writes a result file saying more (ADR-012).
func (CommandRunner) Command ¶
func (c CommandRunner) Command(s Spec) ([]string, error)
Command implements Runner. It never uses a shell: each argument is expanded on its own.
type Detection ¶
type Detection struct {
Found bool `json:"found"`
Version string `json:"version,omitempty"` // ynh's own version
Capabilities string `json:"capabilities,omitempty"` // the capabilities version ynf checks abilities against
Detail string `json:"detail,omitempty"` // why it was not detected
// Features are the names ynh lists in `features`; absent means none. They are gated on by
// name, never by comparing versions (ADR-012).
Features []string `json:"features,omitempty"`
}
Detection is what detecting ynh on this host found (ADR-012).
func DetectYnh ¶
DetectYnh asks the host's ynh for its version. It is detected when the binary answers `version --format json` and its capabilities version is one ynf supports.
func DetectedYnh ¶
DetectedYnh is DetectYnh, done once per process: detection is cheap, but a sweep resolves many lanes.
type Focus ¶
Focus is a ynh focus: a named prompt, optionally with a profile.
func ResolveFocus ¶
ResolveFocus reads a focus from the harness manifest in harnessDir.
type Harness ¶
type Harness struct {
// ID is the installed harness's id, when it was read from an installed ynh (an image's).
ID string `json:"-"`
Focuses map[string]Focus `json:"focuses"`
// EnvPassthrough is every variable ynh lets reach the agent worker. ynh strips everything
// else, deliberately, model credentials and proxy settings included.
EnvPassthrough []string `json:"env_passthrough"`
// Agent is the harness's own budgets, which a lane may only tighten (ADR-006).
Agent struct {
MaxTurns int `json:"max_turns"`
MaxTokens int `json:"max_tokens"`
MaxWall string `json:"max_wall"`
} `json:"agent"`
// Sensors are the sensors the harness declares, by name; a lane may only scope these.
Sensors map[string]json.RawMessage `json:"sensors"`
}
Harness is what ynf reads from a ynh harness manifest: from the image that runs it (ADR-012), or from the folder ynh runs it from on the host.
func ParseManifest ¶
ParseManifest reads a harness manifest.
func ReadHarness ¶
ReadHarness reads the manifest of the harness in harnessDir.
func (Harness) CheckLane ¶
CheckLane holds a lane to its harness (ADR-006): budgets may only tighten the harness's own, and a sensor scope may only name a sensor the harness declares and narrow its command. With no item's labels yet, a scope's placeholders stand for a safe path segment, so its shape is still checked; CheckScopes checks it with an item's own.
func (Harness) CheckScopes ¶
CheckScopes holds a lane to its harness as CheckLane does, with the scopes' placeholders filled from the item's labels.
type HarnessSource ¶
HarnessSource is a harness to install for one run: a folder (on disk, in the run's checkout or absolute), or a pin from a repository. Exactly one of Dir and Pin is set.
func (HarnessSource) String ¶
func (s HarnessSource) String() string
type Installed ¶
type Installed struct {
// ID is what `ynh agent run --harness` takes for it.
ID string
Name string
Version string
// Commit is the commit it was installed from; empty for a folder, which has none.
Commit string
// Pin is the repository and ref it was installed from, for a pin; empty for a folder.
Pin string
// PinURL is Pin with the repository as ynh was given it (a bare host and path made
// https://host/path); empty for a folder.
PinURL string
// Path is where ynh keeps the installed harness, which holds its manifest.
Path string
}
Installed is a harness as ynh installed it into a run's own home.
func InstallHarness ¶
InstallHarness installs src into a ynh home of its own, ynhHome, and says what ynh installed. A pin is made an id this way, and so is a folder for a ynh that does not list agent-run-harness-path; one that does is given the folder directly and never reaches here. A folder is run by ynh from where it is; a pin is cloned at its tag or commit, which is the one step that reaches the network, and it happens here, before the run starts and on the host, never inside the run's containment. The home is passed as YNH_HOME to every ynh command here and replaces the operator's, so the operator's own home is never read or written. The run needs the same YNH_HOME.
type Resolved ¶
type Resolved struct {
Runner Runner
// Detected is true when the lane named no runner and detection chose this one.
Detected bool
// Note says what an unnamed lane resolved to on this host, such as "ynh (detected 0.10.0)" or
// "command (ynh not found)"; empty when the lane named its runner.
Note string
}
Resolved is the runner a lane gets and how it got it.
type Result ¶
type Result struct {
Outcome string `json:"outcome"`
Detail string `json:"detail,omitempty"`
Model string `json:"model,omitempty"` // backend/model, when the runner reports one
Session string `json:"session,omitempty"` // runner session id (ynh: session_id)
Usage
}
Result is a run's outcome in ynf's terms.
type Runner ¶
type Runner interface {
Name() string
// Command returns the argv to run inside the worktree.
Command(spec Spec) ([]string, error)
// Interpret maps an exit code (and anything the run wrote to hostRunDir) to a Result.
Interpret(exitCode int, stdout []byte, hostRunDir string) Result
}
Runner builds the command a lane runs and interprets how it ended.
type Spec ¶
type Spec struct {
Lane policy.Lane
Labels []string
Task string // the task text, written to TaskFile by the engine
TaskFile string // path inside the worktree's step folder, as the command sees it
RunDir string // the step folder, as the command sees it
Feedback string
// InImage is set when the run happens in an image built by `ynh image --entrypoint agent`,
// whose entrypoint is already `ynh agent run --harness local/<name>`.
InImage bool
// Contained is set when the run is contained (ADR-007): in an image, or inline in a container
// the operator provides.
Contained bool
// Focus is the lane's focus, resolved from the harness: its prompt is already in the task.
Focus *Focus
// HostAutoApprove is --auto-approve asked for by the person who started the work, for a run on
// their own machine (ADR-007). A lane's setting never applies outside containment.
HostAutoApprove string
}
Spec is what a runner is asked to do.
type Usage ¶
type Usage struct {
Effort string `json:"effort,omitempty"` // reasoning effort, when the runner reports it
// EffortRequested is the effort the run was asked for, when it was: a lane's effort or the
// harness's default. A backend may run at another, which Effort then shows.
EffortRequested string `json:"effort_requested,omitempty"`
Turns int `json:"turns,omitempty"` // agent turns
Tokens int `json:"tokens,omitempty"` // tokens consumed: input and output
// The split, when the runner reports it. Cache reads are not in Tokens, and are often most of
// what a long session costs.
InputTokens int `json:"input_tokens,omitempty"`
OutputTokens int `json:"output_tokens,omitempty"`
CacheReadTokens int `json:"cache_read_tokens,omitempty"`
// Backend is the vendor CLI that ran, such as claude: what is known when the model is not.
Backend string `json:"backend,omitempty"`
CostUSD float64 `json:"cost_usd,omitempty"` // when the runner reports it; ynf never prices tokens
BoundBy string `json:"bound_by,omitempty"` // the cap that ended the run, if one did
// Harness is name@version, and HarnessSHA the commit it was installed from: a harness change is
// a confounder when comparing models, not a model effect.
Harness string `json:"harness,omitempty"`
HarnessSHA string `json:"harness_sha,omitempty"`
RunnerVersion string `json:"runner_version,omitempty"` // ynh's version
// FailedSensors names the sensors that had failed when the run ended, in the runner's order.
FailedSensors []string `json:"failed_sensors,omitempty"`
AutoApprove string `json:"auto_approve,omitempty"`
}
Usage is what a run spent and on what, when its runner reports it, so outcomes can be compared by model and effort (ADR-011). A command runner's result file may report it too.
type YnhRunner ¶
YnhRunner runs `ynh agent run` (ADR-012). It owns the mapping from ynh's exit codes to ynf's outcomes, and every ynh-only setting: budgets, sensor scoping, the trajectory path.
func (YnhRunner) Command ¶
Command implements Runner. In an agent image the entrypoint already names ynh agent run and the harness, so only the flags are passed.