@ai-zen/agents-sdk 0.10.0 → 0.11.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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.0] - 2026-09-28
4
+
5
+ ### 💥 Breaking Changes
6
+
7
+ - **`createCallSkillSubAgentTool` 移除第三参 `provider`** — Skill 子 Agent 不再经 `provider.buildTools(parent.definition, …)` 重新解析工具集,改为**直接沿用父 Agent 的工具集**(`ctx.agent.tools`),仅剔除 `call_skill_sub_agent` 自身:Skill 子 Agent 作为一次性对话分身,沿用调用者的能力而不再走第二遍权限过滤,同时避免 skill 链式自递归。传入 `Provider` 的调用方需删除该实参
8
+
9
+ ### 🚀 New Features
10
+
11
+ - **Skill 子 Agent 纳入统一委派边界** — `call_skill_sub_agent` 由 `AgentToolLazy` 承载(原为就地实现的 `CallbackTool`),因此与常规 SubAgent 工具共享同一套 `onSubAgentStart` / `onSubAgentEnd` 插件钩子与 `sub-agent-start` / `sub-agent-end` 事件。将护栏装配到 `ctx.subAgent` 的消费方(如上下文护栏)与渲染子 Agent 流式输出的消费方(如 CLI),自此均覆盖该路径
12
+
13
+ ### 🛠 Optimized
14
+
15
+ - **Skill 子 Agent 的构建收敛到 `buildAgent`** — 子 Agent 的初始消息(`System(SKILL.md 内容)` + `User(task)`)改由 `buildAgent` 决定(依托 core 4.3.0 的 `messages` 可选),原先手写的 abort 联动与返回值处理一并删除,交由工具基类统一实现
16
+ - **校验失败改为抛错** — `skill_id` 不存在、或 Skill 未声明 `sub-agent: true` 时抛出错误(原为返回提示文本);正常路径由 `skill_id` 枚举限定,不触发
17
+ - **依赖 `@ai-zen/agents-core` 升至 `^4.3.0`** — 依赖声明保持 `workspace:^`,由 pnpm 在发布时展开为 `^4.3.0`。core 4.3.0 使 `AgentToolLazy.messages` 变为可选
18
+
19
+ ### ✅ Tests
20
+
21
+ - `skillTools.test.ts` 中 `createCallSkillSubAgentTool` 用例重写为围绕 `AgentToolLazy`:工具契约不变、未知 Skill 抛错、非子 Agent Skill 抛错、委派边界(`onSubAgentStart` 与 `sub-agent-start` 分发、子 Agent 沿用父工具集且剔除自身、初始消息取自 SKILL.md 与 `task`);SDK 全量 **463 passed / 6 skipped**
22
+
3
23
  ## [0.10.0] - 2026-09-28
4
24
 
5
25
  ### 🚀 New Features
@@ -1,6 +1,5 @@
1
- import { CallbackTool } from "@ai-zen/agents-core";
1
+ import { CallbackTool, AgentToolLazy } from "@ai-zen/agents-core";
2
2
  import type { SkillInfo } from "../discovery/skills.js";
3
- import type { Provider } from "../../runtime/Provider.js";
4
3
  /**
5
4
  * 创建 load_skill 工具。
6
5
  * 枚举所有允许的 skill(不限是否支持子 Agent),由 filteredSkills 提供完整信息。
@@ -10,6 +9,9 @@ export declare function createLoadSkillTool(skillDirs: string[], filteredSkills:
10
9
  * 创建 call_skill_sub_agent 工具。
11
10
  * 只展示 subAgent: true 的 Skill,枚举中自动排除不支持子 Agent 模式的 skill。
12
11
  *
13
- * 回调中创建独立的 Skill 子 Agent,通过 caps 按父 Agent 权限独立解析工具集。
12
+ * 工具由 AgentToolLazy 承载:子 Agent 在 exec 时构建,从而复用统一的委派边界
13
+ * (onSubAgentStart / onSubAgentEnd 钩子与 sub-agent-start / sub-agent-end 事件)。
14
+ * 子 Agent 沿用父 Agent 的工具能力(不做权限过滤),但剔除 call_skill_sub_agent 自身,
15
+ * 避免 skill 链式自递归。
14
16
  */
15
- export declare function createCallSkillSubAgentTool(skillDirs: string[], filteredSkills: SkillInfo[], provider?: Provider): CallbackTool;
17
+ export declare function createCallSkillSubAgentTool(skillDirs: string[], filteredSkills: SkillInfo[]): AgentToolLazy;
@@ -1,5 +1,4 @@
1
- import { CallbackTool, Agent, Message } from "@ai-zen/agents-core";
2
- import { SdkAgent } from "../../runtime/SdkAgent.js";
1
+ import { CallbackTool, Agent, AgentToolLazy, Message } from "@ai-zen/agents-core";
3
2
  import { createDisclosureParam } from "../disclosure.js";
4
3
  import { readSkill } from "../discovery/skills.js";
5
4
  import { getLogger } from "../../shared/logger.js";
