agent

package
v1.7.0 Latest Latest
Warning

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

Go to latest
Published: May 21, 2026 License: Apache-2.0 Imports: 27 Imported by: 0

Documentation

Overview

Package agent wraps the Google ADK runner with sensible defaults (streaming mode, in-memory session service, app name) so consumers hit the same shape regardless of whether they're driving the agent from a one-shot CLI, a REPL, or an HTTP handler.

Multi-turn conversation history is preserved automatically when Run() is called repeatedly with the same userID + sessionID — by default ADK's session.InMemoryService accumulates events. Pass WithSessionService to plug in a durable backend (e.g. an eventlog-backed Service for SQLite/Postgres persistence + audit log + crash-resume).

Index

Constants

View Source
const DefaultAppName = "core-agent"

DefaultAppName tags this process in the ADK runner. Telemetry and session stores key off this; override with WithAppName when embedding in a host that wants its own identity.

View Source
const DefaultInstruction = `You are a helpful assistant. Be concise and accurate.

Tools execute in parallel by default. Execute multiple independent tool calls in parallel when feasible — searching, reading files, independent shell commands, or editing different files. When investigating code, if you need to read multiple files or grep multiple directories, issue all the tool calls in a single response; do not execute them one by one.

Do not issue multiple ` + "`edit_file`" + ` or ` + "`write_file`" + ` calls targeting the same path in one response — those must run sequentially across turns so each edit sees the prior result; parallel writes to the same file race and corrupt state. Efficiency is secondary to correctness: if you are unsure whether two operations are independent, run them sequentially.`

DefaultInstruction is the system instruction applied to every agent that doesn't override it via WithInstruction. Comprises a baseline helpfulness/concision directive plus a parallelism mandate adapted from google-gemini/gemini-cli's prompt patterns (packages/core/src/prompts/snippets.ts).

The parallelism mandate is load-bearing for Gemini, which otherwise emits one tool call per assistant turn even when independent operations are obviously batchable. Direct measurement (dev/parallel-probe/) shows Gemini-3.1-pro-preview-customtools without this instruction never batched across 65 search turns; Claude is less affected but still benefits marginally.

Exported so consumers building on WithInstruction can reuse the baseline + mandate verbatim: `agent.WithInstruction(agent.DefaultInstruction + "\n\n" + extra)`.

View Source
const DefaultSchedulingInstruction = `` /* 1137-byte string literal not displayed */

DefaultSchedulingInstruction is the composable system-instruction constant for autonomous loops that have a tools.Scheduler installed (via RunAutonomous's WithScheduler option, or per-subagent via BackgroundAgentManager). It covers the cross-cutting cadence and state-persistence guidance that doesn't fit in the schedule_next_turn tool's per-call description.

Opt-in by composition — the autonomous driver does NOT inject this automatically. Recommended consumer usage:

agent.New(m,
    agent.WithInstruction(
        agent.DefaultInstruction + "\n\n" +
        agent.DefaultSchedulingInstruction + "\n\n" +
        myConsumerInstruction,
    ),
    agent.WithTools(...),
)

See docs/scheduled-monitoring-design.md for the design rationale and the matching tool-description text (Layer 1 of the steering pattern).

Variables

View Source
var ErrDepthExceeded = errors.New("agent: BackgroundAgentManager: max subagent depth exceeded")

ErrDepthExceeded is returned by Spawn when the calling context is already at the max subagent depth.

View Source
var ErrInboxClosed = errors.New("agent: inbox closed")

ErrInboxClosed is returned by Agent.Inject when the agent's inbox has been closed (typically because the agent has been shut down via its run context cancelling). Callers that publish messages on an unrelated lifecycle (e.g. a stdin scanner) should treat this as "stop publishing."

View Source
var ErrManagerClosed = errors.New("agent: BackgroundAgentManager: closed")

ErrManagerClosed is returned by Spawn after Close has been called.

View Source
var ErrNoParent = errors.New("agent: BackgroundAgentManager: parent agent not wired (use agent.WithBackgroundManager)")

ErrNoParent is returned by Spawn when the manager hasn't been attached to an agent yet (i.e. agent.New(... WithBackgroundManager ...) hasn't run).

View Source
var ErrNoSpawner = errors.New("agent: NewSpawnRemoteAgentTool: spawner is required (use RefuseRemoteAgentSpawner for the headless / unattended case)")

ErrNoSpawner is returned by NewSpawnRemoteAgentTool when nil is passed for the spawner. Use RefuseRemoteAgentSpawner instead of nil when you want the tool registered but no-op.

View Source
var ErrSubagentExists = errors.New("agent: BackgroundAgentManager: subagent with this name already exists")

ErrSubagentExists is returned by Spawn when a subagent with the requested name is already registered (running or terminal). Names must be unique within a manager.

