@ai-zen/agents-sdk 0.5.4 → 0.5.6

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 CHANGED
@@ -1,180 +1,197 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.6] - 2026-08-14
4
+
5
+ ### 🚀 New Features
6
+
7
+ - **`AgentPlugin` gains the `onToolCall` interception hook** — corresponding to Core 3.3.0's `onToolCall` hook: fired before every tool call execution, receiving the **same `ToolCallContext` instance** that is passed to `Tool.exec(ctx)`. Returning a string rejects the tool (not executed; the reason is returned to the LLM as the tool result and the conversation continues to the next round); returning `undefined` allows execution. Multiple plugins run in registration order and any one returning a string rejects (short-circuit). `SdkAgent.send()` wraps this hook into plugin iteration before delegating to `super.send()`, isomorphic with the existing inner-loop hooks, and clears it afterwards
8
+
9
+ ### 🛠 Optimized
10
+
11
+ - **`@ai-zen/agents-core` dependency upgraded to 3.3.0** — `FunctionCallContext` was unified into `ToolCallContext` (a single class spanning interception decision → execution). SDK internal references (`SdkCallbackTool.exec`, skill / sub-agent tool callbacks) are synced to `ToolCallContext`, while the deprecated `FunctionCallContext` alias is retained for backward compatibility
12
+
13
+ ## [0.5.5] - 2026-08-13
14
+
15
+ ### 📄 Docs
16
+
17
+ - **README translated to English** — the main `README.md` is now English-first, with the original Chinese content preserved as `README.zh.md`
18
+ - **Package metadata standardized** — `description` unified to English across packages
19
+
3
20
  ## [0.5.4] - 2026-08-05
4
21
 
5
- ### 🚀 新功能
22
+ ### 🚀 New Features
6
23
 
7
- - **`ExecAsyncTool`(exec_async)统一走 shell 解析** — 移除 Unix 平台手动分词逻辑,所有平台均经 `spawn(command, [], { shell: true })` 执行。工具描述明确告知 agent:其本身不捕获输出,如需留存/查看输出可在命令中使用 shell 重定向写入文件(`>` / `>>`),并支持管道(`|`)等 shell 语法
24
+ - **`ExecAsyncTool` (exec_async) now uniformly uses shell parsing** — removed the manual word-splitting logic on Unix; all platforms now execute via `spawn(command, [], { shell: true })`. The tool description explicitly tells the agent it does not capture output itself; to retain/inspect output, use shell redirection to a file (`>` / `>>`) in the command, and shell syntax such as pipes (`|`) is supported
8
25
 
9
- ### 🎯 优化
26
+ ### 🎯 Optimized
10
27
 
11
- - **`ExecTool`(exec)的 `timeout` 改为必填** — schema `required` 由 `["command"]` 扩为 `["command", "timeout"]`,`call()` 类型签名 `timeout: number`(必填),并在运行时双校验(缺失/非正数/非有限数即抛错)。`timeout` 必填后,命令始终受超时保护,避免无超时长跑
12
- - **超时原因明确告知 agent** — `exec` 超时被终止(`error.killed` 为 true)时返回结构新增 `terminated: "timeout"` 字段。弥补 Node 不会自动在 stderr 写入超时提示的限制,使 agent 能明确判断命令因超时被终止,从而灵活应对
28
+ - **`ExecTool` (exec) `timeout` is now required** — schema `required` expanded from `["command"]` to `["command", "timeout"]`; the `call()` type signature is `timeout: number` (required), with double validation at runtime (throws on missing / non-positive / non-finite). With `timeout` required, commands are always protected by a timeout and cannot run indefinitely
29
+ - **Timeout reason clearly reported to the agent** — when `exec` is killed by a timeout (`error.killed` is `true`), the returned structure adds a `terminated: "timeout"` field. This compensates for Node not automatically writing a timeout notice to stderr, letting the agent clearly determine that the command was terminated by a timeout and respond accordingly
13
30
 
14
31
  ## [0.5.3] - 2026-08-05
15
32
 
16
- ### 🚀 新功能
33
+ ### 🚀 New Features
17
34
 
18
- - **初始化时默认释放含 socket-pty 的 mcp.json** — `ConfigManager.bootstrap()` 新增 `ensureDefaultMcpConfig()`,首启在 `~/.ai-zen/mcp.json` 写入默认 MCP 配置(含 socket-pty 终端 server,`command: npx -y @ai-zen/socket-pty mcp`),文件已存在则幂等不覆盖;新增 `readMcpConfig()` / `writeMcpConfig()` 读写方法;新增并导出 `DEFAULT_MCP_CONFIG` 常量
19
- - **`load_mcp` 透传 server description** — `McpServerConfig` 新增 `description?` 字段,`discoverMcpServers` 解析不再丢弃;`load_mcp` 的 `server` 参数枚举按 `- {id}: {description}` 拼接各 server 说明供 LLM 参考(与 `load_skill` 同构)
20
- - **新增 `ContextGuardPlugin` 上下文安全护栏** — 在每次内循环**发请求前**(`onInnerLoopStart`,Core 中位于 try 块外)检测上一轮 `usage.prompt_tokens`,超过 `maxTokens × ratio`(默认 1.2,即超阈 20%)时抛出 `ContextOverflowError` 中断对话,防止读入超大文件导致上下文失控。与 `AutoMigratePlugin` 职责分离、区间互补;无需改动 Core
35
+ - **Default mcp.json with socket-pty released on init** — `ConfigManager.bootstrap()` adds `ensureDefaultMcpConfig()`, which on first run writes a default MCP config (incl. the socket-pty terminal server, `command: npx -y @ai-zen/socket-pty mcp`) to `~/.ai-zen/mcp.json`; idempotent, does not overwrite if the file exists. Added `readMcpConfig()` / `writeMcpConfig()` methods, and exported `DEFAULT_MCP_CONFIG` constant
36
+ - **`load_mcp` passes through server description** — `McpServerConfig` gains an optional `description?` field, no longer discarded by `discoverMcpServers`; the `server` parameter enum in `load_mcp` is built as `- {id}: {description}` so the LLM can see each server's description (isomorphic with `load_skill`)
37
+ - **New `ContextGuardPlugin` context safety guard** — before each inner loop's request (`onInnerLoopStart`, outside the try block in Core), checks the previous round's `usage.prompt_tokens`; when it exceeds `maxTokens × ratio` (default 1.2, i.e. 20% over threshold), throws `ContextOverflowError` to interrupt the conversation, preventing context runaway from reading oversized files. Responsibilities are separated from `AutoMigratePlugin` and the ranges complement each other; no Core changes needed
21
38
 
22
- ### 🆕 新增导出
39
+ ### 🆕 New Exports
23
40
 
24
- - `DEFAULT_MCP_CONFIG`(constants)、`ContextGuardPlugin`、`ContextOverflowError`
41
+ - `DEFAULT_MCP_CONFIG` (constants), `ContextGuardPlugin`, `ContextOverflowError`
25
42
 
26
43
  ## [0.5.2] - 2026-08-03
27
44
 
28
- ### 🚀 新功能
45
+ ### 🚀 New Features
29
46
 
