Help us shape the future of Go! Take the 2026 Go Developer Survey

agent

package
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

Package agent provides LLM agents built on the runtime loop, composable as sub-agents, and a Runner that persists conversations in sessions.

Tool call pipeline

New installs its loop middleware in this order: input guardrails, hooks (WithHooks), skills (WithSkills), the middleware of WithMiddleware in the order given, the permission policy (WithPermissions), handoffs, context engineering, and finally tool and output guardrails. Each tool call the model requests then passes through these steps:

  1. BeforeTool, in that order: PreToolUse hooks, the allowed and disallowed tools of an active skill, the WithMiddleware middleware, the permission policy, the handoff check, and tool input guardrails. Each stage sees the arguments as earlier stages rewrote them and may allow the call, ask for approval or deny it. The most restrictive decision wins whatever the order, so a hook that allows a call does not lift a permission rule's ask or deny, and the first denial skips the remaining stages. The permission policy also receives the decision so far, which changes its result in dontAsk mode. A tool input guardrail that trips ends the run instead of denying the call.
  2. Approval, when a stage asked, or when no stage decided and the tool requires approval (tool.Info.RequiresApproval, per call for a tool.CallApprover). The Approver of WithApprover decides; without one the run is interrupted and resumed with the approvals. An allowed call skips approval.
  3. RevalidateTool, when an approval changed the arguments: the permission policy, tool input guardrails and any other loop.ToolRevalidator check them again. BeforeTool, including hooks, does not run again.
  4. Execution. The arguments are validated against the tool's schema, then the call runs inside the WrapTool middleware, the first in the order above outermost, so tool output guardrails wrap the call most closely. Inside those wrappers run the tool middleware of WithToolMiddleware, the first outermost, and then the tool.
  5. AfterTool, in reverse order: the guardrails first, which end the run if a tool output guardrail tripped during execution, then the permission policy, the WithMiddleware middleware, skills, and PostToolUse or PostToolUseFailure hooks last. Denied calls pass AfterTool too, but fire no hooks.

Choose the mechanism by purpose:

  • permission.Policy (WithPermissions): rules and modes for tools, paths and commands, with remembered approvals.
  • hook.Manager (WithHooks): Claude Code compatible command and HTTP hooks, for policies kept outside the program.
  • Tool guardrails (WithToolGuardrail): checks whose failure must stop the run, on the arguments that will run and the result the tool returned.
  • A loop.Middleware with BeforeTool (WithMiddleware): policies written in Go. Middleware that enforces an argument policy must also implement loop.ToolRevalidator.
  • tool.Middleware (WithToolMiddleware): execution concerns such as timeouts and output truncation that need no access to the run; use a loop.ToolWrapper when the wrapper needs it.
  • WithApprover, tool.CallApprover or tool.Info.RequiresApproval: which calls need approval and who grants it.

Index

Constants

View Source
const ActiveAgentKey = "agentx.active_agent"

ActiveAgentKey is the session state key holding the name of the agent a Runner's session was last handed off to, which handles the session's next message; see WithHandoffs. It is absent while the Runner's own agent is active. Delete it to return the session to that agent.

View Source
const CheckpointsKey = "agentx.checkpoints"

CheckpointsKey is the session state key holding the checkpoints of a session; see Runner.Checkpoints.

View Source
const DefaultMaxDepth = 5

DefaultMaxDepth bounds how deeply sub-agents can be nested: a sub-agent of a top-level agent is at depth 1, its own sub-agents at depth 2.

View Source
const DefaultMaxHandoffs = 10

DefaultMaxHandoffs bounds the handoffs of a run; see WithMaxHandoffs.

View Source
const FailedRunKey = "agentx.failed_run"

FailedRunKey is the session state key holding the ID of the session's last run if it failed, for example on a provider outage. Unlike an interrupted run, it does not block new runs: Runner.Resume continues it, and the next Run gives it up.

View Source
const HandoffToolPrefix = "transfer_to_"

HandoffToolPrefix starts the names of handoff tools.

View Source
const MaxCheckpoints = 100

MaxCheckpoints is the number of the most recent checkpoints a Runner keeps for each session, as Claude Code keeps file snapshots for the 100 most recent checkpoints of a session.

View Source
const PendingRunKey = "agentx.pending_run"

PendingRunKey is the session state key holding the ID of an interrupted run.

View Source
const SessionValuesKey = "agentx.session_values"

SessionValuesKey is the session state key holding the session-scoped run values, those whose keys start with loop.SessionValuePrefix. The Runner saves them when a run ends and passes them to the session's next runs, so middleware can keep state for a session, such as remembered permission grants.

Variables

View Source
var ErrCannotRewind = errors.New("agent: cannot rewind")

ErrCannotRewind is returned by Runner.Rewind for a checkpoint that cannot be rewound in the mode asked: the agent has no file history to rewind the code, or the checkpoint's message is no longer in the conversation.

View Source
var ErrSessionBusy = errors.New("agent: the session is busy")

ErrSessionBusy is returned by Runner.Rewind while the session has a run or another operation of the Runner in progress.

Functions

func AgentVerifier

func AgentVerifier(a Agent) hook.Verifier

AgentVerifier returns a hook.Verifier for hook.Agent hooks that runs a on each check's prompt, without history, and returns its final answer. The hook's model name is ignored.

func AsTool

func AsTool(a Agent, opts ToolOptions) tool.Tool

