@langgraph-js/sdk 3.7.1 → 3.8.1

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.
@@ -33,6 +33,8 @@ export interface ChatProviderProps {
33
33
  showHistory?: boolean;
34
34
  showGraph?: boolean;
35
35
  fallbackToAvailableAssistants?: boolean;
36
+ /** 初始化时是否自动激活最近的历史会话(默认 false,创建新会话) */
37
+ autoRestoreLastSession?: boolean;
36
38
  onInitError?: (error: any, currentAgent: string) => void;
37
39
  client?: ILangGraphClient;
38
40
  legacyMode?: boolean;
@@ -48,51 +50,57 @@ export declare const useChatProvider: (props: ChatProviderProps) => {
48
50
  currentArtifactId: PreinitializedWritableAtom<[string, string] | null> & object;
49
51
  showArtifact: PreinitializedWritableAtom<boolean> & object;
50
52
  client: PreinitializedWritableAtom<import("../LangGraphClient.js").LangGraphClient<unknown> | null> & object;
53
+ history: PreinitializedWritableAtom<import("../History.js").History | null> & object;
54
+ sessions: PreinitializedWritableAtom<import("../History.js").SessionInfo[]> & object;
51
55
  renderMessages: PreinitializedWritableAtom<import("../LangGraphClient.js").RenderMessage[]> & object;
52
56
  userInput: PreinitializedWritableAtom<string> & object;
53
57
  loading: PreinitializedWritableAtom<boolean> & object;
54
58
  inChatError: PreinitializedWritableAtom<string | null> & object;
55
59
  currentAgent: PreinitializedWritableAtom<string> & object;
60
+ currentChatId: PreinitializedWritableAtom<string | null> & object;
61
+ currentNodeName: PreinitializedWritableAtom<string> & object;
62
+ tools: PreinitializedWritableAtom<import("../index.js").UnionTool<any, Object, any>[]> & object;
56
63
  collapsedTools: PreinitializedWritableAtom<string[]> & object;
64
+ showGraph: PreinitializedWritableAtom<boolean> & object;
65
+ graphVisualize: PreinitializedWritableAtom<import("@langchain/langgraph-sdk").AssistantGraph | null> & object;
57
66
  showHistory: PreinitializedWritableAtom<boolean> & object;
58
67
  historyList: PreinitializedWritableAtom<import("@langchain/langgraph-sdk").Thread<{
59
68
  messages: import("@langchain/langgraph-sdk").Message[];
60
69
  }>[]> & object;
61
- currentChatId: PreinitializedWritableAtom<string | null> & object;
62
- showGraph: PreinitializedWritableAtom<boolean> & object;
63
- graphVisualize: PreinitializedWritableAtom<import("@langchain/langgraph-sdk").AssistantGraph | null> & object;
64
- currentNodeName: PreinitializedWritableAtom<string> & object;
65
- tools: PreinitializedWritableAtom<import("../index.js").UnionTool<any, Object, any>[]> & object;
66
70
  };
67
71
  mutations: {
68
72
  setCurrentArtifactById: (id: string, tool_id: string) => void;
69
73
  setShowArtifact: (show: boolean) => void;
70
- refreshTools: () => Promise<void>;
71
- setTools(new_tools: import("../index.js").UnionTool<any>[]): void;
72
- isFELocking(): boolean | undefined;
73
- getClient(): import("../LangGraphClient.js").LangGraphClient<unknown> | null;
74
- initClient: () => Promise<import("../LangGraphClient.js").LangGraphClient<unknown>>;
74
+ initClient: () => Promise<import("../History.js").History>;
75
+ getClient: () => import("../LangGraphClient.js").LangGraphClient<unknown> | null;
76
+ getHistory: () => import("../History.js").History | null;
77
+ activateSession: (sessionId: string) => Promise<void>;
78
+ createNewSession: () => Promise<void>;
79
+ refreshSessionList: () => Promise<void>;
80
+ refreshHistoryList: () => Promise<void>;
75
81
  sendMessage: (message?: import("@langchain/langgraph-sdk").Message[], extraData?: import("../LangGraphClient.js").SendMessageOptions, withoutCheck?: boolean) => Promise<void>;
76
82
  stopGeneration: () => void;
83
+ setUserInput: (input: string) => void;
84
+ revertChatTo(messageId: string, resend?: boolean, sendOptions?: import("../LangGraphClient.js").SendMessageOptions & import("../time-travel/index.js").RevertChatToOptions): Promise<void>;
85
+ refreshTools: () => Promise<void>;
86
+ setTools(new_tools: import("../index.js").UnionTool<any>[]): void;
77
87
  toggleToolCollapse: (toolId: string) => void;
88
+ getToolUIRender: (tool_name: string) => ((message: import("../LangGraphClient.js").RenderMessage) => Object) | null;
89
+ isFELocking: () => boolean | undefined;
78
90
  toggleHistoryVisible: () => void;
79
- refreshHistoryList: () => Promise<void>;
91
+ toggleGraphVisible(): void;
92
+ refreshGraph: () => Promise<void>;
93
+ setCurrentAgent(agent: string): Promise<import("../History.js").History>;
80
94
  addToHistory: (thread: import("@langchain/langgraph-sdk").Thread<{
81
95
  messages: import("@langchain/langgraph-sdk").Message[];
82
96
  }>) => void;
83
- revertChatTo(messageId: string, resend?: boolean, sendOptions?: import("../LangGraphClient.js").SendMessageOptions & import("../time-travel/index.js").RevertChatToOptions): Promise<void>;
84
- setUserInput(input: string): void;
85
- setCurrentAgent(agent: string): Promise<void>;
86
- toggleGraphVisible(): void;
87
- refreshGraph: () => Promise<void>;
88
- createNewChat(): void;
89
- toHistoryChat(thread: import("@langchain/langgraph-sdk").Thread<{
97
+ createNewChat: () => Promise<void>;
98
+ toHistoryChat: (thread: import("@langchain/langgraph-sdk").Thread<{
90
99
  messages: import("@langchain/langgraph-sdk").Message[];
91
- }>): Promise<import("@langchain/langgraph-sdk").Thread<unknown> | undefined>;
100
+ }>) => Promise<void>;
92
101
  deleteHistoryChat(thread: import("@langchain/langgraph-sdk").Thread<{
93
102
  messages: import("@langchain/langgraph-sdk").Message[];
94
103
  }>): Promise<void>;
95
- getToolUIRender: (tool_name: string) => ((message: import("../LangGraphClient.js").RenderMessage) => Object) | null;
96
104
  };
97
105
  }>;
98
106
  };
@@ -125,6 +133,10 @@ export declare const ChatProvider: import("vue").DefineComponent<import("vue").E
125
133
  type: PropType<boolean>;
126
134
  default: boolean;
127
135
  };
136
+ autoRestoreLastSession: {
137
+ type: PropType<boolean>;
138
+ default: boolean;
139
+ };
128
140
  onInitError: {
129
141
  type: PropType<(error: any, currentAgent: string) => void>;
130
142
  default: undefined;
@@ -156,6 +168,10 @@ export declare const ChatProvider: import("vue").DefineComponent<import("vue").E
156
168
  type: PropType<boolean>;
157
169
  default: boolean;
158
170
  };
171
+ autoRestoreLastSession: {
172
+ type: PropType<boolean>;
173
+ default: boolean;
174
+ };
159
175
  onInitError: {
160
176
  type: PropType<(error: any, currentAgent: string) => void>;
161
177
  default: undefined;
@@ -163,9 +179,10 @@ export declare const ChatProvider: import("vue").DefineComponent<import("vue").E
163
179
  }>> & Readonly<{}>, {
164
180
  apiUrl: string;
165
181
  defaultHeaders: Record<string, string>;
166
- showHistory: boolean;
167
182
  showGraph: boolean;
183
+ showHistory: boolean;
168
184
  defaultAgent: string;
169
185
  withCredentials: boolean;
186
+ autoRestoreLastSession: boolean;
170
187
  onInitError: (error: any, currentAgent: string) => void;
171
188
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -51,6 +51,7 @@ export const useChatProvider = (props) => {
51
51
  showHistory: props.showHistory,
52
52
  showGraph: props.showGraph,
53
53
  fallbackToAvailableAssistants: props.fallbackToAvailableAssistants,
54
+ autoRestoreLastSession: props.autoRestoreLastSession,
54
55
  });
55
56
  const unionStore = useUnionStoreVue(store, useStore);
56
57
  // 提供 store 给子组件
@@ -106,6 +107,10 @@ export const ChatProvider = defineComponent({
106
107
  type: Boolean,
107
108
  default: false,
108
109
  },
110
+ autoRestoreLastSession: {
111
+ type: Boolean,
112
+ default: false,
113
+ },
109
114
  onInitError: {
110
115
  type: Function,
111
116
  default: undefined,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langgraph-js/sdk",
3
- "version": "3.7.1",
3
+ "version": "3.8.1",
4
4
  "description": "The UI SDK for LangGraph - seamlessly integrate your AI agents with frontend interfaces",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
package/src/History.ts ADDED
@@ -0,0 +1,294 @@
1
+ import { LangGraphClient, LangGraphClientConfig } from "./LangGraphClient.js";
2
+ import type { Thread } from "@langchain/langgraph-sdk";
3
+
4
+ export interface SessionInfo {
5
+ /** 会话唯一标识,同时也是 threadId */
6
+ sessionId: string;
7
+ /** LangGraphClient 实例(懒加载) */
8
+ client?: LangGraphClient;
9
+ /** Thread 信息(懒加载,第一条消息后才创建) */
10
+ thread?: Thread<any>;
11
+ /** Agent 名称 */
12
+ agentName: string;
13
+ }
14
+
15
+ export interface CreateSessionOptions {
16
+ /** 会话 ID / Thread ID,不提供则自动生成 */
17
+ sessionId?: string;
18
+ /** Agent 名称 */
19
+ agentName?: string;
20
+ /** 是否从已有 Thread 恢复会话 */
21
+ restore?: boolean;
22
+ /** Graph ID */
23
+ graphId?: string;
24
+ }
25
+
26
+ /**
27
+ * @zh History 类用于管理多个 LangGraphClient 实例,支持多会话场景
28
+ * @en History class manages multiple LangGraphClient instances for multi-session scenarios
29
+ */
30
+ export class History {
31
+ /** 存储所有会话的 Map */
32
+ private sessions: Map<string, SessionInfo> = new Map();
33
+ /** 当前活跃的会话 ID */
34
+ private activeSessionId: string | null = null;
35
+ /** 客户端配置,用于创建新的 LangGraphClient 实例 */
36
+ private clientConfig: LangGraphClientConfig;
37
+ /** 虚拟 Client,用于查询操作(不绑定特定 Thread) */
38
+ private virtualClient: LangGraphClient;
39
+
40
+ constructor(clientConfig: LangGraphClientConfig) {
41
+ this.clientConfig = clientConfig;
42
+ this.virtualClient = new LangGraphClient(clientConfig);
43
+ }
44
+
45
+ /**
46
+ * @zh 创建新会话(延迟创建 Thread,直到发送第一条消息)
47
+ * @en Creates a new session (lazy Thread creation until first message)
48
+ */
49
+ async createSession(options: CreateSessionOptions = {}): Promise<SessionInfo> {
50
+ const sessionId = options.sessionId || this.generateSessionId();
51
+ const agentName = options.agentName || this.virtualClient.getCurrentAssistant()?.graph_id;
52
+
53
+ if (!agentName) {
54
+ throw new Error("Agent name is required. Please call init() first or provide agentName.");
55
+ }
56
+
57
+ if (this.sessions.has(sessionId)) {
58
+ throw new Error(`Session ${sessionId} already exists`);
59
+ }
60
+
61
+ const sessionInfo: SessionInfo = {
62
+ sessionId,
63
+ agentName,
64
+ };
65
+
66
+ // 如果是从已有 Thread 恢复,则立即获取 Thread
67
+ if (options.restore) {
68
+ sessionInfo.thread = (await this.virtualClient.threads.get(sessionId)) as Thread<any>;
69
+ }
70
+ // 否则 thread 为 undefined,等待第一条消息时由 Client 自动创建
71
+
72
+ this.sessions.set(sessionId, sessionInfo);
73
+
74
+ return sessionInfo;
75
+ }
76
+
77
+ /**
78
+ * @zh 激活指定会话(懒加载创建 Client)
79
+ * @en Activates the specified session (lazy load client)
80
+ */
81
+ async activateSession(sessionId: string): Promise<SessionInfo> {
82
+ const session = this.sessions.get(sessionId);
83
+ if (!session) {
84
+ throw new Error(`Session ${sessionId} not found`);
85
+ }
86
+
87
+ // 懒加载:只在激活时创建 Client
88
+ if (!session.client) {
89
+ const client = new LangGraphClient(this.clientConfig);
90
+ await client.initAssistant(session.agentName);
91
+
92
+ // 只有在有 thread 的情况下才重置(恢复已有会话)
93
+ // 新会话的 thread 会在发送第一条消息时自动创建
94
+ if (session.thread) {
95
+ await client.resetThread(session.agentName, sessionId);
96
+ }
97
+
98
+ session.client = client;
99
+ }
100
+ const lastSession = this.activeSessionId && this.sessions.get(this.activeSessionId);
101
+ // 空闲的 client 就需要销毁
102
+ if (lastSession && lastSession.client?.status === "idle") {
103
+ lastSession.client?.reset();
104
+ lastSession.client = undefined;
105
+ }
106
+ this.activeSessionId = sessionId;
107
+ return session;
108
+ }
109
+
110
+ /**
111
+ * @zh 获取当前活跃的会话
112
+ * @en Gets the current active session
113
+ */
114
+ getActiveSession(): SessionInfo | null {
115
+ if (!this.activeSessionId) {
116
+ return null;
117
+ }
118
+ return this.sessions.get(this.activeSessionId) || null;
119
+ }
120
+
121
+ /**
122
+ * @zh 获取指定会话
123
+ * @en Gets the specified session
124
+ */
125
+ getSession(sessionId: string): SessionInfo | null {
126
+ return this.sessions.get(sessionId) || null;
127
+ }
128
+
129
+ /**
130
+ * @zh 获取所有会话
131
+ * @en Gets all sessions
132
+ */
133
+ getAllSessions(): SessionInfo[] {
134
+ return Array.from(this.sessions.values());
135
+ }
136
+
137
+ /**
138
+ * @zh 删除指定会话
139
+ * @en Deletes the specified session
140
+ */
141
+ async deleteSession(sessionId: string): Promise<boolean> {
142
+ const session = this.sessions.get(sessionId);
143
+ if (!session) {
144
+ return false;
145
+ }
146
+
147
+ // 如果删除的是当前活跃会话,清空活跃会话
148
+ if (this.activeSessionId === sessionId) {
149
+ this.activeSessionId = null;
150
+ }
151
+
152
+ // 删除对应的远程 Thread
153
+ try {
154
+ await this.virtualClient.deleteThread(sessionId);
155
+ } catch (error) {
156
+ console.warn(`Failed to delete thread for session ${sessionId}:`, error);
157
+ }
158
+
159
+ this.sessions.delete(sessionId);
160
+ return true;
161
+ }
162
+
163
+ /**
164
+ * @zh 清空所有会话
165
+ * @en Clears all sessions
166
+ */
167
+ async clearAllSessions(): Promise<void> {
168
+ const sessionIds = Array.from(this.sessions.keys());
169
+ for (const sessionId of sessionIds) {
170
+ await this.deleteSession(sessionId);
171
+ }
172
+ this.activeSessionId = null;
173
+ }
174
+
175
+ /**
176
+ * @zh 获取会话数量
177
+ * @en Gets the number of sessions
178
+ */
179
+ getSessionCount(): number {
180
+ return this.sessions.size;
181
+ }
182
+
183
+ /**
184
+ * @zh 生成会话 ID (UUID v4 格式)
185
+ * @en Generates a session ID (UUID v4 format)
186
+ */
187
+ private generateSessionId(): string {
188
+ // 优先使用 crypto.randomUUID (Node.js 15.6+, 浏览器支持)
189
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
190
+ return crypto.randomUUID();
191
+ }
192
+
193
+ // 降级方案:生成符合 UUID v4 格式的随机 ID
194
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
195
+ const r = (Math.random() * 16) | 0;
196
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
197
+ return v.toString(16);
198
+ });
199
+ }
200
+
201
+ /**
202
+ * @zh 从已有的 Thread 添加会话(仅添加元数据,不创建 Client)
203
+ * @en Adds a session from an existing Thread (metadata only, no client created)
204
+ */
205
+ async addSessionFromThread(threadId: string, agentName?: string): Promise<SessionInfo> {
206
+ const agent = agentName || this.virtualClient.getCurrentAssistant()?.graph_id;
207
+ if (!agent) {
208
+ throw new Error("Agent name is required. Please call init() first or provide agentName.");
209
+ }
210
+
211
+ return this.createSession({
212
+ sessionId: threadId,
213
+ agentName: agent,
214
+ restore: true,
215
+ });
216
+ }
217
+
218
+ /**
219
+ * @zh 获取当前活跃的客户端
220
+ * @en Gets the current active client
221
+ */
222
+ getActiveClient(): LangGraphClient | null {
223
+ const session = this.getActiveSession();
224
+ return session?.client || null;
225
+ }
226
+
227
+ /**
228
+ * @zh 从远程列出所有会话
229
+ * @en Lists all sessions from remote
230
+ */
231
+ async listRemoteSessions(
232
+ options: {
233
+ sortOrder?: "asc" | "desc";
234
+ sortBy?: "created_at" | "updated_at";
235
+ offset?: number;
236
+ limit?: number;
237
+ } = {}
238
+ ) {
239
+ return this.virtualClient.listThreads(options);
240
+ }
241
+
242
+ /**
243
+ * @zh 从远程同步会话到本地(仅同步元数据,不创建 Client)
244
+ * @en Syncs sessions from remote to local (metadata only, no client created)
245
+ */
246
+ async syncFromRemote(
247
+ options: {
248
+ limit?: number;
249
+ agentName?: string;
250
+ } = {}
251
+ ): Promise<SessionInfo[]> {
252
+ const agentName = options.agentName || this.virtualClient.getCurrentAssistant()?.graph_id;
253
+ if (!agentName) {
254
+ throw new Error("Agent name is required. Please call init() first or provide agentName.");
255
+ }
256
+
257
+ const threads = await this.listRemoteSessions({
258
+ limit: options.limit || 100,
259
+ sortBy: "updated_at",
260
+ sortOrder: "desc",
261
+ });
262
+
263
+ const syncedSessions: SessionInfo[] = [];
264
+
265
+ for (const thread of threads) {
266
+ const threadId = thread.thread_id;
267
+
268
+ // 更新或创建会话信息
269
+ if (this.sessions.has(threadId)) {
270
+ const session = this.sessions.get(threadId)!;
271
+ session.thread = thread;
272
+ syncedSessions.push(session);
273
+ } else {
274
+ const sessionInfo: SessionInfo = {
275
+ sessionId: threadId,
276
+ thread,
277
+ agentName,
278
+ };
279
+ this.sessions.set(threadId, sessionInfo);
280
+ syncedSessions.push(sessionInfo);
281
+ }
282
+ }
283
+
284
+ return syncedSessions;
285
+ }
286
+
287
+ /**
288
+ * @zh 初始化 History(必须先调用)
289
+ * @en Initializes History (must be called first)
290
+ */
291
+ async init(agentName?: string) {
292
+ return this.virtualClient.initAssistant(agentName);
293
+ }
294
+ }
@@ -121,6 +121,8 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
121
121
  /** Message 处理器 */