30
- - **`AgentPlugin` 新增 `onInnerLoopsStart` / `onInnerLoopsEnd` 钩子** — 对应 Core 3.2.0 的整组内循环起止钩子(一次 send 各触发一次)。`SdkAgent.send()` 在委托 `super.send()` 前后将这两个钩子包装为插件遍历调用,与单轮 `onInnerLoopStart` / `onInnerLoopEnd` 同构。插件可通过 `ctx` 拿到当前 agent、发送内容与消息快照
47
+ - **`AgentPlugin` gains `onInnerLoopsStart` / `onInnerLoopsEnd` hooks** — corresponding to Core 3.2.0's whole-group inner-loop start/end hooks (each fires once per `send`). `SdkAgent.send()` wraps these two hooks into plugin iteration before/after delegating to `super.send()`, isomorphic with the per-round `onInnerLoopStart` / `onInnerLoopEnd`. Plugins can access the current agent, the sent content, and the message snapshot via `ctx`
31
48
 
32
49
  ## [0.5.1] - 2026-08-03
33
50
 
34
- ### 🛠 优化
51
+ ### 🛠 Optimized
35
52
 
36
- - **依赖 `@ai-zen/agents-core` 升级并改为范围版本** — 从 `workspace:*`(发布时替换为精确版本 `3.0.1`)改为 `workspace:^`(发布为 `^3.1.0`)。core 3.1.0 起 `Message` 构造自动生成 `id`,SDK 透传的消息随之携带稳定 id;范围版本使 core 后续 minor/patch 升级不再需要 SDK 单独发版跟进
53
+ - **`@ai-zen/agents-core` dependency upgraded and switched to a range version** — from `workspace:*` (replaced with the exact version `3.0.1` at publish time) to `workspace:^` (published as `^3.1.0`). Since core 3.1.0, `Message` auto-generates an `id` in the constructor, so messages passed through the SDK carry a stable id; the range version means subsequent core minor/patch upgrades no longer require a separate SDK release
37
54
 
38
55
  ## [0.5.0] - 2026-07-29
39
56
 
40
- ### 💥 破坏性变更
57
+ ### 💥 Breaking Changes
41
58
 
42
- - **内置工具全部类化** — 17 个内置工具从单例 `CallbackTool` 实例改为类(`CwdTool`、`ReadFileTool`、`WriteFileTool`、`ExecTool` 等,PascalCase 命名),继承新抽象基类 `SdkCallbackTool`。`BUILTIN_TOOLS` 单例注册表替换为 `BUILTIN_TOOL_CLASSES` 类注册表(`Array<new (env: ToolEnv) => SdkCallbackTool>`)
43
- - **`generateImage` 类化为 `GenerateImageTool`** — 删除工厂函数 `createGenerateImageTool(config)`,构造签名与其它内置工具统一为 `(env: ToolEnv)`。仍按 `config.defaultImageModel` 条件注册,不进入 `BUILTIN_TOOL_CLASSES` 静态注册表
44
- - **`discoverBuiltinTools` 签名变更** — 从 `discoverBuiltinTools(config: AppConfig)` 改为 `discoverBuiltinTools(env: ToolEnv)`,用 `env` 实例化工具类
45
- - **`Provider` 新增 `cwd` 与 `env`** — `cwd` 默认 `process.cwd()`,是相对路径解析的基准;`env: ToolEnv`(`{ cwd, config }`)在构造时建立,`refresh()` 用它实例化内置工具。**工具不再依赖全局 `process.cwd()`**,每个 Provider 可绑定不同工作目录
46
- - **删除会话/草稿产品层** — `Conversation` / `Draft` 类型、`ConversationRepository`、`DraftRepository`、`AutoDraftPlugin` 及其测试全部移除。会话、草稿持久化下放给各端(CLI/Desktop)自行实现(可复用 `EntityRepository`)
47
- - **`index.ts` 导出变更** — 移除 `Conversation`/`Draft`/`ConversationRepository`/`DraftRepository`/`AutoDraftPlugin`/`BUILTIN_TOOLS`/`execAsyncTool`/`sleepTool`/`createGenerateImageTool`;新增 `ToolEnv`、`SdkCallbackTool`、`BUILTIN_TOOL_CLASSES`、`GenerateImageTool` 及 17 个工具类
59
+ - **All built-in tools are now classes** — the 17 built-in tools changed from singleton `CallbackTool` instances to classes (`CwdTool`, `ReadFileTool`, `WriteFileTool`, `ExecTool`, etc., PascalCase naming) extending the new abstract base `SdkCallbackTool`. The `BUILTIN_TOOLS` singleton registry was replaced with the `BUILTIN_TOOL_CLASSES` class registry (`Array<new (env: ToolEnv) => SdkCallbackTool>`)
60
+ - **`generateImage` classed as `GenerateImageTool`** — removed the factory function `createGenerateImageTool(config)`; constructor signature unified with other built-in tools as `(env: ToolEnv)`. Still conditionally registered via `config.defaultImageModel`, not part of the static `BUILTIN_TOOL_CLASSES` registry
61
+ - **`discoverBuiltinTools` signature changed** — from `discoverBuiltinTools(config: AppConfig)` to `discoverBuiltinTools(env: ToolEnv)`, instantiating tool classes with `env`
62
+ - **`Provider` gains `cwd` and `env`** — `cwd` defaults to `process.cwd()` and is the base for relative path resolution; `env: ToolEnv` (`{ cwd, config }`) is established at construction and used by `refresh()` to instantiate built-in tools. **Tools no longer depend on the global `process.cwd()`**; each Provider can be bound to a different working directory
63
+ - **Conversation/draft product layer removed** — `Conversation` / `Draft` types, `ConversationRepository`, `DraftRepository`, `AutoDraftPlugin`, and their tests were all removed. Conversation and draft persistence are delegated to each consumer (CLI/Desktop), which may reuse `EntityRepository`
64
+ - **`index.ts` export changes** — removed `Conversation`/`Draft`/`ConversationRepository`/`DraftRepository`/`AutoDraftPlugin`/`BUILTIN_TOOLS`/`execAsyncTool`/`sleepTool`/`createGenerateImageTool`; added `ToolEnv`, `SdkCallbackTool`, `BUILTIN_TOOL_CLASSES`, `GenerateImageTool`, and the 17 tool classes
48
65
 
49
- ### 🚀 新功能
66
+ ### 🚀 New Features
50
67
 
51
- - **`ToolEnv` 接口** — 工具环境 `{ cwd, config }`,在工具构造时注入,作为相对路径解析与配置读取的基准
52
- - **`SdkCallbackTool` 抽象基类** — `env` 构造注入 + 子类实现 `call()` + `exec()` 桥接 + `resolve()` 相对路径解析(public,便于测试直调)
68
+ - **`ToolEnv` interface** — tool environment `{ cwd, config }`, injected at tool construction, serving as the base for relative path resolution and config reads
69
+ - **`SdkCallbackTool` abstract base** — `env` constructor injection + subclass `call()` + `exec()` bridge + `resolve()` relative path resolution (public, easy to call directly in tests)
53
70
 
54
- ### 🎯 优化
71
+ ### 🎯 Optimized
55
72
 
