The MemoryBuilder provides a simplified, unified interface for managing conversation memory, working memory, and session state in ADK agents.
Overview
Unified Memory provides:
- Simplified API - Single interface for sessions, memory, and state
- Working memory - Maintain evolving context across conversations
- Message format - Simple message objects instead of complex Content types
- Session management - Create, list, and manage user sessions
- Memory search - Search across conversation history
- Auto-persistence - Automatically sync to memory services
Quick Start
import { MemoryBuilder } from "@iqai/adk";
// Create memory builder
const memory = MemoryBuilder.create({
appName: "my-app",
userId: "user-123",
lastMessages: 10, // Keep last 10 messages in context
workingMemory: {
enabled: true,
template: "Current context: none",
},
});
// Create a session
const session = await memory.createSession();
// Add messages
await memory.addMessage(session, {
role: "user",
content: "Hello!",
});
await memory.addMessage(session, {
role: "assistant",
content: "Hi! How can I help?",
});
// Recall conversation
const messages = await memory.recall(session.id);
console.log(messages);
// [
// { role: "user", content: "Hello!" },
// { role: "assistant", content: "Hi! How can I help?" }
// ]
Configuration
UnifiedMemoryConfig
interface UnifiedMemoryConfig {
/** Application name */
appName: string;
/** User ID */
userId: string;
/** Number of recent messages to include (false = all messages) */
lastMessages?: number | false;
/** Working memory configuration */
workingMemory?: WorkingMemoryConfig;
}
interface WorkingMemoryConfig {
/** Enable working memory */
enabled: boolean;
/** Initial template for working memory */
template?: string;
}
Default Configuration
const defaultConfig = {
lastMessages: 10, // Last 10 messages
workingMemory: {
enabled: false,
},
};
Unified Memory uses simple message objects:
interface SimpleMessage {
role: "user" | "assistant" | "system";
content: string;
}
This is much simpler than ADK’s native Content type, making it easier to work with conversation history.
Session Management
Creating Sessions
// Create new session
const session = await memory.createSession();
// Create with initial state
const sessionWithState = await memory.createSession({
userName: "Alice",
preferences: { theme: "dark" },
});
// Create with specific ID
const specificSession = await memory.createSession(
{ userName: "Bob" },
"session-123"
);
Retrieving Sessions
// Get specific session
const session = await memory.getSession("session-123");
if (session) {
console.log("Session state:", session.state);
}
// List all sessions
const { sessions, cursor } = await memory.listSessions();
console.log("User has", sessions.length, "sessions");
Deleting Sessions
await memory.deleteSession("session-123");
Ending Sessions
// Mark session as ended and persist to memory
const endedSession = await memory.endSession("session-123");
Adding Messages
Simple Messages
await memory.addMessage(session, {
role: "user",
content: "What's the weather?",
});
await memory.addMessage(session, {
role: "assistant",
content: "It's sunny and 72°F.",
});
ADK Events
You can also add full ADK Event objects:
import { Event } from "@iqai/adk";
const event = new Event({
author: "my-agent",
content: {
role: "model",
parts: [{ text: "Here's my response..." }],
},
});
await memory.addEvent(session, event);
Recalling Conversations
Recall as Simple Messages
const messages = await memory.recall("session-123");
// Returns SimpleMessage[]
messages.forEach(msg => {
console.log(`${msg.role}: ${msg.content}`);
});
Recall as Events
const events = await memory.recallEvents("session-123");
// Returns Event[]
events.forEach(event => {
console.log(event.author, event.text);
});
Both methods respect the lastMessages configuration.
Working Memory
Working memory is a special piece of context that evolves over time:
const memory = MemoryBuilder.create({
appName: "my-app",
userId: "user-123",
workingMemory: {
enabled: true,
template: "User preferences: none set yet",
},
});
const session = await memory.createSession();
// Get current working memory
const current = await memory.getWorkingMemory(session.id);
console.log(current); // "User preferences: none set yet"
// Update working memory
await memory.updateWorkingMemory(
session,
"User preferences: dark mode, notifications enabled"
);
// Next time it's retrieved, it has the updated value
const updated = await memory.getWorkingMemory(session.id);
console.log(updated); // "User preferences: dark mode, notifications enabled"
Use Cases for Working Memory
User Preferences
await memory.updateWorkingMemory(
session,
"User: Alice. Preferences: concise responses, code examples preferred"
);
Current Task Context
await memory.updateWorkingMemory(
session,
"Working on: Building a REST API. Stack: Node.js + Express + PostgreSQL"
);
Conversation Summary
await memory.updateWorkingMemory(
session,
"Summary: User is planning a trip to Japan in March. Interested in temples and food."
);
Memory Search
Search across all conversations (requires a MemoryService):
import { VertexAIMemoryService } from "@iqai/adk";
const memoryService = new VertexAIMemoryService({
corpusName: "my-corpus",
projectId: process.env.GCP_PROJECT_ID!,
location: "us-central1",
});
const memory = MemoryBuilder.create({
appName: "my-app",
userId: "user-123",
})
.withMemoryService(memoryService);
// Search across conversations
const results = await memory.search("trip to Japan");
results.forEach(result => {
console.log("Found:", result.content);
console.log("Relevance:", result.score);
});
Custom Services
Use custom session and memory services:
import {
PostgresSessionService,
VertexAIMemoryService
} from "@iqai/adk";
const memory = MemoryBuilder.create({
appName: "my-app",
userId: "user-123",
})
.withSessionService(
new PostgresSessionService({ connectionString: "..." })
)
.withMemoryService(
new VertexAIMemoryService({ corpusName: "my-corpus" })
);
Integration with Agents
While MemoryBuilder simplifies memory management, agents still use the native Session and Event types. Convert between formats:
import { AgentBuilder, MemoryBuilder } from "@iqai/adk";
const memory = MemoryBuilder.create({
appName: "my-app",
userId: "user-123",
lastMessages: 5,
});
// Use the session service from MemoryBuilder
const { runner } = await AgentBuilder
.create("assistant")
.withModel("gpt-4")
.withSessionService(memory.getSessionService())
.build();
// Create or get session
const session = await memory.createSession();
// Add user message via MemoryBuilder
await memory.addMessage(session, {
role: "user",
content: "Hello!",
});
// Run agent (it will see the conversation history)
const events = await runner.run({
userId: "user-123",
sessionId: session.id,
newMessage: { parts: [{ text: "What can you help with?" }] },
});
// Store agent response
const lastEvent = events[events.length - 1];
await memory.addEvent(session, lastEvent);
// Recall as simple messages
const messages = await memory.recall(session.id);
console.log("Conversation:", messages);
Advanced Example: Chatbot with Working Memory
import { AgentBuilder, MemoryBuilder } from "@iqai/adk";
const memory = MemoryBuilder.create({
appName: "chatbot",
userId: "user-123",
lastMessages: 10,
workingMemory: {
enabled: true,
template: "No context yet.",
},
});
const { runner } = await AgentBuilder
.create("chatbot")
.withModel("gpt-4")
.withSessionService(memory.getSessionService())
.withInstruction(`
You are a helpful assistant.
Working Memory (context that persists):
{{workingMemory}}
Update working memory when you learn important information about the user.
`)
.build();
async function chat(sessionId: string, userMessage: string) {
const session = await memory.getSession(sessionId)
|| await memory.createSession();
// Get working memory
const workingMemory = await memory.getWorkingMemory(session.id) || "";
// Add user message
await memory.addMessage(session, {
role: "user",
content: userMessage,
});
// Run agent with working memory in context
const events = await runner.run({
userId: "user-123",
sessionId: session.id,
newMessage: {
parts: [{ text: userMessage }]
},
state: { workingMemory },
});
const response = events[events.length - 1].text || "";
// Store assistant response
await memory.addMessage(session, {
role: "assistant",
content: response,
});
// Check if agent wants to update working memory
// (You could use structured output or parse the response)
if (response.includes("[UPDATE_MEMORY:")) {
const match = response.match(/\[UPDATE_MEMORY: (.+?)\]/);
if (match) {
await memory.updateWorkingMemory(session, match[1]);
}
}
return response;
}
// Usage
await chat("session-1", "My name is Alice");
// Agent responds and updates working memory: "User name: Alice"
await chat("session-1", "I prefer dark mode");
// Agent responds and updates: "User name: Alice. Preferences: dark mode"
await chat("session-1", "What's my name?");
// Agent responds: "Your name is Alice" (from working memory)
Comparison with Standard Memory
| Feature | MemoryBuilder | Standard Memory |
|---|
| API Complexity | Simple, high-level | More granular control |
| Message Format | SimpleMessage | Content + Parts |
| Working Memory | Built-in | Manual implementation |
| Session Management | Simplified | Direct session service |
| Use Case | Quick prototyping, simple apps | Complex memory patterns |
Best Practices
Set reasonable lastMessages - Don’t load entire conversation history. Use 5-20 recent messages for context.
Update working memory strategically - Only update when important context changes (user preferences, current task, etc.).
Use memory search sparingly - Memory search can be slow. Cache results or use for specific queries only.
End sessions properly - Call endSession() to persist final state to memory services.
Combine with standard memory - MemoryBuilder is built on top of standard memory services. Mix and match as needed.
See Also