func AskAs

func AskAs[T any](ctx context.Context, a Agent, prompt string) (T, error)

AskAs runs a on a single prompt without history and decodes its final answer as T. Configure a with WithOutput[T], so the model answers in JSON matching T.

func ContextWithSessionState

func ContextWithSessionState(ctx context.Context, st *session.State) context.Context

ContextWithSessionState returns a context in which SessionState returns st. A Runner does this for the runs of its sessions; use it to give runs started without a Runner a state, for example for WithInstructionTemplate.

func HookVerifier

func HookVerifier(m model.Model, opts ...Option) hook.Verifier

HookVerifier returns a hook.Verifier for hook.Agent hooks that runs a new agent on m for each check: it is built with opts, has instructions for the task and at most 50 turns, as in Claude Code, and its final answer is the verdict. A model name set on the hook overrides the request's model. Give it the tools it may use with WithTools, typically read-only ones such as builtin.ReadOnlyTools.

func MemoryProvider

func MemoryProvider(m memory.Memory, scope string, limit int) actx.Provider

MemoryProvider recalls memories relevant to each input and adds them as a reminder.

func NestHandoffHistory

func NestHandoffHistory(msgs []*model.Message) []*model.Message

NestHandoffHistory is a handoff input filter that replaces the conversation with a single user message holding a transcript of it in a <CONVERSATION HISTORY> block, like the OpenAI Agents SDK's nest_handoff_history. The agent handed off to then sees the earlier turns, including tool calls and results, as context rather than as its own. Images and other binary content are noted, not copied; the transcript is not redacted.

func RemoveToolCalls

func RemoveToolCalls(msgs []*model.Message) []*model.Message

RemoveToolCalls is a handoff input filter that removes tool calls and their results from the conversation, and assistant messages left empty, like the OpenAI Agents SDK's remove_all_tools. Use it when the agent handed off to should not see the work of the previous one, or has no tools, which some providers require when the conversation holds tool calls.

func RenderTemplate

func RenderTemplate(ctx context.Context, s string) (string, error)

RenderTemplate fills the placeholders of s from the session state of ctx; see SessionState and ContextWithSessionState. {key} is replaced with the value of key: a string as it is, any other value as JSON. It is an error if the state, or a state at all, is missing for {key}; {key?} is replaced with nothing then. Keys start with a letter or underscore, followed by letters, digits and _ . : -, so braces around anything else, such as JSON, stay as they are. {{ and }} stand for literal { and }, for example {{key}} for the text {key}.

func SessionState

func SessionState(ctx context.Context) (*session.State, bool)

SessionState returns the session state carried by ctx and reports false if none is present. Tools, hooks, middleware and instruction functions can use it to share per-session values.

A Runner supplies its session's state and saves it when the run ends, including failures and interruptions. Sub-agents and handoff targets share the same state. Its operations are safe for concurrent use, with the value-sharing rules of session.State. Store JSON values for persistence and leave keys starting with "agentx." to the Runner.

Types

type Agent

type Agent interface {
	Name() string
	Description() string
	Run(ctx context.Context, in *Input) iter.Seq2[*loop.Event, error]
}

Agent runs tasks and reports progress as runtime events.

func Ref

func Ref(name, description string) Agent

Ref returns a reference to the agent named name, for WithHandoffs, so agents can hand off to each other although each must be built before the agents that hand off to it. The reference resolves, when the model hands off, to the agent of that name among the agents the run's first agent hands off to, directly or through others, including that agent itself. description describes the agent to the model. A reference cannot run on its own.

type Checkpoint

type Checkpoint struct {
	// ID identifies the checkpoint. It is the ID of the run, which the
	// run's events carry in Event.RunID.
	ID string
	// Index is the position of the run's user message in the session's
	// messages, or -1 if it is no longer there, for example after
	// compaction, so that only the code can be rewound.
	Index int
	// Message is the run's original user input before context and middleware
	// augmentation, if Index is not -1.
	Message *model.Message
	// Time is when the run started.
	Time time.Time
	// Agent names the agent the session's message went to when the run
	// started: the agent of ActiveAgentKey, or "" for the Runner's own
	// agent. Rewinding the conversation makes it active again, so the
	// conversation continues with the agent that had it before handoffs.
	Agent string
	// Changes are the file changes saved to the agent's file history
	// during the run, oldest first.
	Changes []builtin.FileChange
	// Code reports whether rewinding the code to the checkpoint would
	// restore files: the file history keeps the checkpoint and changes
	// saved since.
	Code bool
}

Checkpoint is a point of a session that Runner.Rewind can return to: the start of a run, before its user message, like the checkpoint Claude Code creates for each prompt. See https://code.claude.com/docs/en/checkpointing.

type Config