View Source
var ErrTooManyConcurrent = errors.New("agent: BackgroundAgentManager: max concurrent subagents reached")

ErrTooManyConcurrent is returned by Spawn when the manager already has MaxConcurrent running subagents.

View Source
var ErrUnknownScheduler = errors.New("agent: BackgroundAgentManager: unknown scheduler choice")

ErrUnknownScheduler is wrapped and returned by Spawn when a spec.Scheduler value isn't one of the recognized choices.

View Source
var ErrUnknownTool = errors.New("agent: BackgroundAgentManager: unknown tool")

ErrUnknownTool is wrapped and returned by Spawn when a spec.Tools or spec.Extras entry isn't present in the catalog.

Functions

func CurrentSubagentDepth

func CurrentSubagentDepth(ctx context.Context) int

CurrentSubagentDepth returns the recursion depth of the current subagent invocation. Zero when we're not inside a subagent (i.e. the parent's top-level turn).

func NewBackgroundSpawnTools added in v1.2.0

func NewBackgroundSpawnTools(mgr *BackgroundAgentManager) []tool.Tool

NewBackgroundSpawnTools is a convenience that returns all four model-facing background-agent tools in one slice, ready to pass through agent.WithTools. The bundled CLI uses this to wire the full suite atomically.

func NewCheckAgentTool added in v1.2.0

func NewCheckAgentTool(mgr *BackgroundAgentManager) tool.Tool

NewCheckAgentTool returns a tool the parent's model can call to inspect one subagent's detailed status — including its terminal result (final text, stop reason, totals) once it's finished.

func NewListAgentsTool added in v1.2.0

func NewListAgentsTool(mgr *BackgroundAgentManager) tool.Tool

NewListAgentsTool returns a tool the parent's model can call to see every subagent the manager has tracked (running + terminal). Empty list when none have been spawned.

func NewSpawnAgentTool added in v1.2.0

func NewSpawnAgentTool(mgr *BackgroundAgentManager) tool.Tool

NewSpawnAgentTool returns a tool the parent's model can call to launch a new in-process background subagent. The tool's name in the model's view is "spawn_agent"; the registered handler defers to mgr.Spawn after reading the calling tool.Context's branch so the new subagent's events land in the right hierarchical branch.

Spawn errors (invalid spec, depth/concurrency cap, unknown tool) are returned as the tool's result text rather than as Go errors, so the model sees them in conversation context and can adapt (e.g. by stopping a sibling first). Provider/model construction errors propagate normally since those are typically caller-fixable configuration problems.

func NewSpawnRemoteAgentTool added in v1.2.0

func NewSpawnRemoteAgentTool(spawner RemoteAgentSpawner, mgr *BackgroundAgentManager) (tool.Tool, error)

NewSpawnRemoteAgentTool returns a tool the parent's model can call to launch an out-of-process subagent via the consumer-supplied spawner. The handle's Events() channel is drained by a goroutine the manager starts inside Spawn; events of Kind="alert" land on the manager's alert channel under the subagent's name, and the terminal handle status is recorded for list/check/stop uniformity alongside in-process subagents.

Pass nil for mgr to skip the alert + registry fan-in (alerts will be dropped); typically you want both wired, especially for the bundled CLI.

func NewStopAgentTool added in v1.2.0

func NewStopAgentTool(mgr *BackgroundAgentManager) tool.Tool

NewStopAgentTool returns a tool the parent's model can call to cancel a running subagent. No-op if the subagent already terminal. Returns an error result (not a tool failure) when the name is unknown so the model can adapt.

func NewSubagentTool

func NewSubagentTool(opts SubagentOptions) (tool.Tool, error)

NewSubagentTool wraps an *agent.Agent as a tool the parent's model can call. The subagent runs through ADK's runner using the parent's session.Service (so its events stream live into the same audit log as the parent), with session.Event.Branch set to "<parent_branch>.<this>" so the audit log stays distinguishable and ADK's contents-processor branch filter keeps the subagent's events from leaking into the parent's next-turn LLM request.

The parent's session.Service is captured from Inner — Inner is expected to have been constructed with the same WithEventLog (or WithSessionService) the parent uses. The agent.WithSubagents convenience option handles this wiring automatically; consumers who construct subagent tools directly via NewSubagentTool need to share the session.Service themselves.

Types

type Agent

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

Agent is the wrapper around an ADK llmagent + runner. One Agent represents one configured LLM-driven role.

func New

func New(model adkmodel.LLM, opts ...Option) (*Agent, error)

New constructs an Agent backed by model. Returns a clear error if the underlying ADK constructors reject the configuration.

func (*Agent) AgentName

func (a *Agent) AgentName() string

