@langgraph-js/sdk 3.8.0 → 3.8.2

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.
@@ -80,6 +80,7 @@ export declare class MessageProcessor {
80
80
  messages: RenderMessage[];
81
81
  }>;
82
82
  }, messagesMetadata?: Record<string, any>): RenderMessage[];
83
+ private beforeFold;
83
84
  /**
84
85
  * @zh 统一的消息处理入口,按顺序执行所有处理步骤
85
86
  * @en Unified message processing entry point, executing all processing steps in order
@@ -264,21 +264,25 @@ export class MessageProcessor {
264
264
  if (rootMessage.type === "tool" && childrenMap.has(rootMessage.tool_call_id)) {
265
265
  rootMessage.sub_messages.unshift(...childrenMap.get(rootMessage.tool_call_id));
266
266
  // 根据 id 去重
267
- rootMessage.sub_messages = rootMessage.sub_messages.filter((i, index, self) => self.findIndex((t) => t.id === i.id) === index);
267
+ const sub_messages = rootMessage.sub_messages.filter((i, index, self) => self.findIndex((t) => t.id === i.id) === index);
268
+ rootMessage.sub_messages = this.beforeFold(sub_messages);
268
269
  }
269
270
  }
270
271
  return rootMessages;
271
272
  }
273
+ beforeFold(messages) {
274
+ // 1. 组合工具消息
275
+ const composedMessages = this.composeToolMessages(messages);
276
+ // 2. 附加信息
277
+ const messagesWithInfo = this.attachInfoForMessage(composedMessages);
278
+ return messagesWithInfo;
279
+ }
272
280
  /**
273
281
  * @zh 统一的消息处理入口,按顺序执行所有处理步骤
274
282
  * @en Unified message processing entry point, executing all processing steps in order
275
283
  */
276
284
  processMessages(messages, graphState, messagesMetadata) {
277
- // 1. 组合工具消息
278
- const composedMessages = this.composeToolMessages(messages);
279
- // 2. 附加信息
280
- const messagesWithInfo = this.attachInfoForMessage(composedMessages);
281
285
  // 3. 折叠树状消息(如果提供了 messagesMetadata)
282
- return this.foldTreeMessages(messagesWithInfo, graphState, messagesMetadata);
286
+ return this.foldTreeMessages(this.beforeFold(messages), graphState, messagesMetadata);
283
287
  }
284
288
  }
@@ -1,5 +1,6 @@
1
1
  import { RenderMessage } from "../LangGraphClient.js";
2
2
  import { LangGraphClient } from "../LangGraphClient.js";
3
+ import { InterruptResponse } from "./createTool.js";
3
4
  export type DeepPartial<T> = {
4
5
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
5
6
  };