@@ -70,9 +69,12 @@ export function createLoadSkillTool(skillDirs, filteredSkills) {
70
69
  * 创建 call_skill_sub_agent 工具。
71
70
  * 只展示 subAgent: true 的 Skill,枚举中自动排除不支持子 Agent 模式的 skill。
72
71
  *
73
- * 回调中创建独立的 Skill 子 Agent,通过 caps 按父 Agent 权限独立解析工具集。
72
+ * 工具由 AgentToolLazy 承载:子 Agent 在 exec 时构建,从而复用统一的委派边界
73
+ * (onSubAgentStart / onSubAgentEnd 钩子与 sub-agent-start / sub-agent-end 事件)。
74
+ * 子 Agent 沿用父 Agent 的工具能力(不做权限过滤),但剔除 call_skill_sub_agent 自身,
75
+ * 避免 skill 链式自递归。
74
76
  */
75
- export function createCallSkillSubAgentTool(skillDirs, filteredSkills, provider) {
77
+ export function createCallSkillSubAgentTool(skillDirs, filteredSkills) {
76
78
  // 只保留支持子 Agent 模式的 skill
77
79
  const subAgentSkills = filteredSkills.filter((s) => s.subAgent);
78
80
  const ids = subAgentSkills.map((s) => s.id);
@@ -82,7 +84,7 @@ export function createCallSkillSubAgentTool(skillDirs, filteredSkills, provider)
82
84
  .map((s) => ` - ${s.id}: ${s.description || "无描述"}`)
83
85
  .join("\n");
84
86
  const skillIdDescription = `${param.description}\n\n各 Skill 说明:\n${skillDescriptions || " 无可用 Skill"}`;
85
- return new CallbackTool({
87
+ return new AgentToolLazy({
86
88
  function: {
87
89
  name: "call_skill_sub_agent",
88
90
  description: "将任务委派给指定的 Skill 子 Agent,由其独立完成并返回结果。",
@@ -103,46 +105,28 @@ export function createCallSkillSubAgentTool(skillDirs, filteredSkills, provider)
103
105
  additionalProperties: false,
104
106
  },
105
107
  },
106
- async callback(input, ctx) {
107
- const skillId = input.skill_id;
108
- const task = input.task;
108
+ // 初始消息依赖运行时参数(skill_id → SKILL.md 内容),故不传 messages 模板,
109
+ // 由 buildAgent 读取 SKILL.md 后自行决定;abort 联动与委派边界由 AgentToolLazy 统一处理
110
+ buildAgent: async (parsedArgs, ctx) => {
111
+ const skillId = parsedArgs.skill_id;
112
+ const task = parsedArgs.task;
109
113
  const skill = await readSkill(skillDirs, skillId);
110
114
  if (!skill) {
111
- return `❌ Skill "${skillId}" 不存在,请确认名称是否正确`;
115
+ throw new Error(`❌ Skill "${skillId}" 不存在,请确认名称是否正确`);
112
116
  }
113
117
  if (!skill.subAgent) {
114
- return `Skill "${skillId}" 不支持子 Agent 模式,请使用 load_skill 加载指导后自行处理`;
118
+ throw new Error(`Skill "${skillId}" 不支持子 Agent 模式,请使用 load_skill 加载指导后自行处理`);
115
119
  }
116
- // 临时 Skill 子 Agent 复用父 Agent 定义(权限 + 模型),排除当前 Skill 防自调用
120
+ // 沿用父 Agent 的工具能力(不做权限过滤),剔除自身以防自递归
117
121
  const parentAgent = ctx.agent;
118
- const skillTools = provider && parentAgent instanceof SdkAgent
119
- ? provider.buildTools(parentAgent.definition, {
120
- exclude: { skills: [skillId] },
121
- })
122
- : [];
123
- const subAgent = new Agent({
122
+ const tools = parentAgent.tools.filter((t) => t.function.name !== "call_skill_sub_agent");
123
+ return new Agent({
124
124
  client: parentAgent.client,
125
125
  model: parentAgent.model,
126
126
  modelConfig: parentAgent.modelConfig,
127
- messages: [
128
- Message.System(skill.content),
129
- Message.User(task),
130
- ],
131
- tools: skillTools,
127
+ messages: [Message.System(skill.content), Message.User(task)],
128
+ tools,
132
129
  });
133
- // 子 Agent 中断联动:外层 abort → subAgent.abort()
134
- const onAbort = () => subAgent.abort();
135
- if (ctx.signal) {
136
- ctx.signal.addEventListener("abort", onAbort, { once: true });
137
- }
138
- try {
139
- await subAgent.run();
140
- }
141
- finally {
142
- ctx.signal?.removeEventListener("abort", onAbort);
143
- }
144
- const lastMsg = subAgent.messages.at(-1);
145
- return typeof lastMsg?.content === "string" ? lastMsg.content : "";
146
130
  },
147
131
  });
148
132
  }
@@ -170,7 +170,7 @@ export class Provider {
170
170
  // call_skill_sub_agent:只要有支持子 Agent 的 skill 就注册
171
171
  const hasSubAgentSkills = filteredSkills.some((s) => s.subAgent);
172
172
  if (allowedToolNames.has("call_skill_sub_agent") && hasSubAgentSkills) {
173
- result.push(createCallSkillSubAgentTool(this.skillsPaths, filteredSkills, this));
173
+ result.push(createCallSkillSubAgentTool(this.skillsPaths, filteredSkills));
174
174
  }
175
175
  const mcpManager = this.mcpManager;
176
176
  if (allowedToolNames.has("load_mcp") && mcpManager && filteredMcps.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-zen/agents-sdk",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
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",
@@ -16,7 +16,7 @@
16
16
  "author": "LZQCN",
17
17
  "license": "MIT",
18
18
  "dependencies": {
19
- "@ai-zen/agents-core": "^4.2.0",
19
+ "@ai-zen/agents-core": "^4.3.0",
20
20
  "@modelcontextprotocol/sdk": "^1.29.0",
21
21
  "dayjs": "^1.11.21",
22
22
  "openai": "^7.5.0"