Docs/Foundational Primitives/Chat History & Memory Engine

Chat History & Memory Engine

Large Language Models (LLMs) are stateless by default. To maintain coherent multi-turn conversations, agents require state management that balances context window constraints, latency, storage cost, and long-term user facts.

AgentCore provides a modular memory architecture covering context windowing strategies, pluggable database persistence adapters, UI message converters, self-managed tool memory, and third-party semantic memory integrations (Mem0, Vector DBs).

Memory Pipeline Flow

1. InputUIMessage / Prompt
2. ConvertconvertToModelMessages
3. OptimizeWindow & Token Strategy
4. AugmentFacts & Mem0 RAG
5. PersistStore Sync & onFinish

1. Dual Message Format & UI Conversion

Frontend UI libraries (like Next.js React client components) track message states with UI-specific attributes such as tool invocation progress (state: 'call' | 'result'), attachments, and temporary rendering flags. LLM providers expect strict, standardized AgentMessage role arrays.

The convertToModelMessages() Function

Transforms client UIMessage[] into clean, role-compliant AgentMessage[], automatically formatting tool invocation results into tool-role messages:

converter-usage.ts
1import { convertToModelMessages, type UIMessage, type AgentMessage } from "@bablusingh-dev/agentcore";
2
3// 1. Raw UI messages received from client request
4const uiMessages: UIMessage[] = [
5 {
6 id: "msg-1",
7 role: "user",
8 content: "What's the weather in Tokyo?",
9 createdAt: new Date(),
10 },
11 {
12 id: "msg-2",
13 role: "assistant",
14 content: "",
15 toolInvocations: [
16 {
17 toolCallId: "call_abc123",
18 toolName: "get_weather",
19 args: { city: "Tokyo" },
20 state: "result",
21 result: { temperature: "22°C", condition: "Sunny" },
22 },
23 ],
24 },
25];
26
27// 2. Convert UI state to Model-ready AgentMessage array
28const modelMessages: AgentMessage[] = convertToModelMessages(uiMessages);
29
30console.log(modelMessages);
31/* Output:
32[
33 { id: 'msg-1', role: 'user', content: "What's the weather in Tokyo?", timestamp: 1770417000000 },
34 { id: 'msg-2', role: 'assistant', content: '', toolCalls: [{ id: 'call_abc123', name: 'get_weather', arguments: { city: 'Tokyo' } }] },
35 { role: 'tool', toolCallId: 'call_abc123', name: 'get_weather', content: '{"temperature":"22°C","condition":"Sunny"}' }
36]
37*/

2. Context Window Strategies & Truncation

As multi-turn chats grow, passing full history consumes excessive tokens and risks exceeding the LLM context limit. AgentCore provides four built-in strategy processors:

sliding_window

Sliding Window

Keeps system prompts at the top and retains the last maxMessages turns. Drops oldest turns automatically.

token_window

Token Budget Window

Calculates total estimated tokens and fits recent non-system messages into a strict maxTokens budget from back to front.

summary

Auto-Summarization

When turns exceed summarizeThreshold, older turns are condensed into a summary system message, preserving key context.

full

Full History

Unbounded message retention. Passes all historical turns directly to the provider without trimming.

Configuring Strategies in Agent

strategy-examples.ts
1import { Agent, SlidingWindowMemory, TokenWindowMemory, SummaryMemory } from "@bablusingh-dev/agentcore";
2
3// Option A: Quick string declaration with maxMessages
4const agentSliding = new Agent({
5 model: "openai/gpt-4o",
6 memory: "sliding_window",
7 maxMessages: 12, // Keeps system prompt + last 12 turns
8});
9
10// Option B: Token budget window (e.g. 3,000 token max context budget)
11const agentToken = new Agent({
12 model: "anthropic/claude-3-5-sonnet",
13 memory: "token_window",
14 maxTokens: 3000,
15});
16
17// Option C: Explicit strategy class instantiation
18const agentSummary = new Agent({
19 model: "openai/gpt-4o-mini",
20 memory: new SummaryMemory(10, 4), // Summarize after 10 turns, retain 4 recent turns
21});

