Storage API
Storage adapters persist conversation state between interactions.
Available Adapters
| Adapter | Persistence | Best For |
|---|---|---|
MemoryStorage | None | Development, testing |
FileStorage | File-based | Single server, prototypes |
RedisStorage | Redis | Production, distributed |
SQLiteStorage | SQLite | Single server production |
MemoryStorage
In-memory storage. Data is lost when the process ends.
typescript
import { MemoryStorage } from "@andresaya/flowkit";
const storage = new MemoryStorage();WARNING
Only for development. Data is lost on restart.
FileStorage
Persists to JSON files.
typescript
import { FileStorage } from "@andresaya/flowkit";
const storage = new FileStorage({
dir: "./data/conversations",
pretty: true,
});Configuration
typescript
interface FileStorageOptions {
dir: string; // Path to storage directory
extension?: string; // File extension (default: ".json")
pretty?: boolean; // Pretty print JSON (default: false)
}RedisStorage
Persists to Redis. Ideal for production and distributed systems.
typescript
import { RedisStorage } from "@andresaya/flowkit";
import Redis from "ioredis";
const client = new Redis(process.env.REDIS_URL ?? "redis://localhost:6379");
const storage = new RedisStorage({
client,
prefix: "flowkit:",
ttl: 3600, // 1 hour expiry
});Configuration
typescript
interface RedisStorageOptions {
client: RedisClient; // ioredis client instance
prefix?: string; // Key prefix (default: "flowkit:")
ttl?: number; // TTL in seconds (default: 86400)
}SQLiteStorage
Persists to SQLite database.
typescript
import { SQLiteStorage } from "@andresaya/flowkit";
import Database from "better-sqlite3";
const db = new Database("./data/conversations.db");
const storage = new SQLiteStorage({
db,
table: "conversations",
});Configuration
typescript
interface SQLiteStorageOptions {
db: SQLiteDatabase; // better-sqlite3 instance
table?: string; // Table name (default: "conversations")
}StorageAdapter Interface
All adapters implement:
typescript
interface StorageAdapter {
/** Load conversation state */
load(conversationId: string): Promise<ConversationState | null>;
/** Save conversation state */
save(state: ConversationState): Promise<void>;
/** Delete conversation state */
delete(conversationId: string): Promise<void>;
}ConversationState Type
typescript
interface ConversationState {
conversationId: string;
currentStep: string;
slots: Record<string, JsonValue>;
history: Array<{ role: "user" | "assistant"; content: string }>;
ended: boolean;
createdAt: number;
updatedAt: number;
}Custom Storage Adapter
Create your own adapter:
typescript
import { StorageAdapter, ConversationState } from "@andresaya/flowkit";
class PostgresStorage implements StorageAdapter {
constructor(private pool: Pool) {}
async load(conversationId: string): Promise<ConversationState | null> {
const result = await this.pool.query(
"SELECT state FROM conversations WHERE id = $1",
[conversationId]
);
return result.rows[0]?.state ?? null;
}
async save(state: ConversationState): Promise<void> {
await this.pool.query(
`INSERT INTO conversations (id, state, updated_at)
VALUES ($1, $2, NOW())
ON CONFLICT (id) DO UPDATE SET state = $2, updated_at = NOW()`,
[state.conversationId, state]
);
}
async delete(conversationId: string): Promise<void> {
await this.pool.query(
"DELETE FROM conversations WHERE id = $1",
[conversationId]
);
}
}Usage in FlowEngine
typescript
const engine = new FlowEngine(flow, {
llm: adapter,
storage: new RedisStorage({
host: process.env.REDIS_HOST,
ttl: 3600
})
});Accessing State
Through the engine:
typescript
// Get all slots
const slots = await engine.getSlots(sessionId);
// Get specific slot
const name = await engine.getSlot(sessionId, "user_name");
// Set a slot
await engine.setSlot(sessionId, "verified", true);
// Get full state
const state = await engine.getState(sessionId);
// Delete conversation
await engine.delete(sessionId);Best Practices
Choose the Right Storage
- Development:
MemoryStorage - Single server:
FileStorageorSQLiteStorage - Production:
RedisStorage
Set TTL
For Redis, always set a TTL to prevent memory issues:
typescript
new RedisStorage({ ttl: 3600 }) // 1 hourSession IDs
Use meaningful session IDs:
typescript
const sessionId = `user-${userId}-${Date.now()}`;