Interface IStorageAdapter

Core storage adapter interface for AgentOS persistence.

Implementations of this interface provide the actual storage mechanism (SQL database, NoSQL, in-memory, etc.) while AgentOS remains storage-agnostic.

Design Principles:

  • All methods are async for non-blocking I/O
  • Returns null when entities don't exist (not throwing errors)
  • Uses strong typing for compile-time safety
  • Supports transaction-like batch operations
  • Designed for multi-user scenarios (userId scoping)

Lifecycle:

  1. Instantiate adapter with configuration
  2. Call initialize() to set up database/schema
  3. Use CRUD operations during runtime
  4. Call close() when shutting down (optional cleanup)

IStorageAdapter

Example

// Example implementation instantiation
const storage: IStorageAdapter = new SqlStorageAdapter({
type: 'better-sqlite3',
database: './agentos.db'
});

await storage.initialize();

// Create conversation
const conversation = await storage.createConversation({
id: 'conv-123',
userId: 'user-456',
createdAt: Date.now(),
lastActivity: Date.now()
});

// Store message
await storage.storeMessage({
id: 'msg-001',
conversationId: 'conv-123',
role: 'user',
content: 'Hello!',
timestamp: Date.now()
});

// Query messages
const messages = await storage.getMessages('conv-123', { limit: 10 });
interface IStorageAdapter {
    initialize(): Promise<void>;
    close(): Promise<void>;
    createConversation(conversation): Promise<IConversation>;
    getConversation(conversationId): Promise<null | IConversation>;
    updateConversation(conversationId, updates): Promise<IConversation>;
    deleteConversation(conversationId): Promise<boolean>;
    listConversations(userId, options?): Promise<IConversation[]>;
    storeMessage(message): Promise<IConversationMessage>;
    getMessage(messageId): Promise<null | IConversationMessage>;
    getMessages(conversationId, options?): Promise<IConversationMessage[]>;
    deleteMessage(messageId): Promise<boolean>;
    deleteMessagesForConversation(conversationId): Promise<number>;
    getMessageCount(conversationId): Promise<number>;
    getConversationTokenUsage(conversationId): Promise<ITokenUsage>;
}

Implemented by

