PraisonAI Integration
Dakera is a first-class memory provider for PraisonAI — a drop-in "dakera" backend alongside mem0, chroma, and mongodb. Point your agent's memory at Dakera and it gets persistent, importance-scored recall that decays over time, with short- and long-term tiers.
praisonaiagents[dakera] · provider "dakera" · adapter DakeraMemoryAdapter · SDK dakera ≥ 0.12.8 · Docs → · Source PR →Overview
PraisonAI is a multi-agent framework whose memory subsystem is protocol-driven: every backend is a small adapter registered by name, so an agent asks for memory by a provider string and the framework wires up the right adapter behind the scenes. Out of the box it ships adapters for mem0, chroma, and mongodb. The Dakera integration (merged in PR #2591) adds a fourth, registered under the key "dakera".
The adapter, DakeraMemoryAdapter, wraps the Dakera SDK's DakeraClient and implements PraisonAI's MemoryProtocol. Because Dakera is a self-hosted memory server rather than a flat vector store, the adapter also implements two optional protocols the built-in stores don't all offer — DeletableMemoryProtocol and ResettableMemoryProtocol — giving you targeted deletion and per-tier resets on top of store and search.
When to use the Dakera provider
- You want your agent's memory to stay on your own infrastructure. Dakera is self-hosted — memory content and queries never leave your server, and there is no cloud key to manage.
- You want recall that ages. Dakera ranks hits by importance × recency × semantic relevance, so stale context stops out-competing fresh facts without any manual pruning.
- You want a real short/long-term split. Dakera has a first-class
memory_typefield, so the two PraisonAI tiers map onto distinct memory types (workingandepisodic) instead of one undifferentiated pool. - You're already on PraisonAI. Swapping to Dakera is a one-string change — no agent code changes — because it slots into the same provider abstraction as
mem0,chroma, andmongodb.
PraisonAI’s memory layer calls the Dakera provider to recall ranked context before the agent responds and to persist new facts after — short-term mapped to working memory, long-term to episodic.
Quick Start
Run Dakera
git clone https://github.com/dakera-ai/dakera-deploy
cd dakera-deploy && docker compose up -d # API on :3000
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.
Configure
export DAKERA_URL="http://localhost:3000"
export DAKERA_API_KEY="dk-..."
export DAKERA_AGENT_ID="my-agent"
Attach memory to an agent
The simplest form is env-driven — just name the provider:
from praisonaiagents import Agent
agent = Agent(name="assistant", memory="dakera")
Or configure it 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
},
},
)
Configuration reference
The adapter reads config from either a flat dict or a nested {"config": {…}} form (mirroring the mem0 adapter), then falls back to environment variables, then to built-in defaults. Every field:
| Option | Type | Default | Env fallback |
|---|---|---|---|
url / base_url | str | http://localhost:3000 | DAKERA_URL, then DAKERA_API_URL |
api_key | str | None | DAKERA_API_KEY |
agent_id | str | praisonai | DAKERA_AGENT_ID |
short_term_type | str | working | — |
long_term_type | str | episodic | — |
default_importance | float | 0.5 | — |
url and base_url are aliases for the same server URL — the adapter tries url first, then base_url. agent_id namespaces every write and read, so two agents that share an id share memory, and two that differ are fully isolated.
Tier mapping
Dakera exposes a first-class memory_type field, so PraisonAI's two tiers map onto distinct Dakera types rather than one flat pool. Both are overridable via short_term_type / long_term_type:
| PraisonAI tier | Dakera memory_type | Config key | Use it for |
|---|---|---|---|
| short-term | working | short_term_type | Within-session scratch context — what the user is doing right now |
| long-term | episodic | long_term_type | Durable facts that should survive across sessions |
Memory operations
The Memory facade forwards to the adapter, which implements three protocols. You can drive it directly for full control:
from praisonaiagents import Memory
memory = Memory(config={"provider": "dakera", "config": {"agent_id": "my-agent"}})
# --- MemoryProtocol: store ---
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"])
# --- MemoryProtocol: search (ranked, per-tier) ---
recent = memory.search_short_term("Python", limit=5)
durable = memory.search_long_term("colour preference", limit=5, min_importance=0.7)
Store — signatures and arguments
store_short_term writes to the working tier and store_long_term to episodic; both return the new memory's id as a string.
store_short_term(text: str, metadata: dict | None = None, **kwargs) -> str
store_long_term (text: str, metadata: dict | None = None, **kwargs) -> str
| Argument | Type | Effect |
|---|---|---|
text | str | The content to store. Embedded server-side — no local embedding call. |
importance | float | Score for this memory. Falls back to metadata["importance"], then default_importance (0.5). |
tags | list[str] | Labels for filtering. Also accepted via metadata["tags"]. |
session_id | str | Groups a memory under a session. Also accepted via metadata["session_id"]. |
metadata | dict | Arbitrary payload. The reserved keys importance, tags, and session_id are lifted out (explicit kwargs win) so they never leak into the stored blob. |
Search — signatures and result shape
search_short_term(query: str, limit: int = 5, **kwargs) -> list[dict]
search_long_term (query: str, limit: int = 5, **kwargs) -> list[dict]
Pass min_importance to drop low-value hits before ranking. limit becomes the server-side top_k. Each result is normalised to a consistent dict:
{
"id": "mem-42",
"text": "User prefers dark mode",
"metadata": {"...": "..."},
"score": 0.87, # importance × recency × relevance
"memory_type": "episodic",
}
Enumerate — get every memory for the agent
get_all_memories pages through the agent's memories without needing a query embedding (default limit=1000):
everything = memory.get_all_memories(limit=500) # list[dict], same shape as search
Delete — DeletableMemoryProtocol
delete_memory (memory_id: str, memory_type: str | None = None) -> bool
delete_memories(memory_ids: list[str]) -> int
delete_memory forgets one memory and returns True on success (a failed delete is logged and returns False rather than raising). delete_memories forgets a batch and returns the count actually removed.
Reset — ResettableMemoryProtocol
reset_short_term() -> None # clears the 'working' tier for this agent
reset_long_term() -> None # clears the 'episodic' tier for this agent
Each reset performs a filtered batch-forget scoped to one memory_type and this agent_id — so you can wipe scratch context between tasks while leaving durable knowledge intact.
How the provider slots into PraisonAI
PraisonAI's memory layer is a registry of factory functions keyed by provider string. The Dakera integration registers itself exactly like the built-in backends:
# praisonaiagents/memory/adapters/__init__.py
register_memory_factory("mem0", create_mem0_memory_adapter)
register_memory_factory("chroma", create_chroma_memory_adapter)
register_memory_factory("mongodb", create_mongodb_memory_adapter)
register_memory_factory("dakera", create_dakera_memory_adapter) # ← added in PR #2591
When you name memory="dakera", PraisonAI looks up create_dakera_memory_adapter, which lazily imports the dakera SDK and returns a DakeraMemoryAdapter wrapping a DakeraClient. The factory is also wired into the explicit-provider path in Memory._init_protocol_driven_memory(), so asking for dakera without the SDK installed raises a clear install hint instead of silently falling back to SQLite.
Under the hood
Each protocol method maps to a single Dakera SDK call — the adapter is a thin, predictable translation layer:
| Adapter method | DakeraClient call |
|---|---|
store_short_term / store_long_term | store_memory(agent_id, content, memory_type, importance, metadata, session_id, tags) |
search_short_term / search_long_term | recall(agent_id, query, top_k, memory_type, min_importance) |
get_all_memories | batch_recall(BatchRecallRequest(agent_id, limit)) |
delete_memory | forget(agent_id, memory_id) |
reset_short_term / reset_long_term | batch_forget(BatchForgetRequest(agent_id, filter=BatchMemoryFilter(memory_type))) |
The integration ships with a unit suite (tests/unit/memory/test_dakera_adapter.py) that injects a fake dakera module to exercise registration, config resolution, tier mapping, and every operation end-to-end — no running server required.
Drop-in with the other providers
Because PraisonAI abstracts memory behind a provider name, dakera is interchangeable with the built-in mem0, chroma, and mongodb backends — you swap one string, not your agent code. What Dakera adds on top is the combination the others don't offer together: self-hosted operation (no data leaves your server, no cloud key) and decay-weighted recall — importance × recency × semantic relevance, so stale context stops out-competing fresh facts. It's the same engine that scores 88.2% Recall@20 on the 1,540-question LoCoMo benchmark.
| Provider | Self-hosted | Ranked recall | Short/long tiers | Delete / reset |
|---|---|---|---|---|
dakera | Yes | Decay-weighted | working / episodic | Yes / Yes |
mem0 | Hosted or OSS | Yes | Two tiers | Varies |
chroma | Yes | Vector similarity | Single store | Delete only |
mongodb | Yes | Vector similarity | Single store | Delete only |
Full example — persist and recall across sessions
The Memory API works standalone, so you can capture durable facts in one run and surface them in another — the point of persistent memory:
from praisonaiagents import Memory
memory = Memory(config={"provider": "dakera", "config": {"agent_id": "support-bot"}})
# ---- 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"])
memory.store_short_term("Currently debugging a serialization bug", metadata={"session_id": "s1"})
# ---- 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
Because the same agent_id namespaces both writes and reads, any agent you wire to that id inherits the same memory.
Managing memory over time
The delete and reset protocols let you curate what an agent remembers — prune a single wrong fact, clear scratch context between tasks, or wipe a tier entirely without touching the other:
from praisonaiagents import Memory
memory = Memory(config={"provider": "dakera", "config": {"agent_id": "support-bot"}})
# Remove one memory that turned out wrong
mid = memory.store_long_term("Alice is on the Free plan") # oops — she upgraded
memory.delete_memory(mid) # -> True
# Prune a batch by id
removed = memory.delete_memories(["mem-3", "mem-7", "mem-9"]) # -> count deleted
# Between tasks: clear working scratch, keep durable knowledge
memory.reset_short_term() # wipes the 'working' tier for this agent
# Full teardown of long-term knowledge for this agent
memory.reset_long_term() # wipes the 'episodic' tier for this agent
Every operation is scoped to the adapter's agent_id, so resetting one agent never disturbs another sharing the same server.
Environment reference
The adapter resolves configuration in order: explicit config keys → environment variables → defaults. A typical .env for a self-hosted deployment:
# .env
DAKERA_URL=http://localhost:3000 # or DAKERA_API_URL
DAKERA_API_KEY=dk-... # optional for local, required if the server enforces auth
DAKERA_AGENT_ID=support-bot # namespace; defaults to "praisonai" if unset
With those set you can attach memory with nothing but the provider name — Agent(name="assistant", memory="dakera") — and every field is picked up from the environment.
How it works
- The
dakeraprovider is a client for the self-hosted Dakera server — memory content and queries never leave it. store_short_term/store_long_termembed content server-side and persist it underagent_id, tagged by tier — short-term asworking, long-term asepisodic.search_*runs a hybrid semantic + keyword query and ranks hits by importance × recency × relevance.- Recall decays by access pattern, so frequently-used facts stay prominent and stale ones fade — no manual pruning.
Related integrations
Links
- PraisonAI docs — Dakera memory
- Source PR — MervinPraison/PraisonAI #2591
- Dakera deploy — Docker Compose setup
- All integrations
Troubleshooting
| Symptom | Cause & fix |
|---|---|
| ImportError mentioning dakera | The SDK isn't installed. Run pip install "praisonaiagents[dakera]" (or pip install dakera). Naming dakera explicitly surfaces this hint by design rather than falling back to SQLite. |
| Connection refused / timeouts | The Dakera server isn't reachable. Confirm it's running (docker compose up -d) and that url / DAKERA_URL points at it — the default is http://localhost:3000. |
| Empty recall results | Reads and writes must share an agent_id. If you didn't set one, both default to praisonai; a typo'd or mismatched id isolates the namespaces. Also check min_importance isn't filtering everything out. |
| Short-term hits in long-term search | The tiers are separate memory_types. search_long_term only queries episodic; use get_all_memories to see both, or search_short_term for working. |
| Reserved keys in stored payload | They won't be — importance, tags, and session_id are lifted out of metadata before storage. Pass them as explicit kwargs for clarity; kwargs take precedence over metadata. |
Frequently Asked Questions
How do I use Dakera memory in PraisonAI?
Install praisonaiagents[dakera], run a self-hosted Dakera server, then set your agent's memory to "dakera" (or a config dict with provider: "dakera"). It works like the built-in mem0, chroma, and mongodb providers.
Does PraisonAI support short- and long-term memory with Dakera?
Yes. The short-term tier maps to Dakera's working memory type and long-term to episodic, both overridable via short_term_type / long_term_type. Store and search each tier independently, with importance and tag filters.
Which memory protocols does the adapter implement?
DakeraMemoryAdapter implements PraisonAI's core MemoryProtocol (store and search), plus the optional DeletableMemoryProtocol (delete_memory / delete_memories) and ResettableMemoryProtocol (reset_short_term / reset_long_term).
Can I point two agents at the same memory?
Yes. Memory is namespaced by agent_id. Give two agents the same id and they share recall; give them different ids and they're fully isolated. Unset, it defaults to praisonai (or DAKERA_AGENT_ID).
Does Dakera send my data to a cloud service?
No. The provider is a client for a self-hosted Dakera server. Content is embedded server-side and both memories and queries stay on infrastructure you control — there's no cloud key.
Is Dakera required to use PraisonAI?
No — it's an optional extra. Installing praisonaiagents[dakera] adds the Dakera provider (SDK dakera ≥ 0.12.8) without affecting the core package or other memory backends.
Ready to ship?
Deploy Dakera in minutes — self-hosted and free. Cloud managed hosting coming soon.
Give your AI agents persistent memory
Self-host free today — or join the Dakera Cloud waitlist for managed hosting, SLA & founder pricing.