@ai-zen/agents-sdk 0.6.0 → 0.7.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +10 -7
  3. package/README.zh.md +10 -7
  4. package/dist/capabilities/discovery/builtin.d.ts +3 -3
  5. package/dist/capabilities/discovery/builtin.js +4 -12
  6. package/dist/capabilities/implements/builtin/GenerateImageTool.d.ts +8 -8
  7. package/dist/capabilities/implements/builtin/GenerateImageTool.js +26 -27
  8. package/dist/capabilities/implements/builtin/ViewImageTool.d.ts +24 -0
  9. package/dist/capabilities/implements/builtin/ViewImageTool.js +109 -0
  10. package/dist/capabilities/implements/builtin/index.d.ts +6 -4
  11. package/dist/capabilities/implements/builtin/index.js +8 -4
  12. package/dist/capabilities/implements/skillTools.js +5 -5
  13. package/dist/capabilities/implements/subAgentTools.js +17 -8
  14. package/dist/config/constants.js +12 -1
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +2 -0
  17. package/dist/plugin/AutoMigratePlugin.d.ts +1 -1
  18. package/dist/plugin/AutoMigratePlugin.js +1 -1
  19. package/dist/plugin/AutoRefreshToolsPlugin.d.ts +1 -1
  20. package/dist/plugin/AutoRefreshToolsPlugin.js +2 -2
  21. package/dist/plugin/ContextGuardPlugin.d.ts +2 -2
  22. package/dist/plugin/ContextGuardPlugin.js +1 -1
  23. package/dist/plugin/UnknownToolHintPlugin.d.ts +21 -0
  24. package/dist/plugin/UnknownToolHintPlugin.js +30 -0
  25. package/dist/runtime/Provider.d.ts +8 -7
  26. package/dist/runtime/Provider.js +14 -4
  27. package/dist/runtime/SdkAgent.d.ts +14 -107
  28. package/dist/runtime/SdkAgent.js +8 -120
  29. package/dist/runtime/SdkCallbackTool.d.ts +12 -4
  30. package/dist/runtime/SdkCallbackTool.js +5 -2
  31. package/dist/runtime/createAgent.js +4 -3
  32. package/dist/runtime/createModel.d.ts +17 -4
  33. package/dist/runtime/createModel.js +15 -11
  34. package/dist/types/index.d.ts +2 -0
  35. package/package.json +3 -2
@@ -1,10 +1,10 @@
1
- import type { AgentPlugin, SendContext } from "../runtime/SdkAgent.js";
1
+ import type { AgentPlugin, SendContext } from "@ai-zen/agents-core";
2
2
  export interface ContextGuardOptions {
3
3
  /** 上下文告警阈值(token)。用量超过 maxTokens × ratio 即中断。 */
4
4
  maxTokens: number;
5
5
  /**
6
6
  * 超出比例。用量 > maxTokens × ratio 时判定为「严重超限」(如读入超大文件),
7
- * 在请求前抛出 ContextOverflowError 中断对话。默认 1.2(即 +20%)。
7
+ * 在请求前抛出 ContextOverflowError 中断对话。默认 1.5(即 +50%)。
8
8
  */
9
9
  ratio?: number;
10
10
  }
@@ -25,7 +25,7 @@ export class ContextGuardPlugin {
25
25
  }
