Documentation
¶
Overview ¶
Package agentflow provides a production-grade framework for building agentic AI systems in Go.
An agentic AI system is one where a language model can autonomously decide to invoke tools, observe results, and continue reasoning in a loop until the task is complete. This package provides the core abstractions and orchestration logic to build such systems with any AI provider that supports tool use (function calling).
Architecture ¶
The framework is built around five core interfaces:
- Provider abstracts an AI model API (Anthropic, OpenAI, OpenRouter, etc.)
- Tool defines a capability the agent can invoke (web search, file read, API call, etc.)
- Hook intercepts the execution pipeline at defined lifecycle phases
- PermissionChecker controls whether a tool is allowed to execute
- Compactor manages conversation history when context limits are approached
The Agentic Loop ¶
The core of the framework is a simple but powerful loop:
for {
response := provider.CreateStream(messages)
toolCalls := extractToolCalls(response)
if len(toolCalls) == 0 {
break // model is done
}
results := executor.Execute(toolCalls)
messages = append(messages, results...)
}
The loop streams events through a channel, allowing real-time observation of every step: text deltas, tool invocations, progress updates, and completion signals.
Quick Start ¶
provider := openrouter.New("sk-or-...", "anthropic/claude-sonnet-4-20250514")
agent := agentflow.NewAgent(provider,
agentflow.WithTools(myTool),
agentflow.WithSystemPrompt("You are a helpful assistant."),
)
messages := []agentflow.Message{agentflow.NewUserMessage("Hello")}
for ev := range agent.Run(ctx, messages) {
// handle events
}
Index ¶
- Constants
- Variables
- func FilterEvents(ch <-chan Event, types ...EventType) <-chan Event
- func GenerateSessionID() string
- func IsContextTooLargeError(err error) bool
- func IsHealthy(ctx context.Context, p Provider) error
- func IsRetryableError(err error) bool
- func IsToolAllowed(t Tool, mode ExecutionMode) bool
- func SessionPreview(messages []Message, maxLen int) string
- type Agent
- func (a *Agent) AddHook(h Hook)
- func (a *Agent) Clone(opts ...Option) *Agent
- func (a *Agent) Resume(ctx context.Context, sessionID string, additionalMessage string) (<-chan Event, error)
- func (a *Agent) Run(ctx context.Context, messages []Message) <-chan Event
- func (a *Agent) RunSession(ctx context.Context, session *Session, messages []Message) <-chan Event
- func (a *Agent) RunSync(ctx context.Context, messages []Message) ([]Message, error)
- func (a *Agent) SpawnChild(ctx context.Context, cfg SubAgentConfig, task string) <-chan Event
- func (a *Agent) SpawnChildren(ctx context.Context, cfg SubAgentConfig, tasks []string) <-chan Event
- func (a *Agent) Tools() []string
- type BudgetWarningEvent
- type CompactionEvent
- type Compactor
- type Config
- type ContentBlock
- type ContentBlockType
- type ContentDelta
- type DocumentContent
- type ErrorAction
- type ErrorEvent
- type ErrorStrategy
- type ErrorStrategyFunc
- type Event
- type EventType
- type ExecutionMode
- type HeadTailLimiter
- type HealthChecker
- type Hook
- type HookAction
- type HookBlockedEvent
- type HookContext
- type HookFunc
- type HookPhase
- type ImageContent
- type LocalityAware
- type Message
- type MultiPhaseHook
- type NoLimiter
- type Option
- func WithCompactor(c Compactor) Option
- func WithDisableInputValidation() Option
- func WithErrorStrategy(s ErrorStrategy) Option
- func WithEventBufferSize(n int) Option
- func WithExecutionMode(mode ExecutionMode) Option
- func WithHook(h Hook) Option
- func WithLogger(logger *slog.Logger) Option
- func WithMaxConcurrency(n int) Option
- func WithMaxResultSize(chars int) Option
- func WithMaxTokens(n int) Option
- func WithMaxTurns(n int) Option
- func WithOnEvent(fn func(Event)) Option
- func WithPermission(p PermissionChecker) Option
- func WithProviderExtras(extras map[string]any) Option
- func WithRateLimiter(limiter RateLimiter) Option
- func WithResultLimiter(limiter ResultLimiter) Option
- func WithRetryPolicy(p RetryPolicy) Option
- func WithSessionStore(store SessionStore) Option
- func WithSystemPrompt(s string) Option
- func WithTemperature(t float64) Option
- func WithThinkingPrompt(thinkPrompt, answerPrompt string) Option
- func WithTokenBudget(budget TokenBudget) Option
- func WithTool(t Tool) Option
- func WithToolRetries(n int) Option
- func WithToolTimeout(d time.Duration) Option
- func WithTools(tools ...Tool) Option
- type OrchestrateResult
- type PermissionChecker
- type PermissionDeniedEvent
- type PermissionFunc
- type PermissionResult
- type ProgressEvent
- type ProgressFunc
- type Provider
- type ProviderError
- type RateLimiter
- type Request
- type ResultLimiter
- type RetryEvent
- type RetryPolicy
- type Role
- type Session
- type SessionInfo
- type SessionStore
- type Stream
- type StreamEvent
- type StreamEventType
- type SubAgentConfig
- type SubAgentEndEvent
- type SubAgentStartEvent
- type TextDeltaEvent
- type TimeoutAware
- type TokenBucketLimiter
- type TokenBudget
- type Tool
- type ToolCall
- type ToolDefinition
- type ToolEndEvent
- type ToolError
- type ToolLocality
- type ToolResult
- type ToolResultBlock
- type ToolStartEvent
- type TruncateLimiter
- type TurnEndEvent
- type TurnEndReason
- type TurnStartEvent
- type Usage
- type UsageEvent
Constants ¶
const ( DefaultMaxConcurrency = 10 DefaultEventBufferSize = 256 )
Default configuration values.
const DefaultMaxResultChars = 50000
Default maximum result size in characters.
Variables ¶
var ( // ErrToolNotFound is returned when a model requests a tool that is not registered. ErrToolNotFound = errors.New("agentflow: tool not found") // ErrPermissionDenied is returned when a tool invocation is blocked by the permission checker. ErrPermissionDenied = errors.New("agentflow: permission denied") // ErrMaxTurnsExceeded is returned when the agentic loop exceeds the configured turn limit. ErrMaxTurnsExceeded = errors.New("agentflow: max turns exceeded") // ErrStreamClosed is returned when attempting to read from a closed stream. ErrStreamClosed = errors.New("agentflow: stream closed") // ErrInputValidation is returned when tool input fails schema validation. ErrInputValidation = errors.New("agentflow: input validation failed") // ErrHookBlocked is returned when a hook blocks tool execution or loop continuation. ErrHookBlocked = errors.New("agentflow: blocked by hook") ErrProviderUnavailable = errors.New("agentflow: provider unavailable") // ErrSessionNotFound is returned when a session ID does not exist in the store. ErrSessionNotFound = errors.New("agentflow: session not found") // ErrToolLoop is returned when the agent detects a repeated tool calling pattern. ErrToolLoop = errors.New("agentflow: tool calling loop detected") )
Sentinel errors returned by the framework.
Functions ¶
func FilterEvents ¶
FilterEvents returns a channel that only delivers events matching the specified types. The returned channel is closed when the input channel is closed.
for ev := range agentflow.FilterEvents(agent.Run(ctx, msgs), agentflow.EventTextDelta, agentflow.EventTurnEnd) {
// only text deltas and turn ends
}
func GenerateSessionID ¶
func GenerateSessionID() string
GenerateSessionID creates a cryptographically random session identifier.
func IsContextTooLargeError ¶
IsContextTooLargeError reports whether err indicates a context size overflow.
func IsHealthy ¶
IsHealthy checks if a provider is healthy. If the provider does not implement HealthChecker, it is assumed healthy.
func IsRetryableError ¶
IsRetryableError reports whether err is a retryable provider error.
func IsToolAllowed ¶
func IsToolAllowed(t Tool, mode ExecutionMode) bool
IsToolAllowed checks whether a tool is permitted in the given execution mode. In ModeLocal, all tools are allowed. In ModeRemote, only ToolRemoteSafe and ToolAny tools are permitted.
func SessionPreview ¶
SessionPreview extracts a preview string from the first user message.
Types ¶
type Agent ¶
type Agent struct {
// contains filtered or unexported fields
}
Agent orchestrates the agentic loop: model calls, tool execution, and message management. It is the primary entry point for consumers of the framework.
An Agent is immutable after construction — configuration is set via Option functions passed to NewAgent. The same Agent can be used for multiple concurrent Run calls, each with its own independent conversation state.
func NewAgent ¶
NewAgent creates an Agent with the given provider and options. The provider handles communication with the AI model, while options configure tools, hooks, permissions, and loop behavior.
agent := agentflow.NewAgent(provider,
agentflow.WithTools(searchTool, calcTool),
agentflow.WithSystemPrompt("You are helpful."),
agentflow.WithMaxTurns(10),
)
func (*Agent) AddHook ¶
AddHook appends a lifecycle hook to the agent. This is useful when hooks need to be added after initial construction (e.g., by extension packages).
func (*Agent) Clone ¶
Clone creates a copy of this agent with the same configuration, then applies the given options on top. Useful for deriving specialized agents from a common base without SubAgentConfig.
base := agentflow.NewAgent(provider, agentflow.WithMaxTurns(10))
researcher := base.Clone(agentflow.WithSystemPrompt("You are a researcher."))
writer := base.Clone(agentflow.WithSystemPrompt("You are a writer."))
func (*Agent) Resume ¶
func (a *Agent) Resume(ctx context.Context, sessionID string, additionalMessage string) (<-chan Event, error)
Resume loads a previously saved session and continues the conversation. The agent picks up where it left off, using the stored message history.
If additionalMessage is non-empty, it is appended as a new user message before the loop resumes.
for ev := range agent.Resume(ctx, "session-id-123", "Continue from where you left off") { ... }
func (*Agent) Run ¶
Run executes the agentic loop asynchronously. It returns a channel that delivers events as they occur: streaming text, tool invocations, progress updates, and completion signals. The channel is closed when the loop terminates.
Cancel the context to stop the loop gracefully. In-flight tool executions will receive the cancellation signal via their context.
for ev := range agent.Run(ctx, messages) {
switch ev.Type {
case agentflow.EventTextDelta:
fmt.Print(ev.TextDelta.Text)
case agentflow.EventTurnEnd:
fmt.Println("Done:", ev.TurnEnd.Reason)
}
}
func (*Agent) RunSession ¶
RunSession executes the agentic loop with automatic session persistence. The session is saved after each turn completes. If the session has an empty ID, one is generated automatically.
Use this instead of Run when you need crash recovery and conversation history.
session := &agentflow.Session{
Metadata: map[string]any{"user": "alice"},
}
for ev := range agent.RunSession(ctx, session, messages) { ... }
// session.ID is now set and can be used with Resume()
func (*Agent) RunSync ¶
RunSync is a convenience wrapper that collects all events and returns the final conversation history. Useful for non-streaming use cases or testing.
Returns the complete message history including all assistant and tool result messages generated during the loop. Returns an error if the loop terminated due to an unrecoverable error.
func (*Agent) SpawnChild ¶
SpawnChild creates and runs a child agent with the given configuration and task. The child runs in a new goroutine and returns an event channel, just like Run().
The child agent inherits unset fields from the parent. The task string becomes the initial user message for the child's conversation.
Cancel the context to stop the child and all its in-flight tool executions.
events := agent.SpawnChild(ctx, agentflow.SubAgentConfig{
SystemPrompt: "You are a research specialist.",
MaxTurns: 5,
}, "Find information about Go concurrency patterns")
for ev := range events {
// handle child events
}
func (*Agent) SpawnChildren ¶
SpawnChildren launches multiple child agents in parallel and merges their event streams into a single channel. Each child receives its own task string. Events are tagged with the child index via EventSubAgentStart/End events.
All children share the same context — canceling it stops all of them.
type BudgetWarningEvent ¶
type BudgetWarningEvent struct {
ConsumedTokens int // Total tokens consumed so far.
MaxTokens int // The configured budget limit.
Percentage float64 // Consumption as a fraction (0.0–1.0).
}
BudgetWarningEvent signals that token consumption crossed the configured threshold.
type CompactionEvent ¶
type CompactionEvent struct {
BeforeCount int // Message count before compaction.
AfterCount int // Message count after compaction.
TurnCount int
}
CompactionEvent signals that conversation history was compacted.
type Compactor ¶
type Compactor interface {
// ShouldCompact reports whether the current message history needs compaction.
// Called at the beginning of each agentic loop iteration before the model call.
ShouldCompact(messages []Message, usage *Usage) bool
// Compact reduces the message history to fit within context limits.
// Returns the compacted messages that replace the original history.
// The implementation may use summarization, truncation, or any other strategy.
Compact(ctx context.Context, messages []Message) ([]Message, error)
}
Compactor manages conversation history when the context window limit is approached. Implementations decide when compaction is needed and how to reduce the message history while preserving essential context.
type Config ¶
type Config struct {
// MaxTurns limits the number of agentic loop iterations. Each iteration
// consists of a model call and optional tool execution. Zero means unlimited.
MaxTurns int
// MaxConcurrency limits the number of tools executing in parallel within
// a single batch. Defaults to DefaultMaxConcurrency.
MaxConcurrency int
// SystemPrompt is prepended to the conversation as a system message.
SystemPrompt string
// Temperature controls the randomness of the model's output.
// nil uses the provider's default.
Temperature *float64
// MaxTokens limits the maximum tokens in the model's response.
// Zero uses the provider's default.
MaxTokens int
// RetryPolicy configures automatic retries for transient provider errors.
// nil means no retries.
RetryPolicy *RetryPolicy
// EventBufferSize is the capacity of the event channel returned by Agent.Run.
// Defaults to DefaultEventBufferSize.
EventBufferSize int
// OnEvent is an optional synchronous callback invoked for every event
// before it is sent to the channel. Use for lightweight processing that
// must see every event. Keep execution fast to avoid blocking the loop.
OnEvent func(Event)
// TokenBudget limits total token consumption across all turns.
// nil means no budget limit.
TokenBudget *TokenBudget
// ResultLimiter controls how oversized tool results are handled.
// Default: TruncateLimiter.
ResultLimiter ResultLimiter
// MaxResultChars is the maximum character count for a single tool result.
// Results exceeding this are passed through the ResultLimiter.
// Default: DefaultMaxResultChars (50000).
MaxResultChars int
// ExecutionMode controls which tools are visible to the model.
// ModeLocal (default) allows all tools. ModeRemote restricts to remote-safe only.
ExecutionMode ExecutionMode
// DisableInputValidation skips JSON Schema validation of tool inputs.
// Default: false (validation enabled). Set to true if tool schemas are
// informational only and should not block execution on mismatch.
DisableInputValidation bool
// RateLimiter controls the rate of provider API calls. When set, the agent
// waits for permission before each CreateStream call. nil means no rate limiting.
RateLimiter RateLimiter
// ToolRetries is the number of times to retry a failed tool execution before
// returning the error to the model. Zero means no retries (default). Only
// retries when the tool returns IsError: true.
ToolRetries int
// ToolTimeout sets a maximum duration for individual tool executions.
// If a tool does not complete within this duration, its context is cancelled
// and an error result is returned. Zero means no timeout (default).
ToolTimeout time.Duration
// ErrorStrategy controls how tool execution errors are handled. When set,
// it is called after a tool returns IsError: true, allowing error transformation
// or loop abortion. nil uses default behavior (send error to model as-is).
ErrorStrategy ErrorStrategy
// Logger enables structured logging for agent lifecycle events: model calls,
// retries, compaction, budget warnings, and validation errors. nil disables
// logging (zero overhead). Use log/slog for structured output.
Logger *slog.Logger
// ThinkingPrompt enables agentic thinking for non-native thinking models.
// When set, the first turn's text output is emitted as EventThinkingDelta
// instead of EventTextDelta. After the thinking turn completes, AnswerPrompt
// is injected as a user message to trigger the final answer turn.
// If the provider natively supports thinking (emits StreamEventThinkingDelta),
// this feature is automatically disabled for that request.
// Empty string means disabled (default).
ThinkingPrompt string
// AnswerPrompt is injected after the thinking turn to trigger the final answer.
// Only used when ThinkingPrompt is set.
AnswerPrompt string
// ProviderExtras carries provider-specific parameters merged into every
// request body. Examples: OpenRouter "plugins" for file parsing, Anthropic
// cache control. Each provider picks the keys it understands.
ProviderExtras map[string]any
}
Config controls Agent behavior. Fields are set via functional Option values passed to NewAgent. Zero values indicate defaults.
type ContentBlock ¶
type ContentBlock struct {
Type ContentBlockType `json:"type"`
// Text is set when Type == ContentText.
Text string `json:"text,omitempty"`
// ToolCall is set when Type == ContentToolCall.
ToolCall *ToolCall `json:"tool_call,omitempty"`
// ToolResult is set when Type == ContentToolResult.
ToolResult *ToolResultBlock `json:"tool_result,omitempty"`
// Image is set when Type == ContentImage.
Image *ImageContent `json:"image,omitempty"`
// Document is set when Type == ContentDocument.
Document *DocumentContent `json:"document,omitempty"`
}
ContentBlock is a discriminated union within a message. Exactly one of the typed fields is set, determined by the Type field.
type ContentBlockType ¶
type ContentBlockType int
ContentBlockType discriminates the variant within a ContentBlock.
const ( // ContentText represents a plain text content block. ContentText ContentBlockType = iota // ContentToolCall represents the model's request to invoke a tool. ContentToolCall // ContentToolResult represents the outcome of a tool execution sent back to the model. ContentToolResult // ContentImage represents an image content block (base64 or URL). ContentImage // ContentDocument represents a document/file content block (base64 or URL). // Supported by providers that accept file inputs (PDF, text, CSV, etc.). ContentDocument )
type ContentDelta ¶
type ContentDelta struct {
Text string
}
ContentDelta represents an incremental text chunk from the model's response.
type DocumentContent ¶
type DocumentContent struct {
// Filename is the original filename (e.g., "report.pdf").
Filename string `json:"filename"`
// MediaType is the MIME type (e.g., "application/pdf", "text/plain", "text/csv").
MediaType string `json:"media_type"`
// Data is the base64-encoded file content. Set this for inline documents.
Data string `json:"data,omitempty"`
// URL is a publicly accessible document URL. Set this for URL-referenced documents.
URL string `json:"url,omitempty"`
}
DocumentContent holds document data for file-based messages. Either Data (base64) or URL should be set, not both.
type ErrorAction ¶
type ErrorAction int
ErrorAction determines how the agent loop handles a tool error.
const ( // ErrorActionDefault sends the error to the model as-is (default behavior). ErrorActionDefault ErrorAction = iota // ErrorActionAbort terminates the agent loop immediately. ErrorActionAbort )
type ErrorEvent ¶
ErrorEvent carries a recoverable error from the agentic loop.
type ErrorStrategy ¶
type ErrorStrategy interface {
// OnToolError is called when a tool returns IsError: true. It receives the
// tool call and the error result, and returns a (possibly modified) result
// and an action.
OnToolError(call *ToolCall, result *ToolResult) (*ToolResult, ErrorAction)
}
ErrorStrategy controls how the agent handles tool execution errors. Implementations can transform error results, suppress them, or abort the loop.
type ErrorStrategyFunc ¶
type ErrorStrategyFunc func(call *ToolCall, result *ToolResult) (*ToolResult, ErrorAction)
ErrorStrategyFunc adapts a function to the ErrorStrategy interface.
func (ErrorStrategyFunc) OnToolError ¶
func (f ErrorStrategyFunc) OnToolError(call *ToolCall, result *ToolResult) (*ToolResult, ErrorAction)
OnToolError delegates to the wrapped function.
type Event ¶
type Event struct {
Type EventType
TextDelta *TextDeltaEvent // Type == EventTextDelta
ThinkDelta *TextDeltaEvent // Type == EventThinkingDelta
ToolStart *ToolStartEvent // Type == EventToolStart
ToolProgress *ProgressEvent // Type == EventToolProgress
ToolEnd *ToolEndEvent // Type == EventToolEnd
TurnStart *TurnStartEvent // Type == EventTurnStart
TurnEnd *TurnEndEvent // Type == EventTurnEnd
Message *Message // Type == EventMessage
Error *ErrorEvent // Type == EventError
Usage *UsageEvent // Type == EventUsage
SubAgentStart *SubAgentStartEvent // Type == EventSubAgentStart
SubAgentEnd *SubAgentEndEvent // Type == EventSubAgentEnd
BudgetWarning *BudgetWarningEvent // Type == EventBudgetWarning
Compaction *CompactionEvent // Type == EventCompaction
Retry *RetryEvent // Type == EventRetry
PermissionDenied *PermissionDeniedEvent // Type == EventPermissionDenied
HookBlocked *HookBlockedEvent // Type == EventHookBlocked
// SubAgentIndex identifies which child agent emitted this event.
// Zero for the parent agent's own events. Set by SpawnChildren.
SubAgentIndex int
}
Event is the primary output type of the agentic loop. It is a discriminated union where exactly one of the typed fields is set, determined by the Type field.
Events are delivered through the channel returned by Agent.Run. Consumers switch on Type to handle each variant.
type EventType ¶
type EventType int
EventType discriminates the variant within an Event.
const ( // EventTextDelta carries streaming text from the model's response. EventTextDelta EventType = iota // EventThinkingDelta carries streaming thinking/reasoning content from the model. EventThinkingDelta // EventToolStart signals that a tool execution is beginning. EventToolStart // EventToolProgress carries incremental progress from a running tool. EventToolProgress // EventToolEnd signals that a tool execution has completed. EventToolEnd // EventTurnStart signals the beginning of a new agentic loop iteration. EventTurnStart // EventTurnEnd signals the end of a loop iteration, or the loop itself. EventTurnEnd // EventMessage carries a complete message added to the conversation history. EventMessage // EventError carries a recoverable error (e.g., a retry is in progress). EventError // EventUsage carries token usage statistics for the current turn. EventUsage // EventSubAgentStart signals that a sub-agent has been spawned. EventSubAgentStart // EventSubAgentEnd signals that a sub-agent has completed. EventSubAgentEnd // EventBudgetWarning signals that token consumption crossed the warning threshold. EventBudgetWarning // EventCompaction signals that conversation history was compacted. EventCompaction // EventRetry signals that a provider call is being retried after a transient error. EventRetry // EventPermissionDenied signals that a tool call was blocked by the permission checker. EventPermissionDenied // EventHookBlocked signals that a hook blocked tool execution or the model call. EventHookBlocked )
type ExecutionMode ¶
type ExecutionMode int
ExecutionMode determines which environment the agent is running in. This controls which tools are visible to the model.
const ( // ModeLocal allows all tools. Use when the agent runs on the user's machine // where filesystem and shell access are expected. ModeLocal ExecutionMode = iota // ModeRemote restricts tools to only those marked as remote-safe. // Use when the agent runs on a server where local filesystem/shell access // is inappropriate or dangerous. The model only sees remote-safe tools — // it cannot call tools it doesn't know about. ModeRemote )
type HeadTailLimiter ¶
type HeadTailLimiter struct {
// HeadRatio is the fraction of maxChars allocated to the head (0.0–1.0).
// Default: 0.7 (70% head, 30% tail).
HeadRatio float64
}
HeadTailLimiter keeps only the first N and last M characters, discarding the middle. Simpler than TruncateLimiter with configurable head/tail ratio.
func (HeadTailLimiter) Limit ¶
func (l HeadTailLimiter) Limit(result *ToolResult, maxChars int) *ToolResult
Limit applies head/tail truncation.
type HealthChecker ¶
type HealthChecker interface {
// HealthCheck tests whether the provider is reachable and operational.
// Returns nil if healthy, or an error describing the failure.
HealthCheck(ctx context.Context) error
}
HealthChecker is an optional interface that providers can implement to support proactive health checking. Use with fallback providers to detect unhealthy backends before they cause request failures.
type Hook ¶
type Hook interface {
// Phase returns when this hook should fire.
Phase() HookPhase
// Execute runs the hook logic. Returning a non-nil HookAction modifies
// the pipeline behavior (block execution, modify input, inject messages).
// Return nil action to proceed without modification.
Execute(ctx context.Context, hc *HookContext) (*HookAction, error)
}
Hook intercepts the agent execution pipeline at defined lifecycle phases. Hooks execute synchronously in registration order. Keep hook execution fast to avoid blocking the agentic loop.
type HookAction ¶
type HookAction struct {
// Block, if true, prevents the current operation from proceeding.
// For PreToolUse: the tool is not executed; BlockReason is sent to the model.
// For PreModelCall: the model call is skipped; the loop terminates.
Block bool
BlockReason string
// ModifiedInput, if non-nil, replaces the tool's input before execution.
// Only effective for PreToolUse hooks.
ModifiedInput json.RawMessage
// InjectMessages appends additional messages to the conversation before
// the next model call. Effective for PostToolUse and OnTurnEnd hooks.
InjectMessages []Message
}
HookAction tells the execution pipeline how to proceed after a hook fires. All fields are optional; a nil HookAction means "continue normally."
type HookBlockedEvent ¶
type HookBlockedEvent struct {
Phase HookPhase
ToolCall *ToolCall // Non-nil for PreToolUse blocks.
Reason string
TurnCount int
}
HookBlockedEvent signals that a hook blocked execution.
type HookContext ¶
type HookContext struct {
// Phase indicates which lifecycle phase triggered this hook.
Phase HookPhase
// ToolCall is set for tool-phase hooks (PreToolUse, PostToolUse).
ToolCall *ToolCall
// ToolResult is set for PostToolUse hooks.
ToolResult *ToolResult
// Messages is the current conversation history at the time the hook fires.
Messages []Message
// TurnCount is the current iteration number of the agentic loop.
TurnCount int
// Metadata is a mutable key-value bag that persists across hooks within a
// single agent run. Hooks can use it to communicate state to each other.
Metadata map[string]any
}
HookContext provides read access to the current execution state when a hook fires.
type HookFunc ¶
type HookFunc struct {
HookPhase HookPhase
Fn func(ctx context.Context, hc *HookContext) (*HookAction, error)
}
HookFunc is an adapter that allows ordinary functions to be used as hooks. It pairs a phase with a function, eliminating the need for a struct that implements the Hook interface for simple cases.
func (HookFunc) Execute ¶
func (h HookFunc) Execute(ctx context.Context, hc *HookContext) (*HookAction, error)
Execute delegates to the wrapped function.
type HookPhase ¶
type HookPhase int
HookPhase defines when a hook fires in the execution pipeline.
const ( // HookPreToolUse fires after input validation, before permission check. // Can block execution or modify input. HookPreToolUse HookPhase = iota // HookPostToolUse fires after tool execution completes. // Can inspect results, log metrics, or inject follow-up messages. HookPostToolUse // HookPreModelCall fires before each model API call. // Can modify messages, inject system context, or block the call. HookPreModelCall // HookPostModelCall fires after the model response is fully received. // Can inspect the response, log usage, or trigger side effects. HookPostModelCall // HookOnTurnEnd fires when the agentic loop would normally terminate // (no more tool calls). Can inject messages to force continuation. HookOnTurnEnd )
type ImageContent ¶
type ImageContent struct {
// MediaType is the MIME type (e.g., "image/png", "image/jpeg", "image/webp", "image/gif").
MediaType string `json:"media_type"`
// Data is the base64-encoded image data. Set this for inline images.
Data string `json:"data,omitempty"`
// URL is a publicly accessible image URL. Set this for URL-referenced images.
URL string `json:"url,omitempty"`
}
ImageContent holds image data for multimodal messages. Either Data (base64) or URL should be set, not both.
type LocalityAware ¶
type LocalityAware interface {
Locality() ToolLocality
}
LocalityAware is an optional interface that tools can implement to declare their execution environment compatibility. Tools that do not implement this interface are treated as ToolLocalOnly — the safe default that prevents accidental remote execution of local-only tools.
type Message ¶
type Message struct {
Role Role `json:"role"`
Content []ContentBlock `json:"content"`
}
Message is a single entry in the conversation history. Each message has a role and one or more content blocks that can be text, tool calls, or tool results.
func NewAssistantMessage ¶
NewAssistantMessage creates a Message with a single text content block from the assistant.
func NewDocumentMessage ¶
func NewDocumentMessage(text string, docs ...DocumentContent) Message
NewDocumentMessage creates a user Message with text and one or more documents. Use for requests where you want the model to analyze uploaded files.
msg := agentflow.NewDocumentMessage("Summarize this PDF",
agentflow.DocumentContent{Filename: "report.pdf", MediaType: "application/pdf", Data: base64Data},
)
func NewImageMessage ¶
func NewImageMessage(text string, images ...ImageContent) Message
NewImageMessage creates a user Message with text and one or more images. Use for vision/multimodal requests where you want the model to analyze images.
msg := agentflow.NewImageMessage("What's in this image?",
agentflow.ImageContent{MediaType: "image/png", Data: base64Data},
)
func NewImageURLMessage ¶
NewImageURLMessage is a convenience for creating an image message from a URL.
func NewUserMessage ¶
NewUserMessage creates a Message with a single text content block from the user.
func (Message) Documents ¶
func (m Message) Documents() []DocumentContent
Documents extracts all document content blocks from the message.
func (Message) Images ¶
func (m Message) Images() []ImageContent
Images extracts all image content blocks from the message.
func (Message) TextContent ¶
TextContent extracts and concatenates all text blocks from the message.
func (Message) ToolResults ¶
func (m Message) ToolResults() []ToolResultBlock
ToolResults extracts all tool result blocks from the message.
type MultiPhaseHook ¶
type MultiPhaseHook interface {
// Phases returns all phases this hook should fire at.
Phases() []HookPhase
// Execute runs the hook logic for the given phase.
Execute(ctx context.Context, hc *HookContext) (*HookAction, error)
}
MultiPhaseHook is an optional interface for hooks that fire at multiple phases. Hooks implementing this interface have their Execute called for each phase returned by Phases(), eliminating the need to register duplicate hooks.
type NoLimiter ¶
type NoLimiter struct{}
NoLimiter passes all results through without modification. Use when you handle result sizing externally or don't need protection.
func (NoLimiter) Limit ¶
func (NoLimiter) Limit(result *ToolResult, _ int) *ToolResult
Limit returns the result unchanged.
type Option ¶
type Option func(*Agent)
Option is a functional option for configuring an Agent.
func WithCompactor ¶
WithCompactor sets the context compaction strategy.
func WithDisableInputValidation ¶
func WithDisableInputValidation() Option
WithDisableInputValidation disables JSON Schema validation of tool inputs. Use this if tool schemas are informational only or if validation causes false positives with a particular model's output format.
func WithErrorStrategy ¶
func WithErrorStrategy(s ErrorStrategy) Option
WithErrorStrategy sets a custom error handling strategy for tool failures. The strategy can transform error results or abort the loop entirely.
agent := agentflow.NewAgent(provider,
agentflow.WithErrorStrategy(agentflow.ErrorStrategyFunc(
func(call *agentflow.ToolCall, result *agentflow.ToolResult) (*agentflow.ToolResult, agentflow.ErrorAction) {
if call.Name == "critical_tool" {
return result, agentflow.ErrorActionAbort
}
return result, agentflow.ErrorActionDefault
},
)),
)
func WithEventBufferSize ¶
WithEventBufferSize sets the capacity of the event channel.
func WithExecutionMode ¶
func WithExecutionMode(mode ExecutionMode) Option
WithExecutionMode sets the execution environment mode. ModeRemote restricts the agent to only remote-safe tools — local-only tools are completely hidden from the model. ModeLocal (default) allows all registered tools.
// Server deployment — only web search and HTTP tools are available:
agent := agentflow.NewAgent(provider,
agentflow.WithTools(builtin.All()...),
agentflow.WithExecutionMode(agentflow.ModeRemote),
)
func WithLogger ¶
WithLogger enables structured logging for agent lifecycle events. The logger receives log entries for model calls, retries, compaction, budget warnings, and input validation errors. nil disables logging.
agent := agentflow.NewAgent(provider,
agentflow.WithLogger(slog.Default()),
)
func WithMaxConcurrency ¶
WithMaxConcurrency sets the maximum number of parallel tool executions.
func WithMaxResultSize ¶
WithMaxResultSize sets the maximum characters for a single tool result. Results exceeding this are passed through the configured ResultLimiter.
func WithMaxTokens ¶
WithMaxTokens sets the maximum tokens in the model's response.
func WithMaxTurns ¶
WithMaxTurns sets the maximum number of agentic loop iterations.
func WithOnEvent ¶
WithOnEvent sets a synchronous event callback. The callback is invoked for every event before it is sent to the channel. Keep execution fast.
func WithPermission ¶
func WithPermission(p PermissionChecker) Option
WithPermission sets the permission checker for tool invocations. Only one permission checker is active; the last one set wins. Use ChainPermission to compose multiple checkers.
func WithProviderExtras ¶
WithProviderExtras sets provider-specific parameters that are merged into every request body. Each provider picks the keys it understands and ignores the rest. This enables provider-specific features without breaking the provider-agnostic API.
Example: OpenRouter file-parser plugin for PDF support:
agent := agentflow.NewAgent(provider,
agentflow.WithProviderExtras(map[string]any{
"plugins": []map[string]any{
{"id": "file-parser", "pdf": map[string]any{"engine": "native"}},
},
}),
)
func WithRateLimiter ¶
func WithRateLimiter(limiter RateLimiter) Option
WithRateLimiter sets a rate limiter for provider API calls. The agent will call limiter.Wait() before each model request, blocking if the rate limit is exceeded.
agent := agentflow.NewAgent(provider,
agentflow.WithRateLimiter(agentflow.NewTokenBucketLimiter(10, time.Second)),
)
func WithResultLimiter ¶
func WithResultLimiter(limiter ResultLimiter) Option
WithResultLimiter sets a custom result limiter for oversized tool outputs.
func WithRetryPolicy ¶
func WithRetryPolicy(p RetryPolicy) Option
WithRetryPolicy configures automatic retries for transient provider errors.
func WithSessionStore ¶
func WithSessionStore(store SessionStore) Option
WithSessionStore enables session persistence. When set, RunSession and Resume methods become available for saving and restoring conversation state.
func WithSystemPrompt ¶
WithSystemPrompt sets the system prompt prepended to every model call.
func WithTemperature ¶
WithTemperature sets the model's temperature parameter.
func WithThinkingPrompt ¶
WithThinkingPrompt enables agentic thinking for non-native thinking models. The first turn emits all model output as EventThinkingDelta (not EventTextDelta). After the thinking turn, answerPrompt is injected as a user message and the model generates a normal response emitted as EventTextDelta.
If the provider natively supports thinking (emits StreamEventThinkingDelta), this feature is automatically disabled — native thinking takes precedence.
agent := agentflow.NewAgent(provider,
agentflow.WithThinkingPrompt(
"Analyze this step by step. Do not provide a final answer yet.",
"Now provide a clear and concise final answer.",
),
)
func WithTokenBudget ¶
func WithTokenBudget(budget TokenBudget) Option
WithTokenBudget sets a token consumption limit for the agent run. The loop terminates with TurnEndBudgetExhausted when the budget is exceeded.
agent := agentflow.NewAgent(provider,
agentflow.WithTokenBudget(agentflow.TokenBudget{
MaxTokens: 100000,
WarningThreshold: 0.8,
}),
)
func WithToolRetries ¶
WithToolRetries sets the number of retry attempts for failed tool executions. Only retries when a tool returns IsError: true. Zero (default) means no retries.
agent := agentflow.NewAgent(provider,
agentflow.WithToolRetries(2), // retry up to 2 times on error
)
func WithToolTimeout ¶
WithToolTimeout sets a maximum duration for individual tool executions. Tools that exceed this duration have their context cancelled and receive an error result. Zero (default) means no timeout.
agent := agentflow.NewAgent(provider,
agentflow.WithToolTimeout(30 * time.Second),
)
type OrchestrateResult ¶
OrchestrateResult holds the outcome of a single sub-agent task.
func Orchestrate ¶
func Orchestrate(ctx context.Context, parent *Agent, cfg SubAgentConfig, tasks []string) []OrchestrateResult
Orchestrate runs multiple tasks in parallel using sub-agents and collects results. This is a high-level utility for common fan-out/fan-in patterns.
results := agentflow.Orchestrate(ctx, agent, agentflow.SubAgentConfig{
SystemPrompt: "You are a research assistant.",
MaxTurns: 5,
}, []string{
"Research Go concurrency patterns",
"Research Go error handling best practices",
"Research Go testing strategies",
})
for _, r := range results {
fmt.Println(r.Task, "→", r.Result)
}
func (OrchestrateResult) String ¶
func (r OrchestrateResult) String() string
type PermissionChecker ¶
type PermissionChecker interface {
// Check returns the permission decision for a tool invocation. The checker
// receives both the call details and the tool definition, enabling fine-grained
// decisions based on the specific input.
Check(ctx context.Context, call *ToolCall, tool Tool) (PermissionResult, error)
}
PermissionChecker controls whether a tool is allowed to execute for a given invocation. Implementations can be static rule-based, interactive, or policy-driven.
func AllowAll ¶
func AllowAll() PermissionChecker
AllowAll returns a PermissionChecker that permits every tool invocation. Use in trusted environments where all tools are safe to execute.
func AllowList ¶
func AllowList(names ...string) PermissionChecker
AllowList returns a PermissionChecker that allows only tools whose names appear in the provided list. All other tools are denied.
func ChainPermission ¶
func ChainPermission(checkers ...PermissionChecker) PermissionChecker
ChainPermission evaluates multiple checkers in order. The first non-Allow result wins. If all checkers return Allow, the final result is Allow. An empty chain allows everything.
func DenyAll ¶
func DenyAll() PermissionChecker
DenyAll returns a PermissionChecker that blocks every tool invocation.
func DenyList ¶
func DenyList(names ...string) PermissionChecker
DenyList returns a PermissionChecker that denies tools whose names appear in the provided list. All other tools are allowed.
func ReadOnlyPermission ¶
func ReadOnlyPermission() PermissionChecker
ReadOnlyPermission returns a PermissionChecker that allows only tools where IsReadOnly returns true for the given input. Write operations are denied.
type PermissionDeniedEvent ¶
type PermissionDeniedEvent struct {
ToolCall ToolCall
}
PermissionDeniedEvent signals that a tool call was blocked by permissions.
type PermissionFunc ¶
PermissionFunc is an adapter that allows ordinary functions to be used as permission checkers, similar to http.HandlerFunc.
func (PermissionFunc) Check ¶
func (f PermissionFunc) Check(ctx context.Context, call *ToolCall, tool Tool) (PermissionResult, error)
Check delegates to the wrapped function.
type PermissionResult ¶
type PermissionResult int
PermissionResult is the outcome of a permission check.
const ( // PermissionAllow permits the tool execution to proceed. PermissionAllow PermissionResult = iota // PermissionDeny blocks the tool execution. The model receives an error // message indicating the tool was denied. PermissionDeny // PermissionAsk indicates an external decision is needed (e.g., prompting // the user). The framework calls the AskFunc configured on the Agent. PermissionAsk )
type ProgressEvent ¶
type ProgressEvent struct {
// ToolCallID identifies which tool invocation this progress belongs to.
// Set automatically by the executor; tools do not need to set this.
ToolCallID string
// Message is a human-readable progress description.
Message string
// Data carries tool-specific structured progress information.
Data any
}
ProgressEvent describes incremental progress from a tool execution.
type ProgressFunc ¶
type ProgressFunc func(ProgressEvent)
ProgressFunc is called by tools to report incremental progress during execution. Progress events are forwarded to the agent's event stream in real time.
type Provider ¶
type Provider interface {
// CreateStream initiates a streaming model call and returns a Stream that
// yields events as they arrive from the API. The caller must consume the
// stream to completion or cancel via context.
//
// The Request contains provider-agnostic fields (messages, tools, parameters).
// Implementations convert these into vendor-specific API formats.
CreateStream(ctx context.Context, req *Request) (Stream, error)
// ModelID returns the identifier of the model this provider targets
// (e.g., "anthropic/claude-sonnet-4-20250514", "openai/gpt-4o").
ModelID() string
}
Provider abstracts an AI model API that supports tool use (function calling). Implementations handle authentication, request formatting, and response parsing specific to each vendor (Anthropic, OpenAI, OpenRouter, etc.).
The interface operates at the stream level rather than request/response level, enabling real-time event delivery to consumers.
type ProviderError ¶
type ProviderError struct {
StatusCode int
Message string
Retryable bool
Err error
ResponseHeaders http.Header
}
ProviderError wraps an error from the AI provider with status and retry information.
func (*ProviderError) Error ¶
func (e *ProviderError) Error() string
func (*ProviderError) IsContextTooLarge ¶
func (e *ProviderError) IsContextTooLarge() bool
IsContextTooLarge reports whether the error indicates the request context exceeds the model's maximum token limit.
func (*ProviderError) IsRetryable ¶
func (e *ProviderError) IsRetryable() bool
IsRetryable reports whether the error is transient and the operation can be retried. Checks multiple signals following the pattern used by production AI SDKs:
- io.ErrUnexpectedEOF (stream ended unexpectedly)
- x-should-retry response header
- HTTP status codes: 408, 409, 429, 5xx
func (*ProviderError) Unwrap ¶
func (e *ProviderError) Unwrap() error
type RateLimiter ¶
type RateLimiter interface {
// Wait blocks until the caller is allowed to proceed. Returns an error
// if the context is cancelled or the limiter is otherwise unable to grant
// permission.
Wait(ctx context.Context) error
}
RateLimiter controls the rate of API calls to a provider. Implementations block until the caller is permitted to proceed, or return an error if the context is cancelled while waiting.
type Request ¶
type Request struct {
// Messages is the conversation history including user messages, assistant
// responses, and tool results from previous iterations.
Messages []Message
// SystemPrompt is an optional system-level instruction prepended to the conversation.
SystemPrompt string
// Tools is the list of tool definitions available to the model for this request.
Tools []ToolDefinition
// MaxTokens limits the maximum number of tokens in the model's response.
MaxTokens int
// Temperature controls the randomness of the model's output.
// nil means the provider's default is used.
Temperature *float64
// StopSequences are optional strings that cause the model to stop generating
// when encountered. Support varies by provider.
StopSequences []string
// Metadata carries key-value pairs that providers may propagate as HTTP
// headers. Use this for trace context propagation (e.g., "traceparent",
// "tracestate") or custom request tagging. Providers add these as headers
// prefixed with nothing — keys map directly to header names.
Metadata map[string]string
// ProviderExtras carries provider-specific parameters that are merged into
// the request body. Examples: OpenRouter "plugins" for file parsing,
// Anthropic cache control, Gemini safety settings. Each provider picks
// the keys it understands and ignores the rest.
ProviderExtras map[string]any
}
Request is the provider-agnostic model request built by the agentic loop.
type ResultLimiter ¶
type ResultLimiter interface {
// Limit inspects a tool result and returns a potentially modified version.
// If the result is within acceptable bounds, it is returned unchanged.
// maxChars is the configured maximum character count.
Limit(result *ToolResult, maxChars int) *ToolResult
}
ResultLimiter controls how oversized tool results are handled before being sent back to the model. Large results can exhaust the context window and degrade model performance.
type RetryEvent ¶
type RetryEvent struct {
Attempt int // Current retry attempt (1-based).
Delay time.Duration // Delay before this retry.
Err error // The error that triggered the retry.
TurnCount int
}
RetryEvent signals that a provider call is being retried.
type RetryPolicy ¶
type RetryPolicy struct {
// MaxRetries is the maximum number of retry attempts. Zero means no retries.
MaxRetries int
// BaseDelay is the initial delay before the first retry.
// Subsequent retries use exponential backoff: BaseDelay * 2^attempt.
BaseDelay time.Duration
// MaxDelay caps the maximum delay between retries.
MaxDelay time.Duration
}
RetryPolicy configures automatic retries for transient errors.
type Session ¶
type Session struct {
// ID uniquely identifies this session. Generated automatically if empty.
ID string `json:"id"`
// Messages is the full conversation history at the time of save.
Messages []Message `json:"messages"`
// Metadata is an arbitrary key-value bag for application-specific data
// (user ID, task description, tags, etc.).
Metadata map[string]any `json:"metadata,omitempty"`
// CreatedAt is when the session was first created.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is when the session was last saved.
UpdatedAt time.Time `json:"updated_at"`
// ModelID records which model was used, for reference when resuming.
ModelID string `json:"model_id,omitempty"`
// TurnCount records how many turns were completed before saving.
TurnCount int `json:"turn_count"`
}
Session holds the complete state needed to resume an agent conversation.
type SessionInfo ¶
type SessionInfo struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ModelID string `json:"model_id,omitempty"`
TurnCount int `json:"turn_count"`
Metadata map[string]any `json:"metadata,omitempty"`
// Preview is the first user message text, truncated for display.
Preview string `json:"preview,omitempty"`
}
SessionInfo is a lightweight summary returned by SessionStore.List.
type SessionStore ¶
type SessionStore interface {
// Save persists the current conversation state. If a session with the given
// ID already exists, it is overwritten.
Save(ctx context.Context, session *Session) error
// Load retrieves a previously saved session by ID. Returns ErrSessionNotFound
// if the session does not exist.
Load(ctx context.Context, id string) (*Session, error)
// List returns metadata for all stored sessions, ordered by last update time
// (most recent first).
List(ctx context.Context) ([]SessionInfo, error)
// Delete removes a session by ID. Returns nil if the session does not exist.
Delete(ctx context.Context, id string) error
}
SessionStore persists conversation state so agents can survive restarts, resume interrupted work, and maintain history across multiple invocations.
Implementations must be safe for concurrent use from multiple goroutines.
type Stream ¶
type Stream interface {
// Next blocks until the next event is available. Returns io.EOF when the
// stream is complete. Any other error indicates a failure in the stream.
Next() (StreamEvent, error)
// Close releases resources associated with the stream. Safe to call
// multiple times. Must be called even if Next returned an error.
Close() error
// Usage returns token usage statistics after the stream completes.
// Returns nil if the stream has not finished or the provider does not
// report usage information.
Usage() *Usage
}
Stream yields events from a model response. The caller reads events sequentially via Next() until io.EOF signals completion. The stream must be closed when done, even after encountering an error.
Implementations must be safe to consume from a single goroutine. The StreamEvent returned by Next is only valid until the next call to Next.
type StreamEvent ¶
type StreamEvent struct {
Type StreamEventType
// Delta is set when Type == StreamEventDelta.
Delta *ContentDelta
// ThinkingDelta is set when Type == StreamEventThinkingDelta.
ThinkingDelta *ContentDelta
// ToolCall is set when Type == StreamEventToolCall.
ToolCall *ToolCall
// Error is set when Type == StreamEventError.
Error error
// Usage is set when Type == StreamEventUsage.
Usage *Usage
}
StreamEvent is a discriminated union of events from a model stream. Exactly one of the typed fields is set, determined by the Type field.
type StreamEventType ¶
type StreamEventType int
StreamEventType discriminates the variant within a StreamEvent.
const ( // StreamEventDelta carries a text content delta from the model. StreamEventDelta StreamEventType = iota // StreamEventToolCall carries a complete tool invocation from the model. StreamEventToolCall // StreamEventError carries a non-fatal error from the stream. StreamEventError // StreamEventDone signals that the stream has completed normally. StreamEventDone // StreamEventUsage carries token usage information, typically at stream end. StreamEventUsage // StreamEventThinkingDelta carries a thinking/reasoning content delta. StreamEventThinkingDelta )
type SubAgentConfig ¶
type SubAgentConfig struct {
// Provider overrides the parent's provider. nil inherits the parent's.
Provider Provider
// Tools overrides the parent's tool set. nil inherits the parent's tools.
// Use an empty slice to spawn a child with no tools.
Tools []Tool
// SystemPrompt overrides the parent's system prompt for the child.
SystemPrompt string
// MaxTurns limits the child's loop iterations. Zero inherits the parent's.
MaxTurns int
// MaxTokens overrides the response token limit. Zero inherits.
MaxTokens int
// MaxConcurrency overrides parallel tool execution limit. Zero inherits.
MaxConcurrency int
// Hooks are additional hooks for the child. Parent hooks are NOT inherited
// to keep child execution isolated.
Hooks []Hook
// Permission overrides the parent's permission checker. nil inherits.
Permission PermissionChecker
}
SubAgentConfig configures a child agent spawned by a parent. Fields left at zero values inherit from the parent agent.
type SubAgentEndEvent ¶
type SubAgentEndEvent struct {
Index int // Child index matching SubAgentStartEvent.
Task string // The original task.
Result string // The sub-agent's final text response.
}
SubAgentEndEvent signals that a sub-agent has completed its work.
type SubAgentStartEvent ¶
type SubAgentStartEvent struct {
Index int // Child index (0-based) within SpawnChildren.
Task string // The task delegated to the sub-agent.
}
SubAgentStartEvent signals that a sub-agent has been spawned.
type TextDeltaEvent ¶
type TextDeltaEvent struct {
Text string
}
TextDeltaEvent carries an incremental text chunk from the model.
type TimeoutAware ¶
TimeoutAware is an optional interface that tools can implement to declare their own execution timeout. When implemented and the returned duration is positive, this timeout takes precedence over the global WithToolTimeout configuration. Tools that do not implement this interface use the global timeout.
type TokenBucketLimiter ¶
type TokenBucketLimiter struct {
// contains filtered or unexported fields
}
TokenBucketLimiter implements a token bucket rate limiting algorithm. It allows bursts up to the bucket capacity and refills tokens at a steady rate.
limiter := agentflow.NewTokenBucketLimiter(10, time.Second) // 10 requests/sec
agent := agentflow.NewAgent(provider,
agentflow.WithRateLimiter(limiter),
)
func NewTokenBucketLimiter ¶
func NewTokenBucketLimiter(capacity int, interval time.Duration) *TokenBucketLimiter
NewTokenBucketLimiter creates a rate limiter that allows up to capacity requests per interval. The bucket starts full, allowing an initial burst.
NewTokenBucketLimiter(5, time.Second) // 5 req/sec, burst of 5 NewTokenBucketLimiter(60, time.Minute) // 60 req/min, burst of 60 NewTokenBucketLimiter(1, 200*time.Millisecond) // 5 req/sec, no burst
type TokenBudget ¶
type TokenBudget struct {
// MaxTokens is the total token limit for the entire agent run.
// Includes both prompt and completion tokens across all turns.
MaxTokens int
// WarningThreshold is the fraction (0.0–1.0) at which a budget warning
// event is emitted. For example, 0.8 means warn at 80% consumption.
// Zero disables the warning. Values above 1.0 are clamped to 1.0.
WarningThreshold float64
}
TokenBudget controls the maximum token consumption for a single agent run. When the budget is exhausted, the agentic loop terminates gracefully with TurnEndBudgetExhausted. A warning event is emitted when the threshold is crossed.
type Tool ¶
type Tool interface {
// Name returns the unique identifier for this tool. Must be alphanumeric
// with underscores, matching the pattern [a-zA-Z_][a-zA-Z0-9_]*.
Name() string
// Description returns a human-readable description sent to the model.
// A clear, specific description significantly improves tool selection accuracy.
Description() string
// InputSchema returns the JSON Schema object describing the tool's input parameters.
// This schema is sent to the model and used for input validation before execution.
InputSchema() map[string]any
// Execute runs the tool with the given validated input. The context carries
// cancellation signals from the agent loop. Implementations should respect
// context cancellation for long-running operations.
//
// The progress function, if non-nil, can be called to report incremental
// progress updates that are forwarded to the event stream.
Execute(ctx context.Context, input json.RawMessage, progress ProgressFunc) (*ToolResult, error)
// IsConcurrencySafe reports whether this tool can safely execute in parallel
// with other concurrency-safe tools given the specific input. Read-only tools
// should return true. Tools that mutate shared state should return false.
IsConcurrencySafe(input json.RawMessage) bool
// IsReadOnly reports whether the tool performs only read operations for the
// given input. Used by permission checkers to make access control decisions.
IsReadOnly(input json.RawMessage) bool
}
Tool defines a capability that an agent can invoke. Tools are registered with an Agent and presented to the AI model as callable functions. The model decides when and how to invoke tools based on their name, description, and input schema.
Implementations must be safe for concurrent use if IsConcurrencySafe returns true.
func SubAgentTool ¶
SubAgentTool creates a Tool that allows the AI model to spawn sub-agents. When the model calls this tool, a child agent is created to handle the delegated task, and its final response is returned as the tool result.
agent := agentflow.NewAgent(provider,
agentflow.WithTools(
agentflow.SubAgentTool(provider, "You are a researcher.", 5),
),
)
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"`
Name string `json:"name"`
Input json.RawMessage `json:"input"`
}
ToolCall represents the model's request to invoke a tool. The ID is generated by the provider and must be referenced in the corresponding ToolResultBlock.
type ToolDefinition ¶
type ToolDefinition struct {
Name string `json:"name"`
Description string `json:"description"`
InputSchema map[string]any `json:"input_schema"`
}
ToolDefinition is the serializable schema sent to the AI provider. It describes a tool's interface so the model knows how to invoke it.
type ToolEndEvent ¶
type ToolEndEvent struct {
ToolCall ToolCall
Result ToolResult
Duration time.Duration
}
ToolEndEvent signals that a tool invocation has completed.
type ToolLocality ¶
type ToolLocality int
ToolLocality declares which execution environments a tool supports.
const ( // ToolLocalOnly means the tool requires local machine access (filesystem, // shell, local processes). Blocked in ModeRemote. ToolLocalOnly ToolLocality = iota // ToolRemoteSafe means the tool is safe for server execution. It does not // access the local filesystem or run local commands. Allowed in both modes. ToolRemoteSafe // ToolAny means the tool has no environment dependency. It works identically // in both local and remote modes (e.g., sleep, pure computation). ToolAny )
type ToolResult ¶
type ToolResult struct {
// Content is the textual result sent to the model. For successful operations,
// this contains the output data. For failures, this contains the error description.
Content string
// IsError indicates the tool execution failed. The model receives Content as
// an error message and can adapt its approach (retry, use a different tool, etc.).
IsError bool
// Metadata is not sent to the model but is included in ToolEndEvent for
// observability. Use it for execution metrics, debug data, or audit information.
Metadata map[string]any
}
ToolResult is the outcome of a tool execution. The Content field is sent back to the model, while Metadata is included only in events for observability.
type ToolResultBlock ¶
type ToolResultBlock struct {
ToolCallID string `json:"tool_use_id"`
Content string `json:"content"`
IsError bool `json:"is_error,omitempty"`
}
ToolResultBlock is the content block sent back to the model after tool execution. It references the original ToolCall by ID so the model can correlate results.
type ToolStartEvent ¶
type ToolStartEvent struct {
ToolCall ToolCall
}
ToolStartEvent signals that a tool invocation is about to execute.
type TruncateLimiter ¶
type TruncateLimiter struct{}
TruncateLimiter truncates oversized results with a notice showing how much content was omitted. The truncation preserves the beginning and end of the content for maximum context.
func (TruncateLimiter) Limit ¶
func (TruncateLimiter) Limit(result *ToolResult, maxChars int) *ToolResult
Limit truncates the result content if it exceeds maxChars. It preserves the first 80% and last 20% of the allowed size, inserting a truncation notice in the middle.
type TurnEndEvent ¶
type TurnEndEvent struct {
TurnNumber int
Reason TurnEndReason
Messages []Message // Final conversation history at loop termination.
}
TurnEndEvent signals the end of an iteration or the entire loop.
type TurnEndReason ¶
type TurnEndReason string
TurnEndReason describes why the agentic loop iteration or the loop itself ended.
const ( // TurnEndComplete means the model finished without requesting tool calls. TurnEndComplete TurnEndReason = "completed" // TurnEndMaxTurns means the configured maximum turn limit was reached. TurnEndMaxTurns TurnEndReason = "max_turns" // TurnEndAborted means the context was cancelled by the caller. TurnEndAborted TurnEndReason = "aborted" // TurnEndError means an unrecoverable error terminated the loop. TurnEndError TurnEndReason = "error" // TurnEndHookBlock means a hook prevented the loop from continuing. TurnEndHookBlock TurnEndReason = "hook_blocked" // TurnEndBudgetExhausted means the token budget was fully consumed. TurnEndBudgetExhausted TurnEndReason = "budget_exhausted" )
type TurnStartEvent ¶
type TurnStartEvent struct {
TurnNumber int
}
TurnStartEvent signals the beginning of a new iteration in the agentic loop.
type Usage ¶
type Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
}
Usage reports token consumption for a model request.
type UsageEvent ¶
UsageEvent carries token usage statistics for a single model call.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
_examples
|
|
|
basic
command
Basic example: a minimal agent with a working calculator tool.
|
Basic example: a minimal agent with a working calculator tool. |
|
chat
command
|
|
|
custom_tools
command
Custom tools example: an agent with multiple tools including web search and file reading.
|
Custom tools example: an agent with multiple tools including web search and file reading. |
|
streaming
command
Streaming example: production-ready HTTP SSE endpoint for an agentic AI.
|
Streaming example: production-ready HTTP SSE endpoint for an agentic AI. |
|
internal
|
|
|
jsonschema
Package jsonschema provides lightweight JSON Schema validation for tool inputs.
|
Package jsonschema provides lightweight JSON Schema validation for tool inputs. |
|
sse
Package sse provides shared types and SSE stream parsing for OpenAI-compatible chat completion APIs.
|
Package sse provides shared types and SSE stream parsing for OpenAI-compatible chat completion APIs. |
|
Package middleware provides reusable hooks for common cross-cutting concerns like logging, metrics collection, and panic recovery.
|
Package middleware provides reusable hooks for common cross-cutting concerns like logging, metrics collection, and panic recovery. |
|
Package observability provides tracing and cost tracking for agent runs.
|
Package observability provides tracing and cost tracking for agent runs. |
|
Package plan provides a two-phase planning workflow for agents.
|
Package plan provides a two-phase planning workflow for agents. |
|
provider
|
|
|
anthropic
Package anthropic provides an agentflow Provider implementation for the Anthropic Messages API (https://docs.anthropic.com/en/api/messages).
|
Package anthropic provides an agentflow Provider implementation for the Anthropic Messages API (https://docs.anthropic.com/en/api/messages). |
|
fallback
Package fallback provides a Provider that cascades through multiple providers.
|
Package fallback provides a Provider that cascades through multiple providers. |
|
gemini
Package gemini provides an agentflow Provider implementation for the Google Gemini API (https://ai.google.dev/api/generate-content).
|
Package gemini provides an agentflow Provider implementation for the Google Gemini API (https://ai.google.dev/api/generate-content). |
|
groq
Package groq provides an agentflow Provider implementation for the Groq API.
|
Package groq provides an agentflow Provider implementation for the Groq API. |
|
mock
Package mock provides a deterministic mock provider for testing agentflow agents.
|
Package mock provides a deterministic mock provider for testing agentflow agents. |
|
ollama
Package ollama provides an agentflow Provider implementation for Ollama-compatible APIs (https://github.com/ollama/ollama/blob/main/docs/api.md).
|
Package ollama provides an agentflow Provider implementation for Ollama-compatible APIs (https://github.com/ollama/ollama/blob/main/docs/api.md). |
|
openai
Package openai provides an agentflow Provider implementation for the OpenAI Chat Completions API (https://platform.openai.com/docs/api-reference/chat).
|
Package openai provides an agentflow Provider implementation for the OpenAI Chat Completions API (https://platform.openai.com/docs/api-reference/chat). |
|
openrouter
Package openrouter provides an agentflow Provider implementation for the OpenRouter API (https://openrouter.ai).
|
Package openrouter provides an agentflow Provider implementation for the OpenRouter API (https://openrouter.ai). |
|
session
|
|
|
filestore
Package filestore provides a file-system-based SessionStore implementation.
|
Package filestore provides a file-system-based SessionStore implementation. |
|
memstore
Package memstore provides an in-memory SessionStore implementation.
|
Package memstore provides an in-memory SessionStore implementation. |
|
Package skill provides reusable workflow templates that agents can invoke by name.
|
Package skill provides reusable workflow templates that agents can invoke by name. |
|
Package task provides a thread-safe task store for agents to create, track, and manage units of work during execution.
|
Package task provides a thread-safe task store for agents to create, track, and manage units of work during execution. |
|
Package team provides multi-agent coordination with shared communication channels and memory.
|
Package team provides multi-agent coordination with shared communication channels and memory. |
|
Package tools provides utilities for building agentflow tools with a fluent API.
|
Package tools provides utilities for building agentflow tools with a fluent API. |
|
builtin
Package builtin provides ready-to-use tools for common agent operations.
|
Package builtin provides ready-to-use tools for common agent operations. |
|
Package trigger provides scheduled agent execution.
|
Package trigger provides scheduled agent execution. |