autonomous

package
v2.8.0-dev.3 Latest Latest
Warning

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

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

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AutonomousHandle

type AutonomousHandle struct {
	// contains filtered or unexported fields
}

AutonomousHandle is the programmatic-control surface returned by StartAutonomous. The autonomous loop runs in its own goroutine; methods on the handle are safe for concurrent callers.

Typical usage from a harness:

h, _ := agent.StartAutonomous(ctx, build, "monitor cluster X",
    agent.WithMaxTurns(0), agent.WithMaxWallclock(time.Hour))
defer h.Stop()
// Inject new instructions as they arrive from outside:
h.Inject("priority changed: focus on Q4 review")
// Or pause briefly:
h.Pause(); ...; h.Resume()
// Block until terminal:
result, err := h.Wait()

func StartAutonomous

func StartAutonomous(ctx context.Context, build BuildFunc, goal string, opts ...AutonomousOption) (*AutonomousHandle, error)

StartAutonomous launches a new autonomous run in a goroutine and returns a handle the caller uses to control / observe it. Otherwise identical surface to RunAutonomous — same BuildFunc, same options. Wait() returns the same RunResult shape.

The goroutine context is derived from ctx with our own cancel function so Stop() can cancel independently of the caller's ctx. If the caller's ctx fires, the run is still cancelled (the derived ctx inherits cancellation).

func (*AutonomousHandle) Done

func (h *AutonomousHandle) Done() <-chan struct{}

Done returns the channel that closes when the autonomous goroutine exits. Useful when a caller wants to combine the wait with other selects (e.g. ctx + Done).

func (*AutonomousHandle) Inject

func (h *AutonomousHandle) Inject(message string) error

Inject queues a message on the underlying agent's inbox. The next turn drains the inbox and prepends an "[Inbox]" block to the prompt the model sees. Returns an error when called before the goroutine has constructed the agent (typically a fraction of a second after StartAutonomous returns) or after the agent is inaccessible.

func (*AutonomousHandle) InjectAs

func (h *AutonomousHandle) InjectAs(message string, caller auth.Caller) error

InjectAs is Inject with a per-message originator identity (see Agent.InjectAs). Same lifecycle rules as Inject.

func (*AutonomousHandle) Pause

func (h *AutonomousHandle) Pause() error

Pause requests the loop to pause at the next per-turn checkpoint. The currently-running turn finishes normally; subsequent turns block until Resume fires or Stop / ctx cancellation tears the goroutine down.

Idempotent: calling Pause while already paused is a no-op. Returns an error only when called after the run has terminated.

Emits a synthetic "paused" event to the agent's eventlog (Author="<binary>/autonomous", CustomMetadata.kind="paused") for audit, when an eventlog is wired. No-op when not.

func (*AutonomousHandle) Ready

func (h *AutonomousHandle) Ready() <-chan struct{}

Ready returns a channel that closes once the underlying agent has been constructed (i.e. the wrappedBuild closure inside the autonomous loop has run and captured the agent). Inject and RequestWake fail with "agent not yet constructed" when called before this fires; out-of-band consumers (stdin readers, alert watchers) should wait on Ready before issuing those calls. May already be closed by the time Ready returns — the select-on-Ready pattern handles both cases naturally.

func (*AutonomousHandle) RequestWake

func (h *AutonomousHandle) RequestWake()

RequestWake fires the underlying agent's wake signal, interrupting any active scheduler sleep. Pairs with Inject for "operator nudged the loop, wake now" semantics; Inject already calls RequestWake internally, so this is for the alert-arrival case (or any other signal that doesn't carry a message). No-op when the agent hasn't been constructed yet.

func (*AutonomousHandle) Resume

func (h *AutonomousHandle) Resume() error

Resume unblocks the autonomous loop's BeforeTurn hook so the next turn can start. Idempotent: calling Resume while not paused is a no-op. Returns an error only when called after the run has terminated.

Emits a synthetic "resumed" event to the agent's eventlog for audit, when an eventlog is wired.

func (*AutonomousHandle) Status

func (h *AutonomousHandle) Status() AutonomousStatus

Status returns the current lifecycle state. Safe to call any time; the goroutine's terminal handoff is mutex-coordinated.

func (*AutonomousHandle) Stop

func (h *AutonomousHandle) Stop() error

Stop cancels the run's context. The currently-running LLM call returns context.Canceled; the loop exits; the goroutine cleans up. Idempotent: subsequent Stop calls are no-ops.

If the loop is paused when Stop is called, the ctx cancellation unblocks the BeforeTurn hook (which selects on both pauseCh and ctx.Done) so the goroutine can exit.

func (*AutonomousHandle) Wait

func (h *AutonomousHandle) Wait() (RunResult, error)

