Skip to content

Repository files navigation

Agentdock

npm version CI status Node.js 22+ MIT License

The Agentdock class adapts a compiled LangGraph graph to the Agentdock event contract and handles SSE backpressure, client disconnects, and response cleanup. Your application owns routes and calls Agentdock from its route controllers.

LangGraph and LangChain own agent execution, tools, models, checkpoints, interrupts, and resume. Your application owns request parsing, authentication, authorization, trusted thread IDs, side effects, and checkpointer lifecycle.

Install

npm install @agentdock-ai/agentdock @agentdock-ai/contracts \
  @langchain/langgraph langchain @langchain/openrouter zod

Install the LangChain provider and LangGraph checkpointer that your application uses. Agentdock does not configure or manage either one.

Create and serve a graph

import { MemorySaver } from "@langchain/langgraph";
import { ChatOpenRouter } from "@langchain/openrouter";
import { createAgent } from "langchain";
import { withAgentEventState, Agentdock } from "@agentdock-ai/agentdock";

const graph = createAgent({
  model: new ChatOpenRouter({
    model: process.env.OPENROUTER_MODEL ?? "openai/gpt-4o-mini",
    apiKey: process.env.OPENROUTER_API_KEY,
  }),
  tools: [], // Use LangChain tool() to add application tools.
  stateSchema: withAgentEventState({}),
  checkpointer: new MemorySaver(),
  systemPrompt: "You are a helpful assistant.",
});

const runtime = new Agentdock(graph);

withAgentEventState(fields) adds the required agentEventState checkpoint field to your graph schema. It preserves Agentdock's run identity, sequence, and full pending interrupt across requests; LangGraph's checkpointer and thread_id still control graph execution and resumption.

Use withAgentEventState(fields) to include application state, and use getResumeState(threadId) to seed a fresh client from a checkpoint:

import { Agentdock, withAgentEventState } from "@agentdock-ai/agentdock";
import { z } from "zod";

const stateSchema = withAgentEventState({ note: z.string().default("") });
const agent = new Agentdock(graph);
const resumeState = await agent.getResumeState(authorizedThreadId);

getResumeState(threadId) returns null when a checkpoint cannot seed a fresh client. A ready result requires a complete, validated pending interrupt. Hydration restores control state; load conversation history separately. Generated fallback message and tool-call IDs are UUID-based opaque identifiers.

Call Agentdock from your route controller

Your Node.js, Next.js, NestJS, or other framework owns URL routing, request validation, authentication, and authorization. After that, pass the trusted run to Agentdock:

await runtime.pipe(response, {
  threadId: authorizedThreadId,
  input: { messages: [{ role: "user", content: message }] },
  context: { userId: authenticatedUser.id },
});

To resume an interrupted graph, use the same authorized thread ID and pass the resume value expected by the graph or middleware:

await runtime.pipe(response, {
  threadId: authorizedThreadId,
  resume: { decisions: [{ type: "approve" }] },
  context: { userId: authenticatedUser.id },
});

For Node and Express-style response objects, call runtime.pipe(response, run). For Web-standard route handlers, return runtime.toResponse(run). Use runtime.stream(run) when your controller needs to consume events directly. Agentdock does not define URL paths or HTTP request/response envelopes.

Production notes

  • MemorySaver is for local development. Use a LangGraph saver suitable for your deployment and create/close its resources in your application.
  • Use a stable, server-derived thread_id for each conversation and ensure your application handles overlapping requests for the same thread safely.
  • Pass trusted per-request data through context; keep secrets and authorization decisions in the application.
  • The Agentdock event mapper supports documented messages, tools, and updates streams. Arbitrary graph output remains application-specific.

See examples/react-agent for a complete Node server with tools and an approval interrupt.

Development

Requires Node.js 22+ and Yarn:

yarn install
yarn typecheck
yarn build
yarn test
yarn format:check

MIT licensed. Package releases are managed with Changesets.