executor

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 13, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package executor runs a session's lead queue: dispatch, retry, replan, settle.

One lead at a time per worker, each with its own budget reservation taken before the work and settled after it, so a lead that overruns is visible as a flagged overshoot rather than a silent overspend (§8.2).

The loop ends on a drained queue, a ceiling, a wall clock, or a fatal error. A fatal error cancels the batch in flight and stops the loop leasing more — so the blast radius is one batch rather than one lead, which is what --workers 1 buys back.

Index

Constants

View Source
const DefaultWorkers = planner.DefaultReplanEvery

DefaultWorkers is the per-session pool size when Workers is unset.

Equal to planner.DefaultReplanEvery, and that is the whole reason for the number. batchSize never runs past a replan boundary, so a pool larger than the replan cadence has workers that can never all be busy: with the previous default of 4 against a cadence of 3, the fourth worker was unreachable in every shipped configuration while three comments, the daemon's startup banner and the README all advertised four — and "four sessions of four workers is sixteen concurrent leads" was wrong by a third.

Tying the two together means the advertised number is the real one. Raising concurrency now means raising both, deliberately, and paying the planner cost §9.1 exists to control.

View Source
const MaxAttempts = 3

MaxAttempts caps retries of a whole lead (§9.5).

Deliberately small, and smaller than it looks. A retry re-runs the entire lead — search, fetches, every model call — and all of it is charged again. The LLM layer already retries individual calls with backoff, so reaching here means something outside a single model call failed, and three full re-runs of a lead is already an expensive way to find that out.

View Source
const MaxWorkers = 16

MaxWorkers clamps Workers however it was configured.

The ceiling is about what leaves this machine, not about goroutines. Each worker holds a lead, and a lead is searches and fetches against real hosts; a misread config or a fat-fingered flag should not be able to point an unbounded fan of requests at one domain from a user's address. The per-domain rate limiter still applies underneath.

Variables

This section is empty.

Functions

func Backoff

func Backoff(attempt int, jitter func() float64) time.Duration

Backoff is the wait before attempt n (1-based), with jitter.

Jitter matters more than the curve here. Without it, several leads that hit the same rate limit retry in lockstep and hit it again together, which is how a brief throttle becomes a sustained one.

func DeadEndCause

func DeadEndCause(err error) string

DeadEndCause maps an error to the short label the digest groups by (§9.1).

Grouped, so the planner sees "bot_block ×20" rather than twenty lines. The label has to be an enum-ish constant for that to work — an error string with a URL in it groups into a population of one.

func EffectiveWorkers

func EffectiveWorkers(workers int) int

EffectiveWorkers is how many leads a given Workers setting actually permits, before the per-batch bounds in batchSize narrow it further.

Exported because a caller has to be able to ask. cmd/mole's cassette guard checked the raw flag, so --workers 0 — which means "use the default" — passed a check meant to enforce serial execution and then ran a pool.

Types

type Class

type Class int

Class is what to do about an error.

const (
	// Degraded is the default. An unrecognized error is more likely a dead
	// link or a parse failure than an outage, and treating the unknown as
	// fatal would abort a session over one bad page.
	Degraded Class = iota
	Transient
	Fatal
)

func Classify

func Classify(err error) Class

Classify decides what an actor error means.

func (Class) String

func (c Class) String() string

type Event

type Event struct {
	Phase string // "planning", "executing", "replanning", "lead", "cached"
	// Detail is a short human-readable note, already formatted.
	Detail string
}

Event is a step the caller may want to show.

type Executor

type Executor struct {
	Store   store.Store
	Ledger  *budget.Ledger
	Queue   *queue.Queue
	Planner *planner.Planner

	// Verifier builds the claim graph (§11). Nil skips verification entirely,
	// which is a supported configuration: the research still runs, claims still
	// carry verified quotes, and derived confidence stays 0 rather than being
	// invented.
	Verifier *verifier.Verifier
	Actors   map[core.ActorType]actors.Actor
	Log      *slog.Logger

	// Owner identifies the PROCESS holding a lease — "cli" or "daemon" — so the
	// two never claim each other's leads (§9.4).
	//
	// Not per worker, despite what this said before the pool existed. Workers in
	// a session share it, and nothing wants otherwise: a lease is claimed for a
	// specific lead in a transaction, so the lead is already the unit of
	// identity, and the heartbeat renews that lease rather than anything owned
	// by a worker. Boot recovery sweeps by age across all owners.
	Owner string

	// Workers is how many leads this session runs at once. Zero takes
	// DefaultWorkers.
	//
	// Per session rather than per process: the supervisor already bounds how many
	// sessions run at once, and one shared pool would let a single large session
	// starve every other one. The product of the two is what a person actually
	// has to reason about — at the defaults, four sessions of three workers is
	// twelve concurrent leads and twelve outbound fetches — so both numbers stay
	// visible instead of being folded into one.
	Workers int

	// Progress reports phase transitions as they happen. Optional.
	//
	// Not decoration. Planning is a single model call with no output until it
	// returns, and on a local model that is minutes of silence — three runs were
	// killed by hand because the CLI printed a header and then nothing, which
	// reads as a hang rather than as work.
	Progress func(Event)

	// Cache holds artifacts already researched in this session (§9.3). Shared
	// with the actor, so a lead-level hit and a URL-level hit are the same
	// cache and one lead's fetches serve another's.
	Cache *cache.Cache

	// Pricing and CheapModel convert a USD reservation into the token ceiling
	// an actor can act on. CheapModel names the tier chunk mining actually
	// uses; pricing the ceiling off the strong model would set it several
	// times too low. Both empty leaves the actor's configured budget in place.
	Pricing    *pricing.Table
	CheapModel string

	// Estimator sizes reservations. Nil uses a fresh one for the session's
	// budget unit.
	Estimator *budget.Estimator

	// Now and Jitter are injectable for tests.
	Now    func() time.Time
	Jitter func() float64

	// Sleep waits between retries. Injectable so a test does not spend the
	// backoff in real time.
	Sleep func(context.Context, time.Duration) error
}

Executor runs one session to completion.

func (*Executor) Run

func (e *Executor) Run(ctx context.Context, sessionID string) (*Result, error)

Run executes a session from prompt to exhausted queue.

Escrow is already held from session creation (§8.3), so the loop can spend down to Available() without starving the report.

type Result

type Result struct {
	SessionID string
	Status    core.SessionStatus

	Digest *planner.Digest
	Claims []core.Claim

	LeadsRun    int
	LeadsFailed int
	LeadsCached int
	Replans     int

	// CacheStats reports whether the cache earned its keep. An unmeasured
	// cache is an assumption.
	CacheStats cache.Stats

	// Verification totals across every pass (§11).
	VerifyPasses    int
	ClaimsVerified  int
	EdgesWritten    int
	Contradictions  int
	FollowUpsQueued int
	// VerifyDegraded is the last reason a pass could not finish, if any.
	VerifyDegraded string

	// Spent is the settled total in the session's budget unit.
	Spent int64
	// StoppedBecause names the ceiling or condition that ended the run, for
	// the report and the trace.
	StoppedBecause string
}

Result is what a session produced.

Jump to

Keyboard shortcuts

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