contents_processor_test.go
Overview
This file contains comprehensive unit tests for the ContentsRequestProcessor function and related content processing utilities within the llminternal package. Its primary focus is to validate the behavior of how session events and their associated LLM-generated content are transformed into a sequence of genai.Content items that populate an LLMRequest. These tests cover multiple scenarios including content filtering by agent settings (IncludeContents), branch filtering, event conversion for foreign agents, and complex rearrangements of function call/response events.
The file is essential for ensuring the correctness of the content preparation pipeline, which is a critical step in generating accurate and context-aware prompts for language model invocations during agent execution. It also tests the conversion of non-local events ("foreign" events) into user-context content, preserving conversational context in multi-agent environments.
Detailed Explanations
Types
testModel
type testModel struct {
model.LLM
}
A stub implementation embedding
model.LLMused as a mock or dummy LLM model for testing purposes.No additional methods or fields are defined; it serves to satisfy the model interface during agent creation.
fakeSession
type fakeSession struct {
events []*session.Event
}
Implements the
session.Sessionandsession.Eventsinterfaces.Holds a slice of
session.Eventpointers to simulate session event history for tests.Provides methods such as
Events(),Len(),At(), andAll()to iterate over events.Other methods return default or empty values as they are not needed for these tests.
Functions and Methods
TestContentsRequestProcessor_IncludeContents(t *testing.T)
Tests the effect of the
IncludeContentsconfiguration on the resultingContentsfield of anLLMRequest.Parameters:
Uses a table-driven approach with test cases specifying:
includeContentsvalue (default,none, or empty string).A slice of
session.Eventto simulate conversation history.Expected
[]*genai.Contentoutput after processing.
Key Scenarios:
Empty event lists produce no content.
Default and empty string settings include all user messages.
"none"excludes some contents, for example, omitting some previous user messages.Foreign agent events are converted to user-context text describing tool calls or messages.
Usage:
Creates an LLM agent with specified
IncludeContents.Creates an invocation context with the agent and a fake session.
Calls
ContentsRequestProcessorand compares output content with expected content usingcmp.Diff.
TestContentsRequestProcessor(t *testing.T)
Tests general behavior of
ContentsRequestProcessorwithout explicitIncludeContentsvariations.Validates filtering by branch, handling of events without content, and foreign agent events.
Test cases include:
Nil and empty event slices.
Events from user and agent with text content.
Events from other agents converted to user-context content.
Branch filtering: only events matching the context branch or its prefixes are included.
Special event filtering such as those containing credential request function calls (excluded).
Uses the same pattern of setting up an agent, context, and fake session, then invoking the processor and asserting results.
TestConvertForeignEvent(t *testing.T)
Focuses on the
ConvertForeignEventfunction fromllminternal.Converts events authored by foreign agents into user-role content with descriptive text.
Tests conversion of:
Text content events.
Function call events (tool calls).
Function response events (tool results).
Validates that the output event has:
Author changed to
"user".Content role set to
"user".Text parts describing the original foreign agent’s action.
TestContentsRequestProcessor_NonLLMAgent(t *testing.T)
Tests that the
ContentsRequestProcessoris a no-op when the agent is not an LLM agent (e.g., a basic agent).Ensures the
LLMRequestremains empty after processing.
TestContentsRequestProcessor_Rearrange(t *testing.T)
The most complex test, validating the correct rearrangement of function call and response sequences in content.
Context:
Some LLM interactions involve multi-step tool calls with intermediate and final results.
The processor must reorder events so that only the final function response is included alongside the initial function call.
Handles mixed scenarios with long-running operations (LRO) and normal calls.
Test data includes:
Basic calls with direct call and response.
Calls with intermediate updates and final completion.
Mixing multiple function calls and responses with varying IDs.
Preservation of mixed text parts intermixed with function calls/responses.
Error case where function response has no matching call event, expecting an error.
Implementation:
Uses helper functions
NewContentFromFunctionCallandNewContentFromFunctionResponseto build content parts.Validates output contents against expected sequences, ensuring proper rearrangement.
NewContentFromFunctionCall(fc *genai.FunctionCall, role string) *genai.Content
Creates a
genai.Contentstruct containing a single function call part.Arguments:
fc: The function call data.role: Role string to assign (e.g.,"model").
Returns:
Pointer to a new
genai.Contentinstance.
Usage:
Used in tests to construct expected content with function calls.
NewContentFromFunctionResponse(fr *genai.FunctionResponse, role string) *genai.Content
Creates a
genai.Contentstruct containing a single function response part.Arguments:
fr: The function response data.role: Role string to assign (e.g.,"user").
Returns:
Pointer to a new
genai.Contentinstance.
Usage:
Used in tests to construct expected content with function responses.
Important Implementation Details
Foreign event conversion: Events authored by agents other than the current agent are converted into user-role content that summarizes the original message or tool call/response. This preserves context for multi-agent scenarios, following a convention of prefixing text with
"For context:"and author attribution.Branch filtering: Events are filtered to include only those matching the current branch or sub-branches, ensuring context relevance.
Function call/response rearrangement: The processor identifies and pairs function calls with their corresponding function responses by call ID. Intermediate responses are filtered out, and only the final response is retained to maintain a coherent function call lifecycle in the content.
Error handling: The processor raises errors when function responses do not have matching function calls, protecting against inconsistent event sequences.
Role assignment: Content parts have roles
"user"or"model"that indicate the source or intended interpretation of the content.Testing with concurrency: Tests use
t.Parallel()where appropriate for concurrent execution of independent test cases.
Interaction with Other System Components
llminternal.ContentsRequestProcessor: The central function under test, which processes session events and populates theContentsfield of anLLMRequest. This function is part of the internal LLM integration pipeline.llmagent: Agent implementation that includes configuration options such asIncludeContentsinfluencing how contents are included.session: Provides event streams that represent the history of interactions, author attributions, branches, timestamps, and LLM responses.genai: Defines core types for content, parts, function calls, and responses used to model LLM outputs and tool interactions.icontext.InvocationContext: Carries contextual information during invocation, such as the current agent, session, and branch, which the processor uses to filter and interpret events.Utilities (
utils.Must): Used to simplify error handling in agent creation during tests.
The file does not itself implement the ContentsRequestProcessor but exercises it extensively with mocks and fake sessions, validating its logic.
Usage Examples
Basic Test Case Example
t.Run("helloAndGoodBye", func(t *testing.T) {
testAgent := utils.Must(llmagent.New(llmagent.Config{
Name: "testAgent",
Model: &testModel{},
IncludeContents: "default",
}))
ctx := icontext.NewInvocationContext(t.Context(), icontext.InvocationContextParams{
Agent: testAgent,
Session: &fakeSession{events: helloAndGoodBye},
})
req := &model.LLMRequest{}
if err := llminternal.ContentsRequestProcessor(ctx, req); err != nil {
t.Fatalf("contentsRequestProcessor failed: %v", err)
}
got := req.Contents
want := []*genai.Content{
genai.NewContentFromText("hello", "user"),
genai.NewContentFromText("good bye", "user"),
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Contents mismatch (-want +got):\n%s", diff)
}
})
Visual Diagram
flowchart TD
Start[Test Function] --> SetupAgent[Create Agent with Config]
SetupAgent --> SetupContext[Create Invocation Context]
SetupContext --> SetupSession[Create Fake Session with Events]
SetupSession --> CallProcessor[Call ContentsRequestProcessor]
CallProcessor --> VerifyOutput[Compare LLMRequest.Contents with Expected]
VerifyOutput --> End[Test Pass/Fail]
subgraph Test Loop
SetupAgent
SetupContext
SetupSession
CallProcessor
VerifyOutput
end
TestCases[Multiple Test Cases] --> Test Loop
This flowchart illustrates the common workflow of test cases in this file:
Each test case sets up an agent configuration.
Creates an invocation context with a session containing events.
Calls the
ContentsRequestProcessor.Verifies the output contents against expected results.