Custom AI Stores & Adapters
PURISTA provides abstract interfaces for memory and knowledge, allowing you to plug in any storage engine (Redis, PostgreSQL, Pinecone, etc.).
1. Custom Conversation Store
A ConversationStore is responsible for persisting the chat transcript. To build your own, implement the ConversationStore interface.
ts
import {
ConversationStore,
ConversationStoreRecord,
type ConversationStoreScope,
} from '@purista/ai'
export class MyCustomStore implements ConversationStore {
async load(
conversationId: string,
scope?: ConversationStoreScope,
): Promise<ConversationStoreRecord | undefined> {
// 1. conversationId is the logical session id, for example "chat-42"
// 2. scope carries tenant/principal/agent isolation metadata
}
async save(record: ConversationStoreRecord, scope?: ConversationStoreScope): Promise<void> {
// 3. Persist using record.conversationId + scope as your compound key
}
async delete(conversationId: string, scope?: ConversationStoreScope): Promise<void> {
// 4. Cleanup using the same logical id + scope
}
}Important:
conversationIdis no longer pre-scoped by the runtime. It is the raw logical conversation/session id.- The runtime passes isolation metadata in
scope, currentlytenantId,principalId,agentName, andagentVersion. - Custom stores should either use that full scope as part of their compound key or ignore only the fields they intentionally do not support.
2. Custom Knowledge Adapter
A KnowledgeAdapter handles document retrieval (RAG). It must support multi-tenant scoping.
ts
import { KnowledgeAdapter, KnowledgeQueryRequest, KnowledgeDocument } from '@purista/ai'
export class MyVectorStoreAdapter implements KnowledgeAdapter {
async query(request: KnowledgeQueryRequest): Promise<KnowledgeDocument[]> {
const { query, limit, scope } = request
// 1. Filter by scope (tenantId, principalId, agentName, agentVersion, sessionId)
// 2. Perform vector search
// 3. Return top-N documents
}
async upsert(request: KnowledgeUpsertRequest): Promise<void> {
// 4. Ingest new knowledge with correct scope
}
}3. Why the interface pattern?
By following the interface pattern:
- Your business logic (agent handler) remains independent of the storage engine.
- You can switch from an in-memory test store to a production-grade database with a single line of code in your bootstrap.
- PURISTA handles the scope metadata forwarding automatically before calling your store or adapter.
