Documentation
¶
Overview ¶
Package loop implements the agent loop: it calls the model, executes tool calls, asks for approvals and checkpoints state so interrupted runs can be resumed. Everything else, such as hooks and context engineering, plugs into the loop as Middleware.
Index ¶
- Constants
- Variables
- func Block(reason string) error
- func CloseToolCalls(msgs []*model.Message, content string) *model.Message
- func Deps[T any](ctx context.Context) (T, bool)
- func ForwardEvent(ctx context.Context, ev *Event) bool
- func InterruptCall(ctx context.Context, intr *Interrupt) bool
- func ReportUsage(ctx context.Context, u model.Usage)
- func Stop(reason string) error
- func WithDeps[T any](ctx context.Context, v T) context.Context
- func WithheldAnswer(name string) *model.Message
- type AfterModeler
- type AfterRunner
- type AfterTooler
- type AnswerHolder
- type Approval
- type ApprovalRequest
- type Approver
- type ApproverFunc
- type BeforeFinisher
- type BeforeModeler
- type BeforeRunner
- type BeforeTooler
- type BeforeTurner
- type Checkpointer
- type Compaction
- type Config
- type ContextWrapper
- type Decision
- type Event
- type EventType
- type Funcs
- func (f *Funcs) AfterModel(ctx context.Context, run *Run, req *model.Request, resp *model.Response) error
- func (f *Funcs) AfterRun(ctx context.Context, run *Run, res *Result)
- func (f *Funcs) AfterTool(ctx context.Context, run *Run, plan *ToolPlan, res *model.ToolResult) error
- func (f *Funcs) BeforeFinish(ctx context.Context, run *Run, msg *model.Message) (bool, error)
- func (f *Funcs) BeforeModel(ctx context.Context, run *Run, req *model.Request) error
- func (f *Funcs) BeforeRun(ctx context.Context, run *Run, in *RunInput) error
- func (f *Funcs) BeforeTool(ctx context.Context, run *Run, plan *ToolPlan) error
- func (f *Funcs) BeforeTurn(ctx context.Context, run *Run) error
- func (f *Funcs) Name() string
- func (f *Funcs) RevalidateTool(ctx context.Context, run *Run, plan *ToolPlan) error
- func (f *Funcs) WrapContext(ctx context.Context, run *Run) (context.Context, func())
- func (f *Funcs) WrapModel(run *Run, next model.Model) model.Model
- func (f *Funcs) WrapTool(run *Run, next tool.Invoker) tool.Invoker
- type Guardrail
- type GuardrailError
- type Handoff
- type Interrupt
- type Limits
- type MemoryCheckpointer
- type Middleware
- type ModelWrapper
- type Output
- type OutputError
- type OutputRetry
- type PendingCall
- type RememberScope
- type Request
- type Result
- type Run
- func (r *Run) Agent() string
- func (r *Run) Append(msgs ...*model.Message)
- func (r *Run) Caller() *Run
- func (r *Run) DecodeValue[T any](key string) (T, bool, error)
- func (r *Run) Emit(ev *Event) bool
- func (r *Run) EncodeValue(key string, v any) error
- func (r *Run) Halt(reason string)
- func (r *Run) ID() string
- func (r *Run) Logger() *slog.Logger
- func (r *Run) Messages() []*model.Message
- func (r *Run) NewMessages() []*model.Message
- func (r *Run) ReplaceMessages(msgs []*model.Message)
- func (r *Run) SessionID() string
- func (r *Run) SetValue(key, value string)
- func (r *Run) System() string
- func (r *Run) Tools() []*model.ToolSpec
- func (r *Run) Turn() int
- func (r *Run) Value(key string) (string, bool)
- type RunInput
- type Runtime
- func (r *Runtime) Config() Config
- func (r *Runtime) Discard(ctx context.Context, runID string) error
- func (r *Runtime) Resume(ctx context.Context, runID string, approvals map[string]Approval) iter.Seq2[*Event, error]
- func (r *Runtime) ResumeState(ctx context.Context, st *State, approvals map[string]Approval) iter.Seq2[*Event, error]
- func (r *Runtime) Run(ctx context.Context, req *Request) iter.Seq2[*Event, error]
- type Settings
- type State
- type Status
- type Step
- type StopCondition
- type ToolPlan
- type ToolProvider
- type ToolRevalidator
- type ToolWrapper
Constants ¶
const DefaultMaxTurns = 50
DefaultMaxTurns bounds the number of model calls in a run.
const DefaultOutputRetries = 2
DefaultOutputRetries is how often an answer that does not match Config.Output is sent back to the model when Output.Retries is zero.
const HandoffFromKey = "agentx.handoff.from"
HandoffFromKey is the run value that names the agent that handed the run off to the agent running it, in a run continued by agent.WithHandoffs. Middleware such as tracing reads it.
const SessionValuePrefix = "session."
SessionValuePrefix starts the keys of run values that belong to the session rather than the run. agent.Runner saves them with the session when a run ends and passes them to the session's next runs in Request.Values; callers of Runtime.Run carry them from Result.Values themselves.
const StateVersion = 1
StateVersion is the version of the State format written by this package. Resume accepts only states of this version.
Variables ¶
var ( Approve = Approval{Approved: true} Deny = Approval{Reason: "The user denied this tool call."} )
Approve and Deny are convenience approvals.
var ErrCheckpointNotFound = errors.New("checkpoint not found")
ErrCheckpointNotFound is returned when a checkpoint does not exist.
var ErrNoCheckpointer = errors.New("loop: resume requires a checkpointer")
ErrNoCheckpointer is returned by Resume when the runtime has no Checkpointer. Resume such runs from Interrupt.State with ResumeState.
Functions ¶
func Block ¶
Block returns an error that ends the run with StatusBlocked. Use it in BeforeRun to reject the input.
func CloseToolCalls ¶
CloseToolCalls returns a message that answers, with an error result holding content, the tool calls of the last assistant message in msgs that have no result, or nil if all are answered. Append it to end a conversation without leaving calls unanswered, which providers reject.
func Deps ¶
Deps returns the dependency of type T that ctx carries; see WithDeps. The type must match exactly: a dependency stored as a concrete type is not returned for an interface it implements.
func ForwardEvent ¶
ForwardEvent passes ev, an event of a nested run that the current tool call runs, such as a sub-agent's run, to the consumer of the run executing the call. The consumer gets a copy with Depth increased by one and, for an event of the nested run itself, ParentCallID set to the ID of the call; events the nested run forwarded keep theirs. The copy keeps the nested run's RunID, Agent and Turn.
ForwardEvent is safe for concurrent use, also by calls running concurrently. It reports false, without delivering the event, outside a tool call of a run, once the call has returned, or when the consumer stopped iterating. The nested run need not stop then: like any tool call, the call keeps its result.
func InterruptCall ¶
InterruptCall asks the run executing the current tool call to interrupt with the approval requests of intr, which typically come from a nested run such as a sub-agent. The tool's result is discarded. When the run is resumed, the tool is called again and ResumedCall returns intr and the decisions for its requests.
InterruptCall reports false outside a tool call of a run; the tool must then handle the interrupt itself.
func ReportUsage ¶
ReportUsage adds usage, for example of a sub-agent's run, to the run executing the current tool call, so the run's usage covers the work done on its behalf. Outside a tool call it does nothing.
func WithDeps ¶
WithDeps returns a context carrying v as the dependency of type T, for example a database handle or the current user, in the style of the OpenAI Agents SDK's run context and Pydantic AI's deps. Tools, hooks, middleware and instruction functions of runs started with the context read it with Deps. A context holds one dependency per type; a later WithDeps of the same type replaces it for the derived context.
Dependencies live only in the context: they are not sent to the model and not saved with checkpoints or sessions. Pass them again, with the context of Resume, when an interrupted run is resumed.
func WithheldAnswer ¶
WithheldAnswer returns the assistant message that replaces an answer the guardrail named name withheld.
Types ¶
type AfterModeler ¶
type AfterModeler interface {
AfterModel(ctx context.Context, run *Run, req *model.Request, resp *model.Response) error
}
AfterModeler runs after each model call, once the assistant message has been added to the conversation. req is the request that was sent.
type AfterRunner ¶
AfterRunner runs when a run ends, including when it is interrupted. If the consumer stops iterating early, it runs with StatusRunning: the run stopped where it was, and Result.Reason says whether it can be resumed from a checkpoint. It does not run if the consumer stops at EventRunStart, before the run took a step.
type AfterTooler ¶
type AfterTooler interface {
AfterTool(ctx context.Context, run *Run, plan *ToolPlan, res *model.ToolResult) error
}
AfterTooler runs after each tool call, including denied ones, and may modify the result.
type AnswerHolder ¶
type AnswerHolder interface {
HoldAnswer() bool
}
AnswerHolder is implemented by BeforeFinisher middleware that must see the final answer before the consumer does, such as the guard package's output guardrails with guard.HoldOutput. If HoldAnswer reports true, the runtime holds the EventDelta and EventMessage events of each model response until it knows the response has tool calls, when they are sent, or until every BeforeFinisher accepted the answer. An answer that does not end the run that way is never sent: one a BeforeFinisher rejects with a *GuardrailError or continues the run past, one the provider paused (model.FinishPause), one that fails Config.Output (its OutputRetry has no Output then), and one of a run that stops or fails before the answer is accepted. It stays in the conversation, including Result.Messages and Result.NewMessages, but is not Result.Output or OutputError.Output. Schema diagnostics reported to the consumer then describe only a generic mismatch, since details may quote unchecked text. The deltas of a response therefore arrive at once, after the response ended, unless the response calls tools.
type Approval ¶
type Approval struct {
Approved bool `json:"approved"`
// Reason is shown to the model when the call is denied.
Reason string `json:"reason,omitempty"`
// UpdatedInput replaces the call arguments when approved.
UpdatedInput json.RawMessage `json:"updated_input,omitempty"`
// Remember asks middleware that decides approvals, such as the
// permission package's Policy, to approve later calls like this one
// without asking again, for the rest of the run or of the session.
// Middleware reads it with ToolPlan.Approval.
Remember RememberScope `json:"remember,omitempty"`
// RememberRules, if set, lists what to remember instead of what the
// middleware derives from the call, for example permission rules such
// as "Bash(npm test *)".
RememberRules []string `json:"remember_rules,omitempty"`
}
Approval is the decision for an ApprovalRequest.
type ApprovalRequest ¶
type ApprovalRequest struct {
Call *model.ToolCall `json:"call"`
// Reason is the explanation given by the hook that asked, if any.
Reason string `json:"reason,omitempty"`
// Agent names the agent whose call this is. Requests of sub-agents
// reach the parent's interrupt with their own agent name.
Agent string `json:"agent,omitempty"`
}
ApprovalRequest asks for permission to run a tool call.
type Approver ¶
type Approver interface {
Approve(ctx context.Context, req *ApprovalRequest) (Approval, error)
}
Approver decides approval requests synchronously, for example by prompting a user in a terminal.
type ApproverFunc ¶
type ApproverFunc func(ctx context.Context, req *ApprovalRequest) (Approval, error)
ApproverFunc adapts a function to Approver.
func (ApproverFunc) Approve ¶
func (f ApproverFunc) Approve(ctx context.Context, req *ApprovalRequest) (Approval, error)
Approve calls f.
type BeforeFinisher ¶
type BeforeFinisher interface {
BeforeFinish(ctx context.Context, run *Run, msg *model.Message) (bool, error)
}
BeforeFinisher runs when the model answers without tool calls. Returning true continues the run; the middleware must have appended the next input with Run.Append.
type BeforeModeler ¶
type BeforeModeler interface {
BeforeModel(ctx context.Context, run *Run, req *model.Request) error
}
BeforeModeler runs before each model call and may modify the request. The request's options are copies, but the values in ProviderOptions are shared with the configuration, and the messages are shared with the run: replace a value in ProviderOptions or a message in Request.Messages instead of modifying it.
type BeforeRunner ¶
BeforeRunner runs when a new run starts, before the input enters the conversation. It does not run when an interrupted run is resumed.
type BeforeTooler ¶
BeforeTooler runs for each tool call while the turn decides which calls need approval, before the run may be interrupted.
type BeforeTurner ¶
BeforeTurner runs at the start of each turn, before the model request is built. It may replace the conversation, for example to compact it.
type Checkpointer ¶
type Checkpointer interface {
Save(ctx context.Context, st *State) error
Load(ctx context.Context, runID string) (*State, error)
Delete(ctx context.Context, runID string) error
}
Checkpointer persists run state so interrupted or crashed runs can be resumed. Checkpoints are keyed by run ID: 1 to 128 ASCII letters, digits, '_' and '-'; the built-in checkpointers reject others. A run overwrites its checkpoint once its input is added, after each turn, before each batch of tool calls, and when it is interrupted, fails or its consumer stops iterating; it deletes the checkpoint when it ends in a status that is not resumable or fails before its input is added.
type Compaction ¶
type Compaction struct {
// Messages is the conversation after compaction.
Messages []*model.Message `json:"messages"`
// Before and After are the estimated input sizes in tokens.
Before int `json:"before"`
After int `json:"after"`
Summary string `json:"summary,omitempty"`
}
Compaction describes a compaction of the conversation for EventCompacted.
type Config ¶
type Config struct {
Settings
Tools *tool.Registry
// Middlewares extend the loop in order. If any is a ToolProvider, its
// tools are added to a copy of Tools.
Middlewares []Middleware
}
Config configures a Runtime.
type ContextWrapper ¶
type ContextWrapper interface {
WrapContext(ctx context.Context, run *Run) (_ context.Context, release func())
}
ContextWrapper derives the context of a run once when Run or Resume starts, for example to start a trace span that the run's model and tool calls become children of. The returned context must derive from ctx. release, if non-nil, is called when the Run or Resume call returns, however the run ended.
type Event ¶
type Event struct {
Type EventType `json:"type"`
RunID string `json:"run_id,omitempty"`
SessionID string `json:"session_id,omitempty"`
Agent string `json:"agent,omitempty"`
Turn int `json:"turn,omitempty"`
Delta *model.StreamEvent `json:"delta,omitempty"`
Message *model.Message `json:"message,omitempty"`
ToolCall *model.ToolCall `json:"tool_call,omitempty"`
ToolResult *model.ToolResult `json:"tool_result,omitempty"`
Compaction *Compaction `json:"compaction,omitempty"`
// OutputRetry describes the rejected answer for EventOutputRetry.
OutputRetry *OutputRetry `json:"output_retry,omitempty"`
Interrupt *Interrupt `json:"interrupt,omitempty"`
// Handoff describes the transfer for EventHandoff.
Handoff *Handoff `json:"handoff,omitempty"`
// Usage is the usage of the model call for EventMessage.
Usage model.Usage `json:"usage,omitzero"`
Result *Result `json:"result,omitempty"`
// Depth is zero for the events of the run itself. Events of nested runs,
// such as a sub-agent's, that a tool call forwards with ForwardEvent
// have the depth of the nested run below this one: 1 for a sub-agent, 2
// for a sub-agent of a sub-agent. Their RunID, Agent and Turn are those
// of the nested run, and an EventRunEnd among them ends the nested run,
// not this one.
Depth int `json:"depth,omitempty"`
// ParentCallID is set on forwarded events to the ID of the tool call
// that started the nested run that emitted them, in the run directly
// above it.
ParentCallID string `json:"parent_call_id,omitempty"`
}
Event is emitted by a run.
type EventType ¶
type EventType string
EventType identifies a runtime event.
const ( // EventRunStart is the first event of a run or a resumed run. EventRunStart EventType = "run_start" // EventTurnStart precedes each model call. EventTurnStart EventType = "turn_start" // EventDelta carries a streaming delta when streaming is enabled. EventDelta EventType = "delta" // EventMessage carries a complete assistant message. EventMessage EventType = "message" // EventToolCall is emitted before a tool call runs. EventToolCall EventType = "tool_call" // EventToolResult carries the result of a tool call. EventToolResult EventType = "tool_result" // EventCompacted reports that the conversation was compacted. EventCompacted EventType = "compacted" // EventOutputRetry reports that the final answer did not match // Config.Output and was sent back to the model; see OutputRetry. EventOutputRetry EventType = "output_retry" // EventHandoff reports that the run was handed off to another agent, // whose events follow; see Handoff. Its Agent is the agent handing off. EventHandoff EventType = "handoff" // EventInterrupted reports that the run paused for approval. EventInterrupted EventType = "interrupted" // EventRunEnd is the last event and carries the Result. EventRunEnd EventType = "run_end" )
type Funcs ¶
type Funcs struct {
MiddlewareName string
WrapContextFunc func(ctx context.Context, run *Run) (context.Context, func())
BeforeRunFunc func(ctx context.Context, run *Run, in *RunInput) error
BeforeTurnFunc func(ctx context.Context, run *Run) error
BeforeModelFunc func(ctx context.Context, run *Run, req *model.Request) error
WrapModelFunc func(run *Run, next model.Model) model.Model
AfterModelFunc func(ctx context.Context, run *Run, req *model.Request, resp *model.Response) error
BeforeToolFunc func(ctx context.Context, run *Run, plan *ToolPlan) error
RevalidateToolFunc func(ctx context.Context, run *Run, plan *ToolPlan) error
WrapToolFunc func(run *Run, next tool.Invoker) tool.Invoker
AfterToolFunc func(ctx context.Context, run *Run, plan *ToolPlan, res *model.ToolResult) error
BeforeFinishFunc func(ctx context.Context, run *Run, msg *model.Message) (bool, error)
AfterRunFunc func(ctx context.Context, run *Run, res *Result)
}
Funcs builds a middleware from functions. Nil functions are skipped.
func (*Funcs) AfterModel ¶
func (f *Funcs) AfterModel(ctx context.Context, run *Run, req *model.Request, resp *model.Response) error
AfterModel implements AfterModeler.
func (*Funcs) AfterTool ¶
func (f *Funcs) AfterTool(ctx context.Context, run *Run, plan *ToolPlan, res *model.ToolResult) error
AfterTool implements AfterTooler.
func (*Funcs) BeforeFinish ¶
BeforeFinish implements BeforeFinisher.
func (*Funcs) BeforeModel ¶
BeforeModel implements BeforeModeler.
func (*Funcs) BeforeTool ¶
BeforeTool implements BeforeTooler.
func (*Funcs) BeforeTurn ¶
BeforeTurn implements BeforeTurner.
func (*Funcs) RevalidateTool ¶
RevalidateTool implements ToolRevalidator.
func (*Funcs) WrapContext ¶
WrapContext implements ContextWrapper.
type Guardrail ¶
type Guardrail struct {
// Name names the guardrail.
Name string `json:"name"`
// Kind is where it ran: "input", "output", "tool_input" or
// "tool_output".
Kind string `json:"kind,omitempty"`
// Message explains the trip, for example to show to the user.
Message string `json:"message,omitempty"`
// Info is any information the guardrail attached.
Info any `json:"info,omitempty"`
}
Guardrail describes the guardrail whose tripwire ended a run, for Result.Guardrail. See the guard package.
type GuardrailError ¶
type GuardrailError struct {
Guardrail Guardrail
// Usage is the usage of a model call the guardrail cut short or
// rejected, which a ModelWrapper returning the error reports so the
// run still counts it.
Usage model.Usage
}
GuardrailError is returned by middleware, typically the guard package's, when a guardrail's tripwire triggers. Returned from a stage or from a model call (see ModelWrapper), it ends the run with StatusBlocked and Result.Guardrail set; Result.Output is then empty, so a withheld answer is not shown by accident. Returned from BeforeFinish, it withholds the final answer: the conversation, the run's result and what a Runner saves keep WithheldAnswer in its place, which keeps the conversation valid for providers. Its events were sent already unless an AnswerHolder held them.
func (*GuardrailError) Error ¶
func (e *GuardrailError) Error() string
type Handoff ¶
type Handoff struct {
// From and To name the agents.
From string `json:"from"`
To string `json:"to"`
// Tool and CallID identify the tool call that requested the handoff.
Tool string `json:"tool,omitempty"`
CallID string `json:"call_id,omitempty"`
// Input holds the arguments of the call, for handoffs with a typed
// input.
Input json.RawMessage `json:"input,omitempty"`
}
Handoff describes the transfer of a run from one agent to another, for EventHandoff. See agent.WithHandoffs.
type Interrupt ¶
type Interrupt struct {
RunID string `json:"run_id"`
Requests []*ApprovalRequest `json:"requests"`
// State is the state of the paused run. It lets ResumeState continue
// the run without a Checkpointer, as sub-agents do.
State *State `json:"state,omitempty"`
}
Interrupt describes a run paused for approval. Resume it with a decision for each request, keyed by the request's call ID.
type Limits ¶
type Limits struct {
// Requests bounds the model calls.
Requests int `json:"requests,omitempty"`
// ToolCalls bounds the executed tool calls. A batch that would exceed
// it does not start; denied calls do not count.
ToolCalls int `json:"tool_calls,omitempty"`
// InputTokens bounds model.Usage.PromptTokens, the input tokens
// including cache reads and writes.
InputTokens int `json:"input_tokens,omitempty"`
// OutputTokens bounds model.Usage.OutputTokens.
OutputTokens int `json:"output_tokens,omitempty"`
// TotalTokens bounds model.Usage.TotalTokens.
TotalTokens int `json:"total_tokens,omitempty"`
}
Limits bounds the usage of a run, including the usage that nested runs, such as sub-agents, report with ReportUsage. Zero fields are unlimited.
Requests is checked before each model call, ToolCalls before each batch of tool calls, and the token limits before both: once tokens are spent, the run does no further work. A run that reaches a limit ends with StatusLimitExceeded; tool calls that did not run are answered as such, so the conversation stays valid. A final answer is kept even if its model call crossed a token limit.
type MemoryCheckpointer ¶
type MemoryCheckpointer struct {
// contains filtered or unexported fields
}
MemoryCheckpointer keeps checkpoints in process memory, encoded as JSON like a persistent checkpointer, so a state that cannot be stored fails here too. The zero value is ready to use.
func NewMemoryCheckpointer ¶
func NewMemoryCheckpointer() *MemoryCheckpointer
NewMemoryCheckpointer returns an empty in-memory checkpointer.
func (*MemoryCheckpointer) Delete ¶
func (c *MemoryCheckpointer) Delete(_ context.Context, runID string) error
Delete implements Checkpointer.
type Middleware ¶
type Middleware interface {
// Name identifies the middleware. Names must be unique in a Runtime.
Name() string
}
Middleware extends the agent loop. Every middleware implements Name and any of the stage interfaces below; the runtime calls only the stages a middleware implements.
Before stages run in registration order, After stages in reverse order, and for Wrap stages the first middleware is outermost.
An error returned from a stage ends the run: Block and Stop end it with StatusBlocked and StatusStopped, any other error fails it. Middleware that should not stop the run on failure must handle its errors itself.
type ModelWrapper ¶
ModelWrapper wraps each model call. The wrapper may call next any number of times, including not at all.
type Output ¶
type Output struct {
// Name names the schema for providers. It defaults to "output" and may
// hold letters, digits, underscores and dashes, up to 64.
Name string
// Schema describes the answer. It must be an object schema with
// properties, such as tool.SchemaOf of a struct type.
Schema *tool.Schema
// Retries bounds how often an answer that does not match Schema is sent
// back to the model. Zero means DefaultOutputRetries; a negative value
// means none.
Retries int
}
Output asks the model for a final answer in JSON matching Schema and validates it.
Unless Config.ResponseFormat is set, the runtime requests Schema as the response format in strict mode; see tool.Schema.StrictJSON. When the model answers without tool calls, the answer is checked against Schema before BeforeFinish middleware, such as Stop hooks, runs. An answer in a single Markdown code block, such as one fenced with ```json, is checked without the fence. An answer that does not match is sent back to the model with the problems found, and the run continues; each attempt takes a turn. Once the retries are used up, the run fails with an *OutputError; resuming it gives the model the same number of retries again. Answers cut off by the token limit, withheld by a content filter or refused are not checked: they end the run as they would without Output. Each answer sent back is reported with an EventOutputRetry.
type OutputError ¶
type OutputError struct {
// Output is the text of the last answer. It is empty when an
// AnswerHolder holds answers: it was rejected before answer-holder checks.
Output string
// Problems lists what does not match the schema. When an AnswerHolder
// holds answers, it reports only a generic mismatch, since detailed
// diagnostics may quote text that has not passed answer-holder checks.
Problems []string
// Attempts is the number of answers checked.
Attempts int
}
OutputError reports that the final answer of a run did not match Config.Output after all retries. It is the error of the failed run.
func (*OutputError) Error ¶
func (e *OutputError) Error() string
type OutputRetry ¶
type OutputRetry struct {
// Output is the text of the answer. It is empty when an AnswerHolder
// holds answers: it was rejected before answer-holder checks.
Output string `json:"output"`
// Problems lists what does not match the schema. When an AnswerHolder
// holds answers, it reports only a generic mismatch; see OutputError.
Problems []string `json:"problems,omitempty"`
// Attempt numbers the answer among those the run checked, from 1. The
// count restarts when a run that failed with an *OutputError is
// resumed.
Attempt int `json:"attempt"`
// Retries is the number of retries allowed; the run fails with an
// *OutputError if answer Retries+1 does not match either.
Retries int `json:"retries"`
}
OutputRetry describes an answer that did not match Config.Output and was sent back to the model, for EventOutputRetry.
type PendingCall ¶
type PendingCall struct {
Call *model.ToolCall `json:"call"`
// Denied is set when middleware or the approver rejected the call.
Denied bool `json:"denied,omitempty"`
Reason string `json:"reason,omitempty"`
// NeedsApproval is set while approval is outstanding.
NeedsApproval bool `json:"needs_approval,omitempty"`
ReadOnly bool `json:"read_only,omitempty"`
// Concurrent is set for calls of tools marked tool.Concurrent.
Concurrent bool `json:"concurrent,omitempty"`
// Values holds middleware state; see ToolPlan.SetValue.
Values map[string]string `json:"values,omitempty"`
// ModelArguments holds the arguments the model sent when middleware or
// an approval changed them; Call holds the arguments that run.
ModelArguments json.RawMessage `json:"model_arguments,omitempty"`
// Started is set once the call began executing, and Result once it
// finished. A resumed run reuses results and does not repeat a call
// with side effects that may have run.
Started bool `json:"started,omitempty"`
Result *model.ToolResult `json:"result,omitempty"`
// Nested is the interrupt the call raised for approvals of a nested
// run, such as a sub-agent; see InterruptCall. NestedApprovals holds
// the decisions once they are made.
Nested *Interrupt `json:"nested,omitempty"`
NestedApprovals map[string]Approval `json:"nested_approvals,omitempty"`
// Approval is the decision of the approval the call needed, if any,
// without its UpdatedInput; see ToolPlan.Approval.
Approval *Approval `json:"approval,omitempty"`
// Resuming is set while the call is repeated to resume its nested run.
// If the run stops then, the nested run may have executed approved
// calls, so a call with side effects is not repeated, like any cut-off
// call with side effects. A read-only call is repeated with its nested
// run, like any cut-off read-only call.
Resuming bool `json:"resuming,omitempty"`
}
PendingCall is a tool call whose pre-execution checks have run.
type RememberScope ¶
type RememberScope string
RememberScope is how long an approval is remembered; see Approval.Remember.
const ( // RememberRun remembers an approval for the rest of the run. RememberRun RememberScope = "run" // RememberSession remembers an approval for the rest of the session: // it is kept in a run value whose key starts with SessionValuePrefix, // which agent.Runner carries to the session's later runs. RememberSession RememberScope = "session" )
type Request ¶
type Request struct {
// RunID identifies the run; generated when empty.
RunID string
SessionID string
// History is the conversation before Input. It is not modified.
History []*model.Message
// Input is the new user message.
Input *model.Message
// NewSession marks the first run of a session, for example to fire the
// SessionStart hook.
NewSession bool
// MaxTurns, if positive, overrides Config.MaxTurns for this run.
MaxTurns int
// Limits, if non-nil, replaces Config.Limits for this run.
Limits *Limits
// Values are the initial values of the run, as Run.SetValue stores
// them, for example the session-scoped values of the session's earlier
// runs; see SessionValuePrefix. Empty values are ignored.
Values map[string]string
// Usage and Turns are the usage and turns of earlier parts of the same
// run, such as those of an agent that handed the run off to this one.
// They count toward the limits and are included in the Result.
Usage model.Usage
Turns int
}
Request starts a run.
type Result ¶
type Result struct {
RunID string `json:"run_id"`
Status Status `json:"status"`
// Reason explains a non-completed status.
Reason string `json:"reason,omitempty"`
// FinishReason is the finish reason of the last model response, for
// example model.FinishRefusal when the model declined to answer.
FinishReason model.FinishReason `json:"finish_reason,omitempty"`
// Output is the text of the final assistant message, or the result of
// the tool the run stopped at; see Config.StopAtTools. Decode parses it.
Output string `json:"output"`
// Messages is the whole conversation after the run, including history.
// It may be shorter than history plus new messages after compaction.
Messages []*model.Message `json:"messages,omitempty"`
// NewMessages are the messages added by this run.
NewMessages []*model.Message `json:"new_messages,omitempty"`
Usage model.Usage `json:"usage"`
Turns int `json:"turns"`
// Interrupt lists the approvals needed to resume.
Interrupt *Interrupt `json:"interrupt,omitempty"`
// Err is the error of a failed run. In JSON it is the string "error".
Err error `json:"-"`
// Values are the run's values when it ended; see Run.SetValue and
// SessionValuePrefix.
Values map[string]string `json:"values,omitempty"`
// Agent names the agent that ran last, which differs from the agent
// started when the run was handed off; see EventHandoff.
Agent string `json:"agent,omitempty"`
// Guardrail describes the guardrail whose tripwire ended a run with
// StatusBlocked; see GuardrailError.
Guardrail *Guardrail `json:"guardrail,omitempty"`
}
Result summarizes a finished or interrupted run.
func Collect ¶
Collect drains events and returns the run result. onEvent, if non-nil, sees every event, including those forwarded from nested runs.
func (*Result) Decode ¶
Decode unmarshals the output of a completed run into v with encoding/json. Output in a single Markdown code block is decoded from inside the block, as Config.Output checks it. It returns an error if the run did not complete or the model refused to answer.
func (*Result) DecodeAs ¶
DecodeAs decodes the output of a completed run as a T, as Decode does. Agents configured with agent.WithOutput[T] answer with JSON of a T.
func (Result) MarshalJSON ¶
MarshalJSON encodes the result with Err as the string "error".
func (*Result) UnmarshalJSON ¶
UnmarshalJSON decodes a result encoded by MarshalJSON. Err, if set, only keeps the error's text.
type Run ¶
type Run struct {
// contains filtered or unexported fields
}
Run gives middleware access to the state of a run. The methods are not safe for concurrent use, except the read methods and Emit while tools execute.
func CallingRun ¶
CallingRun returns the run executing the current tool call, or nil outside a tool call of a run. Calls may run concurrently, so only the read methods of the run may be used.
func (*Run) Caller ¶
Caller returns the run whose tool call started this run, such as the run that called a sub-agent, or nil if the run was not started by a tool call. Following Caller from CallingRun leads to the outermost run, which holds the session of a sub-agent's work. Only the read methods of the returned run may be used.
func (*Run) DecodeValue ¶
DecodeValue decodes the run value of key, as stored by EncodeValue, into a T. It reports false if the run has no such value; a value that is not JSON of a T is an error.
func (*Run) Emit ¶
Emit sends an event to the consumer of the run. It reports false when the consumer stopped iterating; no event is delivered after that. Tool calls running concurrently may emit too: their events are delivered one at a time, from the goroutine iterating the run.
func (*Run) EncodeValue ¶
EncodeValue stores v as the run value of key, encoded as JSON, so values other than strings survive checkpoints; read it with DecodeValue. A nil v deletes the key. Like SetValue, it must not be called from tools that may run concurrently.
func (*Run) Messages ¶
Messages returns the conversation, including history. It must not be modified.
func (*Run) NewMessages ¶
NewMessages returns the messages this run added to the conversation, starting with its input. It must not be modified.
func (*Run) ReplaceMessages ¶
ReplaceMessages replaces the conversation with a shorter one whose messages were removed from the front, as compaction does.
func (*Run) SetValue ¶
SetValue stores a value in the run state, which is saved with checkpoints. An empty value deletes the key. Prefix keys with the middleware name.
type RunInput ¶
type RunInput struct {
NewSession bool
// Query is the text of the input message before any middleware ran.
Query string
// System is the system prompt. It starts as Config.Instructions.
System string
// Message is the input message. Middleware may modify it, for example
// by inserting parts in front of the user's text.
Message *model.Message
}
RunInput is the input of a new run, as seen by BeforeRun.
type Runtime ¶
type Runtime struct {
// contains filtered or unexported fields
}
Runtime runs the agent loop. It is safe for concurrent runs.
func (*Runtime) Discard ¶
Discard deletes the checkpoint of a run that will not be resumed. A missing checkpoint is not an error.
func (*Runtime) Resume ¶
func (r *Runtime) Resume(ctx context.Context, runID string, approvals map[string]Approval) iter.Seq2[*Event, error]
Resume continues a run from its checkpoint. It resumes runs that were interrupted for approval, that failed, or whose process stopped while they were running; see Status.Resumable.
approvals maps tool call IDs to decisions for an interrupted run; calls without a decision are denied. Approvals are ignored for runs that were not interrupted: requests they raise go to the Approver or interrupt the run. Finished tool calls are not repeated, and calls with side effects that were cut off are reported to the model as possibly incomplete instead of being run again.
A run that stopped after the model's final answer, before the answer was handled, handles it without calling the model again. If the consumer stops at EventRunStart, the checkpoint is left as it was.
func (*Runtime) ResumeState ¶
func (r *Runtime) ResumeState(ctx context.Context, st *State, approvals map[string]Approval) iter.Seq2[*Event, error]
ResumeState is like Resume for a state obtained elsewhere, such as Interrupt.State of an earlier run, without a Checkpointer.
func (*Runtime) Run ¶
Run starts a run and returns its events. The last event is EventRunEnd; a failed run then yields its error.
If the consumer stops iterating early, the run stops before its next step: tool calls that have not started do not run, and AfterRun middleware sees StatusRunning. Once the input was added, the state is checkpointed as running, so with a Checkpointer the run can be resumed from where it stopped; Result.Reason says whether it can. If the consumer stops at EventRunStart, nothing runs, not even AfterRun, and there is nothing to resume.
type Settings ¶ added in v1.1.0
type Settings struct {
// Name identifies the agent in events and hooks.
Name string
Model model.Model
// Instructions is the base system prompt; middleware may extend it.
Instructions string
// ToolMiddlewares wrap every tool call inside the ToolWrapper
// middleware; the first is outermost.
ToolMiddlewares []tool.Middleware
Checkpointer Checkpointer
// Approver decides calls that need approval. Without one, the run is
// interrupted and must be resumed with approvals.
Approver Approver
MaxTurns int
MaxTokens int
Temperature *float64
TopP *float64
Reasoning *model.Reasoning
ToolChoice *model.ToolChoice
ResponseFormat *model.ResponseFormat
// Seed is passed to the provider in model.Request.Seed.
Seed *int
// ProviderOptions is passed to the provider in
// model.Request.ProviderOptions.
ProviderOptions map[string]map[string]any
// Stream calls Model.Stream and emits delta events.
Stream bool
// Parallelism bounds tool calls running concurrently, which are those of
// read-only and concurrent tools. Defaults to 8.
Parallelism int
Logger *slog.Logger
// Output asks the model for JSON matching a schema and validates the
// final answer; see Output.
Output *Output
// Limits bounds the usage of each run; Request.Limits overrides it.
Limits Limits
// Budget, if set, is called with the run's usage so far before each
// model call and each batch of tool calls. An error ends the run with
// StatusLimitExceeded and the error's text as the reason, for example
// when the usage priced in a currency exceeds a budget.
Budget func(model.Usage) error
// StopAtTools ends the run as completed once a tool with one of these
// names returns a result that is not an error. Result.Output is the
// content of that result, and the model is not called again.
StopAtTools []string
// StopWhen ends the run as completed when any condition holds after a
// turn's tool calls have run; see StopCondition.
StopWhen []StopCondition
}
Settings are the run settings shared by Config and agent.Config: the model and its request options, approval and checkpointing, and the limits and stop conditions of runs.
type State ¶
type State struct {
// Version is the format version; see StateVersion.
Version int `json:"version,omitempty"`
RunID string `json:"run_id"`
SessionID string `json:"session_id,omitempty"`
Agent string `json:"agent,omitempty"`
Turn int `json:"turn"`
// System is the system prompt assembled at the start of the run.
System string `json:"system,omitempty"`
// Messages is the whole conversation, including prior history.
Messages []*model.Message `json:"messages"`
// Start is the index in Messages where this run's input begins.
Start int `json:"start"`
Usage model.Usage `json:"usage"`
Status Status `json:"status"`
Reason string `json:"reason,omitempty"`
// FinishReason is the finish reason of the last model response. A run
// resumed after the model's final answer uses it to handle the answer.
FinishReason model.FinishReason `json:"finish_reason,omitempty"`
// Pending holds the planned tool calls of the current turn while they
// are being approved or executed.
Pending []*PendingCall `json:"pending,omitempty"`
// Values holds middleware state; see Run.SetValue.
Values map[string]string `json:"values,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
// MaxTurns and Limits are the run's overrides of the configuration,
// from its Request, kept so that a resumed run applies them too.
MaxTurns int `json:"max_turns,omitempty"`
Limits *Limits `json:"limits,omitempty"`
// OutputRetries counts the answers sent back to the model because they
// did not match Config.Output.
OutputRetries int `json:"output_retries,omitempty"`
}
State is the resumable state of a run. It is what checkpoints store.
func (*State) NewMessages ¶
NewMessages returns the messages added by this run.
type Status ¶
type Status string
Status is the state of a run.
const ( StatusRunning Status = "running" StatusCompleted Status = "completed" // StatusInterrupted means the run is waiting for tool approvals and can // be resumed. StatusInterrupted Status = "interrupted" StatusFailed Status = "failed" // StatusMaxTurns means the turn limit was reached. StatusMaxTurns Status = "max_turns" // StatusStopped means middleware, for example a hook, stopped the run. StatusStopped Status = "stopped" // StatusBlocked means middleware, for example a UserPromptSubmit hook, // rejected the input. StatusBlocked Status = "blocked" // StatusIncomplete means the final answer is incomplete: it was cut off // by the output token limit or withheld by a content filter. Reason // says which. Result.Output holds what was returned unless an AnswerHolder // withholds it. StatusIncomplete Status = "incomplete" // StatusLimitExceeded means the run reached one of its Limits or its // Budget; Reason names it. Like StatusMaxTurns it is final: continue // the conversation with a new run, which starts with its own limits. StatusLimitExceeded Status = "limit_exceeded" )
type Step ¶
type Step struct {
// Turn is the turn number.
Turn int
// Message is the model's message of the turn.
Message *model.Message
// ToolResults are the results of its tool calls, in call order.
ToolResults []*model.ToolResult
// Usage is the run's usage so far.
Usage model.Usage
}
Step is a turn whose tool calls have run, as a StopCondition sees it.
type StopCondition ¶
StopCondition reports whether a run should end after a step. It must not modify the step. A run that a condition stops ends as completed, and Result.Output is the text of the model's last message, which may be empty when the model only called tools.
type ToolPlan ¶
type ToolPlan struct {
// Call is the tool call. BeforeTool may rewrite its arguments.
Call *model.ToolCall
// Info describes the tool; Known is false for unknown tools. Its
// RequiresApproval is that of this call when the tool is a
// tool.CallApprover.
Info tool.Info
Known bool
// contains filtered or unexported fields
}
ToolPlan is a tool call as seen by BeforeTool and AfterTool.
func (*ToolPlan) Allow ¶
func (p *ToolPlan) Allow()
Allow skips approval unless another middleware asks or denies.
func (*ToolPlan) Approval ¶
Approval returns the decision of the approval the call needed, without its UpdatedInput, and reports false if the call needed none or is not decided yet. AfterTool middleware uses it, for example, to remember an approval; see Approval.Remember.
type ToolProvider ¶
ToolProvider contributes tools to the runtime's registry.
type ToolRevalidator ¶
type ToolRevalidator interface {
RevalidateTool(ctx context.Context, run *Run, plan *ToolPlan) error
}
ToolRevalidator checks arguments changed by an approved UpdatedInput, after approval and before execution. Middleware that enforces argument policies in BeforeTool must also implement this stage; BeforeTool itself is not repeated, so hooks and other one-time operations do not run twice.
RevalidateTool may Deny the call or return an error, as BeforeTool does. Ask is already satisfied by the explicit approval, including approval of the edited arguments, and does not prompt again. Call and Info describe those arguments, and Approval returns the decision. Revalidators must not rewrite Call; the runtime rejects a changed call rather than execute arguments an earlier revalidator did not check.
Revalidation runs in middleware order, stopping at a denial or error. Unchanged and denied approvals do not run this stage.
type ToolWrapper ¶
ToolWrapper wraps each tool execution, after the arguments have been validated. Read-only and concurrent calls run concurrently, so the returned invoker must be safe for concurrent use and may only call the read methods of run and Emit.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package checkpointtest checks loop.Checkpointer implementations against the contract the built-in checkpointers follow.
|
Package checkpointtest checks loop.Checkpointer implementations against the contract the built-in checkpointers follow. |