26
26
  async onInnerLoopStart(ctx) {
27
27
  const { agent } = ctx;
28
- const { maxTokens, ratio = 1.2 } = this.options;
28
+ const { maxTokens, ratio = 1.5 } = this.options;
29
29
  // 首轮请求前尚无用量数据,跳过(只能在发出首轮请求、拿到 usage 后才有据可查)
30
30
  const promptTokens = agent.lastUsage?.prompt_tokens;
31
31
  if (promptTokens == null)
@@ -0,0 +1,21 @@
1
+ import type { AgentPlugin, UnknownToolContext } from "@ai-zen/agents-core";
2
+ import type { Provider } from "../runtime/Provider.js";
3
+ /**
4
+ * 未知工具智能提示插件 — MCP 场景引导。
5
+ *
6
+ * 当 LLM 调用不存在的工具时,根据当前环境给出更智能的提示:
7
+ * - 有 MCP 配置但 `call_mcp_tool` 不在工具列表中(权限禁用)→ 提示权限问题
8
+ * - 有 MCP 配置且 `call_mcp_tool` 可用 → 提示使用 `call_mcp_tool`
9
+ * - 否则 → 仅提示工具不存在
10
+ *
11
+ * 由调用方显式注册(`agent.use(new UnknownToolHintPlugin({ provider }))`)。
12
+ * 未注册时,Agent 回落到底层的简单文本默认提示(core 内建)。
13
+ */
14
+ export declare class UnknownToolHintPlugin implements AgentPlugin {
15
+ /** 全局 Provider 实例 */
16
+ private readonly provider;
17
+ constructor(options: {
18
+ provider: Provider;
19
+ });
20
+ onUnknownTool(ctx: UnknownToolContext): string | undefined;
21
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 未知工具智能提示插件 — MCP 场景引导。
3
+ *
4
+ * 当 LLM 调用不存在的工具时,根据当前环境给出更智能的提示:
5
+ * - 有 MCP 配置但 `call_mcp_tool` 不在工具列表中(权限禁用)→ 提示权限问题
6
+ * - 有 MCP 配置且 `call_mcp_tool` 可用 → 提示使用 `call_mcp_tool`
7
+ * - 否则 → 仅提示工具不存在
8
+ *
9
+ * 由调用方显式注册(`agent.use(new UnknownToolHintPlugin({ provider }))`)。
10
+ * 未注册时,Agent 回落到底层的简单文本默认提示(core 内建)。
11
+ */
12
+ export class UnknownToolHintPlugin {
13
+ /** 全局 Provider 实例 */
14
+ provider;
15
+ constructor(options) {
16
+ this.provider = options.provider;
17
+ }
18
+ onUnknownTool(ctx) {
19
+ const toolName = ctx.toolCall.function?.name ?? "未知";
20
+ const hasMcpConfig = this.provider.mcpPaths.length > 0;
21
+ const hasCallMcpTool = ctx.availableTools.some((t) => t.function.name === "call_mcp_tool");
22
+ if (hasMcpConfig && !hasCallMcpTool) {
23
+ return `工具 "${toolName}" 不存在。当前有 MCP 服务器配置,但 call_mcp_tool 权限已被禁用,如需使用 MCP 工具请调整权限。`;
24
+ }
25
+ if (hasMcpConfig && hasCallMcpTool) {
26
+ return `工具 "${toolName}" 不存在。如果要调用 MCP 工具,请使用 call_mcp_tool。`;
27
+ }
28
+ return `工具 "${toolName}" 不存在。`;
29
+ }
30
+ }
@@ -1,5 +1,5 @@
1
1
  import type { Tool } from "@ai-zen/agents-core";
2
- import type { AppConfig, AgentDefinition, AgentPermissions, McpServerConfig, ToolEnv } from "../types/index.js";
2
+ import type { AppConfig, AgentDefinition, McpServerConfig, ToolEnv } from "../types/index.js";
3
3
  import type { SkillInfo } from "../capabilities/discovery/skills.js";
4
4
  import { McpConnectionManager } from "./McpConnectionManager.js";
5
5
  /**
@@ -22,6 +22,11 @@ export interface ExcludeOptions {
22
22
  mcps?: string[];
23
23
  subagents?: string[];
24
24
  }
25
+ /** filter / buildTools 的过滤选项 */
26
+ export interface FilterOptions {
27
+ /** 排除项黑名单(优先级高于 permissions) */
28
+ exclude?: ExcludeOptions;
29
+ }
25
30
  /**
26
31
  * Provider — 全局上下文实例 + 能力注册表。
27
32
  *
@@ -96,15 +101,11 @@ export declare class Provider {
96
101
  * 按权限过滤候选集,返回过滤后的名称列表。
97
102
  * 纯名称操作(安全预过滤 + 权限过滤),不涉及 Tool 实例化。
98
103
  */
99
- filter(permissions: AgentPermissions, options?: {
100
- exclude?: ExcludeOptions;
101
- }): FilterOutput;
104
+ filter(definition: AgentDefinition, options?: FilterOptions): FilterOutput;
102
105
  /**
103
106
  * 快捷方法:filter + instantiate 一步完成。
104
107
  */
105
- buildTools(permissions: AgentPermissions, options?: {
106
- exclude?: ExcludeOptions;
107
- }): Tool[];
108
+ buildTools(definition: AgentDefinition, options?: FilterOptions): Tool[];
108
109
  /**
109
110
  * 将过滤后的名称列表实例化为 Tool 数组。
110
111
  */
@@ -91,7 +91,7 @@ export class Provider {
91
91
  * 按权限过滤候选集,返回过滤后的名称列表。
92
92
  * 纯名称操作(安全预过滤 + 权限过滤),不涉及 Tool 实例化。
93
93
  */
94
- filter(permissions, options) {
94
+ filter(definition, options) {
95
95
  const exclude = options?.exclude ?? {};
96
96
  const excludeTools = new Set(exclude.tools ?? []);
97
97
  const excludeSkills = new Set(exclude.skills ?? []);
@@ -112,7 +112,17 @@ export class Provider {
112
112
  ...this.userTools.map((t) => t.function.name),
113
113
  ...DYNAMIC_TOOL_NAMES,
114
114
  ].filter((name) => !excludeTools.has(name));
115
- const evaluator = new PermissionEvaluator(permissions);
115
+ // 工具可用性过滤:调用候选工具的 isAvailable(直接透传完整 app config + agent definition)。
116
+ // 工具自行声明可用条件(如依赖图片模型配置、仅视觉模型可用),返回 false 则剔除。
117
+ const candidates = [...this.builtinTools, ...this.userTools];
118
+ for (let i = toolNames.length - 1; i >= 0; i--) {
119
+ const tool = candidates.find((t) => t.function.name === toolNames[i]);
120
+ const isAvailable = tool?.isAvailable;
121
+ if (isAvailable && !isAvailable(this.config, definition)) {
122
+ toolNames.splice(i, 1);
123
+ }
124
+ }
125
+ const evaluator = new PermissionEvaluator(definition.permissions);
116
126
  const filtered = evaluator.filter({
117
127
  tools: toolNames,
118
128
  skills: this.skills
@@ -133,8 +143,8 @@ export class Provider {
133
143
  /**
134
144
  * 快捷方法:filter + instantiate 一步完成。
135
145
  */
136
- buildTools(permissions, options) {
137
- return this.instantiate(this.filter(permissions, options));
146
+ buildTools(definition, options) {
147
+ return this.instantiate(this.filter(definition, options));
138
148
  }
139
149
  /**
140
150
  * 将过滤后的名称列表实例化为 Tool 数组。
@@ -1,127 +1,34 @@
1
- import { Agent, type ChatCompletionModel } from "@ai-zen/agents-core";
2
- import type { AgentNS, Tool, ToolCallContext, UnknownToolContext } from "@ai-zen/agents-core";
3
- import type { AgentDefinition, AgentPermissions } from "../types/index.js";
1
+ import type OpenAI from "openai";
2
+ import { Agent } from "@ai-zen/agents-core";
3
+ import type { AgentNS, Tool } from "@ai-zen/agents-core";
4
+ import type { AgentDefinition } from "../types/index.js";
4
5
  import type { Provider } from "./Provider.js";
5
- /**
6
- * Agent 插件上下文:当前 SdkAgent + 发送内容 + 消息列表。
7
- *
8
- * 注意:
9
- * - messages 是当前 agent 消息数组的**快照**(浅拷贝),插件不应直接修改它。
10
- * 所有消息变更应通过 agent 上的方法进行。
11
- * - 如果 onAfterSend 替换了 ctx.agent,send() 方法会使用新 agent 的消息作为返回值。
12
- */
13
- export interface SendContext {
14
- agent: SdkAgent;
15
- content: string;
16
- /** 当前 agent 消息数组的浅拷贝快照,仅供读取,不应直接修改 */
17
- messages: AgentNS.Message[];
18
- }
19
- /**
20
- * Agent 插件接口。
21
- * 每个插件单一职责,通过钩子介入 Agent 生命周期。
22
- *
23
- * onInit: Agent.init() 时调用,用于异步初始化
24
- * onBeforeSend: Agent.send() 调用前触发。可用于刷新工具列表等。
25
- * onAfterSend: Agent.send() 返回后调用。可通过 ctx.agent 替换当前 Agent。
26
- * onInnerLoopStart: Agent 内循环开始前触发。由 Core Agent 在内循环中调用。
27
- * onInnerLoopEnd: Agent 内循环结束后触发。由 Core Agent 在内循环中调用。
28
- * onInnerLoopsStart: Agent 整组内循环开始前触发(一次 send 仅一次)。由 Core Agent 在 run() 的 while 循环前调用。
29
- * onInnerLoopsEnd: Agent 整组内循环结束后触发(一次 send 仅一次)。由 Core Agent 在 run() 的 while 循环后调用。
30
- * onToolCall: 单个工具调用执行前触发(对应 Core onToolCall 钩子)。
31
- * 返回字符串 = 拒绝该工具(原因作为工具结果回给 LLM,工具不执行);
32
- * 返回 undefined = 放行。多个插件按注册顺序调用,任一返回字符串即拒绝。
33
- */
34
- export interface AgentPlugin {
35
- /** Agent.init() 时调用,用于异步初始化 */
36
- onInit?(): Promise<void>;
37
- /** Agent.send() 调用前触发 */
38
- onBeforeSend?(ctx: SendContext): Promise<void>;
39
- /** Agent.send() 返回后调用,可通过 ctx.agent 替换当前 Agent */
40
- onAfterSend?(ctx: SendContext): Promise<void>;
41
- /** Agent 内循环开始前触发 */
42
- onInnerLoopStart?(ctx: SendContext): Promise<void>;
43
- /** Agent 内循环结束后触发 */
44
- onInnerLoopEnd?(ctx: SendContext): Promise<void>;
45
- /** Agent 整组内循环开始前触发(一次 send 仅一次) */
46
- onInnerLoopsStart?(ctx: SendContext): Promise<void>;
47
- /** Agent 整组内循环结束后触发(一次 send 仅一次) */
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>;
55
- }
6
+ export type { AgentPlugin, SendContext } from "@ai-zen/agents-core";
56
7
  /**
57
8
  * SDK Agent — 继承 Core Agent,携带 SDK 层额外信息。
58
9
  *
59
- * Core Agent 不做复杂逻辑(不感知权限、不感知文件系统),
60
- * SdkAgent 在 Core Agent 基础上增加了 SDK 层需要的元数据,
61
- * 并通过 provider 字段访问全局上下文。
62
- *
63
- * 携带:
10
+ * Core Agent 不感知权限、文件系统等业务逻辑;
11
+ * SdkAgent 在 Core Agent 基础上增加了 SDK 层需要的元数据:
64
12
  * - provider:全局 Provider 实例
65
- * - definition:Agent 原始定义
66
- * - permissions:Agent 权限,供 call_skill_sub_agent 等回调读取
13
+ * - definition:Agent 原始定义(含权限 permissions)
67
14
  *
68
- * 插件能力:
69
- * - use(plugin):注册插件
70
- * - init():初始化所有已注册插件
71
- * - send():重写,在前后执行插件钩子
15
+ * 插件能力(use / init / send 钩子分发)继承自 Core Agent,此处不再重复实现。
16
+ * 未知工具的 MCP 智能提示由独立插件 `UnknownToolHintPlugin` 提供(调用方显式 use)。
17
+ * 权限统一从 `definition.permissions` 读取,不再单独持有。
72
18
  */
73
19
  export declare class SdkAgent extends Agent {
74
20
  /** 全局 Provider 实例 */
75
21
  readonly provider: Provider;
76
22
  /** Agent 原始定义 */
77
23
  readonly definition: AgentDefinition;
78
- /** Agent 权限 */
79
- readonly permissions?: AgentPermissions;
80
- /**
81
- * 当 LLM 调用不存在的工具时,给出智能提示。
82
- * 如果有 MCP 配置但 call_mcp_tool 不在工具列表中(权限禁用),提示权限问题;
83
- * 如果有 MCP 配置且 call_mcp_tool 可用,提示使用 call_mcp_tool;
84
- * 否则仅提示工具不存在。
85
- */
86
- onUnknownTool: (ctx: UnknownToolContext) => string;
87
- /** 已注册的插件列表 */
88
- private _plugins;
89
24
  constructor(params: {
90
25
  provider: Provider;
91
26
  definition: AgentDefinition;
92
- model: ChatCompletionModel;
93
- model_config?: Record<string, unknown>;
27
+ client: OpenAI;
28
+ model: string;
29
+ modelConfig?: Record<string, unknown>;
94
30
  messages?: AgentNS.Message[];
95
31
  tools?: Tool[];
96
- permissions?: AgentPermissions;
97
- rag?: any;
98
32
  allowJsonParseError?: boolean;
99
33
  });
100
- /**
101
- * 注册一个插件。
102
- * 可以在 init() 之前或之后调用,但 beforeSend/afterSend 钩子仅在
103
- * init() 之后发送消息时生效。
104
- */
105
- use(plugin: AgentPlugin): void;
106
- /**
107
- * 初始化所有已注册插件。
108
- * SdkAgent 本身没有异步初始化需求——模型、工具、消息在构造时已就绪。
109
- * init() 的存在完全是为了给插件一个执行异步初始化的机会。
110
- *
111
- * 如果不使用任何插件,可以不调 init()。
112
- */
113
- init(): Promise<void>;
114
- /**
115
- * 发送消息,在前后执行插件钩子。
116
- *
117
- * 流程:
118
- * 1. onBeforeSend — send 外部准备(刷新工具等)
119
- * 2. super.send() — 委托 Core Agent,内含内循环及其钩子
120
- * 3. onAfterSend — send 外部后处理(保存草稿、迁移等)
121
- *
122
- * 注意:
123
- * - ctx.messages 是当前 agent 消息的**浅拷贝快照**,仅供读取,不应直接修改。
124
- * 所有消息变更应通过 agent 上的方法进行(如 agent.messages.push 等)。
125
- */
126
- send(content: string): Promise<AgentNS.Message[]>;
127
34
  }
@@ -1,143 +1,31 @@
1
1
  import { Agent } from "@ai-zen/agents-core";
2
- // ---------------------------------------------------------------------------
3
- // SdkAgent
4
- // ---------------------------------------------------------------------------
5
2
  /**
6
3
  * SDK Agent — 继承 Core Agent,携带 SDK 层额外信息。
7
4
  *
8
- * Core Agent 不做复杂逻辑(不感知权限、不感知文件系统),
9
- * SdkAgent 在 Core Agent 基础上增加了 SDK 层需要的元数据,
10
- * 并通过 provider 字段访问全局上下文。
11
- *
12
- * 携带:
5
+ * Core Agent 不感知权限、文件系统等业务逻辑;
6
+ * SdkAgent 在 Core Agent 基础上增加了 SDK 层需要的元数据:
13
7
  * - provider:全局 Provider 实例
14
- * - definition:Agent 原始定义
15
- * - permissions:Agent 权限,供 call_skill_sub_agent 等回调读取
8
+ * - definition:Agent 原始定义(含权限 permissions)
16
9
  *
17
- * 插件能力:
18
- * - use(plugin):注册插件
19
- * - init():初始化所有已注册插件
20
- * - send():重写,在前后执行插件钩子
10
+ * 插件能力(use / init / send 钩子分发)继承自 Core Agent,此处不再重复实现。
11
+ * 未知工具的 MCP 智能提示由独立插件 `UnknownToolHintPlugin` 提供(调用方显式 use)。
12
+ * 权限统一从 `definition.permissions` 读取,不再单独持有。
21
13
  */
22
14
  export class SdkAgent extends Agent {
23
15
  /** 全局 Provider 实例 */
24
16
  provider;
25
17
  /** Agent 原始定义 */
26
18
  definition;
27
- /** Agent 权限 */
28
- permissions;
29
- /**
30
- * 当 LLM 调用不存在的工具时,给出智能提示。
31
- * 如果有 MCP 配置但 call_mcp_tool 不在工具列表中(权限禁用),提示权限问题;
32
- * 如果有 MCP 配置且 call_mcp_tool 可用,提示使用 call_mcp_tool;
33
- * 否则仅提示工具不存在。
34
- */
35
- onUnknownTool = (ctx) => {
36
- const toolName = ctx.toolCall.function?.name ?? "未知";
37
- const hasMcpConfig = this.provider.mcpPaths.length > 0;
38
- const hasCallMcpTool = (this.tools ?? []).some((t) => t.function.name === "call_mcp_tool");
39
- if (hasMcpConfig && !hasCallMcpTool) {
40
- return `工具 "${toolName}" 不存在。当前有 MCP 服务器配置,但 call_mcp_tool 权限已被禁用,如需使用 MCP 工具请调整权限。`;
41
- }
42
- if (hasMcpConfig && hasCallMcpTool) {
43
- return `工具 "${toolName}" 不存在。如果要调用 MCP 工具,请使用 call_mcp_tool。`;
44
- }
45
- return `工具 "${toolName}" 不存在。`;
46
- };
47
- /** 已注册的插件列表 */
48
- _plugins = [];
49
19
  constructor(params) {
50
20
  super({
21
+ client: params.client,
51
22
  model: params.model,
52
- model_config: params.model_config,
23
+ modelConfig: params.modelConfig,
53
24
  messages: params.messages,
54
25
  tools: params.tools,
55
- rag: params.rag,
56
26
  allowJsonParseError: params.allowJsonParseError,
57
27
  });
58
28
  this.provider = params.provider;
59
29
  this.definition = params.definition;
60
- this.permissions = params.permissions;
61
- }
62
- /**
63
- * 注册一个插件。
64
- * 可以在 init() 之前或之后调用,但 beforeSend/afterSend 钩子仅在
65
- * init() 之后发送消息时生效。
66
- */
67
- use(plugin) {
68
- this._plugins.push(plugin);
69
- }
70
- /**
71
- * 初始化所有已注册插件。
72
- * SdkAgent 本身没有异步初始化需求——模型、工具、消息在构造时已就绪。
73
- * init() 的存在完全是为了给插件一个执行异步初始化的机会。
74
- *
75
- * 如果不使用任何插件,可以不调 init()。
76
- */
77
- async init() {
78
- for (const plugin of this._plugins) {
79
- await plugin.onInit?.();
80
- }
81
- }
82
- /**
83
- * 发送消息,在前后执行插件钩子。
84
- *
85
- * 流程:
86
- * 1. onBeforeSend — send 外部准备(刷新工具等)
87
- * 2. super.send() — 委托 Core Agent,内含内循环及其钩子
88
- * 3. onAfterSend — send 外部后处理(保存草稿、迁移等)
89
- *
90
- * 注意:
91
- * - ctx.messages 是当前 agent 消息的**浅拷贝快照**,仅供读取,不应直接修改。
92
- * 所有消息变更应通过 agent 上的方法进行(如 agent.messages.push 等)。
93
- */
94
- async send(content) {
95
- const ctx = {
96
- agent: this,
97
- content,
98
- messages: [...this.messages],
99
- };
100
- for (const plugin of this._plugins) {
101
- await plugin.onBeforeSend?.(ctx);
102
- }
103
- this.onInnerLoopStart = async () => {
104
- for (const plugin of this._plugins) {
105
- await plugin.onInnerLoopStart?.(ctx);
106
- }
107
- };
108
- this.onInnerLoopEnd = async () => {
109
- for (const plugin of this._plugins) {
110
- await plugin.onInnerLoopEnd?.(ctx);
111
- }
112
- };
113
- this.onInnerLoopsStart = async () => {
114
- for (const plugin of this._plugins) {
115
- await plugin.onInnerLoopsStart?.(ctx);
116
- }
117
- };
118
- this.onInnerLoopsEnd = async () => {
119
- for (const plugin of this._plugins) {
120
- await plugin.onInnerLoopsEnd?.(ctx);
121
- }
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
- };
132
- await super.send(content);
133
- this.onInnerLoopStart = undefined;
134
- this.onInnerLoopEnd = undefined;
135
- this.onInnerLoopsStart = undefined;
136
- this.onInnerLoopsEnd = undefined;
137
- this.onToolCall = undefined;
138
- for (const plugin of this._plugins) {
139
- await plugin.onAfterSend?.(ctx);
140
- }
141
- return this.messages;
142
30
  }
143
31
  }
@@ -1,6 +1,6 @@
1
1
  import { Tool, ToolCallContext } from "@ai-zen/agents-core";
2
2
  import type { AgentNS } from "@ai-zen/agents-core";
3
- import type { ToolEnv } from "../types/index.js";
3
+ import type { AgentDefinition, AppConfig, ToolEnv } from "../types/index.js";
4
4
  /** SdkCallbackTool 构造选项。env 为核心字段,未来可在此扩展可选项。 */
5
5
  export interface SdkCallbackToolOptions {
6
6
  /** 注入的工具环境 */
@@ -23,14 +23,22 @@ export declare abstract class SdkCallbackTool extends Tool {
23
23
  readonly env: ToolEnv;
24
24
  /** 工具定义。由子类以类体字段 function = {...} 提供。 */
25
25
  function: AgentNS.FunctionDefine;
26
+ /**
27
+ * 工具对当前 Agent 的可用性判断。由工具自行声明,直接透传完整
28
+ * app config 与 agent definition(含 modelId / permissions 等),工具自取所需
29
+ * (如是否配置了图片模型、当前模型是否为视觉模型)。
30
+ * 在 buildTools/filter 阶段调用;返回 false 的工具不会注册给该 Agent。
31
+ * 不实现则默认可用。
32
+ */
33
+ isAvailable?(config: AppConfig, definition: AgentDefinition): boolean;
26
34
  constructor(options: SdkCallbackToolOptions);
27
35
  /**
28
- * 工具核心逻辑(由子类实现,参数为 parsed_args)。
36
+ * 工具核心逻辑(由子类实现,参数为 parsedArgs)。
29
37
  * 可选第二参 ctx:透传完整 ToolCallContext,需中止能力(signal)的工具自行读取。
30
38
  */
31
39
  abstract call(input: unknown, ctx?: ToolCallContext): unknown | Promise<unknown>;
32
- /** 桥接 core 的 Tool.exec:解析参数 → call → 序列化 */
33
- exec(ctx: ToolCallContext): Promise<string>;
40
+ /** 桥接 core 的 Tool.exec:解析参数 → call → 序列化/透传内容块 */
41
+ exec(ctx: ToolCallContext): Promise<AgentNS.MessageContent>;
34
42
  /** 将相对路径解析到 env.cwd,绝对路径原样返回 */
35
43
  resolve(p: string): string;
36
44
  }
@@ -19,11 +19,14 @@ export class SdkCallbackTool extends Tool {
19
19
  super();
20
20
  this.env = options.env;
21
21
  }
22
- /** 桥接 core 的 Tool.exec:解析参数 → call → 序列化 */
22
+ /** 桥接 core 的 Tool.exec:解析参数 → call → 序列化/透传内容块 */
23
23
  async exec(ctx) {
24
- const result = await this.call(ctx.parsed_args, ctx);
24
+ const result = await this.call(ctx.parsedArgs, ctx);
25
25
  if (typeof result === "string")
26
26
  return result;
27
+ // 内容块数组(图片/文件等)直接透传,让模型能收到结构化内容
28
+ if (Array.isArray(result))
29
+ return result;
27
30
  // JSON.stringify(undefined) 返回 undefined(非字符串),会破坏 Promise<string> 契约
28
31
  return JSON.stringify(result) ?? "";
29
32
  }
@@ -18,8 +18,8 @@ export async function createAgent(provider, agentId) {
18
18
  const modelId = definition.modelId ?? provider.config.defaultModel;
19
19
  if (!modelId)
20
20
  throw new Error("未指定模型且无默认模型");
21
- const model = createModel(provider, modelId);
22
- const tools = provider.buildTools(definition.permissions ?? {}, {
21
+ const { client, model, modelConfig } = createModel(provider, modelId);
22
+ const tools = provider.buildTools(definition, {
23
23
  exclude: {
24
24
  subagents: definition.function?.name
25
25
  ? [definition.function.name]
@@ -29,10 +29,11 @@ export async function createAgent(provider, agentId) {
29
29
  const agent = new SdkAgent({
30
30
  provider,
31
31
  definition,
32
+ client,
32
33
  model,
34
+ modelConfig,
33
35
  messages: definition.messages,
34
36
  tools,
35
- permissions: definition.permissions,
36
37
  });
37
38
  return agent;
38
39
  }
@@ -1,8 +1,21 @@
1
- import type { ChatCompletionModel } from "@ai-zen/agents-core";
1
+ import OpenAI from "openai";
2
2
  import type { Provider } from "./Provider.js";
3
3
  /**
4
- * 模型工厂 — 根据 modelId 和 Provider 构建 Core ChatCompletionModel。
4
+ * Agent 模型装配结果:openai SDK client + 模型名 + 模型参数。
5
+ * Agent 构造时直接消费此结构。
6
+ */
7
+ export interface AgentModel {
8
+ /** openai 官方 SDK 客户端 */
9
+ client: OpenAI;
10
+ /** 发送给 API 的模型名 */
11
+ model: string;
12
+ /** 模型参数(defaultParams),透传给 API(可含厂商特有字段,如 DeepSeek thinking) */
13
+ modelConfig?: Record<string, unknown>;
14
+ }
15
+ /**
16
+ * 模型工厂 — 根据 modelId 和 Provider 装配 openai SDK client。
5
17
  *
6
- * 同步版本,使用 endp​oint.chatCompletionSync() 避免不必要的 async。
18
+ * 端点(baseUrl / apiKey)来自 config.endpoints,发送给 API 的模型名 = modelName || id。
19
+ * 任何 OpenAI 兼容端点(OpenAI / 智谱 BigModel / DeepSeek 等)均可通过 baseURL 接入。
7
20
  */
8
- export declare function createModel(provider: Provider, modelId: string): ChatCompletionModel;
21
+ export declare function createModel(provider: Provider, modelId: string): AgentModel;
@@ -1,8 +1,9 @@
1
- import { OpenAI, ChatGPT } from "@ai-zen/agents-core";
1
+ import OpenAI from "openai";
2
2
  /**
3
- * 模型工厂 — 根据 modelId 和 Provider 构建 Core ChatCompletionModel。
3
+ * 模型工厂 — 根据 modelId 和 Provider 装配 openai SDK client。
4
4
  *
5
- * 同步版本,使用 endp​oint.chatCompletionSync() 避免不必要的 async。
5
+ * 端点(baseUrl / apiKey)来自 config.endpoints,发送给 API 的模型名 = modelName || id。
6
+ * 任何 OpenAI 兼容端点(OpenAI / 智谱 BigModel / DeepSeek 等)均可通过 baseURL 接入。
6
7
  */
7
8
  export function createModel(provider, modelId) {
8
9
  const config = provider.config;
@@ -12,15 +13,18 @@ export function createModel(provider, modelId) {
12
13
  const endpointConfig = config.endpoints.find((e) => e.id === modelConfig.endpointId);
13
14
  if (!endpointConfig)
14
15
  throw new Error(`端点 "${modelConfig.endpointId}" 未配置`);
15
- const endpoint = new OpenAI({
16
- openai_endpoint: endpointConfig.baseUrl,
17
- api_key: endpointConfig.apiKey,
16
+ if (!endpointConfig.apiKey) {
17
+ throw new Error(`端点 "${endpointConfig.name}" 的 API Key 未设置`);
18
+ }
19
+ const client = new OpenAI({
20
+ apiKey: endpointConfig.apiKey,
21
+ baseURL: endpointConfig.baseUrl,
18
22
  });
19
23
  // 发送给 API 的模型名:modelName > id
20
24
  const apiModelName = modelConfig.modelName || modelConfig.id;
21
- const model = new ChatGPT({
22
- model_config: modelConfig.defaultParams,
23
- request_config: endpoint.chatCompletionSync(apiModelName),
24
- });
25
- return model;
25
+ return {
26
+ client,
27
+ model: apiModelName,
28
+ modelConfig: modelConfig.defaultParams,
29
+ };
26
30
  }
@@ -29,6 +29,8 @@ export interface Model {
29
29
  maxContextTokens: number;
30
30
  maxContextChars?: number;
31
31
  defaultParams?: Record<string, unknown>;
32
+ /** 是否支持图片输入(视觉模型)。看图工具(viewImage)仅对视觉模型启用;generateImage 是否返回图片内容块也据此判断 */
33
+ vision?: boolean;
32
34
  description?: string;
33
35
  version?: number;
34
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-zen/agents-sdk",
3
- "version": "0.6.0",
3
+ "version": "0.7.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",
@@ -18,7 +18,8 @@
18
18
  "dependencies": {
19
19
  "@modelcontextprotocol/sdk": "^1.29.0",
20
20
  "dayjs": "^1.11.21",
21
- "@ai-zen/agents-core": "^3.4.0"
21
+ "openai": "^7.5.0",
22
+ "@ai-zen/agents-core": "^4.0.0"
22
23
  },
23
24
  "devDependencies": {
24
25
  "@types/node": "^24.12.2",