56
- - **多会话并行支持** — `cwd` 下沉到 Provider(`ToolEnv.cwd`),多个 Provider 可并行服务不同工作目录的会话,互不干扰
57
- - **工具实例 per-Provider** — 每个 Provider 通过 `discoverBuiltinTools(env)` 实例化自己的一套工具,消除全局单例状态
73
+ - **Multi-session parallelism** — `cwd` moved down to the Provider (`ToolEnv.cwd`); multiple Providers can serve sessions in different working directories in parallel without interference
74
+ - **Per-Provider tool instances** — each Provider instantiates its own set of tools via `discoverBuiltinTools(env)`, eliminating global singleton state
58
75
 
59
76
  ## [0.4.0] - 2026-07-29
60
77
 
61
- ### 💥 破坏性变更
78
+ ### 💥 Breaking Changes
62
79
 
63
- - **`load_mcp` 返回值从纯文本改为结构化 JSON** — 现在返回 `{ tools, resources }`,其中 tools 包含完整的 `inputSchema`(参数 JSON Schema),resources 包含 `uri`、`name`、`description`、`mimeType`。LLM 可获得精确的参数结构信息,不再需要靠描述文字猜测参数格式
64
- - **`load_mcp` 不再返回 `prompts` 字段** — prompts 属于 UI 层用途,不对 Agent 暴露
65
- - **`createLogger()` 替换为全局单例 `getLogger()` / `setLogger()`** — 日志不再支持多例,SDK 内部所有模块统一通过 `getLogger()` 获取同一实例
66
- - **`index.ts` 导出变更** — `createLogger` → `getLogger` / `setLogger`
80
+ - **`load_mcp` return value changed from plain text to structured JSON** — now returns `{ tools, resources }`, where tools include the complete `inputSchema` (parameter JSON Schema) and resources include `uri`, `name`, `description`, `mimeType`. The LLM gets precise parameter structure instead of guessing from description text
81
+ - **`load_mcp` no longer returns a `prompts` field** — prompts are for the UI layer and are not exposed to Agents
82
+ - **`createLogger()` replaced with the global singletons `getLogger()` / `setLogger()`** — logging no longer supports multiple instances; all SDK-internal modules uniformly obtain the same instance via `getLogger()`
83
+ - **`index.ts` export changes** — `createLogger` → `getLogger` / `setLogger`
67
84
 
68
- ### 🎯 优化
85
+ ### 🎯 Optimized
69
86
 
70
- - **`load_mcp` 连接成功后在日志中打印完整 manifest** — 包含 tools、resources、prompts 的完整 JSON,便于调试排查
71
- - **SDK 内部日志统一** — `mcps.ts`、`skills.ts`、`usertools.ts`、`McpConnectionManager.ts` 中的 `console.warn`/`console.error` 全部改为 `getLogger().warn`/`getLogger().error`
87
+ - **`load_mcp` prints the full manifest to the log after a successful connection** — complete JSON with tools, resources, and prompts, for easier debugging
88
+ - **SDK-internal logging unified** — `console.warn`/`console.error` in `mcps.ts`, `skills.ts`, `usertools.ts`, and `McpConnectionManager.ts` all changed to `getLogger().warn`/`getLogger().error`
72
89
 
73
90
  ## [0.3.4] - 2026-07-27
74
91
 
75
- ### 🎯 优化
92
+ ### 🎯 Optimized
76
93
 
77
- - **`AutoMigratePlugin` 钩子重命名** — `onHandoff` → `onMigrated`,语义更清晰:迁移前用 `onBeforeMigrate`(此时 `agent.messages` 仍是完整旧历史),迁移完成后用 `onMigrated`(交接文档已注入)
78
- - **`conversation-runner.ts` 保存逻辑修正** — 将保存旧对话从 `onMigrated`(原 `onHandoff`)移至 `onBeforeMigrate`,确保保存的是完整的旧对话历史,而非迁移后的新消息
94
+ - **`AutoMigratePlugin` hook renamed** — `onHandoff` → `onMigrated`, with clearer semantics: use `onBeforeMigrate` before migration (at which point `agent.messages` is still the full old history) and `onMigrated` after migration completes (the handoff document has been injected)
95
+ - **`conversation-runner.ts` save logic fixed** — saving the old conversation moved from `onMigrated` (formerly `onHandoff`) to `onBeforeMigrate`, ensuring the complete old conversation history is saved rather than the post-migration new messages
79
96
 
80
97
  ## [0.3.3] - 2026-07-27
81
98
 
82
- ### 🎯 优化
99
+ ### 🎯 Optimized
83
100
 
84
- - **默认 SubAgent System Prompt 新增两条强制性要求**:
85
- 1. 信息不明确/模糊/缺失时拒绝执行,要求补充
86
- 2. 存在自相矛盾信息时指出矛盾,要求澄清
87
- - **默认 Agent System Prompt 新增原则**:"有矛盾就问 — 如果用户指令中存在自相矛盾之处,应指出矛盾并请求澄清,而不是自行取舍"
88
- - **默认 SubAgent `function.description` 和 `task` 参数描述**同步更新,强调不明确信息将导致拒绝执行
101
+ - **Default SubAgent System Prompt gains two mandatory requirements**:
102
+ 1. Refuse to execute when information is unclear/ambiguous/missing; ask for clarification
103
+ 2. Point out contradictions when conflicting information is present; ask for clarification
104
+ - **Default Agent System Prompt adds a principle**: "Ask when contradictory — if the user's instructions contain contradictions, point them out and request clarification instead of deciding on your own"
105
+ - **Default SubAgent `function.description` and `task` parameter description** updated in sync, emphasizing that unclear information will lead to refusal
89
106
 
90
107
  ## [0.3.2] - 2026-07-26
91
108
 
92
- ### 💥 破坏性变更
109
+ ### 💥 Breaking Changes
93
110
 
94
- - **`EntityRepository` 所有方法改为异步** — `list()`、`read()`、`write()`、`delete()` 现在返回 `Promise`,需 `await`
95
- - **`DraftRepository` 所有方法改为异步** — `read()`、`write()`、`delete()` 需 `await`
96
- - **`ConfigManager` 所有方法改为异步** — `read()`、`write()`、`ensureDirs()`、`ensureDefaultAgent()`、`ensureDefaultSubAgent()`、`ensureDefaultConfig()`、`bootstrap()` 均需 `await`
97
- - **`createAgent()` 恢复为 `async`** — 因底层仓储改为异步,`createAgent(provider, agentId)` 需 `await`
98
- - **`AutoDraftPlugin.checkDraftForRestore()` 改为异步** — 需 `await`
111
+ - **All `EntityRepository` methods are now async** — `list()`, `read()`, `write()`, `delete()` now return `Promise`, requiring `await`
112
+ - **All `DraftRepository` methods are now async** — `read()`, `write()`, `delete()` require `await`
113
+ - **All `ConfigManager` methods are now async** — `read()`, `write()`, `ensureDirs()`, `ensureDefaultAgent()`, `ensureDefaultSubAgent()`, `ensureDefaultConfig()`, `bootstrap()` all require `await`
114
+ - **`createAgent()` is `async` again** — as the underlying repositories became async, `createAgent(provider, agentId)` requires `await`
115
+ - **`AutoDraftPlugin.checkDraftForRestore()` is now async** — requires `await`
99
116
 
100
- ### 🎯 优化
117
+ ### 🎯 Optimized
101
118
 
