Transform your LangGraph TypeScript apps from stateless to stateful in minutes with cloud-based persistence.
The Problem: LangGraph apps lose memory between runs. Setting up persistent checkpointers requires database setup, custom implementations, and maintenance overhead.
The Solution: Convo SDK is a drop-in replacement for LangGraph checkpointers that provides cloud-based persistence with zero setup.
npm install convo-sdk @langchain/langgraph @langchain/anthropic
Get your API key: dashboard.convo.diy
Your first persistent LangGraph agent in under 10 lines of code.
import { Convo } from "convo-sdk";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatAnthropic } from "@langchain/anthropic";
// Initialize Convo
const convo = new Convo();
await convo.init({ apiKey: "your-convo-api-key" });
// Create agent with persistent memory
const agent = createReactAgent({
  llm: new ChatAnthropic({ 
	  model: "claude-3-7-sonnet-latest",
	  anthropicApiKey: "your-anthropic-key"
	}),
  tools: [], // Add your tools here
  checkpointer: convo.checkpointer(), // Magic happens here!
});
// Create conversation thread
const threadId = await convo.newThread();
// Chat with memory
const response1 = await agent.invoke(
  { messages: [{ role: "user", content: "Hi, I'm Alice" }] },
  { configurable: { thread_id: threadId } }
);
const response2 = await agent.invoke(
  { messages: [{ role: "user", content: "What's my name?" }] },
  { configurable: { thread_id: threadId } }
);
console.log(response2); // Agent remembers: "Your name is Alice!"
Key Points:
convo.checkpointer()thread_id maintains separate conversation historyHandle multiple users with isolated conversation threads.
import { Convo } from "convo-sdk";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatAnthropic } from "@langchain/anthropic";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
class ChatService {
  private convo: Convo;
  private agent: any;
	private threads: any;
  async initialize() {
    this.convo = new Convo();
    await this.convo.init({ apiKey: "CONVO_API_KEY" });
    // Using convo to create a thread
    this.threads = {
    	"alice": await this.convo.newThread(),
    	"bob": await this.convo.newThread()
    }
    // Create agent with tools
    this.agent = createReactAgent({
      llm: new ChatAnthropic({ model: "claude-3-7-sonnet-latest", apiKey: "ANTHROPIC_API_KEY" }),
      tools: [
        tool(
          async ({ query }: { query: string }) => `Search results for: ${query}`,
          {
            name: "search",
            description: "Search the web",
            schema: z.object({ query: z.string() }),
          }
        ),
      ],
      checkpointer: this.convo.checkpointer(),
    });
  }
  async chat(userId: string, message: string) {
    // Each user gets their own persistent thread
    const threadId = this.threads[userId];
    const result = await this.agent.invoke(
      { messages: [{ role: "user", content: message }] },
      { configurable: { thread_id: threadId } }
    );
		
		console.log(`${userId} asked: ${message}`);
		
    return result.messages[result.messages.length - 1].content;
  }
  async getChatHistory(userId: string) {
    const threadId = `user_${userId}`;
    return await this.convo.getThreadState(threadId);
  }
}
// Usage
const chatService = new ChatService();
await chatService.initialize();
// Alice's conversation
console.log("======================= Alice's conversations ==========================");
const alice_chat_1 = await chatService.chat("alice", "Search for Famous photographers");
console.log(alice_chat_1);
const alice_chat_2 = await chatService.chat("alice", "What did you find?"); // Remembers previous search
console.log(alice_chat_2);
// Bob's separate conversation
console.log("======================= Bob's conversations ==========================");
const bob_chat_1 = await chatService.chat("bob", "Hello, I need help with React");
console.log(bob_chat_1);
// Bob and Alice have completely separate conversation histories
Key Features: