@langgraph-js/sdk 3.0.3 → 3.1.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.
@@ -100,6 +100,7 @@ export class LangGraphClient extends EventEmitter {
100
100
  async listThreads() {
101
101
  return this.threads.search({
102
102
  sortOrder: "desc",
103
+ sortBy: "updated_at",
103
104
  });
104
105
  }
105
106
  async deleteThread(threadId) {
@@ -0,0 +1,29 @@
1
+ import { PreinitializedWritableAtom } from "nanostores";
2
+ export * from "./types.js";
3
+ import { LangGraphClient, RenderMessage } from "../LangGraphClient.js";
4
+ export interface ComposedArtifact {
5
+ id: string;
6
+ filename: string;
7
+ filetype: string;
8
+ versions: Artifact[];
9
+ }
10
+ export interface Artifact {
11
+ group_id: string;
12
+ id: string;
13
+ code: string;
14
+ filename: string;
15
+ filetype: string;
16
+ version: number;
17
+ is_done: boolean;
18
+ }
19
+ export declare const useArtifacts: (renderMessages: PreinitializedWritableAtom<RenderMessage[]>, client: PreinitializedWritableAtom<LangGraphClient<unknown> | null>) => {
20
+ data: {
21
+ artifacts: PreinitializedWritableAtom<ComposedArtifact[]> & object;
22
+ currentArtifactId: PreinitializedWritableAtom<[string, string] | null> & object;
23
+ showArtifact: PreinitializedWritableAtom<boolean> & object;
24
+ };
25
+ mutation: {
26
+ setCurrentArtifactById: (id: string, tool_id: string) => void;
27
+ setShowArtifact: (show: boolean) => void;
28
+ };
29
+ };
@@ -0,0 +1,98 @@
1
+ import { atom, effect } from "nanostores";
2
+ export * from "./types.js";
3
+ import { ToolRenderData } from "../tool/ToolUI.js";
4
+ // 创建 artifacts computed store
5
+ const extractArtifactsFromMessages = (renderMessages, client) => {
6
+ const files = new Map();
7
+ for (const message of renderMessages) {
8
+ if (message.type === "tool" && message.name === "create_artifacts") {
9
+ const tool = new ToolRenderData(message, client);
10
+ const command = tool.getInputRepaired();
11
+ if (!command.id)
12
+ continue;
13
+ command.tool_id = tool.message.id;
14
+ command.is_done = tool.state === "done";
15
+ files.set(command.id, [...(files.get(command.id) || []), command]);
16
+ }
17
+ }
18
+ const composedFiles = new Map();
19
+ // 遍历每个 ID 的命令序列,生成对应的 artifact 版本
20
+ for (const [id, commands] of files) {
21
+ const artifacts = [];
22
+ let currentContent = "";
23
+ let currentFilename = "";
24
+ let currentFiletype = "";
25
+ let version = 1;
26
+ // 按命令顺序处理每个操作
27
+ for (const command of commands) {
28
+ switch (command.command) {
29
+ case "create":
30
+ // 创建新 artifact,直接使用 content
31
+ currentContent = command.content;
32
+ currentFilename = command.title || `artifact-${id}`;
33
+ currentFiletype = command.type || command.language;
34
+ break;
35
+ case "update":
36
+ // 更新现有内容,使用 old_str 和 new_str 进行替换
37
+ if (command.old_str && command.new_str) {
38
+ currentContent = currentContent.replace(command.old_str, command.new_str);
39
+ }
40
+ else if (command.content) {
41
+ // 如果没有 old_str/new_str,则直接使用 content 覆盖
42
+ currentContent = command.content;
43
+ }
44
+ break;
45
+ case "rewrite":
46
+ currentContent = command.content;
47
+ break;
48
+ }
49
+ // 创建当前版本的 artifact
50
+ const artifact = {
51
+ group_id: id,
52
+ id: command.tool_id,
53
+ code: currentContent,
54
+ filename: currentFilename,
55
+ filetype: currentFiletype,
56
+ version: version,
57
+ is_done: command.is_done,
58
+ };
59
+ artifacts.push(artifact);
60
+ version++;
61
+ }
62
+ composedFiles.set(id, artifacts);
63
+ }
64
+ return [...composedFiles.values()].map((artifacts) => ({
65
+ id: artifacts[0].group_id,
66
+ filename: artifacts[artifacts.length - 1].filename,
67
+ filetype: artifacts[artifacts.length - 1].filetype,
68
+ versions: artifacts,
69
+ }));
70
+ };
71
+ export const useArtifacts = (renderMessages, client) => {
72
+ // 创建 artifacts store
73
+ const showArtifact = atom(false);
74
+ const currentArtifactId = atom(null);
75
+ const artifacts = atom([]);
76
+ effect([renderMessages, client], () => {
77
+ artifacts.set(extractArtifactsFromMessages(renderMessages.get(), client.get()));
78
+ });
79
+ const debouncedSetCurrentArtifactById = (id, tool_id) => {
80
+ const current = currentArtifactId.get();
81
+ if ((current === null || current === void 0 ? void 0 : current[0]) === id && (current === null || current === void 0 ? void 0 : current[1]) === tool_id) {
82
+ return;
83
+ }
84
+ showArtifact.set(true);
85
+ currentArtifactId.set([id, tool_id]);
86
+ };
87
+ return {
88
+ data: {
89
+ artifacts,
90
+ currentArtifactId,
91
+ showArtifact,
92
+ },
93
+ mutation: {
94
+ setCurrentArtifactById: debouncedSetCurrentArtifactById,
95
+ setShowArtifact: (show) => showArtifact.set(show),
96
+ },
97
+ };
98
+ };
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ export declare const ArtifactCommandSchema: {
3
+ command: z.ZodEnum<["create", "update", "rewrite"]>;
4
+ id: z.ZodString;
5
+ title: z.ZodString;
6
+ type: z.ZodString;
7
+ language: z.ZodString;
8
+ content: z.ZodString;
9
+ old_str: z.ZodString;
10
+ new_str: z.ZodString;
11
+ };
12
+ export type ArtifactCommand = z.infer<z.ZodObject<typeof ArtifactCommandSchema>>;
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ export const ArtifactCommandSchema = {
3
+ command: z.enum(["create", "update", "rewrite"]).describe("The operation to perform: create new artifact, update existing, or rewrite"),
4
+ id: z.string().describe("Unique identifier for the artifact"),
5
+ title: z.string().describe("Human-readable title for the artifact"),
6
+ type: z.string().describe("MIME type of the artifact content (e.g., 'application/vnd.ant.react')"),
7
+ language: z.string().describe("Programming language or format of the content"),
8
+ content: z.string().describe("The actual content to be created or updated. Don't Reply These Code to User, User can see these code in artifacts."),
9
+ old_str: z.string().describe("The existing content to be replaced (for update operations)"),
10
+ new_str: z.string().describe("The new content to replace the old content (for update operations)"),
11
+ };
package/dist/index.d.ts CHANGED
@@ -5,3 +5,4 @@ export * from "@langchain/langgraph-sdk";
5
5
  export * from "./ui-store/index.js";
6
6
  export * from "./ToolManager.js";
7
7
  export * from "./TestKit.js";
8
+ export * from "./artifacts/index.js";
package/dist/index.js CHANGED
@@ -5,3 +5,4 @@ export * from "@langchain/langgraph-sdk";
5
5
  export * from "./ui-store/index.js";
6
6
  export * from "./ToolManager.js";
7
7
  export * from "./TestKit.js";
8
+ export * from "./artifacts/index.js";
@@ -2,6 +2,9 @@ import { ReactNode } from "react";
2
2
  import { UnionStore } from "../ui-store/index.js";
3
3
  export declare const useChat: () => UnionStore<{
4
4
  data: {
5
+ artifacts: import("nanostores").PreinitializedWritableAtom<import("../index.js").ComposedArtifact[]> & object;
6
+ currentArtifactId: import("nanostores").PreinitializedWritableAtom<[string, string] | null> & object;
7
+ showArtifact: import("nanostores").PreinitializedWritableAtom<boolean> & object;
5
8
  client: import("nanostores").PreinitializedWritableAtom<import("../LangGraphClient.js").LangGraphClient<unknown> | null> & object;
6
9
  renderMessages: import("nanostores").PreinitializedWritableAtom<import("../LangGraphClient.js").RenderMessage[]> & object;
7
10
  userInput: import("nanostores").PreinitializedWritableAtom<string> & object;
@@ -20,9 +23,12 @@ export declare const useChat: () => UnionStore<{
20
23
  tools: import("nanostores").PreinitializedWritableAtom<import("../index.js").UnionTool<any, Object, any>[]> & object;
21
24
  };
22
25
  mutations: {
26
+ setCurrentArtifactById: (id: string, tool_id: string) => void;
27
+ setShowArtifact: (show: boolean) => void;
23
28
  refreshTools: () => Promise<void>;
24
29
  setTools(new_tools: import("../index.js").UnionTool<any>[]): void;
25
30
  isFELocking(): boolean | undefined;
31
+ getClient(): import("../LangGraphClient.js").LangGraphClient<unknown> | null;
26
32
  initClient: () => Promise<import("../LangGraphClient.js").LangGraphClient<unknown>>;
27
33
  sendMessage: (message?: import("@langchain/langgraph-sdk").Message[], extraData?: import("../LangGraphClient.js").SendMessageOptions, withoutCheck?: boolean) => Promise<void>;
28
34
  stopGeneration: () => void;
@@ -31,6 +31,9 @@ export declare const createChatStore: (initClientName: string, config: Partial<L
31
31
  onInit?: (client: LangGraphClient) => void;
32
32
  }) => {
33
33
  data: {
34
+ artifacts: import("nanostores").PreinitializedWritableAtom<import("../artifacts/index.js").ComposedArtifact[]> & object;
35
+ currentArtifactId: import("nanostores").PreinitializedWritableAtom<[string, string] | null> & object;
36
+ showArtifact: import("nanostores").PreinitializedWritableAtom<boolean> & object;
34
37
  client: import("nanostores").PreinitializedWritableAtom<LangGraphClient<unknown> | null> & object;
35
38
  renderMessages: import("nanostores").PreinitializedWritableAtom<RenderMessage[]> & object;
36
39
  userInput: import("nanostores").PreinitializedWritableAtom<string> & object;
@@ -49,9 +52,12 @@ export declare const createChatStore: (initClientName: string, config: Partial<L
49
52
  tools: import("nanostores").PreinitializedWritableAtom<UnionTool<any, Object, any>[]> & object;
50
53
  };
51
54
  mutations: {
55
+ setCurrentArtifactById: (id: string, tool_id: string) => void;
56
+ setShowArtifact: (show: boolean) => void;
52
57
  refreshTools: () => Promise<void>;
53
58
  setTools(new_tools: UnionTool<any>[]): void;
54
59
  isFELocking(): boolean | undefined;
60
+ getClient(): LangGraphClient<unknown> | null;
55
61
  initClient: () => Promise<LangGraphClient<unknown>>;
56
62
  sendMessage: (message?: Message[], extraData?: SendMessageOptions, withoutCheck?: boolean) => Promise<void>;
57
63
  stopGeneration: () => void;
@@ -3,6 +3,7 @@ import { LangGraphClient } from "../LangGraphClient.js";
3
3
  import { debounce } from "ts-debounce";
4
4
  import { ToolRenderData } from "../tool/ToolUI.js";
5
5
  import { createLangGraphServerClient } from "../client/LanggraphServer.js";
6
+ import { useArtifacts } from "../artifacts/index.js";
6
7
  /**
7
8
  * @zh 格式化日期对象为时间字符串。
8
9
  * @en Formats a Date object into a time string.
@@ -238,6 +239,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
238
239
  const tool = (_a = toolsDefine.find((i) => i.name === tool_name)) === null || _a === void 0 ? void 0 : _a.render;
239
240
  return tool ? (message) => tool(new ToolRenderData(message, client.get())) : null;
240
241
  };
242
+ const artifactHook = useArtifacts(renderMessages, client);
241
243
  return {
242
244
  data: {
243
245
  client,
@@ -254,6 +256,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
254
256
  graphVisualize,
255
257
  currentNodeName,
256
258
  tools,
259
+ ...artifactHook.data,
257
260
  },
258
261
  mutations: {
259
262
  refreshTools,
@@ -265,6 +268,9 @@ export const createChatStore = (initClientName, config, context = {}) => {
265
268
  var _a;
266
269
  return (_a = client.get()) === null || _a === void 0 ? void 0 : _a.isFELocking(renderMessages.get());
267
270
  },
271
+ getClient() {
272
+ return client.get();
273
+ },
268
274
  initClient,
269
275
  sendMessage,
270
276
  stopGeneration,
@@ -346,6 +352,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
346
352
  await refreshHistoryList();
347
353
  },
348
354
  getToolUIRender,
355
+ ...artifactHook.mutation,
349
356
  },
350
357
  };
351
358
  };
@@ -40,6 +40,9 @@ export interface ChatProviderProps {
40
40
  export declare const useChatProvider: (props: ChatProviderProps) => {
41
41
  unionStore: UnionStoreVue<{
42
42
  data: {
43
+ artifacts: PreinitializedWritableAtom<import("../index.js").ComposedArtifact[]> & object;
44
+ currentArtifactId: PreinitializedWritableAtom<[string, string] | null> & object;
45
+ showArtifact: PreinitializedWritableAtom<boolean> & object;
43
46
  client: PreinitializedWritableAtom<import("../LangGraphClient.js").LangGraphClient<unknown> | null> & object;
44
47
  renderMessages: PreinitializedWritableAtom<import("../LangGraphClient.js").RenderMessage[]> & object;
45
48
  userInput: PreinitializedWritableAtom<string> & object;
@@ -58,9 +61,12 @@ export declare const useChatProvider: (props: ChatProviderProps) => {
58
61
  tools: PreinitializedWritableAtom<import("../index.js").UnionTool<any, Object, any>[]> & object;
59
62
  };
60
63
  mutations: {
64
+ setCurrentArtifactById: (id: string, tool_id: string) => void;
65
+ setShowArtifact: (show: boolean) => void;
61
66
  refreshTools: () => Promise<void>;
62
67
  setTools(new_tools: import("../index.js").UnionTool<any>[]): void;
63
68
  isFELocking(): boolean | undefined;
69
+ getClient(): import("../LangGraphClient.js").LangGraphClient<unknown> | null;
64
70
  initClient: () => Promise<import("../LangGraphClient.js").LangGraphClient<unknown>>;
65
71
  sendMessage: (message?: import("@langchain/langgraph-sdk").Message[], extraData?: import("../LangGraphClient.js").SendMessageOptions, withoutCheck?: boolean) => Promise<void>;
66
72
  stopGeneration: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langgraph-js/sdk",
3
- "version": "3.0.3",
3
+ "version": "3.1.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",
@@ -188,6 +188,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
188
188
  async listThreads() {
189
189
  return this.threads.search({
190
190
  sortOrder: "desc",
191
+ sortBy: "updated_at",
191
192
  });
192
193
  }
193
194
  async deleteThread(threadId: string) {
@@ -0,0 +1,129 @@
1
+ import { atom, computed, effect, PreinitializedWritableAtom } from "nanostores";
2
+ export * from "./types.js";
3
+ import { ArtifactCommand } from "./types.js";
4
+ import { ToolRenderData } from "../tool/ToolUI.js";
5
+ import { LangGraphClient, RenderMessage } from "../LangGraphClient.js";
6
+
7
+ export interface ComposedArtifact {
8
+ id: string;
9
+ filename: string;
10
+ filetype: string;
11
+ versions: Artifact[];
12
+ }
13
+
14
+ export interface Artifact {
15
+ group_id: string;
16
+ id: string;
17
+ code: string;
18
+ filename: string;
19
+ filetype: string;
20
+ version: number;
21
+ is_done: boolean;
22
+ }
23
+
24
+ // 创建 artifacts computed store
25
+ const extractArtifactsFromMessages = (renderMessages: any[], client: any): ComposedArtifact[] => {
26
+ type MiddleArtifactCommand = ArtifactCommand & {
27
+ tool_id?: string;
28
+ is_done?: boolean;
29
+ };
30
+ const files = new Map<string, MiddleArtifactCommand[]>();
31
+ for (const message of renderMessages) {
32
+ if (message.type === "tool" && message.name === "create_artifacts") {
33
+ const tool = new ToolRenderData<ArtifactCommand, {}>(message, client!);
34
+ const command = tool.getInputRepaired() as MiddleArtifactCommand;
35
+ if (!command.id) continue;
36
+ command.tool_id = tool.message.id!;
37
+ command.is_done = tool.state === "done";
38
+ files.set(command.id, [...(files.get(command.id) || []), command]);
39
+ }
40
+ }
41
+ const composedFiles = new Map<string, Artifact[]>();
42
+
43
+ // 遍历每个 ID 的命令序列,生成对应的 artifact 版本
44
+ for (const [id, commands] of files) {
45
+ const artifacts: Artifact[] = [];
46
+ let currentContent = "";
47
+ let currentFilename = "";
48
+ let currentFiletype = "";
49
+ let version = 1;
50
+
51
+ // 按命令顺序处理每个操作
52
+ for (const command of commands) {
53
+ switch (command.command) {
54
+ case "create":
55
+ // 创建新 artifact,直接使用 content
56
+ currentContent = command.content;
57
+ currentFilename = command.title || `artifact-${id}`;
58
+ currentFiletype = command.type || command.language;
59
+ break;
60
+
61
+ case "update":
62
+ // 更新现有内容,使用 old_str 和 new_str 进行替换
63
+ if (command.old_str && command.new_str) {
64
+ currentContent = currentContent.replace(command.old_str, command.new_str);
65
+ } else if (command.content) {
66
+ // 如果没有 old_str/new_str,则直接使用 content 覆盖
67
+ currentContent = command.content;
68
+ }
69
+ break;
70
+
71
+ case "rewrite":
72
+ currentContent = command.content;
73
+ break;
74
+ }
75
+
76
+ // 创建当前版本的 artifact
77
+ const artifact: Artifact = {
78
+ group_id: id,
79
+ id: command.tool_id!,
80
+ code: currentContent,
81
+ filename: currentFilename,
82
+ filetype: currentFiletype,
83
+ version: version,
84
+ is_done: command.is_done!,
85
+ };
86
+
87
+ artifacts.push(artifact);
88
+ version++;
89
+ }
90
+
91
+ composedFiles.set(id, artifacts);
92
+ }
93
+
94
+ return [...composedFiles.values()].map((artifacts) => ({
95
+ id: artifacts[0].group_id,
96
+ filename: artifacts[artifacts.length - 1].filename,
97
+ filetype: artifacts[artifacts.length - 1].filetype,
98
+ versions: artifacts,
99
+ }));
100
+ };
101
+ export const useArtifacts = (renderMessages: PreinitializedWritableAtom<RenderMessage[]>, client: PreinitializedWritableAtom<LangGraphClient<unknown> | null>) => {
102
+ // 创建 artifacts store
103
+ const showArtifact = atom<boolean>(false);
104
+ const currentArtifactId = atom<[string, string] | null>(null);
105
+ const artifacts = atom<ComposedArtifact[]>([]);
106
+
107
+ effect([renderMessages, client], () => {
108
+ artifacts.set(extractArtifactsFromMessages(renderMessages.get(), client.get()));
109
+ });
110
+ const debouncedSetCurrentArtifactById = (id: string, tool_id: string) => {
111
+ const current = currentArtifactId.get();
112
+ if (current?.[0] === id && current?.[1] === tool_id) {
113
+ return;
114
+ }
115
+ showArtifact.set(true);
116
+ currentArtifactId.set([id, tool_id]);
117
+ };
118
+ return {
119
+ data: {
120
+ artifacts,
121
+ currentArtifactId,
122
+ showArtifact,
123
+ },
124
+ mutation: {
125
+ setCurrentArtifactById: debouncedSetCurrentArtifactById,
126
+ setShowArtifact: (show: boolean) => showArtifact.set(show),
127
+ },
128
+ };
129
+ };
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ export const ArtifactCommandSchema = {
3
+ command: z.enum(["create", "update", "rewrite"]).describe("The operation to perform: create new artifact, update existing, or rewrite"),
4
+ id: z.string().describe("Unique identifier for the artifact"),
5
+ title: z.string().describe("Human-readable title for the artifact"),
6
+ type: z.string().describe("MIME type of the artifact content (e.g., 'application/vnd.ant.react')"),
7
+ language: z.string().describe("Programming language or format of the content"),
8
+ content: z.string().describe("The actual content to be created or updated. Don't Reply These Code to User, User can see these code in artifacts."),
9
+ old_str: z.string().describe("The existing content to be replaced (for update operations)"),
10
+ new_str: z.string().describe("The new content to replace the old content (for update operations)"),
11
+ };
12
+ export type ArtifactCommand = z.infer<z.ZodObject<typeof ArtifactCommandSchema>>;
package/src/index.ts CHANGED
@@ -5,3 +5,4 @@ export * from "@langchain/langgraph-sdk";
5
5
  export * from "./ui-store/index.js";
6
6
  export * from "./ToolManager.js";
7
7
  export * from "./TestKit.js";
8
+ export * from "./artifacts/index.js";
@@ -1,10 +1,11 @@
1
- import { atom, computed } from "nanostores";
1
+ import { atom } from "nanostores";
2
2
  import { LangGraphClient, LangGraphClientConfig, RenderMessage, SendMessageOptions } from "../LangGraphClient.js";
3
- import { AssistantGraph, Client, Message, Thread } from "@langchain/langgraph-sdk";
3
+ import { AssistantGraph, Message, Thread } from "@langchain/langgraph-sdk";
4
4
  import { debounce } from "ts-debounce";
5
5
  import { ToolRenderData } from "../tool/ToolUI.js";
6
6
  import { UnionTool } from "../tool/createTool.js";
7
7
  import { createLangGraphServerClient } from "../client/LanggraphServer.js";
8
+ import { useArtifacts } from "../artifacts/index.js";
8
9
 
9
10
  /**
10
11
  * @zh 格式化日期对象为时间字符串。
@@ -245,6 +246,7 @@ export const createChatStore = (
245
246
  return tool ? (message: RenderMessage) => tool(new ToolRenderData(message, client.get()!)) : null;
246
247
  };
247
248
 
249
+ const artifactHook = useArtifacts(renderMessages, client);
248
250
  return {
249
251
  data: {
250
252
  client,
@@ -261,6 +263,7 @@ export const createChatStore = (
261
263
  graphVisualize,
262
264
  currentNodeName,
263
265
  tools,
266
+ ...artifactHook.data,
264
267
  },
265
268
  mutations: {
266
269
  refreshTools,
@@ -271,6 +274,9 @@ export const createChatStore = (
271
274
  isFELocking() {
272
275
  return client.get()?.isFELocking(renderMessages.get());
273
276
  },
277
+ getClient() {
278
+ return client.get();
279
+ },
274
280
  initClient,
275
281
  sendMessage,
276
282
  stopGeneration,
@@ -351,6 +357,7 @@ export const createChatStore = (
351
357
  await refreshHistoryList();
352
358
  },
353
359
  getToolUIRender,
360
+ ...artifactHook.mutation,
354
361
  },
355
362
  };
356
363
  };