Overview
Memory gives agents the ability to remember. Without it, everyagent.run() is a blank slate. With it, agents maintain conversation history, learn user preferences, track entities, remember decisions, and build knowledge graphs.
All memory features share a single storage backend and are configured through the memory field on AgentConfig.
Quick Start
UnifiedMemoryConfig
The complete memory configuration. Onlystorage is required — everything else is opt-in.
Reading the So when the table says
boolean | XConfig types. Several features (like summaries, userFacts, entities) accept a value of type boolean | SomeConfig. That’s a union — it means you have three ways to set each one:boolean | EntityConfig, both entities: true and entities: { namespace: "acme" } are valid — true is simply a shorthand for “turn it on, use the defaults.” Pass the config object only when you want to change a default. This is why you’ll see both forms throughout the examples.(Features that always need a backend — learnings needs a vectorStore, graph needs a GraphStore — take only a config object, not a boolean, because there’s no sensible default without that backend.)Memory Architecture
Memory is not a single store — it’s a layered subsystem with one orchestrator coordinating up to nine specialized stores over a shared storage backend.The memory lifecycle
Everyagent.run() wraps the LLM call with two memory phases:
-
Before the run — Context Assembly.
MemoryManager.buildContext()reads every enabled store, ranks the results, fits them within the token budget, and injects the result into the system prompt. Each block is wrapped in a<memory section="…" scope="current_user">sentinel so the LLM never conflates one store’s data with another’s. -
After the run — Background Extraction.
MemoryManager.afterRun()fires (non-blocking) and runs up to six parallel extractions against the last 6 turns of the conversation: user facts, profile, entities, learnings, graph, procedures. Failures emitmemory.errorevents rather than failing silently.
The stores
The same
memory config works identically across Agent, VoiceAgent, and BrowserAgent. The only difference: voice agents load context once at session start (not per turn), because the realtime session is persistent.
Sessions and History
Sessions are the foundation. Everyagent.run() with a sessionId appends messages to a persistent history.
maxMessages is exceeded: The oldest messages are removed from the session. If summaries is enabled (the default), those removed messages are first summarized so the context isn’t lost entirely.
Token-based trimming: Instead of counting messages, you can limit by tokens:
Summaries
Default: ON. When session history overflowsmaxMessages, the overflow messages are summarized by the LLM and stored. These summaries are injected into the system prompt on future runs so the agent remembers older context.
SummaryConfig
Understanding the options:
maxCountcaps how many “recap notes” exist for a single long conversation. Each overflow event creates one summary. More summaries = longer memory of the conversation’s arc, but older ones eventually drop off. Lower it for short-lived chats; raise it for long-running threads (support cases that span weeks).maxTokensis the budget for how much of those summaries gets injected into the prompt. This directly affects cost — every run pays for these tokens. Lower it (e.g.1000) to save money; raise it (e.g.4000) when the conversation history is rich and the agent needs more of it.
User Facts
Default: OFF. Automatically extracts persistent facts about the user from conversations: preferences, location, profession, interests, communication style. Facts are stored peruserId and injected into the system prompt on every run for that user, across all sessions.
UserFactsConfig
Understanding
maxFacts:
This is the ceiling on how much the agent remembers about one person. When a user accumulates more facts than this, the framework keeps the most important and recent ones (not just the newest — a high-importance fact like “allergic to peanuts” outranks a trivial recent one).
- Default
100is plenty for most consumer apps. - Lower it (e.g.
30) to keep prompts lean and costs down when you only care about a handful of key preferences. - Raise it (e.g.
300) for power users or B2B accounts where the agent benefits from deep history. Higher values mean more storage and slightly larger prompts.
- “User prefers dark mode”
- “User is a software engineer in Mumbai”
- “User’s favorite language is TypeScript”
invalidatedAt is set) and the new one takes over. Each invalidation records a reason:
"superseded"— a newer fact about the same subject replaced it (e.g. “moved to Berlin” supersedes “lives in Mumbai”). Superseded facts disappear silently — they are never shown to the model."forgotten"— the user explicitly asked the agent to forget the fact (e.g. “forget my birthday”). Forgotten facts are surfaced in a dedicated “the user asked you to forget these” block so the model knows not to restate them, andrecall_user_factswill not return them.
timezone config. Without it, a user near midnight gets the wrong date. Recurring events (birthdays, anniversaries) are stored without a year unless the user states one explicitly.
User Profile
Default: OFF. A structured profile object with built-in fields (name, role, timezone, language) plus custom fields. More structured than user facts.UserProfileConfig
Understanding
customFields:
The profile always tracks four built-in fields automatically: name, role, timezone, language. customFields lets you add your own domain-specific fields the extractor will look for.
- It’s a whitelist — the agent can only populate the fields you list. It can’t invent a
salaryfield unless you ask for it. This keeps the profile clean and predictable. - Use it for structured attributes your product cares about:
"company","plan"(free/pro/enterprise),"department","accountTier". - Don’t use it for free-form preferences (“likes dark mode”) — those belong in User Facts, which is unstructured by design.
Entity Memory
Default: OFF. Extracts companies, people, projects, and products mentioned in conversations. Each entity has facts, events, and relationships.EntityConfig
Understanding
namespace:
Entities are always scoped to the user who created them (privacy). namespace adds a second, orthogonal partition on top of that — think of it as which “team workspace” the entities belong to.
- Leave it
"global"(default) if you have one product and don’t need to separate entity sets. Simplest, works for most apps. - Set a per-tenant namespace (
"acme","meridian") when one deployment serves multiple organizations and you want each org’s entity knowledge kept in its own bucket. - Use a hierarchical path (
"acme/engineering","acme/sales") when you want sub-divisions within a tenant — e.g. the engineering team’s “Stripe” entity shouldn’t mix with the finance team’s.
- Entity: “Stripe” (type: company) — facts: [“Payment processor”, “Used for billing”]
- Entity: “Raj” (type: person) — facts: [“Frontend engineer”, “Works on checkout”]
Decision Log
Default: OFF. Records what the agent decided and why. Useful for auditing and learning from past decisions.DecisionConfig
Understanding
maxContextDecisions:
Every decision the agent logs is stored permanently (you can always search the full history with the search_decisions tool). This setting only controls how many of the most recent decisions are automatically shown to the agent at the start of each run, so it stays consistent with what it decided before.
- Lower it (e.g.
3) to save prompt tokens, or if recent decisions aren’t very relevant to the next one. - Raise it (e.g.
10) for agents that need strong continuity — e.g. a negotiation or approval agent that should remember its recent rulings to avoid contradicting itself. - It does not limit how many decisions are stored — only how many are surfaced in context. Storage is unlimited.
log_decision, record_outcome, and search_decisions tools automatically.
Learned Knowledge
Default: OFF. Vector-backed insights that the agent learns over time. Requires a vector store for semantic search.LearningsConfig
Understanding the options:
vectorStoreis required because learnings are recalled by meaning, not exact match — that needs a vector index (Qdrant, Pinecone, in-memory, etc.). This is whylearningstakes a config object, not justtrue: there’s no default backend.collectionis the named bucket within that store. Change it only if you run multiple agents that should keep their learnings in separate collections within the same vector database.topKcontrols how many learnings are pulled into the prompt per run. Higher = the agent considers more accumulated knowledge but spends more tokens and risks diluting focus.3is a good default; raise to5–8for knowledge-heavy agents (research, support playbooks), lower to1–2for tight token budgets.
Graph Memory
Default: OFF. A knowledge graph where entities are connected by typed, directed relationships. Enables the agent to answer questions that require traversing relationships (e.g., “Who works with Raj?”).GraphMemoryConfig
Understanding the options:
storeis required — the graph needs somewhere to live. UseInMemoryGraphStorefor development andNeo4jGraphStorefor production (persistent, queryable at scale).autoExtract: true(default) means the agent automatically builds the graph as people talk (“Raj works at Acme” → createsRaj —works_at→ Acme). Set it tofalseif you want to build the graph manually via tools and avoid the extra extraction LLM call per turn.maxContextNodescaps how much of the graph is summarized into the prompt. Higher = the agent sees more of the relationship web (better for “who connects to whom” questions) but uses more tokens. Raise it for richly-connected domains (org charts, supply chains); keep it low otherwise.
Procedural Memory
Default: OFF. Records successful multi-step tool workflows and suggests them when similar tasks arise.ProceduresConfig
Understanding
maxProcedures:
Each procedure is a learned, reusable playbook (“to do X, call these tools in this order”). This caps how many the agent keeps. When the limit is hit, the least-used / oldest procedures are dropped first, so frequently-successful workflows survive.
- Default
50suits most agents — they only repeat a handful of distinct workflows. - Raise it (e.g.
200) for agents that handle many distinct repeatable tasks (a broad ops agent). - Lower it if you want the agent to only retain its few most-proven workflows.
Scope Hierarchy
Most memory is personal — “User prefers dark mode” belongs to one user. But some knowledge is genuinely shared: a workflow like “how to reconcile an invoice with a PO mismatch” belongs to a whole team, and a policy like “refunds over $500 need VP approval” belongs to the whole organization. Learnings and Procedures support an explicit four-level scope so shared knowledge isn’t trapped in one user’s silo:
Reads union all accessible scopes. When Alice (user) talks to the
invoice-recon agent at tenant acme, a recall_procedure / search_learnings call returns her personal items plus the agent’s shared items plus the tenant’s items plus globals — but never another user’s personal scope.
Writes pick one scope. The save_learning tool exposes a scope parameter so the model can promote an insight to the team or org level:
Context Budget
Controls how the memory context string is distributed across sections when injected into the system prompt.ContextBudgetConfig
Understanding the options:
Once you enable several memory types, their combined context can grow large.
contextBudget is the spending limit for that combined block and the rule for who gets priority when it overflows.
maxTokens— the ceiling for the entire memory section of the prompt. Without it, every enabled store is injected in full (fine for small setups, risky once you have many). Set it to keep prompts predictable, e.g.4000.priorities— when the stores together exceedmaxTokens, higher-weighted sections are kept and lower ones are trimmed or dropped first. Weights are relative, not absolute —{ summaries: 3, userFacts: 2, entities: 1 }means summaries get roughly half the budget, facts a third, entities a sixth. Valid keys:"summaries","userProfile","userFacts","entities","decisions","graph","procedures". Any section you don’t list uses its sensible default weight.
Tuning by use case: a support agent might favorsummaries(conversation continuity); a research agent might favorlearnings; a CRM agent might favoruserFacts+entities. Bump the weight of whatever matters most for your job.
Using a Cheaper Model for Extraction
All background extraction (summaries, facts, entities, profiles) uses the agent’s primary model by default. This can be expensive. Setmodel to use a cheaper model:
Full-Featured Example
Every option enabled:Observability
Memory mutations and failures emit typed events on the agent’sEventBus. The most important is memory.error — without it, a broken extractor (malformed LLM JSON, an unreachable embedding service) fails silently and you only find out weeks later when a user complains.
These flow into @agentium/observability (OpenTelemetry, Prometheus, Langfuse) with no extra wiring.
Multi-Tenant Example
A single agent serving many organizations. Personal facts stay private; tenant policies are shared org-wide.Debugging Memory Context
If the model seems to “forget” something, inspect exactly whatbuildContext produced:
agentName).
When to Enable What
Storage Options
Thestorage field accepts any StorageDriver. Choose based on your needs: