@langgraph-js/sdk 4.3.0 → 4.3.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.
@@ -13,6 +13,8 @@ export type RenderMessage = Message & {
13
13
  /** 工具入参 ,聚合而来*/
14
14
  tool_input?: string;
15
15
  additional_kwargs?: {
16
+ create_time: string;
17
+ update_time: string;
16
18
  done?: boolean;
17
19
  tool_calls?: {
18
20
  function: {
@@ -26,9 +28,6 @@ export type RenderMessage = Message & {
26
28
  output_tokens: number;
27
29
  };
28
30
  tool_call_id?: string;
29
- response_metadata?: {
30
- create_time: string;
31
- };
32
31
  sub_messages?: RenderMessage[];
33
32
  /** 耗时 */
34
33
  spend_time?: number;
@@ -136,10 +135,7 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
136
135
  /** 代理 assistants 属性到内部 client */
137
136
  get assistants(): {
138
137
  search(query?: {
139
- graphId? /**
140
- * The maximum number of retries that can be made for a single call,
141
- * with an exponential backoff between each attempt. Defaults to 6.
142
- */: string;
138
+ graphId?: string;
143
139
  metadata?: import("@langchain/langgraph-sdk").Metadata;
144
140
  limit?: number;
145
141
  offset?: number;
@@ -341,6 +341,7 @@ export class LangGraphClient extends EventEmitter {
341
341
  else if (chunk.event === "messages/partial" || chunk.event === "messages/complete") {
342
342
  for (const message of chunk.data) {
343
343
  this.messageProcessor.updateStreamingMessage(message);
344
+ this.messageProcessor.spendTime.setSpendTime(message.id);
344
345
  }
345
346
  this.emit("message", chunk);
346
347
  return true;
@@ -1,5 +1,6 @@
1
1
  import { Message, AIMessage, ToolMessage } from "@langchain/langgraph-sdk";
2
2
  import { RenderMessage } from "./LangGraphClient.js";
3
+ import { SpendTime } from "./SpendTime.js";
3
4
  /**
4
5
  * @zh StreamingMessageType 类用于判断消息的类型。
5
6
  * @en The StreamingMessageType class is used to determine the type of a message.
@@ -17,6 +18,7 @@ export declare class MessageProcessor {
17
18
  private streamingMessage;
18
19
  /** 图发过来的更新信息 */
19
20
  private graphMessages;
21
+ spendTime: SpendTime;
20
22
  constructor();
21
23
  /**
22
24
  * @zh 获取流式消息
@@ -1,3 +1,5 @@
1
+ import { SpendTime } from "./SpendTime.js";
2
+ import { formatFullTime } from "./ui-store/createChatStore.js";
1
3
  /**
2
4
  * @zh StreamingMessageType 类用于判断消息的类型。
3
5
  * @en The StreamingMessageType class is used to determine the type of a message.
@@ -20,6 +22,7 @@ export class MessageProcessor {
20
22
  streamingMessage = [];
21
23
  /** 图发过来的更新信息 */
22
24
  graphMessages = [];
25
+ spendTime = new SpendTime();
23
26
  constructor() { }
24
27
  /**
25
28
  * @zh 获取流式消息
@@ -101,10 +104,13 @@ export class MessageProcessor {
101
104
  let lastMessage = null;
102
105
  const result = [...messages]; // 创建副本避免修改原数组
103
106
  for (const message of result) {
104
- const createTime = message.response_metadata?.create_time || "";
107
+ const createTime = message.additional_kwargs?.create_time || formatFullTime(this.spendTime.getStartTime(message.id));
108
+ const updateTime = message.additional_kwargs?.update_time || formatFullTime(this.spendTime.getEndTime(message.id));
109
+ message.additional_kwargs.create_time = createTime;
110
+ message.additional_kwargs.update_time = updateTime;
105
111
  // 工具必须要使用 tool_call_id 来保证一致性
106
112
  message.unique_id = message.tool_call_id || message.id;
107
- message.spend_time = new Date(createTime).getTime() - new Date(lastMessage?.response_metadata?.create_time || createTime).getTime();
113
+ message.spend_time = new Date(updateTime).getTime() - new Date(createTime).getTime();
108
114
  if (!message.usage_metadata && message.response_metadata?.usage) {
109
115
  const usage = message.response_metadata.usage;
110
116
  message.usage_metadata = {
package/dist/TestKit.d.ts CHANGED
@@ -171,6 +171,8 @@ export declare class TestLangGraphChat {
171
171
  node_name?: string;
172
172
  tool_input?: string;
173
173
  additional_kwargs?: {
174
+ create_time: string;
175
+ update_time: string;
174
176
  done?: boolean;
175
177
  tool_calls?: {
176
178
  function: {
@@ -184,9 +186,6 @@ export declare class TestLangGraphChat {
184
186
  output_tokens: number;
185
187
  };
186
188
  tool_call_id?: string;
187
- response_metadata?: {
188
- create_time: string;
189
- };
190
189
  sub_messages?: RenderMessage[];
191
190
  spend_time?: number;
192
191
  unique_id?: string;
@@ -245,6 +244,8 @@ export declare class TestLangGraphChat {
245
244
  node_name?: string;
246
245
  tool_input?: string;
247
246
  additional_kwargs?: {
247
+ create_time: string;
248
+ update_time: string;
248
249
  done?: boolean;
249
250
  tool_calls?: {
250
251
  function: {
@@ -258,9 +259,6 @@ export declare class TestLangGraphChat {
258
259
  output_tokens: number;
259
260
  };
260
261
  tool_call_id?: string;
261
- response_metadata?: {
262
- create_time: string;
263
- };
264
262
  sub_messages?: RenderMessage[];
265
263
  spend_time?: number;
266
264
  unique_id?: string;
@@ -292,6 +290,8 @@ export declare class TestLangGraphChat {
292
290
  node_name?: string;
293
291
  tool_input?: string;
294
292
  additional_kwargs?: {
293
+ create_time: string;
294
+ update_time: string;
295
295
  done?: boolean;
296
296
  tool_calls?: {
297
297
  function: {
@@ -305,9 +305,6 @@ export declare class TestLangGraphChat {
305
305
  output_tokens: number;
306
306
  };
307
307
  tool_call_id?: string;
308
- response_metadata?: {
309
- create_time: string;
310
- };
311
308
  sub_messages?: RenderMessage[];
312
309
  spend_time?: number;
313
310
  unique_id?: string;
@@ -5,6 +5,7 @@ import { RevertChatToOptions } from "../time-travel/index.js";
5
5
  import { History, SessionInfo } from "../History.js";
6
6
  import { InterruptData } from "../humanInTheLoop.js";
7
7
  export declare const formatTime: (date: Date) => string;
8
+ export declare const formatFullTime: (date: Date) => string;
8
9
  export declare const formatTokens: (tokens: number) => string;
9
10
  export declare const getMessageContent: (content: any) => string;
10
11
  export declare const getHistoryContent: (thread: Thread) => string | any[];
@@ -6,6 +6,16 @@ import { useArtifacts } from "../artifacts/index.js";
6
6
  import { History } from "../History.js";
7
7
  // ============ 工具函数 ============
8
8
  export const formatTime = (date) => date.toLocaleTimeString();
9
+ export const formatFullTime = (date) => {
10
+ const pad = (n) => n.toString().padStart(2, "0");
11
+ const yyyy = date.getFullYear();
12
+ const mm = pad(date.getMonth() + 1);
13
+ const dd = pad(date.getDate());
14
+ const hh = pad(date.getHours());
15
+ const mi = pad(date.getMinutes());
16
+ const ss = pad(date.getSeconds());
17
+ return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}`;
18
+ };
9
19
  export const formatTokens = (tokens) => tokens.toLocaleString("en");
10
20
  export const getMessageContent = (content) => {
11
21
  if (typeof content === "string")
@@ -277,6 +287,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
277
287
  return;
278
288
  inChatError.set(null);
279
289
  try {
290
+ loading.set(true);
280
291
  await c.sendMessage(message || userInput.get(), extraData);
281
292
  }
282
293
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langgraph-js/sdk",
3
- "version": "4.3.0",
3
+ "version": "4.3.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",
@@ -2,6 +2,7 @@ import type { Thread, Message, Assistant, HumanMessage, AIMessage, ToolMessage,
2
2
  import { EventEmitter } from "eventemitter3";
3
3
  import { ToolManager } from "./ToolManager.js";
4
4
  import { CallToolResult } from "./tool/createTool.js";
5
+ import { SpendTime } from "./SpendTime.js";
5
6
  import { createActionRequestID, HumanInTheLoopDecision, HumanInTheLoopState, InterruptData } from "./humanInTheLoop.js";
6
7
  import { type ILangGraphClient } from "@langgraph-js/pure-graph/dist/types.js";
7
8
  import { MessageProcessor } from "./MessageProcessor.js";
@@ -16,6 +17,8 @@ export type RenderMessage = Message & {
16
17
  /** 工具入参 ,聚合而来*/
17
18
  tool_input?: string;
18
19
  additional_kwargs?: {
20
+ create_time: string;
21
+ update_time: string;
19
22
  done?: boolean;
20
23
  tool_calls?: {
21
24
  function: {
@@ -29,9 +32,6 @@ export type RenderMessage = Message & {
29
32
  output_tokens: number;
30
33
  };
31
34
  tool_call_id?: string;
32
- response_metadata?: {
33
- create_time: string;
34
- };
35
35
  // 子消息
36
36
  sub_messages?: RenderMessage[];
37
37
  /** 耗时 */
@@ -105,6 +105,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
105
105
  private currentAssistant: Assistant | null = null;
106
106
  private currentThread: Thread<TStateType> | null = null;
107
107
  tools: ToolManager = new ToolManager();
108
+
108
109
  availableAssistants: Assistant[] = [];
109
110
  graphState: any = {};
110
111
  currentRun?: { run_id: string };
@@ -459,6 +460,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
459
460
  } else if (chunk.event === "messages/partial" || chunk.event === "messages/complete") {
460
461
  for (const message of chunk.data) {
461
462
  this.messageProcessor.updateStreamingMessage(message);
463
+ this.messageProcessor.spendTime.setSpendTime(message.id!);
462
464
  }
463
465
  this.emit("message", chunk);
464
466
  return true;
@@ -1,5 +1,7 @@
1
1
  import { Message, AIMessage, ToolMessage } from "@langchain/langgraph-sdk";
2
2
  import { RenderMessage } from "./LangGraphClient.js";
3
+ import { SpendTime } from "./SpendTime.js";
4
+ import { formatFullTime, formatTime } from "./ui-store/createChatStore.js";
3
5
 
4
6
  /**
5
7
  * @zh StreamingMessageType 类用于判断消息的类型。
@@ -25,7 +27,7 @@ export class MessageProcessor {
25
27
  private streamingMessage: RenderMessage[] = [];
26
28
  /** 图发过来的更新信息 */
27
29
  private graphMessages: RenderMessage[] = [];
28
-
30
+ public spendTime = new SpendTime();
29
31
  constructor() {}
30
32
 
31
33
  /**
@@ -117,11 +119,14 @@ export class MessageProcessor {
117
119
  const result = [...messages]; // 创建副本避免修改原数组
118
120
 
119
121
  for (const message of result) {
120
- const createTime = message.response_metadata?.create_time || "";
122
+ const createTime = message.additional_kwargs?.create_time || formatFullTime(this.spendTime.getStartTime(message.id!));
123
+ const updateTime = message.additional_kwargs?.update_time || formatFullTime(this.spendTime.getEndTime(message.id!));
124
+ message.additional_kwargs!.create_time = createTime;
125
+ message.additional_kwargs!.update_time = updateTime;
121
126
  // 工具必须要使用 tool_call_id 来保证一致性
122
127
  message.unique_id = message.tool_call_id! || message.id!;
123
128
 
124
- message.spend_time = new Date(createTime).getTime() - new Date(lastMessage?.response_metadata?.create_time || createTime).getTime();
129
+ message.spend_time = new Date(updateTime).getTime() - new Date(createTime).getTime();
125
130
  if (!message.usage_metadata && (message as AIMessage).response_metadata?.usage) {
126
131
  const usage = (message as AIMessage).response_metadata!.usage as {
127
132
  prompt_tokens: number;
@@ -170,7 +175,7 @@ export class MessageProcessor {
170
175
  ...(parentMessage?.additional_kwargs || {}),
171
176
  ...(message.additional_kwargs || {}),
172
177
  done: isDone,
173
- };
178
+ } as RenderMessage["additional_kwargs"];
174
179
  }
175
180
  if (parentMessage) {
176
181
  message.usage_metadata = parentMessage.usage_metadata;
@@ -0,0 +1,71 @@
1
+ # ArtifactViewer 实现说明
2
+
3
+ `ArtifactViewer` 组件主要负责与 `langgraph-js` SDK 的状态同步,并集成 `ai-artifacts` Web Component 来展示 AI 生成的内容。
4
+
5
+ ## 核心功能
6
+
7
+ 1. **状态同步**: 监听 `useChat` hook 中的 `artifacts` 变化。
8
+ 2. **沙箱渲染**: 使用 `<ai-artifacts>` Web Component 加载远程渲染引擎。
9
+ 3. **交互反馈**: 通过 `eventCenter` 捕获沙箱内的 `sendBackToAI` 事件,支持 Human-in-the-loop 流程。
10
+
11
+ ## 核心实现步骤
12
+
13
+ ### 1. 同步 Artifacts 状态
14
+
15
+ 利用 `useEffect` 监听 SDK 的 `artifacts` 和 `loading` 状态。当数据更新且加载完成后,使用 `setArtifactStore` 将数据推送到 `ai-artifacts` 的全局存储中。
16
+
17
+ ```typescript
18
+ useEffect(() => {
19
+ if (loading) return;
20
+ setArtifactStore({
21
+ artifacts: { default: artifacts as ArtifactType[] },
22
+ });
23
+ }, [artifacts, loading]);
24
+ ```
25
+
26
+ ### 2. 集成渲染引擎 (Web Component)
27
+
28
+ 在 JSX 中使用 `ai-artifacts` 标签。需要提供 `src` (渲染引擎地址)、`store-id` (默认为 `default`) 以及当前选中的 `group-id` 和 `version-id`。
29
+
30
+ ```tsx
31
+ <ai-artifacts src={artifactsUrl} store-id="default" group-id={currentArtifactId?.[0] || ""} version-id={currentArtifactId?.[1] || ""} className="w-full min-h-[400px]"></ai-artifacts>
32
+ ```
33
+
34
+ ### 3. 事件处理 (Human-in-the-loop)
35
+
36
+ 监听来自渲染沙箱的 `sendBackToAI` 事件。这通常发生在用户点击“修复”或“修改”按钮时,将相关的错误信息或修改建议传回给 AI。
37
+
38
+ ```typescript
39
+ useEffect(() => {
40
+ const handleSendBackToAI = (data: any) => {
41
+ onSendBackToAI(data);
42
+ };
43
+ eventCenter.on("sendBackToAI", handleSendBackToAI);
44
+ return () => {
45
+ eventCenter.off("sendBackToAI", handleSendBackToAI);
46
+ };
47
+ }, [onSendBackToAI]);
48
+ ```
49
+
50
+ ### 4. TypeScript 声明
51
+
52
+ 为了让 React 识别自定义的 Web Component 标签,需要添加类型声明:
53
+
54
+ ```typescript
55
+ declare module "react" {
56
+ namespace JSX {
57
+ interface IntrinsicElements {
58
+ "ai-artifacts": React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
59
+ src?: string;
60
+ "store-id"?: string;
61
+ "group-id"?: string;
62
+ "version-id"?: string;
63
+ };
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ ## 配置项
70
+
71
+ - `artifactsUrl`: 渲染沙箱的 URL 地址,建议通过 `localStorage` 或环境变量进行配置,以便灵活切换(例如:`https://langgraph-artifacts.netlify.app/`)。
@@ -13,6 +13,16 @@ import { InterruptData, InterruptResponse } from "../humanInTheLoop.js";
13
13
  // ============ 工具函数 ============
14
14
 
15
15
  export const formatTime = (date: Date) => date.toLocaleTimeString();
16
+ export const formatFullTime = (date: Date) => {
17
+ const pad = (n: number) => n.toString().padStart(2, "0");
18
+ const yyyy = date.getFullYear();
19
+ const mm = pad(date.getMonth() + 1);
20
+ const dd = pad(date.getDate());
21
+ const hh = pad(date.getHours());
22
+ const mi = pad(date.getMinutes());
23
+ const ss = pad(date.getSeconds());
24
+ return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}`;
25
+ };
16
26
  export const formatTokens = (tokens: number) => tokens.toLocaleString("en");
17
27
 
18
28
  export const getMessageContent = (content: any) => {
@@ -334,6 +344,7 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
334
344
 
335
345
  inChatError.set(null);
336
346
  try {
347
+ loading.set(true);
337
348
  await c.sendMessage(message || userInput.get(), extraData);
338
349
  } catch (e) {
339
350
  const isThreadRunning = (e as Error).message.includes("422");