122
122
  private messageProcessor: MessageProcessor;
123
123
  private legacyMode: boolean;
124
+ /** 当前流式状态 */
125
+ private _status: "idle" | "busy" | "interrupted" | "error" = "idle";
124
126
  constructor(config: LangGraphClientConfig) {
125
127
  super();
126
128
  this.client = config.client;
@@ -142,6 +144,11 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
142
144
  get runs(): ILangGraphClient["runs"] {
143
145
  return this.client.runs;
144
146
  }
147
+
148
+ /** 获取当前流式状态 */
149
+ get status() {
150
+ return this._status;
151
+ }
145
152
  private listAssistants() {
146
153
  return this.assistants.search({
147
154
  metadata: null,
@@ -211,10 +218,19 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
211
218
  * @zh 列出所有的 Thread。
212
219
  * @en Lists all Threads.
213
220
  */
214
- async listThreads() {
221
+ async listThreads(
222
+ options: {
223
+ sortOrder?: "asc" | "desc";
224
+ sortBy?: "created_at" | "updated_at";
225
+ offset?: number;
226
+ limit?: number;
227
+ } = {}
228
+ ) {
215
229
  return this.threads.search({
216
- sortOrder: "desc",
217
- sortBy: "updated_at",
230
+ sortOrder: options.sortOrder || "desc",
231
+ sortBy: options.sortBy || "updated_at",
232
+ offset: options.offset || 0,
233
+ limit: options.limit || 10,
218
234
  });
219
235
  }
220
236
  async deleteThread(threadId: string) {
@@ -350,6 +366,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
350
366
  ];
351
367
 
352
368
  const streamRecord: any[] = [];
369
+ this._status = "busy";
353
370
  this.emit("start", {
354
371
  event: "start",
355
372
  });
@@ -396,6 +413,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
396
413
  const data = await this.runFETool();
397
414
  if (data) streamRecord.push(...data);
398
415
  this.humanInTheLoop = null;
416
+ this._status = "idle";
399
417
  this.emit("done", {
400
418
  event: "done",
401
419
  });
@@ -427,6 +445,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
427
445
  if (chunk.event === "metadata") {
428
446
  this.currentRun = chunk.data;
429
447
  } else if (chunk.event === "error" || chunk.event === "Error" || chunk.event === "__stream_error__") {
448
+ this._status = "error";
430
449
  this.emit("error", chunk);
431
450
  } else if (chunk.event === "messages/metadata") {
432
451
  Object.assign(this.messagesMetadata, chunk.data);
@@ -444,6 +463,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
444
463
  };
445
464
 
446
465
  if (data.__interrupt__) {
466
+ this._status = "interrupted";
447
467
  this.humanInTheLoop = camelcaseKeys(data.__interrupt__, {
448
468
  deep: true,
449
469
  });
@@ -481,6 +501,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
481
501
  // json 校验
482
502
  return this.callFETool(toolMessage, tool.args);
483
503
  });
504
+ this._status = "interrupted";
484
505
  this.currentThread!.status = "interrupted"; // 修复某些机制下,状态不为 interrupted 与后端有差异
485
506
  return Promise.all(result);
486
507
  }
@@ -545,6 +566,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
545
566
  this.messageProcessor.clearStreamingMessages();
546
567
  this.currentRun = undefined;
547
568
  this.tools.clearWaiting();
569
+ this._status = "idle";
548
570
  this.emit("value", {
549
571
  event: "messages/partial",
550
572
  data: {
package/src/index.ts CHANGED
@@ -7,3 +7,4 @@ export * from "./ToolManager.js";
7
7
  export * from "./TestKit.js";
8
8
  export * from "./artifacts/index.js";
9
9
  export * from "./client/index.js";
10
+ export * from "./History.js";
@@ -23,6 +23,8 @@ interface ChatProviderProps {
23
23
  showHistory?: boolean;
24
24
  showGraph?: boolean;
25
25
  fallbackToAvailableAssistants?: boolean;
26
+ /** 初始化时是否自动激活最近的历史会话(默认 false,创建新会话) */
27
+ autoRestoreLastSession?: boolean;
26
28
  onInitError?: (error: any, currentAgent: string) => void;
27
29
  client?: ILangGraphClient;
28
30
  legacyMode?: boolean;
@@ -37,6 +39,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
37
39
  showHistory = false,
38
40
  showGraph = false,
39
41
  fallbackToAvailableAssistants = false,
42
+ autoRestoreLastSession = false,
40
43
  onInitError,
41
44
  client,
42
45
  legacyMode = false,
@@ -73,8 +76,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
73
76
  showHistory,
74
77
  showGraph,
75
78
  fallbackToAvailableAssistants,
79
+ autoRestoreLastSession,
76
80
  });
77
- }, [defaultAgent, apiUrl, stableHeaders, withCredentials, showHistory, showGraph, fallbackToAvailableAssistants]);
81
+ }, [defaultAgent, apiUrl, stableHeaders, withCredentials, showHistory, showGraph, fallbackToAvailableAssistants, autoRestoreLastSession]);
78
82
 
79
83
  const unionStore = useUnionStore(store, useStore);
80
84
 
@@ -3,6 +3,7 @@ import { RenderMessage } from "../LangGraphClient.js";
3
3
  import { LangGraphClient } from "../LangGraphClient.js";
4
4
  import { getMessageContent } from "../ui-store/createChatStore.js";
5
5
  import { jsonrepair } from "jsonrepair";
6
+ import { InterruptResponse } from "./createTool.js";
6
7
 
7
8
  export type DeepPartial<T> = {
8
9
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
@@ -12,10 +13,35 @@ export class ToolRenderData<I, D> {
12
13
  public message: RenderMessage,
13
14
  public client: LangGraphClient
14
15
  ) {}
16
+ /**
17
+ * 获取人机交互数据
18
+ * 直接使用 reviewConfig 获取可以显示的按钮
19
+ * actionRequest 获取当前工具的入参
20
+ */
21
+ getHumanInTheLoopData() {
22
+ const configOfHumanInTheLoop = this.client.humanInTheLoop?.find((i) => i.value.reviewConfigs?.some((j) => j.actionName === this.message.name));
23
+ if (!configOfHumanInTheLoop) return null;
24
+ return {
25
+ config: configOfHumanInTheLoop,
26
+ reviewConfig: configOfHumanInTheLoop.value.reviewConfigs.find((j) => j.actionName === this.message.name)!,
27
+ actionRequest: configOfHumanInTheLoop.value.actionRequests.find((j) => j.name === this.message.name)!,
28
+ };
29
+ }
30
+ /** 发送恢复状态的数据 */
31
+ sendResumeData(response: InterruptResponse["decisions"][number]) {
32
+ if (response.type === "edit") {
33
+ /**@ts-ignore 修复 sb 的 langchain 官方的命名不统一,我们一致采用下划线版本,而非驼峰版本 */
34
+ response.editedAction = response.edited_action;
35
+ }
36
+ return this.client.doneFEToolWaiting(this.message.id!, { decisions: [response] });
37
+ }
15
38
  get state() {
16
39
  if (this.message.type === "tool" && this.message?.additional_kwargs?.done) {
17
40
  return "done";
18
41
  }
42
+ if (this.client.status === "interrupted" && this.client.humanInTheLoop?.some((i) => i.value.reviewConfigs?.some((j) => j.actionName === this.message.name))) {
43
+ return "interrupted";
44
+ }
19
45
  if (this.message.tool_input) {
20
46
  return "loading";
21
47
  }
@@ -25,6 +25,9 @@ export interface UnionTool<Args extends ZodRawShape, Child extends Object = Obje
25
25
  isPureParams?: boolean;
26
26
  }
27
27
  export type ToolCallback<Args extends ZodRawShape> = (args: z.infer<z.ZodObject<Args>>, context?: any) => CallToolResult | Promise<CallToolResult>;
28
+ /**
29
+ * HumanInTheLoop 的标准回复格式
30
+ */
28
31
  export type InterruptResponse = {
29
32
  decisions: (
30
33
  | { type: "approve" }
@@ -35,7 +38,7 @@ export type InterruptResponse = {
35
38
  args: Record<string, any>;
36
39
  };
37
40
  }
38
- | { type: "reject"; message: string }
41
+ | { type: "reject"; message?: string }
39
42
  )[];
40
43
  };
41
44
  export type CallToolResult = string | { type: "text"; text: string }[] | InterruptResponse;