PraisonAI ships a pluggable memory subsystem with providers for mem0, chroma, and mongodb. Now there's a fourth: dakera. Set your agent's memory to "dakera" and it recalls importance-scored memories that decay over time — so stale context stops competing with fresh, relevant facts.
One line to attach memory
The simplest form is env-driven — just name the provider, and it reads config from DAKERA_URL, DAKERA_API_KEY, and DAKERA_AGENT_ID:
from praisonaiagents import Agent
agent = Agent(name="assistant", memory="dakera")
Prefer explicit config? Pass a dict instead — everything the env vars set, inline:
agent = Agent(
name="assistant",
memory={
"provider": "dakera",
"config": {
"url": "http://localhost:3000",
"api_key": "dk-...",
"agent_id": "my-agent", # namespaces this agent's memories
},
},
)
Where it fits among the providers
PraisonAI already abstracts memory behind a provider name, so dakera is interchangeable with the built-ins — same interface, different engine. What it brings is a combination the others don't offer together:
| Provider | Self-hosted | Ranked recall | Short/long tiers |
|---|---|---|---|
| dakera | Yes | Decay-weighted | working / episodic |
| mem0 | Hosted or OSS | Yes | Two tiers |
| chroma | Yes | Vector similarity | Single store |
| mongodb | Yes | Vector similarity | Single store |
A flat vector store returns the nearest neighbours and nothing more — a fact you mentioned once, months ago, competes on equal footing with what the user just said. Dakera's recall is weighted by importance and recency as well as similarity, so relevance keeps pace with the conversation.
Short- and long-term tiers
PraisonAI's two memory tiers map onto distinct Dakera memory types — and both are overridable via config:
| PraisonAI tier | Dakera type | Use it for |
|---|---|---|
| short-term | working | Within-session scratch context — what the user is doing right now |
| long-term | episodic | Durable facts that should survive across sessions |
from praisonaiagents import Memory
memory = Memory(config={"provider": "dakera", "config": {"agent_id": "my-agent"}})
memory.store_short_term("User is asking about Python today", metadata={"session_id": "sess-1"})
memory.store_long_term("User prefers dark mode", importance=0.9, tags=["preference"])
hits = memory.search_long_term("colour preference", limit=5, min_importance=0.7)
Store returns the new memory's id and search returns ranked dicts (id, text, metadata, score, memory_type). importance, tags, and session_id can be passed as explicit kwargs or nested in metadata — the adapter lifts the reserved keys out so they never leak into the stored payload.
Not just store-and-search
The adapter class, DakeraMemoryAdapter, implements PraisonAI's core MemoryProtocol plus two optional ones the built-in stores don't all offer: DeletableMemoryProtocol and ResettableMemoryProtocol. That means you can curate memory, not just accumulate it:
# Prune a single wrong fact, or a batch
memory.delete_memory("mem-42") # -> True
memory.delete_memories(["mem-3", "mem-7"])
# Between tasks: clear scratch context, keep durable knowledge
memory.reset_short_term() # wipes the 'working' tier
memory.reset_long_term() # wipes the 'episodic' tier
Every operation is scoped to the agent's agent_id, so resetting one agent never disturbs another sharing the same server.
How it plugs in
PraisonAI's memory layer is a registry of factory functions keyed by provider string. Dakera registers itself right alongside the others — register_memory_factory("dakera", create_dakera_memory_adapter) — so naming memory="dakera" resolves to a DakeraMemoryAdapter wrapping the SDK's DakeraClient. Ask for it without the SDK installed and you get a clear install hint, not a silent fallback to SQLite. It ships with a unit suite that exercises registration, config, and every operation against a fake SDK — no running server needed.
Zero-config with env vars
Set three environment variables and the provider needs nothing else — attach memory with just the provider name and every field is resolved from the environment (with sensible defaults: http://localhost:3000, and agent_id of praisonai if you leave it unset):
DAKERA_URL=http://localhost:3000
DAKERA_API_KEY=dk-...
DAKERA_AGENT_ID=support-bot
agent = Agent(name="assistant", memory="dakera") # picks up all three
Install
pip install "praisonaiagents[dakera]"
Dakera is an optional extra — it pulls in the dakera SDK (≥ 0.12.8) and leaves the core package and other providers untouched. Run a self-hosted server with docker compose up -d from dakera-deploy.
Why a fourth provider? mem0, chroma, and mongodb are solid, but each is either a hosted service or an unranked vector store. Dakera is self-hosted and decay-weighted — recall is ranked by importance × recency × relevance, the same engine that scores 88.2% Recall@20 on the 1,540-question LoCoMo benchmark. You swap one string and your agents stop drowning in stale context.
What "decay-weighted" buys you
Recall is scored on three axes at once — importance (how much a memory matters), recency (how fresh or how recently used it is), and semantic relevance to the query. A high-importance fact stays retrievable long after it was written; a low-importance aside from three sessions ago quietly loses to what the user said a minute ago. You get this without cron jobs or manual pruning — the ranking simply ages. On the 1,540-question LoCoMo long-conversation benchmark, that engine scores 88.2% Recall@20, and each search result carries its score so you can see exactly why a memory surfaced.
Memory that survives a restart
The point of persistent memory is that a fact captured in one run surfaces in the next — even a completely separate process. Because agent_id namespaces both writes and reads, any agent wired to the same id inherits the same memory:
# ---- Session 1: capture what's durable ----
memory.store_long_term("Alice is on the Pro plan", importance=0.9, tags=["account"])
memory.store_long_term("Alice prefers Rust for backend work", importance=0.8, tags=["preference"])
# ---- Session 2 (new process): recall before answering ----
facts = memory.search_long_term(
"what plan and language does Alice use",
limit=5,
min_importance=0.7,
)
# -> the Pro-plan + Rust memories, ranked by importance × recency × relevance
Shared or isolated, by design
PraisonAI is a multi-agent framework, and memory follows the same agent_id rule everywhere. Give a planner and an executor the same id and they build on a shared pool of recall; give each agent its own id and their memories are fully isolated on the same server. There's no separate provisioning step — the namespace is the id you pass in config (or DAKERA_AGENT_ID), defaulting to praisonai when unset.
planner = Agent(name="planner", memory={"provider": "dakera", "config": {"agent_id": "team-a"}})
executor = Agent(name="executor", memory={"provider": "dakera", "config": {"agent_id": "team-a"}})
# same id -> shared recall; different ids -> isolated
Verified against the source
Everything here is grounded in the merged code, not marketing: the provider string "dakera", the praisonaiagents[dakera] extra pulling in dakera ≥ 0.12.8, the working / episodic tier mapping, the DAKERA_URL / DAKERA_API_KEY / DAKERA_AGENT_ID env fallbacks, and the three protocols the adapter implements.
Full config options, the operation reference, and troubleshooting are on the PraisonAI integration page → The provider was merged in PR #2591. PraisonAI joins Dakera's lineup alongside LangChain, LlamaIndex, CrewAI, AutoGen, Strands, Dify, Agent Squad, and the Vercel AI SDK — see them all on the integrations page →
Give your PraisonAI agents memory that ages
Deploy Dakera in minutes — self-hosted and free. Then point your agent's memory at "dakera".
