Documentation
¶
Overview ¶
Package llmagent provides an LLM-based agent implementation for Hector v2.
LLM agents use language models to generate responses and can invoke tools to perform actions. They support:
- Instruction-based behavior control
- Tool/function calling
- Sub-agent delegation
- Callbacks for customization
Usage ¶
agent, err := llmagent.New(llmagent.Config{
Name: "assistant",
Model: myModel,
Instruction: "You are a helpful assistant.",
Tools: []tool.Tool{searchTool, calculatorTool},
})
Index ¶
- func ConfigRequestProcessor(ctx ProcessorContext, req *model.Request) error
- func ContentsRequestProcessor(ctx ProcessorContext, req *model.Request) error
- func InstructionRequestProcessor(ctx ProcessorContext, req *model.Request) error
- func LoggingResponseProcessor(ctx ProcessorContext, req *model.Request, resp *model.Response) error
- func New(cfg Config) (agent.Agent, error)
- func RAGContextRequestProcessor(ctx ProcessorContext, req *model.Request) error
- func ThinkingResponseProcessor(ctx ProcessorContext, req *model.Request, resp *model.Response) error
- func ToolsRequestProcessor(ctx ProcessorContext, req *model.Request) error
- func TransferToolsRequestProcessor(ctx ProcessorContext, req *model.Request) error
- type AfterModelCallback
- type AfterToolCallback
- type BeforeModelCallback
- type BeforeToolCallback
- type Config
- type ContentProcessor
- func (p *ContentProcessor) ConvertForeignAgentMessage(msg *a2a.Message, author string) *a2a.Message
- func (p *ContentProcessor) FilterAuthEvents(messages []*a2a.Message) []*a2a.Message
- func (p *ContentProcessor) Process(messages []*a2a.Message) []*a2a.Message
- func (p *ContentProcessor) RearrangeEventsForFunctionResponsesInHistory(events []*agent.Event) ([]*agent.Event, error)
- func (p *ContentProcessor) RearrangeEventsForLatestFunctionResponse(events []*agent.Event) ([]*agent.Event, error)
- func (p *ContentProcessor) SanitizeMessage(msg *a2a.Message) *a2a.Message
- type ContextProvider
- type Flow
- type FunctionCallInfo
- type FunctionResponseInfo
- type IncludeContents
- type InstructionProvider
- type Pipeline
- func (p *Pipeline) AddRequestProcessor(processor RequestProcessor)
- func (p *Pipeline) AddResponseProcessor(processor ResponseProcessor)
- func (p *Pipeline) PrependRequestProcessor(processor RequestProcessor)
- func (p *Pipeline) PrependResponseProcessor(processor ResponseProcessor)
- func (p *Pipeline) ProcessRequest(ctx ProcessorContext, req *model.Request) error
- func (p *Pipeline) ProcessResponse(ctx ProcessorContext, req *model.Request, resp *model.Response) error
- type ProcessorContext
- type ReasoningConfig
- type RequestProcessor
- type ResponseProcessor
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ConfigRequestProcessor ¶
func ConfigRequestProcessor(ctx ProcessorContext, req *model.Request) error
ConfigRequestProcessor applies the agent's generate config to the request.
func ContentsRequestProcessor ¶
func ContentsRequestProcessor(ctx ProcessorContext, req *model.Request) error
ContentsRequestProcessor builds the conversation history from session events. Following adk-go pattern: ALWAYS reads from session events on every LLM call. This is the source of truth for conversation history.
func InstructionRequestProcessor ¶
func InstructionRequestProcessor(ctx ProcessorContext, req *model.Request) error
InstructionRequestProcessor resolves instruction templates and sets system instruction.
func LoggingResponseProcessor ¶
LoggingResponseProcessor logs response details for debugging.
func New ¶
New creates a new LLM-based agent.
To convert an agent to a tool for agent-as-tool delegation (Pattern 2), use the agenttool package:
import "github.com/verikod/hector/pkg/tool/agenttool"
searchAgent, _ := llmagent.New(llmagent.Config{...})
rootAgent, _ := llmagent.New(llmagent.Config{
Tools: []tool.Tool{
agenttool.New(searchAgent, nil), // ✅ Clean factory pattern
},
})
func RAGContextRequestProcessor ¶
func RAGContextRequestProcessor(ctx ProcessorContext, req *model.Request) error
RAGContextRequestProcessor injects relevant RAG context into the messages. This runs AFTER ContentsRequestProcessor to inject context based on user query.
func ThinkingResponseProcessor ¶
func ThinkingResponseProcessor(ctx ProcessorContext, req *model.Request, resp *model.Response) error
ThinkingResponseProcessor processes thinking blocks in the response.
func ToolsRequestProcessor ¶
func ToolsRequestProcessor(ctx ProcessorContext, req *model.Request) error
ToolsRequestProcessor collects tool definitions and adds them to the request.
func TransferToolsRequestProcessor ¶
func TransferToolsRequestProcessor(ctx ProcessorContext, req *model.Request) error
TransferToolsRequestProcessor adds agent transfer tools based on sub-agents.
Types ¶
type AfterModelCallback ¶
type AfterModelCallback func(ctx agent.CallbackContext, resp *model.Response, err error) (*model.Response, error)
AfterModelCallback runs after an LLM call. Return non-nil Response to replace the LLM response.
type AfterToolCallback ¶
type AfterToolCallback func(ctx tool.Context, t tool.Tool, args, result map[string]any, err error) (map[string]any, error)
AfterToolCallback runs after tool execution. Return non-nil result to replace the tool result.
type BeforeModelCallback ¶
type BeforeModelCallback func(ctx agent.CallbackContext, req *model.Request) (*model.Response, error)
BeforeModelCallback runs before an LLM call. Return non-nil Response to skip the actual LLM call.
type BeforeToolCallback ¶
type BeforeToolCallback func(ctx tool.Context, t tool.Tool, args map[string]any) (map[string]any, error)
BeforeToolCallback runs before tool execution. Return non-nil result to skip actual tool execution.
type Config ¶
type Config struct {
// Name must be unique within the agent tree.
Name string
// DisplayName is the human-readable name used for UI/Chat attribution.
// If empty, defaults to Name.
DisplayName string
// Description helps LLMs decide when to delegate to this agent.
Description string
// Model is the LLM to use for generation.
Model model.LLM
// Instruction guides the agent's behavior.
// Supports template placeholders like {variable} resolved from state.
Instruction string
// EnableStreaming enables token-by-token streaming from the LLM.
// When false (default), responses are returned as complete chunks.
EnableStreaming bool
// InstructionProvider allows dynamic instruction generation.
// Takes precedence over Instruction if set.
InstructionProvider InstructionProvider
// GlobalInstruction applies to all agents in the tree.
// Only the root agent's GlobalInstruction is used.
GlobalInstruction string
// GlobalInstructionProvider allows dynamic global instruction.
GlobalInstructionProvider InstructionProvider
// GenerateConfig contains LLM generation settings.
GenerateConfig *model.GenerateConfig
// Tools available to the agent.
Tools []tool.Tool
// Toolsets provide dynamic tool resolution.
Toolsets []tool.Toolset
// SubAgents can receive delegated tasks.
SubAgents []agent.Agent
// BeforeAgentCallbacks run before the agent starts.
BeforeAgentCallbacks []agent.BeforeAgentCallback
// AfterAgentCallbacks run after the agent completes.
AfterAgentCallbacks []agent.AfterAgentCallback
// BeforeModelCallbacks run before each LLM call.
BeforeModelCallbacks []BeforeModelCallback
// AfterModelCallbacks run after each LLM call.
AfterModelCallbacks []AfterModelCallback
// BeforeToolCallbacks run before each tool execution.
BeforeToolCallbacks []BeforeToolCallback
// AfterToolCallbacks run after each tool execution.
AfterToolCallbacks []AfterToolCallback
// DisallowTransferToParent prevents delegation to parent agent.
DisallowTransferToParent bool
// DisallowTransferToPeers prevents delegation to sibling agents.
DisallowTransferToPeers bool
// IncludeContents controls conversation history inclusion.
IncludeContents IncludeContents
// OutputKey saves agent output to session state under this key.
OutputKey string
// InputSchema validates input when agent is used as a tool.
InputSchema map[string]any
// OutputSchema enforces structured output format.
OutputSchema map[string]any
// OutputSchemaName identifies the schema.
OutputSchemaName string
// OutputSchemaStrict enables strict schema validation.
OutputSchemaStrict *bool
// Reasoning configures the chain-of-thought reasoning loop.
// When nil, defaults are applied (semantic termination, 100 max iterations).
Reasoning *ReasoningConfig
// WorkingMemory is the context window management strategy.
// Controls how conversation history is filtered to fit within LLM limits.
// If nil, all history is included (no filtering).
WorkingMemory memory.WorkingMemoryStrategy
// AutoRecall enables automatic memory recall.
AutoRecall bool
// AutoRecallLimit limits the number of recalled memories.
AutoRecallLimit int
// ContextProvider retrieves relevant context for RAG.
// When set, the agent will query the provider with user input
// and inject relevant context into the conversation.
ContextProvider ContextProvider
// RequestProcessors are custom processors added to the request pipeline.
// These run AFTER the default processors.
RequestProcessors []RequestProcessor
// ResponseProcessors are custom processors added to the response pipeline.
// These run AFTER the default processors.
ResponseProcessors []ResponseProcessor
// Pipeline allows complete customization of the processor pipeline.
// If set, RequestProcessors and ResponseProcessors are ignored.
Pipeline *Pipeline
// MetricsRecorder records tool execution metrics.
// If nil, metrics are not recorded (no-op).
MetricsRecorder observability.Recorder
// DisableSafetyProtocols disables the automatic injection of safety protocols
// (Tool Reliability and Chain of Thought).
DisableSafetyProtocols bool
}
Config contains the configuration for an LLM agent.
type ContentProcessor ¶
type ContentProcessor struct {
// contains filtered or unexported fields
}
ContentProcessor handles message history processing for LLM context. It handles tool call/result pairing, foreign agent message conversion, and auth filtering.
The processor is model-aware: different providers have different requirements for how tool calls and results should be formatted:
- OpenAI: Tool results are separate function_call_output items
- Anthropic/Gemini: Tool results must be paired with tool_use in same message
func NewContentProcessor ¶
func NewContentProcessor(agentName string, provider model.Provider) *ContentProcessor
NewContentProcessor creates a new content processor for the given agent and provider.
func (*ContentProcessor) ConvertForeignAgentMessage ¶
ConvertForeignAgentMessage converts messages from other agents to user context. In multi-agent setups, foreign agent messages need to be presented as user context.
func (*ContentProcessor) FilterAuthEvents ¶
func (p *ContentProcessor) FilterAuthEvents(messages []*a2a.Message) []*a2a.Message
FilterAuthEvents removes authentication-related events from the history.
func (*ContentProcessor) Process ¶
func (p *ContentProcessor) Process(messages []*a2a.Message) []*a2a.Message
Process handles tool call/result formatting for LLM protocols.
This method is model-aware:
- OpenAI/Ollama: Returns messages as-is (tool results are separate function_call_output items)
- Anthropic: Returns messages as-is (tool_use in assistant msg, tool_result in next user msg)
- Gemini: May need special handling (currently returns as-is)
The Flow already creates the correct message structure for all providers:
- Assistant message with tool_use blocks
- User message with tool_result blocks
This processor primarily exists for future model-specific transformations and to filter out any malformed messages.
func (*ContentProcessor) RearrangeEventsForFunctionResponsesInHistory ¶
func (p *ContentProcessor) RearrangeEventsForFunctionResponsesInHistory(events []*agent.Event) ([]*agent.Event, error)
RearrangeEventsForFunctionResponsesInHistory reorganizes entire event history to ensure every function call is immediately followed by its response.
This follows adk-go's rearrangeEventsForFunctionResponsesInHistory pattern.
func (*ContentProcessor) RearrangeEventsForLatestFunctionResponse ¶
func (p *ContentProcessor) RearrangeEventsForLatestFunctionResponse(events []*agent.Event) ([]*agent.Event, error)
RearrangeEventsForLatestFunctionResponse handles async function responses. If the latest event is a function response, it searches backward for the matching call, removes all intervening events, and ensures proper call/response pairing.
This follows adk-go's rearrangeEventsForLatestFunctionResponse pattern for handling long-running/async tools where responses may arrive out of order.
func (*ContentProcessor) SanitizeMessage ¶
func (p *ContentProcessor) SanitizeMessage(msg *a2a.Message) *a2a.Message
SanitizeMessage removes empty parts from a message, helpful for some models (e.g. Gemini).
type ContextProvider ¶
type ContextProvider func(ctx agent.ReadonlyContext, query string) (string, error)
ContextProvider retrieves relevant context based on user input. Used for RAG context injection when IncludeContext is enabled. The returned string is injected into the conversation as additional context.
type Flow ¶
type Flow struct {
// contains filtered or unexported fields
}
Flow implements the adk-go aligned core reasoning loop. Key principles from adk-go:
- Outer loop continues until IsFinalResponse() returns true
- Each runOneStep() handles: preprocess → LLM call → postprocess → tool execution
- Events are yielded and persisted to session immediately
- ContentsRequestProcessor reads from session on EVERY iteration
- No manual message accumulation - session is the source of truth
type FunctionCallInfo ¶
FunctionCallInfo represents a function call extracted from an event.
type FunctionResponseInfo ¶
FunctionResponseInfo represents a function response extracted from an event.
type IncludeContents ¶
type IncludeContents string
IncludeContents controls conversation history handling.
const ( // IncludeContentsDefault includes relevant conversation history. IncludeContentsDefault IncludeContents = "default" // IncludeContentsNone only uses the current turn. IncludeContentsNone IncludeContents = "none" )
type InstructionProvider ¶
type InstructionProvider func(ctx agent.ReadonlyContext) (string, error)
InstructionProvider generates instructions dynamically.
type Pipeline ¶
type Pipeline struct {
// contains filtered or unexported fields
}
Pipeline manages request and response processors.
func NewCustomPipeline ¶
func NewCustomPipeline(reqProcessors []RequestProcessor, respProcessors []ResponseProcessor) *Pipeline
NewCustomPipeline creates a pipeline with custom processors.
func NewPipeline ¶
func NewPipeline() *Pipeline
NewPipeline creates a new processor pipeline with default processors.
func (*Pipeline) AddRequestProcessor ¶
func (p *Pipeline) AddRequestProcessor(processor RequestProcessor)
AddRequestProcessor appends a request processor to the pipeline.
func (*Pipeline) AddResponseProcessor ¶
func (p *Pipeline) AddResponseProcessor(processor ResponseProcessor)
AddResponseProcessor appends a response processor to the pipeline.
func (*Pipeline) PrependRequestProcessor ¶
func (p *Pipeline) PrependRequestProcessor(processor RequestProcessor)
PrependRequestProcessor adds a request processor at the beginning.
func (*Pipeline) PrependResponseProcessor ¶
func (p *Pipeline) PrependResponseProcessor(processor ResponseProcessor)
PrependResponseProcessor adds a response processor at the beginning.
func (*Pipeline) ProcessRequest ¶
func (p *Pipeline) ProcessRequest(ctx ProcessorContext, req *model.Request) error
ProcessRequest runs all request processors in order.
func (*Pipeline) ProcessResponse ¶
func (p *Pipeline) ProcessResponse(ctx ProcessorContext, req *model.Request, resp *model.Response) error
ProcessResponse runs all response processors in order.
type ProcessorContext ¶
type ProcessorContext interface {
agent.InvocationContext
// Agent returns the LLM agent being processed.
LLMAgent() *llmAgent
// Tools returns all available tools for this agent.
Tools() []tool.Tool
// ToolDefinitions returns tool definitions for the LLM.
ToolDefinitions() ([]tool.Definition, error)
}
ProcessorContext provides context for processors. It extends agent.InvocationContext with processor-specific functionality.
type ReasoningConfig ¶
type ReasoningConfig struct {
// MaxIterations is a SAFETY limit (not the primary termination condition).
// The loop terminates when semantic conditions are met (no tool calls, etc.)
// Default: 100 (high enough to not interfere with normal operation)
MaxIterations int
// EnableExitTool adds the exit_loop tool for explicit termination.
EnableExitTool bool
// EnableEscalateTool adds the escalate tool for parent delegation.
EnableEscalateTool bool
// CompletionInstruction is appended to help the model know when to stop.
CompletionInstruction string
}
ReasoningConfig configures the chain-of-thought reasoning loop. This follows adk-go patterns for semantic loop termination.
type RequestProcessor ¶
type RequestProcessor func(ctx ProcessorContext, req *model.Request) error
RequestProcessor transforms an LLM request before it's sent to the model. Processors are called in order, each receiving the modified request from the previous. Return an error to abort the request pipeline.
func AuthRequestProcessor ¶
func AuthRequestProcessor(tokenProvider func(ctx agent.ReadonlyContext) (string, error)) RequestProcessor
AuthRequestProcessor creates a processor that adds authentication tokens. The token is stored in Config.Metadata["Authorization"] for LLM implementations to use.
Example usage:
authProcessor := AuthRequestProcessor(func(ctx agent.ReadonlyContext) (string, error) {
// Get token from session state, environment, or secret manager
token, _ := ctx.ReadonlyState().Get("api_token")
return token.(string), nil
})
func ContentFilterRequestProcessor ¶
func ContentFilterRequestProcessor(filter func(content string) string) RequestProcessor
ContentFilterRequestProcessor creates a processor that filters/transforms content.
func DefaultRequestProcessors ¶
func DefaultRequestProcessors() []RequestProcessor
DefaultRequestProcessors returns the standard request processor chain. Order matters - processors are executed sequentially.
type ResponseProcessor ¶
ResponseProcessor transforms an LLM response after it comes back from the model. Processors are called in order, each receiving the modified response from the previous. Return an error to abort the response pipeline.
func DefaultResponseProcessors ¶
func DefaultResponseProcessors() []ResponseProcessor
DefaultResponseProcessors returns the standard response processor chain.
func ValidationResponseProcessor ¶
func ValidationResponseProcessor(validator func(resp *model.Response) error) ResponseProcessor
ValidationResponseProcessor creates a processor that validates responses.