type Config struct {
	loop.Settings
	Description string
	Tools       []tool.Tool

	// Skills are advertised in the system prompt and loaded with the skill
	// tool.
	Skills *skill.Registry
	// SkillConfig configures how skills run; see skill.Config. The agent
	// fills in what it leaves empty: Fork runs context: fork skills as
	// sub-agents (see WithSkillAgents), Effort defaults to Reasoning's,
	// and HookOptions.Model to Model.
	SkillConfig skill.Config
	// SkillAgents are the agents context: fork skills can name in their
	// agent field.
	SkillAgents []Agent

	// Memory enables long-term memory tools and automatic recall.
	Memory memory.Memory
	// MemoryScope scopes memory reads and writes, for example to a user.
	MemoryScope string
	// MemoryScopeFunc, if set, chooses the scope of each run instead of
	// MemoryScope, for an agent that serves several users.
	MemoryScopeFunc memory.ScopeFunc
	// MemoryRecall is the number of memories recalled automatically for each
	// input. Zero disables automatic recall; the tools remain available.
	MemoryRecall int
	// DisableMemoryTools hides the memory tools from the model.
	DisableMemoryTools bool

	// SubAgents are exposed to the model as tools named after the agents.
	SubAgents []Agent

	Hooks *hook.Manager
	// Middlewares extend the agent loop. They run after the hook and skill
	// middleware and before the permission policy and the context
	// middleware.
	Middlewares []loop.Middleware
	// Permissions decides tool calls with rules and modes; see
	// WithPermissions. It runs after Middlewares, so it sees their
	// decisions.
	Permissions *permission.Policy
	// Context configures context engineering. The agent adds its own
	// providers for skills and memory.
	Context          actx.Config
	ContextProviders []actx.Provider

	// SubAgentEvents forwards the events of sub-agents; see
	// ToolOptions.Events.
	SubAgentEvents bool
	// ConcurrentSubAgents lets sub-agent calls run concurrently; see
	// ToolOptions.Concurrent.
	ConcurrentSubAgents bool
	// MaxDepth bounds sub-agent nesting; see ToolOptions.MaxDepth.
	MaxDepth int
	// FileHistory is the history Runner.Rewind restores files from; see
	// WithFileHistory.
	FileHistory builtin.History

	// Handoffs are the agents the model can hand the run off to; see
	// WithHandoffs. MaxHandoffs bounds the handoffs of a run started on
	// this agent; zero means DefaultMaxHandoffs.
	Handoffs    []Handoff
	MaxHandoffs int
	// Guardrails check the input, output and tool calls of runs; see
	// WithInputGuardrail.
	Guardrails guard.Config
	// Deps add default dependencies to the context of runs; see WithDeps.
	Deps []func(context.Context) context.Context
	// InstructionFuncs extend Instructions for each run or turn; see
	// WithInstructionsFunc.
	InstructionFuncs []Instruction
	// InstructionTemplate fills {key} placeholders in Instructions from
	// the session state; see WithInstructionTemplate.
	InstructionTemplate bool
	// contains filtered or unexported fields
}

Config configures an LLMAgent. Build it with options passed to New.

The embedded loop.Settings configure the agent's runtime: its name, model, request options, approver, checkpointer, limits and stop conditions. The agent adds its handoff tools to StopAtTools.

type Discarder

type Discarder interface {
	Discard(ctx context.Context, runID string) error
}

Discarder is implemented by agents that can delete the saved state of a run that will not be resumed.

type Event added in v1.1.0

type Event = loop.Event

Event is an event of an agent run, as Agent.Run and Runner.Run stream them; see loop.Event. The alias lets code that only runs agents use the agent package alone.

type Handoff

type Handoff struct {
	// Agent receives the run.
	Agent Agent
	// ToolName is the name of the tool that hands off; it defaults to
	// "transfer_to_" and the agent's name.
	ToolName string
	// Description describes the tool; it defaults to one built from the
	// agent's description.
	Description string
	// InputFilter, if set, rewrites the conversation the agent sees, up
	// to and including the handoff call's result, for example with
	// RemoveToolCalls or NestHandoffHistory. It gets a copy of the
	// messages and must not modify them. It applies to the model requests
	// of the run, not to the conversation saved, so later runs of a
	// session see all of it.
	InputFilter func([]*model.Message) []*model.Message
	// contains filtered or unexported fields
}

Handoff is an agent the model can hand a run off to; see WithHandoffs.

type HandoffOption

type HandoffOption func(*Handoff)

HandoffOption configures a handoff.

func HandoffDescription

func HandoffDescription(d string) HandoffOption

HandoffDescription describes the handoff's tool to the model.

func HandoffInput

func HandoffInput[T any](fn func(ctx context.Context, in T) error) HandoffOption

HandoffInput makes the model send arguments of type T, whose schema is derived with tool.SchemaOf, when it hands off, such as a reason or a priority, like the OpenAI Agents SDK's input_type. fn, if not nil, is called with them before the handoff; an error refuses the handoff and is reported to the model. The arguments are added to the input of the agent that takes over and reported in loop.Handoff.Input.

func HandoffInputFilter

func HandoffInputFilter(f func([]*model.Message) []*model.Message) HandoffOption

HandoffInputFilter sets the handoff's Handoff.InputFilter.

func HandoffName

func HandoffName(name string) HandoffOption

HandoffName names the handoff's tool.

type HistoryProvider

type HistoryProvider interface {
	FileHistory() builtin.History
}

HistoryProvider is implemented by agents with a file history, such as an LLMAgent built with WithFileHistory. A Runner starts a checkpoint of the history for each run and restores files from it in Rewind.

type HookProvider

type HookProvider interface {
	Hooks() *hook.Manager
}

HookProvider is implemented by agents with a hook manager, such as LLMAgent. A Runner dispatches the SessionStart and SessionEnd events of its sessions to it. For the context of SessionStart hooks to reach the model, the agent's runs must use hook.Middleware with the same manager.

type Input

