πΎ Database System
The ElizaOS database system provides persistent storage capabilities for agents. It handles memory storage, entity relationships, knowledge management, and more through a flexible adapter-based architecture.
Overviewβ
ElizaOS uses a unified database architecture based on Drizzle ORM with adapters that implement the IDatabaseAdapter
interface. The current release includes support for:
Adapter | Best For | Key Features |
---|---|---|
PGLite | Local development & testing | Lightweight PostgreSQL implementation running in Node.js process |
PostgreSQL | Production deployments | Full PostgreSQL with vector search, scaling, and high reliability |
Additional database adapters will be supported in future releases as ElizaOS continues to evolve.
Core Functionalityβ
All database adapters extend the BaseDrizzleAdapter
abstract class, which provides a comprehensive set of methods for managing all aspects of agent data:
Entity Systemβ
Method | Description |
---|---|
createEntity() | Create a new entity |
getEntityById() | Retrieve an entity by ID |
getEntitiesForRoom() | Get all entities in a room |
updateEntity() | Update entity attributes |
getComponent() | Get a specific component of an entity |
getComponents() | Get all components for an entity |
createComponent() | Add a component to an entity |
updateComponent() | Update a component |
deleteComponent() | Remove a component |
Memory Managementβ
Method | Description |
---|---|
createMemory() | Store a new memory with metadata |
getMemoryById() | Retrieve a specific memory |
getMemories() | Get memories matching criteria |
getMemoriesByIds() | Get multiple memories by IDs |
getMemoriesByRoomIds() | Get memories from multiple rooms |
searchMemories() | Search memories by vector similarity |
searchMemoriesByEmbedding() | Search using raw embedding vector |
deleteMemory() | Remove a specific memory |
deleteAllMemories() | Remove all memories in a room |
countMemories() | Count memories matching criteria |
Room & Participant Managementβ
Method | Description |
---|---|
createRoom() | Create a new conversation room |
getRoom() | Get room by ID |
getRooms() | Get all rooms in a world |
updateRoom() | Update room attributes |
deleteRoom() | Remove a room |
addParticipant() | Add entity to room |
removeParticipant() | Remove entity from room |
getParticipantsForEntity() | Get all rooms an entity is in |
getParticipantsForRoom() | List entities in a room |
getParticipantUserState() | Get entity's state in a room |
setParticipantUserState() | Update entity's state in a room |
Relationship Managementβ
Method | Description |
---|---|
createRelationship() | Create a relationship between entities |
updateRelationship() | Update relationship attributes |
getRelationship() | Get a specific relationship |
getRelationships() | Get all relationships for an entity |
Caching Systemβ
Method | Description |
---|---|
getCache() | Retrieve cached data |
setCache() | Store data in cache |
deleteCache() | Remove data from cache |
World & Task Managementβ
Method | Description |
---|---|
createWorld() | Create a new world |
getWorld() | Get world by ID |
getAllWorlds() | List all worlds |
updateWorld() | Update world attributes |
removeWorld() | Delete a world |
createTask() | Create a new task |
getTasks() | Get tasks matching criteria |
getTasksByName() | Find tasks by name |
getTask() | Get task by ID |
updateTask() | Update task attributes |
deleteTask() | Remove a task |
Agent Managementβ
Method | Description |
---|---|
createAgent() | Create a new agent record |
getAgent() | Get agent by ID |
getAgents() | List all agents |
updateAgent() | Update agent attributes |
deleteAgent() | Remove an agent |
countAgents() | Count total agents |
Embedding & Searchβ
Method | Description |
---|---|
ensureEmbeddingDimension() | Configure embedding dimensions |
getCachedEmbeddings() | Retrieve cached embeddings |
searchMemories() | Vector search for memories |
searchMemoriesByEmbedding() | Advanced vector search |
Architectureβ
ElizaOS uses a singleton pattern for database connections to ensure efficient resource usage:
βββββββββββββββββββββββββββββββββββββββ
β AgentRuntime β
βββββββββββββββββ¬ββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β IDatabaseAdapter β
βββββββββββββββββ¬ββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β BaseDrizzleAdapter β
βββββββββββββββββ¬ββββββββββββββββββββββ
β
βββββββββ΄ββββββββ
βΌ βΌ
βββββββββββββββββ βββββββββββββββββββ
β PGLiteAdapter β β PostgresAdapter β
βββββββββ¬ββββββββ ββββββββββ¬βββββββββ
β β
βΌ βΌ
βββββββββββββββββ βββββββββββββββββββ
βPGLiteManager β βPostgresManager β
β (Singleton) β β (Singleton) β
βββββββββββββββββ βββββββββββββββββββ
Each adapter is associated with a singleton connection manager that ensures only one database connection is maintained per process, regardless of how many agents are running.
Implementationβ
Initializationβ
The database adapter is initialized through the SQL plugin:
// Plugin registration in project configuration
const project = {
plugins: ['@elizaos/plugin-sql'],
// ...
};
The SQL plugin automatically selects and initializes the appropriate database adapter based on environment settings:
function createDatabaseAdapter(
config: {
dataDir?: string;
postgresUrl?: string;
},
agentId: UUID
): IDatabaseAdapter {
if (config.postgresUrl) {
return new PgDatabaseAdapter(agentId, postgresConnectionManager);
}
// Default to PGLite
return new PgliteDatabaseAdapter(agentId, pgLiteClientManager);
}
Configurationβ
Configure the database adapter using environment variables or settings:
// For PostgreSQL
process.env.POSTGRES_URL = 'postgresql://username:password@localhost:5432/elizaos';
// For PGLite (default)
process.env.PGLITE_DATA_DIR = './elizadb'; // Optional, defaults to './pglite'
Retry Logic & Error Handlingβ
The database system includes built-in retry logic with exponential backoff and jitter:
protected async withRetry<T>(operation: () => Promise<T>): Promise<T> {
let attempt = 0;
let lastError: Error | null = null;
while (attempt < this.maxRetries) {
try {
return await operation();
} catch (error) {
lastError = error as Error;
const isRetryable = this.isRetryableError(error);
if (!isRetryable) {
break;
}
// Calculate delay with exponential backoff and jitter
const delay = Math.min(
this.baseDelay * Math.pow(2, attempt) + Math.random() * this.jitterMax,
this.maxDelay
);
await new Promise(resolve => setTimeout(resolve, delay));
attempt++;
}
}
throw lastError;
}
Example Usageβ
Here are examples of common database operations:
Store a Memoryβ
await runtime.createMemory(
{
entityId: message.entityId,
agentId: runtime.agentId,
content: { text: 'Important information to remember' },
roomId: message.roomId,
embedding: await runtime.useModel(ModelType.TEXT_EMBEDDING, {
text: 'Important information to remember',
}),
},
'facts'
);
Search for Memoriesβ
const embedding = await runtime.useModel(ModelType.TEXT_EMBEDDING, {
text: 'What did we discuss about databases?',
});
const relevantMemories = await runtime.searchMemories({
tableName: 'messages',
embedding,
roomId: message.roomId,
count: 5,
});
Manage Entity Relationshipsβ
// Create a relationship between entities
await runtime.createRelationship({
sourceEntityId: userEntityId,
targetEntityId: agentEntityId,
tags: ['friend', 'frequent_interaction'],
metadata: {
interactions: 42,
trust_level: 'high',
},
});
// Retrieve relationships
const relationships = await runtime.getRelationships({
entityId: userEntityId,
tags: ['friend'],
});
Database Schemaβ
The schema is managed by Drizzle ORM and includes the following key tables:
Core Tablesβ
- entities: The fundamental objects in the system (users, agents, etc.)
- components: Modular data attached to entities (profiles, settings, etc.)
- memories: Conversation history and other remembered information
- relationships: Connections between entities
- rooms: Conversation channels
- participants: Entity participation in rooms
- worlds: Container for multiple rooms
- tasks: Scheduled or queued operations
- cache: Temporary key-value storage
- agents: Agent configuration and state
Entity-Component Systemβ
ElizaOS uses an entity-component architecture where:
- Entities are the base objects (users, agents, etc.)
- Components are pieces of data attached to entities
- This allows for flexible data modeling and extension
For example, a user entity might have profile, preferences, and authentication components.
Vector Searchβ
Both adapters support vector-based semantic search with some differences:
- PostgreSQL: Uses pgvector extension for optimized vector operations
- PGLite: Implements vector search in JavaScript with an efficient algorithm
The embedding dimension is configurable based on the model used:
await adapter.ensureEmbeddingDimension(1536); // For OpenAI embeddings
FAQβ
How do I choose between PGLite and PostgreSQL?β
-
Use PGLite for:
- Local development and testing
- Single-user deployments
- Situations where installing PostgreSQL is impractical
-
Use PostgreSQL for:
- Production deployments
- Multi-user systems
- High-volume data
- When you need advanced scaling features
How do I configure the database connection?β
For PostgreSQL, set the POSTGRES_URL
environment variable:
POSTGRES_URL=postgresql://username:password@localhost:5432/elizaos
For PGLite, set the data directory (optional):
PGLITE_DATA_DIR=./my-data
How can I inspect the database contents?β
For PostgreSQL, use standard PostgreSQL tools like pgAdmin or psql.
For PGLite, the data is stored in the specified data directory as files. You can use tools like DB Browser for SQLite to inspect the SQLite files that PGLite generates.
How do I migrate between different database adapters?β
Currently, there's no built-in migration tool between adapters. For production systems, it's recommended to start with PostgreSQL if you anticipate needing its features.
What about vector embedding dimension mismatches?β
The system automatically handles embedding dimensions based on the model used. If you change embedding models, make sure to:
- Set the correct dimension with
ensureEmbeddingDimension()
- Be aware that mixing different dimensions in the same database can cause issues
How does the entity-component system work?β
The entity-component system (ECS) provides a flexible way to model data:
- Entities are base objects with unique IDs
- Components are pieces of data attached to entities
- This allows for dynamic composition of objects without complex inheritance
For example, a user entity might have profile, preferences, and authentication components.
How can I improve database performance?β
-
For PostgreSQL:
- Ensure the pgvector extension is properly installed
- Index frequently queried fields
- Use connection pooling
- Consider partitioning for large datasets
-
For PGLite:
- Keep database size reasonable (under 1GB)
- Regularly clean up old memories
- Limit the number of concurrent operations
Will other database adapters be supported in the future?β
Yes, future releases will add support for additional databases such as:
- MongoDB
- SQLite
- Supabase
- Qdrant
- SQL.js
The adapter interface is designed to be extensible to support a wide range of storage solutions.