Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vercel/chat/llms.txt

Use this file to discover all available pages before exploring further.

The StateAdapter interface defines the contract for managing persistent state in Chat SDK. State adapters handle thread subscriptions, distributed locking, and caching.

Built-in Implementations

Chat SDK provides three state adapter implementations:

Interface

interface StateAdapter {
  connect(): Promise<void>;
  disconnect(): Promise<void>;
  
  // Subscriptions
  subscribe(threadId: string): Promise<void>;
  unsubscribe(threadId: string): Promise<void>;
  isSubscribed(threadId: string): Promise<boolean>;
  
  // Locking
  acquireLock(threadId: string, ttlMs: number): Promise<Lock | null>;
  releaseLock(lock: Lock): Promise<void>;
  extendLock(lock: Lock, ttlMs: number): Promise<boolean>;
  
  // Caching
  get<T = unknown>(key: string): Promise<T | null>;
  set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void>;
  delete(key: string): Promise<void>;
}

interface Lock {
  threadId: string;
  token: string;
  expiresAt: number;
}

Methods

connect()

Establish connection to the state backend.
await state.connect();
Called automatically by Chat SDK during initialization.

disconnect()

Close connection to the state backend.
await state.disconnect();
Called automatically by Chat SDK during shutdown.

subscribe()

Subscribe to a thread to receive all future messages.
threadId
string
required
The thread ID to subscribe to
await state.subscribe("slack:C123ABC:1234567890.123456");
Subscriptions persist across restarts and are stored indefinitely until explicitly unsubscribed.

unsubscribe()

Unsubscribe from a thread.
threadId
string
required
The thread ID to unsubscribe from
await state.unsubscribe("slack:C123ABC:1234567890.123456");

isSubscribed()

Check if currently subscribed to a thread.
threadId
string
required
The thread ID to check
isSubscribed
boolean
Whether the thread is subscribed
const subscribed = await state.isSubscribed("slack:C123ABC:1234567890.123456");

acquireLock()

Acquire a distributed lock on a thread with a TTL.
threadId
string
required
The thread ID to lock
ttlMs
number
required
Time-to-live in milliseconds
lock
Lock | null
Lock object if acquired, null if already locked
const lock = await state.acquireLock(threadId, 5000); // 5 second lock
if (lock) {
  try {
    // Process message with exclusive access
  } finally {
    await state.releaseLock(lock);
  }
}
Locks prevent concurrent processing of messages in the same thread across multiple instances.

releaseLock()

Release a previously acquired lock.
lock
Lock
required
The lock object to release
await state.releaseLock(lock);

extendLock()

Extend the TTL of an existing lock.
lock
Lock
required
The lock object to extend
ttlMs
number
required
New time-to-live in milliseconds
success
boolean
Whether the lock was successfully extended
const extended = await state.extendLock(lock, 5000);
if (!extended) {
  // Lock expired or was released
}

get()

Retrieve a cached value by key.
key
string
required
Cache key
value
T | null
Cached value or null if not found
const data = await state.get<{ userId: string }>("user:123");

set()

Store a value in cache with optional TTL.
key
string
required
Cache key
value
T
required
Value to cache
ttlMs
number
Optional time-to-live in milliseconds
await state.set("user:123", { userId: "U123", name: "Alice" }, 3600000); // 1 hour

delete()

Delete a cached value by key.
key
string
required
Cache key to delete
await state.delete("user:123");

Implementing a Custom Adapter

To create a custom state adapter:
import type { StateAdapter, Lock } from "chat";

export class MyStateAdapter implements StateAdapter {
  async connect(): Promise<void> {
    // Connect to your backend
  }

  async disconnect(): Promise<void> {
    // Close connections
  }

  async subscribe(threadId: string): Promise<void> {
    // Store subscription
  }

  async unsubscribe(threadId: string): Promise<void> {
    // Remove subscription
  }

  async isSubscribed(threadId: string): Promise<boolean> {
    // Check if subscribed
    return false;
  }

  async acquireLock(threadId: string, ttlMs: number): Promise<Lock | null> {
    // Implement distributed locking
    return null;
  }

  async releaseLock(lock: Lock): Promise<void> {
    // Release the lock
  }

  async extendLock(lock: Lock, ttlMs: number): Promise<boolean> {
    // Extend lock TTL
    return false;
  }

  async get<T>(key: string): Promise<T | null> {
    // Retrieve cached value
    return null;
  }

  async set<T>(key: string, value: T, ttlMs?: number): Promise<void> {
    // Store cached value
  }

  async delete(key: string): Promise<void> {
    // Delete cached value
  }
}

See Also

Build docs developers (and LLMs) love