Skip to main content

Overview

ff-ai is an AI conversation management SDK built on top of the Vercel AI SDK with first-class Effect.ts integration. It provides type-safe, functional patterns for managing AI conversations, messages, and model usage costs.

Key Features

Installation

bun add ff-ai

Peer Dependencies

The SDK requires the following peer dependencies:
bun add effect @effect/platform ai @ai-sdk/provider valibot @ai-sdk/valibot
For the Drizzle provider:
bun add drizzle-orm postgres

Quick Start

Here’s a simple example of using ff-ai with the Drizzle provider:
import { ConversationStore, createTurnHandler } from 'ff-ai';
import { createDrizzleStoreLayer } from 'ff-ai/providers/drizzle';
import { Effect } from 'effect';
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import postgres from 'postgres';

// Set up database connection
const sql = postgres(process.env.DATABASE_URL!);
const storeLayer = createDrizzleStoreLayer(sql);

// Use the turn handler
const program = Effect.gen(function* () {
  const handler = yield* createTurnHandler({
    identifier: {
      resourceId: 'user-123',
      threadId: 'conversation-456'
    }
  });

  // Get conversation history
  const history = yield* handler.getHistory({ windowSize: 10 });

  // Save user message
  yield* handler.saveUserMessage({
    role: 'user',
    content: 'Hello!'
  });

  // Generate response and save automatically
  const result = yield* Effect.tryPromise(() =>
    generateText({
      model: openai('gpt-4'),
      messages: [
        ...history,
        { role: 'user', content: 'Hello!' }
      ],
      onStepFinish: async (step) => {
        await handler.onStep(step).pipe(Effect.runPromise);
      }
    })
  );

  return result;
});

// Run the program
await program.pipe(
  Effect.provide(storeLayer),
  Effect.runPromise
);

Core Concepts

Effect.ts Integration

All operations in ff-ai are Effect-based, providing:
  • Type-safe error handling: Errors are part of the type signature
  • Composability: Chain operations using Effect operators
  • Dependency injection: Use Effect’s Context for services
  • Resource management: Automatic cleanup with structured concurrency

Thread Identifiers

Conversations are identified by a combination of:
  • resourceId: The resource or user the conversation belongs to
  • threadId: A unique identifier for the conversation thread
This two-level structure allows you to organize conversations by user, project, or any other resource.

Message Format

Messages extend the AI SDK’s ModelMessage type with:
  • id: UUID v7 identifier
  • createdAt: Timestamp for ordering and retrieval

Architecture

┌─────────────────────────────────────────┐
│         Your Application                │
├─────────────────────────────────────────┤
│         createTurnHandler               │
├─────────────────────────────────────────┤
│       ConversationStore (Interface)     │
├─────────────────────────────────────────┤
│     Provider (Drizzle, Custom, etc.)    │
├─────────────────────────────────────────┤
│         Database / Storage              │
└─────────────────────────────────────────┘

Next Steps