@@ -7,7 +8,39 @@ export declare class ToolRenderData<I, D> {
7
8
  message: RenderMessage;
8
9
  client: LangGraphClient;
9
10
  constructor(message: RenderMessage, client: LangGraphClient);
10
- get state(): "idle" | "done" | "loading";
11
+ /**
12
+ * 获取人机交互数据
13
+ * 直接使用 reviewConfig 获取可以显示的按钮
14
+ * actionRequest 获取当前工具的入参
15
+ */
16
+ getHumanInTheLoopData(): {
17
+ config: {
18
+ id: string;
19
+ value: {
20
+ actionRequests: {
21
+ name: string;
22
+ description: string;
23
+ args: any;
24
+ }[];
25
+ reviewConfigs: {
26
+ actionName: string;
27
+ allowedDecisions: ("approve" | "edit" | "reject")[];
28
+ }[];
29
+ };
30
+ };
31
+ reviewConfig: {
32
+ actionName: string;
33
+ allowedDecisions: ("approve" | "edit" | "reject")[];
34
+ };
35
+ actionRequest: {
36
+ name: string;
37
+ description: string;
38
+ args: any;
39
+ };
40
+ } | null;
41
+ /** 发送恢复状态的数据 */
42
+ sendResumeData(response: InterruptResponse["decisions"][number]): void;
43
+ get state(): "idle" | "interrupted" | "done" | "loading";
11
44
  get input(): I | null;
12
45
  get output(): string;
13
46
  getJSONOutput(): D;
@@ -7,10 +7,36 @@ export class ToolRenderData {
7
7
  this.message = message;
8
8
  this.client = client;
9
9
  }
10
+ /**
11
+ * 获取人机交互数据
12
+ * 直接使用 reviewConfig 获取可以显示的按钮
13
+ * actionRequest 获取当前工具的入参
14
+ */
15
+ getHumanInTheLoopData() {
16
+ const configOfHumanInTheLoop = this.client.humanInTheLoop?.find((i) => i.value.reviewConfigs?.some((j) => j.actionName === this.message.name));
17
+ if (!configOfHumanInTheLoop)
18
+ return null;
19
+ return {
20
+ config: configOfHumanInTheLoop,
21
+ reviewConfig: configOfHumanInTheLoop.value.reviewConfigs.find((j) => j.actionName === this.message.name),
22
+ actionRequest: configOfHumanInTheLoop.value.actionRequests.find((j) => j.name === this.message.name),
23
+ };
24
+ }
25
+ /** 发送恢复状态的数据 */
26
+ sendResumeData(response) {
27
+ if (response.type === "edit") {
28
+ /**@ts-ignore 修复 sb 的 langchain 官方的命名不统一,我们一致采用下划线版本,而非驼峰版本 */
29
+ response.editedAction = response.edited_action;
30
+ }
31
+ return this.client.doneFEToolWaiting(this.message.id, { decisions: [response] });
32
+ }
10
33
  get state() {
11
34
  if (this.message.type === "tool" && this.message?.additional_kwargs?.done) {
12
35
  return "done";
13
36
  }
37
+ if (this.client.status === "interrupted" && this.client.humanInTheLoop?.some((i) => i.value.reviewConfigs?.some((j) => j.actionName === this.message.name))) {
38
+ return "interrupted";
39
+ }
14
40
  if (this.message.tool_input) {
15
41
  return "loading";
16
42
  }
@@ -22,6 +22,9 @@ export interface UnionTool<Args extends ZodRawShape, Child extends Object = Obje
22
22
  isPureParams?: boolean;
23
23
  }
24
24
  export type ToolCallback<Args extends ZodRawShape> = (args: z.infer<z.ZodObject<Args>>, context?: any) => CallToolResult | Promise<CallToolResult>;
25
+ /**
26
+ * HumanInTheLoop 的标准回复格式
27
+ */
25
28
  export type InterruptResponse = {
26
29
  decisions: ({
27
30
  type: "approve";
@@ -33,7 +36,7 @@ export type InterruptResponse = {
33
36
  };
34
37
  } | {
35
38
  type: "reject";
36
- message: string;
39
+ message?: string;
37
40
  })[];
38
41
  };
39
42
  export type CallToolResult = string | {
@@ -170,10 +173,10 @@ export declare const createMCPTool: <Args extends ZodRawShape>(tool: UnionTool<A
170
173
  }[];
171
174
  isError?: undefined;
172
175
  } | {
173
- content: {
176
+ content: InterruptResponse | {
174
177
  type: "text";
175
178
  text: string;
176
- }[] | InterruptResponse | undefined;
179
+ }[] | undefined;
177
180
  isError?: undefined;
178
181
  } | {
179
182
  content: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langgraph-js/sdk",
3
- "version": "3.8.0",
3
+ "version": "3.8.2",
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",
@@ -307,23 +307,26 @@ export class MessageProcessor {
307
307
  if (rootMessage.type === "tool" && childrenMap.has(rootMessage.tool_call_id)) {
308
308
  rootMessage.sub_messages.unshift(...childrenMap.get(rootMessage.tool_call_id)!);
309
309
  // 根据 id 去重
310
- rootMessage.sub_messages = rootMessage.sub_messages.filter((i, index, self) => self.findIndex((t) => t.id === i.id) === index);
310
+ const sub_messages = rootMessage.sub_messages.filter((i, index, self) => self.findIndex((t) => t.id === i.id) === index);
311
+ rootMessage.sub_messages = this.beforeFold(sub_messages);
311
312
  }
312
313
  }
313
314
  return rootMessages;
314
315
  }
315
- /**
316
- * @zh 统一的消息处理入口,按顺序执行所有处理步骤
317
- * @en Unified message processing entry point, executing all processing steps in order
318
- */
319
- processMessages(messages: RenderMessage[], graphState?: any, messagesMetadata?: Record<string, any>): RenderMessage[] {
316
+ private beforeFold(messages: RenderMessage[]) {
320
317
  // 1. 组合工具消息
321
318
  const composedMessages = this.composeToolMessages(messages);
322
319
 
323
320
  // 2. 附加信息
324
321
  const messagesWithInfo = this.attachInfoForMessage(composedMessages);
325
-
322
+ return messagesWithInfo;
323
+ }
324
+ /**
325
+ * @zh 统一的消息处理入口,按顺序执行所有处理步骤
326
+ * @en Unified message processing entry point, executing all processing steps in order
327
+ */
328
+ processMessages(messages: RenderMessage[], graphState?: any, messagesMetadata?: Record<string, any>): RenderMessage[] {
326
329
  // 3. 折叠树状消息(如果提供了 messagesMetadata)
327
- return this.foldTreeMessages(messagesWithInfo, graphState, messagesMetadata);
330
+ return this.foldTreeMessages(this.beforeFold(messages), graphState, messagesMetadata);
328
331
  }
329
332
  }
@@ -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;