@langgraph-js/sdk 4.2.0 → 4.3.1
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 +1 -1
- package/dist/react/ChatContext.js +1 -8
- package/dist/solid/ChatContext.d.ts +100 -0
- package/dist/solid/ChatContext.js +77 -0
- package/dist/solid/index.d.ts +1 -0
- package/dist/solid/index.js +1 -0
- package/dist/tool/createTool.d.ts +2 -39
- package/dist/tool/createTool.js +13 -43
- package/dist/ui-store/createChatStore.js +10 -6
- package/dist/vue/ChatContext.js +1 -8
- package/package.json +15 -2
- package/src/History.ts +1 -1
- package/src/artifacts/README.md +71 -0
- package/src/react/ChatContext.ts +6 -13
- package/src/solid/ChatContext.ts +119 -0
- package/src/solid/index.ts +1 -0
- package/src/tool/createTool.ts +14 -52
- package/src/ui-store/createChatStore.ts +10 -6
- package/src/vue/ChatContext.ts +6 -13
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 ||
|
|
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
|
-
|
|
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>;
|
package/dist/tool/createTool.js
CHANGED
|
@@ -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
|
-
|
|
35
|
-
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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:
|
|
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);
|
|
@@ -274,6 +277,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
274
277
|
return;
|
|
275
278
|
inChatError.set(null);
|
|
276
279
|
try {
|
|
280
|
+
loading.set(true);
|
|
277
281
|
await c.sendMessage(message || userInput.get(), extraData);
|
|
278
282
|
}
|
|
279
283
|
catch (e) {
|
package/dist/vue/ChatContext.js
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "4.3.1",
|
|
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
|
@@ -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/`)。
|
package/src/react/ChatContext.ts
CHANGED
|
@@ -91,19 +91,12 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
91
91
|
}
|
|
92
92
|
initializedRef.current = true;
|
|
93
93
|
|
|
94
|
-
unionStore
|
|
95
|
-
.
|
|
96
|
-
.
|
|
97
|
-
|
|
98
|
-
|
|
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";
|
package/src/tool/createTool.ts
CHANGED
|
@@ -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
|
-
|
|
64
|
-
|
|
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
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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:
|
|
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);
|
|
@@ -331,6 +334,7 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
331
334
|
|
|
332
335
|
inChatError.set(null);
|
|
333
336
|
try {
|
|
337
|
+
loading.set(true);
|
|
334
338
|
await c.sendMessage(message || userInput.get(), extraData);
|
|
335
339
|
} catch (e) {
|
|
336
340
|
const isThreadRunning = (e as Error).message.includes("422");
|
package/src/vue/ChatContext.ts
CHANGED
|
@@ -101,19 +101,12 @@ export const useChatProvider = (props: ChatProviderProps) => {
|
|
|
101
101
|
|
|
102
102
|
// 初始化客户端
|
|
103
103
|
onMounted(() => {
|
|
104
|
-
unionStore
|
|
105
|
-
.
|
|
106
|
-
.
|
|
107
|
-
|
|
108
|
-
|
|
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 {
|