AgentName returns the configured agent name (the WithName value) stored on construction. Used by NewSubagentTool to derive a default tool name.

func (*Agent) AppName

func (a *Agent) AppName() string

AppName returns the AppName the agent was constructed with (the value passed to runner.Config). Used by callers that need to identify the session triple (app, user, session) for queries against the event log or session.Service.

func (*Agent) BackgroundManager added in v1.2.0

func (a *Agent) BackgroundManager() *BackgroundAgentManager

BackgroundManager returns the BackgroundAgentManager the agent was constructed with via WithBackgroundManager, or nil when none was wired. Used by spawn tools + the runner's REPL alert display to reach the manager without keeping a separate reference.

func (*Agent) EventLog

func (a *Agent) EventLog() *eventlog.Handle

EventLog returns the *eventlog.Handle the agent was constructed with via WithEventLog, or nil when no event log was wired. Use to reach back to Stream.Since / Stream.Watch for replay or live tail without keeping a separate reference.

func (*Agent) InboxArrived added in v1.3.0

func (a *Agent) InboxArrived() <-chan struct{}

InboxArrived returns a channel that fires when a new message has been injected. The harness can use this to decide when to start the next turn instead of polling — typical pattern:

for {
    select {
    case <-ctx.Done():
        return
    case <-ag.InboxArrived():
        runOneTurn("continue") // inbox prepended automatically
    }
}

The channel has a 1-buffer signal-style semantics: multiple pushes between consumer wake-ups coalesce into one notification (the consumer drains the queue and sees them all).

func (*Agent) Inject added in v1.3.0

func (a *Agent) Inject(message string) error

Inject queues message on the agent's inbox. The next call to Agent.Run will drain pending messages, format them as an "[Inbox]" block, and prepend the block to the prompt the model sees.

Inject is safe to call concurrently from any goroutine — typical usage is a harness goroutine reading from stdin, an HTTP handler, or an orchestrator's gRPC stream. Drop-oldest backpressure kicks in when the queue exceeds the soft cap (256) so a stuck consumer can't deadlock the agent.

Returns ErrInboxClosed once the agent has been shut down; callers publishing on an unrelated lifecycle should treat that as "stop."

func (*Agent) RequestWake added in v1.6.0

func (a *Agent) RequestWake()

RequestWake fires the agent's wake signal. Used by:

  • BackgroundAgentManager (via a driver-side goroutine) to wake a sleeping supervisor as soon as a child alert arrives, instead of waiting for the supervisor's next scheduled wake.
  • The future attach-mode `POST /sessions/<id>/wake` endpoint, when an operator outside the process wants an immediate rescan.
  • Operator input via Agent.Inject — Inject calls RequestWake internally so a typed command also pierces an active sleep.

No-op when the agent has no wake signal (defensive: hand-constructed Agent structs used in tests don't necessarily wire one up).

func (*Agent) Run

func (a *Agent) Run(ctx context.Context, prompt string) iter.Seq2[*session.Event, error]

Run executes one turn of the agent against prompt and returns the event iterator straight from ADK's runner. Callers are expected to range over the returned iter.Seq2 and consume events as they arrive — partial text chunks, tool calls, and the final TurnComplete event.

Multi-turn use: call Run() repeatedly on the same Agent. The configured session ID is reused across calls, so the ADK accumulates conversation history automatically.

When a BackgroundAgentManager is wired via WithBackgroundManager, any alerts background subagents have emitted since the last turn are drained (non-blocking) and prepended to the prompt so the parent's model sees them before deciding what to do next.

Inbox messages queued via Agent.Inject from external callers (harness, orchestrator, HTTP handler) are also drained and prepended, sibling to the alerts block. Ordering: alerts go first (internal state changes); inbox goes second (external input, closer to the prompt logically); then the original prompt.

func (*Agent) RunWithContents added in v1.7.0

func (a *Agent) RunWithContents(ctx context.Context, contents []*genai.Content) iter.Seq2[*session.Event, error]

RunWithContents drives one agent turn from a pre-built conversation history (genai.Contents) instead of a single prompt string. The trailing message is treated as the new user input; everything before it is pre-populated into a fresh session as history events.

Each call uses a fresh sessionID so prior calls don't accumulate state — the caller-supplied history is authoritative. Use this when integrating with a runtime (the AX adapter is the motivating example) that supplies the full conversation history per turn rather than relying on a session-managed prompt.

The last content's Role must be genai.RoleUser; non-user trailing messages return an error. Empty contents return an error.

func (*Agent) SessionID

func (a *Agent) SessionID() string

SessionID returns the session identifier the agent was constructed with. Combined with AppName + UserID this is the key the event log uses to scope ForSession queries.

func (*Agent) SessionService

func (a *Agent) SessionService() session.Service

SessionService returns the session.Service backing this agent. When no WithSessionService option was passed at construction this is the default in-memory service. Useful for callers that want to query session state directly (e.g. listing prior events) without keeping their own reference to the Service they passed in.

func (*Agent) Tools

func (a *Agent) Tools() []tool.Tool

Tools returns the resolved tool list the agent was constructed with — including any subagent tools materialized by WithSubagents. Useful for diagnostics ("does my parent know about the research subagent?") without introspecting ADK internals.

func (*Agent) UserID

func (a *Agent) UserID() string

UserID returns the user identifier the agent was constructed with.

func (*Agent) WakeRequested added in v1.6.0

func (a *Agent) WakeRequested() <-chan struct{}

WakeRequested returns a channel that fires whenever RequestWake (or Inject, which calls RequestWake internally) is invoked. The autonomous driver attaches this channel to the context it passes to Scheduler.BeforeNextTurn so SleepScheduler can select on it alongside its sleep timer and ctx.Done. Buffered(1) coalesced semantics: multiple wakes between consumer drains land as one notification.

type Alert added in v1.2.0

type Alert struct {
	From      string
	Text      string
	Timestamp time.Time
	Kind      string // "alert" (default) | "completed" | "failed" | "stopped"
}

Alert is one report message a spawned subagent (or the manager itself on completion) emitted upward to the parent.

type AutonomousHandle added in v1.3.0

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 added in v1.3.0

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 added in v1.3.0

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 added in v1.3.0

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) Pause added in v1.3.0

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 added in v1.6.0

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 added in v1.6.0

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 added in v1.3.0

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 added in v1.3.0

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 added in v1.3.0

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 added in v1.3.0

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 added in v1.3.0

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 added in v1.6.0

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 added in v1.6.0

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 added in v1.6.0

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 added in v1.6.0

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 added in v1.6.0

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 added in v1.3.0

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 added in v1.3.0