Methods

  • Initializes the storage adapter.

    This should:

    • Establish database connections
    • Create necessary tables/schemas if they don't exist
    • Run migrations if needed
    • Validate configuration

    Must be called before any other methods.

    Returns Promise<void>

    Resolves when initialization is complete

    Throws

    If initialization fails (connection errors, invalid config, etc.)

    Example

    const storage = new SqlStorageAdapter(config);
    await storage.initialize(); // Sets up database schema
  • Closes the storage adapter and releases resources.

    This should:

    • Close database connections
    • Flush any pending writes
    • Clean up temporary resources

    Call during application shutdown for graceful cleanup.

    Returns Promise<void>

    Resolves when cleanup is complete

    Example

    process.on('SIGTERM', async () => {
    await storage.close();
    process.exit(0);
    });
  • Creates a new conversation record.

    Parameters

    Returns Promise<IConversation>

    The created conversation (may include defaults)

    Throws

    If conversation with same ID already exists or validation fails

    Example

    const conversation = await storage.createConversation({
    id: uuidv4(),
    userId: 'user-123',
    agentId: 'agent-coding',
    createdAt: Date.now(),
    lastActivity: Date.now(),
    title: 'New coding project'
    });
  • Retrieves a conversation by its ID.

    Parameters

    • conversationId: string

      The unique conversation identifier

    Returns Promise<null | IConversation>

    The conversation or null if not found

    Example

    const conv = await storage.getConversation('conv-123');
    if (conv) {
    console.log('Found:', conv.title);
    }
  • Updates an existing conversation's metadata.

    Only provided fields will be updated. Omitted fields remain unchanged.

    Parameters

    • conversationId: string

      The conversation to update

    • updates: Partial<IConversation>

      Fields to update

    Returns Promise<IConversation>

    The updated conversation

    Throws

    If conversation doesn't exist

    Example

    // Update title and last activity
    const updated = await storage.updateConversation('conv-123', {
    title: 'Renamed conversation',
    lastActivity: Date.now()
    });
  • Deletes a conversation and all its messages.

    Warning: This is a destructive operation that cannot be undone. Consider implementing soft deletes in production.

    Parameters

    • conversationId: string

      The conversation to delete

    Returns Promise<boolean>

    True if deleted, false if not found

    Example

    const deleted = await storage.deleteConversation('conv-123');
    if (deleted) {
    console.log('Conversation deleted successfully');
    }
  • Lists all conversations for a specific user.

    Results are typically ordered by lastActivity (most recent first).

    Parameters

    • userId: string

      The user whose conversations to retrieve

    • Optional options: {
          limit?: number;
          offset?: number;
          agentId?: string;
      }

      Optional filtering/pagination

      • Optional limit?: number

        Maximum conversations to return

      • Optional offset?: number

        Number of conversations to skip

      • Optional agentId?: string

        Filter by specific agent

    Returns Promise<IConversation[]>

    Array of conversations

    Example

    // Get user's 20 most recent conversations
    const conversations = await storage.listConversations('user-123', {
    limit: 20
    });

    // Get conversations for specific agent
    const codingConvs = await storage.listConversations('user-123', {
    agentId: 'agent-coding'
    });
  • Stores a new message in a conversation.

    Note: This also updates the parent conversation's lastActivity timestamp.

    Parameters

    Returns Promise<IConversationMessage>

    The stored message

    Throws

    If conversation doesn't exist or validation fails

    Example

    await storage.storeMessage({
    id: uuidv4(),
    conversationId: 'conv-123',
    role: 'user',
    content: 'Explain async/await',
    timestamp: Date.now()
    });
  • Retrieves a single message by its ID.

    Parameters

    • messageId: string

      The unique message identifier

    Returns Promise<null | IConversationMessage>

    The message or null if not found

    Example

    const msg = await storage.getMessage('msg-456');
    if (msg) {
    console.log(`[${msg.role}]: ${msg.content}`);
    }
  • Retrieves all messages for a conversation with optional filtering.

    This is the primary method for loading conversation history.

    Parameters

    • conversationId: string

      The conversation to query

    • Optional options: IMessageQueryOptions

      Query options for filtering/pagination

    Returns Promise<IConversationMessage[]>

    Array of messages matching criteria

    Example

    // Get all messages (oldest first)
    const allMessages = await storage.getMessages('conv-123');

    // Get last 50 messages (newest first)
    const recent = await storage.getMessages('conv-123', {
    limit: 50,
    order: 'desc'
    });

    // Get only assistant responses from last hour
    const assistantRecent = await storage.getMessages('conv-123', {
    roles: ['assistant'],
    since: Date.now() - 3600000
    });
  • Deletes a specific message.

    Note: This does NOT update the conversation's lastActivity timestamp.

    Parameters

    • messageId: string

      The message to delete

    Returns Promise<boolean>

    True if deleted, false if not found

    Example

    const deleted = await storage.deleteMessage('msg-456');
    
  • Deletes all messages in a conversation.

    Warning: Destructive operation. Consider soft deletes in production.

    Parameters

    • conversationId: string

      The conversation whose messages to delete

    Returns Promise<number>

    Number of messages deleted

    Example

    const deletedCount = await storage.deleteMessagesForConversation('conv-123');
    console.log(`Deleted ${deletedCount} messages`);
  • Counts total messages in a conversation.

    Useful for pagination and UI indicators.

    Parameters

    • conversationId: string

      The conversation to count

    Returns Promise<number>

    Total message count

    Example

    const count = await storage.getMessageCount('conv-123');
    console.log(`This conversation has ${count} messages`);
  • Calculates total token usage for a conversation.

    Sums up all message usage statistics.

    Parameters

    • conversationId: string

      The conversation to analyze

    Returns Promise<ITokenUsage>

    Aggregated token usage

    Example

    const usage = await storage.getConversationTokenUsage('conv-123');
    console.log(`Total tokens: ${usage.totalTokens}`);
    console.log(`Cost estimate: $${usage.totalTokens * 0.00001}`);