type Input struct {
	// Message is the new user message.
	Message *model.Message
	// History is the conversation before Message.
	History    []*model.Message
	SessionID  string
	RunID      string
	NewSession bool
	// MaxTurns, if positive, and Limits, if non-nil, override the agent's
	// turn limit and usage limits for this run.
	MaxTurns int
	Limits   *loop.Limits
	// Values are the initial run values; see loop.Request.Values.
	Values map[string]string
	// Skill, if set, is a skill the user invokes at the start of the run,
	// as with /name arguments in Claude Code; see RunSkill and
	// skill.WithCall.
	Skill *skill.Call
	// Agent, if set, names the agent of the handoff graph that handles the
	// input instead of this one, as a Runner sets it to the session's
	// active agent; see WithHandoffs and Result.Agent.
	Agent string
	// Deps add dependencies to the context of the run; see RunDeps.
	Deps []func(context.Context) context.Context
}

Input is the input of an agent run.

func Text

func Text(s string) *Input

Text returns an input holding a single user text message.

type Instruction

type Instruction struct {
	Func InstructionFunc
	// EveryTurn evaluates Func before each model call instead of once per
	// run.
	EveryTurn bool
}

Instruction is a function that extends an agent's instructions; see WithInstructionsFunc.

type InstructionFunc

type InstructionFunc func(ctx context.Context, run *loop.Run) (string, error)

InstructionFunc returns instructions for a run, for example from the run's dependencies (loop.Deps) or session state (SessionState). An error fails the run.

type InstructionOption

type InstructionOption func(*Instruction)

InstructionOption configures an instruction function.

func EveryTurn

func EveryTurn() InstructionOption

EveryTurn evaluates an instruction function before each model call, for instructions that change during a run, such as ones that depend on session state that tools write. Its text is added to each request without being saved in the run's system prompt. Instructions that change between calls defeat the providers' prompt caching of what follows them, so prefer the default of once per run.

type LLMAgent

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

LLMAgent is an agent driven by a language model.

func MustNew

func MustNew(name string, opts ...Option) *LLMAgent

MustNew is like New but panics on error.

func New

func New(name string, opts ...Option) (*LLMAgent, error)

New returns an LLM agent.

func (*LLMAgent) Ask

func (a *LLMAgent) Ask(ctx context.Context, prompt string) (string, error)

Ask runs the agent on a single prompt without history and returns its final answer.

func (*LLMAgent) Description

func (a *LLMAgent) Description() string

Description implements Agent.

func (*LLMAgent) Discard

func (a *LLMAgent) Discard(ctx context.Context, runID string) error

Discard implements Discarder by deleting the run's checkpoint, in the checkpointers of the agents it hands off to too.

func (*LLMAgent) FileHistory

func (a *LLMAgent) FileHistory() builtin.History

FileHistory returns the agent's file history, or nil if it has none.

func (*LLMAgent) Hooks

func (a *LLMAgent) Hooks() *hook.Manager

Hooks returns the agent's hook manager, or nil if it has no hooks. A Runner dispatches its SessionStart and SessionEnd events to it.

func (*LLMAgent) Name

func (a *LLMAgent) Name() string

Name implements Agent.

func (*LLMAgent) Resume

func (a *LLMAgent) Resume(ctx context.Context, runID string, approvals map[string]loop.Approval) iter.Seq2[*loop.Event, error]

Resume implements Resumer. It requires a checkpointer. With handoffs, the run resumes on the agent that was running it, found in the checkpointers of the agents the agent hands off to.

func (*LLMAgent) ResumeState

func (a *LLMAgent) ResumeState(ctx context.Context, st *loop.State, approvals map[string]loop.Approval) iter.Seq2[*loop.Event, error]

ResumeState implements StateResumer. With handoffs, the run resumes on the agent the state names.

func (*LLMAgent) Run

func (a *LLMAgent) Run(ctx context.Context, in *Input) iter.Seq2[*loop.Event, error]

Run implements Agent. A run the model hands off continues on the agent it hands off to; see WithHandoffs.

func (*LLMAgent) Runtime

func (a *LLMAgent) Runtime() *loop.Runtime

Runtime returns the underlying runtime.

func (*LLMAgent) Tools

func (a *LLMAgent) Tools() *tool.Registry

Tools returns the tools available to the model, including skill, memory and sub-agent tools.

type Option

type Option func(*Config)

Option configures an agent.

func WithApprover

func WithApprover(a loop.Approver) Option

WithApprover decides tool approvals synchronously.

func WithBudget

func WithBudget(f func(model.Usage) error) Option

WithBudget ends a run with loop.StatusLimitExceeded when f returns an error for the run's usage so far, for example a cost limit. f is called before each model call and each batch of tool calls.

func WithCheckpointer

func WithCheckpointer(cp loop.Checkpointer) Option

WithCheckpointer persists run state for resumption.

func WithConcurrentSubAgents

func WithConcurrentSubAgents() Option

WithConcurrentSubAgents lets calls of the agent's sub-agents run in parallel with each other and with adjacent read-only calls, bounded by WithParallelism. By default sub-agents run one at a time, since they may have side effects whose order matters. Sub-agents interrupted for approval together are resumed together.

func WithContext

func WithContext(cfg actx.Config) Option

WithContext configures context engineering.

func WithContextProvider

func WithContextProvider(ps ...actx.Provider) Option

WithContextProvider adds a context provider.

func WithDeps

func WithDeps[T any](v T) Option

