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.
npm install @agentdock-ai/agentdock @agentdock-ai/contracts \
@langchain/langgraph langchain @langchain/openrouter zodInstall the LangChain provider and LangGraph checkpointer that your application uses. Agentdock does not configure or manage either one.
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.
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.
MemorySaveris 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_idfor 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, andupdatesstreams. Arbitrary graph output remains application-specific.
See examples/react-agent for a complete
Node server with tools and an approval interrupt.
Requires Node.js 22+ and Yarn:
yarn install
yarn typecheck
yarn build
yarn test
yarn format:checkMIT licensed. Package releases are managed with Changesets.