102
- - **全面消除同步文件 IO** — 所有生产代码中的 `existsSync`、`readFileSync`、`writeFileSync`、`readdirSync`、`mkdirSync`、`unlinkSync`、`renameSync` 全部替换为 `fs.promises` 异步 API,避免事件循环阻塞
103
- - **`skillTools.ts` — 工具回调中的 `readdirSync` 替换为 `fs.promises.readdir`**
119
+ - **Synchronous file I/O fully eliminated** — all `existsSync`, `readFileSync`, `writeFileSync`, `readdirSync`, `mkdirSync`, `unlinkSync`, `renameSync` in production code replaced with the `fs.promises` async API, avoiding event-loop blocking
120
+ - **`skillTools.ts`** — `readdirSync` in the tool callback replaced with `fs.promises.readdir`
104
121
 
105
- ### ✅ 测试
122
+ ### ✅ Tests
106
123
 
107
- - 7 个测试文件同步更新为 `async`/`await`,测试辅助函数也使用 `fs.promises`
124
+ - 7 test files updated in sync to `async`/`await`; test helpers also use `fs.promises`
108
125
 
109
126
  ## [0.3.1] - 2026-07-26
110
127
 
111
- ### 💥 破坏性变更
128
+ ### 💥 Breaking Changes
112
129
 
113
- - **`Provider` 移至 `runtime`,合并 `Capabilities`** — 删除 `capabilities/Capabilities.ts` 和原 `runtime/Provider.ts`,Provider 直接暴露 `filter()`、`buildTools()`、`instantiate()`、`refresh()`
114
- - **去除 `getMcpManager()` 方法** — `mcpManager` 从 lazy getter 改为构造时直接 `new McpConnectionManager()`(有 mcpPaths 时),`readonly` 属性
115
- - **字段重命名** — `builtinInstances` → `builtinTools`,`userInstances` → `userTools`,`subagentDefs` → `subagents`
116
- - **`createModel` 签名变更** — 从 `createModel(config, modelId)` 改为 `createModel(provider, modelId)`,调用方不再需要 `.config` 解构
117
- - **`SdkAgent` 去掉 `caps` 字段** — 只保留 `provider`
130
+ - **`Provider` moved to `runtime`, merging `Capabilities`** — deleted `capabilities/Capabilities.ts` and the original `runtime/Provider.ts`; Provider now directly exposes `filter()`, `buildTools()`, `instantiate()`, `refresh()`
131
+ - **`getMcpManager()` removed** — `mcpManager` changed from a lazy getter to being constructed directly as `new McpConnectionManager()` (when mcpPaths exist), a `readonly` property
132
+ - **Field renames** — `builtinInstances` → `builtinTools`, `userInstances` → `userTools`, `subagentDefs` → `subagents`
133
+ - **`createModel` signature changed** — from `createModel(config, modelId)` to `createModel(provider, modelId)`; callers no longer need the `.config` destructure
134
+ - **`SdkAgent` drops the `caps` field** — only `provider` remains
118
135
 
119
- ### 🚀 新功能
136
+ ### 🚀 New Features
120
137
 
121
- - **用户工具 ESM 支持** — 移除 `node:vm` 沙箱,统一使用 `import()` 加载 `.js` / `.mjs` 文件,每次 `refresh()` 加时间戳 querystring 防止缓存
122
- - **`CallbackTool` 替代 `createToolFromObject`** — `{ function, exec }` 格式直接映射为 `CallbackTool`
138
+ - **User tool ESM support** — removed the `node:vm` sandbox, uniformly using `import()` to load `.js` / `.mjs` files; each `refresh()` appends a timestamp querystring to prevent caching
139
+ - **`CallbackTool` replaces `createToolFromObject`** — the `{ function, exec }` format maps directly to `CallbackTool`
123
140
 
124
- ### 🎯 优化
141
+ ### 🎯 Optimized
125
142
 
126
- - **默认 Agent 系统提示词更新** — 精简为五条原则:开动脑筋、实事求是、一切行动听指挥、安全第一、能打胜仗
127
- - **默认 SubAgent `function.description` 优化** — 强调主 Agent 必须提供完整任务上下文
143
+ - **Default Agent system prompt updated** — condensed to five principles: think hard, be truthful, follow instructions, safety first, win battles
144
+ - **Default SubAgent `function.description` optimized** — emphasizes that the main Agent must provide complete task context
128
145
 
129
- ### 🗑 移除
146
+ ### 🗑 Removed
130
147
 
131
- - 删除 `capabilities/Provider.ts`(已移回 `runtime/Provider.ts`)
132
- - 删除 `createToolFromObject` 工具函数
133
- - 删除 `TODO.md`、`TODO2.md`
134
- - 测试 fixture 从 `.js` 迁移为 `.mjs`
148
+ - Deleted `capabilities/Provider.ts` (moved back to `runtime/Provider.ts`)
149
+ - Deleted the `createToolFromObject` utility function
150
+ - Deleted `TODO.md` and `TODO2.md`
151
+ - Test fixtures migrated from `.js` to `.mjs`
135
152
 
136
153
  ## [0.2.6] - 2026-07-20
137
154
 
138
- ### 🔧 修复
155
+ ### 🔧 Fixed
139
156
 
140
- - **默认 SubAgent 函数名和描述不足以让 LLM 识别为子 Agent** — `function.name` 从 `general_assistant` 改为 `sub_agent_default`,`function.description` 重写为详细描述,明确子 Agent 身份和能力边界。参数名 `query` → `task` 与设计规范统一,system prompt 明确角色定位
141
- - **`DEFAULT_SUBAGENT_ID` 从 `general-assistant` 改为 `sub-agent-default`** — 文件名与函数名对应,便于识别
157
+ - **Default SubAgent function name and description insufficient for the LLM to recognize it as a sub-agent** — `function.name` changed from `general_assistant` to `sub_agent_default`; `function.description` rewritten with detailed wording, clarifying the sub-agent identity and capability boundary. The parameter name changed from `query` to `task` to align with the design spec; the system prompt clarifies the role
158
+ - **`DEFAULT_SUBAGENT_ID` changed from `general-assistant` to `sub-agent-default`** — filename matches the function name for easy recognition
142
159
 
143
160
  ## [0.2.5] - 2026-07-20
144
161
 
145
- ### 🔧 修复
162
+ ### 🔧 Fixed
146
163
 
147
- - **`DEFAULT_SUBAGENT_DEFINITION` 缺少 `permissions` 配置** — 默认 SubAgent `general-assistant` 未配置权限,导致所有维度等同于 `deny: ['*']`,完全无法使用任何工具/skill/MCP/SubAgent。现已按设计规范补全,仅 `subagents` 维度设为 `deny: ['*']` 防止递归调用
164
+ - **`DEFAULT_SUBAGENT_DEFINITION` missing `permissions` config** — the default SubAgent `general-assistant` had no permissions, so every dimension effectively became `deny: ['*']`, making it completely unable to use any tool/skill/MCP/SubAgent. Now completed per the design spec, with only the `subagents` dimension set to `deny: ['*']` to prevent recursive calls
148
165
 
149
166
  ## [0.2.4] - 2026-07-20
150
167
 
151
- ### 🔧 修复
168
+ ### 🔧 Fixed
152
169
 