WithDeps gives the agent's runs v as their dependency of type T, which tools, hooks, middleware and instruction functions read with loop.Deps[T]. It is a default: a dependency of type T that the run's context already carries, from loop.WithDeps or RunDeps, takes precedence. Sub-agents and agents the run is handed off to see the dependencies of the run that started them, and their own defaults for other types. Dependencies are not saved with checkpoints or sessions; see loop.WithDeps.

func WithDescription

func WithDescription(d string) Option

WithDescription describes the agent to parent agents.

func WithFileHistory

func WithFileHistory(h builtin.History) Option

WithFileHistory gives the agent the file history its file tools save to, the same as builtin.Config.History, so a Runner starts a checkpoint of it for each run and Runner.Rewind can restore the files; see builtin.FileHistory.

func WithHandoff

func WithHandoff(a Agent, opts ...HandoffOption) Option

WithHandoff is like WithHandoffs for a single agent with options.

func WithHandoffs

func WithHandoffs(agents ...Agent) Option

WithHandoffs lets the model hand the run off to agents, in the style of the OpenAI Agents SDK's handoffs and Google ADK's agent transfer. Each agent appears as a tool named "transfer_to_" and its name. When the model calls one, the calls of its turn run, the agent's part of the run ends, and the run continues on the agent handed off to, with its own instructions, tools, middleware, guardrails and limits: it sees the conversation so far, and a note about the handoff as its input, and emits a loop.EventHandoff before its events. The run keeps its ID, usage and turn count, so limits apply to the whole run, and Result.Agent names the agent that ran last. Only the first handoff call of a turn hands off; the others are denied. A run is handed off at most WithMaxHandoffs times.

Handoff tools are read-only (tool.Info.ReadOnly): a call only checks the handoff, which happens after the turn, so permission plan mode allows it.

The agent handed off to does not run its input guardrails, and its UserPromptSubmit hooks see the note as the prompt. PreToolUse and PostToolUse hooks with a matcher such as "transfer_to_.*" observe and can deny handoffs.

A Runner remembers the agent its session was handed off to (see ActiveAgentKey) and sends the session's next message to it. An interrupted run resumes on the agent that was running; agents that hand off to each other should share a checkpointer. To hand off to an agent that is built later, such as back to this one, use Ref.

func WithHook

func WithHook(event hook.EventType, matcher string, h hook.Hook) Option

WithHook registers a hook. Invalid matchers panic.

func WithHooks

func WithHooks(m *hook.Manager) Option

WithHooks adds the hooks of a manager, including its FailClosed setting. They are copied into the agent's own manager, so m is not modified by other options, and hooks registered in m later are not added.

func WithInputGuardrail

func WithInputGuardrail(g guard.InputGuardrail, opts ...guard.InputOption) Option

WithInputGuardrail checks the input of the agent's new runs with g; a tripped guardrail ends the run with loop.StatusBlocked and loop.Result.Guardrail set. Guardrails run one after another before the run starts, before hooks see the input; guard.Parallel runs g concurrently with the first model call instead. Input guardrails do not run for the agent a run is handed off to, whose input was checked.

func WithInstructionFiles

func WithInstructionFiles(dir string) Option

WithInstructionFiles adds the instruction files, such as AGENTS.md, of dir and its parents up to the project root to the system prompt, with the defaults of actx.InstructionFiles.

func WithInstructionTemplate

func WithInstructionTemplate() Option

WithInstructionTemplate fills placeholders in the static instructions of WithInstructions from the session state when a run starts, like Google ADK's {key} templating; see RenderTemplate. A required key that the state lacks fails the run. Text of WithInstructionsFunc is not templated, as ADK's instruction providers are not.

func WithInstructions

func WithInstructions(s string) Option

WithInstructions sets the base system prompt.

func WithInstructionsFunc

func WithInstructionsFunc(f InstructionFunc, opts ...InstructionOption) Option

WithInstructionsFunc adds instructions that f returns, in the style of Pydantic AI's @agent.instructions and the OpenAI Agents SDK's dynamic instructions. By default f runs once when a run starts, after the hooks accepted its input, and its text follows the static instructions of WithInstructions, and the text of earlier functions, separated by a blank line; the system prompt then stays the same for the whole run, which keeps it cacheable, and a resumed run reuses it. Empty text adds nothing. EveryTurn evaluates f before each model call instead. The text is used as it is; see RenderTemplate to fill in session state.

When a run is handed off, the instructions of the agent it is handed off to apply.

func WithLimits

func WithLimits(l loop.Limits) Option

WithLimits bounds the usage of each run; Input.Limits overrides it for a run. See loop.Limits.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the logger.

func WithMaxDepth

func WithMaxDepth(n int) Option

WithMaxDepth bounds how deeply sub-agents can be nested below the agent; the default is DefaultMaxDepth. A sub-agent call beyond it returns an error result to the model.

func WithMaxHandoffs

func WithMaxHandoffs(n int) Option

WithMaxHandoffs bounds the handoffs of the runs started on the agent; the default is DefaultMaxHandoffs. A handoff beyond it is refused with an error result to the model.

func WithMaxTokens

func WithMaxTokens(n int) Option

WithMaxTokens bounds output tokens per model call.

func WithMaxTurns

func WithMaxTurns(n int) Option

WithMaxTurns bounds model calls per run.

func WithMemory

func WithMemory(m memory.Memory, scope string, recall int) Option

