@ai-zen/agents-sdk 0.2.0-alpha.2 → 0.2.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/README.md +29 -1
- package/dist/capabilities/Capabilities.d.ts +3 -1
- package/dist/capabilities/Capabilities.js +4 -3
- package/dist/capabilities/discovery/skills.d.ts +6 -2
- package/dist/capabilities/discovery/skills.js +12 -8
- package/dist/capabilities/discovery/usertools.d.ts +3 -1
- package/dist/capabilities/discovery/usertools.js +12 -7
- package/dist/capabilities/implements/builtin/exec.js +8 -1
- package/dist/capabilities/implements/builtin/execAsync.d.ts +2 -0
- package/dist/capabilities/implements/builtin/execAsync.js +148 -0
- package/dist/capabilities/implements/builtin/index.d.ts +4 -2
- package/dist/capabilities/implements/builtin/index.js +6 -2
- package/dist/capabilities/implements/builtin/sleep.d.ts +2 -0
- package/dist/capabilities/implements/builtin/sleep.js +41 -0
- package/dist/capabilities/implements/skillTools.js +12 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/plugin/AutoRefreshToolsPlugin.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,7 +77,35 @@ await agent.send("你好");
|
|
|
77
77
|
| `runtime` | ✅ 已实现 — Provider、Capabilities、createAgent、MCP 连接管理、任务迁移 |
|
|
78
78
|
| `plugin` | ✅ 已实现 — AutoMigratePlugin / AutoDraftPlugin / AutoRefreshToolsPlugin |
|
|
79
79
|
| `shared` | ✅ 已实现 — SdkError + 可注入 Logger |
|
|
80
|
-
| 测试 | ✅
|
|
80
|
+
| 测试 | ✅ 359 个测试,45 个文件,全通过(含真实 API 聊天 e2e) |
|
|
81
|
+
|
|
82
|
+
## 内置工具
|
|
83
|
+
|
|
84
|
+
| 工具 | 说明 |
|
|
85
|
+
|------|------|
|
|
86
|
+
| `cwd` | 获取当前工作目录 |
|
|
87
|
+
| `readFile` | 读取文件 |
|
|
88
|
+
| `writeFile` | 写入文件 |
|
|
89
|
+
| `exec` | 执行命令(支持 `timeout` 超时参数) |
|
|
90
|
+
| `exec_async` | 异步执行命令,启动后立即返回,不等待结果 |
|
|
91
|
+
| `mkdir` | 创建目录 |
|
|
92
|
+
| `rm` | 删除文件或目录 |
|
|
93
|
+
| `glob` | 使用 glob 模式扫描查找文件 |
|
|
94
|
+
| `ls` | 列出目录内容 |
|
|
95
|
+
| `exist` | 检查文件或目录是否存在 |
|
|
96
|
+
| `findText` | 在文件中搜索文本或正则 |
|
|
97
|
+
| `downloadFile` | 从 URL 下载文件并保存到本地 |
|
|
98
|
+
| `rename` | 重命名或移动文件/目录 |
|
|
99
|
+
| `copy` | 复制文件或目录 |
|
|
100
|
+
| `batchEdit` | 批量编辑文件文本 |
|
|
101
|
+
| `edit` | 编辑文件中的文本 |
|
|
102
|
+
| `sleep` | 等待指定毫秒数后继续 |
|
|
103
|
+
|
|
104
|
+
条件注入(需配置 `imageModels`):
|
|
105
|
+
|
|
106
|
+
| 工具 | 说明 |
|
|
107
|
+
|------|------|
|
|
108
|
+
| `generateImage` | 根据文字描述生成图片 |
|
|
81
109
|
|
|
82
110
|
## 内置插件
|
|
83
111
|
|
|
@@ -138,12 +138,13 @@ export class Capabilities {
|
|
|
138
138
|
/**
|
|
139
139
|
* 重新执行全局发现(重新扫描文件系统)。
|
|
140
140
|
*/
|
|
141
|
-
refresh() {
|
|
141
|
+
refresh(options) {
|
|
142
|
+
const silent = options?.silent ?? false;
|
|
142
143
|
const provider = this.provider;
|
|
143
144
|
this.builtinInstances = discoverBuiltinTools(provider.config);
|
|
144
|
-
this.userInstances = discoverUserTools(provider.toolsPaths);
|
|
145
|
+
this.userInstances = discoverUserTools(provider.toolsPaths, { silent });
|
|
145
146
|
this.subagentDefs = discoverSubAgents(provider.subAgentsPaths);
|
|
146
|
-
this.skills = discoverSkills(provider.skillsPaths);
|
|
147
|
+
this.skills = discoverSkills(provider.skillsPaths, { silent });
|
|
147
148
|
this.mcps = discoverMcpServers(provider.mcpPaths);
|
|
148
149
|
}
|
|
149
150
|
}
|
|
@@ -30,13 +30,17 @@ export interface SkillInfo {
|
|
|
30
30
|
* 按优先级从高到低传入路径列表,同名 skill 靠前的路径优先(先到先得)。
|
|
31
31
|
* 解析 YAML frontmatter 中的 name 和 description,同时校验合规。
|
|
32
32
|
*/
|
|
33
|
-
export declare function discoverSkills(paths: string[]
|
|
33
|
+
export declare function discoverSkills(paths: string[], options?: {
|
|
34
|
+
silent?: boolean;
|
|
35
|
+
}): SkillInfo[];
|
|
34
36
|
/**
|
|
35
37
|
* 读取单个 Skill 的完整内容与元数据。
|
|
36
38
|
* 按优先级从高到低传入路径列表,靠前的路径优先(先到先得)。
|
|
37
39
|
* 返回 null 如果 skill 在所有目录中都不存在或 SKILL.md 不可读。
|
|
38
40
|
*/
|
|
39
|
-
export declare function readSkill(skillDirs: string[], skillId: string
|
|
41
|
+
export declare function readSkill(skillDirs: string[], skillId: string, options?: {
|
|
42
|
+
silent?: boolean;
|
|
43
|
+
}): SkillInfo | null;
|
|
40
44
|
/** @internal */
|
|
41
45
|
export declare function parseFrontmatter(content: string): Frontmatter;
|
|
42
46
|
/** @internal */
|
|
@@ -8,7 +8,8 @@ const log = createLogger();
|
|
|
8
8
|
* 按优先级从高到低传入路径列表,同名 skill 靠前的路径优先(先到先得)。
|
|
9
9
|
* 解析 YAML frontmatter 中的 name 和 description,同时校验合规。
|
|
10
10
|
*/
|
|
11
|
-
export function discoverSkills(paths) {
|
|
11
|
+
export function discoverSkills(paths, options) {
|
|
12
|
+
const silent = options?.silent ?? false;
|
|
12
13
|
const seen = new Set();
|
|
13
14
|
const items = [];
|
|
14
15
|
for (const dir of paths) {
|
|
@@ -29,7 +30,7 @@ export function discoverSkills(paths) {
|
|
|
29
30
|
const skillMdPath = join(dir, entry.name, "SKILL.md");
|
|
30
31
|
if (!existsSync(skillMdPath))
|
|
31
32
|
continue;
|
|
32
|
-
const skill = readSkillFromPath(entry.name, skillMdPath);
|
|
33
|
+
const skill = readSkillFromPath(entry.name, skillMdPath, silent);
|
|
33
34
|
if (skill) {
|
|
34
35
|
seen.add(entry.name);
|
|
35
36
|
items.push(skill);
|
|
@@ -44,26 +45,29 @@ export function discoverSkills(paths) {
|
|
|
44
45
|
* 按优先级从高到低传入路径列表,靠前的路径优先(先到先得)。
|
|
45
46
|
* 返回 null 如果 skill 在所有目录中都不存在或 SKILL.md 不可读。
|
|
46
47
|
*/
|
|
47
|
-
export function readSkill(skillDirs, skillId) {
|
|
48
|
+
export function readSkill(skillDirs, skillId, options) {
|
|
49
|
+
const silent = options?.silent ?? false;
|
|
48
50
|
for (const dir of skillDirs) {
|
|
49
51
|
const candidate = join(dir, skillId, "SKILL.md");
|
|
50
52
|
if (existsSync(candidate)) {
|
|
51
|
-
return readSkillFromPath(skillId, candidate);
|
|
53
|
+
return readSkillFromPath(skillId, candidate, silent);
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
return null;
|
|
55
57
|
}
|
|
56
58
|
// ---- 内部 ----
|
|
57
|
-
function readSkillFromPath(skillId, skillMdPath) {
|
|
59
|
+
function readSkillFromPath(skillId, skillMdPath, silent) {
|
|
58
60
|
try {
|
|
59
61
|
const content = readFileSync(skillMdPath, "utf-8");
|
|
60
62
|
const fm = parseFrontmatter(content);
|
|
61
63
|
if (!fm.name)
|
|
62
64
|
return null;
|
|
63
65
|
// 规范合规校验
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
if (!silent) {
|
|
67
|
+
const errors = validateSkill(skillId, fm);
|
|
68
|
+
for (const err of errors) {
|
|
69
|
+
log.warn(`[skills] ${err.skillId}: ${err.field} — ${err.message}`);
|
|
70
|
+
}
|
|
67
71
|
}
|
|
68
72
|
return {
|
|
69
73
|
id: skillId,
|
|
@@ -10,4 +10,6 @@ import { Tool } from "@ai-zen/agents-core";
|
|
|
10
10
|
* 3. 支持直接导出 { function, exec } 格式的对象(自动适配为 Tool)
|
|
11
11
|
* 4. 支持导出 CallbackTool 兼容的 { function, callback } 格式
|
|
12
12
|
*/
|
|
13
|
-
export declare function discoverUserTools(paths: string[]
|
|
13
|
+
export declare function discoverUserTools(paths: string[], options?: {
|
|
14
|
+
silent?: boolean;
|
|
15
|
+
}): Tool[];
|
|
@@ -13,7 +13,8 @@ import { Tool, CallbackTool } from "@ai-zen/agents-core";
|
|
|
13
13
|
* 3. 支持直接导出 { function, exec } 格式的对象(自动适配为 Tool)
|
|
14
14
|
* 4. 支持导出 CallbackTool 兼容的 { function, callback } 格式
|
|
15
15
|
*/
|
|
16
|
-
export function discoverUserTools(paths) {
|
|
16
|
+
export function discoverUserTools(paths, options) {
|
|
17
|
+
const silent = options?.silent ?? false;
|
|
17
18
|
const seen = new Set();
|
|
18
19
|
const tools = [];
|
|
19
20
|
for (const dir of paths) {
|
|
@@ -28,7 +29,7 @@ export function discoverUserTools(paths) {
|
|
|
28
29
|
if (!seen.has(name)) {
|
|
29
30
|
seen.add(name);
|
|
30
31
|
try {
|
|
31
|
-
const tool = loadToolFile(join(dir, name + ".js"));
|
|
32
|
+
const tool = loadToolFile(join(dir, name + ".js"), silent);
|
|
32
33
|
if (tool) {
|
|
33
34
|
tools.push(tool);
|
|
34
35
|
}
|
|
@@ -51,7 +52,7 @@ export function discoverUserTools(paths) {
|
|
|
51
52
|
* 使用 vm.compileFunction 创建沙箱执行环境,避免污染全局作用域。
|
|
52
53
|
* 注入有限的全局 API(console, setTimeout 等),不暴露 process/require。
|
|
53
54
|
*/
|
|
54
|
-
function loadToolFile(filepath) {
|
|
55
|
+
function loadToolFile(filepath, silent) {
|
|
55
56
|
const code = readFileSync(filepath, "utf-8");
|
|
56
57
|
// 构造沙箱上下文
|
|
57
58
|
const sandbox = {
|
|
@@ -83,17 +84,19 @@ function loadToolFile(filepath) {
|
|
|
83
84
|
return null;
|
|
84
85
|
}
|
|
85
86
|
// 适配不同导出格式
|
|
86
|
-
return normalizeToolExport(exported, filepath);
|
|
87
|
+
return normalizeToolExport(exported, filepath, silent);
|
|
87
88
|
}
|
|
88
89
|
catch (err) {
|
|
89
|
-
|
|
90
|
+
if (!silent) {
|
|
91
|
+
console.error(`[usertools] 加载工具文件失败: ${filepath} — ${err?.message ?? err}`);
|
|
92
|
+
}
|
|
90
93
|
return null;
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
96
|
/**
|
|
94
97
|
* 统一各种导出格式为 Tool 实例。
|
|
95
98
|
*/
|
|
96
|
-
function normalizeToolExport(exported, filepath) {
|
|
99
|
+
function normalizeToolExport(exported, filepath, silent) {
|
|
97
100
|
// 情况 1:直接是 Tool 实例
|
|
98
101
|
if (exported instanceof Tool) {
|
|
99
102
|
return exported;
|
|
@@ -114,7 +117,9 @@ function normalizeToolExport(exported, filepath) {
|
|
|
114
117
|
callback: target.callback,
|
|
115
118
|
});
|
|
116
119
|
}
|
|
117
|
-
|
|
120
|
+
if (!silent) {
|
|
121
|
+
console.error(`[usertools] 无法识别的工具格式: ${filepath}`);
|
|
122
|
+
}
|
|
118
123
|
return null;
|
|
119
124
|
}
|
|
120
125
|
/**
|
|
@@ -11,18 +11,25 @@ export const execTool = new CallbackTool({
|
|
|
11
11
|
type: "string",
|
|
12
12
|
description: "要执行的命令",
|
|
13
13
|
},
|
|
14
|
+
timeout: {
|
|
15
|
+
type: "number",
|
|
16
|
+
description: "超时时间(毫秒),超时后会终止进程。默认无超时。建议长时间运行的命令使用 exec_async 异步执行。",
|
|
17
|
+
},
|
|
14
18
|
},
|
|
15
19
|
required: ["command"],
|
|
16
20
|
additionalProperties: false,
|
|
17
21
|
},
|
|
18
22
|
},
|
|
19
23
|
async callback(input) {
|
|
24
|
+
const command = input.command;
|
|
25
|
+
const timeout = input.timeout;
|
|
20
26
|
const result = await new Promise((resolve) => {
|
|
21
|
-
exec(
|
|
27
|
+
const child = exec(command, { timeout: timeout && timeout > 0 ? timeout : undefined }, (error, stdout, stderr) => {
|
|
22
28
|
resolve({
|
|
23
29
|
stdout,
|
|
24
30
|
stderr,
|
|
25
31
|
exitCode: error?.code ?? (error ? 1 : null),
|
|
32
|
+
killed: error?.killed ?? false,
|
|
26
33
|
});
|
|
27
34
|
});
|
|
28
35
|
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { CallbackTool } from "@ai-zen/agents-core";
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
export const execAsyncTool = new CallbackTool({
|
|
4
|
+
function: {
|
|
5
|
+
name: "exec_async",
|
|
6
|
+
description: "异步执行命令,启动程序后立即返回,不等待执行结果。适用于启动长期运行的进程(如服务器、监听程序、GUI应用等)或不需要等待结果的命令。注意:该工具不会捕获命令的输出,如果需要获取输出请使用 exec。",
|
|
7
|
+
parameters: {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: {
|
|
10
|
+
command: {
|
|
11
|
+
type: "string",
|
|
12
|
+
description: "要执行的命令(含参数)",
|
|
13
|
+
},
|
|
14
|
+
cwd: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "工作目录(可选,默认当前目录)",
|
|
17
|
+
},
|
|
18
|
+
detached: {
|
|
19
|
+
type: "boolean",
|
|
20
|
+
description: "是否完全脱离当前进程组(可选,默认 false)。设为 true 时,即使当前 Agent 进程退出,启动的程序仍会继续运行。适用于需要独立运行的守护进程或 GUI 程序。",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
required: ["command"],
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
async callback(input) {
|
|
28
|
+
const command = input.command;
|
|
29
|
+
const cwd = input.cwd ?? undefined;
|
|
30
|
+
const detached = input.detached ?? false;
|
|
31
|
+
// Windows 用 shell 模式,其他平台直接 spawn 避免 shell 安全问题
|
|
32
|
+
const useShell = process.platform === "win32";
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
let child;
|
|
35
|
+
if (useShell) {
|
|
36
|
+
// Windows: 通过 shell 执行整条命令
|
|
37
|
+
child = spawn(command, [], {
|
|
38
|
+
cwd,
|
|
39
|
+
detached,
|
|
40
|
+
stdio: "ignore",
|
|
41
|
+
shell: true,
|
|
42
|
+
windowsHide: true,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Unix: 解析命令和参数,直接 spawn
|
|
47
|
+
const args = [];
|
|
48
|
+
let current = "";
|
|
49
|
+
let inQuote = null;
|
|
50
|
+
for (const ch of command) {
|
|
51
|
+
if (inQuote) {
|
|
52
|
+
if (ch === "\\") {
|
|
53
|
+
current += command[command.indexOf(ch) + 1] ?? "";
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (ch === inQuote) {
|
|
57
|
+
inQuote = null;
|
|
58
|
+
if (current)
|
|
59
|
+
args.push(current);
|
|
60
|
+
current = "";
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
current += ch;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
if (ch === '"' || ch === "'") {
|
|
67
|
+
inQuote = ch;
|
|
68
|
+
}
|
|
69
|
+
else if (ch === " ") {
|
|
70
|
+
if (current) {
|
|
71
|
+
args.push(current);
|
|
72
|
+
current = "";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
current += ch;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (current)
|
|
81
|
+
args.push(current);
|
|
82
|
+
child = spawn(args[0], args.slice(1), {
|
|
83
|
+
cwd,
|
|
84
|
+
detached,
|
|
85
|
+
stdio: "ignore",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// 记录是否已 resolve
|
|
89
|
+
let resolved = false;
|
|
90
|
+
child.on("error", (err) => {
|
|
91
|
+
if (resolved)
|
|
92
|
+
return;
|
|
93
|
+
resolved = true;
|
|
94
|
+
resolve(JSON.stringify({
|
|
95
|
+
success: false,
|
|
96
|
+
pid: null,
|
|
97
|
+
message: `启动失败: ${err.message}`,
|
|
98
|
+
}));
|
|
99
|
+
});
|
|
100
|
+
child.on("spawn", () => {
|
|
101
|
+
if (resolved)
|
|
102
|
+
return;
|
|
103
|
+
resolved = true;
|
|
104
|
+
resolve(JSON.stringify({
|
|
105
|
+
success: true,
|
|
106
|
+
pid: child.pid ?? null,
|
|
107
|
+
message: `进程已启动 (PID: ${child.pid ?? "unknown"})`,
|
|
108
|
+
}));
|
|
109
|
+
});
|
|
110
|
+
// 如果进程很快退出(如命令不存在被 shell 拒绝),捕获退出码
|
|
111
|
+
child.on("exit", (code) => {
|
|
112
|
+
if (resolved)
|
|
113
|
+
return;
|
|
114
|
+
resolved = true;
|
|
115
|
+
resolve(JSON.stringify({
|
|
116
|
+
success: code === 0,
|
|
117
|
+
pid: child.pid ?? null,
|
|
118
|
+
exitCode: code,
|
|
119
|
+
message: code === null
|
|
120
|
+
? `进程已退出 (PID: ${child.pid ?? "unknown"})`
|
|
121
|
+
: `进程已退出 (PID: ${child.pid ?? "unknown"}, 退出码: ${code})`,
|
|
122
|
+
}));
|
|
123
|
+
});
|
|
124
|
+
// 给子进程一点时间来触发 spawn/error/exit 事件
|
|
125
|
+
// 若 500ms 后仍未触发,认为启动成功
|
|
126
|
+
const timeout = setTimeout(() => {
|
|
127
|
+
if (resolved)
|
|
128
|
+
return;
|
|
129
|
+
resolved = true;
|
|
130
|
+
resolve(JSON.stringify({
|
|
131
|
+
success: true,
|
|
132
|
+
pid: child.pid ?? null,
|
|
133
|
+
message: `进程已启动 (PID: ${child.pid ?? "unknown"})`,
|
|
134
|
+
}));
|
|
135
|
+
}, 500);
|
|
136
|
+
// 超时后清理
|
|
137
|
+
const cleanup = () => {
|
|
138
|
+
clearTimeout(timeout);
|
|
139
|
+
child.removeAllListeners();
|
|
140
|
+
};
|
|
141
|
+
child.on("spawn", cleanup);
|
|
142
|
+
child.on("error", cleanup);
|
|
143
|
+
child.on("exit", cleanup);
|
|
144
|
+
// 允许子进程独立运行(不阻止父进程退出)
|
|
145
|
+
child.unref();
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
});
|
|
@@ -14,6 +14,8 @@ import { renameTool } from "./rename.js";
|
|
|
14
14
|
import { copyTool } from "./copy.js";
|
|
15
15
|
import { batchEditTool } from "./batchEdit.js";
|
|
16
16
|
import { editTool } from "./edit.js";
|
|
17
|
-
|
|
17
|
+
import { execAsyncTool } from "./execAsync.js";
|
|
18
|
+
import { sleepTool } from "./sleep.js";
|
|
19
|
+
/** 17 个内置工具实例,注册与实现一体。 */
|
|
18
20
|
export declare const BUILTIN_TOOLS: Tool[];
|
|
19
|
-
export { cwdTool, readFileTool, writeFileTool, execTool, mkdirTool, rmTool, globTool, lsTool, existTool, findTextTool, downloadFileTool, renameTool, copyTool, batchEditTool, editTool };
|
|
21
|
+
export { cwdTool, readFileTool, writeFileTool, execTool, mkdirTool, rmTool, globTool, lsTool, existTool, findTextTool, downloadFileTool, renameTool, copyTool, batchEditTool, editTool, execAsyncTool, sleepTool };
|
|
@@ -13,7 +13,9 @@ import { renameTool } from "./rename.js";
|
|
|
13
13
|
import { copyTool } from "./copy.js";
|
|
14
14
|
import { batchEditTool } from "./batchEdit.js";
|
|
15
15
|
import { editTool } from "./edit.js";
|
|
16
|
-
|
|
16
|
+
import { execAsyncTool } from "./execAsync.js";
|
|
17
|
+
import { sleepTool } from "./sleep.js";
|
|
18
|
+
/** 17 个内置工具实例,注册与实现一体。 */
|
|
17
19
|
export const BUILTIN_TOOLS = [
|
|
18
20
|
cwdTool,
|
|
19
21
|
readFileTool,
|
|
@@ -30,5 +32,7 @@ export const BUILTIN_TOOLS = [
|
|
|
30
32
|
copyTool,
|
|
31
33
|
batchEditTool,
|
|
32
34
|
editTool,
|
|
35
|
+
execAsyncTool,
|
|
36
|
+
sleepTool,
|
|
33
37
|
];
|
|
34
|
-
export { cwdTool, readFileTool, writeFileTool, execTool, mkdirTool, rmTool, globTool, lsTool, existTool, findTextTool, downloadFileTool, renameTool, copyTool, batchEditTool, editTool };
|
|
38
|
+
export { cwdTool, readFileTool, writeFileTool, execTool, mkdirTool, rmTool, globTool, lsTool, existTool, findTextTool, downloadFileTool, renameTool, copyTool, batchEditTool, editTool, execAsyncTool, sleepTool };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CallbackTool } from "@ai-zen/agents-core";
|
|
2
|
+
export const sleepTool = new CallbackTool({
|
|
3
|
+
function: {
|
|
4
|
+
name: "sleep",
|
|
5
|
+
description: "等待指定的时间(毫秒)。用于需要延迟执行的场景,例如等待其他操作完成、操作间隔控制等。注意:过长的等待时间会影响响应速度,建议不超过 30000 毫秒(30 秒)。",
|
|
6
|
+
parameters: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
ms: {
|
|
10
|
+
type: "number",
|
|
11
|
+
description: "等待的毫秒数(1 秒 = 1000 毫秒)。建议不超过 30000(30 秒)。",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
required: ["ms"],
|
|
15
|
+
additionalProperties: false,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
async callback(input) {
|
|
19
|
+
const ms = input.ms;
|
|
20
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) {
|
|
21
|
+
return JSON.stringify({
|
|
22
|
+
success: false,
|
|
23
|
+
error: "ms 必须是正整数",
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (ms > 300_000) {
|
|
27
|
+
// 超过 5 分钟给出警告
|
|
28
|
+
return JSON.stringify({
|
|
29
|
+
success: false,
|
|
30
|
+
error: `等待时间 ${ms}ms 过长,建议不超过 300000ms(5 分钟)。如需长时间等待请分段执行。`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
34
|
+
return JSON.stringify({
|
|
35
|
+
success: true,
|
|
36
|
+
waitedMs: ms,
|
|
37
|
+
waitedSeconds: (ms / 1000).toFixed(1),
|
|
38
|
+
message: `已等待 ${ms}ms(${(ms / 1000).toFixed(1)} 秒)`,
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
});
|
|
@@ -12,6 +12,11 @@ const EMPTY_HINT = "(当前没有可用的 Skill,请联系用户添加)";
|
|
|
12
12
|
export function createLoadSkillTool(skillDirs, filteredSkills) {
|
|
13
13
|
const ids = filteredSkills.map((s) => s.id);
|
|
14
14
|
const param = createDisclosureParam(ids, "选择一个 Skill", EMPTY_HINT);
|
|
15
|
+
// 拼接各 skill 的描述供 LLM 参考
|
|
16
|
+
const skillDescriptions = filteredSkills
|
|
17
|
+
.map((s) => ` - ${s.id}: ${s.description || "无描述"}`)
|
|
18
|
+
.join("\n");
|
|
19
|
+
const skillIdDescription = `${param.description}\n\n各 Skill 说明:\n${skillDescriptions || " 无可用 Skill"}`;
|
|
15
20
|
return new CallbackTool({
|
|
16
21
|
function: {
|
|
17
22
|
name: "load_skill",
|
|
@@ -21,7 +26,7 @@ export function createLoadSkillTool(skillDirs, filteredSkills) {
|
|
|
21
26
|
properties: {
|
|
22
27
|
skill_id: {
|
|
23
28
|
type: "string",
|
|
24
|
-
description:
|
|
29
|
+
description: skillIdDescription,
|
|
25
30
|
...(param.enum ? { enum: param.enum } : {}),
|
|
26
31
|
},
|
|
27
32
|
},
|
|
@@ -57,6 +62,11 @@ export function createCallSkillSubAgentTool(skillDirs, filteredSkills, caps) {
|
|
|
57
62
|
const subAgentSkills = filteredSkills.filter((s) => s.subAgent);
|
|
58
63
|
const ids = subAgentSkills.map((s) => s.id);
|
|
59
64
|
const param = createDisclosureParam(ids, "选择一个 Skill(支持子 Agent)", EMPTY_HINT);
|
|
65
|
+
// 拼接各 skill 的描述供 LLM 参考
|
|
66
|
+
const skillDescriptions = subAgentSkills
|
|
67
|
+
.map((s) => ` - ${s.id}: ${s.description || "无描述"}`)
|
|
68
|
+
.join("\n");
|
|
69
|
+
const skillIdDescription = `${param.description}\n\n各 Skill 说明:\n${skillDescriptions || " 无可用 Skill"}`;
|
|
60
70
|
return new CallbackTool({
|
|
61
71
|
function: {
|
|
62
72
|
name: "call_skill_sub_agent",
|
|
@@ -66,7 +76,7 @@ export function createCallSkillSubAgentTool(skillDirs, filteredSkills, caps) {
|
|
|
66
76
|
properties: {
|
|
67
77
|
skill_id: {
|
|
68
78
|
type: "string",
|
|
69
|
-
description:
|
|
79
|
+
description: skillIdDescription,
|
|
70
80
|
...(param.enum ? { enum: param.enum } : {}),
|
|
71
81
|
},
|
|
72
82
|
task: {
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export type { AutoDraftOptions } from "./plugin/AutoDraftPlugin.js";
|
|
|
32
32
|
export { AutoRefreshToolsPlugin } from "./plugin/AutoRefreshToolsPlugin.js";
|
|
33
33
|
export { BUILTIN_TOOLS } from "./capabilities/implements/builtin/index.js";
|
|
34
34
|
export { createGenerateImageTool } from "./capabilities/implements/builtin/generateImage.js";
|
|
35
|
+
export { execAsyncTool } from "./capabilities/implements/builtin/execAsync.js";
|
|
36
|
+
export { sleepTool } from "./capabilities/implements/builtin/sleep.js";
|
|
35
37
|
export { createLoadSkillTool, createCallSkillSubAgentTool } from "./capabilities/implements/skillTools.js";
|
|
36
38
|
export { createLoadMcpTool, createCallMcpTool, createReadMcpResourceTool } from "./capabilities/implements/mcpTools.js";
|
|
37
39
|
export { createSubAgentTool } from "./capabilities/implements/subAgentTools.js";
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,8 @@ export { AutoRefreshToolsPlugin } from "./plugin/AutoRefreshToolsPlugin.js";
|
|
|
29
29
|
// 工具
|
|
30
30
|
export { BUILTIN_TOOLS } from "./capabilities/implements/builtin/index.js";
|
|
31
31
|
export { createGenerateImageTool } from "./capabilities/implements/builtin/generateImage.js";
|
|
32
|
+
export { execAsyncTool } from "./capabilities/implements/builtin/execAsync.js";
|
|
33
|
+
export { sleepTool } from "./capabilities/implements/builtin/sleep.js";
|
|
32
34
|
export { createLoadSkillTool, createCallSkillSubAgentTool } from "./capabilities/implements/skillTools.js";
|
|
33
35
|
export { createLoadMcpTool, createCallMcpTool, createReadMcpResourceTool } from "./capabilities/implements/mcpTools.js";
|
|
34
36
|
export { createSubAgentTool } from "./capabilities/implements/subAgentTools.js";
|
|
@@ -11,7 +11,7 @@ export class AutoRefreshToolsPlugin {
|
|
|
11
11
|
const { agent } = ctx;
|
|
12
12
|
if (!agent.caps)
|
|
13
13
|
return;
|
|
14
|
-
agent.caps.refresh();
|
|
14
|
+
agent.caps.refresh({ silent: true });
|
|
15
15
|
agent.tools = agent.caps.buildTools(agent.permissions ?? {}, {
|
|
16
16
|
exclude: {
|
|
17
17
|
subagents: agent.definition.function?.name
|