Wait blocks until the autonomous goroutine exits, then returns the same RunResult + error pair RunAutonomous returns. Safe to call from multiple goroutines; the result + err are set under the mutex once before the done channel closes.

type AutonomousOption

type AutonomousOption func(*autoConfig)

AutonomousOption mutates RunAutonomous configuration. Use the With* helpers below.

func WithBeforeTurn

func WithBeforeTurn(cb func(ctx context.Context, turnNo int) error) AutonomousOption

WithBeforeTurn installs a callback invoked at the top of each iteration of the autonomous loop, after budget checks and before the turn's runOneTurn call. The callback receives the upcoming turn number (1-based). Returning a non-nil error aborts the run with that error.

This is the seam AutonomousHandle uses to implement Pause: the callback blocks while paused, returning when Resume fires or the run context is cancelled. Library callers can wire arbitrary gating logic (rate limits, external approvals, etc.) on top.

func WithContinuationPrompt

func WithContinuationPrompt(s string) AutonomousOption

WithContinuationPrompt overrides the prompt sent on every turn after the first. Default: "continue". Real consumers often pass something more specific to their loop ("what's your next step?").

func WithDoneToolDescription

func WithDoneToolDescription(desc string) AutonomousOption

WithDoneToolDescription overrides the description shown to the model for the internal done tool. Override when the default prose doesn't fit your task — for example to instruct the model to call done only after writing a summary.

func WithDoneToolName

func WithDoneToolName(name string) AutonomousOption

WithDoneToolName overrides the function name of the internal done tool. Useful when "report_done" collides with an existing tool the consumer has registered. Default: "report_done".

func WithMaxCost

func WithMaxCost(usd float64) AutonomousOption

WithMaxCost caps the cumulative dollar cost of the run. Requires a non-zero pricing source — either WithTracker(tracker, pricing) or the recorded UsageMetadata being priced via the same Pricing.

func WithMaxDefer

func WithMaxDefer(d time.Duration) AutonomousOption

WithMaxDefer is a driver-level ceiling on how far in the future the scheduler can wait. Zero means no cap, matching the existing WithMaxTurns / WithMaxWallclock convention. Acts as an operator safety net: if a turn emits a schedule intent past this ceiling, the driver clamps the wake-time and logs a warning, then proceeds with the clamped value. The model-facing cap is configured via WithScheduleToolMaxDefer.

func WithMaxTokens

func WithMaxTokens(input, output int) AutonomousOption

WithMaxTokens caps the cumulative input + output token totals for the run. A zero value for either disables that side of the cap.

func WithMaxTurns

func WithMaxTurns(n int) AutonomousOption

WithMaxTurns caps the number of turns the loop will execute. Zero disables the cap (use with caution; pair with another budget). The default is 50.

func WithMaxWallclock

func WithMaxWallclock(d time.Duration) AutonomousOption

WithMaxWallclock caps the wall-clock duration of the run, measured from RunAutonomous entry. Checked between turns; a single rogue turn can still exceed this — pair with WithPerTurnTimeout to bound that.

func WithPerTurnTimeout

func WithPerTurnTimeout(d time.Duration) AutonomousOption

WithPerTurnTimeout wraps each turn's context with a timeout so a single hung turn cannot stall the whole run. Distinct from WithMaxWallclock, which bounds total time.

func WithPermissionsGate

func WithPermissionsGate(g *permissions.Gate) AutonomousOption

WithPermissionsGate hands the driver a reference to the permissions gate the consumer wired into their tools. The driver only uses this for one purpose: a startup check that rejects ask-mode + no-prompter configurations that would deadlock on the first tool call. The gate is otherwise enforced by the tools themselves; passing it here does not change runtime gating behavior.

Pass this when your build function constructs gated tools and your permission mode might be ask. Omit it for ModeYolo / ModeAllow runs where deadlock isn't a risk.

func WithPricing

func WithPricing(p usage.Pricing) AutonomousOption

WithPricing sets the Pricing used for cost rollup when a usage.Tracker is not supplied. Useful for headless runs that just want a final dollar number on RunResult.

func WithProgress

func WithProgress(cb func(turn int, ev *session.Event)) AutonomousOption

WithProgress invokes cb for every session.Event observed during the run. The turn index is the 1-based count of completed turns at the time the event is emitted (always at least 1 inside a turn).

func WithRetryPolicy

func WithRetryPolicy(p RetryPolicy) AutonomousOption

WithRetryPolicy installs a callback consulted whenever a turn returns an error. The callback receives the error and the 1-indexed attempt count and returns one of AbortRun, RetryTurn, or SkipTurn. Without a policy, the driver aborts on the first error.

func WithScheduleToolDescription

func WithScheduleToolDescription(desc string) AutonomousOption

