state_agent_test.go
Overview
This file contains comprehensive unit and integration tests for the LLM agent implementation, focusing on session lifecycle management, agent callbacks, and tool invocation with callback chains. It provides mock implementations, test helpers, and multiple test cases that verify the correctness of agent behavior within a session-driven environment.
The tests validate how the LLM agent:
Manages session state through lifecycle callbacks.
Interacts with a fake LLM model to simulate language model responses.
Invokes tools with before/after callbacks that perform auditing, security checks, validation, and response enhancements.
Persists state and logs within the session service.
Runs through a runner that orchestrates the agent execution in a simulated environment.
The file thus serves as a critical verification suite ensuring robust integration of LLM agents with session management, callback processing, and tool execution.
Key Components
FakeLLM
FakeLLM is a mock implementation of the model.LLM interface used to simulate LLM responses in tests.
Fields:
GenerateContentFunc: A customizable function to override the default content generation behavior.
Methods:
Name() string: Returns the fixed name "fake-llm".GenerateContent(ctx context.Context, req *model.LLMRequest, stream bool) iter.Seq2[*model.LLMResponse, error]: Implements content generation as a generator function yielding a singleLLMResponse. If a custom function is provided, it delegates to it; otherwise, it yields a default response with text"fake model response".
Usage:
Injected as the LLM model in agent tests to control and predict LLM output during agent invocation.
assertSessionValues
A helper function to verify the presence or absence of keys in both the callback context session state and the underlying session service state.
Parameters:
t *testing.T: Testing handle for assertions.cctx agent.CallbackContext: The callback context representing the current agent invocation.params *assertSessionParams: Struct containing:title(string): Descriptive title for error messages.keysInCtxSession ([]string): Keys expected to be found in the callback context's session state.
keysInServiceSession ([]string): Keys expected in the persistent session service state.
keysNotInServiceSession ([]string): Keys expected not to be present in the session service state.
Behavior:
Asserts key presence or absence and fails the test if expectations are not met.
Callbacks for Agent Lifecycle
These are implementations of agent lifecycle callbacks wired into the tests to simulate state mutation and validation at different phases:
beforeAgentCallback(t) agent.BeforeAgentCallback:
Sets state key "before_agent_callback_state_key" in the callback context if not already set. Returns a non-nil content on repeated calls to simulate single-reply behavior.**beforeModelCallback(t) func(agent.CallbackContext, model.LLMRequest) (model.LLMResponse, error):
Sets "before_model_callback_state_key" and verifies cumulative session state.**afterModelCallback(t) func(agent.CallbackContext, model.LLMResponse, error) (model.LLMResponse, error):
Sets "after_model_callback_state_key" and asserts session state including keys set in earlier callbacks.afterAgentCallback(t) agent.AfterAgentCallback:
Sets "after_agent_callback_state_key" after all model processing and validates that previous keys persist in session service state.
Usage:
These callbacks are registered in the agent configuration during tests to validate correct state propagation and callback chaining (Agent Lifecycle and Callbacks).
TestAgentSessionLifecycle
This test function verifies the full lifecycle of an agent session:
Initializes an in-memory session service.
Creates and configures a
rootAgentwith theFakeLLMand the above lifecycle callbacks.Sets up a
runnerto execute the agent within the session context.Creates a session and runs the agent with a simple user prompt.
Iterates through the event stream to simulate full agent execution.
Confirms that state keys set in callbacks are persisted in the final session state.
It validates that session state propagates correctly through all lifecycle callbacks and that the agent integrates properly with the session service (Session Management, Agent Execution Runner).
Tool Implementations
Three example tools simulate external functionalities callable by the agent:
GetWeather:
Simulates retrieving weather data with randomized temperature, conditions, humidity, and timestamp.Calculate:
Performs basic mathematical operations (add, subtract, multiply, divide) on two floats. Handles divide-by-zero by returning infinity or an error string.LogActivity:
Appends a log message with timestamp to an "activity_log" array persisted in the tool context state.
Each tool receives a typed argument struct and returns a typed result struct, facilitating JSON serialization and integration with function tools (Function Tools).
Before Tool Callbacks
Callbacks run before tool execution to enable auditing, security, and validation:
beforeToolAuditCallback:
Logs all tool calls and their arguments to an "audit_log" in the tool state and prints audit messages.beforeToolSecurityCallback:
Blocks weather requests for restricted locations (e.g., "classified","secret"), sets a "security_log" key in state, and returns an error response to abort tool execution.beforeToolValidationCallback:
Prevents division by zero in the "calculate" tool by returning an error map without invoking the tool.
These callbacks demonstrate how to enforce policies and observe tooling activity before execution (Agent Lifecycle and Callbacks).
After Tool Callbacks
Callbacks run after tool execution to enhance or process results asynchronously:
afterToolEnhancementCallback:
Adds metadata fields like"enhanced": true, "enhancement_timestamp", and execution context info to the tool response.afterToolAsyncCallback:
Simulates asynchronous post-processing, adding"async_processed": trueand "processor" metadata.
These callbacks modify the results returned from tools, enabling richer responses or additional processing steps (Agent Lifecycle and Callbacks).
Helper Function: collectToolResults
Consumes the event stream from a runner execution and collects the tool function call responses into a slice of generic maps for inspection.
Skips nil events or events without content.
Extracts function call responses from content parts.
Fails the test on stream errors.
Used in the TestToolCallbacksAgent to gather and verify the output of tool calls.
TestToolCallbacksAgent
This complex test exercises the interaction of the agent with tools and their associated callbacks:
Configures a
FakeLLMthat simulates user queries mapped to tool function calls with arguments.Creates function tools (
get_weather,calculate,log_activity) bound to their implementations.Sets up an
llmagentwith the fake LLM, tools, and the before/after tool callbacks.Runs test cases covering:
Successful weather query.
Blocked weather query due to security restrictions.
Successful calculation.
Blocked calculation due to division by zero.
Logging activity and verifying log persistence.
For each test case:
Creates a session.
Runs the agent with the test query.
Collects tool results.
Asserts expected substrings exist or do not exist in the tool result.
Checks session state for keys set by callbacks (e.g., "security_log" or "activity_log").
This test validates the full pipeline of tool invocation with layered callbacks and state management (Tooling System, LLM Integration and Agents).
Interaction with Other Parts of the System
Session Management:
Uses an in-memory session service (session.InMemoryService()) to simulate state persistence and retrieval (Session Management, In-Memory Session Service).Agent Framework:
Instantiates agents usingllmagent.Newand runs them inside arunnerwhich manages session and user context (LLM Integration and Agents, Agent Execution Runner).Tooling System:
Creates function tools viafunctiontool.Newand integrates them into the agent with before/after callbacks for auditing, security, validation, and enhancement (Tooling System, Function Tools).Callback Lifecycle:
Implements agent lifecycle callbacks and tool invocation callbacks to intercept and influence agent behavior and tool calls (Agent Lifecycle and Callbacks).
Important Implementation Details and Algorithms
State Verification via Callback Context and Service:
The tests carefully verify that session state keys set in callback contexts (cctx.State()) and persisted in the session service (testSessionService) exist or do not exist as expected at various lifecycle points. This ensures state propagation semantics are correct.Callback Chaining:
The custom callbacks demonstrate chaining and state mutation in a sequence:BeforeAgent → BeforeModel → AfterModel → AfterAgent
BeforeTool → AfterTool
Each callback sets unique keys and validates previous keys, illustrating the stateful progression of agent invocation.
Tool Execution Short-Circuiting:
Before tool callbacks have the ability to block or modify tool calls by returning a non-nil error or result, effectively simulating security and validation enforcement.Event Stream Iteration:
The tests process event streams from the runner, which yield partial or full responses including LLM-generated content and tool function call results, validating asynchronous interaction models.Randomized Data in Tools:
The weather tool uses random sampling to simulate varying weather conditions, illustrating how tools can generate dynamic content.Error Handling and Reporting:
Tests fail on unexpected errors and missing state keys, ensuring strict validation of agent and tool execution correctness.
Usage Examples
Creating and Running a Simple Agent Session (From TestAgentSessionLifecycle)
ctx := context.Background()
testSessionService = session.InMemoryService()
fakeLLM := &FakeLLM{
GenerateContentFunc: func(ctx context.Context, req *model.LLMRequest, stream bool) (model.LLMResponse, error) {
return model.LLMResponse{
Content: genai.NewContentFromText("test model response", genai.RoleModel),
}, nil
},
}
rootAgent, err := llmagent.New(llmagent.Config{
Name: "root_agent",
Instruction: "Test instruction",
Model: fakeLLM,
BeforeAgentCallbacks: []agent.BeforeAgentCallback{beforeAgentCallback(t)},
BeforeModelCallbacks: []llmagent.BeforeModelCallback{beforeModelCallback(t)},
AfterModelCallbacks: []llmagent.AfterModelCallback{afterModelCallback(t)},
AfterAgentCallbacks: []agent.AfterAgentCallback{afterAgentCallback(t)},
})
if err != nil {
t.Fatal(err)
}
r, err := runner.New(runner.Config{
AppName: "test_app",
Agent: rootAgent,
SessionService: testSessionService,
})
if err != nil {
t.Fatal(err)
}
createResp, err := testSessionService.Create(ctx, &session.CreateRequest{AppName: "test_app", UserID: "test_user"})
if err != nil {
t.Fatal(err)
}
sessionID := createResp.Session.ID()
userContent := genai.NewContentFromText("Hello agent", genai.RoleUser)
eventStream := r.Run(ctx, "test_user", sessionID, userContent, agent.RunConfig{})
for _, err := range eventStream {
if err != nil {
t.Fatal(err)
}
}
// Validate session state keys set by callbacks...
Testing Tool Callbacks (From TestToolCallbacksAgent)
fakeLLM := &FakeLLM{
GenerateContentFunc: func(ctx context.Context, req *model.LLMRequest, stream bool) (model.LLMResponse, error) {
// Map user queries to tool function calls
switch userText {
case "weather in London":
return model.LLMResponse{Content: genai.NewContentFromFunctionCall("get_weather", map[string]any{"location": "London"}, genai.RoleModel)}, nil
// other cases...
}
},
}
getWeatherTool, _ := functiontool.New(functiontool.Config{Name: "get_weather"}, GetWeather)
calculateTool, _ := functiontool.New(functiontool.Config{Name: "calculate"}, Calculate)
logActivityTool, _ := functiontool.New(functiontool.Config{Name: "log_activity"}, LogActivity)
agentConfig := llmagent.Config{
Name: "tool_callbacks_agent",
Model: fakeLLM,
Tools: []tool.Tool{getWeatherTool, calculateTool, logActivityTool},
BeforeToolCallbacks: []llmagent.BeforeToolCallback{
beforeToolAuditCallback,
beforeToolSecurityCallback,
beforeToolValidationCallback,
},
AfterToolCallbacks: []llmagent.AfterToolCallback{
afterToolEnhancementCallback,
afterToolAsyncCallback,
},
}
rootAgent, err := llmagent.New(agentConfig)
// Setup runner, create session, run agent, collect and verify results...
Mermaid Diagram: Structure and Workflow of state_agent_test.go
flowchart TD
A[TestAgentSessionLifecycle] --> B[FakeLLM]
A --> C[Callbacks: beforeAgent, beforeModel, afterModel, afterAgent]
A --> D["Session Service (InMemory)"]
A --> E[Runner]
F[TestToolCallbacksAgent] --> G[FakeLLM with Query-to-Tool Mapping]
F --> H[Tools: GetWeather, Calculate, LogActivity]
F --> I[BeforeToolCallbacks: Audit, Security, Validation]
F --> J[AfterToolCallbacks: Enhancement, Async]
F --> D
B -->|Simulates| LLM
H -->|Simulates| External Tools
I -->|Pre-process| H
J -->|Post-process| H
E -->|Runs| A
E -->|Runs| F
D -->|Persists State| A
D -->|Persists State| F
Detailed Descriptions of Functions and Types
FakeLLM
GenerateContentFunc:
Custom function for generating LLM responses in tests.GenerateContent:
Returns a generator yielding one response, either fromGenerateContentFuncor a default fake response.Name:
Returns "fake-llm".
assertSessionValues
Validates session keys in callback context and session service.
Reports errors if keys are missing or unexpectedly present.
beforeAgentCallback
Sets "before_agent_callback_state_key" in context state.
Returns a response preventing further replies if key already set.
beforeModelCallback
Sets "before_model_callback_state_key" in context state.
Asserts cumulative keys from previous callbacks.
afterModelCallback
Sets "after_model_callback_state_key" in context state.
Asserts cumulative keys including those from model and agent callbacks.
afterAgentCallback
Sets "after_agent_callback_state_key" in context state.
Asserts all previous keys including those persisted in session service.
TestAgentSessionLifecycle
Tests full session lifecycle with callback state changes.
Runs agent once with a user message.
Validates final session state for callback keys.
Tool Implementations
GetWeather: Simulates weather conditions with random values.
Calculate: Supports add, subtract, multiply, divide with divide-by-zero handling.
LogActivity: Logs messages with timestamps into session state.
Before Tool Callbacks
Audit: Logs tool calls.
Security: Blocks restricted locations in weather tool.
Validation: Prevents division by zero in calculate tool.
After Tool Callbacks
Enhancement: Adds metadata to tool response.
Async: Simulates asynchronous post-processing.
collectToolResults
Aggregates function call responses from event streams.
Fails on errors or missing results.
TestToolCallbacksAgent
Uses fake LLM to map queries to tool calls.
Tests multiple scenarios for success, blocking, validation.
Asserts tool results and session state keys.
References to Related Topics
LLM Integration and Agents — For understanding agent construction, invocation, and callback lifecycle.
Agent Lifecycle and Callbacks — For details on callback types and chaining.
Session Management — For session service interaction and state persistence.
Agent Execution Runner — For running agents within sessions and managing event streams.
Tooling System & Function Tools — For creating and invoking tools with JSON-schema-based function tools.
Instruction Injection — Relevant for dynamic instruction handling in agents, though not directly tested here.
This documentation provides a detailed understanding of the test suite validating agent session lifecycle and tool callback integrations in the LLM agent framework.