@ai-zen/agents-sdk 0.4.0 → 0.5.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/CHANGELOG.md +21 -0
- package/README.md +19 -15
- package/dist/capabilities/discovery/builtin.d.ts +7 -6
- package/dist/capabilities/discovery/builtin.js +10 -9
- package/dist/capabilities/implements/builtin/BatchEditTool.d.ts +15 -0
- package/dist/capabilities/implements/builtin/BatchEditTool.js +82 -0
- package/dist/capabilities/implements/builtin/CopyTool.d.ts +10 -0
- package/dist/capabilities/implements/builtin/CopyTool.js +43 -0
- package/dist/capabilities/implements/builtin/CwdTool.d.ts +6 -0
- package/dist/capabilities/implements/builtin/CwdTool.js +20 -0
- package/dist/capabilities/implements/builtin/DownloadFileTool.d.ts +9 -0
- package/dist/capabilities/implements/builtin/{downloadFile.js → DownloadFileTool.js} +29 -24
- package/dist/capabilities/implements/builtin/EditTool.d.ts +11 -0
- package/dist/capabilities/implements/builtin/EditTool.js +84 -0
- package/dist/capabilities/implements/builtin/ExecAsyncTool.d.ts +10 -0
- package/dist/capabilities/implements/builtin/{execAsync.js → ExecAsyncTool.js} +32 -34
- package/dist/capabilities/implements/builtin/ExecTool.d.ts +9 -0
- package/dist/capabilities/implements/builtin/ExecTool.js +46 -0
- package/dist/capabilities/implements/builtin/ExistTool.d.ts +8 -0
- package/dist/capabilities/implements/builtin/ExistTool.js +30 -0
- package/dist/capabilities/implements/builtin/FindTextTool.d.ts +12 -0
- package/dist/capabilities/implements/builtin/{findText.js → FindTextTool.js} +43 -37
- package/dist/capabilities/implements/builtin/GenerateImageTool.d.ts +21 -0
- package/dist/capabilities/implements/builtin/GenerateImageTool.js +121 -0
- package/dist/capabilities/implements/builtin/GlobTool.d.ts +10 -0
- package/dist/capabilities/implements/builtin/GlobTool.js +51 -0
- package/dist/capabilities/implements/builtin/LsTool.d.ts +8 -0
- package/dist/capabilities/implements/builtin/LsTool.js +33 -0
- package/dist/capabilities/implements/builtin/MkdirTool.d.ts +9 -0
- package/dist/capabilities/implements/builtin/MkdirTool.js +39 -0
- package/dist/capabilities/implements/builtin/ReadFileTool.d.ts +8 -0
- package/dist/capabilities/implements/builtin/ReadFileTool.js +37 -0
- package/dist/capabilities/implements/builtin/RenameTool.d.ts +9 -0
- package/dist/capabilities/implements/builtin/RenameTool.js +37 -0
- package/dist/capabilities/implements/builtin/RmTool.d.ts +9 -0
- package/dist/capabilities/implements/builtin/RmTool.js +39 -0
- package/dist/capabilities/implements/builtin/SleepTool.d.ts +8 -0
- package/dist/capabilities/implements/builtin/SleepTool.js +46 -0
- package/dist/capabilities/implements/builtin/WriteFileTool.d.ts +9 -0
- package/dist/capabilities/implements/builtin/WriteFileTool.js +40 -0
- package/dist/capabilities/implements/builtin/index.d.ts +29 -21
- package/dist/capabilities/implements/builtin/index.js +44 -37
- package/dist/capabilities/implements/builtin/test-helpers.d.ts +3 -0
- package/dist/capabilities/implements/builtin/test-helpers.js +4 -0
- package/dist/index.d.ts +5 -9
- package/dist/index.js +6 -9
- package/dist/runtime/Provider.d.ts +9 -1
- package/dist/runtime/Provider.js +7 -1
- package/dist/runtime/SdkCallbackTool.d.ts +28 -0
- package/dist/runtime/SdkCallbackTool.js +33 -0
- package/dist/types/index.d.ts +12 -20
- package/package.json +1 -1
- package/dist/capabilities/implements/builtin/batchEdit.d.ts +0 -2
- package/dist/capabilities/implements/builtin/batchEdit.js +0 -76
- package/dist/capabilities/implements/builtin/copy.d.ts +0 -2
- package/dist/capabilities/implements/builtin/copy.js +0 -38
- package/dist/capabilities/implements/builtin/cwd.d.ts +0 -2
- package/dist/capabilities/implements/builtin/cwd.js +0 -15
- package/dist/capabilities/implements/builtin/downloadFile.d.ts +0 -2
- package/dist/capabilities/implements/builtin/edit.d.ts +0 -2
- package/dist/capabilities/implements/builtin/edit.js +0 -79
- package/dist/capabilities/implements/builtin/exec.d.ts +0 -2
- package/dist/capabilities/implements/builtin/exec.js +0 -38
- package/dist/capabilities/implements/builtin/execAsync.d.ts +0 -2
- package/dist/capabilities/implements/builtin/exist.d.ts +0 -2
- package/dist/capabilities/implements/builtin/exist.js +0 -25
- package/dist/capabilities/implements/builtin/findText.d.ts +0 -2
- package/dist/capabilities/implements/builtin/generateImage.d.ts +0 -9
- package/dist/capabilities/implements/builtin/generateImage.js +0 -112
- package/dist/capabilities/implements/builtin/glob.d.ts +0 -2
- package/dist/capabilities/implements/builtin/glob.js +0 -45
- package/dist/capabilities/implements/builtin/ls.d.ts +0 -2
- package/dist/capabilities/implements/builtin/ls.js +0 -28
- package/dist/capabilities/implements/builtin/mkdir.d.ts +0 -2
- package/dist/capabilities/implements/builtin/mkdir.js +0 -34
- package/dist/capabilities/implements/builtin/readFile.d.ts +0 -2
- package/dist/capabilities/implements/builtin/readFile.js +0 -31
- package/dist/capabilities/implements/builtin/rename.d.ts +0 -2
- package/dist/capabilities/implements/builtin/rename.js +0 -32
- package/dist/capabilities/implements/builtin/rm.d.ts +0 -2
- package/dist/capabilities/implements/builtin/rm.js +0 -34
- package/dist/capabilities/implements/builtin/sleep.d.ts +0 -2
- package/dist/capabilities/implements/builtin/sleep.js +0 -41
- package/dist/capabilities/implements/builtin/writeFile.d.ts +0 -2
- package/dist/capabilities/implements/builtin/writeFile.js +0 -34
- package/dist/crud/ConversationRepository.d.ts +0 -9
- package/dist/crud/ConversationRepository.js +0 -10
- package/dist/crud/DraftRepository.d.ts +0 -15
- package/dist/crud/DraftRepository.js +0 -52
- package/dist/plugin/AutoDraftPlugin.d.ts +0 -26
- package/dist/plugin/AutoDraftPlugin.js +0 -62
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-07-29
|
|
4
|
+
|
|
5
|
+
### 💥 破坏性变更
|
|
6
|
+
|
|
7
|
+
- **内置工具全部类化** — 17 个内置工具从单例 `CallbackTool` 实例改为类(`CwdTool`、`ReadFileTool`、`WriteFileTool`、`ExecTool` 等,PascalCase 命名),继承新抽象基类 `SdkCallbackTool`。`BUILTIN_TOOLS` 单例注册表替换为 `BUILTIN_TOOL_CLASSES` 类注册表(`Array<new (env: ToolEnv) => SdkCallbackTool>`)
|
|
8
|
+
- **`generateImage` 类化为 `GenerateImageTool`** — 删除工厂函数 `createGenerateImageTool(config)`,构造签名与其它内置工具统一为 `(env: ToolEnv)`。仍按 `config.defaultImageModel` 条件注册,不进入 `BUILTIN_TOOL_CLASSES` 静态注册表
|
|
9
|
+
- **`discoverBuiltinTools` 签名变更** — 从 `discoverBuiltinTools(config: AppConfig)` 改为 `discoverBuiltinTools(env: ToolEnv)`,用 `env` 实例化工具类
|
|
10
|
+
- **`Provider` 新增 `cwd` 与 `env`** — `cwd` 默认 `process.cwd()`,是相对路径解析的基准;`env: ToolEnv`(`{ cwd, config }`)在构造时建立,`refresh()` 用它实例化内置工具。**工具不再依赖全局 `process.cwd()`**,每个 Provider 可绑定不同工作目录
|
|
11
|
+
- **删除会话/草稿产品层** — `Conversation` / `Draft` 类型、`ConversationRepository`、`DraftRepository`、`AutoDraftPlugin` 及其测试全部移除。会话、草稿持久化下放给各端(CLI/Desktop)自行实现(可复用 `EntityRepository`)
|
|
12
|
+
- **`index.ts` 导出变更** — 移除 `Conversation`/`Draft`/`ConversationRepository`/`DraftRepository`/`AutoDraftPlugin`/`BUILTIN_TOOLS`/`execAsyncTool`/`sleepTool`/`createGenerateImageTool`;新增 `ToolEnv`、`SdkCallbackTool`、`BUILTIN_TOOL_CLASSES`、`GenerateImageTool` 及 17 个工具类
|
|
13
|
+
|
|
14
|
+
### 🚀 新功能
|
|
15
|
+
|
|
16
|
+
- **`ToolEnv` 接口** — 工具环境 `{ cwd, config }`,在工具构造时注入,作为相对路径解析与配置读取的基准
|
|
17
|
+
- **`SdkCallbackTool` 抽象基类** — `env` 构造注入 + 子类实现 `call()` + `exec()` 桥接 + `resolve()` 相对路径解析(public,便于测试直调)
|
|
18
|
+
|
|
19
|
+
### 🎯 优化
|
|
20
|
+
|
|
21
|
+
- **多会话并行支持** — `cwd` 下沉到 Provider(`ToolEnv.cwd`),多个 Provider 可并行服务不同工作目录的会话,互不干扰
|
|
22
|
+
- **工具实例 per-Provider** — 每个 Provider 通过 `discoverBuiltinTools(env)` 实例化自己的一套工具,消除全局单例状态
|
|
23
|
+
|
|
3
24
|
## [0.4.0] - 2026-07-29
|
|
4
25
|
|
|
5
26
|
### 💥 破坏性变更
|
package/README.md
CHANGED
|
@@ -17,12 +17,12 @@ Desktop ──┘ │
|
|
|
17
17
|
## 模块分层
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
types ←
|
|
20
|
+
types ← 纯类型,零业务依赖(含 ToolEnv 工具环境)
|
|
21
21
|
config ← 读写 config.json + 迁移 + 内存缓存 + 原子写入
|
|
22
|
-
crud ←
|
|
22
|
+
crud ← 能力实体 CRUD(Agent 定义等;会话/草稿已下放给各端自行持久化)
|
|
23
23
|
capabilities ← 能力发现与装配(内置 + 用户 + MCP + Skill + SubAgent)
|
|
24
|
-
runtime ← Provider + 模型工厂 + Agent 组装 + MCP 连接管理 + 任务迁移
|
|
25
|
-
plugin ← Agent 插件(autoMigrate、
|
|
24
|
+
runtime ← Provider + 模型工厂 + Agent 组装 + MCP 连接管理 + 任务迁移 + SdkCallbackTool 工具基类
|
|
25
|
+
plugin ← Agent 插件(autoMigrate、autoRefreshTools)
|
|
26
26
|
shared ← 日志、错误
|
|
27
27
|
```
|
|
28
28
|
|
|
@@ -32,14 +32,14 @@ shared ← 日志、错误
|
|
|
32
32
|
|
|
33
33
|
| 实体 | 说明 |
|
|
34
34
|
|------|------|
|
|
35
|
-
| **Provider** | 全局上下文 +
|
|
35
|
+
| **Provider** | 全局上下文 + 能力注册表,持有配置、路径(含 `cwd`)、模型工厂、MCP 管理器,整合发现 → 过滤 → 实例化 |
|
|
36
|
+
| **ToolEnv** | 工具环境 `{ cwd, config }`,Provider 实例化内置工具时注入,作为相对路径解析与配置读取的基准 |
|
|
37
|
+
| **SdkCallbackTool** | 内置工具抽象基类:`env` 构造注入 + 子类实现 `call()` + `resolve()` 相对路径解析 |
|
|
36
38
|
| **SdkAgent** | 继承 Core Agent,携带 SDK 元数据,支持 `use()` 插件注册 |
|
|
37
39
|
| **AgentPlugin** | 插件接口(`onInit`, `onBeforeSend`, `onAfterSend`, `onInnerLoopStart`, `onInnerLoopEnd`) |
|
|
38
40
|
| **Endpoint** | API 端点(baseUrl + apiKey) |
|
|
39
41
|
| **Model** | 模型配置,绑定 Endpoint |
|
|
40
42
|
| **SubAgent** | 有 `function` 字段的 Agent,可被其他 Agent 作为工具调用 |
|
|
41
|
-
| **Conversation** | 对话记录 |
|
|
42
|
-
| **Draft** | 当前会话自动保存 |
|
|
43
43
|
|
|
44
44
|
## 权限模型
|
|
45
45
|
|
|
@@ -56,10 +56,13 @@ Agent.permissions
|
|
|
56
56
|
## 消费模式
|
|
57
57
|
|
|
58
58
|
```typescript
|
|
59
|
-
const provider = await Provider.create({
|
|
59
|
+
const provider = await Provider.create({
|
|
60
|
+
config,
|
|
61
|
+
cwd: "/path/to/workspace", // 每个 Provider 一个工作目录,多会话并行互不干扰
|
|
62
|
+
...paths,
|
|
63
|
+
});
|
|
60
64
|
const agent = createAgent(provider, "my-agent");
|
|
61
|
-
agent.use(new AutoMigratePlugin({ maxTokens, migrationAgent,
|
|
62
|
-
agent.use(new AutoDraftPlugin({ draftsDir, agentId, modelId }));
|
|
65
|
+
agent.use(new AutoMigratePlugin({ maxTokens, migrationAgent, onMigrated }));
|
|
63
66
|
agent.use(new AutoRefreshToolsPlugin());
|
|
64
67
|
await agent.init();
|
|
65
68
|
await agent.send("你好");
|
|
@@ -71,15 +74,17 @@ await agent.send("你好");
|
|
|
71
74
|
|------|------|
|
|
72
75
|
| `types` | ✅ 已实现 — 核心实体、权限模型、MCP 类型完整 |
|
|
73
76
|
| `config` | ✅ 已实现 — ConfigManager + 出厂默认配置 + 一键 bootstrap |
|
|
74
|
-
| `crud` | ✅ 已实现 — Agent
|
|
77
|
+
| `crud` | ✅ 已实现 — Agent 等能力实体 CRUD(会话/草稿由各端自行持久化) |
|
|
75
78
|
| `capabilities` | ✅ 已实现 — 发现 + 权限过滤 + 安全预过滤 + 枚举披露 |
|
|
76
79
|
| `runtime` | ✅ 已实现 — Provider、Capabilities、createAgent、MCP 连接管理、任务迁移 |
|
|
77
|
-
| `plugin` | ✅ 已实现 — AutoMigratePlugin /
|
|
80
|
+
| `plugin` | ✅ 已实现 — AutoMigratePlugin / AutoRefreshToolsPlugin |
|
|
78
81
|
| `shared` | ✅ 已实现 — SdkError + 可注入 Logger |
|
|
79
|
-
| 测试 | ✅
|
|
82
|
+
| 测试 | ✅ 409 个测试,47 个文件,全通过(含真实 API 聊天 e2e) |
|
|
80
83
|
|
|
81
84
|
## 内置工具
|
|
82
85
|
|
|
86
|
+
内置工具全部类化(继承 `SdkCallbackTool`),由 Provider 用 `ToolEnv` 实例化——每个 Provider 一套实例,`cwd` 注入,相对路径以 `Provider.cwd` 为基准,不依赖全局 `process.cwd()`。
|
|
87
|
+
|
|
83
88
|
| 工具 | 说明 |
|
|
84
89
|
|------|------|
|
|
85
90
|
| `cwd` | 获取当前工作目录 |
|
|
@@ -100,7 +105,7 @@ await agent.send("你好");
|
|
|
100
105
|
| `edit` | 编辑文件中的文本 |
|
|
101
106
|
| `sleep` | 等待指定毫秒数后继续 |
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
条件注入(`GenerateImageTool` 需配置 `defaultImageModel` 才注册):
|
|
104
109
|
|
|
105
110
|
| 工具 | 说明 |
|
|
106
111
|
|------|------|
|
|
@@ -111,7 +116,6 @@ await agent.send("你好");
|
|
|
111
116
|
| 插件 | 说明 |
|
|
112
117
|
|------|------|
|
|
113
118
|
| `AutoMigratePlugin` | 上下文超限时自动触发任务迁移,生成交接文档,透明替换 Agent |
|
|
114
|
-
| `AutoDraftPlugin` | 每次 `send()` 后自动保存当前消息历史到 draft 文件 |
|
|
115
119
|
| `AutoRefreshToolsPlugin` | 每次 `send()` 前重新扫描文件系统,刷新工具列表 |
|
|
116
120
|
|
|
117
121
|
## 设计原则
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Tool } from "@ai-zen/agents-core";
|
|
2
|
-
import type {
|
|
1
|
+
import type { Tool } from "@ai-zen/agents-core";
|
|
2
|
+
import type { ToolEnv } from "../../types/index.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* 发现内置工具:用 ToolEnv 实例化全部内置工具类。
|
|
5
|
+
*
|
|
6
|
+
* generateImage 依赖图片模型配置(defaultImageModel),未配置时不注册,
|
|
7
|
+
* 因此不进入 BUILTIN_TOOL_CLASSES 静态注册表,在此按条件实例化。
|
|
7
8
|
*/
|
|
8
|
-
export declare function discoverBuiltinTools(
|
|
9
|
+
export declare function discoverBuiltinTools(env: ToolEnv): Tool[];
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { BUILTIN_TOOL_CLASSES } from "../implements/builtin/index.js";
|
|
2
|
+
import { GenerateImageTool } from "../implements/builtin/GenerateImageTool.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* 发现内置工具:用 ToolEnv 实例化全部内置工具类。
|
|
5
|
+
*
|
|
6
|
+
* generateImage 依赖图片模型配置(defaultImageModel),未配置时不注册,
|
|
7
|
+
* 因此不进入 BUILTIN_TOOL_CLASSES 静态注册表,在此按条件实例化。
|
|
7
8
|
*/
|
|
8
|
-
export function discoverBuiltinTools(
|
|
9
|
-
const tools =
|
|
10
|
-
if (config.defaultImageModel) {
|
|
9
|
+
export function discoverBuiltinTools(env) {
|
|
10
|
+
const tools = BUILTIN_TOOL_CLASSES.map((Cls) => new Cls(env));
|
|
11
|
+
if (env.config.defaultImageModel) {
|
|
11
12
|
const existingNames = new Set(tools.map((t) => t.function.name));
|
|
12
13
|
if (!existingNames.has("generateImage")) {
|
|
13
|
-
tools.push(
|
|
14
|
+
tools.push(new GenerateImageTool(env));
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
17
|
return tools;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
2
|
+
import type { ToolEnv } from "../../../types/index.js";
|
|
3
|
+
interface Replacement {
|
|
4
|
+
oldText: string;
|
|
5
|
+
newText: string;
|
|
6
|
+
isReplaceAll?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare class BatchEditTool extends SdkCallbackTool {
|
|
9
|
+
constructor(env: ToolEnv);
|
|
10
|
+
call(input: {
|
|
11
|
+
path: string;
|
|
12
|
+
replacements: Replacement[];
|
|
13
|
+
}): Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as fsp from "fs/promises";
|
|
2
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
3
|
+
export class BatchEditTool extends SdkCallbackTool {
|
|
4
|
+
constructor(env) {
|
|
5
|
+
super({
|
|
6
|
+
function: {
|
|
7
|
+
name: "batchEdit",
|
|
8
|
+
description: "批量编辑文件文本,可以优先使用这个工具对文件进行编辑",
|
|
9
|
+
parameters: {
|
|
10
|
+
type: "object",
|
|
11
|
+
properties: {
|
|
12
|
+
path: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "文件路径",
|
|
15
|
+
},
|
|
16
|
+
replacements: {
|
|
17
|
+
type: "array",
|
|
18
|
+
description: "要替换的文本数组",
|
|
19
|
+
items: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
oldText: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "要替换的文本",
|
|
25
|
+
},
|
|
26
|
+
newText: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "替换后的文本",
|
|
29
|
+
},
|
|
30
|
+
isReplaceAll: {
|
|
31
|
+
type: "boolean",
|
|
32
|
+
description: "是否替换所有匹配的文本(默认仅替换首次匹配)。使用此功能前应确保你提供的 oldText 足够精确,避免误替换",
|
|
33
|
+
default: false,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
required: ["oldText", "newText"],
|
|
37
|
+
additionalProperties: false,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
required: ["path", "replacements"],
|
|
42
|
+
additionalProperties: false,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
env,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async call(input) {
|
|
49
|
+
try {
|
|
50
|
+
const filePath = this.resolve(input.path);
|
|
51
|
+
const content = await fsp.readFile(filePath, "utf-8");
|
|
52
|
+
let newContent = content;
|
|
53
|
+
const results = [];
|
|
54
|
+
for (const replacement of input.replacements) {
|
|
55
|
+
if (!newContent.includes(replacement.oldText)) {
|
|
56
|
+
results.push({
|
|
57
|
+
oldText: replacement.oldText,
|
|
58
|
+
newText: replacement.newText,
|
|
59
|
+
result: "文件中未精确匹配到要替换的文本",
|
|
60
|
+
});
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (replacement.isReplaceAll) {
|
|
64
|
+
newContent = newContent.replaceAll(replacement.oldText, replacement.newText);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
newContent = newContent.replace(replacement.oldText, replacement.newText);
|
|
68
|
+
}
|
|
69
|
+
results.push({
|
|
70
|
+
oldText: replacement.oldText,
|
|
71
|
+
newText: replacement.newText,
|
|
72
|
+
result: "success",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
await fsp.writeFile(filePath, newContent);
|
|
76
|
+
return JSON.stringify(results);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return error?.message;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
2
|
+
import type { ToolEnv } from "../../../types/index.js";
|
|
3
|
+
export declare class CopyTool extends SdkCallbackTool {
|
|
4
|
+
constructor(env: ToolEnv);
|
|
5
|
+
call(input: {
|
|
6
|
+
src: string;
|
|
7
|
+
dest: string;
|
|
8
|
+
recursive?: boolean;
|
|
9
|
+
}): Promise<string>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as fsp from "fs/promises";
|
|
2
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
3
|
+
export class CopyTool extends SdkCallbackTool {
|
|
4
|
+
constructor(env) {
|
|
5
|
+
super({
|
|
6
|
+
function: {
|
|
7
|
+
name: "copy",
|
|
8
|
+
description: "复制文件或目录(相当于 cp 命令)",
|
|
9
|
+
parameters: {
|
|
10
|
+
type: "object",
|
|
11
|
+
properties: {
|
|
12
|
+
src: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "源路径",
|
|
15
|
+
},
|
|
16
|
+
dest: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "目标路径",
|
|
19
|
+
},
|
|
20
|
+
recursive: {
|
|
21
|
+
type: "boolean",
|
|
22
|
+
description: "是否递归复制目录,复制目录时需设为 true",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
required: ["src", "dest"],
|
|
26
|
+
additionalProperties: false,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
env,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async call(input) {
|
|
33
|
+
try {
|
|
34
|
+
await fsp.cp(this.resolve(input.src), this.resolve(input.dest), {
|
|
35
|
+
recursive: input.recursive ?? false,
|
|
36
|
+
});
|
|
37
|
+
return "success";
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return error?.message;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
2
|
+
export class CwdTool extends SdkCallbackTool {
|
|
3
|
+
constructor(env) {
|
|
4
|
+
super({
|
|
5
|
+
function: {
|
|
6
|
+
name: "cwd",
|
|
7
|
+
description: "获取当前工作目录 cwd",
|
|
8
|
+
parameters: {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {},
|
|
11
|
+
required: [],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
env,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
call() {
|
|
18
|
+
return this.env.cwd;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
2
|
+
import type { ToolEnv } from "../../../types/index.js";
|
|
3
|
+
export declare class DownloadFileTool extends SdkCallbackTool {
|
|
4
|
+
constructor(env: ToolEnv);
|
|
5
|
+
call(input: {
|
|
6
|
+
url: string;
|
|
7
|
+
outputPath?: string;
|
|
8
|
+
}): Promise<string>;
|
|
9
|
+
}
|
|
@@ -1,34 +1,39 @@
|
|
|
1
|
-
import { CallbackTool } from "@ai-zen/agents-core";
|
|
2
1
|
import * as fsp from "fs/promises";
|
|
3
2
|
import * as path from "path";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
type: "
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
4
|
+
export class DownloadFileTool extends SdkCallbackTool {
|
|
5
|
+
constructor(env) {
|
|
6
|
+
super({
|
|
7
|
+
function: {
|
|
8
|
+
name: "downloadFile",
|
|
9
|
+
description: "从 URL 下载文件(图片、PDF 等二进制文件)并保存到本地磁盘。自动从 URL 推断文件名,也可指定保存路径。",
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
url: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "文件下载链接",
|
|
16
|
+
},
|
|
17
|
+
outputPath: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "保存路径(可选)。可以是目录或完整文件路径。不指定则下载到当前工作目录,自动从 URL 推断文件名。",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: ["url"],
|
|
23
|
+
additionalProperties: false,
|
|
18
24
|
},
|
|
19
25
|
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
async callback(input) {
|
|
26
|
+
env,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async call(input) {
|
|
25
30
|
try {
|
|
26
31
|
const url = input.url;
|
|
27
32
|
if (!url)
|
|
28
33
|
throw new Error("url 不能为空");
|
|
29
34
|
let savePath;
|
|
30
35
|
if (input.outputPath) {
|
|
31
|
-
savePath = input.outputPath;
|
|
36
|
+
savePath = this.resolve(input.outputPath);
|
|
32
37
|
const stat = await fsp.stat(savePath).catch(() => null);
|
|
33
38
|
if (stat?.isDirectory()) {
|
|
34
39
|
const urlPath = new URL(url).pathname;
|
|
@@ -39,7 +44,7 @@ export const downloadFileTool = new CallbackTool({
|
|
|
39
44
|
else {
|
|
40
45
|
const urlPath = new URL(url).pathname;
|
|
41
46
|
const fileName = path.basename(urlPath) || `download_${Date.now()}`;
|
|
42
|
-
savePath = path.join(
|
|
47
|
+
savePath = path.join(this.env.cwd, fileName);
|
|
43
48
|
}
|
|
44
49
|
await fsp.mkdir(path.dirname(savePath), { recursive: true });
|
|
45
50
|
const response = await fetch(url);
|
|
@@ -66,5 +71,5 @@ export const downloadFileTool = new CallbackTool({
|
|
|
66
71
|
error: error?.message || "下载失败",
|
|
67
72
|
});
|
|
68
73
|
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
2
|
+
import type { ToolEnv } from "../../../types/index.js";
|
|
3
|
+
export declare class EditTool extends SdkCallbackTool {
|
|
4
|
+
constructor(env: ToolEnv);
|
|
5
|
+
call(input: {
|
|
6
|
+
path: string;
|
|
7
|
+
oldText: string;
|
|
8
|
+
newText: string;
|
|
9
|
+
isReplaceAll?: boolean;
|
|
10
|
+
}): Promise<string>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as fsp from "fs/promises";
|
|
2
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
3
|
+
function countOccurrences(content, text) {
|
|
4
|
+
let count = 0;
|
|
5
|
+
let pos = 0;
|
|
6
|
+
while (true) {
|
|
7
|
+
pos = content.indexOf(text, pos);
|
|
8
|
+
if (pos === -1)
|
|
9
|
+
break;
|
|
10
|
+
count++;
|
|
11
|
+
pos += text.length;
|
|
12
|
+
}
|
|
13
|
+
return count;
|
|
14
|
+
}
|
|
15
|
+
export class EditTool extends SdkCallbackTool {
|
|
16
|
+
constructor(env) {
|
|
17
|
+
super({
|
|
18
|
+
function: {
|
|
19
|
+
name: "edit",
|
|
20
|
+
description: "编辑文件中的文本,支持精确替换或替换所有匹配项",
|
|
21
|
+
parameters: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
path: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "文件路径",
|
|
27
|
+
},
|
|
28
|
+
oldText: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "要替换的文本",
|
|
31
|
+
},
|
|
32
|
+
newText: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "替换后的文本",
|
|
35
|
+
},
|
|
36
|
+
isReplaceAll: {
|
|
37
|
+
type: "boolean",
|
|
38
|
+
description: "是否替换所有匹配的文本(默认 false,仅替换首次匹配)。使用此功能前应确保你提供的 oldText 足够精确,避免误替换",
|
|
39
|
+
default: false,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
required: ["path", "oldText", "newText"],
|
|
43
|
+
additionalProperties: false,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
env,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async call(input) {
|
|
50
|
+
try {
|
|
51
|
+
const filePath = this.resolve(input.path);
|
|
52
|
+
const oldText = input.oldText;
|
|
53
|
+
const newText = input.newText;
|
|
54
|
+
const isReplaceAll = input.isReplaceAll ?? false;
|
|
55
|
+
const content = await fsp.readFile(filePath, "utf-8");
|
|
56
|
+
const count = countOccurrences(content, oldText);
|
|
57
|
+
if (count === 0) {
|
|
58
|
+
return JSON.stringify({
|
|
59
|
+
result: "文件中未精确匹配到要替换的文本",
|
|
60
|
+
matchCount: 0,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const newContent = isReplaceAll
|
|
64
|
+
? content.replaceAll(oldText, newText)
|
|
65
|
+
: content.replace(oldText, newText);
|
|
66
|
+
await fsp.writeFile(filePath, newContent);
|
|
67
|
+
if (!isReplaceAll && count > 1) {
|
|
68
|
+
return JSON.stringify({
|
|
69
|
+
result: `警告:未开启替换所有(isReplaceAll=false),但文本 "${oldText}" 在文件中出现了 ${count} 次,仅替换了首次匹配。如果希望替换所有匹配,请将 isReplaceAll 设为 true`,
|
|
70
|
+
matchCount: count,
|
|
71
|
+
replacedCount: 1,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return JSON.stringify({
|
|
75
|
+
result: "success",
|
|
76
|
+
matchCount: count,
|
|
77
|
+
replacedCount: isReplaceAll ? count : 1,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
return error?.message;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
2
|
+
import type { ToolEnv } from "../../../types/index.js";
|
|
3
|
+
export declare class ExecAsyncTool extends SdkCallbackTool {
|
|
4
|
+
constructor(env: ToolEnv);
|
|
5
|
+
call(input: {
|
|
6
|
+
command: string;
|
|
7
|
+
cwd?: string;
|
|
8
|
+
detached?: boolean;
|
|
9
|
+
}): Promise<string>;
|
|
10
|
+
}
|
|
@@ -1,39 +1,43 @@
|
|
|
1
|
-
import { CallbackTool } from "@ai-zen/agents-core";
|
|
2
1
|
import { spawn } from "child_process";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
type: "
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
2
|
+
import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
|
|
3
|
+
export class ExecAsyncTool extends SdkCallbackTool {
|
|
4
|
+
constructor(env) {
|
|
5
|
+
super({
|
|
6
|
+
function: {
|
|
7
|
+
name: "exec_async",
|
|
8
|
+
description: "异步执行命令,启动程序后立即返回,不等待执行结果。适用于启动长期运行的进程(如服务器、监听程序、GUI应用等)或不需要等待结果的命令。注意:该工具不会捕获命令的输出,如果需要获取输出请使用 exec。",
|
|
9
|
+
parameters: {
|
|
10
|
+
type: "object",
|
|
11
|
+
properties: {
|
|
12
|
+
command: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "要执行的命令(含参数)",
|
|
15
|
+
},
|
|
16
|
+
cwd: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "工作目录(可选,默认当前工作目录)",
|
|
19
|
+
},
|
|
20
|
+
detached: {
|
|
21
|
+
type: "boolean",
|
|
22
|
+
description: "是否完全脱离当前进程组(可选,默认 false)。设为 true 时,即使当前 Agent 进程退出,启动的程序仍会继续运行。适用于需要独立运行的守护进程或 GUI 程序。",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
required: ["command"],
|
|
26
|
+
additionalProperties: false,
|
|
21
27
|
},
|
|
22
28
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
async callback(input) {
|
|
29
|
+
env,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async call(input) {
|
|
28
33
|
const command = input.command;
|
|
29
|
-
const cwd = input.cwd
|
|
34
|
+
const cwd = input.cwd ? this.resolve(input.cwd) : this.env.cwd;
|
|
30
35
|
const detached = input.detached ?? false;
|
|
31
36
|
// Windows 用 shell 模式,其他平台直接 spawn 避免 shell 安全问题
|
|
32
37
|
const useShell = process.platform === "win32";
|
|
33
38
|
return new Promise((resolve) => {
|
|
34
39
|
let child;
|
|
35
40
|
if (useShell) {
|
|
36
|
-
// Windows: 通过 shell 执行整条命令
|
|
37
41
|
child = spawn(command, [], {
|
|
38
42
|
cwd,
|
|
39
43
|
detached,
|
|
@@ -85,7 +89,6 @@ export const execAsyncTool = new CallbackTool({
|
|
|
85
89
|
stdio: "ignore",
|
|
86
90
|
});
|
|
87
91
|
}
|
|
88
|
-
// 记录是否已 resolve
|
|
89
92
|
let resolved = false;
|
|
90
93
|
child.on("error", (err) => {
|
|
91
94
|
if (resolved)
|
|
@@ -107,7 +110,6 @@ export const execAsyncTool = new CallbackTool({
|
|
|
107
110
|
message: `进程已启动 (PID: ${child.pid ?? "unknown"})`,
|
|
108
111
|
}));
|
|
109
112
|
});
|
|
110
|
-
// 如果进程很快退出(如命令不存在被 shell 拒绝),捕获退出码
|
|
111
113
|
child.on("exit", (code) => {
|
|
112
114
|
if (resolved)
|
|
113
115
|
return;
|
|
@@ -121,8 +123,6 @@ export const execAsyncTool = new CallbackTool({
|
|
|
121
123
|
: `进程已退出 (PID: ${child.pid ?? "unknown"}, 退出码: ${code})`,
|
|
122
124
|
}));
|
|
123
125
|
});
|
|
124
|
-
// 给子进程一点时间来触发 spawn/error/exit 事件
|
|
125
|
-
// 若 500ms 后仍未触发,认为启动成功
|
|
126
126
|
const timeout = setTimeout(() => {
|
|
127
127
|
if (resolved)
|
|
128
128
|
return;
|
|
@@ -133,7 +133,6 @@ export const execAsyncTool = new CallbackTool({
|
|
|
133
133
|
message: `进程已启动 (PID: ${child.pid ?? "unknown"})`,
|
|
134
134
|
}));
|
|
135
135
|
}, 500);
|
|
136
|
-
// 超时后清理
|
|
137
136
|
const cleanup = () => {
|
|
138
137
|
clearTimeout(timeout);
|
|
139
138
|
child.removeAllListeners();
|
|
@@ -141,8 +140,7 @@ export const execAsyncTool = new CallbackTool({
|
|
|
141
140
|
child.on("spawn", cleanup);
|
|
142
141
|
child.on("error", cleanup);
|
|
143
142
|
child.on("exit", cleanup);
|
|
144
|
-
// 允许子进程独立运行(不阻止父进程退出)
|
|
145
143
|
child.unref();
|
|
146
144
|
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
145
|
+
}
|
|
146
|
+
}
|