npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@macrow/copilotkit-langgraph-history

v0.1.7

Published

Open-source CopilotKit + LangGraph chat history persistence. Restore thread history on page refresh.

Readme

copilotkit-langgraph-history

This is a temporary fork of xxx. PR submitted: https://github.com/clickspider/copilotkit-langgraph-history/pull/3

npm version License: MIT TypeScript

Open-source LangGraph thread history persistence for CopilotKit. Restore chat history on page refresh with your own LangGraph deployment.

The Problem

Building a chat app with CopilotKit and LangGraph? You've probably noticed:

  • Page refresh = empty chat - All messages disappear
  • Thread switching loses context - No automatic history restoration
  • No persistence of agent state - Users lose context

CopilotKit's default runtime doesn't automatically fetch historical messages from LangGraph's checkpoint system. This package adds that capability.

The Solution

With this package:

  • Chat history restored on page load
  • Seamless thread switching
  • Agent state preserved
  • Works with any LangGraph deployment (LangGraph Cloud, self-hosted)
  • MIT licensed, open-source

Installation

npm install copilotkit-langgraph-history
# or
pnpm add copilotkit-langgraph-history
# or
yarn add copilotkit-langgraph-history

Peer Dependencies

This package requires the following peer dependencies:

npm install @copilotkit/runtime @copilotkitnext/runtime @ag-ui/core @langchain/langgraph-sdk rxjs

Quick Start

Next.js App Router

// app/api/copilotkit/route.ts
import { CopilotRuntime, createCopilotEndpointSingleRoute } from "@copilotkit/runtime/v2";
import {
  HistoryHydratingAgentRunner,
  createIsolatedAgent,
} from "copilotkit-langgraph-history";

const deploymentUrl = process.env.LANGGRAPH_DEPLOYMENT_URL!;
const langsmithApiKey = process.env.LANGSMITH_API_KEY;
const graphId = "my-agent";

function createRuntime() {
  // Create isolated agent (prevents serverless state contamination)
  const agent = createIsolatedAgent({
    deploymentUrl,
    graphId,
    langsmithApiKey,
    onRequest: (_url, initReq) => {
      initReq.headers = { ...initReq.headers, Authorization: 'Bearer authToken' };
      return initReq;
    },
  });

  // Create history-hydrating runner
  const runner = new HistoryHydratingAgentRunner({
    agent,
    deploymentUrl,
    graphId,
    langsmithApiKey,
    historyLimit: 100, // Max messages to load
    onRequest: (_url, initReq) => {
      initReq.headers = { ...initReq.headers, Authorization: 'Bearer authToken' };
      return initReq;
    },
  });

  return new CopilotRuntime({
    agents: { [graphId]: agent },
    runner,
  });
}

export const POST = async (req: Request) => {
  const runtime = createRuntime();
  const route = createCopilotEndpointSingleRoute({
    runtime,
    basePath: "/api/copilotkit",
  });
  return route.handleRequest(req);
};

Frontend (React)

import { CopilotKit } from "@copilotkit/react-core";
import { CopilotChat } from "@copilotkit/react-ui";

function App() {
  return (
    <CopilotKit
      runtimeUrl="/api/copilotkit"
      agent="my-agent"
      threadId={threadId} // Pass your thread ID here
    >
      <CopilotChat />
    </CopilotKit>
  );
}

Configuration

HistoryHydratingAgentRunner Options

| Option | Type | Default | Description | |--------|------|---------|-------------------------------------| | agent | LangGraphAgent | required | The LangGraphAgent instance | | deploymentUrl | string | required | LangGraph deployment URL | | graphId | string | required | Graph identifier | | langsmithApiKey | string | undefined | LangSmith API key | | historyLimit | number | 100 | Max checkpoints to fetch (max 1000) | | clientTimeoutMs | number | 1800000 | HTTP timeout (default 30 min) | | debug | boolean | false | Enable debug logging | | stateExtractor | function | undefined | Custom state extraction | | onRequest | function | undefined | Custom client request hook |

