Skip to main content

Overview

The ConversationStore is the core abstraction in ff-ai for managing conversation persistence. It provides a provider-agnostic interface that can be implemented with any storage backend.

Interface

The ConversationStore is defined as an Effect Context.Tag with two methods:

Methods

getMessages

Retrieve messages from a conversation thread.
object
required
Parameters for retrieving messages
Effect<ConversationMessage[], StoreError>
An Effect that resolves to an array of messages, ordered chronologically (oldest first)
Window Size Behavior The windowSize parameter controls conversation context:
  • Counts only user messages (not assistant or tool messages)
  • Returns all messages from the Nth most recent user message onward
  • Default is 10 user messages
  • Set to 0 to retrieve no messages
  • The implementation handles cases where fewer messages exist than the window size
Example:

saveMessages

Persist messages to a conversation thread.
object
required
Parameters for saving messages
Effect<void, StoreError>
An Effect that resolves when messages are saved successfully
Example:

Thread Identifier

Both methods accept a ThreadIdentifier which consists of:
This two-level identification allows you to:
  • Organize conversations by resource (user, project, workspace)
  • Have multiple conversation threads per resource
  • Easily query all conversations for a resource

Error Handling

Both methods return an Effect that may fail with StoreError:
Handle errors using Effect operators:

Implementing a Custom Provider

You can implement a custom storage provider by creating a Layer that provides the ConversationStore service:

Built-in Providers

Drizzle Provider

PostgreSQL-backed storage using Drizzle ORM

Best Practices

Larger window sizes provide more context but increase token costs and latency. Start with the default of 10 user messages and adjust based on your use case.
Always handle StoreError in your application logic. Consider fallbacks like returning empty arrays or cached data.
Establish a naming convention for resourceId and threadId early. For example: user-{uuid} and thread-{uuid}.
For very long conversations, the window size mechanism provides automatic pagination based on user messages.

Next Steps

Messages

Learn about message types and utilities

Turn Handler

Use the high-level turn handler API

Drizzle Provider

Set up PostgreSQL storage

Examples

See complete implementations