@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 +21 -0
- package/README.md +308 -0
- package/dist/index.cjs +947 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +647 -0
- package/dist/index.d.ts +647 -0
- package/dist/index.js +936 -0
- package/dist/index.js.map +1 -0
- package/package.json +101 -0
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
|
+
[](https://www.npmjs.com/package/copilotkit-langgraph-history)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](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.
|