createIsolatedAgent Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | deploymentUrl | string | required | LangGraph deployment URL | | graphId | string | required | Graph identifier | | langsmithApiKey | string | undefined | LangSmith API key | | clientTimeoutMs | number | 1800000 | HTTP timeout | | debug | boolean | false | Enable debug mode | | onRequest | function | undefined | Custom client request hook |

Advanced Usage

Custom State Extraction

If you need to extract custom fields from the CopilotKit request:

const runner = new HistoryHydratingAgentRunner({
  agent,
  deploymentUrl,
  graphId,
  stateExtractor: (input, forwardedProps) => ({
    // Extract from forwardedProps.configurable (useCoAgent config)
    tenantId: forwardedProps?.configurable?.tenantId as string,
    userId: forwardedProps?.configurable?.userId as string,
    // Or from input.state (useCoAgent initialState)
    ...input.state,
  }),
});

Why createIsolatedAgent?

In serverless environments (especially Vercel Fluid Compute), Node.js module-level state can be shared between bundled routes. This causes a critical bug where the LangGraph deployment URL gets contaminated between different agent configurations.

createIsolatedAgent fixes this by:

  1. Creating agents with frozen, immutable config
  2. Verifying the internal client URL matches expected
  3. Force-replacing the client if contamination is detected

Always use createIsolatedAgent instead of new LangGraphAgent() in serverless environments.

Debug Mode

Enable debug logging to troubleshoot issues:

const runner = new HistoryHydratingAgentRunner({
  // ...
  debug: true,
});

This logs:

  • History fetching progress
  • Message transformation details
  • Stream processing events
  • State extraction results

How It Works

History Hydration Flow

When a client connects to an existing thread:

  1. Fetch History: Retrieves all checkpoints from LangGraph via client.threads.getHistory()
  2. Extract Messages: Processes checkpoints chronologically, deduplicating messages by ID
  3. Transform Format: Converts LangGraph messages to CopilotKit format
  4. Emit Events: Sends MESSAGES_SNAPSHOT and STATE_SNAPSHOT events to frontend
  5. Join Stream: If thread is busy, joins the active execution stream

Event Types Handled

  • on_chat_model_streamTEXT_MESSAGE_CONTENT
  • on_chat_model_startTEXT_MESSAGE_START
  • on_chat_model_endTEXT_MESSAGE_END
  • on_tool_startTOOL_CALL_START
  • on_tool_endTOOL_CALL_END
  • Custom CopilotKit events (manual message/tool/state emission)
  • Interrupt events

API Reference

Exports

// Core
export { HistoryHydratingAgentRunner } from "copilotkit-langgraph-history";
export { createIsolatedAgent } from "copilotkit-langgraph-history";

// Types
export type {
  HistoryHydratingRunnerConfig,
  StateExtractor,
  CreateIsolatedAgentConfig,
  LangGraphMessage,
  ThreadState,
} from "copilotkit-langgraph-history";

// Constants
export {
  DEFAULT_TIMEOUT,
  DEFAULT_HISTORY_LIMIT,
  MAX_HISTORY_LIMIT,
} from "copilotkit-langgraph-history";

// Event Enums
export {
  CustomEventNames,
  LangGraphEventTypes,
} from "copilotkit-langgraph-history";

// Utilities (advanced)
export {
  transformMessages,
  extractContent,
  processStreamChunk,
} from "copilotkit-langgraph-history";

Environment Variables

# Required
LANGGRAPH_DEPLOYMENT_URL=https://your-deployment.langchain.com

# Optional (for authentication)
LANGSMITH_API_KEY=your-api-key

Troubleshooting

"No history found for thread"

  • Ensure the thread exists in LangGraph
  • Check that deploymentUrl is correct
  • Verify langsmithApiKey has access to the deployment

Messages not loading on refresh

  • Confirm threadId is being passed to <CopilotKit>
  • Check browser console for hydration errors
  • Enable debug: true to see detailed logs

"URL mismatch detected" warning

This is expected when the runner detects and fixes serverless state contamination. The client is automatically replaced with the correct URL.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE for details.

Credits

Created by Daniel Frey.

Inspired by the need for thread history persistence in CopilotKit + LangGraph applications.