@langgraph-js/sdk 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +0 -0
- package/README.md +163 -0
- package/dist/LangGraphClient.js +392 -0
- package/dist/SpendTime.js +27 -0
- package/dist/ToolManager.js +91 -0
- package/dist/index.js +5 -0
- package/dist/tool/copilotkit-actions.js +1 -0
- package/dist/tool/createTool.js +60 -0
- package/dist/tool/index.js +2 -0
- package/dist/tool/utils.js +119 -0
- package/dist/ui-store/UnionStore.js +9 -0
- package/dist/ui-store/createChatStore.js +137 -0
- package/dist/ui-store/index.js +2 -0
- package/index.html +12 -0
- package/package.json +35 -7
- package/src/LangGraphClient.ts +461 -0
- package/src/SpendTime.ts +29 -0
- package/src/ToolManager.ts +100 -0
- package/src/index.ts +5 -0
- package/src/tool/copilotkit-actions.ts +72 -0
- package/src/tool/createTool.ts +78 -0
- package/src/tool/index.ts +2 -0
- package/src/tool/utils.ts +158 -0
- package/src/ui-store/UnionStore.ts +20 -0
- package/src/ui-store/createChatStore.ts +153 -0
- package/src/ui-store/index.ts +2 -0
- package/test/testResponse.json +5418 -0
- package/tsconfig.json +112 -0
- package/ui/index.ts +182 -0
- package/ui/tool.ts +55 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { actionParametersToJsonSchema, convertJsonSchemaToZodRawShape } from "./utils";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
4
|
+
/** 用于格式校验 */
|
|
5
|
+
export const createTool = (tool) => {
|
|
6
|
+
return tool;
|
|
7
|
+
};
|
|
8
|
+
/** 提供一种兼容 copilotkit 的定义方式,简化定义形式
|
|
9
|
+
* 来自 copilotkit 的 frontend action
|
|
10
|
+
*/
|
|
11
|
+
export const createFETool = (tool) => {
|
|
12
|
+
return {
|
|
13
|
+
name: tool.name,
|
|
14
|
+
description: tool.description || "",
|
|
15
|
+
parameters: convertJsonSchemaToZodRawShape(actionParametersToJsonSchema(tool.parameters || [])),
|
|
16
|
+
returnDirect: tool.returnDirect,
|
|
17
|
+
callbackMessage: tool.callbackMessage,
|
|
18
|
+
async execute(args, context) {
|
|
19
|
+
try {
|
|
20
|
+
const result = await tool.handler?.(args, context);
|
|
21
|
+
if (typeof result === "string") {
|
|
22
|
+
return [{ type: "text", text: result }];
|
|
23
|
+
}
|
|
24
|
+
return [{ type: "text", text: JSON.stringify(result) }];
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
return [{ type: "text", text: `Error: ${error}` }];
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
///======= UnionTool 到 各种工具的辅助函数
|
|
33
|
+
export const createJSONDefineTool = (tool) => {
|
|
34
|
+
return {
|
|
35
|
+
name: tool.name,
|
|
36
|
+
description: tool.description,
|
|
37
|
+
parameters: zodToJsonSchema(z.object(tool.parameters)),
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export const createMCPTool = (tool) => {
|
|
41
|
+
return [
|
|
42
|
+
tool.name,
|
|
43
|
+
tool.description,
|
|
44
|
+
tool.parameters,
|
|
45
|
+
async (args) => {
|
|
46
|
+
try {
|
|
47
|
+
const result = await tool.execute(args);
|
|
48
|
+
if (typeof result === "string") {
|
|
49
|
+
return { content: [{ type: "text", text: result }] };
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
content: result,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return { content: [{ type: "text", text: `Error: ${error}` }], isError: true };
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* copy and modify from copilotkit
|
|
3
|
+
* https://github.com/copilotkit/copilotkit
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
export function actionParametersToJsonSchema(actionParameters) {
|
|
9
|
+
// Create the parameters object based on the argumentAnnotations
|
|
10
|
+
let parameters = {};
|
|
11
|
+
for (let parameter of actionParameters || []) {
|
|
12
|
+
parameters[parameter.name] = convertAttribute(parameter);
|
|
13
|
+
}
|
|
14
|
+
let requiredParameterNames = [];
|
|
15
|
+
for (let arg of actionParameters || []) {
|
|
16
|
+
if (arg.required !== false) {
|
|
17
|
+
requiredParameterNames.push(arg.name);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Create the ChatCompletionFunctions object
|
|
21
|
+
return {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: parameters,
|
|
24
|
+
required: requiredParameterNames,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function convertAttribute(attribute) {
|
|
28
|
+
switch (attribute.type) {
|
|
29
|
+
case "string":
|
|
30
|
+
return {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: attribute.description,
|
|
33
|
+
...(attribute.enum && { enum: attribute.enum }),
|
|
34
|
+
};
|
|
35
|
+
case "number":
|
|
36
|
+
case "boolean":
|
|
37
|
+
return {
|
|
38
|
+
type: attribute.type,
|
|
39
|
+
description: attribute.description,
|
|
40
|
+
};
|
|
41
|
+
case "object":
|
|
42
|
+
case "object[]":
|
|
43
|
+
const properties = attribute.attributes?.reduce((acc, attr) => {
|
|
44
|
+
acc[attr.name] = convertAttribute(attr);
|
|
45
|
+
return acc;
|
|
46
|
+
}, {});
|
|
47
|
+
const required = attribute.attributes?.filter((attr) => attr.required !== false).map((attr) => attr.name);
|
|
48
|
+
if (attribute.type === "object[]") {
|
|
49
|
+
return {
|
|
50
|
+
type: "array",
|
|
51
|
+
items: {
|
|
52
|
+
type: "object",
|
|
53
|
+
...(properties && { properties }),
|
|
54
|
+
...(required && required.length > 0 && { required }),
|
|
55
|
+
},
|
|
56
|
+
description: attribute.description,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
type: "object",
|
|
61
|
+
description: attribute.description,
|
|
62
|
+
...(properties && { properties }),
|
|
63
|
+
...(required && required.length > 0 && { required }),
|
|
64
|
+
};
|
|
65
|
+
default:
|
|
66
|
+
// Handle arrays of primitive types and undefined attribute.type
|
|
67
|
+
if (attribute.type?.endsWith("[]")) {
|
|
68
|
+
const itemType = attribute.type.slice(0, -2);
|
|
69
|
+
return {
|
|
70
|
+
type: "array",
|
|
71
|
+
items: { type: itemType },
|
|
72
|
+
description: attribute.description,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Fallback for undefined type or any other unexpected type
|
|
76
|
+
return {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: attribute.description,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function convertJsonSchemaToZodRawShape(jsonSchema) {
|
|
83
|
+
const spec = {};
|
|
84
|
+
for (const [key, value] of Object.entries(jsonSchema.properties)) {
|
|
85
|
+
spec[key] = convertJsonSchemaToZodSchema(value, jsonSchema.required ? jsonSchema.required.includes(key) : false);
|
|
86
|
+
}
|
|
87
|
+
return spec;
|
|
88
|
+
}
|
|
89
|
+
export function convertJsonSchemaToZodSchema(jsonSchema, required) {
|
|
90
|
+
if (jsonSchema.type === "object") {
|
|
91
|
+
const spec = {};
|
|
92
|
+
if (!jsonSchema.properties || !Object.keys(jsonSchema.properties).length) {
|
|
93
|
+
return !required ? z.object(spec).optional() : z.object(spec);
|
|
94
|
+
}
|
|
95
|
+
for (const [key, value] of Object.entries(jsonSchema.properties)) {
|
|
96
|
+
spec[key] = convertJsonSchemaToZodSchema(value, jsonSchema.required ? jsonSchema.required.includes(key) : false);
|
|
97
|
+
}
|
|
98
|
+
let schema = z.object(spec).describe(jsonSchema.description);
|
|
99
|
+
return required ? schema : schema.optional();
|
|
100
|
+
}
|
|
101
|
+
else if (jsonSchema.type === "string") {
|
|
102
|
+
let schema = z.string().describe(jsonSchema.description);
|
|
103
|
+
return required ? schema : schema.optional();
|
|
104
|
+
}
|
|
105
|
+
else if (jsonSchema.type === "number") {
|
|
106
|
+
let schema = z.number().describe(jsonSchema.description);
|
|
107
|
+
return required ? schema : schema.optional();
|
|
108
|
+
}
|
|
109
|
+
else if (jsonSchema.type === "boolean") {
|
|
110
|
+
let schema = z.boolean().describe(jsonSchema.description);
|
|
111
|
+
return required ? schema : schema.optional();
|
|
112
|
+
}
|
|
113
|
+
else if (jsonSchema.type === "array") {
|
|
114
|
+
let itemSchema = convertJsonSchemaToZodSchema(jsonSchema.items, true);
|
|
115
|
+
let schema = z.array(itemSchema).describe(jsonSchema.description);
|
|
116
|
+
return required ? schema : schema.optional();
|
|
117
|
+
}
|
|
118
|
+
throw new Error("Invalid JSON schema");
|
|
119
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { atom } from "nanostores";
|
|
2
|
+
import { LangGraphClient } from "../LangGraphClient";
|
|
3
|
+
export const formatTime = (date) => {
|
|
4
|
+
return date.toLocaleTimeString("en-US");
|
|
5
|
+
};
|
|
6
|
+
export const formatTokens = (tokens) => {
|
|
7
|
+
return tokens.toLocaleString("en");
|
|
8
|
+
};
|
|
9
|
+
export const getMessageContent = (content) => {
|
|
10
|
+
if (typeof content === "string")
|
|
11
|
+
return content;
|
|
12
|
+
if (Array.isArray(content)) {
|
|
13
|
+
return content
|
|
14
|
+
.map((item) => {
|
|
15
|
+
if (typeof item === "string")
|
|
16
|
+
return item;
|
|
17
|
+
if (item.type === "text")
|
|
18
|
+
return item.text;
|
|
19
|
+
if (item.type === "image_url")
|
|
20
|
+
return `[图片]`;
|
|
21
|
+
return JSON.stringify(item);
|
|
22
|
+
})
|
|
23
|
+
.join("");
|
|
24
|
+
}
|
|
25
|
+
return JSON.stringify(content);
|
|
26
|
+
};
|
|
27
|
+
export const createChatStore = (initClientName, config, context = {}) => {
|
|
28
|
+
const client = atom(null);
|
|
29
|
+
const renderMessages = atom([]);
|
|
30
|
+
const userInput = atom("");
|
|
31
|
+
const loading = atom(false);
|
|
32
|
+
const collapsedTools = atom([]);
|
|
33
|
+
const inChatError = atom(null);
|
|
34
|
+
const showHistory = atom(true);
|
|
35
|
+
const currentAgent = atom(initClientName);
|
|
36
|
+
const currentChatId = atom(null);
|
|
37
|
+
const initClient = async () => {
|
|
38
|
+
const newClient = new LangGraphClient(config);
|
|
39
|
+
await newClient.initAssistant(currentAgent.get());
|
|
40
|
+
// 不再需要创建,sendMessage 会自动创建
|
|
41
|
+
// await newClient.createThread();
|
|
42
|
+
newClient.onStreamingUpdate((event) => {
|
|
43
|
+
if (event.type === "thread" || event.type === "done") {
|
|
44
|
+
// console.log(event.data);
|
|
45
|
+
// 创建新会话时,需要自动刷新历史面板
|
|
46
|
+
return refreshHistoryList();
|
|
47
|
+
}
|
|
48
|
+
if (event.type === "error") {
|
|
49
|
+
loading.set(false);
|
|
50
|
+
inChatError.set(event.data?.message || "发生错误");
|
|
51
|
+
}
|
|
52
|
+
console.log(newClient.renderMessage);
|
|
53
|
+
renderMessages.set(newClient.renderMessage);
|
|
54
|
+
});
|
|
55
|
+
context.onInit?.(newClient);
|
|
56
|
+
// newClient.tools.bindTools([fileTool, askUserTool]);
|
|
57
|
+
newClient.graphState = {};
|
|
58
|
+
client.set(newClient);
|
|
59
|
+
};
|
|
60
|
+
const sendMessage = async () => {
|
|
61
|
+
if (!userInput.get().trim() || loading.get() || !client.get())
|
|
62
|
+
return;
|
|
63
|
+
loading.set(true);
|
|
64
|
+
inChatError.set(null);
|
|
65
|
+
await client.get()?.sendMessage(userInput.get());
|
|
66
|
+
userInput.set("");
|
|
67
|
+
loading.set(false);
|
|
68
|
+
};
|
|
69
|
+
const interruptMessage = () => {
|
|
70
|
+
client.get()?.cancelRun();
|
|
71
|
+
};
|
|
72
|
+
const toggleToolCollapse = (toolId) => {
|
|
73
|
+
const prev = collapsedTools.get();
|
|
74
|
+
collapsedTools.set(prev.includes(toolId) ? prev.filter((id) => id !== toolId) : [...prev, toolId]);
|
|
75
|
+
};
|
|
76
|
+
const toggleHistoryVisible = () => {
|
|
77
|
+
showHistory.set(!showHistory.get());
|
|
78
|
+
};
|
|
79
|
+
const historyList = atom([]);
|
|
80
|
+
const refreshHistoryList = async () => {
|
|
81
|
+
if (!client.get())
|
|
82
|
+
return;
|
|
83
|
+
try {
|
|
84
|
+
const response = await client.get()?.listThreads();
|
|
85
|
+
historyList.set(response || []);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
console.error("Failed to fetch threads:", error);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const addToHistory = (thread) => {
|
|
92
|
+
const prev = historyList.get();
|
|
93
|
+
historyList.set([thread, ...prev]);
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
data: {
|
|
97
|
+
client,
|
|
98
|
+
renderMessages,
|
|
99
|
+
userInput,
|
|
100
|
+
loading,
|
|
101
|
+
inChatError,
|
|
102
|
+
currentAgent,
|
|
103
|
+
collapsedTools,
|
|
104
|
+
showHistory,
|
|
105
|
+
historyList,
|
|
106
|
+
currentChatId,
|
|
107
|
+
},
|
|
108
|
+
mutations: {
|
|
109
|
+
initClient,
|
|
110
|
+
sendMessage,
|
|
111
|
+
interruptMessage,
|
|
112
|
+
toggleToolCollapse,
|
|
113
|
+
toggleHistoryVisible,
|
|
114
|
+
refreshHistoryList,
|
|
115
|
+
addToHistory,
|
|
116
|
+
setUserInput(input) {
|
|
117
|
+
userInput.set(input);
|
|
118
|
+
},
|
|
119
|
+
setCurrentAgent(agent) {
|
|
120
|
+
currentAgent.set(agent);
|
|
121
|
+
return initClient().then(() => {
|
|
122
|
+
refreshHistoryList();
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
createNewChat() {
|
|
126
|
+
client.get()?.reset();
|
|
127
|
+
},
|
|
128
|
+
toHistoryChat(thread) {
|
|
129
|
+
client.get()?.resetThread(thread.metadata?.graph_id, thread.thread_id);
|
|
130
|
+
},
|
|
131
|
+
async deleteHistoryChat(thread) {
|
|
132
|
+
await client.get()?.threads.delete(thread.thread_id);
|
|
133
|
+
await refreshHistoryList();
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
};
|
package/index.html
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Document</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="message"></div>
|
|
10
|
+
</body>
|
|
11
|
+
<script type="module" src="/ui/index.ts"></script>
|
|
12
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,16 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langgraph-js/sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "index.
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "The UI SDK for LangGraph - seamlessly integrate your AI agents with frontend interfaces",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"publishConfig": {
|
|
7
8
|
"registry": "https://registry.npmjs.org/",
|
|
8
9
|
"access": "public"
|
|
9
10
|
},
|
|
10
|
-
"keywords": [
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
"keywords": [
|
|
12
|
+
"langgraph",
|
|
13
|
+
"ui",
|
|
14
|
+
"sdk",
|
|
15
|
+
"frontend",
|
|
16
|
+
"ai",
|
|
17
|
+
"agents",
|
|
18
|
+
"langchain",
|
|
19
|
+
"react"
|
|
20
|
+
],
|
|
21
|
+
"author": "LangGraph Team",
|
|
22
|
+
"license": "Apache-2.0",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/KonghaYao/YaoAgent.git"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://langgraph-js.netlify.app",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/KonghaYao/YaoAgent/issues"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@langchain/langgraph-sdk": "^0.0.74",
|
|
33
|
+
"nanostores": "^1.0.1",
|
|
34
|
+
"zod": "^3.24.3",
|
|
35
|
+
"zod-to-json-schema": "^3.24.3"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"vite": "^6.3.4"
|
|
39
|
+
},
|
|
13
40
|
"scripts": {
|
|
14
|
-
"
|
|
41
|
+
"build": "tsc",
|
|
42
|
+
"prepublish": "pnpm build"
|
|
15
43
|
}
|
|
16
44
|
}
|