@langgraph-js/sdk 2.0.0 → 2.2.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/dist/LangGraphClient.d.ts +24 -40
- package/dist/LangGraphClient.js +17 -4
- package/dist/client/LanggraphServer.d.ts +2 -1
- package/dist/client/LanggraphServer.js +2 -2
- package/dist/time-travel/index.d.ts +11 -0
- package/dist/time-travel/index.js +30 -0
- package/dist/types.d.ts +12 -36
- package/dist/ui-store/createChatStore.d.ts +7 -2
- package/dist/ui-store/createChatStore.js +31 -7
- package/package.json +1 -1
- package/src/LangGraphClient.ts +21 -5
- package/src/client/LanggraphServer.ts +3 -2
- package/src/time-travel/index.ts +33 -0
- package/src/types.ts +12 -49
- package/src/ui-store/createChatStore.ts +27 -9
|
@@ -68,7 +68,7 @@ export interface LangGraphClientConfig {
|
|
|
68
68
|
timeoutMs?: number;
|
|
69
69
|
defaultHeaders?: Record<string, string | null | undefined>;
|
|
70
70
|
/** 自定义客户端实现,如果不提供则使用官方 Client */
|
|
71
|
-
client: ILangGraphClient
|
|
71
|
+
client: ILangGraphClient<any, any>;
|
|
72
72
|
}
|
|
73
73
|
export interface LangGraphEvents {
|
|
74
74
|
/** 流开始事件 */
|
|
@@ -113,6 +113,11 @@ export declare class LangGraphClient<TStateType = unknown, TUpdateType = TStateT
|
|
|
113
113
|
private currentAssistant;
|
|
114
114
|
private currentThread;
|
|
115
115
|
tools: ToolManager;
|
|
116
|
+
availableAssistants: Assistant[];
|
|
117
|
+
graphState: any;
|
|
118
|
+
currentRun?: {
|
|
119
|
+
run_id: string;
|
|
120
|
+
};
|
|
116
121
|
stopController: AbortController | null;
|
|
117
122
|
/** 用于存储 subAgent 状态数据的键 */
|
|
118
123
|
subAgentsKey: string;
|
|
@@ -135,7 +140,7 @@ export declare class LangGraphClient<TStateType = unknown, TUpdateType = TStateT
|
|
|
135
140
|
};
|
|
136
141
|
/** 代理 threads 属性到内部 client */
|
|
137
142
|
get threads(): {
|
|
138
|
-
create
|
|
143
|
+
create(payload?: {
|
|
139
144
|
metadata?: import("@langchain/langgraph-sdk").Metadata;
|
|
140
145
|
threadId?: string;
|
|
141
146
|
ifExists?: import("@langchain/langgraph-sdk").OnConflictBehavior;
|
|
@@ -147,16 +152,16 @@ export declare class LangGraphClient<TStateType = unknown, TUpdateType = TStateT
|
|
|
147
152
|
asNode: string;
|
|
148
153
|
}>;
|
|
149
154
|
}>;
|
|
150
|
-
}): Promise<Thread<
|
|
151
|
-
search
|
|
155
|
+
}): Promise<Thread<TStateType>>;
|
|
156
|
+
search(query?: {
|
|
152
157
|
metadata?: import("@langchain/langgraph-sdk").Metadata;
|
|
153
158
|
limit?: number;
|
|
154
159
|
offset?: number;
|
|
155
160
|
status?: import("@langchain/langgraph-sdk").ThreadStatus;
|
|
156
161
|
sortBy?: import("./types.js").ThreadSortBy;
|
|
157
162
|
sortOrder?: import("./types.js").SortOrder;
|
|
158
|
-
}): Promise<Thread<
|
|
159
|
-
get
|
|
163
|
+
}): Promise<Thread<TStateType>[]>;
|
|
164
|
+
get(threadId: string): Promise<Thread<TStateType>>;
|
|
160
165
|
delete(threadId: string): Promise<void>;
|
|
161
166
|
};
|
|
162
167
|
/** 代理 runs 属性到内部 client */
|
|
@@ -166,31 +171,7 @@ export declare class LangGraphClient<TStateType = unknown, TUpdateType = TStateT
|
|
|
166
171
|
offset?: number;
|
|
167
172
|
status?: import("./types.js").RunStatus;
|
|
168
173
|
}): Promise<import("@langchain/langgraph-sdk").Run[]>;
|
|
169
|
-
stream<
|
|
170
|
-
input?: Record<string, unknown> | null;
|
|
171
|
-
metadata?: import("@langchain/langgraph-sdk").Metadata;
|
|
172
|
-
config?: import("@langchain/langgraph-sdk").Config;
|
|
173
|
-
checkpointId?: string;
|
|
174
|
-
checkpoint?: Omit<import("@langchain/langgraph-sdk").Checkpoint, "thread_id">;
|
|
175
|
-
checkpointDuring?: boolean;
|
|
176
|
-
interruptBefore?: "*" | string[];
|
|
177
|
-
interruptAfter?: "*" | string[];
|
|
178
|
-
signal?: AbortController["signal"];
|
|
179
|
-
webhook?: string;
|
|
180
|
-
onDisconnect?: import("./types.js").DisconnectMode;
|
|
181
|
-
afterSeconds?: number;
|
|
182
|
-
ifNotExists?: "create" | "reject";
|
|
183
|
-
command?: Command;
|
|
184
|
-
onRunCreated?: (params: {
|
|
185
|
-
run_id: string;
|
|
186
|
-
thread_id?: string;
|
|
187
|
-
}) => void;
|
|
188
|
-
streamMode?: TStreamMode | undefined;
|
|
189
|
-
streamSubgraphs?: TSubgraphs | undefined;
|
|
190
|
-
streamResumable?: boolean;
|
|
191
|
-
feedbackKeys?: string[];
|
|
192
|
-
} | undefined): import("./types.js").TypedAsyncGenerator<TStreamMode, TSubgraphs, TStateType, TUpdateType, unknown>;
|
|
193
|
-
stream<TStreamMode extends import("@langchain/langgraph-sdk").StreamMode | import("@langchain/langgraph-sdk").StreamMode[] = import("@langchain/langgraph-sdk").StreamMode, TSubgraphs extends boolean = false>(threadId: string, assistantId: string, payload?: {
|
|
174
|
+
stream<TSubgraphs extends boolean = false>(threadId: string, assistantId: string, payload?: {
|
|
194
175
|
input?: Record<string, unknown> | null;
|
|
195
176
|
metadata?: import("@langchain/langgraph-sdk").Metadata;
|
|
196
177
|
config?: import("@langchain/langgraph-sdk").Config;
|
|
@@ -211,12 +192,12 @@ export declare class LangGraphClient<TStateType = unknown, TUpdateType = TStateT
|
|
|
211
192
|
run_id: string;
|
|
212
193
|
thread_id?: string;
|
|
213
194
|
}) => void;
|
|
214
|
-
streamMode?:
|
|
195
|
+
streamMode?: import("@langchain/langgraph-sdk").StreamMode[];
|
|
215
196
|
streamSubgraphs?: TSubgraphs | undefined;
|
|
216
197
|
streamResumable?: boolean;
|
|
217
198
|
feedbackKeys?: string[];
|
|
218
|
-
} | undefined): import("./types.js").TypedAsyncGenerator<
|
|
219
|
-
joinStream(threadId: string
|
|
199
|
+
} | undefined): import("./types.js").TypedAsyncGenerator<TSubgraphs, TStateType, TUpdateType>;
|
|
200
|
+
joinStream(threadId: string, runId: string, options?: {
|
|
220
201
|
signal?: AbortSignal;
|
|
221
202
|
cancelOnDisconnect?: boolean;
|
|
222
203
|
lastEventId?: string;
|
|
@@ -228,7 +209,6 @@ export declare class LangGraphClient<TStateType = unknown, TUpdateType = TStateT
|
|
|
228
209
|
}>;
|
|
229
210
|
cancel(threadId: string, runId: string, wait?: boolean, action?: import("./types.js").CancelAction): Promise<void>;
|
|
230
211
|
};
|
|
231
|
-
availableAssistants: Assistant[];
|
|
232
212
|
private listAssistants;
|
|
233
213
|
/**
|
|
234
214
|
* @zh 初始化 Assistant。
|
|
@@ -239,8 +219,9 @@ export declare class LangGraphClient<TStateType = unknown, TUpdateType = TStateT
|
|
|
239
219
|
* @zh 创建一个新的 Thread。
|
|
240
220
|
* @en Creates a new Thread.
|
|
241
221
|
*/
|
|
242
|
-
createThread({ threadId, }?: {
|
|
222
|
+
createThread({ threadId, graphId, }?: {
|
|
243
223
|
threadId?: string;
|
|
224
|
+
graphId?: string;
|
|
244
225
|
}): Promise<Thread<TStateType>>;
|
|
245
226
|
graphVisualize(): Promise<import("@langchain/langgraph-sdk").AssistantGraph>;
|
|
246
227
|
/**
|
|
@@ -272,15 +253,18 @@ export declare class LangGraphClient<TStateType = unknown, TUpdateType = TStateT
|
|
|
272
253
|
};
|
|
273
254
|
/** 前端工具人机交互时,锁住面板 */
|
|
274
255
|
isFELocking(messages: RenderMessage[]): boolean | undefined;
|
|
275
|
-
graphState: any;
|
|
276
|
-
currentRun?: {
|
|
277
|
-
run_id: string;
|
|
278
|
-
};
|
|
279
256
|
/**
|
|
280
257
|
* @zh 取消当前的 Run。
|
|
281
258
|
* @en Cancels the current Run.
|
|
282
259
|
*/
|
|
283
260
|
cancelRun(): void;
|
|
261
|
+
/**
|
|
262
|
+
* @zh 回滚到指定的消息。但是不会触发数据的重新更新
|
|
263
|
+
* @en Reverts to the specified message.
|
|
264
|
+
*/
|
|
265
|
+
revertChatTo(messageId: string): Promise<{
|
|
266
|
+
messages: Message[];
|
|
267
|
+
}>;
|
|
284
268
|
/**
|
|
285
269
|
* @zh 发送消息到 LangGraph 后端。
|
|
286
270
|
* @en Sends a message to the LangGraph backend.
|
package/dist/LangGraphClient.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from "eventemitter3";
|
|
2
2
|
import { ToolManager } from "./ToolManager.js";
|
|
3
3
|
import { MessageProcessor } from "./MessageProcessor.js";
|
|
4
|
+
import { revertChatTo } from "./time-travel/index.js";
|
|
4
5
|
/**
|
|
5
6
|
* @zh LangGraphClient 类是与 LangGraph 后端交互的主要客户端。
|
|
6
7
|
* @en The LangGraphClient class is the main client for interacting with the LangGraph backend.
|
|
@@ -11,11 +12,11 @@ export class LangGraphClient extends EventEmitter {
|
|
|
11
12
|
this.currentAssistant = null;
|
|
12
13
|
this.currentThread = null;
|
|
13
14
|
this.tools = new ToolManager();
|
|
15
|
+
this.availableAssistants = [];
|
|
16
|
+
this.graphState = {};
|
|
14
17
|
this.stopController = null;
|
|
15
18
|
/** 用于存储 subAgent 状态数据的键 */
|
|
16
19
|
this.subAgentsKey = "task_store";
|
|
17
|
-
this.availableAssistants = [];
|
|
18
|
-
this.graphState = {};
|
|
19
20
|
/** 当前子图位置,但是依赖 stream,不太适合稳定使用*/
|
|
20
21
|
this.graphPosition = "";
|
|
21
22
|
this.extraParams = {};
|
|
@@ -73,10 +74,11 @@ export class LangGraphClient extends EventEmitter {
|
|
|
73
74
|
* @zh 创建一个新的 Thread。
|
|
74
75
|
* @en Creates a new Thread.
|
|
75
76
|
*/
|
|
76
|
-
async createThread({ threadId, } = {}) {
|
|
77
|
+
async createThread({ threadId, graphId, } = {}) {
|
|
77
78
|
try {
|
|
78
79
|
this.currentThread = await this.threads.create({
|
|
79
80
|
threadId,
|
|
81
|
+
graphId,
|
|
80
82
|
});
|
|
81
83
|
return this.currentThread;
|
|
82
84
|
}
|
|
@@ -185,6 +187,17 @@ export class LangGraphClient extends EventEmitter {
|
|
|
185
187
|
this.runs.cancel(this.currentThread.thread_id, this.currentRun.run_id);
|
|
186
188
|
}
|
|
187
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* @zh 回滚到指定的消息。但是不会触发数据的重新更新
|
|
192
|
+
* @en Reverts to the specified message.
|
|
193
|
+
*/
|
|
194
|
+
async revertChatTo(messageId) {
|
|
195
|
+
const { state, checkpoint } = await revertChatTo(this.client, this.currentThread.thread_id, messageId);
|
|
196
|
+
this.graphState = state;
|
|
197
|
+
this.messageProcessor.clearStreamingMessages();
|
|
198
|
+
this.messageProcessor.setGraphMessages(state.messages);
|
|
199
|
+
return state;
|
|
200
|
+
}
|
|
188
201
|
/**
|
|
189
202
|
* @zh 发送消息到 LangGraph 后端。
|
|
190
203
|
* @en Sends a message to the LangGraph backend.
|
|
@@ -195,7 +208,7 @@ export class LangGraphClient extends EventEmitter {
|
|
|
195
208
|
throw new Error("Thread or Assistant not initialized");
|
|
196
209
|
}
|
|
197
210
|
if (!this.currentThread) {
|
|
198
|
-
await this.createThread();
|
|
211
|
+
await this.createThread({ graphId: this.currentAssistant.graph_id });
|
|
199
212
|
this.emit("thread", {
|
|
200
213
|
event: "thread/create",
|
|
201
214
|
data: {
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import { LangGraphClientConfig } from "../LangGraphClient.js";
|
|
1
2
|
import { ILangGraphClient } from "../types.js";
|
|
2
|
-
export declare const createLangGraphServerClient: () => Promise<ILangGraphClient>;
|
|
3
|
+
export declare const createLangGraphServerClient: (config: LangGraphClientConfig) => Promise<ILangGraphClient>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Client, Message } from "@langchain/langgraph-sdk";
|
|
2
|
+
export declare function revertChatTo(client: Client<{
|
|
3
|
+
messages: Message[];
|
|
4
|
+
}, {
|
|
5
|
+
messages: Message[];
|
|
6
|
+
}, unknown>, threadId: string, messageId: string): Promise<{
|
|
7
|
+
state: {
|
|
8
|
+
messages: Message[];
|
|
9
|
+
};
|
|
10
|
+
checkpoint: Pick<import("@langchain/langgraph-sdk").Config, "configurable">;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export async function revertChatTo(client, threadId, messageId) {
|
|
2
|
+
const thread = await client.threads.get(threadId);
|
|
3
|
+
const messages = thread.values.messages;
|
|
4
|
+
const idx = messages.findIndex((message) => message.id === messageId);
|
|
5
|
+
if (idx === -1) {
|
|
6
|
+
throw new Error(`Message id ${messageId} not found`);
|
|
7
|
+
}
|
|
8
|
+
const removeMessages = messages.slice(idx + 1);
|
|
9
|
+
const state = {
|
|
10
|
+
...thread.values,
|
|
11
|
+
messages: removeMessages.map((i) => {
|
|
12
|
+
// sb langgraph 官方实现都不能正常工作
|
|
13
|
+
// return new RemoveMessage({ id: i.id! }).toJSON();
|
|
14
|
+
return {
|
|
15
|
+
type: "remove",
|
|
16
|
+
id: i.id,
|
|
17
|
+
};
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
const res = await client.threads.updateState(threadId, {
|
|
21
|
+
values: state,
|
|
22
|
+
});
|
|
23
|
+
// client.runs.wait();
|
|
24
|
+
return {
|
|
25
|
+
state: {
|
|
26
|
+
messages: messages.slice(0, idx + 1),
|
|
27
|
+
},
|
|
28
|
+
checkpoint: res,
|
|
29
|
+
};
|
|
30
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type MultitaskStrategy = "reject" | "interrupt" | "rollback" | "enqueue";
|
|
|
8
8
|
export type DisconnectMode = "cancel" | "continue";
|
|
9
9
|
export type OnCompletionBehavior = "complete" | "continue";
|
|
10
10
|
export type CancelAction = "interrupt" | "rollback";
|
|
11
|
-
export type TypedAsyncGenerator<
|
|
11
|
+
export type TypedAsyncGenerator<TStateType = unknown, TUpdateType = TStateType, TCustomType = unknown> = AsyncGenerator<{
|
|
12
12
|
values: ValuesStreamEvent<TStateType>;
|
|
13
13
|
updates: UpdatesStreamEvent<TUpdateType>;
|
|
14
14
|
custom: CustomStreamEvent<TCustomType>;
|
|
@@ -16,11 +16,11 @@ export type TypedAsyncGenerator<TStreamMode extends StreamMode | StreamMode[] =
|
|
|
16
16
|
messages: MessagesStreamEvent;
|
|
17
17
|
"messages-tuple": MessagesTupleStreamEvent;
|
|
18
18
|
events: EventsStreamEvent;
|
|
19
|
-
}[
|
|
19
|
+
}[StreamMode] | ErrorStreamEvent | MetadataStreamEvent | FeedbackStreamEvent>;
|
|
20
20
|
/**
|
|
21
21
|
* 兼容 LangGraph SDK 的接口定义,方便进行无侵入式的扩展
|
|
22
22
|
*/
|
|
23
|
-
export interface ILangGraphClient<TStateType =
|
|
23
|
+
export interface ILangGraphClient<TStateType = {}, TUpdateType = TStateType> {
|
|
24
24
|
assistants: {
|
|
25
25
|
search(query?: {
|
|
26
26
|
graphId?: string;
|
|
@@ -35,7 +35,7 @@ export interface ILangGraphClient<TStateType = unknown, TUpdateType = TStateType
|
|
|
35
35
|
}): Promise<AssistantGraph>;
|
|
36
36
|
};
|
|
37
37
|
threads: {
|
|
38
|
-
create
|
|
38
|
+
create(payload?: {
|
|
39
39
|
metadata?: Metadata;
|
|
40
40
|
threadId?: string;
|
|
41
41
|
ifExists?: OnConflictBehavior;
|
|
@@ -47,16 +47,16 @@ export interface ILangGraphClient<TStateType = unknown, TUpdateType = TStateType
|
|
|
47
47
|
asNode: string;
|
|
48
48
|
}>;
|
|
49
49
|
}>;
|
|
50
|
-
}): Promise<Thread<
|
|
51
|
-
search
|
|
50
|
+
}): Promise<Thread<TStateType>>;
|
|
51
|
+
search(query?: {
|
|
52
52
|
metadata?: Metadata;
|
|
53
53
|
limit?: number;
|
|
54
54
|
offset?: number;
|
|
55
55
|
status?: ThreadStatus;
|
|
56
56
|
sortBy?: ThreadSortBy;
|
|
57
57
|
sortOrder?: SortOrder;
|
|
58
|
-
}): Promise<Thread<
|
|
59
|
-
get
|
|
58
|
+
}): Promise<Thread<TStateType>[]>;
|
|
59
|
+
get(threadId: string): Promise<Thread<TStateType>>;
|
|
60
60
|
delete(threadId: string): Promise<void>;
|
|
61
61
|
};
|
|
62
62
|
runs: {
|
|
@@ -65,31 +65,7 @@ export interface ILangGraphClient<TStateType = unknown, TUpdateType = TStateType
|
|
|
65
65
|
offset?: number;
|
|
66
66
|
status?: RunStatus;
|
|
67
67
|
}): Promise<Run[]>;
|
|
68
|
-
stream<
|
|
69
|
-
input?: Record<string, unknown> | null;
|
|
70
|
-
metadata?: Metadata;
|
|
71
|
-
config?: Config;
|
|
72
|
-
checkpointId?: string;
|
|
73
|
-
checkpoint?: Omit<Checkpoint, "thread_id">;
|
|
74
|
-
checkpointDuring?: boolean;
|
|
75
|
-
interruptBefore?: "*" | string[];
|
|
76
|
-
interruptAfter?: "*" | string[];
|
|
77
|
-
signal?: AbortController["signal"];
|
|
78
|
-
webhook?: string;
|
|
79
|
-
onDisconnect?: DisconnectMode;
|
|
80
|
-
afterSeconds?: number;
|
|
81
|
-
ifNotExists?: "create" | "reject";
|
|
82
|
-
command?: Command;
|
|
83
|
-
onRunCreated?: (params: {
|
|
84
|
-
run_id: string;
|
|
85
|
-
thread_id?: string;
|
|
86
|
-
}) => void;
|
|
87
|
-
streamMode?: TStreamMode;
|
|
88
|
-
streamSubgraphs?: TSubgraphs;
|
|
89
|
-
streamResumable?: boolean;
|
|
90
|
-
feedbackKeys?: string[];
|
|
91
|
-
}): TypedAsyncGenerator<TStreamMode, TSubgraphs, TStateType, TUpdateType>;
|
|
92
|
-
stream<TStreamMode extends StreamMode | StreamMode[] = StreamMode, TSubgraphs extends boolean = false>(threadId: string, assistantId: string, payload?: {
|
|
68
|
+
stream<TSubgraphs extends boolean = false>(threadId: string, assistantId: string, payload?: {
|
|
93
69
|
input?: Record<string, unknown> | null;
|
|
94
70
|
metadata?: Metadata;
|
|
95
71
|
config?: Config;
|
|
@@ -110,12 +86,12 @@ export interface ILangGraphClient<TStateType = unknown, TUpdateType = TStateType
|
|
|
110
86
|
run_id: string;
|
|
111
87
|
thread_id?: string;
|
|
112
88
|
}) => void;
|
|
113
|
-
streamMode?:
|
|
89
|
+
streamMode?: StreamMode[];
|
|
114
90
|
streamSubgraphs?: TSubgraphs;
|
|
115
91
|
streamResumable?: boolean;
|
|
116
92
|
feedbackKeys?: string[];
|
|
117
|
-
}): TypedAsyncGenerator<
|
|
118
|
-
joinStream(threadId: string
|
|
93
|
+
}): TypedAsyncGenerator<TSubgraphs, TStateType, TUpdateType>;
|
|
94
|
+
joinStream(threadId: string, runId: string, options?: {
|
|
119
95
|
signal?: AbortSignal;
|
|
120
96
|
cancelOnDisconnect?: boolean;
|
|
121
97
|
lastEventId?: string;
|
|
@@ -25,7 +25,7 @@ export declare const getHistoryContent: (thread: Thread) => string | any[];
|
|
|
25
25
|
* @zh 创建一个用于聊天界面的状态管理器 (store)。
|
|
26
26
|
* @en Creates a state manager (store) for the chat interface.
|
|
27
27
|
*/
|
|
28
|
-
export declare const createChatStore: (initClientName: string, config: LangGraphClientConfig
|
|
28
|
+
export declare const createChatStore: (initClientName: string, config: Partial<LangGraphClientConfig>, context?: {
|
|
29
29
|
showHistory?: boolean;
|
|
30
30
|
showGraph?: boolean;
|
|
31
31
|
onInit?: (client: LangGraphClient) => void;
|
|
@@ -53,7 +53,7 @@ export declare const createChatStore: (initClientName: string, config: LangGraph
|
|
|
53
53
|
setTools(new_tools: UnionTool<any>[]): void;
|
|
54
54
|
isFELocking(): boolean | undefined;
|
|
55
55
|
initClient: () => Promise<LangGraphClient<unknown, unknown>>;
|
|
56
|
-
sendMessage: (message?: Message[], extraData?: SendMessageOptions) => Promise<void>;
|
|
56
|
+
sendMessage: (message?: Message[], extraData?: SendMessageOptions, withoutCheck?: boolean) => Promise<void>;
|
|
57
57
|
stopGeneration: () => void;
|
|
58
58
|
toggleToolCollapse: (toolId: string) => void;
|
|
59
59
|
toggleHistoryVisible: () => void;
|
|
@@ -61,6 +61,11 @@ export declare const createChatStore: (initClientName: string, config: LangGraph
|
|
|
61
61
|
addToHistory: (thread: Thread<{
|
|
62
62
|
messages: Message[];
|
|
63
63
|
}>) => void;
|
|
64
|
+
/**
|
|
65
|
+
* @zh 回滚到指定的消息。
|
|
66
|
+
* @en Reverts to the specified message.
|
|
67
|
+
*/
|
|
68
|
+
revertChatTo(messageId: string, resend?: boolean, sendOptions?: SendMessageOptions): Promise<void>;
|
|
64
69
|
/**
|
|
65
70
|
* @zh 设置用户输入内容。
|
|
66
71
|
* @en Sets the user input content.
|
|
@@ -106,7 +106,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
106
106
|
var _a, _b;
|
|
107
107
|
const newClient = new LangGraphClient({
|
|
108
108
|
...config,
|
|
109
|
-
client: (_a = config.client) !== null && _a !== void 0 ? _a : (await createLangGraphServerClient()),
|
|
109
|
+
client: (_a = config.client) !== null && _a !== void 0 ? _a : (await createLangGraphServerClient(config)),
|
|
110
110
|
});
|
|
111
111
|
await newClient.initAssistant(currentAgent.get());
|
|
112
112
|
currentAgent.set(newClient.getCurrentAssistant().graph_id);
|
|
@@ -158,15 +158,25 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
158
158
|
* @zh 发送消息。
|
|
159
159
|
* @en Sends a message.
|
|
160
160
|
*/
|
|
161
|
-
const sendMessage = async (message, extraData) => {
|
|
162
|
-
var _a;
|
|
163
|
-
if ((!userInput.get().trim() && !(message === null || message === void 0 ? void 0 : message.length)) || loading.get() || !client.get())
|
|
161
|
+
const sendMessage = async (message, extraData, withoutCheck = false) => {
|
|
162
|
+
var _a, _b;
|
|
163
|
+
if ((!withoutCheck && !userInput.get().trim() && !(message === null || message === void 0 ? void 0 : message.length)) || loading.get() || !client.get())
|
|
164
164
|
return;
|
|
165
165
|
loading.set(true);
|
|
166
166
|
inChatError.set(null);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
try {
|
|
168
|
+
await ((_a = client.get()) === null || _a === void 0 ? void 0 : _a.sendMessage(message || userInput.get(), extraData));
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
const isThreadRunning = e.message.includes("422");
|
|
172
|
+
if (isThreadRunning) {
|
|
173
|
+
await ((_b = client.get()) === null || _b === void 0 ? void 0 : _b.resetStream());
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
userInput.set("");
|
|
178
|
+
loading.set(false);
|
|
179
|
+
}
|
|
170
180
|
};
|
|
171
181
|
/**
|
|
172
182
|
* @zh 停止当前的消息生成。
|
|
@@ -259,6 +269,20 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
259
269
|
toggleHistoryVisible,
|
|
260
270
|
refreshHistoryList,
|
|
261
271
|
addToHistory,
|
|
272
|
+
/**
|
|
273
|
+
* @zh 回滚到指定的消息。
|
|
274
|
+
* @en Reverts to the specified message.
|
|
275
|
+
*/
|
|
276
|
+
async revertChatTo(messageId, resend = false, sendOptions) {
|
|
277
|
+
var _a;
|
|
278
|
+
await ((_a = client.get()) === null || _a === void 0 ? void 0 : _a.revertChatTo(messageId));
|
|
279
|
+
if (resend) {
|
|
280
|
+
return sendMessage([], sendOptions, true);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
updateUI(client.get());
|
|
284
|
+
}
|
|
285
|
+
},
|
|
262
286
|
/**
|
|
263
287
|
* @zh 设置用户输入内容。
|
|
264
288
|
* @en Sets the user input content.
|
package/package.json
CHANGED
package/src/LangGraphClient.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { ToolManager } from "./ToolManager.js";
|
|
|
4
4
|
import { CallToolResult } from "./tool/createTool.js";
|
|
5
5
|
import { ILangGraphClient } from "./types.js";
|
|
6
6
|
import { MessageProcessor } from "./MessageProcessor.js";
|
|
7
|
+
import { revertChatTo } from "./time-travel/index.js";
|
|
7
8
|
|
|
8
9
|
export type RenderMessage = Message & {
|
|
9
10
|
/** 对于 AIMessage 来说是节点名称,对于工具节点来说是工具名称 */
|
|
@@ -68,7 +69,7 @@ export interface LangGraphClientConfig {
|
|
|
68
69
|
timeoutMs?: number;
|
|
69
70
|
defaultHeaders?: Record<string, string | null | undefined>;
|
|
70
71
|
/** 自定义客户端实现,如果不提供则使用官方 Client */
|
|
71
|
-
client: ILangGraphClient
|
|
72
|
+
client: ILangGraphClient<any, any>;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
// 定义事件数据类型
|
|
@@ -96,6 +97,9 @@ export class LangGraphClient<TStateType = unknown, TUpdateType = TStateType> ext
|
|
|
96
97
|
private currentAssistant: Assistant | null = null;
|
|
97
98
|
private currentThread: Thread<TStateType> | null = null;
|
|
98
99
|
tools: ToolManager = new ToolManager();
|
|
100
|
+
availableAssistants: Assistant[] = [];
|
|
101
|
+
graphState: any = {};
|
|
102
|
+
currentRun?: { run_id: string };
|
|
99
103
|
stopController: AbortController | null = null;
|
|
100
104
|
/** 用于存储 subAgent 状态数据的键 */
|
|
101
105
|
subAgentsKey = "task_store";
|
|
@@ -122,7 +126,6 @@ export class LangGraphClient<TStateType = unknown, TUpdateType = TStateType> ext
|
|
|
122
126
|
get runs() {
|
|
123
127
|
return this.client.runs;
|
|
124
128
|
}
|
|
125
|
-
availableAssistants: Assistant[] = [];
|
|
126
129
|
private listAssistants() {
|
|
127
130
|
return this.assistants.search({
|
|
128
131
|
metadata: null,
|
|
@@ -162,12 +165,15 @@ export class LangGraphClient<TStateType = unknown, TUpdateType = TStateType> ext
|
|
|
162
165
|
*/
|
|
163
166
|
async createThread({
|
|
164
167
|
threadId,
|
|
168
|
+
graphId,
|
|
165
169
|
}: {
|
|
166
170
|
threadId?: string;
|
|
171
|
+
graphId?: string;
|
|
167
172
|
} = {}) {
|
|
168
173
|
try {
|
|
169
174
|
this.currentThread = await this.threads.create({
|
|
170
175
|
threadId,
|
|
176
|
+
graphId,
|
|
171
177
|
});
|
|
172
178
|
return this.currentThread;
|
|
173
179
|
} catch (error) {
|
|
@@ -272,8 +278,7 @@ export class LangGraphClient<TStateType = unknown, TUpdateType = TStateType> ext
|
|
|
272
278
|
const tool = this.tools.getTool(lastMessage?.name!);
|
|
273
279
|
return tool && tool.render && lastMessage?.type === "tool" && !lastMessage?.additional_kwargs?.done;
|
|
274
280
|
}
|
|
275
|
-
|
|
276
|
-
currentRun?: { run_id: string };
|
|
281
|
+
|
|
277
282
|
/**
|
|
278
283
|
* @zh 取消当前的 Run。
|
|
279
284
|
* @en Cancels the current Run.
|
|
@@ -283,6 +288,17 @@ export class LangGraphClient<TStateType = unknown, TUpdateType = TStateType> ext
|
|
|
283
288
|
this.runs.cancel((this.currentThread as any)!.thread_id, this.currentRun.run_id);
|
|
284
289
|
}
|
|
285
290
|
}
|
|
291
|
+
/**
|
|
292
|
+
* @zh 回滚到指定的消息。但是不会触发数据的重新更新
|
|
293
|
+
* @en Reverts to the specified message.
|
|
294
|
+
*/
|
|
295
|
+
async revertChatTo(messageId: string) {
|
|
296
|
+
const { state, checkpoint } = await revertChatTo(this.client as any, this.currentThread!.thread_id, messageId);
|
|
297
|
+
this.graphState = state;
|
|
298
|
+
this.messageProcessor.clearStreamingMessages();
|
|
299
|
+
this.messageProcessor.setGraphMessages(state.messages! as RenderMessage[]);
|
|
300
|
+
return state;
|
|
301
|
+
}
|
|
286
302
|
/**
|
|
287
303
|
* @zh 发送消息到 LangGraph 后端。
|
|
288
304
|
* @en Sends a message to the LangGraph backend.
|
|
@@ -292,7 +308,7 @@ export class LangGraphClient<TStateType = unknown, TUpdateType = TStateType> ext
|
|
|
292
308
|
throw new Error("Thread or Assistant not initialized");
|
|
293
309
|
}
|
|
294
310
|
if (!this.currentThread) {
|
|
295
|
-
await this.createThread();
|
|
311
|
+
await this.createThread({ graphId: this.currentAssistant!.graph_id });
|
|
296
312
|
this.emit("thread", {
|
|
297
313
|
event: "thread/create",
|
|
298
314
|
data: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { LangGraphClientConfig } from "../LangGraphClient.js";
|
|
1
2
|
import { ILangGraphClient } from "../types.js";
|
|
2
3
|
|
|
3
|
-
export const createLangGraphServerClient = async (): Promise<ILangGraphClient> => {
|
|
4
|
+
export const createLangGraphServerClient = async (config: LangGraphClientConfig): Promise<ILangGraphClient> => {
|
|
4
5
|
const { Client } = await import("@langchain/langgraph-sdk");
|
|
5
|
-
return new Client() as unknown as ILangGraphClient;
|
|
6
|
+
return new Client(config) as unknown as ILangGraphClient;
|
|
6
7
|
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { RemoveMessage } from "@langchain/core/messages";
|
|
2
|
+
import { Client, Message } from "@langchain/langgraph-sdk";
|
|
3
|
+
|
|
4
|
+
export async function revertChatTo(client: Client<{ messages: Message[] }, { messages: Message[] }, unknown>, threadId: string, messageId: string) {
|
|
5
|
+
const thread = await client.threads.get(threadId);
|
|
6
|
+
const messages = thread.values.messages;
|
|
7
|
+
const idx = messages.findIndex((message) => message.id === messageId);
|
|
8
|
+
if (idx === -1) {
|
|
9
|
+
throw new Error(`Message id ${messageId} not found`);
|
|
10
|
+
}
|
|
11
|
+
const removeMessages = messages.slice(idx + 1);
|
|
12
|
+
const state = {
|
|
13
|
+
...thread.values,
|
|
14
|
+
messages: removeMessages.map((i) => {
|
|
15
|
+
// sb langgraph 官方实现都不能正常工作
|
|
16
|
+
// return new RemoveMessage({ id: i.id! }).toJSON();
|
|
17
|
+
return {
|
|
18
|
+
type: "remove",
|
|
19
|
+
id: i.id!,
|
|
20
|
+
};
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
const res = await client.threads.updateState(threadId, {
|
|
24
|
+
values: state,
|
|
25
|
+
});
|
|
26
|
+
// client.runs.wait();
|
|
27
|
+
return {
|
|
28
|
+
state: {
|
|
29
|
+
messages: messages.slice(0, idx + 1),
|
|
30
|
+
},
|
|
31
|
+
checkpoint: res,
|
|
32
|
+
};
|
|
33
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -34,13 +34,7 @@ export type OnCompletionBehavior = "complete" | "continue";
|
|
|
34
34
|
export type CancelAction = "interrupt" | "rollback";
|
|
35
35
|
|
|
36
36
|
// 流式异步生成器类型
|
|
37
|
-
export type TypedAsyncGenerator<
|
|
38
|
-
TStreamMode extends StreamMode | StreamMode[] = [],
|
|
39
|
-
TSubgraphs extends boolean = false,
|
|
40
|
-
TStateType = unknown,
|
|
41
|
-
TUpdateType = TStateType,
|
|
42
|
-
TCustomType = unknown,
|
|
43
|
-
> = AsyncGenerator<
|
|
37
|
+
export type TypedAsyncGenerator<TStateType = unknown, TUpdateType = TStateType, TCustomType = unknown> = AsyncGenerator<
|
|
44
38
|
| {
|
|
45
39
|
values: ValuesStreamEvent<TStateType>;
|
|
46
40
|
updates: UpdatesStreamEvent<TUpdateType>;
|
|
@@ -49,7 +43,7 @@ export type TypedAsyncGenerator<
|
|
|
49
43
|
messages: MessagesStreamEvent;
|
|
50
44
|
"messages-tuple": MessagesTupleStreamEvent;
|
|
51
45
|
events: EventsStreamEvent;
|
|
52
|
-
}[
|
|
46
|
+
}[StreamMode]
|
|
53
47
|
| ErrorStreamEvent
|
|
54
48
|
| MetadataStreamEvent
|
|
55
49
|
| FeedbackStreamEvent
|
|
@@ -58,13 +52,13 @@ export type TypedAsyncGenerator<
|
|
|
58
52
|
/**
|
|
59
53
|
* 兼容 LangGraph SDK 的接口定义,方便进行无侵入式的扩展
|
|
60
54
|
*/
|
|
61
|
-
export interface ILangGraphClient<TStateType =
|
|
55
|
+
export interface ILangGraphClient<TStateType = {}, TUpdateType = TStateType> {
|
|
62
56
|
assistants: {
|
|
63
57
|
search(query?: { graphId?: string; metadata?: Metadata; limit?: number; offset?: number; sortBy?: AssistantSortBy; sortOrder?: SortOrder }): Promise<Assistant[]>;
|
|
64
58
|
getGraph(assistantId: string, options?: { xray?: boolean | number }): Promise<AssistantGraph>;
|
|
65
59
|
};
|
|
66
60
|
threads: {
|
|
67
|
-
create
|
|
61
|
+
create(payload?: {
|
|
68
62
|
metadata?: Metadata;
|
|
69
63
|
threadId?: string;
|
|
70
64
|
ifExists?: OnConflictBehavior;
|
|
@@ -76,16 +70,9 @@ export interface ILangGraphClient<TStateType = unknown, TUpdateType = TStateType
|
|
|
76
70
|
asNode: string;
|
|
77
71
|
}>;
|
|
78
72
|
}>;
|
|
79
|
-
}): Promise<Thread<
|
|
80
|
-
search
|
|
81
|
-
|
|
82
|
-
limit?: number;
|
|
83
|
-
offset?: number;
|
|
84
|
-
status?: ThreadStatus;
|
|
85
|
-
sortBy?: ThreadSortBy;
|
|
86
|
-
sortOrder?: SortOrder;
|
|
87
|
-
}): Promise<Thread<ValuesType>[]>;
|
|
88
|
-
get<ValuesType = TStateType>(threadId: string): Promise<Thread<ValuesType>>;
|
|
73
|
+
}): Promise<Thread<TStateType>>;
|
|
74
|
+
search(query?: { metadata?: Metadata; limit?: number; offset?: number; status?: ThreadStatus; sortBy?: ThreadSortBy; sortOrder?: SortOrder }): Promise<Thread<TStateType>[]>;
|
|
75
|
+
get(threadId: string): Promise<Thread<TStateType>>;
|
|
89
76
|
delete(threadId: string): Promise<void>;
|
|
90
77
|
};
|
|
91
78
|
runs: {
|
|
@@ -97,32 +84,8 @@ export interface ILangGraphClient<TStateType = unknown, TUpdateType = TStateType
|
|
|
97
84
|
status?: RunStatus;
|
|
98
85
|
}
|
|
99
86
|
): Promise<Run[]>;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
assistantId: string,
|
|
103
|
-
payload?: {
|
|
104
|
-
input?: Record<string, unknown> | null;
|
|
105
|
-
metadata?: Metadata;
|
|
106
|
-
config?: Config;
|
|
107
|
-
checkpointId?: string;
|
|
108
|
-
checkpoint?: Omit<Checkpoint, "thread_id">;
|
|
109
|
-
checkpointDuring?: boolean;
|
|
110
|
-
interruptBefore?: "*" | string[];
|
|
111
|
-
interruptAfter?: "*" | string[];
|
|
112
|
-
signal?: AbortController["signal"];
|
|
113
|
-
webhook?: string;
|
|
114
|
-
onDisconnect?: DisconnectMode;
|
|
115
|
-
afterSeconds?: number;
|
|
116
|
-
ifNotExists?: "create" | "reject";
|
|
117
|
-
command?: Command;
|
|
118
|
-
onRunCreated?: (params: { run_id: string; thread_id?: string }) => void;
|
|
119
|
-
streamMode?: TStreamMode;
|
|
120
|
-
streamSubgraphs?: TSubgraphs;
|
|
121
|
-
streamResumable?: boolean;
|
|
122
|
-
feedbackKeys?: string[];
|
|
123
|
-
}
|
|
124
|
-
): TypedAsyncGenerator<TStreamMode, TSubgraphs, TStateType, TUpdateType>;
|
|
125
|
-
stream<TStreamMode extends StreamMode | StreamMode[] = StreamMode, TSubgraphs extends boolean = false>(
|
|
87
|
+
|
|
88
|
+
stream<TSubgraphs extends boolean = false>(
|
|
126
89
|
threadId: string,
|
|
127
90
|
assistantId: string,
|
|
128
91
|
payload?: {
|
|
@@ -143,14 +106,14 @@ export interface ILangGraphClient<TStateType = unknown, TUpdateType = TStateType
|
|
|
143
106
|
ifNotExists?: "create" | "reject";
|
|
144
107
|
command?: Command;
|
|
145
108
|
onRunCreated?: (params: { run_id: string; thread_id?: string }) => void;
|
|
146
|
-
streamMode?:
|
|
109
|
+
streamMode?: StreamMode[];
|
|
147
110
|
streamSubgraphs?: TSubgraphs;
|
|
148
111
|
streamResumable?: boolean;
|
|
149
112
|
feedbackKeys?: string[];
|
|
150
113
|
}
|
|
151
|
-
): TypedAsyncGenerator<
|
|
114
|
+
): TypedAsyncGenerator<TSubgraphs, TStateType, TUpdateType>;
|
|
152
115
|
joinStream(
|
|
153
|
-
threadId: string
|
|
116
|
+
threadId: string,
|
|
154
117
|
runId: string,
|
|
155
118
|
options?:
|
|
156
119
|
| {
|
|
@@ -66,7 +66,7 @@ export const getHistoryContent = (thread: Thread) => {
|
|
|
66
66
|
*/
|
|
67
67
|
export const createChatStore = (
|
|
68
68
|
initClientName: string,
|
|
69
|
-
config: LangGraphClientConfig
|
|
69
|
+
config: Partial<LangGraphClientConfig>,
|
|
70
70
|
context: {
|
|
71
71
|
showHistory?: boolean;
|
|
72
72
|
showGraph?: boolean;
|
|
@@ -113,7 +113,7 @@ export const createChatStore = (
|
|
|
113
113
|
async function initClient() {
|
|
114
114
|
const newClient = new LangGraphClient({
|
|
115
115
|
...config,
|
|
116
|
-
client: config.client ?? (await createLangGraphServerClient()),
|
|
116
|
+
client: config.client ?? (await createLangGraphServerClient(config as LangGraphClientConfig)),
|
|
117
117
|
});
|
|
118
118
|
await newClient.initAssistant(currentAgent.get());
|
|
119
119
|
currentAgent.set(newClient.getCurrentAssistant()!.graph_id);
|
|
@@ -167,16 +167,22 @@ export const createChatStore = (
|
|
|
167
167
|
* @zh 发送消息。
|
|
168
168
|
* @en Sends a message.
|
|
169
169
|
*/
|
|
170
|
-
const sendMessage = async (message?: Message[], extraData?: SendMessageOptions) => {
|
|
171
|
-
if ((!userInput.get().trim() && !message?.length) || loading.get() || !client.get()) return;
|
|
170
|
+
const sendMessage = async (message?: Message[], extraData?: SendMessageOptions, withoutCheck = false) => {
|
|
171
|
+
if ((!withoutCheck && !userInput.get().trim() && !message?.length) || loading.get() || !client.get()) return;
|
|
172
172
|
|
|
173
173
|
loading.set(true);
|
|
174
174
|
inChatError.set(null);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
try {
|
|
176
|
+
await client.get()?.sendMessage(message || userInput.get(), extraData);
|
|
177
|
+
} catch (e) {
|
|
178
|
+
const isThreadRunning = (e as Error).message.includes("422");
|
|
179
|
+
if (isThreadRunning) {
|
|
180
|
+
await client.get()?.resetStream();
|
|
181
|
+
}
|
|
182
|
+
} finally {
|
|
183
|
+
userInput.set("");
|
|
184
|
+
loading.set(false);
|
|
185
|
+
}
|
|
180
186
|
};
|
|
181
187
|
|
|
182
188
|
/**
|
|
@@ -270,6 +276,18 @@ export const createChatStore = (
|
|
|
270
276
|
toggleHistoryVisible,
|
|
271
277
|
refreshHistoryList,
|
|
272
278
|
addToHistory,
|
|
279
|
+
/**
|
|
280
|
+
* @zh 回滚到指定的消息。
|
|
281
|
+
* @en Reverts to the specified message.
|
|
282
|
+
*/
|
|
283
|
+
async revertChatTo(messageId: string, resend = false, sendOptions?: SendMessageOptions) {
|
|
284
|
+
await client.get()?.revertChatTo(messageId);
|
|
285
|
+
if (resend) {
|
|
286
|
+
return sendMessage([], sendOptions, true);
|
|
287
|
+
} else {
|
|
288
|
+
updateUI(client.get()!);
|
|
289
|
+
}
|
|
290
|
+
},
|
|
273
291
|
/**
|
|
274
292
|
* @zh 设置用户输入内容。
|
|
275
293
|
* @en Sets the user input content.
|