Documentation
¶
Overview ¶
Package harness steps a session: load the file, build the context, call the provider, append what comes back, execute the calls, repeat until the model stops calling tools.
Index ¶
- Constants
- func Handler(ctx context.Context, h *Harness) http.Handler
- func System(model string) string
- func ToolSet(model string) string
- func Tools(name string, input []string) []provider.Tool
- type Create
- type Harness
- func (h *Harness) Changed(id string) <-chan struct{}
- func (h *Harness) Create(ctx context.Context, c Create) (string, error)
- func (h *Harness) Info(id string) (Info, error)
- func (h *Harness) Kick(ctx context.Context, id string)
- func (h *Harness) List() ([]Info, error)
- func (h *Harness) Post(ctx context.Context, id, via string, parts []Part) (int, error)
- func (h *Harness) Resume(ctx context.Context) error
- func (h *Harness) Retry(ctx context.Context, id string)
- func (h *Harness) Run(ctx context.Context, id string) (statefile.Status, error)
- func (h *Harness) Step(ctx context.Context, id string) (status statefile.Status, err error)
- func (h *Harness) Stop(ctx context.Context, id, via string) error
- type Info
- type Listed
- type Output
- type Part
- type Pool
- type Remote
- func (r *Remote) Kill(ctx context.Context, session string) error
- func (r *Remote) Read(ctx context.Context, path string) ([]byte, error)
- func (r *Remote) Run(ctx context.Context, session, interpreter, code string) (Output, error)
- func (r *Remote) Write(ctx context.Context, path string, data []byte) error
- type Worker
Constants ¶
const MaxPost = 8 << 20
MaxPost bounds one post: a paragraph and a screenshot, typed or pasted by a person. A file goes to a worker, not into the state file.
Variables ¶
This section is empty.
Functions ¶
func Handler ¶
Handler is the harness's HTTP surface: seven verbs on a session, three reads of the environment, and removing a worker. Records go out in the state file's own bytes, one after another.
GET /sessions ?status= ?limit= ?after=<id> -> [Info], newest updated first
POST /sessions Create body -> {"id"}
GET /sessions/{id} -> Info
GET /sessions/{id}/records ?after=N ?wait=30s to long poll -> records
POST /sessions/{id}/records one body, or multipart; ?via= required, -> {"n"}
who is posting. one message record per
part, each with its Content-Type
POST /sessions/{id}/retry step from the tip, whatever it is -> {"status"}
POST /sessions/{id}/stop ?via= required. cut the step, write it -> 204; the records
down say what happened
GET /workers -> connected workers' hellos, and refused
ones with the reason
DELETE /workers/{name} the worker leaves the mesh for good; its -> 204
join secret still joins new machines
GET /providers -> names this harness can serve as provider/model
GET / -> {"version"}
ctx outlives every request: it is what steps run under.
Types ¶
type Create ¶
type Create struct {
From string `json:"from,omitempty"`
N int `json:"n,omitempty"`
Model string `json:"model,omitempty"`
Context int `json:"context,omitempty"`
Workers []statefile.Worker `json:"workers,omitempty"`
Input []string `json:"input,omitempty"`
}
Create is the body of POST /sessions. From set is a copy of records 1 through N-1 of that session; otherwise a fresh session from Model, Context, and Workers. Workers are not checked: the config is the whitelist, and a worker named before it dials in is a worker the session waits for.
type Harness ¶
type Harness struct {
Sessions statefile.Sessions
Providers map[string]provider.Provider
Workers *Pool
Remove func(name string) error // the coordinator's: the worker leaves the mesh for good
// contains filtered or unexported fields
}
func (*Harness) Create ¶
Create makes a session and returns its id. A fresh one starts with the system prompt and the AGENTS.md scan. A copy is byte for byte and gets nothing appended: it already holds both.
func (*Harness) Kick ¶
Kick steps a session in the background until it is not open. A kick during a run makes the runner look once more before it stops, so a message that lands as a run ends is not left waiting. Each pass gets its own context so a stop ends one pass and not the next. A pass that ends closed or failed copies the file to the session's workers.
func (*Harness) List ¶
List is every session, newest updated first, from the index. Entries a write touched since the last list are read again; the rest are served from memory. The mark is cleared before the read, so a write that lands during the read marks it again. A file that does not read is logged and left out until its next write. Resume fills the index on start, and touch adds a created session.
func (*Harness) Post ¶
Post appends one message record per part under one lock and kicks the session once, so a text and an image reach the model as one turn. The append is the acknowledgement: a closed session starts stepping on it, a stepping one sees it at its next context build. Returns the last n.
func (*Harness) Resume ¶
Resume kicks every session that needs a step. This is the open-files index, rebuilt from the tips on start; a failed session waits for a run or a message. A file that does not read is logged and left out, not a reason to stay down.
func (*Harness) Retry ¶
Retry steps a failed session from its tip: after a stop it continues, after exhausted provider retries it tries again, past the limit it gets the same error again. Nothing is cleared.
func (*Harness) Step ¶
Step runs one cycle and returns the status after it. A failed session is stepped only when a run asked for it; every step spends the ask, so a run on a closed session does not carry over to a later failure. Interrupted sessions get a result for every orphan call and become open; the next cycle steps. Past the context limit nothing is called: the error says so and the session is failed. The worker list enters as a system record whenever it differs from the last one the model saw.
type Info ¶
type Info struct {
ID string `json:"id"`
Status statefile.Status `json:"status"`
Config statefile.Conf `json:"config"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
N int `json:"n"`
Prompt int `json:"prompt"`
Usage statefile.Usage `json:"usage"`
}
Info is what GET /sessions/{id} and each entry of GET /sessions say about a session: everything the tip states, no cost and no title. Prompt is the last step's prompt in tokens, against Config.Context.
type Listed ¶
Listed is a worker as GET /workers shows it: its hello, and why its last connection was refused, when it was.
type Output ¶
Output is what a run left: the tail the worker's side kept, the exit code, the lines dropped before the tail, and the file on the worker holding all of it when the output went over the limits.
type Pool ¶
type Pool struct {
// contains filtered or unexported fields
}
Pool is the set of workers connected right now, keyed by the name the coordinator gave each one's node. Workers dial in over the mesh and are known the moment they say hello; a lost connection forgets the worker until it dials again.
func (*Pool) List ¶
List is every connected worker and every refused one not connected now, sorted by name.
func (*Pool) Serve ¶ added in v0.3.0
Serve holds every worker that dials l, the harness's own node on the mesh, until l closes. WireGuard admits only nodes the coordinator gave keys to, and the source address is checked against node, the coordinator's registry, which also names the worker, so no secret rides the connection and no worker can take another's name. A worker that dials again under a name still held replaces the old entry: the old connection is dead or dying, and the new one is the worker as it is now.
type Remote ¶
Remote is a worker on the far end of a connection. Its hello header says what it is. Requests are multiplexed by id; a call waits for its terminal frame, the connection's end, or ctx: the worker's timeout bounds a run, and a stop cuts it short.
func Connect ¶
Connect reads the worker's hello, checks the connection with admit, whose error is why it is refused, and starts routing its replies. A worker from another release is told to update to this one and refused: it comes back as this release, and the error says whether the update began or why it failed. That worker is returned with the error, so the pool can list it.
type Worker ¶
type Worker interface {
Run(ctx context.Context, session, interpreter, code string) (Output, error)
Read(ctx context.Context, path string) ([]byte, error)
Write(ctx context.Context, path string, data []byte) error
Kill(ctx context.Context, session string) error
}
Worker is the three primitives every worker has, and Kill. Tools are built on the primitives here. Write creates missing parents. Run's environment persists per session and interpreter until Kill; the harness decides when a session's environments stop being worth keeping.