@langgraph-js/sdk 3.3.0 → 3.4.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.
@@ -222,6 +222,7 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
222
222
  revertChatTo(messageId: string): Promise<{
223
223
  messages: Message[];
224
224
  }>;
225
+ messagesMetadata: {};
225
226
  /**
226
227
  * @zh 发送消息到 LangGraph 后端。
227
228
  * @en Sends a message to the LangGraph backend.
@@ -17,6 +17,7 @@ export class LangGraphClient extends EventEmitter {
17
17
  this.stopController = null;
18
18
  /** 用于存储 subAgent 状态数据的键 */
19
19
  this.subAgentsKey = "task_store";
20
+ this.messagesMetadata = {};
20
21
  /** 当前子图位置,但是依赖 stream,不太适合稳定使用*/
21
22
  this.graphPosition = "";
22
23
  this.extraParams = {};
@@ -146,7 +147,7 @@ export class LangGraphClient extends EventEmitter {
146
147
  * @en Messages used for streaming rendering in the UI.
147
148
  */
148
149
  get renderMessage() {
149
- return this.messageProcessor.renderMessages(this.graphState, () => this.getGraphNodeNow());
150
+ return this.messageProcessor.renderMessages(this.graphState, () => this.getGraphNodeNow(), this.messagesMetadata);
150
151
  }
151
152
  /**
152
153
  * @zh 获取 Token 计数器信息。
@@ -245,7 +246,7 @@ export class LangGraphClient extends EventEmitter {
245
246
  messages: messagesToSend,
246
247
  fe_tools: await this.tools.toJSON(this.currentAssistant.graph_id),
247
248
  },
248
- streamMode: ["messages", "values", "updates"],
249
+ streamMode: ["messages", "values"],
249
250
  streamSubgraphs: true,
250
251
  command,
251
252
  });
@@ -263,6 +264,10 @@ export class LangGraphClient extends EventEmitter {
263
264
  else if (chunk.event === "error" || chunk.event === "Error" || chunk.event === "__stream_error__") {
264
265
  this.emit("error", chunk);
265
266
  }
267
+ else if (chunk.event === "messages/metadata") {
268
+ Object.assign(this.messagesMetadata, chunk.data);
269
+ continue;
270
+ }
266
271
  else if (chunk.event === "messages/partial") {
267
272
  for (const message of chunk.data) {
268
273
  this.messageProcessor.updateStreamingMessage(message);
@@ -78,17 +78,23 @@ export declare class MessageProcessor {
78
78
  * @zh 转换 subAgent 消息为工具的子消息
79
79
  * @en Convert subAgent messages to tool sub-messages
80
80
  */
81
- convertSubAgentMessages(messages: RenderMessage[], graphState: any): RenderMessage[];
81
+ convertSubAgentMessages(messages: RenderMessage[], graphState: any, messagesMetadata: Record<string, {
82
+ subagent_id?: string;
83
+ }>): RenderMessage[];
82
84
  /**
83
85
  * @zh 生成用于 UI 中的流式渲染的消息
84
86
  * @en Generate messages used for streaming rendering in the UI
85
87
  */
86
88
  renderMessages(graphState: any, getGraphNodeNow: () => {
87
89
  name: string;
88
- }): RenderMessage[];
90
+ }, messagesMetadata: Record<string, {
91
+ subagent_id?: string;
92
+ }>): RenderMessage[];
89
93
  /**
90
94
  * @zh 统一的消息处理入口,按顺序执行所有处理步骤
91
95
  * @en Unified message processing entry point, executing all processing steps in order
92
96
  */
93
- processMessages(messages: RenderMessage[], graphState?: any): RenderMessage[];
97
+ processMessages(messages: RenderMessage[], graphState: any, messagesMetadata: Record<string, {
98
+ subagent_id?: string;
99
+ }>): RenderMessage[];
94
100
  }