153
- - **`load_skill` 不再注入 System 消息** — 改为在工具返回值中直接返回完整 SKILL.md 内容和 Skill 目录路径、文件列表,LLM 完全透明可见
154
- - **`SkillInfo` 新增 `dirPath` 字段** — 记录 SKILL.md 所在目录的绝对路径
155
- - **`McpConnectionManager.doConnect` 按 Server capabilities 按需调用** — 仅对声明了的能力调用对应方法,避免未声明时返回 Method not found
156
- - **`McpConnectionManager.doConnect` 各 list 调用加 try/catch 保护** — 单个能力获取失败不影响其他能力
170
+ - **`load_skill` no longer injects a System message** — instead returns the full SKILL.md content plus the Skill directory path and file list directly in the tool return value, fully transparent to the LLM
171
+ - **`SkillInfo` gains a `dirPath` field** — records the absolute path of the directory containing SKILL.md
172
+ - **`McpConnectionManager.doConnect` calls methods on demand per server capabilities** — only invokes the corresponding method for declared capabilities, avoiding Method not found for undeclared ones
173
+ - **`McpConnectionManager.doConnect` wraps each list call in try/catch** — a failure to fetch one capability does not affect the others
157
174
 
158
175
  ## [0.2.3] - 2026-07-20
159
176
 
160
- ### 🔧 修复
177
+ ### 🔧 Fixed
161
178
 
162
- - **`AgentRepository` — 使用 `EntityRepository` 替代直接文件操作** — 采用基础仓储统一逻辑
179
+ - **`AgentRepository` — uses `EntityRepository` instead of direct file operations** — adopting the base repository for unified logic
163
180
 
164
181
  ## [0.2.2] - 2026-07-20
165
182
 
166
- ### 🔧 修复
183
+ ### 🔧 Fixed
167
184
 
168
- - **`SdkAgent.send()` — `ctx.messages` 不再直接引用 `this.messages`** — 改为浅拷贝快照,确保消息数组仅由 agent 作为唯一维护者
169
- - **`AutoMigratePlugin` — 不再创建新 Agent 实例** — 直接替换 `agent.messages` 数组,保留所有引用、插件绑定和事件监听
170
- - **`AutoMigratePlugin` — 迁移前增加日志提示** — 使用 `log.warn` 输出迁移开始通知
185
+ - **`SdkAgent.send()` — `ctx.messages` no longer references `this.messages` directly** — changed to a shallow-copied snapshot, ensuring the message array is owned solely by the agent
186
+ - **`AutoMigratePlugin` — no longer creates a new Agent instance** — directly replaces the `agent.messages` array, preserving all references, plugin bindings, and event listeners
187
+ - **`AutoMigratePlugin` — adds a log notice before migration** — uses `log.warn` to output the migration start notice
171
188
 
172
- ### 🎯 优化
189
+ ### 🎯 Optimized
173
190
 
174
- - **`AutoMigratePlugin` — `onHandoff` 签名简化** — 从 `(doc, oldAgent, newAgent)` 改为 `(doc, agent)`,因为 agent 是同一对象
175
- - **`TaskMigrationService.createPrompt()` — 精简提示词** — 明确要求只输出交接文档,不做任何解释
191
+ - **`AutoMigratePlugin` — `onHandoff` signature simplified** — from `(doc, oldAgent, newAgent)` to `(doc, agent)`, since the agent is the same object
192
+ - **`TaskMigrationService.createPrompt()` — streamlined prompt** — explicitly requires only the handoff document as output, no explanations
176
193
 
177
- ### ✅ 测试
194
+ ### ✅ Tests
178
195
 
179
- - 补充迁移前后消息数组**长度精确断言**(迁移前 3 条 → 迁移后 2 条)
180
- - 补充迁移失败时消息数组**长度和内容不变**的断言
196
+ - Added exact assertions for the message array **length before/after migration** (3 before → 2 after)
197
+ - Added assertions that the message array **length and content stay unchanged** on migration failure
package/README.md CHANGED
@@ -1,11 +1,12 @@
1
1
  # @ai-zen/agents-sdk
2
2
 
3
- AI-Zen SDK — 共享业务逻辑层,为 CLI 和 Desktop 提供统一的 Agent 运行时。开箱即用,包含预置厂商配置、默认 Agent 和 SubAgent。
3
+ AI-Zen SDK — shared business logic layer providing a unified Agent runtime for CLI and Desktop. Works out of the box, with preconfigured vendor settings, a default Agent, and a default SubAgent.
4
4
 
5
- ## 真相源
5
+ ## Source of Truth
6
6
 
7
- **[`docs/sdk-design.md`](./docs/sdk-design.md)** 是本包的唯一设计真相源。所有实现必须与文档一致。
8
- ## 架构
7
+ **[`docs/sdk-design.md`](./docs/sdk-design.md)** is the single source of truth for this package's design. All implementations must stay consistent with the document.
8
+
9
+ ## Architecture
9
10
 
10
11
  ```
11
12
  CLI ──┐
@@ -14,36 +15,36 @@ Desktop ──┘ │
14
15
  LLM API
15
16
  ```
16
17
 
17
- ## 模块分层
18
+ ## Module Layering
18
19
 
19
20
  ```
20
- types ← 纯类型,零业务依赖(含 ToolEnv 工具环境)
21
- config ← 读写 config.json + 迁移 + 内存缓存 + 原子写入
22
- crud ← 能力实体 CRUD(Agent 定义等;会话/草稿已下放给各端自行持久化)
23
- capabilities ← 能力发现与装配(内置 + 用户 + MCP + Skill + SubAgent)
24
- runtime ← Provider + 模型工厂 + Agent 组装 + MCP 连接管理 + 任务迁移 + SdkCallbackTool 工具基类
25
- plugin ← Agent 插件(autoMigrate、autoRefreshTools)
26
- shared ← 日志、错误
21
+ types ← pure types, zero business dependencies (incl. ToolEnv)
22
+ config ← read/write config.json + migration + in-memory cache + atomic writes
23
+ crud ← capability-entity CRUD (Agent definitions, etc.; conversations/drafts are persisted by each consumer)
24
+ capabilities ← capability discovery & assembly (built-in + user + MCP + Skill + SubAgent)
25
+ runtime ← Provider + model factory + Agent assembly + MCP connection management + task migration + SdkCallbackTool base
26
+ plugin ← Agent plugins (autoMigrate, autoRefreshTools)
27
+ shared ← logging, errors
27
28
  ```
28
29
 
29
- 依赖方向:`plugin → runtime → capabilities → crud → config → types`,上层依赖下层,反之不行。
30
+ Dependency direction: `plugin → runtime → capabilities → crud → config → types`. Upper layers depend on lower layers, never the other way around.
30
31
 
31
- ## 核心概念
32
+ ## Core Concepts
32
33
 