func (s AutonomousStatus) String() string

String renders the status for diagnostics and tool results.

type BackgroundAgentManager added in v1.2.0

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

BackgroundAgentManager owns the lifecycle of in-process background subagents that the parent agent's model decides to spawn at runtime via the spawn_agent tool family (see background_tools.go).

One manager backs one parent agent. The manager:

  • constructs each spawned subagent against the parent's session service (with branch isolation), the parent's permissions gate (inherited wholesale), and a fresh model.LLM (one client per spawn, see docs/background-subagents-design.md);

  • runs each subagent in its own goroutine via RunAutonomous with per-subagent budgets;

  • multiplexes alert + completion messages from every running subagent onto a single channel the parent's run loop drains before each turn (see Agent.Run);

  • enforces a configurable max-concurrent cap on top of the subagent depth cap (the existing CurrentSubagentDepth check from subagent.go) so a runaway model can't spawn unboundedly.

Construction order is intentional: the manager is built first (without a parent reference), the spawn-related tools are built against the manager, the parent agent.New is called with those tools registered and the manager wired via WithBackgroundManager. agent.New stamps the parent back-reference onto the manager during construction so Spawn can read parent.SessionService / AppName / UserID / SessionID without the consumer plumbing them twice.

func NewBackgroundAgentManager added in v1.2.0

func NewBackgroundAgentManager(opts ...BackgroundManagerOption) (*BackgroundAgentManager, error)

NewBackgroundAgentManager builds a manager from the supplied options. Required: provider + modelID (WithBackgroundProvider). The parent agent reference is established later by WithBackgroundManager when the parent is constructed via agent.New — until that wiring happens, Spawn returns ErrNoParent.

func (*BackgroundAgentManager) Alerts added in v1.2.0

func (m *BackgroundAgentManager) Alerts() <-chan Alert

