@langgraph-js/sdk 4.1.1 → 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 +1 -1
- package/dist/LangGraphClient.js +3 -0
- 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 +9 -6
- package/dist/vue/ChatContext.js +1 -8
- package/package.json +15 -2
- package/src/History.ts +1 -1
- package/src/LangGraphClient.ts +6 -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 +9 -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
|
});
|
package/dist/LangGraphClient.js
CHANGED
|
@@ -140,6 +140,9 @@ export class LangGraphClient extends EventEmitter {
|
|
|
140
140
|
messages: this.messageProcessor.getGraphMessages(),
|
|
141
141
|
},
|
|
142
142
|
});
|
|
143
|
+
if (this.currentThread?.status === "interrupted") {
|
|
144
|
+
this.sendMessage([], { joinRunId: this.currentThread.thread_id });
|
|
145
|
+
}
|
|
143
146
|
return this.currentThread;
|
|
144
147
|
}
|
|
145
148
|
// 从历史中恢复时,应该恢复流式状态
|
|
@@ -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);
|
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.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
package/src/LangGraphClient.ts
CHANGED
|
@@ -236,8 +236,10 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
236
236
|
*/
|
|
237
237
|
async resetThread(agent: string, threadId: string) {
|
|
238
238
|
await this.initAssistant(agent);
|
|
239
|
+
|
|
239
240
|
this.currentThread = await this.threads.get(threadId);
|
|
240
241
|
this.graphState = (this.currentThread as any).values;
|
|
242
|
+
|
|
241
243
|
const graphMessages = this.graphState?.messages || [];
|
|
242
244
|
this.messageProcessor.setGraphMessages(graphMessages);
|
|
243
245
|
this.emit("value", {
|
|
@@ -246,6 +248,10 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
246
248
|
messages: this.messageProcessor.getGraphMessages(),
|
|
247
249
|
},
|
|
248
250
|
});
|
|
251
|
+
if (this.currentThread?.status === "interrupted") {
|
|
252
|
+
this.sendMessage([], { joinRunId: this.currentThread.thread_id });
|
|
253
|
+
}
|
|
254
|
+
|
|
249
255
|
return this.currentThread;
|
|
250
256
|
}
|
|
251
257
|
// 从历史中恢复时,应该恢复流式状态
|
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);
|
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 {
|