@langgraph-js/pure-graph 1.2.0 → 1.4.0
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/README.md +22 -14
- package/dist/adapter/hono/runs.js +18 -1
- package/dist/adapter/nextjs/router.js +18 -7
- package/dist/adapter/zod.d.ts +15 -8
- package/dist/adapter/zod.js +8 -0
- package/dist/global.d.ts +3 -2
- package/dist/storage/index.d.ts +4 -3
- package/dist/storage/index.js +13 -1
- package/dist/storage/memory/threads.d.ts +3 -2
- package/dist/storage/memory/threads.js +29 -2
- package/dist/storage/pg/checkpoint.d.ts +2 -0
- package/dist/storage/pg/checkpoint.js +9 -0
- package/dist/storage/pg/threads.d.ts +43 -0
- package/dist/storage/pg/threads.js +304 -0
- package/dist/storage/sqlite/threads.d.ts +3 -2
- package/dist/storage/sqlite/threads.js +37 -3
- package/dist/threads/index.d.ts +3 -2
- package/dist/threads/index.js +1 -26
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types.d.ts +2 -1
- package/package.json +38 -5
- package/.prettierrc +0 -11
- package/bun.lock +0 -209
- package/dist/adapter/nextjs/zod.d.ts +0 -203
- package/dist/adapter/nextjs/zod.js +0 -60
- package/examples/nextjs/README.md +0 -36
- package/examples/nextjs/app/api/langgraph/[...path]/route.ts +0 -10
- package/examples/nextjs/app/favicon.ico +0 -0
- package/examples/nextjs/app/globals.css +0 -26
- package/examples/nextjs/app/layout.tsx +0 -34
- package/examples/nextjs/app/page.tsx +0 -211
- package/examples/nextjs/next.config.ts +0 -26
- package/examples/nextjs/package.json +0 -24
- package/examples/nextjs/postcss.config.mjs +0 -5
- package/examples/nextjs/tsconfig.json +0 -27
- package/packages/agent-graph/demo.json +0 -35
- package/packages/agent-graph/package.json +0 -18
- package/packages/agent-graph/src/index.ts +0 -47
- package/packages/agent-graph/src/tools/tavily.ts +0 -9
- package/packages/agent-graph/src/tools.ts +0 -38
- package/packages/agent-graph/src/types.ts +0 -42
- package/pnpm-workspace.yaml +0 -4
- package/src/adapter/hono/assistants.ts +0 -24
- package/src/adapter/hono/endpoint.ts +0 -3
- package/src/adapter/hono/index.ts +0 -14
- package/src/adapter/hono/runs.ts +0 -65
- package/src/adapter/hono/threads.ts +0 -37
- package/src/adapter/nextjs/endpoint.ts +0 -2
- package/src/adapter/nextjs/index.ts +0 -2
- package/src/adapter/nextjs/router.ts +0 -193
- package/src/adapter/nextjs/zod.ts +0 -66
- package/src/adapter/zod.ts +0 -135
- package/src/createEndpoint.ts +0 -116
- package/src/e.d.ts +0 -3
- package/src/global.ts +0 -11
- package/src/graph/stream.ts +0 -263
- package/src/graph/stringify.ts +0 -219
- package/src/index.ts +0 -6
- package/src/queue/JsonPlusSerializer.ts +0 -143
- package/src/queue/event_message.ts +0 -30
- package/src/queue/stream_queue.ts +0 -237
- package/src/storage/index.ts +0 -52
- package/src/storage/memory/checkpoint.ts +0 -2
- package/src/storage/memory/queue.ts +0 -91
- package/src/storage/memory/threads.ts +0 -154
- package/src/storage/redis/queue.ts +0 -148
- package/src/storage/sqlite/DB.ts +0 -16
- package/src/storage/sqlite/checkpoint.ts +0 -503
- package/src/storage/sqlite/threads.ts +0 -366
- package/src/storage/sqlite/type.ts +0 -12
- package/src/threads/index.ts +0 -51
- package/src/types.ts +0 -116
- package/src/utils/createEntrypointGraph.ts +0 -20
- package/src/utils/getGraph.ts +0 -44
- package/src/utils/getLangGraphCommand.ts +0 -21
- package/test/graph/entrypoint.ts +0 -21
- package/test/graph/index.ts +0 -60
- package/test/hono.ts +0 -15
- package/tsconfig.json +0 -20
package/README.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# Pure Graph
|
|
2
2
|
|
|
3
|
-
Pure Graph is a library that provides a standard LangGraph endpoint for integrating into various frameworks like NextJS and Hono.js. This document will guide you on how to use Pure Graph in your projects.
|
|
3
|
+
Pure Graph is a library that provides a standard LangGraph endpoint for integrating into various frameworks like NextJS and Hono.js. It supports multiple storage backends (SQLite, PostgreSQL, Redis) and message queues. This document will guide you on how to use Pure Graph in your projects.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multiple Storage Backends**: Support for SQLite, PostgreSQL, Redis, and in-memory storage
|
|
8
|
+
- **Message Queue**: Redis-based stream queue with TTL support
|
|
9
|
+
- **Thread Management**: Comprehensive thread lifecycle management with status tracking
|
|
10
|
+
- **Framework Integration**: Native support for Next.js and Hono.js frameworks
|
|
4
11
|
|
|
5
12
|
## Installation
|
|
6
13
|
|
|
@@ -84,27 +91,28 @@ To integrate Pure Graph into a Hono.js project, follow these steps:
|
|
|
84
91
|
|
|
85
92
|
Here are the environment variables you need to configure:
|
|
86
93
|
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
94
|
+
- `SQLITE_DATABASE_URI`: Path to your SQLite database (e.g., `./.langgraph_api/chat.db`).
|
|
95
|
+
- `DATABASE_URL`: PostgreSQL connection string (required for PostgreSQL checkpoint storage).
|
|
96
|
+
- `CHECKPOINT_TYPE`: Type of checkpoint storage (optional, defaults to memory; options: `postgres`, `redis`, `shallow/redis`).
|
|
97
|
+
- `REDIS_URL`: URL for Redis (required if using Redis checkpoint or message queue).
|
|
90
98
|
|
|
91
99
|
## API Endpoints
|
|
92
100
|
|
|
93
101
|
### Assistants
|
|
94
102
|
|
|
95
|
-
-
|
|
96
|
-
-
|
|
103
|
+
- **GET /assistants**: Search for assistants.
|
|
104
|
+
- **GET /assistants/{assistantId}**: Retrieve a specific assistant graph.
|
|
97
105
|
|
|
98
106
|
### Threads
|
|
99
107
|
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
108
|
+
- **POST /threads**: Create a new thread.
|
|
109
|
+
- **GET /threads**: Search for threads.
|
|
110
|
+
- **GET /threads/{threadId}**: Retrieve a specific thread.
|
|
111
|
+
- **DELETE /threads/{threadId}**: Delete a specific thread.
|
|
104
112
|
|
|
105
113
|
### Runs
|
|
106
114
|
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
-
|
|
115
|
+
- **GET /threads/{threadId}/runs**: List runs in a thread.
|
|
116
|
+
- **POST /threads/{threadId}/runs**: Create a new run.
|
|
117
|
+
- **DELETE /threads/{threadId}/runs/{runId}**: Cancel a specific run.
|
|
118
|
+
- **GET /threads/{threadId}/runs/{runId}/stream**: Stream run data.
|
|
@@ -2,8 +2,9 @@ import { zValidator } from '@hono/zod-validator';
|
|
|
2
2
|
import { Hono } from 'hono';
|
|
3
3
|
import { streamSSE } from 'hono/streaming';
|
|
4
4
|
import { client } from './endpoint';
|
|
5
|
-
import { ThreadIdParamSchema, RunIdParamSchema, RunStreamPayloadSchema, RunListQuerySchema, RunCancelQuerySchema, } from '../zod';
|
|
5
|
+
import { ThreadIdParamSchema, RunIdParamSchema, RunStreamPayloadSchema, RunListQuerySchema, RunCancelQuerySchema, ThreadStateUpdate, } from '../zod';
|
|
6
6
|
import { serialiseAsDict } from '../../graph/stream';
|
|
7
|
+
import z from 'zod';
|
|
7
8
|
const api = new Hono();
|
|
8
9
|
// 最常用的对话接口
|
|
9
10
|
api.post('/threads/:thread_id/runs/stream', zValidator('param', ThreadIdParamSchema), zValidator('json', RunStreamPayloadSchema), async (c) => {
|
|
@@ -34,4 +35,20 @@ api.post('/threads/:thread_id/runs/:run_id/cancel', zValidator('param', RunIdPar
|
|
|
34
35
|
}
|
|
35
36
|
return c.body(null, wait ? 204 : 202);
|
|
36
37
|
});
|
|
38
|
+
api.post('/threads/:thread_id/state', zValidator('param', z.object({ thread_id: z.string().uuid() })), zValidator('json', ThreadStateUpdate), async (c) => {
|
|
39
|
+
// Update Thread State
|
|
40
|
+
const { thread_id } = c.req.valid('param');
|
|
41
|
+
const payload = c.req.valid('json');
|
|
42
|
+
// const config: RunnableConfig = { configurable: { thread_id } };
|
|
43
|
+
// if (payload.checkpoint_id) {
|
|
44
|
+
// config.configurable ??= {};
|
|
45
|
+
// config.configurable.checkpoint_id = payload.checkpoint_id;
|
|
46
|
+
// }
|
|
47
|
+
// if (payload.checkpoint) {
|
|
48
|
+
// config.configurable ??= {};
|
|
49
|
+
// Object.assign(config.configurable, payload.checkpoint);
|
|
50
|
+
// }
|
|
51
|
+
const inserted = await client.threads.updateState(thread_id, payload);
|
|
52
|
+
return c.json(inserted);
|
|
53
|
+
});
|
|
37
54
|
export default api;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @ts-ignore */
|
|
2
2
|
import { NextResponse } from 'next/server';
|
|
3
3
|
import { client } from './endpoint';
|
|
4
|
-
import { AssistantsSearchSchema, AssistantGraphQuerySchema, RunStreamPayloadSchema, RunListQuerySchema, RunCancelQuerySchema, ThreadCreatePayloadSchema, ThreadSearchPayloadSchema, } from '../zod';
|
|
4
|
+
import { AssistantsSearchSchema, AssistantGraphQuerySchema, RunStreamPayloadSchema, RunListQuerySchema, RunCancelQuerySchema, ThreadCreatePayloadSchema, ThreadSearchPayloadSchema, ThreadStateUpdate, } from '../zod';
|
|
5
5
|
import { serialiseAsDict } from '../../graph/stream';
|
|
6
6
|
// Next.js App Router 的 SSE 响应实现
|
|
7
7
|
async function sseResponse(generator) {
|
|
@@ -39,7 +39,7 @@ export async function GET(req) {
|
|
|
39
39
|
const match = pathname.match(/\/assistants\/([^/]+)\/graph$/);
|
|
40
40
|
if (match) {
|
|
41
41
|
const assistant_id = match[1];
|
|
42
|
-
const xrayParam = url.searchParams.get('xray');
|
|
42
|
+
const xrayParam = url.searchParams.get('xray') ?? undefined;
|
|
43
43
|
const queryParams = { xray: xrayParam };
|
|
44
44
|
const { xray } = AssistantGraphQuerySchema.parse(queryParams);
|
|
45
45
|
const data = await client.assistants.getGraph(assistant_id, {
|
|
@@ -62,9 +62,9 @@ export async function GET(req) {
|
|
|
62
62
|
const match = pathname.match(/\/threads\/([0-9a-fA-F-]{36})\/runs$/);
|
|
63
63
|
if (match) {
|
|
64
64
|
const thread_id = match[1];
|
|
65
|
-
const limit = url.searchParams.get('limit');
|
|
66
|
-
const offset = url.searchParams.get('offset');
|
|
67
|
-
const status = url.searchParams.get('status');
|
|
65
|
+
const limit = url.searchParams.get('limit') ?? undefined;
|
|
66
|
+
const offset = url.searchParams.get('offset') ?? undefined;
|
|
67
|
+
const status = url.searchParams.get('status') ?? undefined;
|
|
68
68
|
const queryParams = { limit, offset, status };
|
|
69
69
|
const { limit: parsedLimit, offset: parsedOffset, status: parsedStatus, } = RunListQuerySchema.parse(queryParams);
|
|
70
70
|
const runs = await client.runs.list(thread_id, {
|
|
@@ -120,6 +120,17 @@ export async function POST(req) {
|
|
|
120
120
|
headers: { 'X-Pagination-Total': String(result.length) },
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
|
+
// Threads state update
|
|
124
|
+
if (pathname.match(/\/threads\/[0-9a-fA-F-]{36}\/state$/)) {
|
|
125
|
+
const match = pathname.match(/\/threads\/([0-9a-fA-F-]{36})\/state$/);
|
|
126
|
+
if (match) {
|
|
127
|
+
const thread_id = match[1];
|
|
128
|
+
const body = await req.json();
|
|
129
|
+
const payload = ThreadStateUpdate.parse(body);
|
|
130
|
+
const result = await client.threads.updateState(thread_id, payload);
|
|
131
|
+
return NextResponse.json(result);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
123
134
|
// Runs routes - stream
|
|
124
135
|
if (pathname.match(/\/threads\/[0-9a-fA-F-]{36}\/runs\/stream$/)) {
|
|
125
136
|
const match = pathname.match(/\/threads\/([0-9a-fA-F-]{36})\/runs\/stream$/);
|
|
@@ -137,8 +148,8 @@ export async function POST(req) {
|
|
|
137
148
|
if (match) {
|
|
138
149
|
const thread_id = match[1];
|
|
139
150
|
const run_id = match[2];
|
|
140
|
-
const waitParam = url.searchParams.get('wait');
|
|
141
|
-
const actionParam = url.searchParams.get('action');
|
|
151
|
+
const waitParam = url.searchParams.get('wait') ?? undefined;
|
|
152
|
+
const actionParam = url.searchParams.get('action') ?? undefined;
|
|
142
153
|
const queryParams = {
|
|
143
154
|
wait: waitParam ? waitParam === 'true' : false,
|
|
144
155
|
action: actionParam ?? 'interrupt',
|
package/dist/adapter/zod.d.ts
CHANGED
|
@@ -101,6 +101,7 @@ export declare const Assistant: z.ZodObject<{
|
|
|
101
101
|
metadata: {} & {
|
|
102
102
|
[k: string]: any;
|
|
103
103
|
};
|
|
104
|
+
graph_id: string;
|
|
104
105
|
assistant_id: string;
|
|
105
106
|
config: {
|
|
106
107
|
configurable?: z.objectOutputType<{
|
|
@@ -112,13 +113,13 @@ export declare const Assistant: z.ZodObject<{
|
|
|
112
113
|
} & {
|
|
113
114
|
[k: string]: unknown;
|
|
114
115
|
};
|
|
115
|
-
graph_id: string;
|
|
116
116
|
}, {
|
|
117
117
|
created_at: string;
|
|
118
118
|
updated_at: string;
|
|
119
119
|
metadata: {} & {
|
|
120
120
|
[k: string]: any;
|
|
121
121
|
};
|
|
122
|
+
graph_id: string;
|
|
122
123
|
assistant_id: string;
|
|
123
124
|
config: {
|
|
124
125
|
configurable?: z.objectInputType<{
|
|
@@ -130,7 +131,6 @@ export declare const Assistant: z.ZodObject<{
|
|
|
130
131
|
} & {
|
|
131
132
|
[k: string]: unknown;
|
|
132
133
|
};
|
|
133
|
-
graph_id: string;
|
|
134
134
|
}>;
|
|
135
135
|
export declare const MetadataSchema: z.ZodObject<{
|
|
136
136
|
source: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"input">, z.ZodLiteral<"loop">, z.ZodLiteral<"update">, z.ZodString]>>;
|
|
@@ -255,9 +255,9 @@ export declare const AssistantsSearchSchema: z.ZodObject<{
|
|
|
255
255
|
writes: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
256
256
|
parents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
257
257
|
}, z.ZodUnknown, "strip"> | undefined;
|
|
258
|
+
graph_id?: string | undefined;
|
|
258
259
|
limit?: number | undefined;
|
|
259
260
|
offset?: number | undefined;
|
|
260
|
-
graph_id?: string | undefined;
|
|
261
261
|
}, {
|
|
262
262
|
metadata?: z.objectInputType<{
|
|
263
263
|
source: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"input">, z.ZodLiteral<"loop">, z.ZodLiteral<"update">, z.ZodString]>>;
|
|
@@ -265,9 +265,9 @@ export declare const AssistantsSearchSchema: z.ZodObject<{
|
|
|
265
265
|
writes: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
266
266
|
parents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
267
267
|
}, z.ZodUnknown, "strip"> | undefined;
|
|
268
|
+
graph_id?: string | undefined;
|
|
268
269
|
limit?: number | undefined;
|
|
269
270
|
offset?: number | undefined;
|
|
270
|
-
graph_id?: string | undefined;
|
|
271
271
|
}>;
|
|
272
272
|
export declare const AssistantGraphQuerySchema: z.ZodObject<{
|
|
273
273
|
xray: z.ZodOptional<z.ZodString>;
|
|
@@ -395,13 +395,13 @@ export declare const RunStreamPayloadSchema: z.ZodObject<{
|
|
|
395
395
|
}, "strip", z.ZodTypeAny, {
|
|
396
396
|
assistant_id: string;
|
|
397
397
|
on_disconnect: "cancel" | "continue";
|
|
398
|
+
input?: any;
|
|
398
399
|
metadata?: z.objectOutputType<{
|
|
399
400
|
source: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"input">, z.ZodLiteral<"loop">, z.ZodLiteral<"update">, z.ZodString]>>;
|
|
400
401
|
step: z.ZodOptional<z.ZodNumber>;
|
|
401
402
|
writes: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
402
403
|
parents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
403
404
|
}, z.ZodUnknown, "strip"> | undefined;
|
|
404
|
-
input?: any;
|
|
405
405
|
multitask_strategy?: "reject" | "interrupt" | "rollback" | "enqueue" | undefined;
|
|
406
406
|
checkpoint_id?: string | undefined;
|
|
407
407
|
config?: z.objectOutputType<{
|
|
@@ -432,7 +432,7 @@ export declare const RunStreamPayloadSchema: z.ZodObject<{
|
|
|
432
432
|
webhook?: string | undefined;
|
|
433
433
|
interrupt_before?: string[] | "*" | undefined;
|
|
434
434
|
interrupt_after?: string[] | "*" | undefined;
|
|
435
|
-
stream_mode?: ("values" | "
|
|
435
|
+
stream_mode?: ("values" | "updates" | "debug" | "messages" | "custom" | "events" | "messages-tuple")[] | undefined;
|
|
436
436
|
stream_subgraphs?: boolean | undefined;
|
|
437
437
|
stream_resumable?: boolean | undefined;
|
|
438
438
|
after_seconds?: number | undefined;
|
|
@@ -442,13 +442,13 @@ export declare const RunStreamPayloadSchema: z.ZodObject<{
|
|
|
442
442
|
langsmith_tracer?: unknown;
|
|
443
443
|
}, {
|
|
444
444
|
assistant_id: string;
|
|
445
|
+
input?: any;
|
|
445
446
|
metadata?: z.objectInputType<{
|
|
446
447
|
source: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"input">, z.ZodLiteral<"loop">, z.ZodLiteral<"update">, z.ZodString]>>;
|
|
447
448
|
step: z.ZodOptional<z.ZodNumber>;
|
|
448
449
|
writes: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
449
450
|
parents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
450
451
|
}, z.ZodUnknown, "strip"> | undefined;
|
|
451
|
-
input?: any;
|
|
452
452
|
multitask_strategy?: "reject" | "interrupt" | "rollback" | "enqueue" | undefined;
|
|
453
453
|
checkpoint_id?: string | undefined;
|
|
454
454
|
config?: z.objectInputType<{
|
|
@@ -480,7 +480,7 @@ export declare const RunStreamPayloadSchema: z.ZodObject<{
|
|
|
480
480
|
interrupt_before?: string[] | "*" | undefined;
|
|
481
481
|
interrupt_after?: string[] | "*" | undefined;
|
|
482
482
|
on_disconnect?: "cancel" | "continue" | undefined;
|
|
483
|
-
stream_mode?: ("values" | "
|
|
483
|
+
stream_mode?: ("values" | "updates" | "debug" | "messages" | "custom" | "events" | "messages-tuple")[] | undefined;
|
|
484
484
|
stream_subgraphs?: boolean | undefined;
|
|
485
485
|
stream_resumable?: boolean | undefined;
|
|
486
486
|
after_seconds?: number | undefined;
|
|
@@ -575,3 +575,10 @@ export declare const ThreadSearchPayloadSchema: z.ZodObject<{
|
|
|
575
575
|
sort_by?: "thread_id" | "status" | "created_at" | "updated_at" | undefined;
|
|
576
576
|
sort_order?: "asc" | "desc" | undefined;
|
|
577
577
|
}>;
|
|
578
|
+
export declare const ThreadStateUpdate: z.ZodObject<{
|
|
579
|
+
values: z.ZodOptional<z.ZodNullable<z.ZodUnion<[z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">]>>>;
|
|
580
|
+
}, "strip", z.ZodTypeAny, {
|
|
581
|
+
values?: Record<string, unknown> | Record<string, unknown>[] | null | undefined;
|
|
582
|
+
}, {
|
|
583
|
+
values?: Record<string, unknown> | Record<string, unknown>[] | null | undefined;
|
|
584
|
+
}>;
|
package/dist/adapter/zod.js
CHANGED
|
@@ -117,3 +117,11 @@ export const ThreadSearchPayloadSchema = z
|
|
|
117
117
|
sort_order: z.enum(['asc', 'desc']).describe('Sort order.').optional(),
|
|
118
118
|
})
|
|
119
119
|
.describe('Payload for listing threads.');
|
|
120
|
+
export const ThreadStateUpdate = z
|
|
121
|
+
.object({
|
|
122
|
+
values: z.union([z.record(z.string(), z.unknown()), z.array(z.record(z.string(), z.unknown()))]).nullish(),
|
|
123
|
+
// as_node: z.string().optional(),
|
|
124
|
+
// checkpoint_id: z.string().optional(),
|
|
125
|
+
// checkpoint: CheckpointSchema.nullish(),
|
|
126
|
+
})
|
|
127
|
+
.describe('Payload for adding state to a thread.');
|
package/dist/global.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SqliteSaver } from './storage/sqlite/checkpoint.js';
|
|
2
|
+
import type { PostgresSaver } from '@langchain/langgraph-checkpoint-postgres';
|
|
2
3
|
export declare class LangGraphGlobal {
|
|
3
4
|
static globalMessageQueue: import("./queue/stream_queue.js").StreamQueueManager<import("./queue/stream_queue.js").BaseStreamQueueInterface>;
|
|
4
|
-
static globalCheckPointer:
|
|
5
|
-
static globalThreadsManager: import("./storage/sqlite/threads.js").SQLiteThreadsManager<unknown> | import("./storage/memory/threads.js").MemoryThreadsManager<unknown>;
|
|
5
|
+
static globalCheckPointer: import("@langchain/langgraph-checkpoint-redis").RedisSaver | import("@langchain/langgraph-checkpoint-redis/shallow").ShallowRedisSaver | PostgresSaver | SqliteSaver | import("@langchain/langgraph-checkpoint").MemorySaver;
|
|
6
|
+
static globalThreadsManager: import("./storage/pg/threads.js").PostgresThreadsManager<unknown> | import("./storage/sqlite/threads.js").SQLiteThreadsManager<unknown> | import("./storage/memory/threads.js").MemoryThreadsManager<unknown>;
|
|
6
7
|
}
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -2,9 +2,10 @@ import { BaseStreamQueueInterface, StreamQueueManager } from '../queue/stream_qu
|
|
|
2
2
|
import { MemorySaver } from './memory/checkpoint';
|
|
3
3
|
import { MemoryThreadsManager } from './memory/threads';
|
|
4
4
|
import type { SqliteSaver as SqliteSaverType } from './sqlite/checkpoint';
|
|
5
|
+
import type { PostgresSaver } from '@langchain/langgraph-checkpoint-postgres';
|
|
5
6
|
import { SQLiteThreadsManager } from './sqlite/threads';
|
|
6
|
-
export declare const createCheckPointer: () => Promise<
|
|
7
|
+
export declare const createCheckPointer: () => Promise<import("@langchain/langgraph-checkpoint-redis").RedisSaver | import("@langchain/langgraph-checkpoint-redis/shallow").ShallowRedisSaver | PostgresSaver | SqliteSaverType | MemorySaver>;
|
|
7
8
|
export declare const createMessageQueue: () => Promise<StreamQueueManager<BaseStreamQueueInterface>>;
|
|
8
9
|
export declare const createThreadManager: (config: {
|
|
9
|
-
checkpointer?: SqliteSaverType;
|
|
10
|
-
}) => SQLiteThreadsManager<unknown> | MemoryThreadsManager<unknown
|
|
10
|
+
checkpointer?: SqliteSaverType | PostgresSaver;
|
|
11
|
+
}) => Promise<import("./pg/threads").PostgresThreadsManager<unknown> | SQLiteThreadsManager<unknown> | MemoryThreadsManager<unknown>>;
|
package/dist/storage/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export const createCheckPointer = async () => {
|
|
|
8
8
|
if ((process.env.REDIS_URL && process.env.CHECKPOINT_TYPE === 'redis') ||
|
|
9
9
|
process.env.CHECKPOINT_TYPE === 'shallow/redis') {
|
|
10
10
|
if (process.env.CHECKPOINT_TYPE === 'redis') {
|
|
11
|
+
console.log('Using redis as checkpoint');
|
|
11
12
|
const { RedisSaver } = await import('@langchain/langgraph-checkpoint-redis');
|
|
12
13
|
return await RedisSaver.fromUrl(process.env.REDIS_URL, {
|
|
13
14
|
defaultTTL: 60, // TTL in minutes
|
|
@@ -15,11 +16,18 @@ export const createCheckPointer = async () => {
|
|
|
15
16
|
});
|
|
16
17
|
}
|
|
17
18
|
if (process.env.CHECKPOINT_TYPE === 'shallow/redis') {
|
|
19
|
+
console.log('Using shallow redis as checkpoint');
|
|
18
20
|
const { ShallowRedisSaver } = await import('@langchain/langgraph-checkpoint-redis/shallow');
|
|
19
21
|
return await ShallowRedisSaver.fromUrl(process.env.REDIS_URL);
|
|
20
22
|
}
|
|
21
23
|
}
|
|
24
|
+
if (process.env.DATABASE_URL) {
|
|
25
|
+
console.log('Using postgres as checkpoint');
|
|
26
|
+
const { createPGCheckpoint } = await import('./pg/checkpoint');
|
|
27
|
+
return createPGCheckpoint();
|
|
28
|
+
}
|
|
22
29
|
if (process.env.SQLITE_DATABASE_URI) {
|
|
30
|
+
console.log('Using sqlite as checkpoint');
|
|
23
31
|
const { SqliteSaver } = await import('./sqlite/checkpoint');
|
|
24
32
|
const db = SqliteSaver.fromConnString(process.env.SQLITE_DATABASE_URI);
|
|
25
33
|
return db;
|
|
@@ -38,7 +46,11 @@ export const createMessageQueue = async () => {
|
|
|
38
46
|
}
|
|
39
47
|
return new StreamQueueManager(q);
|
|
40
48
|
};
|
|
41
|
-
export const createThreadManager = (config) => {
|
|
49
|
+
export const createThreadManager = async (config) => {
|
|
50
|
+
if (process.env.DATABASE_URL && config.checkpointer) {
|
|
51
|
+
const { PostgresThreadsManager } = await import('./pg/threads');
|
|
52
|
+
return new PostgresThreadsManager(config.checkpointer);
|
|
53
|
+
}
|
|
42
54
|
if (process.env.SQLITE_DATABASE_URI && config.checkpointer) {
|
|
43
55
|
return new SQLiteThreadsManager(config.checkpointer);
|
|
44
56
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BaseThreadsManager } from '../../threads/index.js';
|
|
2
|
-
import { Command, Metadata, OnConflictBehavior, Run, RunStatus, SortOrder, Thread, ThreadSortBy, ThreadStatus } from '@langgraph-js/sdk';
|
|
3
|
-
export declare class MemoryThreadsManager<ValuesType = unknown>
|
|
2
|
+
import { Command, Config, Metadata, OnConflictBehavior, Run, RunStatus, SortOrder, Thread, ThreadSortBy, ThreadStatus } from '@langgraph-js/sdk';
|
|
3
|
+
export declare class MemoryThreadsManager<ValuesType = unknown> implements BaseThreadsManager<ValuesType> {
|
|
4
4
|
private threads;
|
|
5
5
|
create(payload?: {
|
|
6
6
|
metadata?: Metadata;
|
|
@@ -26,6 +26,7 @@ export declare class MemoryThreadsManager<ValuesType = unknown> extends BaseThre
|
|
|
26
26
|
get(threadId: string): Promise<Thread<ValuesType>>;
|
|
27
27
|
set(threadId: string, thread: Partial<Thread<ValuesType>>): Promise<void>;
|
|
28
28
|
delete(threadId: string): Promise<void>;
|
|
29
|
+
updateState(threadId: string, thread: Partial<Thread<ValuesType>>): Promise<Pick<Config, 'configurable'>>;
|
|
29
30
|
runs: Run[];
|
|
30
31
|
createRun(threadId: string, assistantId: string, payload?: {
|
|
31
32
|
metadata?: Metadata;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { getGraph } from '../../utils/getGraph.js';
|
|
2
|
+
import { serialiseAsDict } from '../../graph/stream.js';
|
|
3
|
+
export class MemoryThreadsManager {
|
|
3
4
|
threads = [];
|
|
4
5
|
async create(payload) {
|
|
5
6
|
const threadId = payload?.threadId || crypto.randomUUID();
|
|
@@ -79,6 +80,32 @@ export class MemoryThreadsManager extends BaseThreadsManager {
|
|
|
79
80
|
throw new Error(`Thread with ID ${threadId} not found.`);
|
|
80
81
|
}
|
|
81
82
|
}
|
|
83
|
+
async updateState(threadId, thread) {
|
|
84
|
+
const index = this.threads.findIndex((t) => t.thread_id === threadId);
|
|
85
|
+
if (index === -1) {
|
|
86
|
+
throw new Error(`Thread with ID ${threadId} not found.`);
|
|
87
|
+
}
|
|
88
|
+
const targetThread = this.threads[index];
|
|
89
|
+
if (targetThread.status === 'busy') {
|
|
90
|
+
throw new Error(`Thread with ID ${threadId} is busy, can't update state.`);
|
|
91
|
+
}
|
|
92
|
+
this.threads[index] = { ...targetThread, values: thread.values };
|
|
93
|
+
if (!targetThread.metadata?.graph_id) {
|
|
94
|
+
throw new Error(`Thread with ID ${threadId} has no graph_id.`);
|
|
95
|
+
}
|
|
96
|
+
const graphId = targetThread.metadata?.graph_id;
|
|
97
|
+
const config = {
|
|
98
|
+
configurable: {
|
|
99
|
+
thread_id: threadId,
|
|
100
|
+
graph_id: graphId,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
const graph = await getGraph(graphId, config);
|
|
104
|
+
const nextConfig = await graph.updateState(config, thread.values);
|
|
105
|
+
const graphState = await graph.getState(config);
|
|
106
|
+
await this.set(threadId, { values: JSON.parse(serialiseAsDict(graphState.values)) });
|
|
107
|
+
return nextConfig;
|
|
108
|
+
}
|
|
82
109
|
runs = [];
|
|
83
110
|
async createRun(threadId, assistantId, payload) {
|
|
84
111
|
const runId = crypto.randomUUID();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PostgresSaver } from '@langchain/langgraph-checkpoint-postgres';
|
|
2
|
+
export const createPGCheckpoint = async () => {
|
|
3
|
+
const checkpointer = PostgresSaver.fromConnString(process.env.DATABASE_URL);
|
|
4
|
+
if (process.env.DATABASE_INIT === 'true') {
|
|
5
|
+
console.log('Initializing postgres checkpoint');
|
|
6
|
+
await checkpointer.setup();
|
|
7
|
+
}
|
|
8
|
+
return checkpointer;
|
|
9
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BaseThreadsManager } from '../../threads/index.js';
|
|
2
|
+
import { Command, Config, Metadata, OnConflictBehavior, Run, RunStatus, SortOrder, Thread, ThreadSortBy, ThreadStatus } from '@langgraph-js/sdk';
|
|
3
|
+
import type { PostgresSaver } from '@langchain/langgraph-checkpoint-postgres';
|
|
4
|
+
export declare class PostgresThreadsManager<ValuesType = unknown> implements BaseThreadsManager<ValuesType> {
|
|
5
|
+
private pool;
|
|
6
|
+
private isSetup;
|
|
7
|
+
constructor(checkpointer: PostgresSaver);
|
|
8
|
+
private setup;
|
|
9
|
+
create(payload?: {
|
|
10
|
+
metadata?: Metadata;
|
|
11
|
+
threadId?: string;
|
|
12
|
+
ifExists?: OnConflictBehavior;
|
|
13
|
+
graphId?: string;
|
|
14
|
+
supersteps?: Array<{
|
|
15
|
+
updates: Array<{
|
|
16
|
+
values: unknown;
|
|
17
|
+
command?: Command;
|
|
18
|
+
asNode: string;
|
|
19
|
+
}>;
|
|
20
|
+
}>;
|
|
21
|
+
}): Promise<Thread<ValuesType>>;
|
|
22
|
+
search(query?: {
|
|
23
|
+
metadata?: Metadata;
|
|
24
|
+
limit?: number;
|
|
25
|
+
offset?: number;
|
|
26
|
+
status?: ThreadStatus;
|
|
27
|
+
sortBy?: ThreadSortBy;
|
|
28
|
+
sortOrder?: SortOrder;
|
|
29
|
+
}): Promise<Thread<ValuesType>[]>;
|
|
30
|
+
get(threadId: string): Promise<Thread<ValuesType>>;
|
|
31
|
+
set(threadId: string, thread: Partial<Thread<ValuesType>>): Promise<void>;
|
|
32
|
+
updateState(threadId: string, thread: Partial<Thread<ValuesType>>): Promise<Pick<Config, 'configurable'>>;
|
|
33
|
+
delete(threadId: string): Promise<void>;
|
|
34
|
+
createRun(threadId: string, assistantId: string, payload?: {
|
|
35
|
+
metadata?: Metadata;
|
|
36
|
+
}): Promise<Run>;
|
|
37
|
+
listRuns(threadId: string, options?: {
|
|
38
|
+
limit?: number;
|
|
39
|
+
offset?: number;
|
|
40
|
+
status?: RunStatus;
|
|
41
|
+
}): Promise<Run[]>;
|
|
42
|
+
updateRun(runId: string, run: Partial<Run>): Promise<void>;
|
|
43
|
+
}
|