33
- | 实体 | 说明 |
34
- |------|------|
35
- | **Provider** | 全局上下文 + 能力注册表,持有配置、路径(含 `cwd`)、模型工厂、MCP 管理器,整合发现 → 过滤 → 实例化 |
36
- | **ToolEnv** | 工具环境 `{ cwd, config }`,Provider 实例化内置工具时注入,作为相对路径解析与配置读取的基准 |
37
- | **SdkCallbackTool** | 内置工具抽象基类:`env` 构造注入 + 子类实现 `call()` + `resolve()` 相对路径解析 |
38
- | **SdkAgent** | 继承 Core Agent,携带 SDK 元数据,支持 `use()` 插件注册 |
39
- | **AgentPlugin** | 插件接口(`onInit`, `onBeforeSend`, `onAfterSend`, `onInnerLoopStart`, `onInnerLoopEnd`) |
40
- | **Endpoint** | API 端点(baseUrl + apiKey) |
41
- | **Model** | 模型配置,绑定 Endpoint |
42
- | **SubAgent** | 有 `function` 字段的 Agent,可被其他 Agent 作为工具调用 |
34
+ | Entity | Description |
35
+ |--------|-------------|
36
+ | **Provider** | Global context + capability registry, holding config, paths (incl. `cwd`), model factory, and MCP manager; integrates discovery → filtering → instantiation |
37
+ | **ToolEnv** | Tool environment `{ cwd, config }`; injected when the Provider instantiates built-in tools, serving as the base for relative path resolution and config reads |
38
+ | **SdkCallbackTool** | Abstract base for built-in tools: `env` constructor injection + subclass `call()` + `resolve()` relative path resolution |
39
+ | **SdkAgent** | Extends the Core Agent, carries SDK metadata, supports `use()` plugin registration |
40
+ | **AgentPlugin** | Plugin interface (`onInit`, `onBeforeSend`, `onAfterSend`, `onInnerLoopStart`, `onInnerLoopEnd`) |
41
+ | **Endpoint** | API endpoint (baseUrl + apiKey) |
42
+ | **Model** | Model config, bound to an Endpoint |
43
+ | **SubAgent** | An Agent with a `function` field, callable by other Agents as a tool |
43
44
 
44
- ## 权限模型
45
+ ## Permission Model
45
46
 
46
- 四维度各自独立,allow/deny 互斥,无命中即拒绝,权限即披露(deny 掉的项对 LLM 完全不可见)。
47
+ The four dimensions are independent; allow/deny are mutually exclusive, no match means deny, and permission is disclosure (denied items are completely invisible to the LLM).
47
48
 
48
49
  ```
49
50
  Agent.permissions
@@ -53,79 +54,79 @@ Agent.permissions
53
54
  └── subagents: { allow: string[] } | { deny: string[] }
54
55
  ```
55
56
 
56
- ## 消费模式
57
+ ## Consumption
57
58
 
58
59
  ```typescript
59
60
  const provider = await Provider.create({
60
61
  config,
61
- cwd: "/path/to/workspace", // 每个 Provider 一个工作目录,多会话并行互不干扰
62
+ cwd: "/path/to/workspace", // one working directory per Provider; parallel sessions don't interfere
62
63
  ...paths,
63
64
  });
64
65
  const agent = createAgent(provider, "my-agent");
65
66
  agent.use(new AutoMigratePlugin({ maxTokens, migrationAgent, onMigrated }));
66
67
  agent.use(new AutoRefreshToolsPlugin());
67
68
  await agent.init();
68
- await agent.send("你好");
69
+ await agent.send("Hello");
69
70
  ```
70
71
 