@@ -194,7 +194,7 @@ export class MessageProcessor {
194
194
  * @zh 转换 subAgent 消息为工具的子消息
195
195
  * @en Convert subAgent messages to tool sub-messages
196
196
  */
197
- convertSubAgentMessages(messages, graphState) {
197
+ convertSubAgentMessages(messages, graphState, messagesMetadata) {
198
198
  const origin_task_store = graphState[this.subAgentsKey];
199
199
  if (!origin_task_store)
200
200
  return messages;
@@ -202,11 +202,12 @@ export class MessageProcessor {
202
202
  /** 获取 subAgent 消息的 id,用于流式过程中对数据进行标记 */
203
203
  messages
204
204
  .filter((i) => {
205
- var _a;
206
- return (_a = i.node_name) === null || _a === void 0 ? void 0 : _a.startsWith("subagent_");
205
+ var _a, _b;
206
+ return ((_a = messagesMetadata[i.id]) === null || _a === void 0 ? void 0 : _a.subagent_id) || ((_b = i.node_name) === null || _b === void 0 ? void 0 : _b.startsWith("subagent_"));
207
207
  })
208
208
  .forEach((i) => {
209
- const tool_call_id = i.node_name.replace("subagent_", "");
209
+ var _a;
210
+ const tool_call_id = ((_a = messagesMetadata[i.id]) === null || _a === void 0 ? void 0 : _a.subagent_id) || i.node_name.replace("subagent_", "");
210
211
  const store = task_store[tool_call_id];
211
212
  if (store) {
212
213
  // 根据 id 进行去重
@@ -233,7 +234,7 @@ export class MessageProcessor {
233
234
  const task = task_store[message.tool_call_id];
234
235
  if (task) {
235
236
  // 递归处理子消息,但避免重复处理
236
- message.sub_agent_messages = this.processMessages(task.messages);
237
+ message.sub_agent_messages = this.processMessages(task.messages, task, messagesMetadata);
237
238
  }
238
239
  }
239
240
  if (message.id && ignoreIds.has(message.id))
@@ -246,7 +247,7 @@ export class MessageProcessor {
246
247
  * @zh 生成用于 UI 中的流式渲染的消息
247
248
  * @en Generate messages used for streaming rendering in the UI
248
249
  */
249
- renderMessages(graphState, getGraphNodeNow) {
250
+ renderMessages(graphState, getGraphNodeNow, messagesMetadata) {
250
251
  var _a;
251
252
  const previousMessage = new Map();
252
253
  const closedToolCallIds = new Set();
@@ -304,20 +305,20 @@ export class MessageProcessor {
304
305
  result.unshift(message);
305
306
  }
306
307
  }
307
- return this.processMessages(result, graphState);
308
+ return this.processMessages(result, graphState, messagesMetadata);
308
309
  }
309
310
  /**
310
311
  * @zh 统一的消息处理入口,按顺序执行所有处理步骤
311
312
  * @en Unified message processing entry point, executing all processing steps in order
312
313
  */
313
- processMessages(messages, graphState) {
314
+ processMessages(messages, graphState, messagesMetadata) {
314
315
  // 1. 组合工具消息
315
316
  const composedMessages = this.composeToolMessages(messages);
316
317
  // 2. 附加信息
317
318
  const messagesWithInfo = this.attachInfoForMessage(composedMessages);
318
319
  // 3. 转换子代理消息(如果提供了 graphState)
319
320
  if (graphState) {
320
- return this.convertSubAgentMessages(messagesWithInfo, graphState);
321
+ return this.convertSubAgentMessages(messagesWithInfo, graphState, messagesMetadata);
321
322
  }
322
323
  return messagesWithInfo;
323
324
  }
@@ -9,7 +9,7 @@ import { useArtifacts } from "../artifacts/index.js";
9
9
  * @en Formats a Date object into a time string.
10
10
  */
11
11
  export const formatTime = (date) => {
12
- return date.toLocaleTimeString("en-US");
12
+ return date.toLocaleTimeString();
13
13
  };
14
14
  /**
15
15
  * @zh 格式化数字为带千位分隔符的字符串。
@@ -46,7 +46,8 @@ export const getMessageContent = (content) => {
46
46
  */
47
47
  export const getHistoryContent = (thread) => {
48
48
  var _a, _b, _c;
49
- const content = (_c = (_b = (_a = thread === null || thread === void 0 ? void 0 : thread.values) === null || _a === void 0 ? void 0 : _a.messages) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.content;
49
+ /** @ts-ignore */
50
+ const content = thread.title || thread.name || ((_c = (_b = (_a = thread === null || thread === void 0 ? void 0 : thread.values) === null || _a === void 0 ? void 0 : _a.messages) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.content);
50
51
  if (content && Array.isArray(content)) {
51
52
  return content.map((item) => {
52
53
  if (item.type === "text") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langgraph-js/sdk",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
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",
@@ -240,7 +240,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
240
240
  * @en Messages used for streaming rendering in the UI.
241
241
  */
242
242
  get renderMessage() {
243
- return this.messageProcessor.renderMessages(this.graphState, () => this.getGraphNodeNow());
243
+ return this.messageProcessor.renderMessages(this.graphState, () => this.getGraphNodeNow(), this.messagesMetadata);
244
244
  }
245
245
  /**
246
246
  * @zh 获取 Token 计数器信息。
@@ -304,6 +304,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
304
304
  this.messageProcessor.setGraphMessages(state.messages! as RenderMessage[]);
305
305
  return state;
306
306
  }
307
+ public messagesMetadata = {};
307
308
  /**
308
309
  * @zh 发送消息到 LangGraph 后端。
309
310
  * @en Sends a message to the LangGraph backend.
@@ -346,7 +347,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
346
347
  messages: messagesToSend,
347
348
  fe_tools: await this.tools.toJSON(this.currentAssistant!.graph_id),
348
349
  },
349
- streamMode: ["messages", "values", "updates"],
350
+ streamMode: ["messages", "values"],
350
351
  streamSubgraphs: true,
351
352
  command,
352
353
  });
@@ -363,6 +364,9 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
363
364
  this.currentRun = chunk.data;
364
365
  } else if (chunk.event === "error" || chunk.event === "Error" || chunk.event === "__stream_error__") {
365
366
  this.emit("error", chunk);
367
+ } else if (chunk.event === "messages/metadata") {
368
+ Object.assign(this.messagesMetadata, chunk.data);
369
+ continue;
366
370
  } else if (chunk.event === "messages/partial") {
367
371
  for (const message of chunk.data) {
368
372
  this.messageProcessor.updateStreamingMessage(message);
@@ -216,7 +216,16 @@ export class MessageProcessor {
216
216
  * @zh 转换 subAgent 消息为工具的子消息
217
217
  * @en Convert subAgent messages to tool sub-messages
218
218
  */
219
- convertSubAgentMessages(messages: RenderMessage[], graphState: any): RenderMessage[] {
219
+ convertSubAgentMessages(
220
+ messages: RenderMessage[],
221
+ graphState: any,
222
+ messagesMetadata: Record<
223
+ string,
224
+ {
225
+ subagent_id?: string;
226
+ }
227
+ >
228
+ ): RenderMessage[] {
220
229
  const origin_task_store = graphState[this.subAgentsKey];
221
230
  if (!origin_task_store) return messages;
222
231
 
@@ -225,10 +234,10 @@ export class MessageProcessor {
225
234
  /** 获取 subAgent 消息的 id,用于流式过程中对数据进行标记 */
226
235
  messages
227
236
  .filter((i) => {
228
- return i.node_name?.startsWith("subagent_");
237
+ return messagesMetadata[i.id!]?.subagent_id || i.node_name?.startsWith("subagent_");
229
238
  })
230
239
  .forEach((i) => {
231
- const tool_call_id = i.node_name!.replace("subagent_", "");
240
+ const tool_call_id = messagesMetadata[i.id!]?.subagent_id || i.node_name!.replace("subagent_", "");
232
241
  const store = task_store[tool_call_id];
233
242
  if (store) {
234
243
  // 根据 id 进行去重
@@ -256,7 +265,7 @@ export class MessageProcessor {
256
265
  const task = task_store[message.tool_call_id];
257
266
  if (task) {
258
267
  // 递归处理子消息,但避免重复处理
259
- message.sub_agent_messages = this.processMessages(task.messages);
268
+ message.sub_agent_messages = this.processMessages(task.messages, task, messagesMetadata);
260
269
  }
261
270
  }
262
271
  if (message.id && ignoreIds.has(message.id)) continue;
@@ -269,7 +278,16 @@ export class MessageProcessor {
269
278
  * @zh 生成用于 UI 中的流式渲染的消息
270
279
  * @en Generate messages used for streaming rendering in the UI
271
280
  */
272
- renderMessages(graphState: any, getGraphNodeNow: () => { name: string }): RenderMessage[] {
281
+ renderMessages(
282
+ graphState: any,
283
+ getGraphNodeNow: () => { name: string },
284
+ messagesMetadata: Record<
285
+ string,
286
+ {
287
+ subagent_id?: string;
288
+ }
289
+ >
290
+ ): RenderMessage[] {
273
291
  const previousMessage = new Map<string, Message>();
274
292
  const closedToolCallIds = new Set<string>();
275
293
  const result: Message[] = [];
@@ -328,14 +346,23 @@ export class MessageProcessor {
328
346
  }
329
347
  }
330
348
 
331
- return this.processMessages(result as RenderMessage[], graphState);
349
+ return this.processMessages(result as RenderMessage[], graphState, messagesMetadata);
332
350
  }
333
351
 
334
352
  /**
335
353
  * @zh 统一的消息处理入口,按顺序执行所有处理步骤
336
354
  * @en Unified message processing entry point, executing all processing steps in order
337
355
  */
338
- processMessages(messages: RenderMessage[], graphState?: any): RenderMessage[] {
356
+ processMessages(
357
+ messages: RenderMessage[],
358
+ graphState: any,
359
+ messagesMetadata: Record<
360
+ string,
361
+ {
362
+ subagent_id?: string;
363
+ }
364
+ >
365
+ ): RenderMessage[] {
339
366
  // 1. 组合工具消息
340
367
  const composedMessages = this.composeToolMessages(messages);
341
368
 
@@ -344,7 +371,7 @@ export class MessageProcessor {
344
371
 
345
372
  // 3. 转换子代理消息(如果提供了 graphState)
346
373
  if (graphState) {
347
- return this.convertSubAgentMessages(messagesWithInfo, graphState);
374
+ return this.convertSubAgentMessages(messagesWithInfo, graphState, messagesMetadata);
348
375
  }
349
376
 
350
377
  return messagesWithInfo;
@@ -12,7 +12,7 @@ import { useArtifacts } from "../artifacts/index.js";
12
12
  * @en Formats a Date object into a time string.
13
13
  */
14
14
  export const formatTime = (date: Date) => {
15
- return date.toLocaleTimeString("en-US");
15
+ return date.toLocaleTimeString();
16
16
  };
17
17
 
18
18
  /**
@@ -47,7 +47,8 @@ export const getMessageContent = (content: any) => {
47
47
  * @en Gets the text representation of Thread content in history.
48
48
  */
49
49
  export const getHistoryContent = (thread: Thread) => {
50
- const content = (thread?.values as any)?.messages?.[0]?.content;
50
+ /** @ts-ignore */
51
+ const content: string | any[] = thread.title || thread.name || (thread?.values as any)?.messages?.[0]?.content;
51
52
  if (content && Array.isArray(content)) {
52
53
  return content.map((item: any) => {
53
54
  if (item.type === "text") {