orch

package
v0.2.3 Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package orch is the planning and orchestration layer from spec 2080/ostres: a layer above the turn loop that turns a job into a plan, runs the plan's steps under a budget through the same gate, checks each against a grounded postcondition, and reports honestly. The turn loop (pkg/agent) is unchanged; orch only wraps it.

Index

Constants

View Source
const (
	PostNone           = "none"
	PostResultNonEmpty = "result_nonempty"
	PostResultContains = "result_contains"
	PostFileExists     = "file_exists"
	PostFileContains   = "file_contains"
	PostShellZero      = "shell_zero"
)

Postcondition kinds.

Variables

This section is empty.

Functions

func TriggerJob

func TriggerJob(text string) bool

TriggerJob is the cheap, no-model structural signal from the spec: a request with an explicit multi-deliverable shape. Three signals fire it, in order of how unambiguous they are: an enumerated checklist of two or more items, an explicit job phrase ("do all of the following", "for each", "workflow"), or three or more distinct action verbs joined by conjunctions. It is deliberately biased toward "turn": a missed job just runs as one turn, while a false positive wastes planning tokens and can fragment a task that needed one context, so a single instruction with one or two verbs never fires (a bare "read X and write Y" stays a turn; the compound bar is three).

func Validate

func Validate(specs []StepSpec, tools, workers []string) error

Validate checks a plan mechanically before it runs: every executor is known, every dependency and placeholder points strictly backward (which also makes the DAG acyclic), and every postcondition is one the orchestrator can evaluate. This is grounded plan-time validation, not asking a model if its plan is good.

Types

type Leaf

type Leaf func(ctx context.Context, executor, prompt string) (Result, error)

Leaf runs one step as a leaf executor: a turn, a single tool call, or a worker turn, selected by executor (`turn`, `tool:<name>`, `worker:<name>`). It is injected by the caller so orch stays decoupled from pkg/channel and the worker system, and so a leaf structurally has no handle to start a plan, which is the two-level bound from the spec enforced by construction.

type Orchestrator

type Orchestrator struct {
	Store       *store.Store
	Leaf        Leaf
	Workspace   string
	Concurrency int          // ready steps run at most this many at once
	MaxAttempts int          // per-step attempt cap before it fails terminally
	Report      func(string) // optional progress sink for logs; the CLI polls the ledger for its live view
	Now         func() time.Time
}

Orchestrator drives a plan to a terminal state: it finds ready steps, runs them under a bounded pool, checks postconditions, repairs a failed step in place, and enforces the plan's budgets. It is the single writer to the plan's ledger rows.

func (*Orchestrator) Run

func (o *Orchestrator) Run(ctx context.Context, planID string) error

Run drives the plan with the given id from its current step state to terminal. It is safe to call on a fresh plan or on resume: it schedules on whatever the ledger says, so a crash mid-job continues rather than restarting.

type Planner

type Planner struct {
	Provider  provider.Provider
	Model     string
	MaxTokens int
	Tools     []string // tool names a `tool:<name>` executor may reference
	Workers   []string // worker names a `worker:<name>` executor may reference
}

Planner decides whether a request is a job and, if so, turns it into a plan. It prefers a template (no model call, correct by construction), falls back to one planning model call for a novel job, and validates the result before it ever runs, since the model cannot be trusted to check its own plan.

func (*Planner) Plan

func (p *Planner) Plan(ctx context.Context, goal string) ([]StepSpec, error)

Plan produces a validated plan for a goal, choosing the cheapest path that works. A goal with no usable plan falls back to a single turn step, so a job always at least runs as one turn rather than failing to start.

type Postcondition

type Postcondition struct {
	// Kind selects the check. The zero value ("" or "none") always passes, for
	// a step whose success genuinely cannot be checked mechanically.
	Kind string `json:"kind"`
	Path string `json:"path,omitempty"` // for file_exists, file_contains
	Text string `json:"text,omitempty"` // for file_contains, result_contains
	Cmd  string `json:"cmd,omitempty"`  // for shell_zero
}

Postcondition is a step's grounded success check. A step is done because a check holds, not because a model said so. The rungs are ordered from most grounded (a file parses, a command exits zero) to least (a produced result mentions a token); the design prefers the mechanical rungs and avoids leaning on the model to grade its own work.

func ParsePostcondition

func ParsePostcondition(s string) Postcondition

ParsePostcondition reads a postcondition from its stored JSON. An empty or malformed value is treated as the always-passing none check rather than an error, so a step with no postcondition simply is not gated on one.

func (Postcondition) Eval

func (p Postcondition) Eval(ctx context.Context, workspace, result string) (bool, string)

Eval runs the check and returns whether it held and a one-line reason. All file paths resolve inside the workspace, and shell_zero runs in the workspace directory, so a postcondition cannot reach outside the job's working tree. result is the step's produced output, for the result_* rungs.

func (Postcondition) Evaluable

func (p Postcondition) Evaluable() bool

Evaluable reports whether this postcondition is one the orchestrator knows how to check, used by plan validation so a plan cannot ship a check that will never evaluate.

func (Postcondition) JSON

func (p Postcondition) JSON() string

JSON renders a postcondition to its stored form.

type Result

type Result struct {
	Text   string
	Tokens int
}

Result is what a leaf executor returns: the produced text and an estimate of the tokens it spent, summed into the plan's budget.

type StepSpec

type StepSpec struct {
	Goal     string            `json:"goal"`
	Deps     []int             `json:"deps"`
	Inputs   map[string]string `json:"inputs"`
	Executor string            `json:"executor"`
	Post     Postcondition     `json:"postcondition"`
}

StepSpec is a planned step before it becomes ledger rows: the schema the planner produces and the orchestrator consumes. Idx is the step's position in the plan; Deps and #E<idx> placeholders reference earlier positions.

Jump to

Keyboard shortcuts

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