PRAISONAI · PYTHON

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.

Package: 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_type field, so the two PraisonAI tiers map onto distinct memory types (working and episodic) 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, and mongodb.
HOW DAKERA MEMORY FLOWS THROUGH A PRAISONAI AGENT User turn the new message Dakera recall rank by importance × recency × relevance → top-K memories PraisonAI agent the dakera provider recalls and stores short/long-term memories injected → LLM Reply write-back: the new exchange is stored for next time

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

1

Run Dakera

git clone https://github.com/dakera-ai/dakera-deploy
cd dakera-deploy && docker compose up -d   # API on :3000
2

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.

3

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:

OptionTypeDefaultEnv fallback
url / base_urlstrhttp://localhost:3000DAKERA_URL, then DAKERA_API_URL
api_keystrNoneDAKERA_API_KEY
agent_idstrpraisonaiDAKERA_AGENT_ID
short_term_typestrworking
long_term_typestrepisodic
default_importancefloat0.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 tierDakera memory_typeConfig keyUse it for
short-termworkingshort_term_typeWithin-session scratch context — what the user is doing right now
long-termepisodiclong_term_typeDurable facts that should survive across sessions
Recall that ages. Whichever tier you query, hits are ranked by importance × recency × semantic relevance — the same engine that scores 88.2% Recall@20 on the 1,540-question LoCoMo benchmark — so stale context stops competing with fresh facts.

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
ArgumentTypeEffect
textstrThe content to store. Embedded server-side — no local embedding call.
importancefloatScore for this memory. Falls back to metadata["importance"], then default_importance (0.5).
tagslist[str]Labels for filtering. Also accepted via metadata["tags"].
session_idstrGroups a memory under a session. Also accepted via metadata["session_id"].
metadatadictArbitrary 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 methodDakeraClient call
store_short_term / store_long_termstore_memory(agent_id, content, memory_type, importance, metadata, session_id, tags)
search_short_term / search_long_termrecall(agent_id, query, top_k, memory_type, min_importance)
get_all_memoriesbatch_recall(BatchRecallRequest(agent_id, limit))
delete_memoryforget(agent_id, memory_id)
reset_short_term / reset_long_termbatch_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.

ProviderSelf-hostedRanked recallShort/long tiersDelete / reset
dakeraYesDecay-weightedworking / episodicYes / Yes
mem0Hosted or OSSYesTwo tiersVaries
chromaYesVector similaritySingle storeDelete only
mongodbYesVector similaritySingle storeDelete 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

  1. The dakera provider is a client for the self-hosted Dakera server — memory content and queries never leave it.
  2. store_short_term / store_long_term embed content server-side and persist it under agent_id, tagged by tier — short-term as working, long-term as episodic.
  3. search_* runs a hybrid semantic + keyword query and ranks hits by importance × recency × relevance.
  4. Recall decays by access pattern, so frequently-used facts stay prominent and stale ones fade — no manual pruning.

Related integrations

Links

Troubleshooting

SymptomCause & fix
ImportError mentioning dakeraThe 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 / timeoutsThe 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 resultsReads 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 searchThe 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 payloadThey 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.

Self-Host Free → Join Cloud Waitlist →

Give your AI agents persistent memory

Self-host free today — or join the Dakera Cloud waitlist for managed hosting, SLA & founder pricing.

✓ You're on the list. We'll be in touch.