DEV Community

Alex Spinov
Alex Spinov

Posted on

LangGraph.js Has a Free API: Build Stateful AI Agents in TypeScript

LangGraph.js is LangChain's framework for building stateful, multi-actor AI agent applications — and its API lets you create complex agent workflows with cycles, persistence, and human-in-the-loop patterns.

Why LangGraph.js Matters

Most AI agent frameworks are linear chains: input → LLM → output. Real-world agents need loops, branching, memory, and error recovery. LangGraph.js models agents as graphs with state machines.

What you get for free:

  • Stateful graph execution with automatic checkpointing
  • Cycles and loops (agents that can retry, reflect, and improve)
  • Built-in persistence (SQLite, PostgreSQL, or custom stores)
  • Human-in-the-loop: pause execution, get approval, resume
  • Streaming support for real-time agent responses
  • TypeScript-first with full type safety

Quick Start

import { StateGraph, Annotation } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";

// Define state shape
const AgentState = Annotation.Root({
  messages: Annotation<BaseMessage[]>({
    reducer: (prev, next) => [...prev, ...next],
  }),
  nextStep: Annotation<string>(),
});

// Create the model
const model = new ChatOpenAI({ model: "gpt-4o" });

// Define nodes
async function callModel(state: typeof AgentState.State) {
  const response = await model.invoke(state.messages);
  return { messages: [response] };
}

async function shouldContinue(state: typeof AgentState.State) {
  const lastMessage = state.messages[state.messages.length - 1];
  if (lastMessage.additional_kwargs?.tool_calls) {
    return "tools";
  }
  return "end";
}

// Build the graph
const graph = new StateGraph(AgentState)
  .addNode("agent", callModel)
  .addNode("tools", toolExecutor)
  .addEdge("__start__", "agent")
  .addConditionalEdges("agent", shouldContinue, {
    tools: "tools",
    end: "__end__",
  })
  .addEdge("tools", "agent")
  .compile();

// Run
const result = await graph.invoke({
  messages: [{ role: "user", content: "Research the latest AI news" }],
});
Enter fullscreen mode Exit fullscreen mode

Persistence: Resume Agents After Crashes

import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";

const checkpointer = SqliteSaver.fromConnString("./agent_state.db");

const graph = new StateGraph(AgentState)
  .addNode("agent", callModel)
  .compile({ checkpointer });

// Run with thread ID — state is automatically saved
const config = { configurable: { thread_id: "user-123" } };
await graph.invoke({ messages: [userMessage] }, config);

// Later: resume from exact state
const state = await graph.getState(config);
console.log("Resumed from:", state.values.messages.length, "messages");
Enter fullscreen mode Exit fullscreen mode

Human-in-the-Loop

const graph = new StateGraph(AgentState)
  .addNode("agent", callModel)
  .addNode("tools", toolExecutor)
  .compile({
    checkpointer,
    interruptBefore: ["tools"], // Pause before tool execution
  });

// Agent runs until it hits tools node, then pauses
const result = await graph.invoke(input, config);
// result.next === ["tools"] — waiting for approval

// Approve and continue
await graph.invoke(null, config); // Resumes from checkpoint
Enter fullscreen mode Exit fullscreen mode

Multi-Agent Collaboration

const researchAgent = createReactAgent({ llm: model, tools: [searchTool] });
const writerAgent = createReactAgent({ llm: model, tools: [writeTool] });

const multiAgent = new StateGraph(TeamState)
  .addNode("researcher", researchAgent)
  .addNode("writer", writerAgent)
  .addNode("supervisor", supervisorNode)
  .addEdge("__start__", "supervisor")
  .addConditionalEdges("supervisor", routeToAgent)
  .addEdge("researcher", "supervisor")
  .addEdge("writer", "supervisor")
  .compile();
Enter fullscreen mode Exit fullscreen mode

Useful Links


Building AI-powered data pipelines? Check out my developer tools on Apify for ready-made web scrapers, or email spinov001@gmail.com for custom solutions.

Top comments (0)