WithMemory enables long-term memory. recall is the number of memories recalled automatically for each input; zero disables automatic recall. Every run of the agent reads and writes memories in scope; an agent that serves several users, such as one behind a server, chooses the scope per run with WithMemoryScopeFunc instead.

func WithMemoryScopeFunc

func WithMemoryScopeFunc(m memory.Memory, scope memory.ScopeFunc, recall int) Option

WithMemoryScopeFunc enables long-term memory like WithMemory, with the scope of each recall and memory tool call taken from its context by scope, for example the user an HTTP middleware authenticated and stored in the request context the server runs the agent with. When scope fails, the recall or the tool call fails, so memories never leak across users whose scope is unknown.

func WithMiddleware

func WithMiddleware(mws ...loop.Middleware) Option

WithMiddleware adds runtime middleware, for example from the middleware package.

func WithModel

func WithModel(m model.Model) Option

WithModel sets the model.

func WithOutput

func WithOutput[T any](opts ...OutputOption) Option

WithOutput makes the agent answer with JSON matching the schema of T, which must be a struct type or a pointer to one; New fails otherwise. The schema, derived with tool.SchemaOf, is requested as the response format unless WithResponseFormat sets one, and the final answer is validated against it. Decode the answer with loop.Result.DecodeAs or use AskAs. See loop.Output for retries and failures.

func WithOutputGuardrail

func WithOutputGuardrail(g guard.OutputGuardrail, opts ...guard.OutputOption) Option

WithOutputGuardrail checks the final answer of the agent's runs with g, after Stop hooks let the run finish. A tripped guardrail ends the run with loop.StatusBlocked and an empty Output, and the conversation keeps loop.WithheldAnswer in place of the answer. guard.HoldOutput also holds the answer's events until the guardrails pass. When a run is handed off, the output guardrails of the agent that answers apply.

func WithParallelism

func WithParallelism(n int) Option

WithParallelism bounds concurrent calls of read-only and concurrent tools.

func WithPermissions

func WithPermissions(p *permission.Policy) Option

WithPermissions decides tool calls with a permission policy: rules and modes in Claude Code's syntax, see the permission package. The policy runs after the hooks, skills and WithMiddleware middleware, whatever the order of the options, so its deny and ask decisions hold whatever they allow; see the package documentation. A later WithPermissions replaces the policy, and nil removes it.

func WithProviderOptions added in v1.1.0

func WithProviderOptions(provider string, opts map[string]any) Option

WithProviderOptions passes provider-specific request fields to the provider adapter named provider, such as "openai" or "anthropic"; see model.Request.ProviderOptions. Options for the same provider merge, later keys replacing earlier ones.

func WithReasoning

func WithReasoning(r *model.Reasoning) Option

WithReasoning configures model reasoning.

func WithResponseFormat

func WithResponseFormat(f *model.ResponseFormat) Option

WithResponseFormat requests structured output.

func WithSeed added in v1.1.0

func WithSeed(seed int) Option

WithSeed asks providers that support it for deterministic sampling; see model.Request.Seed.

func WithSkillAgents

func WithSkillAgents(agents ...Agent) Option

WithSkillAgents makes agents available to context: fork skills, whose agent field names one of them. Without a match, general-purpose, Explore and Plan run on a new agent with the agent's model, tools and approver; see Config.SkillAgents.

func WithSkillConfig

func WithSkillConfig(c skill.Config) Option

WithSkillConfig configures how the agent's skills run, for example enabling command injection with skill.Config.Shell; see Config.SkillConfig.

func WithSkillRegistry

func WithSkillRegistry(r *skill.Registry) Option

WithSkillRegistry adds the skills of a registry. They are copied into the agent's own registry, so r is not modified by other options, and skills registered in r later are not added.

func WithSkills

func WithSkills(skills ...skill.Skill) Option

WithSkills adds skills.

func WithStopAtTools

func WithStopAtTools(names ...string) Option

WithStopAtTools ends a run as completed once one of the named tools returns a result that is not an error; the result's content is the run's output, and the model is not called again.

func WithStopWhen

func WithStopWhen(conds ...loop.StopCondition) Option

WithStopWhen ends a run as completed when any condition holds after a turn's tool calls have run. See loop.StopCondition.

func WithStreaming

func WithStreaming() Option

WithStreaming streams model output as delta events.

func WithSubAgentEvents

func WithSubAgentEvents() Option

WithSubAgentEvents forwards the events of the agent's sub-agents, and of their sub-agents, to the consumer of its runs. Forwarded events have a Depth above zero and ParentCallID set to the call that started the sub-agent; consumers that switch on Event.Type should check Depth. The sub-agents' events are not forwarded by default.

func WithSubAgents

func WithSubAgents(agents ...Agent) Option

WithSubAgents exposes agents as tools.

func WithTemperature

func WithTemperature(t float64) Option

WithTemperature sets the sampling temperature.

func WithToolChoice

func WithToolChoice(tc *model.ToolChoice) Option

WithToolChoice constrains tool use.

func WithToolGuardrail

func WithToolGuardrail(g guard.ToolGuardrail) Option

WithToolGuardrail checks the agent's tool calls before they run and their results after; see guard.ToolGuardrail. A tripped guardrail ends the run with loop.StatusBlocked.

func WithToolMiddleware

func WithToolMiddleware(mws ...tool.Middleware) Option

WithToolMiddleware adds tool middleware.

func WithTools

func WithTools(tools ...tool.Tool) Option

WithTools adds tools.

func WithTopP

func WithTopP(p float64) Option

WithTopP sets nucleus sampling.

func WithoutMemoryTools

func WithoutMemoryTools() Option

WithoutMemoryTools hides the memory tools from the model.

type OutputOption

type OutputOption func(*loop.Output)

OutputOption configures the output of WithOutput.

func OutputName

func OutputName(name string) OutputOption

OutputName names the output schema for providers. It defaults to the name of T if that is a valid name, otherwise to "output".

func OutputRetries

func OutputRetries(n int) OutputOption

OutputRetries sets how often an answer that does not match the output schema is sent back to the model; see loop.Output.Retries.

type Result added in v1.1.0

type Result = loop.Result

Result is the outcome of an agent run, as loop.Collect returns it; see loop.Result.

type Resumer

type Resumer interface {
	Resume(ctx context.Context, runID string, approvals map[string]loop.Approval) iter.Seq2[*loop.Event, error]
}

Resumer is implemented by agents that can resume interrupted runs.

type RewindMode

type RewindMode int

RewindMode selects what Runner.Rewind restores.

const (
	// RewindCode restores the files the tools changed since the
	// checkpoint and keeps the conversation.
	RewindCode RewindMode = 1 << iota
	// RewindConversation removes the checkpoint's user message and the
	// messages after it from the session and keeps the files.
	RewindConversation
	// RewindBoth restores the files and the conversation.
	RewindBoth = RewindCode | RewindConversation
)

type RewindResult

type RewindResult struct {
	// Message is the original user input of the removed run, before context
	// and middleware augmentation, to send again or edit, as Claude Code
	// restores the prompt into the input.
	Message *model.Message
	// Restored are the restored files and Skipped the changed files that
	// were not restored; see builtin.Restoration.
	Restored []builtin.FileChange
	Skipped  []builtin.FileChange
	// Undo is the file history checkpoint holding the files' state before
	// the rewind; restoring it with History.Restore undoes the code
	// rewind.
	Undo string
}

RewindResult is the result of Runner.Rewind.

type RunOption

type RunOption func(*Input)

RunOption configures a single run of a Runner.

func RunDeps

func RunDeps[T any](v T) RunOption

RunDeps gives one run v as its dependency of type T, overriding the agent's default from WithDeps; see loop.Deps. It is not saved: pass it again to Runner.Resume when resuming the run.

func RunLimits

func RunLimits(l loop.Limits) RunOption

RunLimits overrides the agent's usage limits for one run; see Input.Limits. Resuming the run keeps them.

func RunMaxTurns

func RunMaxTurns(n int) RunOption

RunMaxTurns overrides the agent's turn limit for one run; see Input.MaxTurns. Resuming the run keeps it.

func RunSkill

func RunSkill(name, arguments string) RunOption

RunSkill invokes a skill as the user at the start of the run, as typing /name arguments does in Claude Code: its content is added in front of the message and it is active for the run, and the model may invoke it even with disable-model-invocation. See skill.WithCall.

func RunValue

func RunValue(key, value string) RunOption

RunValue sets an initial value of one run, as loop.Run.SetValue stores it, for example permission.ModeKey to choose the run's permission mode. It overrides a session-scoped value of the same key.

type Runner

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

Runner runs an agent against persistent sessions. Runs on the same session are serialized.

If the agent may not checkpoint its runs, the Runner keeps a copy of the state of each session's interrupted run in memory, so Resume can continue it. A copy is kept until the session's next run ends or the run is discarded; sessions that are abandoned while interrupted keep theirs for the Runner's lifetime.

If the agent has hooks (see HookProvider), the Runner fires SessionStart once per session: with source "startup" for a new session, "resume" the first time it runs or resumes an existing one, and "clear" or "fork" for sessions made by Clear and Fork. EndSession fires SessionEnd, after which the session starts again. The Runner remembers the sessions it started until they end.

func NewRunner

func NewRunner(a Agent, store session.Store) *Runner

NewRunner returns a runner. A nil store keeps sessions in memory.

func (*Runner) Checkpoints

func (r *Runner) Checkpoints(ctx context.Context, sessionID string) ([]Checkpoint, error)

Checkpoints returns the checkpoints of a session, oldest first: one for each of its last MaxCheckpoints runs that added a user message, except those removed by rewinding the conversation. With a file history (see HistoryProvider), each lists the files changed during its run.

func (*Runner) Clear

func (r *Runner) Clear(ctx context.Context, sessionID string) (string, error)

Clear ends a session with reason "clear" and starts a new, empty one in its place, like Claude Code's /clear. It returns the new session's ID; the old session stays in the store. The first run of the new session fires SessionStart with source "clear". SessionEnd hook errors are returned with the new ID.

func (*Runner) Discard

func (r *Runner) Discard(ctx context.Context, sessionID string) error

Discard gives up the interrupted run of a session, for example when its checkpoint was lost, or else its failed run. Its pending tool calls are answered as not run, so the session can continue with Run, and the agent's checkpoint of the run is deleted if the agent implements Discarder.

func (*Runner) EndSession

func (r *Runner) EndSession(ctx context.Context, sessionID, reason string) error

EndSession ends a session, like Claude Code does when you exit, run /clear or switch sessions: it runs the agent's SessionEnd hooks with reason, such as "clear", "logout", "prompt_input_exit" or "other" (the default), and Event.Messages holding the conversation. The hooks cannot prevent it and share a time budget; see hook.SessionEndTimeout. Context still queued for the session is dropped.

