@langgraph-js/sdk 4.6.4 → 4.6.5

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.
@@ -284,6 +284,8 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
284
284
  * @deprecated 请使用 doneHumanInTheLoopWaiting 和规范的 humanInTheLoop 协议定义状态
285
285
  */
286
286
  doneFEToolWaiting(id: string, result: CallToolResult): void;
287
+ /** 尝试强制跳过工具调用 */
288
+ private forceSkipToolLock?;
287
289
  /**
288
290
  * @zh 标记人机交互等待已完成。
289
291
  * @en Marks the human in the loop waiting as completed.
@@ -324,7 +324,13 @@ export class LangGraphClient extends EventEmitter {
324
324
  this.processStreamChunk(chunk, command);
325
325
  }
326
326
  }
327
- const data = await this.runFETool();
327
+ const data = (await Promise.race([
328
+ this.runFETool(),
329
+ new Promise((res) => {
330
+ this.forceSkipToolLock = () => res(null);
331
+ }),
332
+ ]));
333
+ this.forceSkipToolLock = undefined;
328
334
  await this.responseHumanInTheLoop();
329
335
  if (data)
330
336
  streamRecord.push(...data);
@@ -421,7 +427,6 @@ export class LangGraphClient extends EventEmitter {
421
427
  // json 校验
422
428
  return this.callFETool(toolMessage, tool.args).catch((e) => console.warn(e));
423
429
  });
424
- console.log("batch call tools", result.length);
425
430
  // 只有当卡住流程时,才改变状态为 interrupted
426
431
  this._status = "interrupted";
427
432
  this.currentThread.status = "interrupted"; // 修复某些机制下,状态不为 interrupted 与后端有差异
@@ -511,6 +516,8 @@ export class LangGraphClient extends EventEmitter {
511
516
  this.resume(result);
512
517
  }
513
518
  }
519
+ /** 尝试强制跳过工具调用 */
520
+ forceSkipToolLock;
514
521
  /**
515
522
  * @zh 标记人机交互等待已完成。
516
523
  * @en Marks the human in the loop waiting as completed.
@@ -520,6 +527,14 @@ export class LangGraphClient extends EventEmitter {
520
527
  this.tools.doneWaiting(tool_id, result);
521
528
  if (this.humanInTheLoop) {
522
529
  this.humanInTheLoop.result[action_request_id] = result;
530
+ if (Object.keys(this.humanInTheLoop.result).length === this.humanInTheLoop.interruptData.length) {
531
+ setTimeout(() => {
532
+ if (this.forceSkipToolLock) {
533
+ console.warn("force kill tool lock");
534
+ this.forceSkipToolLock();
535
+ }
536
+ }, 100);
537
+ }
523
538
  }
524
539
  }
525
540
  /**
@@ -8,6 +8,7 @@ export declare class ToolRenderData<I, D> {
8
8
  message: RenderMessage;
9
9
  client: LangGraphClient;
10
10
  constructor(message: RenderMessage, client: LangGraphClient);
11
+ /** 这个 id 需要联系到 tool call id, 但是很悲哀langgraph 的 hitl interrupt 没有传递任何 id,非常蠢 */
11
12
  private getToolActionRequestID;
12
13
  /**
13
14
  * 获取人机交互数据
@@ -8,6 +8,7 @@ export class ToolRenderData {
8
8
  this.message = message;
9
9
  this.client = client;
10
10
  }
11
+ /** 这个 id 需要联系到 tool call id, 但是很悲哀langgraph 的 hitl interrupt 没有传递任何 id,非常蠢 */
11
12
  getToolActionRequestID() {
12
13
  return createActionRequestID({
13
14
  name: this.message.name,
@@ -43,7 +44,7 @@ export class ToolRenderData {
43
44
  /**@ts-ignore 修复 sb 的 langchain 官方的命名不统一,我们一致采用下划线版本,而非驼峰版本 */
44
45
  response.editedAction = response.edited_action;
45
46
  }
46
- return this.client.doneHumanInTheLoopWaiting(this.message.id, this.getToolActionRequestID(), response);
47
+ return this.client.doneHumanInTheLoopWaiting(this.message.id || this.message.tool_call_id, this.getToolActionRequestID(), response);
47
48
  }
48
49
  get state() {
49
50
  if (this.message.type === "tool" && this.message?.additional_kwargs?.done) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langgraph-js/sdk",
3
- "version": "4.6.4",
3
+ "version": "4.6.5",
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",
@@ -443,7 +443,13 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
443
443
  this.processStreamChunk(chunk, command);
444
444
  }
445
445
  }
446
- const data = await this.runFETool();
446
+ const data = (await Promise.race([
447
+ this.runFETool(),
448
+ new Promise((res) => {
449
+ this.forceSkipToolLock = () => res(null);
450
+ }),
451
+ ])) as any[] | null;
452
+ this.forceSkipToolLock = undefined;
447
453
  await this.responseHumanInTheLoop();
448
454
  if (data) streamRecord.push(...data);
449
455
  this._status = "idle";
@@ -538,7 +544,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
538
544
  // json 校验
539
545
  return this.callFETool(toolMessage, tool.args).catch((e) => console.warn(e));
540
546
  });
541
- console.log("batch call tools", result.length);
547
+
542
548
  // 只有当卡住流程时,才改变状态为 interrupted
543
549
  this._status = "interrupted";
544
550
  this.currentThread!.status = "interrupted"; // 修复某些机制下,状态不为 interrupted 与后端有差异
@@ -632,6 +638,8 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
632
638
  }
633
639
  }
634
640
 
641
+ /** 尝试强制跳过工具调用 */
642
+ private forceSkipToolLock?: () => void;
635
643
  /**
636
644
  * @zh 标记人机交互等待已完成。
637
645
  * @en Marks the human in the loop waiting as completed.
@@ -641,6 +649,14 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
641
649
  this.tools.doneWaiting(tool_id, result);
642
650
  if (this.humanInTheLoop) {
643
651
  this.humanInTheLoop.result[action_request_id] = result;
652
+ if (Object.keys(this.humanInTheLoop.result).length === this.humanInTheLoop.interruptData.length) {
653
+ setTimeout(() => {
654
+ if (this.forceSkipToolLock) {
655
+ console.warn("force kill tool lock");
656
+ this.forceSkipToolLock();
657
+ }
658
+ }, 100);
659
+ }
644
660
  }
645
661
  }
646
662
 
@@ -13,6 +13,7 @@ export class ToolRenderData<I, D> {
13
13
  public message: RenderMessage,
14
14
  public client: LangGraphClient
15
15
  ) {}
16
+ /** 这个 id 需要联系到 tool call id, 但是很悲哀langgraph 的 hitl interrupt 没有传递任何 id,非常蠢 */
16
17
  private getToolActionRequestID() {
17
18
  return createActionRequestID({
18
19
  name: this.message.name!,
@@ -48,7 +49,7 @@ export class ToolRenderData<I, D> {
48
49
  response.editedAction = response.edited_action;
49
50
  }
50
51
 
51
- return this.client.doneHumanInTheLoopWaiting(this.message.id!, this.getToolActionRequestID(), response);
52
+ return this.client.doneHumanInTheLoopWaiting(this.message.id || this.message.tool_call_id!, this.getToolActionRequestID(), response);
52
53
  }
53
54
 
54
55
  get state() {