71
- ## 开发状态
72
-
73
- | 模块 | 状态 |
74
- |------|------|
75
- | `types` | ✅ 已实现 — 核心实体、权限模型、MCP 类型完整 |
76
- | `config` | ✅ 已实现 — ConfigManager + 出厂默认配置 + 一键 bootstrap |
77
- | `crud` | ✅ 已实现 — Agent 等能力实体 CRUD(会话/草稿由各端自行持久化) |
78
- | `capabilities` | ✅ 已实现 — 发现 + 权限过滤 + 安全预过滤 + 枚举披露 |
79
- | `runtime` | ✅ 已实现 — Provider、Capabilities、createAgent、MCP 连接管理、任务迁移 |
80
- | `plugin` | ✅ 已实现 — AutoMigratePlugin / AutoRefreshToolsPlugin |
81
- | `shared` | ✅ 已实现 — SdkError + 可注入 Logger |
82
- | 测试 | ✅ 409 个测试,47 个文件,全通过(含真实 API 聊天 e2e) |
83
-
84
- ## 内置工具
85
-
86
- 内置工具全部类化(继承 `SdkCallbackTool`),由 Provider 用 `ToolEnv` 实例化——每个 Provider 一套实例,`cwd` 注入,相对路径以 `Provider.cwd` 为基准,不依赖全局 `process.cwd()`。
87
-
88
- | 工具 | 说明 |
89
- |------|------|
90
- | `cwd` | 获取当前工作目录 |
91
- | `readFile` | 读取文件 |
92
- | `writeFile` | 写入文件 |
93
- | `exec` | 执行命令(支持 `timeout` 超时参数) |
94
- | `exec_async` | 异步执行命令,启动后立即返回,不等待结果 |
95
- | `mkdir` | 创建目录 |
96
- | `rm` | 删除文件或目录 |
97
- | `glob` | 使用 glob 模式扫描查找文件 |
98
- | `ls` | 列出目录内容 |
99
- | `exist` | 检查文件或目录是否存在 |
100
- | `findText` | 在文件中搜索文本或正则 |
101
- | `downloadFile` | 从 URL 下载文件并保存到本地 |
102
- | `rename` | 重命名或移动文件/目录 |
103
- | `copy` | 复制文件或目录 |
104
- | `batchEdit` | 批量编辑文件文本 |
105
- | `edit` | 编辑文件中的文本 |
106
- | `sleep` | 等待指定毫秒数后继续 |
107
-
108
- 条件注入(`GenerateImageTool` 需配置 `defaultImageModel` 才注册):
109
-
110
- | 工具 | 说明 |
111
- |------|------|
112
- | `generateImage` | 根据文字描述生成图片 |
113
-
114
- ## 内置插件
115
-
116
- | 插件 | 说明 |
117
- |------|------|
118
- | `AutoMigratePlugin` | 上下文超限时自动触发任务迁移,生成交接文档,透明替换 Agent |
119
- | `AutoRefreshToolsPlugin` | 每次 `send()` 前重新扫描文件系统,刷新工具列表 |
120
-
121
- ## 设计原则
122
-
123
- 参见项目根 [`GOAL.md`](../../GOAL.md):
124
-
125
- 1. 逻辑自洽
126
- 2. 设计为先,文档为准
127
- 3. 对称、统一
128
- 4. 去除过度设计
129
- 5. 奥卡姆剃刀
130
- 6. 即时重构,保持分层
131
- 7. 测试是基石
72
+ ## Development Status
73
+
74
+ | Module | Status |
75
+ |--------|--------|
76
+ | `types` | ✅ Implemented — core entities, permission model, MCP types complete |
77
+ | `config` | ✅ Implemented — ConfigManager + factory defaults + one-shot bootstrap |
78
+ | `crud` | ✅ Implemented — capability-entity CRUD for Agents, etc. (conversations/drafts persisted by each consumer) |
79
+ | `capabilities` | ✅ Implemented — discovery + permission filtering + safe pre-filtering + enumeration disclosure |
80
+ | `runtime` | ✅ Implemented — Provider, Capabilities, createAgent, MCP connection management, task migration |
81
+ | `plugin` | ✅ Implemented — AutoMigratePlugin / AutoRefreshToolsPlugin |
82
+ | `shared` | ✅ Implemented — SdkError + injectable Logger |
83
+ | Tests | ✅ 409 tests, 47 files, all passing (incl. real-API chat e2e) |
84
+
85
+ ## Built-in Tools
86
+
87
+ All built-in tools are classes (extending `SdkCallbackTool`), instantiated by the Provider with a `ToolEnv` — one set of instances per Provider, with `cwd` injected and relative paths resolved against `Provider.cwd`, never depending on the global `process.cwd()`.
88
+
89
+ | Tool | Description |
90
+ |------|-------------|
91
+ | `cwd` | Get the current working directory |
92
+ | `readFile` | Read a file |
93
+ | `writeFile` | Write a file |
94
+ | `exec` | Execute a command (supports `timeout`) |
95
+ | `exec_async` | Execute a command asynchronously, returns immediately without waiting |
96
+ | `mkdir` | Create a directory |
97
+ | `rm` | Delete a file or directory |
98
+ | `glob` | Scan and find files using glob patterns |
99
+ | `ls` | List directory contents |
100
+ | `exist` | Check whether a file or directory exists |
101
+ | `findText` | Search for text or regex in files |
102
+ | `downloadFile` | Download a file from a URL and save it locally |
103
+ | `rename` | Rename or move a file/directory |
104
+ | `copy` | Copy a file or directory |
105
+ | `batchEdit` | Batch-edit file text |
106
+ | `edit` | Edit text in a file |
107
+ | `sleep` | Wait for a specified number of milliseconds |
108
+
109
+ Conditionally injected (registered only when `defaultImageModel` is configured):
110
+
111
+ | Tool | Description |
112
+ |------|-------------|
113
+ | `generateImage` | Generate an image from a text description |
114
+
115
+ ## Built-in Plugins
116
+
117
+ | Plugin | Description |
118
+ |--------|-------------|
119
+ | `AutoMigratePlugin` | Automatically triggers task migration when the context overflows, generates a handoff document, and transparently replaces the Agent |
120
+ | `AutoRefreshToolsPlugin` | Re-scans the file system before each `send()` to refresh the tool list |
121
+
122
+ ## Design Principles
123
+
124
+ See the project-root [`PRINCIPLES.md`](../../PRINCIPLES.md):
125
+
126
+ 1. Logical consistency
127
+ 2. Design first, documentation as the source of truth
128
+ 3. Symmetry and uniformity
129
+ 4. No over-engineering
130
+ 5. Occam's razor
131
+ 6. Refactor as you go; keep clean layering
132
+ 7. Tests are the foundation
package/README.zh.md ADDED
@@ -0,0 +1,131 @@
1
+ # @ai-zen/agents-sdk
2
+
3
+ AI-Zen SDK — 共享业务逻辑层,为 CLI 和 Desktop 提供统一的 Agent 运行时。开箱即用,包含预置厂商配置、默认 Agent 和 SubAgent。
4
+
5
+ ## 真相源
6
+
7
+ **[`docs/sdk-design.md`](./docs/sdk-design.md)** 是本包的唯一设计真相源。所有实现必须与文档一致。
8
+ ## 架构
9
+
10
+ ```
11
+ CLI ──┐
12
+ ├── @ai-zen/agents-sdk ──┐
13
+ Desktop ──┘ │
14
+ LLM API
15
+ ```
16
+
17
+ ## 模块分层
18
+
19
+ ```
20
+ types ← 纯类型,零业务依赖(含 ToolEnv 工具环境)
21
+ config ← 读写 config.json + 迁移 + 内存缓存 + 原子写入
22
+ crud ← 能力实体 CRUD(Agent 定义等;会话/草稿已下放给各端自行持久化)
23
+ capabilities ← 能力发现与装配(内置 + 用户 + MCP + Skill + SubAgent)
24
+ runtime ← Provider + 模型工厂 + Agent 组装 + MCP 连接管理 + 任务迁移 + SdkCallbackTool 工具基类
25
+ plugin ← Agent 插件(autoMigrate、autoRefreshTools)
26
+ shared ← 日志、错误
27
+ ```
28
+
29
+ 依赖方向:`plugin → runtime → capabilities → crud → config → types`,上层依赖下层,反之不行。
30
+
31
+ ## 核心概念
32
+
33
+ | 实体 | 说明 |
34
+ |------|------|
35
+ | **Provider** | 全局上下文 + 能力注册表,持有配置、路径(含 `cwd`)、模型工厂、MCP 管理器,整合发现 → 过滤 → 实例化 |
36
+ | **ToolEnv** | 工具环境 `{ cwd, config }`,Provider 实例化内置工具时注入,作为相对路径解析与配置读取的基准 |
37
+ | **SdkCallbackTool** | 内置工具抽象基类:`env` 构造注入 + 子类实现 `call()` + `resolve()` 相对路径解析 |
38
+ | **SdkAgent** | 继承 Core Agent,携带 SDK 元数据,支持 `use()` 插件注册 |
39
+ | **AgentPlugin** | 插件接口(`onInit`, `onBeforeSend`, `onAfterSend`, `onInnerLoopStart`, `onInnerLoopEnd`) |
40
+ | **Endpoint** | API 端点(baseUrl + apiKey) |
41
+ | **Model** | 模型配置,绑定 Endpoint |
42
+ | **SubAgent** | 有 `function` 字段的 Agent,可被其他 Agent 作为工具调用 |
43
+
44
+ ## 权限模型
45
+
46
+ 四维度各自独立,allow/deny 互斥,无命中即拒绝,权限即披露(deny 掉的项对 LLM 完全不可见)。
47
+
48
+ ```
49
+ Agent.permissions
50
+ ├── tools: { allow: string[] } | { deny: string[] }
51
+ ├── skills: { allow: string[] } | { deny: string[] }
52
+ ├── mcps: { allow: string[] } | { deny: string[] }
53
+ └── subagents: { allow: string[] } | { deny: string[] }
54
+ ```
55
+
56
+ ## 消费模式
57
+
58
+ ```typescript
59
+ const provider = await Provider.create({
60
+ config,
61
+ cwd: "/path/to/workspace", // 每个 Provider 一个工作目录,多会话并行互不干扰
62
+ ...paths,
63
+ });
64
+ const agent = createAgent(provider, "my-agent");
65
+ agent.use(new AutoMigratePlugin({ maxTokens, migrationAgent, onMigrated }));
66
+ agent.use(new AutoRefreshToolsPlugin());
67
+ await agent.init();
68
+ await agent.send("你好");
69
+ ```
70
+
71
+ ## 开发状态
72
+
73
+ | 模块 | 状态 |
74
+ |------|------|
75
+ | `types` | ✅ 已实现 — 核心实体、权限模型、MCP 类型完整 |
76
+ | `config` | ✅ 已实现 — ConfigManager + 出厂默认配置 + 一键 bootstrap |
77
+ | `crud` | ✅ 已实现 — Agent 等能力实体 CRUD(会话/草稿由各端自行持久化) |
78
+ | `capabilities` | ✅ 已实现 — 发现 + 权限过滤 + 安全预过滤 + 枚举披露 |
79
+ | `runtime` | ✅ 已实现 — Provider、Capabilities、createAgent、MCP 连接管理、任务迁移 |
80
+ | `plugin` | ✅ 已实现 — AutoMigratePlugin / AutoRefreshToolsPlugin |
81
+ | `shared` | ✅ 已实现 — SdkError + 可注入 Logger |
82
+ | 测试 | ✅ 409 个测试,47 个文件,全通过(含真实 API 聊天 e2e) |
83
+
84
+ ## 内置工具
85
+
86
+ 内置工具全部类化(继承 `SdkCallbackTool`),由 Provider 用 `ToolEnv` 实例化——每个 Provider 一套实例,`cwd` 注入,相对路径以 `Provider.cwd` 为基准,不依赖全局 `process.cwd()`。
87
+
88
+ | 工具 | 说明 |
89
+ |------|------|
90
+ | `cwd` | 获取当前工作目录 |
91
+ | `readFile` | 读取文件 |
92
+ | `writeFile` | 写入文件 |
93
+ | `exec` | 执行命令(支持 `timeout` 超时参数) |
94
+ | `exec_async` | 异步执行命令,启动后立即返回,不等待结果 |
95
+ | `mkdir` | 创建目录 |
96
+ | `rm` | 删除文件或目录 |
97
+ | `glob` | 使用 glob 模式扫描查找文件 |
98
+ | `ls` | 列出目录内容 |
99
+ | `exist` | 检查文件或目录是否存在 |
100
+ | `findText` | 在文件中搜索文本或正则 |
101
+ | `downloadFile` | 从 URL 下载文件并保存到本地 |
102
+ | `rename` | 重命名或移动文件/目录 |
103
+ | `copy` | 复制文件或目录 |
104
+ | `batchEdit` | 批量编辑文件文本 |
105
+ | `edit` | 编辑文件中的文本 |
106
+ | `sleep` | 等待指定毫秒数后继续 |
107
+
108
+ 条件注入(`GenerateImageTool` 需配置 `defaultImageModel` 才注册):
109
+
110
+ | 工具 | 说明 |
111
+ |------|------|
112
+ | `generateImage` | 根据文字描述生成图片 |
113
+
114
+ ## 内置插件
115
+
116
+ | 插件 | 说明 |
117
+ |------|------|
118
+ | `AutoMigratePlugin` | 上下文超限时自动触发任务迁移,生成交接文档,透明替换 Agent |
119
+ | `AutoRefreshToolsPlugin` | 每次 `send()` 前重新扫描文件系统,刷新工具列表 |
120
+
121
+ ## 设计原则
122
+
123
+ 参见项目根 [`PRINCIPLES.md`](../../PRINCIPLES.md):
124
+
125
+ 1. 逻辑自洽
126
+ 2. 设计为先,文档为准
127
+ 3. 对称、统一
128
+ 4. 去除过度设计
129
+ 5. 奥卡姆剃刀
130
+ 6. 即时重构,保持分层
131
+ 7. 测试是基石
@@ -1,5 +1,5 @@
1
1
  import { Agent, type ChatCompletionModel } from "@ai-zen/agents-core";
