Documentation
¶
Overview ¶
Package middleware provides composable hooks for the agent execution loop.
It mirrors the middleware system introduced in langchain's agent factory (langchain.agents.middleware), exposing hooks that wrap model requests and tool calls.
Index ¶
- Variables
- type Chain
- type HumanInTheLoop
- func (m *HumanInTheLoop) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, ...)
- func (m *HumanInTheLoop) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, ...)
- func (m *HumanInTheLoop) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
- func (m *HumanInTheLoop) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
- type HumanInTheLoopConfig
- type Middleware
- type MiddlewareConfig
- type MiddlewareFunc
- func (m *MiddlewareFunc) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, ...)
- func (m *MiddlewareFunc) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, ...)
- func (m *MiddlewareFunc) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
- func (m *MiddlewareFunc) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
- type ModelCallLimit
- type ModelRequest
- type ModelResponse
- type ModelRetry
- type Next
- type PII
- func (p *PII) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, ...)
- func (p *PII) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, ...)
- func (p *PII) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
- func (p *PII) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
- type PassThrough
- func (PassThrough) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, ...)
- func (PassThrough) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, ...)
- func (PassThrough) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
- func (PassThrough) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
- type RetryConfig
- type State
- type Summarization
- func (m *Summarization) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, ...)
- func (m *Summarization) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, ...)
- func (m *Summarization) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
- func (m *Summarization) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
- type TodoList
- func (m *TodoList) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, ...)
- func (m *TodoList) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, ...)
- func (m *TodoList) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
- func (m *TodoList) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
- type TodoListConfig
- type ToolCallLimit
- type ToolError
- type ToolRequest
- type ToolResponse
- type ToolRetry
Constants ¶
This section is empty.
Variables ¶
var ErrNoResponse = errors.New("no response from human in the loop")
ErrNoResponse is returned by HumanInTheLoop when the human provided no input.
Functions ¶
This section is empty.
Types ¶
type Chain ¶
type Chain struct {
// contains filtered or unexported fields
}
Chain composes a list of middleware into a single model and tool pipeline.
func NewChain ¶
func NewChain(middleware ...Middleware) *Chain
NewChain builds a Chain from the given middleware. The middleware are invoked in order for the "before" phase and in reverse order for the "after" phase, forming a nested onion.
func (*Chain) RunModel ¶
func (c *Chain) RunModel( ctx context.Context, state *State, req *ModelRequest, plan func(ctx context.Context) ([]schema.AgentAction, *schema.AgentFinish, error), ) *ModelResponse
RunModel executes the model pipeline composed of all middleware.
The final step invokes plan, which must return actions and/or a finish. If plan returns an error, it is recorded on the response and the after hooks still run so they can recover (e.g. ModelRetry).
func (*Chain) RunTool ¶
func (c *Chain) RunTool( ctx context.Context, state *State, req *ToolRequest, call func(ctx context.Context, input string) (string, error), ) *ToolResponse
RunTool executes the tool pipeline composed of all middleware.
The final step invokes call, which executes the tool and returns an observation. Errors are recorded on the response so after-hooks can recover.
type HumanInTheLoop ¶
type HumanInTheLoop struct {
PassThrough
// contains filtered or unexported fields
}
HumanInTheLoop inserts a human approval step before tool calls are executed, mirroring HumanInTheLoopMiddleware in langchain.
func NewHumanInTheLoop ¶
func NewHumanInTheLoop(cfg HumanInTheLoopConfig) *HumanInTheLoop
NewHumanInTheLoop builds the middleware.
func (*HumanInTheLoop) AfterModel ¶
func (m *HumanInTheLoop) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
AfterModel passes through.
func (*HumanInTheLoop) AfterTool ¶
func (m *HumanInTheLoop) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
AfterTool passes through.
func (*HumanInTheLoop) BeforeModel ¶
func (m *HumanInTheLoop) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
BeforeModel passes through.
func (*HumanInTheLoop) BeforeTool ¶
func (m *HumanInTheLoop) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
BeforeTool runs the human validator.
type HumanInTheLoopConfig ¶
type HumanInTheLoopConfig struct {
// BeforeToolValidator, when set, lets a human approve/reject a tool call.
// If it returns false, the tool observation is set to a rejection message.
BeforeToolValidator func(action string, input string) (bool, string)
// FallbackObservation is used when a tool call is rejected.
FallbackObservation string
}
HumanInTheLoopConfig configures a HumanInTheLoop middleware.
type Middleware ¶
type Middleware interface {
// BeforeModel runs before the model is invoked.
BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
// AfterModel runs after the model returns.
AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
// BeforeTool runs before a tool is called.
BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
// AfterTool runs after a tool returns.
AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
}
Middleware is a composable hook that can wrap model requests and tool calls.
All hooks are optional: implementations only need to define the methods they care about. The zero value of a hook func is nil, which skips that hook.
type MiddlewareConfig ¶
type MiddlewareConfig struct {
BeforeModel func(ctx context.Context, state *State, req *ModelRequest, next Next)
AfterModel func(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
BeforeTool func(ctx context.Context, state *State, req *ToolRequest, next Next)
AfterTool func(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
}
MiddlewareConfig collects the optional hook funcs for a middleware.
type MiddlewareFunc ¶
type MiddlewareFunc struct {
// contains filtered or unexported fields
}
MiddlewareFunc adapts a set of hook functions into a Middleware.
func NewMiddleware ¶
func NewMiddleware(cfg MiddlewareConfig) *MiddlewareFunc
NewMiddleware builds a MiddlewareFunc from the provided hook funcs.
func (*MiddlewareFunc) AfterModel ¶
func (m *MiddlewareFunc) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
AfterModel implements Middleware.
func (*MiddlewareFunc) AfterTool ¶
func (m *MiddlewareFunc) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
AfterTool implements Middleware.
func (*MiddlewareFunc) BeforeModel ¶
func (m *MiddlewareFunc) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
BeforeModel implements Middleware.
func (*MiddlewareFunc) BeforeTool ¶
func (m *MiddlewareFunc) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
BeforeTool implements Middleware.
type ModelCallLimit ¶
type ModelCallLimit struct {
PassThrough
// contains filtered or unexported fields
}
ModelCallLimit aborts the agent after MaxCalls model invocations.
It counts every model request that passes through the before hook. When the limit is exceeded it records an error on the model response and skips the underlying invocation.
func NewModelCallLimit ¶
func NewModelCallLimit(maxCalls int) *ModelCallLimit
NewModelCallLimit builds a ModelCallLimit middleware.
func (*ModelCallLimit) AfterModel ¶
func (m *ModelCallLimit) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
AfterModel records an error when the limit was exceeded.
func (*ModelCallLimit) BeforeModel ¶
func (m *ModelCallLimit) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
BeforeModel enforces the call limit.
type ModelRequest ¶
type ModelRequest struct {
// Inputs are the inputs passed to the model, including the scratchpad.
Inputs map[string]any
// Options are the chain call options.
Options []any
// Step is the index of the current iteration.
Step int
// Skip, when set by a before-hook, prevents the underlying plan from
// running. The after-hooks still execute so they can record the outcome.
Skip bool
}
ModelRequest wraps a single model (plan) invocation.
type ModelResponse ¶
type ModelResponse struct {
// Actions are the actions the model decided to take.
Actions []schema.AgentAction
// Finish is set when the model decided to finish.
Finish *schema.AgentFinish
// Err is set when the model invocation failed.
Err error
}
ModelResponse is the result of a model invocation.
type ModelRetry ¶
type ModelRetry struct {
PassThrough
// contains filtered or unexported fields
}
ModelRetry retries the model invocation when it fails, up to MaxAttempts.
func NewModelRetry ¶
func NewModelRetry(cfg RetryConfig) *ModelRetry
NewModelRetry builds a ModelRetry middleware.
func (*ModelRetry) AfterModel ¶
func (m *ModelRetry) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
AfterModel retries the pipeline when the model returns an error.
func (*ModelRetry) BeforeModel ¶
func (m *ModelRetry) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
BeforeModel passes through.
type PII ¶
type PII struct {
PassThrough
// contains filtered or unexported fields
}
PII replaces likely email addresses and phone numbers in model requests with placeholders, mirroring PIIMiddleware in langchain. It is a thin, dependency free heuristic.
func (*PII) AfterModel ¶
func (p *PII) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
AfterModel passes through.
func (*PII) AfterTool ¶
func (p *PII) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
AfterTool passes through.
func (*PII) BeforeModel ¶
BeforeModel redacts PII from the model inputs.
func (*PII) BeforeTool ¶
BeforeTool passes through.
type PassThrough ¶
type PassThrough struct{}
PassThrough is a no-op middleware useful as a base or in tests.
func (PassThrough) AfterModel ¶
func (PassThrough) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
AfterModel implements Middleware.
func (PassThrough) AfterTool ¶
func (PassThrough) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
AfterTool implements Middleware.
func (PassThrough) BeforeModel ¶
func (PassThrough) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
BeforeModel implements Middleware.
func (PassThrough) BeforeTool ¶
func (PassThrough) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
BeforeTool implements Middleware.
type RetryConfig ¶
type RetryConfig struct {
// MaxAttempts is the maximum number of model attempts before giving up.
MaxAttempts int
// ShouldRetry reports whether a given error should be retried.
ShouldRetry func(error) bool
// OnRetry is invoked before each retry with the attempt index and error.
OnRetry func(attempt int, err error)
}
RetryConfig configures ModelRetry.
type State ¶
type State struct {
// Inputs are the original agent inputs.
Inputs map[string]string
// Steps are the intermediate steps accumulated so far.
Steps []schema.AgentStep
// Output is the final output, set when the agent finishes.
Output map[string]any
}
State is the mutable state shared across middleware during a single agent run. It carries the inputs, the accumulated steps, and the final output.
type Summarization ¶
type Summarization struct {
PassThrough
// MaxSteps is the maximum number of steps to retain before summarizing.
MaxSteps int
// SummarizeFunc, when set, is called to compact the steps.
SummarizeFunc func(steps []schema.AgentStep) []schema.AgentStep
}
Summarization trims the accumulated steps to a trailing window so that long agent runs stay within the model context window. It mirrors SummarizationMiddleware in langchain.
func NewSummarization ¶
NewSummarization builds a Summarization middleware.
func (*Summarization) AfterModel ¶
func (m *Summarization) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
AfterModel passes through.
func (*Summarization) AfterTool ¶
func (m *Summarization) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
AfterTool passes through.
func (*Summarization) BeforeModel ¶
func (m *Summarization) BeforeModel(ctx context.Context, state *State, req *ModelRequest, next Next)
BeforeModel compacts the steps when they exceed MaxSteps.
func (*Summarization) BeforeTool ¶
func (m *Summarization) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
BeforeTool passes through.
type TodoList ¶
type TodoList struct {
PassThrough
// contains filtered or unexported fields
}
TodoList injects a task list into the model request, mirroring TodoListMiddleware in langchain.
func NewTodoList ¶
func NewTodoList(cfg TodoListConfig) *TodoList
NewTodoList builds a TodoList middleware.
func (*TodoList) AfterModel ¶
func (m *TodoList) AfterModel(ctx context.Context, state *State, req *ModelRequest, resp *ModelResponse, next Next)
AfterModel passes through.
func (*TodoList) AfterTool ¶
func (m *TodoList) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
AfterTool passes through.
func (*TodoList) BeforeModel ¶
BeforeModel injects the todo list.
func (*TodoList) BeforeTool ¶
BeforeTool passes through.
type TodoListConfig ¶
type TodoListConfig struct {
// TodoList is the list of tasks the agent should complete.
TodoList []string
// InjectSystemMessage, when set, is a function that adds the todo list to
// the model inputs.
InjectSystemMessage func(inputs map[string]any, todos []string)
}
TodoListConfig configures a TodoList middleware.
type ToolCallLimit ¶
type ToolCallLimit struct {
PassThrough
// contains filtered or unexported fields
}
ToolCallLimit aborts the agent after MaxCalls tool invocations.
func NewToolCallLimit ¶
func NewToolCallLimit(maxCalls int) *ToolCallLimit
NewToolCallLimit builds a ToolCallLimit middleware.
func (*ToolCallLimit) AfterTool ¶
func (m *ToolCallLimit) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
AfterTool records an error when the limit was exceeded.
func (*ToolCallLimit) BeforeTool ¶
func (m *ToolCallLimit) BeforeTool(ctx context.Context, state *State, req *ToolRequest, next Next)
BeforeTool enforces the limit.
type ToolError ¶
type ToolError struct {
PassThrough
// FormatObservation, when set, transforms the raw error into an observation.
FormatObservation func(err error) string
}
ToolError converts a tool error into a regular observation so the agent can recover instead of aborting. This mirrors ToolErrorMiddleware in langchain.
func NewToolError ¶
NewToolError builds a ToolError middleware.
func (*ToolError) AfterTool ¶
func (m *ToolError) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
AfterTool swallows tool errors and records them as observations.
func (*ToolError) BeforeTool ¶
BeforeTool passes through.
type ToolRequest ¶
type ToolRequest struct {
// Action is the action describing the tool to call.
Action schema.AgentAction
// Step is the index of the current iteration.
Step int
// Skip, when set by a before-hook, prevents the underlying tool from
// running. The after-hooks still execute so they can record the outcome.
Skip bool
}
ToolRequest wraps a single tool call.
type ToolResponse ¶
type ToolResponse struct {
// Observation is the tool result.
Observation string
// Err is set when the tool call failed.
Err error
}
ToolResponse is the result of a tool call.
type ToolRetry ¶
type ToolRetry struct {
PassThrough
// contains filtered or unexported fields
}
ToolRetry retries a failing tool call up to MaxAttempts.
func NewToolRetry ¶
NewToolRetry builds a ToolRetry middleware.
func (*ToolRetry) AfterTool ¶
func (m *ToolRetry) AfterTool(ctx context.Context, state *State, req *ToolRequest, resp *ToolResponse, next Next)
AfterTool retries the tool call when it fails.
func (*ToolRetry) BeforeTool ¶
BeforeTool passes through.