@macrow/copilotkit-langgraph-history 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Frey
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,308 @@
1
+ # copilotkit-langgraph-history
2
+
3
+ This is a temporary fork of xxx.
4
+ PR submitted: https://github.com/clickspider/copilotkit-langgraph-history/pull/3
5
+
6
+ [![npm version](https://img.shields.io/npm/v/copilotkit-langgraph-history.svg)](https://www.npmjs.com/package/copilotkit-langgraph-history)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue.svg)](https://www.typescriptlang.org/)
9
+
10
+ **Open-source LangGraph thread history persistence for CopilotKit.** Restore chat history on page refresh with your own LangGraph deployment.
11
+
12
+ ## The Problem
13
+
14
+ Building a chat app with [CopilotKit](https://copilotkit.ai) and [LangGraph](https://langchain-ai.github.io/langgraph/)? You've probably noticed:
15
+
16
+ - **Page refresh = empty chat** - All messages disappear
17
+ - **Thread switching loses context** - No automatic history restoration
18
+ - **No persistence of agent state** - Users lose context
19
+
20
+ CopilotKit's default runtime doesn't automatically fetch historical messages from LangGraph's checkpoint system. This package adds that capability.
21
+
22
+ ## The Solution
23
+
24
+ **With this package:**
25
+ - Chat history restored on page load
26
+ - Seamless thread switching
27
+ - Agent state preserved
28
+ - Works with any LangGraph deployment (LangGraph Cloud, self-hosted)
29
+ - MIT licensed, open-source
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install copilotkit-langgraph-history
35
+ # or
36
+ pnpm add copilotkit-langgraph-history
37
+ # or
38
+ yarn add copilotkit-langgraph-history
39
+ ```
40
+
41
+ ### Peer Dependencies
42
+
43
+ This package requires the following peer dependencies:
44
+
45
+ ```bash
46
+ npm install @copilotkit/runtime @copilotkitnext/runtime @ag-ui/core @langchain/langgraph-sdk rxjs
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ ### Next.js App Router
52
+
53
+ ```typescript
54
+ // app/api/copilotkit/route.ts
55
+ import { CopilotRuntime, createCopilotEndpointSingleRoute } from "@copilotkit/runtime/v2";
56
+ import {
57
+ HistoryHydratingAgentRunner,
58
+ createIsolatedAgent,
59
+ } from "copilotkit-langgraph-history";
60
+
61
+ const deploymentUrl = process.env.LANGGRAPH_DEPLOYMENT_URL!;
62
+ const langsmithApiKey = process.env.LANGSMITH_API_KEY;
63
+ const graphId = "my-agent";
64
+
65
+ function createRuntime() {
66
+ // Create isolated agent (prevents serverless state contamination)
67
+ const agent = createIsolatedAgent({
68
+ deploymentUrl,
69
+ graphId,
70
+ langsmithApiKey,
71
+ onRequest: (_url, initReq) => {
72
+ initReq.headers = { ...initReq.headers, Authorization: 'Bearer authToken' };
73
+ return initReq;
74
+ },
75
+ });
76
+
77
+ // Create history-hydrating runner
78
+ const runner = new HistoryHydratingAgentRunner({
79
+ agent,
80
+ deploymentUrl,
81
+ graphId,
82
+ langsmithApiKey,
83
+ historyLimit: 100, // Max messages to load
84
+ onRequest: (_url, initReq) => {
85
+ initReq.headers = { ...initReq.headers, Authorization: 'Bearer authToken' };
86
+ return initReq;
87
+ },
88
+ });
89
+
90
+ return new CopilotRuntime({
91
+ agents: { [graphId]: agent },
92
+ runner,
93
+ });
94
+ }
95
+
96
+ export const POST = async (req: Request) => {
97
+ const runtime = createRuntime();
98
+ const route = createCopilotEndpointSingleRoute({
99
+ runtime,
100
+ basePath: "/api/copilotkit",
101
+ });
102
+ return route.handleRequest(req);
103
+ };
104
+ ```
105
+
106
+ ### Frontend (React)
107
+
108
+ ```tsx
109
+ import { CopilotKit } from "@copilotkit/react-core";
110
+ import { CopilotChat } from "@copilotkit/react-ui";
111
+
112
+ function App() {
113
+ return (
114
+ <CopilotKit
115
+ runtimeUrl="/api/copilotkit"
116
+ agent="my-agent"
117
+ threadId={threadId} // Pass your thread ID here
118
+ >
119
+ <CopilotChat />
120
+ </CopilotKit>
121
+ );
122
+ }
123
+ ```
124
+
125
+ ## Configuration
126
+
127
+ ### `HistoryHydratingAgentRunner` Options
128
+
129
+ | Option | Type | Default | Description |
130
+ |--------|------|---------|-------------------------------------|
131
+ | `agent` | `LangGraphAgent` | **required** | The LangGraphAgent instance |
132
+ | `deploymentUrl` | `string` | **required** | LangGraph deployment URL |
133
+ | `graphId` | `string` | **required** | Graph identifier |
134
+ | `langsmithApiKey` | `string` | `undefined` | LangSmith API key |
135
+ | `historyLimit` | `number` | `100` | Max checkpoints to fetch (max 1000) |
136
+ | `clientTimeoutMs` | `number` | `1800000` | HTTP timeout (default 30 min) |
137
+ | `debug` | `boolean` | `false` | Enable debug logging |
138
+ | `stateExtractor` | `function` | `undefined` | Custom state extraction |
139
+ | `onRequest` | `function` | `undefined` | Custom client request hook |
140
+
141
+ ### `createIsolatedAgent` Options
142
+
143
+ | Option | Type | Default | Description |
144
+ |--------|------|---------|-------------|
145
+ | `deploymentUrl` | `string` | **required** | LangGraph deployment URL |
146
+ | `graphId` | `string` | **required** | Graph identifier |
147
+ | `langsmithApiKey` | `string` | `undefined` | LangSmith API key |
148
+ | `clientTimeoutMs` | `number` | `1800000` | HTTP timeout |
149
+ | `debug` | `boolean` | `false` | Enable debug mode |
150
+ | `onRequest` | `function` | `undefined` | Custom client request hook |
151
+
152
+ ## Advanced Usage
153
+
154
+ ### Custom State Extraction
155
+
156
+ If you need to extract custom fields from the CopilotKit request:
157
+
158
+ ```typescript
159
+ const runner = new HistoryHydratingAgentRunner({
160
+ agent,
161
+ deploymentUrl,
162
+ graphId,
163
+ stateExtractor: (input, forwardedProps) => ({
164
+ // Extract from forwardedProps.configurable (useCoAgent config)
165
+ tenantId: forwardedProps?.configurable?.tenantId as string,
166
+ userId: forwardedProps?.configurable?.userId as string,
167
+ // Or from input.state (useCoAgent initialState)
168
+ ...input.state,
169
+ }),
170
+ });
171
+ ```
172
+
173
+ ### Why `createIsolatedAgent`?
174
+
175
+ 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.
176
+
177
+ `createIsolatedAgent` fixes this by:
178
+ 1. Creating agents with frozen, immutable config
179
+ 2. Verifying the internal client URL matches expected
180
+ 3. Force-replacing the client if contamination is detected
181
+
182
+ **Always use `createIsolatedAgent` instead of `new LangGraphAgent()` in serverless environments.**
183
+
184
+ ### Debug Mode
185
+
186
+ Enable debug logging to troubleshoot issues:
187
+
188
+ ```typescript
189
+ const runner = new HistoryHydratingAgentRunner({
190
+ // ...
191
+ debug: true,
192
+ });
193
+ ```
194
+
195
+ This logs:
196
+ - History fetching progress
197
+ - Message transformation details
198
+ - Stream processing events
199
+ - State extraction results
200
+
201
+ ## How It Works
202
+
203
+ ### History Hydration Flow
204
+
205
+ When a client connects to an existing thread:
206
+
207
+ 1. **Fetch History**: Retrieves all checkpoints from LangGraph via `client.threads.getHistory()`
208
+ 2. **Extract Messages**: Processes checkpoints chronologically, deduplicating messages by ID
209
+ 3. **Transform Format**: Converts LangGraph messages to CopilotKit format
210
+ 4. **Emit Events**: Sends `MESSAGES_SNAPSHOT` and `STATE_SNAPSHOT` events to frontend
211
+ 5. **Join Stream**: If thread is busy, joins the active execution stream
212
+
213
+ ### Event Types Handled
214
+
215
+ - `on_chat_model_stream` → `TEXT_MESSAGE_CONTENT`
216
+ - `on_chat_model_start` → `TEXT_MESSAGE_START`
217
+ - `on_chat_model_end` → `TEXT_MESSAGE_END`
218
+ - `on_tool_start` → `TOOL_CALL_START`
219
+ - `on_tool_end` → `TOOL_CALL_END`
220
+ - Custom CopilotKit events (manual message/tool/state emission)
221
+ - Interrupt events
222
+
223
+ ## API Reference
224
+
225
+ ### Exports
226
+
227
+ ```typescript
228
+ // Core
229
+ export { HistoryHydratingAgentRunner } from "copilotkit-langgraph-history";
230
+ export { createIsolatedAgent } from "copilotkit-langgraph-history";
231
+
232
+ // Types
233
+ export type {
234
+ HistoryHydratingRunnerConfig,
235
+ StateExtractor,
236
+ CreateIsolatedAgentConfig,
237
+ LangGraphMessage,
238
+ ThreadState,
239
+ } from "copilotkit-langgraph-history";
240
+
241
+ // Constants
242
+ export {
243
+ DEFAULT_TIMEOUT,
244
+ DEFAULT_HISTORY_LIMIT,
245
+ MAX_HISTORY_LIMIT,
246
+ } from "copilotkit-langgraph-history";
247
+
248
+ // Event Enums
249
+ export {
250
+ CustomEventNames,
251
+ LangGraphEventTypes,
252
+ } from "copilotkit-langgraph-history";
253
+
254
+ // Utilities (advanced)
255
+ export {
256
+ transformMessages,
257
+ extractContent,
258
+ processStreamChunk,
259
+ } from "copilotkit-langgraph-history";
260
+ ```
261
+
262
+ ## Environment Variables
263
+
264
+ ```env
265
+ # Required
266
+ LANGGRAPH_DEPLOYMENT_URL=https://your-deployment.langchain.com
267
+
268
+ # Optional (for authentication)
269
+ LANGSMITH_API_KEY=your-api-key
270
+ ```
271
+
272
+ ## Troubleshooting
273
+
274
+ ### "No history found for thread"
275
+
276
+ - Ensure the thread exists in LangGraph
277
+ - Check that `deploymentUrl` is correct
278
+ - Verify `langsmithApiKey` has access to the deployment
279
+
280
+ ### Messages not loading on refresh
281
+
282
+ - Confirm `threadId` is being passed to `<CopilotKit>`
283
+ - Check browser console for hydration errors
284
+ - Enable `debug: true` to see detailed logs
285
+
286
+ ### "URL mismatch detected" warning
287
+
288
+ This is expected when the runner detects and fixes serverless state contamination. The client is automatically replaced with the correct URL.
289
+
290
+ ## Contributing
291
+
292
+ Contributions are welcome! Please feel free to submit a Pull Request.
293
+
294
+ 1. Fork the repository
295
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
296
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
297
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
298
+ 5. Open a Pull Request
299
+
300
+ ## License
301
+
302
+ MIT License - see [LICENSE](LICENSE) for details.
303
+
304
+ ## Credits
305
+
306
+ Created by [Daniel Frey](https://github.com/clickspider).
307
+
308
+ Inspired by the need for thread history persistence in CopilotKit + LangGraph applications.