The session stays in the store: a later Run or Resume continues it and fires SessionStart with source "resume". EndSession waits for a run of the session in progress. It returns the hooks' errors.

func (*Runner) Fork

func (r *Runner) Fork(ctx context.Context, sessionID string) (string, error)

Fork copies the conversation and state of a session into a new session and returns its ID, like Claude Code's --fork-session. An interrupted or failed run is not copied: its pending tool calls are answered as not run in the copy. The first run of the new session fires SessionStart with source "fork".

The checkpoints and the agent's file history are copied too, so either session can be rewound to the checkpoints before the fork, and later changes are recorded only for the session that made them. Both sessions still work on the same files: rewinding the code of one changes the files the other sees.

func (*Runner) Resume

func (r *Runner) Resume(ctx context.Context, sessionID string, approvals map[string]loop.Approval, opts ...RunOption) iter.Seq2[*loop.Event, error]

Resume continues the interrupted run of a session or, if it has none, its failed run; see FailedRunKey. Failed runs are resumed from the agent's checkpoint. Interrupted runs are too, or, if the agent has no checkpointer, from the state this Runner kept in memory when the run was interrupted.

Of the options, only RunDeps applies: dependencies are not saved with the run, so pass them again. The run keeps its other settings.

func (*Runner) Rewind

func (r *Runner) Rewind(ctx context.Context, sessionID, checkpointID string, mode RewindMode) (*RewindResult, error)

Rewind returns a session to a checkpoint listed by Checkpoints, like Claude Code's /rewind (https://code.claude.com/docs/en/checkpointing). mode selects what is restored:

  • RewindCode restores files tracked since the checkpoint from the agent's file history (see HistoryProvider and builtin.Config.History). Files that cannot be restored are reported in RewindResult.Skipped; failures trigger an attempt to undo changes already applied. Untracked files are left alone, but later changes to tracked files, including changes by bash or another session, can be overwritten. The restored files are forgotten by the tools' FileTracker, so the model reads them again before changing them.
  • RewindConversation removes the checkpoint's user message and the messages after it, and the later checkpoints, from the session. RewindResult.Message holds the original input to send again. The agent that was active at the checkpoint (Checkpoint.Agent) becomes active again, undoing later handoffs. The rest of the session state, such as values set with SessionState and session-scoped run values like remembered permission grants, is not rewound, as Claude Code keeps permissions across a rewind.

Rewind refuses with ErrSessionBusy while a run of the session or another operation of this Runner on it is in progress, with ErrCannotRewind when mode cannot be rewound to the checkpoint, and refuses a session with an interrupted run: resume it or discard it first. A failed run is given up, as by the next Run. The file history is kept: a later rewind to an earlier checkpoint still restores the files, and RewindResult.Undo undoes the code rewind. If saving the session fails after the files were restored, Rewind attempts to undo the code rewind and includes any undo failure in the returned error.

func (*Runner) Run

func (r *Runner) Run(ctx context.Context, sessionID string, msg *model.Message, opts ...RunOption) iter.Seq2[*loop.Event, error]

Run sends a message in a session and returns the run's events. An empty sessionID starts a new session; its ID is reported in the events. Options such as RunLimits apply to this run only. The message goes to the agent the session was last handed off to, if any; see ActiveAgentKey. The run's tools and instruction functions reach the session's state with SessionState.

The session is saved when the run ends, including when it is interrupted. If the caller stops iterating early, the run is cancelled and the session is saved once it has ended.

func (*Runner) RunText

func (r *Runner) RunText(ctx context.Context, sessionID, text string, opts ...RunOption) (*loop.Result, error)

RunText sends text in a session and returns the result. Options apply as for Run.

func (*Runner) Store

func (r *Runner) Store() session.Store

Store returns the session store.

type StateResumer

type StateResumer interface {
	ResumeState(ctx context.Context, st *loop.State, approvals map[string]loop.Approval) iter.Seq2[*loop.Event, error]
}

StateResumer is implemented by agents that can resume a run from its state, without a checkpoint. Sub-agents are resumed this way.

type ToolOptions

type ToolOptions struct {
	// Name is the tool name. It defaults to the agent's name. Hooks match
	// the agent's name either way.
	Name string
	// Description is the tool description. It defaults to the agent's
	// description, with a note that the agent cannot see the conversation.
	Description string
	// Hooks receives SubagentStart and SubagentStop events.
	Hooks *hook.Manager
	// Events forwards the sub-agent's events to the consumer of the calling
	// run, tagged with loop.Event.Depth and ParentCallID. Sub-agents of
	// the sub-agent then forward theirs too. See loop.ForwardEvent.
	Events bool
	// Concurrent lets calls run in parallel with adjacent calls of
	// concurrent or read-only tools; see tool.Concurrent. SubagentStart
	// and SubagentStop hooks of sub-agents running concurrently may run
	// concurrently.
	Concurrent bool
	// MaxDepth bounds how deeply the sub-agent may be nested; zero means
	// DefaultMaxDepth. The smallest bound of the agents above a sub-agent
	// applies. A call that would exceed it returns an error result.
	MaxDepth int
}

ToolOptions configures the tool that runs an agent as a sub-agent; see AsTool. The zero value gives the defaults.

Jump to

Keyboard shortcuts

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