@langgraph-js/sdk 4.2.0 → 4.3.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.
package/dist/History.js CHANGED
@@ -191,7 +191,7 @@ export class History {
191
191
  throw new Error("Agent name is required. Please call init() first or provide agentName.");
192
192
  }
193
193
  const threads = await this.listRemoteSessions({
194
- limit: options.limit || 100,
194
+ limit: options.limit || 10,
195
195
  sortBy: "updated_at",
196
196
  sortOrder: "desc",
197
197
  });
@@ -51,14 +51,7 @@ export const ChatProvider = ({ children, defaultAgent = "", apiUrl = "http://loc
51
51
  return;
52
52
  }
53
53
  initializedRef.current = true;
54
- unionStore
55
- .initClient()
56
- .then((res) => {
57
- if (unionStore.showHistory) {
58
- unionStore.refreshHistoryList();
59
- }
60
- })
61
- .catch((err) => {
54
+ unionStore.initClient().catch((err) => {
62
55
  console.error(err);
63
56
  if (onInitErrorRef.current) {
64
57
  onInitErrorRef.current(err, unionStore.currentAgent);
@@ -0,0 +1,100 @@
1
+ import { type JSX, Accessor } from "solid-js";
2
+ import { ILangGraphClient } from "@langgraph-js/pure-graph/dist/types.js";
3
+ import { PreinitializedWritableAtom, StoreValue } from "nanostores";
4
+ export declare const useChat: () => UnionStoreSolid<{
5
+ data: {
6
+ artifacts: PreinitializedWritableAtom<import("../index.js").ComposedArtifact[]> & object;
7
+ currentArtifactId: PreinitializedWritableAtom<[string, string] | null> & object;
8
+ showArtifact: PreinitializedWritableAtom<boolean> & object;
9
+ client: PreinitializedWritableAtom<import("../LangGraphClient.js").LangGraphClient<unknown> | null> & object;
10
+ history: PreinitializedWritableAtom<import("../History.js").History | null> & object;
11
+ sessions: PreinitializedWritableAtom<import("../History.js").SessionInfo[]> & object;
12
+ renderMessages: PreinitializedWritableAtom<import("../LangGraphClient.js").RenderMessage[]> & object;
13
+ userInput: PreinitializedWritableAtom<string> & object;
14
+ loading: PreinitializedWritableAtom<boolean> & object;
15
+ inChatError: PreinitializedWritableAtom<string | null> & object;
16
+ currentAgent: PreinitializedWritableAtom<string> & object;
17
+ currentChatId: PreinitializedWritableAtom<string | null> & object;
18
+ currentNodeName: PreinitializedWritableAtom<string> & object;
19
+ interruptData: PreinitializedWritableAtom<import("../humanInTheLoop.js").InterruptData | null> & object;
20
+ isInterrupted: PreinitializedWritableAtom<boolean> & object;
21
+ tools: PreinitializedWritableAtom<import("../index.js").UnionTool<any, Object, any>[]> & object;
22
+ collapsedTools: PreinitializedWritableAtom<string[]> & object;
23
+ showGraph: PreinitializedWritableAtom<boolean> & object;
24
+ graphVisualize: PreinitializedWritableAtom<import("@langchain/langgraph-sdk").AssistantGraph | null> & object;
25
+ showHistory: PreinitializedWritableAtom<boolean> & object;
26
+ historyList: PreinitializedWritableAtom<import("@langchain/langgraph-sdk").Thread<{
27
+ messages: import("@langchain/langgraph-sdk").Message[];
28
+ }>[]> & object;
29
+ };
30
+ mutations: {
31
+ setCurrentArtifactById: (id: string, tool_id: string) => void;
32
+ setShowArtifact: (show: boolean) => void;
33
+ initClient: () => Promise<import("../History.js").History>;
34
+ getClient: () => import("../LangGraphClient.js").LangGraphClient<unknown> | null;
35
+ getHistory: () => import("../History.js").History | null;
36
+ activateSession: (sessionId: string) => Promise<void>;
37
+ createNewSession: () => Promise<void>;
38
+ refreshSessionList: () => Promise<void>;
39
+ refreshHistoryList: () => Promise<void>;
40
+ sendMessage: (message?: import("@langchain/langgraph-sdk").Message[], extraData?: import("../LangGraphClient.js").SendMessageOptions, withoutCheck?: boolean, isResume?: boolean) => Promise<void>;
41
+ stopGeneration: () => void;
42
+ setUserInput: (input: string) => void;
43
+ revertChatTo(messageId: string, resend?: boolean, sendOptions?: import("../LangGraphClient.js").SendMessageOptions & import("../time-travel/index.js").RevertChatToOptions): Promise<void>;
44
+ refreshTools: () => Promise<void>;
45
+ setTools(new_tools: import("../index.js").UnionTool<any>[]): void;
46
+ toggleToolCollapse: (toolId: string) => void;
47
+ getToolUIRender: (tool_name: string) => ((message: import("../LangGraphClient.js").RenderMessage) => Object) | null;
48
+ isFELocking: () => boolean | undefined;
49
+ toggleHistoryVisible: () => void;
50
+ toggleGraphVisible(): void;
51
+ refreshGraph: () => Promise<void>;
52
+ setCurrentAgent(agent: string): Promise<import("../History.js").History>;
53
+ resumeFromInterrupt(data: any): Promise<void>;
54
+ addToHistory: (thread: import("@langchain/langgraph-sdk").Thread<{
55
+ messages: import("@langchain/langgraph-sdk").Message[];
56
+ }>) => void;
57
+ createNewChat: () => Promise<void>;
58
+ toHistoryChat: (thread: import("@langchain/langgraph-sdk").Thread<{
59
+ messages: import("@langchain/langgraph-sdk").Message[];
60
+ }>) => Promise<void>;
61
+ deleteHistoryChat(thread: import("@langchain/langgraph-sdk").Thread<{
62
+ messages: import("@langchain/langgraph-sdk").Message[];
63
+ }>): Promise<void>;
64
+ };
65
+ }>;
66
+ interface ChatProviderProps {
67
+ children: JSX.Element;
68
+ defaultAgent?: string;
69
+ apiUrl?: string;
70
+ defaultHeaders?: Record<string, string>;
71
+ withCredentials?: boolean;
72
+ showHistory?: boolean;
73
+ showGraph?: boolean;
74
+ fallbackToAvailableAssistants?: boolean;
75
+ /** 初始化时是否自动激活最近的历史会话(默认 false,创建新会话) */
76
+ autoRestoreLastSession?: boolean;
77
+ onInitError?: (error: any, currentAgent: string) => void;
78
+ client?: ILangGraphClient;
79
+ legacyMode?: boolean;
80
+ }
81
+ /**
82
+ * @zh UnionStore 类型用于合并 store 的 data 和 mutations,使其可以直接访问。
83
+ * @en The UnionStore type is used to merge the data and mutations of a store, allowing direct access.
84
+ */
85
+ export type UnionStoreSolid<T extends {
86
+ data: Record<string, PreinitializedWritableAtom<any>>;
87
+ mutations: Record<string, any>;
88
+ }> = {
89
+ [k in keyof T["data"]]: Accessor<StoreValue<T["data"][k]>>;
90
+ } & T["mutations"];
91
+ /**
92
+ * @zh useUnionStore Hook 用于将 nanostores 的 store 结构转换为更易于在 UI 组件中使用的扁平结构。
93
+ * @en The useUnionStore Hook is used to transform the nanostores store structure into a flatter structure that is easier to use in UI components.
94
+ */
95
+ export declare const useUnionStoreSolid: <T extends {
96
+ data: Record<string, any>;
97
+ mutations: Record<string, any>;
98
+ }>(store: T, useStore: (store: PreinitializedWritableAtom<any>) => Accessor<any>) => UnionStoreSolid<T>;
99
+ export declare const ChatProvider: (props: ChatProviderProps) => JSX.Element;
100
+ export {};
@@ -0,0 +1,77 @@
1
+ import { createContext, useContext, createMemo, onMount, createComponent } from "solid-js";
2
+ import { createChatStore } from "../ui-store/index.js";
3
+ import { useStore } from "@nanostores/solid";
4
+ const ChatContext = createContext(undefined);
5
+ export const useChat = () => {
6
+ const context = useContext(ChatContext);
7
+ if (!context) {
8
+ throw new Error("useChat must be used within a ChatProvider");
9
+ }
10
+ return context;
11
+ };
12
+ /**
13
+ * @zh useUnionStore Hook 用于将 nanostores 的 store 结构转换为更易于在 UI 组件中使用的扁平结构。
14
+ * @en The useUnionStore Hook is used to transform the nanostores store structure into a flatter structure that is easier to use in UI components.
15
+ */
16
+ export const useUnionStoreSolid = (store, useStore) => {
17
+ const data = Object.fromEntries(Object.entries(store.data).map(([key, value]) => {
18
+ return [key, useStore(value)];
19
+ }));
20
+ return {
21
+ ...data,
22
+ ...store.mutations,
23
+ };
24
+ };
25
+ export const ChatProvider = (props) => {
26
+ // 使用 createMemo 稳定 defaultHeaders 的引用
27
+ const stableHeaders = createMemo(() => props.defaultHeaders || {});
28
+ // 使用 createMemo 创建 fetch 函数
29
+ const F = createMemo(() => props.withCredentials
30
+ ? (url, options) => {
31
+ options.credentials = "include";
32
+ return fetch(url, options);
33
+ }
34
+ : fetch);
35
+ const store = createMemo(() => {
36
+ const config = {
37
+ apiUrl: props.apiUrl || "http://localhost:8123",
38
+ defaultHeaders: stableHeaders(),
39
+ callerOptions: {
40
+ fetch: F(),
41
+ maxRetries: 1,
42
+ },
43
+ legacyMode: props.legacyMode || false,
44
+ };
45
+ /** @ts-ignore */
46
+ if (props.client)
47
+ config.client = props.client;
48
+ return createChatStore(props.defaultAgent || "", config, {
49
+ showHistory: props.showHistory || false,
50
+ showGraph: props.showGraph || false,
51
+ fallbackToAvailableAssistants: props.fallbackToAvailableAssistants || false,
52
+ autoRestoreLastSession: props.autoRestoreLastSession || false,
53
+ });
54
+ });
55
+ const unionStore = useUnionStoreSolid(store(), useStore);
56
+ // 初始化标志
57
+ let initialized = false;
58
+ onMount(() => {
59
+ if (initialized) {
60
+ return;
61
+ }
62
+ initialized = true;
63
+ unionStore.initClient().catch((err) => {
64
+ console.error(err);
65
+ if (props.onInitError) {
66
+ props.onInitError(err, unionStore.currentAgent());
67
+ }
68
+ });
69
+ });
70
+ // 使用 createComponent 创建 Provider 组件
71
+ return createComponent(ChatContext.Provider, {
72
+ value: unionStore,
73
+ get children() {
74
+ return props.children;
75
+ },
76
+ });
77
+ };
@@ -0,0 +1 @@
1
+ export * from "./ChatContext.js";
@@ -0,0 +1 @@
1
+ export * from "./ChatContext.js";
@@ -1,5 +1,4 @@
1
1
  import { z, ZodRawShape } from "zod";
2
- import { Action, Parameter } from "./copilotkit-actions.js";
3
2
  import { Message } from "@langchain/langgraph-sdk";
4
3
  import { ToolRenderData } from "./ToolUI.js";
5
4
  import { HumanInTheLoopDecision, InterruptResponse as HumanInTheLoopResponse } from "../humanInTheLoop.js";
@@ -33,16 +32,8 @@ export declare const createTool: <Args extends ZodRawShape>(tool: UnionTool<Args
33
32
  * create Type Safe Tool with zod and UI Render Feature
34
33
  */
35
34
  export declare const createUITool: <Args extends ZodRawShape, Child extends Object = {}>(tool: UnionTool<Args, Child>) => UnionTool<Args, Child>;
36
- /**
37
- * 提供一种兼容 copilotkit 的定义方式,简化定义形式
38
- * 来自 copilotkit 的 frontend action
39
- */
40
- export declare const createFETool: <const T extends Parameter[], Args extends ZodRawShape, Child extends Object = {}>(tool: Action<T> & {
41
- allowAgent?: string[];
42
- allowGraph?: string[];
43
- render?: (tool: ToolRenderData<any, any>) => Child;
44
- onlyRender?: boolean;
45
- }) => UnionTool<Args>;
35
+ export declare const createRenderUITool: <Args extends ZodRawShape, Child extends Object = {}>(tool: UnionTool<Args, Child>) => UnionTool<Args, Child>;
36
+ export declare const createInteractiveUITool: <Args extends ZodRawShape, Child extends Object = {}>(tool: UnionTool<Args, Child>) => UnionTool<Args, Child>;
46
37
  export declare const createJSONDefineTool: <Args extends ZodRawShape>(tool: UnionTool<Args>) => {
47
38
  name: string;
48
39
  description: string;
@@ -150,31 +141,3 @@ export declare const createJSONDefineTool: <Args extends ZodRawShape>(tool: Unio
150
141
  } | undefined;
151
142
  });
152
143
  };
153
- export declare const createMCPTool: <Args extends ZodRawShape>(tool: UnionTool<Args>) => (string | Args | ((args: z.infer<z.ZodObject<Args>>) => Promise<{
154
- content: {
155
- type: string;
156
- text: string;
157
- }[];
158
- isError?: undefined;
159
- } | {
160
- content: HumanInTheLoopDecision | HumanInTheLoopResponse | {
161
- type: "text";
162
- text: string;
163
- }[] | undefined;
164
- isError?: undefined;
165
- } | {
166
- content: {
167
- type: string;
168
- text: string;
169
- }[];
170
- isError: boolean;
171
- }>))[];
172
- /**
173
- * @deprecated Use createUITool instead
174
- */
175
- export declare const createToolUI: <const T extends Parameter[], Args extends ZodRawShape, Child extends Object = {}>(tool: Action<T> & {
176
- allowAgent?: string[];
177
- allowGraph?: string[];
178
- render?: (tool: ToolRenderData<any, any>) => Child;
179
- onlyRender?: boolean;
180
- }) => UnionTool<Args>;
@@ -1,6 +1,6 @@
1
- import { actionParametersToJsonSchema, convertJsonSchemaToZodRawShape } from "./utils.js";
2
1
  import { z } from "zod";
3
2
  import { zodToJsonSchema } from "zod-to-json-schema";
3
+ import { ToolManager } from "../ToolManager.js";
4
4
  /** 用于格式校验 */
5
5
  export const createTool = (tool) => {
6
6
  return tool;
@@ -30,33 +30,28 @@ export const createUITool = (tool) => {
30
30
  execute,
31
31
  };
32
32
  };
33
- /**
34
- * 提供一种兼容 copilotkit 的定义方式,简化定义形式
35
- * 来自 copilotkit 的 frontend action
36
- */
37
- export const createFETool = (tool) => {
38
- return {
39
- render: tool.render,
40
- onlyRender: tool.onlyRender,
41
- name: tool.name,
42
- description: tool.description || "",
43
- parameters: convertJsonSchemaToZodRawShape(actionParametersToJsonSchema(tool.parameters || [])),
44
- returnDirect: tool.returnDirect,
45
- callbackMessage: tool.callbackMessage,
46
- allowAgent: tool.allowAgent,
47
- allowGraph: tool.allowGraph,
48
- async execute(args, context) {
33
+ export const createRenderUITool = createUITool;
34
+ export const createInteractiveUITool = (tool) => {
35
+ const execute = tool.execute ||
36
+ (async (args, context) => {
49
37
  try {
50
38
  const result = await tool.handler?.(args, context);
51
39
  if (typeof result === "string") {
52
40
  return [{ type: "text", text: result }];
53
41
  }
42
+ else if (result.decisions) {
43
+ return result;
44
+ }
54
45
  return [{ type: "text", text: JSON.stringify(result) }];
55
46
  }
56
47
  catch (error) {
57
48
  return [{ type: "text", text: `Error: ${error}` }];
58
49
  }
59
- },
50
+ });
51
+ return {
52
+ ...tool,
53
+ handler: ToolManager.waitForUIDone,
54
+ execute,
60
55
  };
61
56
  };
62
57
  ///======= UnionTool 到 各种工具的辅助函数
@@ -67,28 +62,3 @@ export const createJSONDefineTool = (tool) => {
67
62
  parameters: tool.isPureParams ? tool.parameters : zodToJsonSchema(z.object(tool.parameters)),
68
63
  };
69
64
  };
70
- export const createMCPTool = (tool) => {
71
- return [
72
- tool.name,
73
- tool.description,
74
- tool.parameters,
75
- async (args) => {
76
- try {
77
- const result = await tool.execute?.(args);
78
- if (typeof result === "string") {
79
- return { content: [{ type: "text", text: result }] };
80
- }
81
- return {
82
- content: result,
83
- };
84
- }
85
- catch (error) {
86
- return { content: [{ type: "text", text: `Error: ${error}` }], isError: true };
87
- }
88
- },
89
- ];
90
- };
91
- /**
92
- * @deprecated Use createUITool instead
93
- */
94
- export const createToolUI = createFETool;
@@ -100,12 +100,14 @@ export const createChatStore = (initClientName, config, context = {}) => {
100
100
  await historyManager.init(currentAgent.get(), { fallbackToAvailableAssistants: context.fallbackToAvailableAssistants });
101
101
  history.set(historyManager);
102
102
  // 同步远程会话列表
103
- await refreshSessionList();
104
103
  // 根据配置决定初始化行为
105
- const syncedSessions = sessions.get();
106
- if (context.autoRestoreLastSession && syncedSessions.length > 0) {
107
- // 自动激活最近的历史会话
108
- await activateSession(syncedSessions[0].sessionId);
104
+ if (context.autoRestoreLastSession) {
105
+ await refreshSessionList();
106
+ if (sessions.get().length > 0) {
107
+ const syncedSessions = sessions.get();
108
+ // 自动激活最近的历史会话
109
+ await activateSession(syncedSessions[0].sessionId);
110
+ }
109
111
  }
110
112
  else {
111
113
  // 创建新会话
@@ -118,7 +120,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
118
120
  if (!historyManager)
119
121
  return;
120
122
  try {
121
- const syncedSessions = await historyManager.syncFromRemote({ limit: 100 });
123
+ const syncedSessions = await historyManager.syncFromRemote({ limit: 10 });
122
124
  sessions.set(syncedSessions);
123
125
  historyList.set(syncedSessions.filter((s) => s.thread).map((s) => s.thread));
124
126
  }
@@ -199,6 +201,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
199
201
  interruptData.set(null);
200
202
  isInterrupted.set(false);
201
203
  }
204
+ updateUI(newClient);
202
205
  };
203
206
  newClient.on("start", onStart);
204
207
  newClient.on("thread", onThread);
@@ -58,14 +58,7 @@ export const useChatProvider = (props) => {
58
58
  provide(ChatContextKey, unionStore);
59
59
  // 初始化客户端
60
60
  onMounted(() => {
61
- unionStore
62
- .initClient()
63
- .then(() => {
64
- if (unionStore.showHistory) {
65
- unionStore.refreshHistoryList();
66
- }
67
- })
68
- .catch((err) => {
61
+ unionStore.initClient().catch((err) => {
69
62
  console.error(err);
70
63
  if (props.onInitError) {
71
64
  props.onInitError(err, unionStore.currentAgent.value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langgraph-js/sdk",
3
- "version": "4.2.0",
3
+ "version": "4.3.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",
@@ -17,6 +17,10 @@
17
17
  "import": "./dist/vue/index.js",
18
18
  "types": "./dist/vue/index.d.ts"
19
19
  },
20
+ "./solid": {
21
+ "import": "./dist/solid/index.js",
22
+ "types": "./dist/solid/index.d.ts"
23
+ },
20
24
  ".": {
21
25
  "import": "./dist/index.js",
22
26
  "types": "./dist/index.d.ts"
@@ -31,7 +35,8 @@
31
35
  "agents",
32
36
  "langchain",
33
37
  "react",
34
- "vue"
38
+ "vue",
39
+ "solid-js"
35
40
  ],
36
41
  "author": "LangGraph Team",
37
42
  "license": "Apache-2.0",
@@ -56,8 +61,10 @@
56
61
  },
57
62
  "peerDependencies": {
58
63
  "@nanostores/react": "^1.0.0",
64
+ "@nanostores/solid": "^1.0.0",
59
65
  "@nanostores/vue": "^1.0.0",
60
66
  "react": "^19||^18",
67
+ "solid-js": "^1.0.0",
61
68
  "vue": "^3.0.0"
62
69
  },
63
70
  "peerDependenciesMeta": {
@@ -67,6 +74,12 @@
67
74
  "@nanostores/vue": {
68
75
  "optional": true
69
76
  },
77
+ "@nanostores/solid": {
78
+ "optional": true
79
+ },
80
+ "solid-js": {
81
+ "optional": true
82
+ },
70
83
  "react": {
71
84
  "optional": true
72
85
  },
package/src/History.ts CHANGED
@@ -255,7 +255,7 @@ export class History {
255
255
  }
256
256
 
257
257
  const threads = await this.listRemoteSessions({
258
- limit: options.limit || 100,
258
+ limit: options.limit || 10,
259
259
  sortBy: "updated_at",
260
260
  sortOrder: "desc",
261
261
  });
@@ -91,19 +91,12 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
91
91
  }
92
92
  initializedRef.current = true;
93
93
 
94
- unionStore
95
- .initClient()
96
- .then((res) => {
97
- if (unionStore.showHistory) {
98
- unionStore.refreshHistoryList();
99
- }
100
- })
101
- .catch((err) => {
102
- console.error(err);
103
- if (onInitErrorRef.current) {
104
- onInitErrorRef.current(err, unionStore.currentAgent);
105
- }
106
- });
94
+ unionStore.initClient().catch((err) => {
95
+ console.error(err);
96
+ if (onInitErrorRef.current) {
97
+ onInitErrorRef.current(err, unionStore.currentAgent);
98
+ }
99
+ });
107
100
  }, [unionStore]);
108
101
 
109
102
  return createElement(ChatContext.Provider, { value: unionStore }, children);
@@ -0,0 +1,119 @@
1
+ import { createContext, useContext, createMemo, onMount, type JSX, type Component, createComponent, Accessor } from "solid-js";
2
+ import { createChatStore, UnionStore } from "../ui-store/index.js";
3
+ import { useStore } from "@nanostores/solid";
4
+ import { ILangGraphClient } from "@langgraph-js/pure-graph/dist/types.js";
5
+ import { PreinitializedWritableAtom, StoreValue } from "nanostores";
6
+
7
+ const ChatContext = createContext<UnionStoreSolid<ReturnType<typeof createChatStore>> | undefined>(undefined);
8
+
9
+ export const useChat = () => {
10
+ const context = useContext(ChatContext);
11
+ if (!context) {
12
+ throw new Error("useChat must be used within a ChatProvider");
13
+ }
14
+ return context;
15
+ };
16
+
17
+ interface ChatProviderProps {
18
+ children: JSX.Element;
19
+ defaultAgent?: string;
20
+ apiUrl?: string;
21
+ defaultHeaders?: Record<string, string>;
22
+ withCredentials?: boolean;
23
+ showHistory?: boolean;
24
+ showGraph?: boolean;
25
+ fallbackToAvailableAssistants?: boolean;
26
+ /** 初始化时是否自动激活最近的历史会话(默认 false,创建新会话) */
27
+ autoRestoreLastSession?: boolean;
28
+ onInitError?: (error: any, currentAgent: string) => void;
29
+ client?: ILangGraphClient;
30
+ legacyMode?: boolean;
31
+ }
32
+ /**
33
+ * @zh UnionStore 类型用于合并 store 的 data 和 mutations,使其可以直接访问。
34
+ * @en The UnionStore type is used to merge the data and mutations of a store, allowing direct access.
35
+ */
36
+ export type UnionStoreSolid<T extends { data: Record<string, PreinitializedWritableAtom<any>>; mutations: Record<string, any> }> = {
37
+ [k in keyof T["data"]]: Accessor<StoreValue<T["data"][k]>>;
38
+ } & T["mutations"];
39
+
40
+ /**
41
+ * @zh useUnionStore Hook 用于将 nanostores 的 store 结构转换为更易于在 UI 组件中使用的扁平结构。
42
+ * @en The useUnionStore Hook is used to transform the nanostores store structure into a flatter structure that is easier to use in UI components.
43
+ */
44
+ export const useUnionStoreSolid = <T extends { data: Record<string, any>; mutations: Record<string, any> }>(
45
+ store: T,
46
+ useStore: (store: PreinitializedWritableAtom<any>) => Accessor<any>
47
+ ): UnionStoreSolid<T> => {
48
+ const data: any = Object.fromEntries(
49
+ Object.entries(store.data as any).map(([key, value]) => {
50
+ return [key, useStore(value as any)];
51
+ })
52
+ );
53
+
54
+ return {
55
+ ...data,
56
+ ...store.mutations,
57
+ };
58
+ };
59
+
60
+ export const ChatProvider = (props: ChatProviderProps) => {
61
+ // 使用 createMemo 稳定 defaultHeaders 的引用
62
+ const stableHeaders = createMemo(() => props.defaultHeaders || {});
63
+
64
+ // 使用 createMemo 创建 fetch 函数
65
+ const F = createMemo(() =>
66
+ props.withCredentials
67
+ ? (url: string, options: RequestInit) => {
68
+ options.credentials = "include";
69
+ return fetch(url, options);
70
+ }
71
+ : fetch
72
+ );
73
+
74
+ const store = createMemo(() => {
75
+ const config = {
76
+ apiUrl: props.apiUrl || "http://localhost:8123",
77
+ defaultHeaders: stableHeaders(),
78
+ callerOptions: {
79
+ fetch: F(),
80
+ maxRetries: 1,
81
+ },
82
+ legacyMode: props.legacyMode || false,
83
+ };
84
+ /** @ts-ignore */
85
+ if (props.client) config.client = props.client;
86
+ return createChatStore(props.defaultAgent || "", config, {
87
+ showHistory: props.showHistory || false,
88
+ showGraph: props.showGraph || false,
89
+ fallbackToAvailableAssistants: props.fallbackToAvailableAssistants || false,
90
+ autoRestoreLastSession: props.autoRestoreLastSession || false,
91
+ });
92
+ });
93
+
94
+ const unionStore = useUnionStoreSolid(store(), useStore);
95
+
96
+ // 初始化标志
97
+ let initialized = false;
98
+
99
+ onMount(() => {
100
+ if (initialized) {
101
+ return;
102
+ }
103
+ initialized = true;
104
+ unionStore.initClient().catch((err) => {
105
+ console.error(err);
106
+ if (props.onInitError) {
107
+ props.onInitError(err, unionStore.currentAgent());
108
+ }
109
+ });
110
+ });
111
+
112
+ // 使用 createComponent 创建 Provider 组件
113
+ return createComponent(ChatContext.Provider, {
114
+ value: unionStore,
115
+ get children() {
116
+ return props.children;
117
+ },
118
+ });
119
+ };
@@ -0,0 +1 @@
1
+ export * from "./ChatContext.js";
@@ -5,6 +5,7 @@ import { zodToJsonSchema } from "zod-to-json-schema";
5
5
  import { Message } from "@langchain/langgraph-sdk";
6
6
  import { ToolRenderData } from "./ToolUI.js";
7
7
  import { HumanInTheLoopDecision, InterruptResponse as HumanInTheLoopResponse } from "../humanInTheLoop.js";
8
+ import { ToolManager } from "../ToolManager.js";
8
9
 
9
10
  export interface UnionTool<Args extends ZodRawShape, Child extends Object = Object, ResponseType = any> {
10
11
  name: string;
@@ -58,40 +59,27 @@ export const createUITool = <Args extends ZodRawShape, Child extends Object = {}
58
59
  execute,
59
60
  };
60
61
  };
61
-
62
- /**
63
- * 提供一种兼容 copilotkit 的定义方式,简化定义形式
64
- * 来自 copilotkit 的 frontend action
65
- */
66
- export const createFETool = <const T extends Parameter[], Args extends ZodRawShape, Child extends Object = {}>(
67
- tool: Action<T> & {
68
- allowAgent?: string[];
69
- allowGraph?: string[];
70
- render?: (tool: ToolRenderData<any, any>) => Child;
71
- onlyRender?: boolean;
72
- }
73
- ): UnionTool<Args> => {
74
- return {
75
- render: tool.render,
76
- onlyRender: tool.onlyRender,
77
- name: tool.name,
78
- description: tool.description || "",
79
- parameters: convertJsonSchemaToZodRawShape(actionParametersToJsonSchema(tool.parameters || [])) as any,
80
- returnDirect: tool.returnDirect,
81
- callbackMessage: tool.callbackMessage,
82
- allowAgent: tool.allowAgent,
83
- allowGraph: tool.allowGraph,
84
- async execute(args, context) {
62
+ export const createRenderUITool = createUITool;
63
+ export const createInteractiveUITool = <Args extends ZodRawShape, Child extends Object = {}>(tool: UnionTool<Args, Child>): UnionTool<Args, Child> => {
64
+ const execute =
65
+ tool.execute ||
66
+ (async (args, context) => {
85
67
  try {
86
- const result = await tool.handler?.(args as any, context);
68
+ const result = await tool.handler?.(args, context);
87
69
  if (typeof result === "string") {
88
70
  return [{ type: "text", text: result }];
71
+ } else if (result.decisions) {
72
+ return result;
89
73
  }
90
74
  return [{ type: "text", text: JSON.stringify(result) }];
91
75
  } catch (error) {
92
76
  return [{ type: "text", text: `Error: ${error}` }];
93
77
  }
94
- },
78
+ });
79
+ return {
80
+ ...tool,
81
+ handler: ToolManager.waitForUIDone,
82
+ execute,
95
83
  };
96
84
  };
97
85
 
@@ -103,29 +91,3 @@ export const createJSONDefineTool = <Args extends ZodRawShape>(tool: UnionTool<A
103
91
  parameters: tool.isPureParams ? tool.parameters : zodToJsonSchema(z.object(tool.parameters)),
104
92
  };
105
93
  };
106
-
107
- export const createMCPTool = <Args extends ZodRawShape>(tool: UnionTool<Args>) => {
108
- return [
109
- tool.name,
110
- tool.description,
111
- tool.parameters,
112
- async (args: z.infer<z.ZodObject<Args>>) => {
113
- try {
114
- const result = await tool.execute?.(args);
115
- if (typeof result === "string") {
116
- return { content: [{ type: "text", text: result }] };
117
- }
118
- return {
119
- content: result,
120
- };
121
- } catch (error) {
122
- return { content: [{ type: "text", text: `Error: ${error}` }], isError: true };
123
- }
124
- },
125
- ];
126
- };
127
-
128
- /**
129
- * @deprecated Use createUITool instead
130
- */
131
- export const createToolUI = createFETool;
@@ -134,13 +134,15 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
134
134
  history.set(historyManager);
135
135
 
136
136
  // 同步远程会话列表
137
- await refreshSessionList();
138
137
 
139
138
  // 根据配置决定初始化行为
140
- const syncedSessions = sessions.get();
141
- if (context.autoRestoreLastSession && syncedSessions.length > 0) {
142
- // 自动激活最近的历史会话
143
- await activateSession(syncedSessions[0].sessionId);
139
+ if (context.autoRestoreLastSession) {
140
+ await refreshSessionList();
141
+ if (sessions.get().length > 0) {
142
+ const syncedSessions = sessions.get();
143
+ // 自动激活最近的历史会话
144
+ await activateSession(syncedSessions[0].sessionId);
145
+ }
144
146
  } else {
145
147
  // 创建新会话
146
148
  await createNewSession();
@@ -154,7 +156,7 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
154
156
  if (!historyManager) return;
155
157
 
156
158
  try {
157
- const syncedSessions = await historyManager.syncFromRemote({ limit: 100 });
159
+ const syncedSessions = await historyManager.syncFromRemote({ limit: 10 });
158
160
  sessions.set(syncedSessions);
159
161
  historyList.set(syncedSessions.filter((s) => s.thread).map((s) => s.thread!));
160
162
  } catch (error) {
@@ -243,6 +245,7 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
243
245
  interruptData.set(null);
244
246
  isInterrupted.set(false);
245
247
  }
248
+ updateUI(newClient);
246
249
  };
247
250
 
248
251
  newClient.on("start", onStart);
@@ -101,19 +101,12 @@ export const useChatProvider = (props: ChatProviderProps) => {
101
101
 
102
102
  // 初始化客户端
103
103
  onMounted(() => {
104
- unionStore
105
- .initClient()
106
- .then(() => {
107
- if (unionStore.showHistory) {
108
- unionStore.refreshHistoryList();
109
- }
110
- })
111
- .catch((err) => {
112
- console.error(err);
113
- if (props.onInitError) {
114
- props.onInitError(err, unionStore.currentAgent.value);
115
- }
116
- });
104
+ unionStore.initClient().catch((err) => {
105
+ console.error(err);
106
+ if (props.onInitError) {
107
+ props.onInitError(err, unionStore.currentAgent.value);
108
+ }
109
+ });
117
110
  });
118
111
 
119
112
  return {