3. Persistence Stores & Custom Database Drivers

By default, memory is cached in-RAM via InMemoryStore. For serverless applications, background tasks, or persistent multi-session chats, AgentCore provides file storage and a pluggable MemoryStore interface.

Built-in Stores

built-in-stores.ts
1import { Agent, InMemoryStore, FileMemoryStore } from "@bablusingh-dev/agentcore";
2
3// 1. High-performance In-RAM store (default)
4const inMemoryStore = new InMemoryStore();
5
6// 2. Local File-backed JSON store (Node.js environment)
7const fileStore = new FileMemoryStore("./storage/agent-sessions.json");
8
9const agent = new Agent({
10 model: "openai/gpt-4o",
11 memory: "sliding_window",
12 memoryStore: fileStore,
13});

Building a Custom Database Adapter (Redis / Supabase / PostgreSQL)

Implement the MemoryStore interface to connect Redis, Supabase, MongoDB, or PostgreSQL seamlessly:

redis-memory-store.ts
1import { type MemoryStore, type AgentMessage } from "@bablusingh-dev/agentcore";
2import { Redis } from "@upstash/redis"; // Example Upstash/Redis client
3
4export class RedisMemoryStore implements MemoryStore {
5 private redis: Redis;
6
7 constructor() {
8 this.redis = Redis.fromEnv();
9 }
10
11 async getMessages(sessionId: string): Promise<AgentMessage[]> {
12 const raw = await this.redis.get<AgentMessage[]>(`chat:messages:${sessionId}`);
13 return raw ?? [];
14 }
15
16 async setMessages(sessionId: string, messages: AgentMessage[]): Promise<void> {
17 await this.redis.set(`chat:messages:${sessionId}`, messages);
18 }
19
20 async clearMessages(sessionId: string): Promise<void> {
21 await this.redis.del(`chat:messages:${sessionId}`);
22 await this.redis.del(`chat:facts:${sessionId}`);
23 }
24
25 async getFacts(sessionId: string): Promise<Record<string, string>> {
26 const facts = await this.redis.hgetall(`chat:facts:${sessionId}`);
27 return (facts as Record<string, string>) ?? {};
28 }
29
30 async setFact(sessionId: string, key: string, value: string): Promise<void> {
31 await this.redis.hset(`chat:facts:${sessionId}`, { [key]: value });
32 }
33
34 async deleteFact(sessionId: string, key: string): Promise<void> {
35 await this.redis.hdel(`chat:facts:${sessionId}`, key);
36 }
37}
38
39// Pass custom store to Agent
40const agentWithRedis = new Agent({
41 model: "openai/gpt-4o",
42 memoryStore: new RedisMemoryStore(),
43});

4. Tool-Driven Agentic Memory (Self-Managing Memory)

When enableMemoryTools: true is configured, AgentCore automatically registers type-safe memory tools with the LLM agent:

  • remember_fact(key, value): Allows the model to save user facts or explicit preferences into the facts scratchpad during dialogue.
  • recall_fact(key?): Allows the model to query stored user preferences.
  • forget_fact(key): Deletes an outdated fact.

Stored facts are automatically injected into future prompt turns under a dedicated system prompt block:

agentic-memory-demo.ts
1import { Agent } from "@bablusingh-dev/agentcore";
2
3const agent = new Agent({
4 model: "openai/gpt-4o",
5 systemPrompt: "You are a helpful coding assistant.",
6 memory: "sliding_window",
7 enableMemoryTools: true, // Enables remember_fact, recall_fact, and forget_fact
8 maxSteps: 3, // Allows agent to execute memory tool and respond in 1 call
9});
10
11// Turn 1: User discloses a preference
12const res1 = await agent.run("Hi, remember that I prefer TypeScript and Dark Mode in Next.js.");
13// Agent executes 'remember_fact({ key: "tech_stack", value: "TypeScript, Dark Mode, Next.js" })'
14
15// Turn 2: In a later turn, the agent automatically recalls the saved facts!
16const res2 = await agent.run("Generate a basic button component for me.");
17console.log(res2.text);
18// Output will automatically use TypeScript + Dark mode styling based on saved memory facts!

