Persistence Backend Plugins

Add custom conversation, knowledge, and state stores via Python entry points

Register custom storage backends for conversations, knowledge, and state through a central registry.

python
from praisonaiagents import Agent, MemoryConfig
from praisonaiagents import db

agent = Agent(
    name="Assistant",
    instructions="Persist conversations to MySQL",
    memory=MemoryConfig(
        db=db(database_url="mysql://user:pass@localhost:3306/praisonai"),
        session_id="session-1",
    ))
agent.start("Hello — save this conversation")

The user chats with the agent; registered plugins persist conversations, knowledge, and state.

Diagram

🤖 Agent

📝 StoreRegistry

💬 Conversation

📚 Knowledge

🔄 State

📦 Entry Point

Quick Start

  1. Simple Usage

    Use a built-in backend via the registry:

    python
    from praisonai.persistence import create_conversation_store
    
    store = create_conversation_store(
        "mysql",
        url="mysql://user:pass@localhost:3306/praisonai",
    )
  2. With Configuration

    Register a custom backend at runtime:

    python
    from praisonai.persistence import get_default_registry
    
    def my_store_factory(url=None, **kwargs):
        from my_pkg import MyConversationStore
        return MyConversationStore(url=url, **kwargs)
    
    registry = get_default_registry("conversation")
    registry.register("mybackend", my_store_factory, aliases=("mb",))
    store = registry.create("mb", url="proto://host")

    Package it as an entry point in pyproject.toml:

    toml
    [project.entry-points."praisonai.conversation_stores"]
    mybackend = "my_pkg.factory:create_store"

How It Works

Three global registries cover each storage kind:

RegistryEntry-point groupPurpose
CONVERSATION_STORESpraisonai.conversation_storesChat history and sessions
KNOWLEDGE_STORESpraisonai.knowledge_storesVector databases and RAG
STATE_STORESpraisonai.state_storesApplication state and cache
Diagram
StoreFactoryStoreRegistryAppStoreFactoryStoreRegistryAppcreate(“backend”, **kwargs)resolve alias → factoryinstantiatestore instance

Multi-tenant isolation

All three factory functions accept an injected registry= — pass your own StoreRegistry to keep tenant registrations from leaking into the process-default registry.

python
from praisonai.persistence import StoreRegistry, create_conversation_store

def tenant_a_factory(url=None, **kwargs):
    from my_pkg import MyConversationStore
    return MyConversationStore(url=url, **kwargs)

tenant_a = StoreRegistry("conversation", "praisonai.conversation_stores")
tenant_a.register("mystore", tenant_a_factory)

store = create_conversation_store(
    "mystore",
    url="proto://host",
    registry=tenant_a,   # scoped — does not touch the process default
)

Same shape for create_knowledge_store(..., registry=) and create_state_store(..., registry=). See Registry Dependency Injection for the wider pattern.


Configuration Options

StoreRegistry API

MethodSignatureDescription
registerregister(name, factory, *, aliases=())Register a backend factory with optional aliases
createcreate(name, **kwargs)Create a store instance by name or alias
list_registered() -> list[str]All registered backend names
list_aliases() -> dict[str, str]Alias → canonical name mappings
get_default_registryget_default_registry(kind: str) -> StoreRegistryReturn the process-default registry for "conversation" / "knowledge" / "state", building it lazily on first call. Prefer DI (registry=) in library code.

Built-in conversation backends

postgres, async_postgres, mysql, async_mysql, sqlite, sync_sqlite, async_sqlite, json, singlestore, supabase, surrealdb, turso

Common aliases: neon, cockroachdb, crdb → postgres; aiomysql → async_mysql; libsql → turso.

Built-in knowledge backends

chroma, qdrant, pinecone, weaviate, lancedb, milvus, pgvector, redis, cassandra, clickhouse, and others.

Built-in state backends

redis, dynamodb, firestore, mongodb, async_mongodb, upstash, memory, gcs


Best Practices

Use lazy imports in factories

Follow built-in backends — import heavy dependencies inside the factory function, not at module level.

Provide meaningful aliases

Register short aliases (mb, pg) alongside canonical names for easier CLI and config usage.

Handle unknown backends clearly

Factory functions should raise clear errors with connection hints — the registry lists available backends on ValueError.

Keep factories thread-safe

Registries use threading.Lock — factory functions should also be safe for concurrent creation.


Related