WithScheduleToolDescription overrides the description shown to the model for the internal schedule tool. The default includes a cadence ladder, good-vs-bad next_prompt examples, and the state-persistence reminder; override when domain-specific guidance is needed (e.g. "always wake by the top of the hour"). Only takes effect when WithScheduler is also set.

func WithScheduleToolMaxDefer

func WithScheduleToolMaxDefer(d time.Duration) AutonomousOption

WithScheduleToolMaxDefer sets the tool-level cap on how far the model may schedule a wake. Calls past the cap return a tool-result error to the model so it can adapt. Zero means no cap. Distinct from WithMaxDefer, which is the driver's silent safety net. Only takes effect when WithScheduler is also set.

func WithScheduleToolName

func WithScheduleToolName(name string) AutonomousOption

WithScheduleToolName overrides the function name of the internal schedule tool. Useful when the default "schedule_next_turn" collides with a consumer-registered tool. Only takes effect when WithScheduler is also set.

func WithScheduler

func WithScheduler(s coretools.Scheduler) AutonomousOption

WithScheduler installs a tools.Scheduler that's consulted between turns when the prior turn emitted a schedule intent via the schedule_next_turn tool. Loops without a scheduler don't get the tool registered at all, so the model can't emit intent the driver has no way to honor.

Bundled schedulers: tools.SleepScheduler() for long-lived daemons (sleeps the goroutine between turns), tools.ExitOnDeferScheduler() for orchestrator-managed deployments (exits with StopReasonDeferred + RunResult.NextWakeAt populated, ResumeAutonomous picks up at the wake-time). See docs/scheduled-monitoring-design.md.

func WithTracker

func WithTracker(t *usage.Tracker, p usage.Pricing) AutonomousOption

WithTracker hands the driver an existing usage.Tracker plus the Pricing to use for per-turn cost accounting. Each turn appends to the tracker; RunResult also rolls up totals independently so callers can read them without touching the tracker.

When omitted, RunResult still tracks tokens — but cost is zero unless a non-zero Pricing is supplied via WithPricing.

type AutonomousStatus

type AutonomousStatus int

AutonomousStatus describes the lifecycle state of a run started via StartAutonomous. Read via AutonomousHandle.Status; transitions are driven by Pause / Resume / Stop and by the run goroutine's terminal handoff.

const (
	// AutonomousRunning — goroutine is alive and not paused.
	AutonomousRunning AutonomousStatus = iota
	// AutonomousPaused — Pause was called; loop is blocked at the
	// next pre-turn checkpoint until Resume fires.
	AutonomousPaused
	// AutonomousStopped — Stop was called; goroutine has unwound or
	// is about to (the ctx cancel propagates through the current
	// turn's LLM/tool calls).
	AutonomousStopped
	// AutonomousCompleted — RunAutonomous returned with
	// Reason==Completed.
	AutonomousCompleted
	// AutonomousFailed — RunAutonomous returned with a non-Completed
	// terminal reason (budget exceeded, retry aborted, etc.) or a
	// Go error from the loop machinery.
	AutonomousFailed
)

func (AutonomousStatus) String

func (s AutonomousStatus) String() string

String renders the status for diagnostics and tool results.

type BuildFunc

type BuildFunc func(extraTools []tool.Tool) (*agent.Agent, error)

BuildFunc has the same shape RunAutonomous expects: the driver hands it the extra tools it injected (today: just the done tool) and the consumer returns a configured *agent.Agent. The Agent's session.Service must be wired (durable or in-memory).

type ResumeBuildFunc

type ResumeBuildFunc func(extras []tool.Tool, sessionID string) (*agent.Agent, error)

ResumeBuildFunc is the agent constructor accepted by ResumeAutonomous. It mirrors RunAutonomous's BuildFunc signature but adds the sessionID the new agent must adopt — implementations pass it to agent.WithSession so the constructed agent reuses the session being resumed.

type RetryDecision

type RetryDecision int

RetryDecision tells the driver what to do after a turn fails.

const (
	// AbortRun stops the run immediately and propagates the error.
	AbortRun RetryDecision = iota
	// RetryTurn re-runs the same prompt for another attempt.
	RetryTurn
	// SkipTurn moves on to the continuation prompt as if the failed
	// turn had completed normally without a done signal.
	SkipTurn
)

type RetryPolicy

type RetryPolicy func(turnErr error, attempt int) RetryDecision

RetryPolicy decides what RunAutonomous does when a turn errors. The callback receives the error and the 1-indexed attempt count (the first failure is attempt=1, second is attempt=2, etc.).

type RunResult