5. Third-Party Memory Providers (Mem0 & Vector DBs)

Connect external memory engines to retrieve semantic memories and extract facts automatically across multi-session conversations.

Using Mem0Provider

mem0-integration.ts
1import { Agent, Mem0Provider } from "@bablusingh-dev/agentcore";
2
3const mem0Provider = new Mem0Provider({
4 apiKey: process.env.MEM0_API_KEY,
5});
6
7const agent = new Agent({
8 model: "openai/gpt-4o",
9 memoryProvider: mem0Provider,
10});
11
12// Before generation, relevant memories from Mem0 are automatically injected into prompt context.
13// After generation finishes, conversation turns are automatically saved back to Mem0.
14const res = await agent.run("What projects was I working on last week?");

Using VectorMemoryProvider (Semantic Embeddings)

vector-memory.ts
1import { Agent, VectorMemoryProvider } from "@bablusingh-dev/agentcore";
2
3// Connect any vector database (Pinecone, Qdrant, ChromaDB, Weaviate)
4const vectorProvider = new VectorMemoryProvider({
5 search: async (query: string, limit = 5) => {
6 // Perform vector similarity search in your database
7 return ["User built an e-commerce dashboard using AgentCore and Tailwind."];
8 },
9 insert: async (text: string, metadata) => {
10 // Generate vector embedding and store in database
11 },
12});
13
14const agent = new Agent({
15 model: "openai/gpt-4o",
16 memoryProvider: vectorProvider,
17});

6. End-to-End Production Next.js Example

Here is a complete Next.js App Router API Route (app/api/chat/route.ts) combining UI conversion, sliding window memory, tool execution, and server-side persistence callbacks:

app/api/chat/route.ts
1// app/api/chat/route.ts
2import { convertToModelMessages, streamText, FileMemoryStore } from "@bablusingh-dev/agentcore";
3
4const memoryStore = new FileMemoryStore("./storage/sessions.json");
5
6export async function POST(req: Request) {
7 const { messages, sessionId = "user_123" } = await req.json();
8
9 // 1. Convert client UI messages to AgentMessage format
10 const modelMessages = convertToModelMessages(messages);
11
12 // 2. Initiate streaming text generation with memory strategy & persistence
13 const { textStream, response } = streamText({
14 model: "openai/gpt-4o-mini",
15 messages: modelMessages,
16 memory: "sliding_window",
17 memoryStore: memoryStore,
18 enableMemoryTools: true,
19 maxSteps: 3,
20 onFinish: async ({ response, messages }) => {
21 console.log(`[Session ${sessionId}] Usage: ${response.usage?.totalTokens} tokens`);
22 // Optional: Save final context to external analytics / Postgres database
23 },
24 });
25
26 // 3. Return readable stream to client
27 const encoder = new TextEncoder();
28 const readable = new ReadableStream({
29 async start(controller) {
30 for await (const chunk of textStream) {
31 controller.enqueue(encoder.encode(chunk));
32 }
33 controller.close();
34 },
35 });
36
37 return new Response(readable, {
38 headers: { "Content-Type": "text/plain; charset=utf-8" },
39 });
40}

7. Memory API Reference

Agent Memory Configuration (AgentConfig)

OptionTypeDefaultDescription
memory'sliding_window' | 'token_window' | 'summary' | 'full' | IMemoryStrategy'full'Memory strategy processor mode.
maxMessagesnumber20Maximum turn limit for sliding_window mode.
maxTokensnumber4000Max token budget for token_window mode.
memoryStoreMemoryStoreInMemoryStoreStorage driver for message history & facts persistence.
enableMemoryToolsbooleanfalseRegisters remember_fact and recall_fact tools.
memoryProviderMemoryProviderundefinedThird-party memory engine (Mem0, Vector DB) for auto RAG context.