Alerts returns the channel external consumers (the runner's REPL alert display goroutine, library consumers building their own UIs) drain to surface alerts as they arrive. The pre-turn drain inside Agent.Run uses PrependPendingAlerts instead — that path uses a non-blocking drain so it doesn't compete with this channel.

Note: a single alert lands on this channel exactly once. Consumers must agree on who drains it; today the runner.WriteEvents alert- display goroutine drains for REPL display, and Agent.Run drains for pre-turn injection. They're separated by which path is active (REPL vs headless vs autonomous).

func (*BackgroundAgentManager) Close added in v1.2.0

func (m *BackgroundAgentManager) Close() error

Close stops every running subagent and prevents new spawns. Blocks until each goroutine has exited so callers don't race with shutdown. Idempotent.

func (*BackgroundAgentManager) Get added in v1.2.0

Get returns the handle for the named subagent. ok=false when the name isn't registered.

func (*BackgroundAgentManager) List added in v1.2.0

List returns all currently-tracked handles, sorted by start time. Terminal handles remain in the list until Close (so check_agent can return final status). Defensive copy of slice.

func (*BackgroundAgentManager) OnAlert added in v1.2.0

func (m *BackgroundAgentManager) OnAlert(h func(Alert))

OnAlert installs a synchronous hook called from pushAlert before the channel send. Useful for surfacing alerts to side channels (e.g. the REPL's inline display) without competing with the model- context drain on Alerts() / PrependPendingAlerts. Pass nil to clear.

The hook runs in whichever goroutine triggered the alert (typically a subagent's goroutine for report_alert, the Spawn goroutine for completion). Hooks should not block.

func (*BackgroundAgentManager) Parent added in v1.2.0

func (m *BackgroundAgentManager) Parent() *Agent

Parent returns the agent the manager is attached to, or nil if no agent.New has wired it yet. Exposed for tests + diagnostics.

func (*BackgroundAgentManager) PrependPendingAlerts added in v1.2.0

func (m *BackgroundAgentManager) PrependPendingAlerts(prompt string) string

PrependPendingAlerts drains every pending alert from the manager's channel (non-blocking) and, when non-empty, returns prompt with a "[Background reports]" header prepended. Empty channel returns prompt unchanged.

Called by Agent.Run before each turn so the parent's model sees what its subagents have reported since the last turn.

func (*BackgroundAgentManager) Spawn added in v1.2.0

func (m *BackgroundAgentManager) Spawn(ctx context.Context, parentBranch string, spec BackgroundSpec) (*BackgroundHandle, error)

Spawn launches a new background subagent under spec. parentBranch is the branch the calling tool's context carries (typically empty for the top-level parent, "bg.<name>" when nested); the subagent's own branch becomes "<parentBranch>.bg.<spec.Name>" via composeBranch so the eventlog audit trail remains hierarchical.

Returns the handle immediately; the subagent's goroutine runs RunAutonomous against spec.Goal until budgets fire, the model signals done via report_completed, the parent calls Stop, or the goroutine's context is cancelled.

Returned errors are pre-flight: invalid spec, depth or concurrency cap exceeded, unknown tool name, or manager not yet attached to a parent. Once the goroutine is running, terminal errors land on the handle (h.Err()) and a corresponding Alert is pushed.

func (*BackgroundAgentManager) Stop added in v1.2.0

func (m *BackgroundAgentManager) Stop(name string) error

Stop cancels the named subagent's context. The goroutine exits at the next ctx-aware checkpoint inside RunAutonomous. Returns nil even when the subagent is already terminal; surfaces "not found" when the name isn't registered.

type BackgroundBudgets added in v1.2.0

type BackgroundBudgets struct {
	MaxTurns       int
	MaxCost        float64
	MaxWallclock   time.Duration
	PerTurnTimeout time.Duration
}

BackgroundBudgets bounds a single spawned subagent's run. Zero values mean no cap for that dimension. The manager's WithBackgroundDefaultBudgets supplies the defaults; per-spawn overrides come from the spawn_agent tool args.

type BackgroundHandle added in v1.2.0

type BackgroundHandle struct {
	Name      string
	Branch    string
	StartedAt time.Time
	// contains filtered or unexported fields
}

BackgroundHandle is the lifecycle record for one spawned subagent. Exposed read-only via Manager.List / Manager.Get so the parent model's check_agent tool can introspect status without reaching into internal state.

func (*BackgroundHandle) Done added in v1.2.0

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

Done returns a channel that closes when the subagent's goroutine exits. Use to wait for completion from the parent without polling.

func (*BackgroundHandle) Err added in v1.2.0

func (h *BackgroundHandle) Err() error

Err returns the terminal error if the subagent's RunAutonomous returned one. Nil while running or on clean completion.

func (*BackgroundHandle) Result added in v1.2.0

func (h *BackgroundHandle) Result() *RunResult

Result returns the terminal RunResult if the subagent has finished, or nil if it's still running.

func (*BackgroundHandle) Status added in v1.2.0

func (h *BackgroundHandle) Status() BackgroundStatus

Status returns the current status (safe for concurrent callers).

type BackgroundManagerOption added in v1.2.0

type BackgroundManagerOption func(*bgMgrConfig)

BackgroundManagerOption configures NewBackgroundAgentManager.

func WithBackgroundAlertBuffer added in v1.2.0

func WithBackgroundAlertBuffer(n int) BackgroundManagerOption

WithBackgroundAlertBuffer sets the alert channel buffer. When full, the oldest pending alert is dropped to make room (with a warning logged). Default 256.

func WithBackgroundCatalog added in v1.2.0

func WithBackgroundCatalog(tools []tool.Tool) BackgroundManagerOption

WithBackgroundCatalog registers the tool instances spawn_agent arguments can refer to by name. Pass the parent's already-gated tool list (typically tools.Default() plus any MCP/skill tools flattened to a single slice); the manager looks up each requested tool by Tool.Name(). Tools not listed here can't be requested.

func WithBackgroundDefaultBudgets added in v1.2.0

func WithBackgroundDefaultBudgets(b BackgroundBudgets) BackgroundManagerOption

WithBackgroundDefaultBudgets sets the budgets a spawn request inherits when its own per-call args don't override. Default: 50 turns / $1.00 / 10 minutes, no per-turn timeout.

func WithBackgroundDefaultScheduler added in v1.6.0

func WithBackgroundDefaultScheduler(s coretools.Scheduler) BackgroundManagerOption

WithBackgroundDefaultScheduler sets the tools.Scheduler that spawned subagents inherit when the per-spawn BackgroundSpec.Scheduler is empty or "default". Pass tools.SleepScheduler() for the canonical in-process supervisor topology where the parent runs as a long-lived daemon and children sleep between scans. Pass tools.ExitOnDeferScheduler() for orchestrator-managed deployments. Pass nil (or leave unset) to run subagents without between-turn pacing — the schedule_next_turn tool is then unavailable to those subagents.

Per-spawn overrides via BackgroundSpec.Scheduler win when supplied; see Spawn / NewSpawnAgentTool.

func WithBackgroundGate added in v1.2.0

func WithBackgroundGate(g *permissions.Gate) BackgroundManagerOption

WithBackgroundGate wires the permissions gate that spawned subagents inherit (by reference; same instance). Required when running in ask/allow mode; the manager rejects spawn requests when the gate is in ask-mode without a prompter (same deadlock guard as RunAutonomous).

func WithBackgroundMaxConcurrent added in v1.2.0

func WithBackgroundMaxConcurrent(n int) BackgroundManagerOption

WithBackgroundMaxConcurrent caps how many subagents can be Running at once. Spawn calls that would exceed this return a clean tool- result error the model can adapt to. Default 8.

func WithBackgroundMaxDepth added in v1.2.0

func WithBackgroundMaxDepth(n int) BackgroundManagerOption

WithBackgroundMaxDepth caps how deep the subagent tree can go. A spawn from a context already at depth>=N returns an error result instead of nesting further. Default 2.

func WithBackgroundProvider added in v1.2.0

func WithBackgroundProvider(p models.Provider, modelID string) BackgroundManagerOption

WithBackgroundProvider wires the model provider + model ID used to build a fresh LLM client per spawn. Required.

type BackgroundSpec added in v1.2.0

type BackgroundSpec struct {
	Name         string
	SystemPrompt string
	Goal         string
	Tools        []string
	Extras       []string
	Budgets      BackgroundBudgets
	// Scheduler selects the between-turn scheduler the subagent's
	// RunAutonomous loop honors. Valid values: "" or "default" (use
	// the manager's WithBackgroundDefaultScheduler — may itself be
	// nil), "sleep" (in-process goroutine sleep), "exit_on_defer"
	// (orchestrator-managed exit), "none" (no scheduler — the
	// schedule_next_turn tool won't be registered for this subagent).
	Scheduler string
}

BackgroundSpec is the request shape a single Spawn call expects. Built from the spawn_agent tool args by the tool handler.

type BackgroundStatus added in v1.2.0

type BackgroundStatus int

BackgroundStatus is the lifecycle state of a background subagent.

const (
	// StatusRunning — goroutine alive, RunAutonomous loop active.
	StatusRunning BackgroundStatus = iota
	// StatusCompleted — RunAutonomous returned with Reason==Completed.
	StatusCompleted
	// StatusFailed — RunAutonomous returned with a non-Completed
	// terminal reason (MaxTurns, MaxCost, error, etc.).
	StatusFailed
	// StatusStopped — explicit Stop() canceled the run.
	StatusStopped
)

func (BackgroundStatus) String added in v1.2.0

func (s BackgroundStatus) String() string

String renders the status for tool results and diagnostics.

type BuildFunc added in v1.3.0

type BuildFunc func(extraTools []tool.Tool) (*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. The Agent's session.Service must be wired (durable or in-memory).

type Option

type Option func(*options)

Option mutates Agent construction. Use the With* helpers below.

func WithAppName

func WithAppName(s string) Option

WithAppName overrides the AppName handed to the ADK runner. Useful when embedding so telemetry and session stores can distinguish multiple agents inside one binary.

func WithBackgroundManager added in v1.2.0

func WithBackgroundManager(mgr *BackgroundAgentManager) Option

WithBackgroundManager attaches a BackgroundAgentManager to the agent. The manager's parent back-reference is set during construction so its Spawn calls can read the agent's session triple + session.Service without the consumer plumbing them twice.

Each turn of Agent.Run drains pending alerts from the manager's channel (non-blocking) and prepends them to the prompt the underlying ADK runner sees, so the parent's model is aware of what its background subagents have reported since the last turn.

Pass nil to clear (e.g. for tests that re-construct an agent).

func WithDescription

func WithDescription(s string) Option

WithDescription overrides the agent's description.

func WithEventLog

func WithEventLog(h *eventlog.Handle) Option

WithEventLog wires an eventlog.Handle into the agent — the Handle's Service becomes the agent's session.Service (so every event lands in the durable log), and the Handle is stored on the agent so callers can reach back to it for replay/watch via Agent.EventLog().

Equivalent to WithSessionService(h.Service) plus a stash of the Handle for later access; passing nil is a no-op.

func WithInstruction

func WithInstruction(s string) Option

WithInstruction overrides the system instruction.

func WithName

func WithName(s string) Option

WithName overrides the agent's display name (visible in OTEL spans).

func WithSession

func WithSession(userID, sessionID string) Option

WithSession overrides the user/session IDs handed to the ADK runner. Reuse the same pair across Run() calls to preserve conversation history.

func WithSessionService

func WithSessionService(s session.Service) Option

WithSessionService overrides the session.Service handed to the ADK runner. The default is session.InMemoryService(), which loses all state when the process exits. Pass a durable Service (typically the one returned by eventlog.Open(...).Service when wiring the audit log + crash-resume substrate) to persist sessions across runs.

The supplied Service is also exposed via Agent.SessionService() so callers can query session state directly without keeping their own reference. Passing nil restores the default.

func WithStreaming

func WithStreaming(m adkagent.StreamingMode) Option

WithStreaming overrides the streaming mode. Default is StreamingModeSSE (required to receive Partial events).

func WithSubagents

func WithSubagents(agents []*Agent) Option

WithSubagents registers each agent as a callable tool the parent's model can invoke by name. The subagent runs through ADK's runner using the parent's session.Service (so its events stream live into the same audit log) with session.Event.Branch set to "<parent_branch>.<subagent_name>" — ADK's contents-processor branch filter then keeps the subagent's events from leaking back into the parent's next-turn LLM request, which preserves context isolation while keeping the audit log unified.

Each subagent's tool name comes from its own WithName value. Use NewSubagentTool directly for per-subagent overrides (custom name, description, depth cap, branch label).

Resolved at the end of New() so that the parent's session.Service and session triple — set by other With* options — are captured at the point the subagent tools are constructed.

func WithSystemInstructionPrefix

func WithSystemInstructionPrefix(prefix string) Option

WithSystemInstructionPrefix prepends prefix to the agent's default instruction. Used for memory loading: AGENTS.md / CLAUDE.md / GEMINI.md project memory becomes part of the system prompt rather than the user's first message.

func WithTools

func WithTools(ts []tool.Tool) Option

WithTools registers a set of tools the agent may call. Order is preserved but immaterial; ADK keys tools by Name.

func WithToolsets

func WithToolsets(ts []tool.Toolset) Option

WithToolsets registers groups of tools (MCP servers, skills, etc.). Each Toolset implements google.golang.org/adk/tool.Toolset and is passed to llmagent.Config.Toolsets.

type RemoteAgentEvent added in v1.2.0

type RemoteAgentEvent struct {
	Kind      string // "alert" | "log" | "completed" | "failed" | "stopped"
	Text      string
	Timestamp time.Time
}

RemoteAgentEvent is what the consumer's transport delivers back from the remote subagent. The Kind field is the manager's hook for classifying — "alert" gets fanned into the parent's alert channel as a normal Alert; terminal kinds ("completed" / "failed" / "stopped") trigger the terminal Alert + handle close.

type RemoteAgentHandle added in v1.2.0

type RemoteAgentHandle interface {
	// ID returns the spawner-assigned identifier for diagnostics.
	// Stable across the handle's lifetime.
	ID() string

	// Status returns the current lifecycle state of the remote
	// subagent. Implementations are expected to be cheap (cached
	// status from the last received event is fine).
	Status(ctx context.Context) (RemoteAgentStatus, error)

	// Stop signals the remote subagent to terminate. The
	// implementation decides whether this is best-effort (e.g.
	// async cancel of a K8s Job) or synchronous.
	Stop(ctx context.Context) error

	// Events returns a channel of events streamed from the remote
	// subagent. The consumer's implementation closes the channel
	// once the remote has terminated; the manager's fan-in
	// goroutine exits on close.
	Events() <-chan RemoteAgentEvent
}

RemoteAgentHandle is the contract for a running remote subagent. Implementations live in the consumer's package (the substrate adapter); the manager treats it opaquely apart from draining Events() for the alert pipeline.

type RemoteAgentSpawner added in v1.2.0

type RemoteAgentSpawner interface {
	// Spawn launches a remote subagent under spec and returns a
	// handle the manager uses for status checks, stop, and event
	// fan-in. Errors at this point propagate as Go errors (caller
	// is wiring the spawner directly); errors that surface later
	// flow through RemoteAgentHandle.Events() as Kind="failed".
	Spawn(ctx context.Context, spec RemoteAgentSpec) (RemoteAgentHandle, error)
}

RemoteAgentSpawner is implemented by consumers who want the parent agent's model to be able to spawn out-of-process subagents — gRPC to a remote agent server, K8s Jobs, Cloud Run, NATS-dispatched workers, anything that runs an agent somewhere other than this process. core-agent stays agnostic about transport: the consumer's Spawn implementation is responsible for whatever IPC and lifecycle the substrate requires.

Mirrors the consumer-pluggability shape of tools.NewAskUserTool + tools.Prompter: a small interface the host implements, wired into a tool the model can call uniformly.

func RefuseRemoteAgentSpawner added in v1.2.0

func RefuseRemoteAgentSpawner(reason string) RemoteAgentSpawner

RefuseRemoteAgentSpawner returns a spawner whose Spawn always errors with reason. Use it as the default spawner when running headless / unattended so the model sees a clean tool result it can adapt to, rather than the bundled CLI crashing on a nil dereference. Analog of tools.RefusePrompter.

type RemoteAgentSpec added in v1.2.0

type RemoteAgentSpec struct {
	ID           string
	Name         string
	SystemPrompt string
	Goal         string
	Tools        []string
	Extras       []string
	Budgets      BackgroundBudgets
}

RemoteAgentSpec is what the manager hands to the consumer's spawner — the same shape as the in-process BackgroundSpec, plus a stable opaque ID the consumer can use as a primary key in their substrate (e.g. the K8s Job name). Spec.Name is the human-facing identifier the parent's model chose; Spec.ID is the manager's invariant under the manager's registry. They're usually the same string but kept distinct so consumers don't have to guess.

type RemoteAgentStatus added in v1.2.0

type RemoteAgentStatus int

RemoteAgentStatus mirrors BackgroundStatus but lives in the remote space. Implementations map their native states (K8s Job phase, HTTP response, etc.) onto these.

const (
	RemoteStatusPending RemoteAgentStatus = iota
	RemoteStatusRunning
	RemoteStatusCompleted
	RemoteStatusFailed
	RemoteStatusStopped
)

func (RemoteAgentStatus) String added in v1.2.0

func (s RemoteAgentStatus) String() string

type ResumeBuildFunc

type ResumeBuildFunc func(extras []tool.Tool, sessionID string) (*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, 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"
)

type SubagentOptions

type SubagentOptions struct {
	// Inner is the *agent.Agent to expose as a tool the parent's
	// model can call. The tool's function name comes from
	// Inner.AgentName() (set via agent.WithName), unless overridden
	// via Name. The tool's description comes from Inner's
	// llmagent.Description, unless overridden via Description.
	Inner *Agent

	// Name overrides the function name shown to the parent's model.
	// Empty falls back to Inner.AgentName().
	Name string

	// Description overrides the function description shown to the
	// parent's model. Empty falls back to Inner's Description (or a
	// generic fallback when that's also empty).
	Description string

	// MaxDepth caps recursion depth. A subagent at depth >= MaxDepth
	// that is invoked from another subagent gets an error result
	// rather than being allowed to recurse. Default 2; pass a
	// larger value if your agent topology genuinely needs deeper
	// nesting.
	MaxDepth int

	// Branch overrides the branch label appended to the parent's
	// branch on the subagent's events. Defaults to the tool name
	// (which is Inner.AgentName() unless Name overrides it). The
	// resulting branch is "<parent_branch>.<this>".
	Branch string

	// ParentService, when non-nil, overrides the session.Service
	// the subagent's runner uses. The agent.WithSubagents
	// convenience option fills this in automatically with the
	// parent agent's service so subagent events land in the
	// parent's audit log without any consumer plumbing.
	//
	// When nil, NewSubagentTool falls back to Inner.SessionService()
	// — which is fine for callers who construct subagents
	// pre-wired against the same Handle.
	ParentService session.Service

	// ParentAppName, ParentUserID, ParentSessionID identify the
	// parent's session triple. When set, the subagent runs through
	// the parent's session row (with branch isolation) so cross-
	// session audit queries find both. Empty values fall back to
	// Inner's own AppName/UserID/SessionID. Set automatically by
	// agent.WithSubagents.
	ParentAppName   string
	ParentUserID    string
	ParentSessionID string
}

SubagentOptions configures NewSubagentTool. Inner is required; everything else has sensible defaults.

Jump to

Keyboard shortcuts

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