type RunResult struct {
	// Reason explains why the loop stopped.
	Reason StopReason
	// FinalText is the accumulated streaming text from the last turn
	// that produced any output.
	FinalText string
	// Turns is the number of turns the driver actually executed
	// (including failed ones that were retried or skipped).
	Turns int
	// InputTokens / OutputTokens are summed from each turn's
	// UsageMetadata. Zero when no usage info was returned.
	InputTokens  int
	OutputTokens int
	// CostUSD is the cumulative dollar cost computed via the
	// configured Pricing. Zero when pricing is zero.
	CostUSD float64
	// Duration is the wall-clock time from RunAutonomous entry to
	// loop exit.
	Duration time.Duration
	// DoneDetail is the detail string the model passed to the done
	// tool when Reason==StopReasonCompleted.
	DoneDetail string
	// NextWakeAt is set when Reason==StopReasonDeferred — the
	// scheduler returned ErrSchedulerDefer and the loop exited
	// cleanly with a wake-time persisted to the eventlog. Whatever
	// orchestrator wraps the process restarts at or after this time
	// and ResumeAutonomous picks up the deferred checkpoint.
	NextWakeAt time.Time
}

RunResult is the structured outcome of RunAutonomous.

func ResumeAutonomous

func ResumeAutonomous(ctx context.Context, build ResumeBuildFunc, ref SessionRef, opts ...AutonomousOption) (RunResult, error)

ResumeAutonomous reads the most recent checkpoint event from the session's event log, reconstructs RunResult totals, and continues the run from the next turn. The build function receives the resumed sessionID so the constructed agent rejoins the same session via agent.WithSession.

Behavior:

  • Acquires an exclusive SessionLock on (App, User, Session). A concurrent ResumeAutonomous on the same session returns ErrSessionLocked from eventlog.
  • If the session has no checkpoint events at all, the run starts from turn 0 with whatever event history the session already holds — "make this existing session autonomous from here" is a valid use case.
  • If the latest checkpoint has stop_reason set (terminal state), ResumeAutonomous returns that state immediately without constructing the agent or running any turns.
  • Otherwise, the loop continues with prompt = checkpoint.ContinuationPrompt; budgets carry forward.

func RunAutonomous

func RunAutonomous(ctx context.Context, build func(extraTools []tool.Tool) (*agent.Agent, error), goal string, opts ...AutonomousOption) (RunResult, error)

RunAutonomous drives a multi-turn loop against an Agent built by build, sending goal as the first prompt and a continuation prompt thereafter, until one of the stop conditions fires. Returns a RunResult describing why it stopped and the totals it accumulated, plus any error.

The driver constructs the agent via build, passing in an extra "done" tool the model calls to signal completion. The tool name is "report_done" by default and can be overridden with WithDoneToolName. Consumers compose the done tool with their own tool registry inside build (see examples/autonomous for the pattern).

The constructor pattern keeps the driver from mutating a caller-supplied Agent (which would race with concurrent runs) and keeps agent.New's surface free of "extra tools" plumbing that only matters here.

type SessionRef

type SessionRef struct {
	Handle    *eventlog.Handle
	AppName   string
	UserID    string
	SessionID string
}

SessionRef identifies the session ResumeAutonomous resumes from. Handle supplies both the eventlog.Stream (used to find the latest checkpoint) and the session.Service (used by the constructed agent for live event reads + writes).

type StopReason

type StopReason string

StopReason explains why RunAutonomous returned.

const (
	// StopReasonCompleted means the model called the done tool.
	StopReasonCompleted StopReason = "completed"
	// StopReasonMaxTurns means WithMaxTurns was hit.
	StopReasonMaxTurns StopReason = "max_turns_exceeded"
	// StopReasonMaxTokens means WithMaxTokens (input or output) was hit.
	StopReasonMaxTokens StopReason = "max_tokens_exceeded" //nolint:gosec // not a credential
	// StopReasonMaxCost means WithMaxCost was hit.
	StopReasonMaxCost StopReason = "max_cost_exceeded"
	// StopReasonWallclockExceeded means WithMaxWallclock was hit.
	StopReasonWallclockExceeded StopReason = "wallclock_exceeded"
	// StopReasonContextCancelled means the supplied context was
	// cancelled or its deadline expired.
	StopReasonContextCancelled StopReason = "context_cancelled"
	// StopReasonRetryAborted means the configured RetryPolicy
	// returned AbortRun for a turn error.
	StopReasonRetryAborted StopReason = "retry_policy_aborted"
	// StopReasonDeferred means the configured Scheduler returned
	// ErrSchedulerDefer in response to a schedule emission. The loop
	// exited cleanly with RunResult.NextWakeAt populated; whatever
	// orchestrator wraps the process restarts at or after the
	// wake-time and ResumeAutonomous picks up.
	StopReasonDeferred StopReason = "deferred"
)

Jump to

Keyboard shortcuts

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