Recall Storage¶
SessionEventTools implements the MemGPT Recall Storage pattern: the full verbatim
event log is always retained and searchable by keyword, even after context compaction has
pruned older events from the active context window. The agent can surface any prior
exchange on demand rather than relying solely on what fits in the prompt.
Registration¶
// Default page size (EventFilter.DEFAULT_PAGE_SIZE = 10)
SessionEventTools tools = SessionEventTools.builder(sessionService).build();
// Custom page size
SessionEventTools tools = SessionEventTools.builder(sessionService)
.pageSize(20)
.build();
ChatClient client = ChatClient.builder(chatModel)
.defaultTools(tools)
.defaultAdvisors(advisor) // SessionMemoryAdvisor sets chat_memory_session_id
.build();
Tip
Register SessionMemoryAdvisor alongside SessionEventTools. The advisor writes the
chat_memory_session_id context key that the tool uses to resolve the active session.
Without the advisor, the tool falls back to the literal session ID "default".
Tool signature¶
The conversation_search tool is automatically discovered by Spring AI's tool mechanism.
| Parameter | Required | Description |
|---|---|---|
innerThought |
yes | Agent's private reasoning (not returned to the caller) |
query |
yes | Case-insensitive keyword to search for |
page |
no | Zero-indexed result page; defaults to 0; negative values are clamped to 0 |
Results are returned in chronological order as a JSON array:
[
{ "timestamp": "2025-06-01T12:00:00Z", "type": "user", "text": "Tell me about Spring AI" },
{ "timestamp": "2025-06-01T12:00:01Z", "type": "assistant", "text": "Spring AI is a framework..." }
]
When nothing matches: "No results found." is returned.
How it works¶
- Resolves the session ID from
ToolContextusing thechat_memory_session_idkey (the same key written bySessionMemoryAdvisor). If the key is absent or blank, aWARN-level log is emitted and the tool falls back to the literal session ID"default". - Calls
SessionService.getEvents(sessionId, EventFilter.keywordSearch(query, page, pageSize)). EventFilter.matches()applies a case-insensitive substring check on each event'smessage.getText()before pagination is applied.- Returns structured JSON, or
"No results found."when nothing matches.
Synthetic events are searchable
Synthetic summary events produced by RecursiveSummarizationCompactionStrategy are
included in keyword search — their summary text is part of the recall history too.
Pagination¶
Page size defaults to EventFilter.DEFAULT_PAGE_SIZE (10) and is configurable via the
builder (SessionEventTools.builder(sessionService).pageSize(20).build()). Pass
page=1, page=2, … to walk through large histories:
The model can call conversation_search multiple times with incrementing page values to
paginate through the full history until it finds what it needs.