From d0d0e8dbafe5ef88ee53c4efb49c78d303ac12fc Mon Sep 17 00:00:00 2001 From: kurihada Date: Thu, 11 Dec 2025 18:42:07 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=B8=85=E7=90=86=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=BB=93=E6=9E=84=EF=BC=8C=E7=BB=9F=E4=B8=80=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=AE=9A=E4=B9=89=EF=BC=8C=E7=A7=BB=E9=99=A4=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 提取 Provider 配置到公共模块 core/providers.ts - 统一 PermissionAction/PermissionRule 类型定义到 permission/types.ts - 移除 core/agent.ts 中未使用的 legacyTools 系统 - 移除 tools/index.ts 中未使用的 allTools 导出 - 减少约 125 行重复/冗余代码 --- src/agent/executor.ts | 54 +++---------------- src/agent/types.ts | 17 ++---- src/core/agent.ts | 117 +++++++++--------------------------------- src/core/providers.ts | 65 +++++++++++++++++++++++ src/tools/index.ts | 3 -- 5 files changed, 98 insertions(+), 158 deletions(-) create mode 100644 src/core/providers.ts diff --git a/src/agent/executor.ts b/src/agent/executor.ts index 08b060d..8fc1302 100644 --- a/src/agent/executor.ts +++ b/src/agent/executor.ts @@ -1,7 +1,3 @@ -import { createAnthropic } from '@ai-sdk/anthropic'; -import { createDeepSeek } from '@ai-sdk/deepseek'; -import { createOpenAI } from '@ai-sdk/openai'; -import { createQwen } from 'qwen-ai-provider-v5'; import { generateText, streamText, @@ -10,7 +6,7 @@ import { type Tool as AITool, type LanguageModel, } from 'ai'; -import type { Tool, ToolResult, ProviderType, AgentConfig, ContentBlock } from '../types/index.js'; +import type { Tool, ToolResult, AgentConfig, ContentBlock } from '../types/index.js'; import { buildZodSchema } from '../types/index.js'; import { ToolRegistry } from '../tools/registry.js'; import type { @@ -20,44 +16,7 @@ import type { ImageData, } from './types.js'; import { checkBashPermission } from './permission-merger.js'; - -// Provider 配置 -interface ProviderOptions { - apiKey: string; - baseUrl?: string; -} - -// Provider 工厂函数类型 -type ProviderFactory = (options: ProviderOptions) => (model: string) => LanguageModel; - -/** - * 检查 baseUrl 是否为阿里云百炼/DashScope - */ -function isDashScopeUrl(baseUrl?: string): boolean { - if (!baseUrl) return false; - return baseUrl.includes('dashscope'); -} - -// Provider 注册表 -const providers: Record = { - anthropic: ({ apiKey, baseUrl }) => { - const client = createAnthropic({ apiKey, baseURL: baseUrl }); - return (model) => client(model); - }, - deepseek: ({ apiKey, baseUrl }) => { - const client = createDeepSeek({ apiKey, baseURL: baseUrl }); - return (model) => client(model); - }, - openai: ({ apiKey, baseUrl }) => { - // 如果是百炼的 URL,使用 qwen provider - if (isDashScopeUrl(baseUrl)) { - const client = createQwen({ apiKey, baseURL: baseUrl }); - return (model) => client(model); - } - const client = createOpenAI({ apiKey, baseURL: baseUrl }); - return (model) => client(model); - }, -}; +import { getModelFactory } from '../core/providers.js'; /** * Agent 执行器 @@ -80,11 +39,10 @@ export class AgentExecutor { // 获取模型工厂 const provider = agentInfo.model?.provider ?? baseConfig.provider; - const providerFactory = providers[provider]; - if (!providerFactory) { - throw new Error(`不支持的 provider: ${provider}`); - } - this.getModel = providerFactory({ apiKey: baseConfig.apiKey, baseUrl: baseConfig.baseUrl }); + this.getModel = getModelFactory(provider, { + apiKey: baseConfig.apiKey, + baseUrl: baseConfig.baseUrl, + }); } /** diff --git a/src/agent/types.ts b/src/agent/types.ts index 87ca8d0..a9f1267 100644 --- a/src/agent/types.ts +++ b/src/agent/types.ts @@ -1,4 +1,8 @@ import type { ProviderType } from '../types/index.js'; +import type { PermissionAction, PermissionRule } from '../permission/types.js'; + +// 重新导出权限类型,方便外部使用 +export type { PermissionAction, PermissionRule }; /** * Agent 模式 @@ -8,19 +12,6 @@ import type { ProviderType } from '../types/index.js'; */ export type AgentMode = 'primary' | 'subagent' | 'all'; -/** - * 权限动作 - */ -export type PermissionAction = 'allow' | 'deny' | 'ask'; - -/** - * 权限规则(支持通配符模式) - */ -export interface PermissionRule { - pattern: string; - action: PermissionAction; -} - /** * Agent Bash 权限配置 */ diff --git a/src/core/agent.ts b/src/core/agent.ts index 1a55e53..2931526 100644 --- a/src/core/agent.ts +++ b/src/core/agent.ts @@ -1,7 +1,3 @@ -import { createAnthropic } from '@ai-sdk/anthropic'; -import { createDeepSeek } from '@ai-sdk/deepseek'; -import { createOpenAI } from '@ai-sdk/openai'; -import { createQwen } from 'qwen-ai-provider-v5'; import { generateText, streamText, @@ -10,7 +6,7 @@ import { type Tool as AITool, type LanguageModel, } from 'ai'; -import type { Tool, ToolResult, Message, AgentConfig, ProviderType, UserInput, ContentBlock } from '../types/index.js'; +import type { Tool, ToolResult, Message, AgentConfig, UserInput, ContentBlock } from '../types/index.js'; import { buildZodSchema } from '../types/index.js'; import { ToolRegistry } from '../tools/registry.js'; import { SessionManager } from '../session/index.js'; @@ -22,44 +18,7 @@ import { import type { AgentInfo, ImageData } from '../agent/types.js'; import { agentRegistry, AgentExecutor } from '../agent/index.js'; import { loadVisionConfig } from '../utils/config.js'; - -// Provider 配置 -interface ProviderOptions { - apiKey: string; - baseUrl?: string; -} - -// Provider 工厂函数类型 -type ProviderFactory = (options: ProviderOptions) => (model: string) => LanguageModel; - -/** - * 检查 baseUrl 是否为阿里云百炼/DashScope - */ -function isDashScopeUrl(baseUrl?: string): boolean { - if (!baseUrl) return false; - return baseUrl.includes('dashscope'); -} - -// Provider 注册表 -const providers: Record = { - anthropic: ({ apiKey, baseUrl }) => { - const client = createAnthropic({ apiKey, baseURL: baseUrl }); - return (model) => client(model); - }, - deepseek: ({ apiKey, baseUrl }) => { - const client = createDeepSeek({ apiKey, baseURL: baseUrl }); - return (model) => client(model); - }, - openai: ({ apiKey, baseUrl }) => { - // 如果是百炼的 URL,使用 qwen provider - if (isDashScopeUrl(baseUrl)) { - const client = createQwen({ apiKey, baseURL: baseUrl }); - return (model) => client(model); - } - const client = createOpenAI({ apiKey, baseURL: baseUrl }); - return (model) => client(model); - }, -}; +import { getModelFactory } from './providers.js'; export class Agent { private getModel: (model: string) => LanguageModel; @@ -72,9 +31,6 @@ export class Agent { // 已发现的工具(通过 tool_search 发现的) private discoveredTools: Set = new Set(); - // 兼容旧模式:直接注册的工具 - private legacyTools: Map = new Map(); - // 会话管理器(可选) private sessionManager: SessionManager | null = null; @@ -91,11 +47,10 @@ export class Agent { this.config = config; this.originalSystemPrompt = config.systemPrompt; - const providerFactory = providers[config.provider]; - if (!providerFactory) { - throw new Error(`不支持的 provider: ${config.provider}`); - } - this.getModel = providerFactory({ apiKey: config.apiKey, baseUrl: config.baseUrl }); + this.getModel = getModelFactory(config.provider, { + apiKey: config.apiKey, + baseUrl: config.baseUrl, + }); // 初始化压缩管理器 this.compressionManager = new CompressionManager(compressionConfig); @@ -130,41 +85,20 @@ export class Agent { return this.sessionManager; } - /** - * 注册单个工具(兼容旧代码) - */ - registerTool(customTool: Tool): void { - this.legacyTools.set(customTool.name, customTool); - } - - /** - * 批量注册工具(兼容旧代码) - */ - registerTools(tools: Tool[]): void { - for (const tool of tools) { - this.legacyTools.set(tool.name, tool); - } - } - /** * 获取当前可用的工具 - * - 如果使用 registry 模式:返回核心工具 + 已发现的工具 - * - 如果使用旧模式:返回所有注册的工具 - * - 如果当前有 Agent 模式,应用工具过滤 + * 返回核心工具 + 已发现的工具,如果当前有 Agent 模式,应用工具过滤 */ private getAvailableTools(): Tool[] { - let tools: Tool[]; - - if (this.registry) { - // 新模式:核心工具 + 已发现的工具 - const coreTools = this.registry.getCoreTools(); - const discoveredTools = this.registry.getTools([...this.discoveredTools]); - tools = [...coreTools, ...discoveredTools]; - } else { - // 旧模式:返回所有注册的工具 - tools = [...this.legacyTools.values()]; + if (!this.registry) { + throw new Error('工具注册表未初始化,请先调用 setRegistry()'); } + // 核心工具 + 已发现的工具 + const coreTools = this.registry.getCoreTools(); + const discoveredTools = this.registry.getTools([...this.discoveredTools]); + let tools = [...coreTools, ...discoveredTools]; + // 应用 Agent 模式的工具过滤 if (this.currentAgentMode?.tools) { tools = this.filterToolsByAgentConfig(tools); @@ -435,21 +369,16 @@ export class Agent { * 获取当前可用工具的数量 */ getToolCount(): { core: number; discovered: number; total: number } { - if (this.registry) { - const coreCount = this.registry.getCoreTools().length; - const discoveredCount = this.discoveredTools.size; - return { - core: coreCount, - discovered: discoveredCount, - total: coreCount + discoveredCount, - }; - } else { - return { - core: this.legacyTools.size, - discovered: 0, - total: this.legacyTools.size, - }; + if (!this.registry) { + return { core: 0, discovered: 0, total: 0 }; } + const coreCount = this.registry.getCoreTools().length; + const discoveredCount = this.discoveredTools.size; + return { + core: coreCount, + discovered: discoveredCount, + total: coreCount + discoveredCount, + }; } /** diff --git a/src/core/providers.ts b/src/core/providers.ts new file mode 100644 index 0000000..82e9b8b --- /dev/null +++ b/src/core/providers.ts @@ -0,0 +1,65 @@ +import { createAnthropic } from '@ai-sdk/anthropic'; +import { createDeepSeek } from '@ai-sdk/deepseek'; +import { createOpenAI } from '@ai-sdk/openai'; +import { createQwen } from 'qwen-ai-provider-v5'; +import type { LanguageModel } from 'ai'; +import type { ProviderType } from '../types/index.js'; + +/** + * Provider 配置选项 + */ +export interface ProviderOptions { + apiKey: string; + baseUrl?: string; +} + +/** + * Provider 工厂函数类型 + */ +export type ProviderFactory = (options: ProviderOptions) => (model: string) => LanguageModel; + +/** + * 检查 baseUrl 是否为阿里云百炼/DashScope + */ +function isDashScopeUrl(baseUrl?: string): boolean { + if (!baseUrl) return false; + return baseUrl.includes('dashscope'); +} + +/** + * Provider 注册表 + * 支持 Anthropic、DeepSeek、OpenAI 及 OpenAI 兼容 API(如阿里云百炼) + */ +export const providers: Record = { + anthropic: ({ apiKey, baseUrl }) => { + const client = createAnthropic({ apiKey, baseURL: baseUrl }); + return (model) => client(model); + }, + deepseek: ({ apiKey, baseUrl }) => { + const client = createDeepSeek({ apiKey, baseURL: baseUrl }); + return (model) => client(model); + }, + openai: ({ apiKey, baseUrl }) => { + // 如果是百炼的 URL,使用 qwen provider + if (isDashScopeUrl(baseUrl)) { + const client = createQwen({ apiKey, baseURL: baseUrl }); + return (model) => client(model); + } + const client = createOpenAI({ apiKey, baseURL: baseUrl }); + return (model) => client(model); + }, +}; + +/** + * 获取模型工厂函数 + */ +export function getModelFactory( + provider: ProviderType, + options: ProviderOptions +): (model: string) => LanguageModel { + const factory = providers[provider]; + if (!factory) { + throw new Error(`不支持的 provider: ${provider}`); + } + return factory(options); +} diff --git a/src/tools/index.ts b/src/tools/index.ts index d269b52..639927a 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -100,6 +100,3 @@ export { todoManager } from './todo/index.js'; export { initTaskContext, updateTaskDescription } from './task/index.js'; export { updateSkillDescription } from './skill/index.js'; export type { ToolWithMetadata, ToolMetadata, ToolCategory, ToolSearchResult } from './types.js'; - -// 兼容旧代码:导出所有工具数组(基础 Tool 类型) -export const allTools = toolRegistry.getAllTools();