FirestoreConversationStore¶
FirestoreConversationStore is the production-grade Firestore implementation of ConversationStore. It provides collection prefixing, automatic Date/Timestamp conversion, and cascade deletion of messages when a conversation is deleted.
Import¶
Optional Dependency
The @google-cloud/firestore package is loaded lazily. It is only required when FirestoreConversationStore is instantiated. Consumers that use InMemoryConversationStore do not need the Firestore dependency.
Constructor¶
FirestoreConversationStoreConfig¶
interface FirestoreConversationStoreConfig {
projectId?: string;
collectionPrefix?: string;
firestore?: any;
}
| Property | Type | Default | Description |
|---|---|---|---|
projectId | string | -- | GCP project ID for Firestore client construction. Ignored if firestore is provided. |
collectionPrefix | string | "" | Prefix for collection names (e.g. "prod_" produces "prod_conversations"). |
firestore | any | -- | Pre-constructed Firestore instance. Takes priority over projectId. |
Firestore Collection Schema¶
{prefix}conversations/{conversationId} -- Conversation document
{prefix}conversations/{conversationId}/messages/{messageId} -- Message subcollection
Recommended Indexes¶
For the listConversations query with filters, create composite indexes on:
conversations:(userId, updatedAt DESC),(agentName, updatedAt DESC)
Implementation Details¶
Message Ordering¶
getMessages() returns messages ordered by timestamp ascending. When a limit is specified, the store queries in descending order with the limit and then reverses the results in memory. This ensures the most recent N messages are returned in the correct chronological order.
Cascade Deletion¶
deleteConversation() first deletes all messages in the subcollection (Firestore does not cascade subcollection deletes automatically), then deletes the conversation document.
Message Count¶
When addMessage() is called, it reads the current conversation document to get the count, increments it, and writes back. This is eventually consistent but sufficient for denormalized display counts.
Debugging¶
Enable debug logging by setting the DEBUG environment variable:
Error logs are always emitted regardless of the DEBUG setting.
Code Example¶
import { FirestoreConversationStore } from "@modernpath/agent-framework";
// Production setup
const conversationStore = new FirestoreConversationStore({
projectId: "my-gcp-project",
collectionPrefix: "prod_",
});
// Or with a shared Firestore instance
import { Firestore } from "@google-cloud/firestore";
const db = new Firestore({
projectId: "my-gcp-project",
ignoreUndefinedProperties: true,
});
const conversationStore2 = new FirestoreConversationStore({
firestore: db,
collectionPrefix: "staging_",
});
Multi-Environment Configuration¶
import {
InMemoryConversationStore,
FirestoreConversationStore,
ConversationStore,
} from "@modernpath/agent-framework";
function createConversationStore(env: string): ConversationStore {
if (env === "test") {
return new InMemoryConversationStore();
}
return new FirestoreConversationStore({
projectId: process.env.GCP_PROJECT_ID,
collectionPrefix: `${env}_`,
});
}
Usage with Conversation Handler¶
import {
FirestoreConversationStore,
createConversationHandler,
} from "@modernpath/agent-framework";
const conversationStore = new FirestoreConversationStore({
projectId: "my-project",
collectionPrefix: "prod_",
});
const handler = createConversationHandler({
resolveAgent: (name) => agentFactory.resolve(name),
getUserId: (event) => extractUserId(event.headers),
conversationStore,
defaultAgentName: "QAChatAgent",
maxHistoryMessages: 50,
});
Related Pages¶
- ConversationStore Interface -- the interface this class implements
- InMemoryConversationStore -- in-memory alternative for testing
- Serverless / Conversation Handler -- REST endpoints
- Tracing / FirestoreTraceStore -- similar Firestore pattern for traces