2
- import type { AgentNS, Tool, UnknownToolContext } from "@ai-zen/agents-core";
2
+ import type { AgentNS, Tool, ToolCallContext, UnknownToolContext } from "@ai-zen/agents-core";
3
3
  import type { AgentDefinition, AgentPermissions } from "../types/index.js";
4
4
  import type { Provider } from "./Provider.js";
5
5
  /**
@@ -27,6 +27,9 @@ export interface SendContext {
27
27
  * onInnerLoopEnd: Agent 内循环结束后触发。由 Core Agent 在内循环中调用。
28
28
  * onInnerLoopsStart: Agent 整组内循环开始前触发(一次 send 仅一次)。由 Core Agent 在 run() 的 while 循环前调用。
29
29
  * onInnerLoopsEnd: Agent 整组内循环结束后触发(一次 send 仅一次)。由 Core Agent 在 run() 的 while 循环后调用。
30
+ * onToolCall: 单个工具调用执行前触发(对应 Core onToolCall 钩子)。
31
+ * 返回字符串 = 拒绝该工具(原因作为工具结果回给 LLM,工具不执行);
32
+ * 返回 undefined = 放行。多个插件按注册顺序调用,任一返回字符串即拒绝。
30
33
  */
31
34
  export interface AgentPlugin {
32
35
  /** Agent.init() 时调用,用于异步初始化 */
@@ -43,6 +46,12 @@ export interface AgentPlugin {
43
46
  onInnerLoopsStart?(ctx: SendContext): Promise<void>;
44
47
  /** Agent 整组内循环结束后触发(一次 send 仅一次) */
45
48
  onInnerLoopsEnd?(ctx: SendContext): Promise<void>;
49
+ /**
50
+ * 单个工具调用执行前触发(对应 Core onToolCall 钩子,收同一个 ToolCallContext 实例)。
51
+ * 返回字符串 = 拒绝该工具(不执行,原因作为工具结果回给 LLM,继续下一轮);
52
+ * 返回 undefined = 放行。多个插件按注册顺序调用,任一返回字符串即拒绝。
53
+ */
54
+ onToolCall?(ctx: ToolCallContext): string | undefined | Promise<string | undefined>;
46
55
  }
47
56
  /**
48
57
  * SDK Agent — 继承 Core Agent,携带 SDK 层额外信息。
@@ -120,11 +120,21 @@ export class SdkAgent extends Agent {
120
120
  await plugin.onInnerLoopsEnd?.(ctx);
121
121
  }
122
122
  };
123
+ // 工具调用拦截:任一插件返回字符串即拒绝该工具(短路),全部放行则返回 undefined
124
+ this.onToolCall = async (ctx) => {
125
+ for (const plugin of this._plugins) {
126
+ const denied = await plugin.onToolCall?.(ctx);
127
+ if (denied !== undefined)
128
+ return denied;
129
+ }
130
+ return undefined;
131
+ };
123
132
  await super.send(content);
124
133
  this.onInnerLoopStart = undefined;
125
134
  this.onInnerLoopEnd = undefined;
126
135
  this.onInnerLoopsStart = undefined;
127
136
  this.onInnerLoopsEnd = undefined;
137
+ this.onToolCall = undefined;
128
138
  for (const plugin of this._plugins) {
129
139
  await plugin.onAfterSend?.(ctx);
130
140
  }
@@ -1,4 +1,4 @@
1
- import { Tool, FunctionCallContext } from "@ai-zen/agents-core";
1
+ import { Tool, ToolCallContext } from "@ai-zen/agents-core";
2
2
  import type { AgentNS } from "@ai-zen/agents-core";
3
3
  import type { ToolEnv } from "../types/index.js";
4
4
  /**
@@ -22,7 +22,7 @@ export declare abstract class SdkCallbackTool extends Tool {
22
22
  /** 工具核心逻辑(由子类实现,参数为 parsed_args) */
23
23
  abstract call(input: unknown): unknown | Promise<unknown>;
24
24
  /** 桥接 core 的 Tool.exec:解析参数 → call → 序列化 */
25
- exec(ctx: FunctionCallContext): Promise<string>;
25
+ exec(ctx: ToolCallContext): Promise<string>;
26
26
  /** 将相对路径解析到 env.cwd,绝对路径原样返回 */
27
27
  resolve(p: string): string;
28
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-zen/agents-sdk",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "AI-Zen Agents SDK — shared business logic for CLI and Desktop",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,7 +18,7 @@
18
18
  "dependencies": {
19
19
  "@modelcontextprotocol/sdk": "^1.29.0",
20
20
  "dayjs": "^1.11.21",
21
- "@ai-zen/agents-core": "^3.2.0"
21
+ "@ai-zen/agents-core": "^3.3.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^24.12.2",