From 8b1c4d36a03b1d73ee7defabdc859329397421cf Mon Sep 17 00:00:00 2001 From: iven Date: Thu, 12 Mar 2026 00:31:24 +0800 Subject: [PATCH] refactor: remove v1 legacy code replaced by OpenClaw - Remove src/core/* - replaced by OpenClaw built-in capabilities - Remove src/db/* - OpenClaw has its own SQLite storage - Remove src/config/* - OpenClaw config system replaces this - Remove src/im/* - OpenClaw Channel system replaces this - Remove src/api/* - WebSocket + Tauri Commands replace this - Remove src/utils/* - using OpenClaw utilities - Remove src/app.ts, src/index.ts - no longer needed All v1 code is preserved in archive/v1-code-backup branch Co-Authored-By: Claude Opus 4.6 --- src/api/index.ts | 144 ---------- src/app.ts | 173 ------------ src/config/index.ts | 118 -------- src/core/ai/index.ts | 4 - src/core/ai/manager.ts | 142 ---------- src/core/ai/providers/openai.ts | 139 ---------- src/core/ai/providers/zhipu.ts | 138 --------- src/core/ai/types.ts | 48 ---- src/core/memory/index.ts | 1 - src/core/memory/memory.ts | 70 ----- src/core/multi-agent/agents/combiner-agent.ts | 40 --- src/core/multi-agent/agents/executor-agent.ts | 83 ------ src/core/multi-agent/agents/planner-agent.ts | 64 ----- src/core/multi-agent/base-agent.ts | 126 --------- src/core/multi-agent/index.ts | 7 - src/core/multi-agent/message-bus.ts | 71 ----- src/core/multi-agent/orchestrator.ts | 262 ------------------ src/core/multi-agent/types.ts | 63 ----- src/core/proactive/index.ts | 1 - src/core/proactive/proactive.ts | 90 ------ src/core/remote-execution/engine.ts | 166 ----------- src/core/remote-execution/index.ts | 2 - src/core/remote-execution/types.ts | 46 --- src/core/task-orchestration/index.ts | 2 - src/core/task-orchestration/orchestrator.ts | 196 ------------- src/core/task-orchestration/types.ts | 53 ---- src/db/database.ts | 91 ------ src/db/index.ts | 2 - src/db/schema.ts | 118 -------- src/im/adapters/feishu.ts | 124 --------- src/im/gateway.ts | 80 ------ src/im/index.ts | 3 - src/im/types.ts | 33 --- src/index.ts | 34 --- src/utils/id.ts | 12 - src/utils/index.ts | 3 - src/utils/logger.ts | 57 ---- 37 files changed, 2806 deletions(-) delete mode 100644 src/api/index.ts delete mode 100644 src/app.ts delete mode 100644 src/config/index.ts delete mode 100644 src/core/ai/index.ts delete mode 100644 src/core/ai/manager.ts delete mode 100644 src/core/ai/providers/openai.ts delete mode 100644 src/core/ai/providers/zhipu.ts delete mode 100644 src/core/ai/types.ts delete mode 100644 src/core/memory/index.ts delete mode 100644 src/core/memory/memory.ts delete mode 100644 src/core/multi-agent/agents/combiner-agent.ts delete mode 100644 src/core/multi-agent/agents/executor-agent.ts delete mode 100644 src/core/multi-agent/agents/planner-agent.ts delete mode 100644 src/core/multi-agent/base-agent.ts delete mode 100644 src/core/multi-agent/index.ts delete mode 100644 src/core/multi-agent/message-bus.ts delete mode 100644 src/core/multi-agent/orchestrator.ts delete mode 100644 src/core/multi-agent/types.ts delete mode 100644 src/core/proactive/index.ts delete mode 100644 src/core/proactive/proactive.ts delete mode 100644 src/core/remote-execution/engine.ts delete mode 100644 src/core/remote-execution/index.ts delete mode 100644 src/core/remote-execution/types.ts delete mode 100644 src/core/task-orchestration/index.ts delete mode 100644 src/core/task-orchestration/orchestrator.ts delete mode 100644 src/core/task-orchestration/types.ts delete mode 100644 src/db/database.ts delete mode 100644 src/db/index.ts delete mode 100644 src/db/schema.ts delete mode 100644 src/im/adapters/feishu.ts delete mode 100644 src/im/gateway.ts delete mode 100644 src/im/index.ts delete mode 100644 src/im/types.ts delete mode 100644 src/index.ts delete mode 100644 src/utils/id.ts delete mode 100644 src/utils/index.ts delete mode 100644 src/utils/logger.ts diff --git a/src/api/index.ts b/src/api/index.ts deleted file mode 100644 index 53014e3..0000000 --- a/src/api/index.ts +++ /dev/null @@ -1,144 +0,0 @@ -// ZCLAW API 层 - 供 Tauri 前端调用的接口 -import type { ZClawApp } from '../app'; -import { createLogger } from '../utils/logger'; - -const log = createLogger('API'); - -export interface APIResponse { - success: boolean; - data?: T; - error?: string; -} - -// API 处理器集合 - 供 Tauri Commands 调用 -export class ZClawAPI { - constructor(private app: ZClawApp) {} - - // === 聊天 === - async sendMessage(userId: string, content: string): Promise> { - try { - const reply = await this.app.handleUserMessage(userId, content); - return { success: true, data: { reply } }; - } catch (error: any) { - log.error(`sendMessage error: ${error.message}`); - return { success: false, error: error.message }; - } - } - - // === 任务 === - async submitTask(userId: string, payload: any): Promise> { - try { - const engine = this.app.getRemoteExecution(); - const taskId = await engine.submitTask({ - id: '', - userId, - deviceId: 'local', - channel: 'desktop', - type: 'immediate', - priority: 'normal', - payload, - status: 'pending', - createdAt: new Date(), - }); - return { success: true, data: { taskId } }; - } catch (error: any) { - return { success: false, error: error.message }; - } - } - - async getTaskStatus(taskId: string): Promise> { - try { - const engine = this.app.getRemoteExecution(); - const status = await engine.getStatus(taskId); - return { success: true, data: { status } }; - } catch (error: any) { - return { success: false, error: error.message }; - } - } - - async getTaskStats(): Promise { - try { - const stats = this.app.getRemoteExecution().getStats(); - return { success: true, data: stats }; - } catch (error: any) { - return { success: false, error: error.message }; - } - } - - // === 多 Agent === - async executeGoal(userId: string, goal: string): Promise { - try { - const result = await this.app.getAgentOrchestrator().executeGoal(goal); - return { success: true, data: result }; - } catch (error: any) { - return { success: false, error: error.message }; - } - } - - // === 记忆 === - async getUserProfile(userId: string): Promise { - try { - const profile = await this.app.getMemory().getProfile(userId); - return { success: true, data: profile || null }; - } catch (error: any) { - return { success: false, error: error.message }; - } - } - - async getMemoryEvents(userId: string, query: string = '', limit: number = 20): Promise { - try { - const events = await this.app.getMemory().recall(userId, query, limit); - return { success: true, data: events }; - } catch (error: any) { - return { success: false, error: error.message }; - } - } - - // === 定时任务 === - async listScheduledTasks(userId: string): Promise { - try { - const tasks = await this.app.getProactive().listTasks(userId); - return { success: true, data: tasks }; - } catch (error: any) { - return { success: false, error: error.message }; - } - } - - async scheduleTask(userId: string, schedule: any, taskConfig: any): Promise { - try { - await this.app.getProactive().scheduleTask({ - id: '', - userId, - channel: 'desktop', - schedule, - task: taskConfig, - status: 'active', - }); - return { success: true }; - } catch (error: any) { - return { success: false, error: error.message }; - } - } - - // === 系统状态 === - async getSystemStatus(): Promise { - try { - const taskStats = this.app.getRemoteExecution().getStats(); - const agents = this.app.getAgentOrchestrator().getAgents().map(a => a.getInfo()); - const activePlans = this.app.getAgentOrchestrator().getActivePlans(); - const connectedIMs = this.app.getIMGateway().getConnectedAdapters(); - - return { - success: true, - data: { - taskStats, - activeAgents: agents.length, - activePlans: activePlans.length, - connectedIMs, - }, - }; - } catch (error: any) { - return { success: false, error: error.message }; - } - } -} diff --git a/src/app.ts b/src/app.ts deleted file mode 100644 index 9e3a9f8..0000000 --- a/src/app.ts +++ /dev/null @@ -1,173 +0,0 @@ -// ZCLAW 主应用类 - 统一协调所有系统 -import { loadConfig, getConfig } from './config'; -import { initDatabase, closeDatabase } from './db'; -import { AIManager } from './core/ai/manager'; -import { AgentOrchestrator } from './core/multi-agent/orchestrator'; -import { RemoteExecutionEngine } from './core/remote-execution/engine'; -import { TaskOrchestrator } from './core/task-orchestration/orchestrator'; -import { PersistentMemorySystem } from './core/memory/memory'; -import { ProactiveServiceSystem } from './core/proactive/proactive'; -import { IMGateway } from './im/gateway'; -import { FeishuAdapter } from './im/adapters/feishu'; -import { createLogger, setLogLevel } from './utils/logger'; - -const log = createLogger('ZCLAW'); - -export class ZClawApp { - private ai!: AIManager; - private agentOrchestrator!: AgentOrchestrator; - private remoteExecution!: RemoteExecutionEngine; - private taskOrchestrator!: TaskOrchestrator; - private memory!: PersistentMemorySystem; - private proactive!: ProactiveServiceSystem; - private imGateway!: IMGateway; - - async start(): Promise { - log.info('========================================'); - log.info(' ZCLAW - AI Agent Platform'); - log.info(' Version: 0.1.0'); - log.info('========================================'); - - // 1. 加载配置 - const config = loadConfig(); - setLogLevel(config.log.level); - log.info('Configuration loaded'); - - // 2. 初始化数据库 - initDatabase(config.db.path); - log.info('Database initialized'); - - // 3. 初始化 AI 管理器 - this.ai = new AIManager(); - log.info('AI Manager initialized'); - - // 4. 初始化核心系统 - this.remoteExecution = new RemoteExecutionEngine(); - this.taskOrchestrator = new TaskOrchestrator(); - this.memory = new PersistentMemorySystem(); - this.proactive = new ProactiveServiceSystem(); - log.info('Core systems initialized'); - - // 5. 初始化多 Agent 协作系统 - this.agentOrchestrator = new AgentOrchestrator(this.ai); - log.info('Agent Orchestrator initialized'); - - // 6. 初始化 IM 网关 - this.imGateway = new IMGateway(); - this.setupIMAdapters(config); - this.setupMessageRouting(); - log.info('IM Gateway initialized'); - - // 7. 连接 IM - await this.imGateway.connectAll(); - - log.info('ZCLAW started successfully! 🦞'); - log.info(`Server: ${config.server.host}:${config.server.port}`); - log.info(`AI Provider: ${config.ai.provider} (${config.ai.defaultModel})`); - log.info(`Connected IMs: ${this.imGateway.getConnectedAdapters().join(', ') || 'none'}`); - } - - private setupIMAdapters(config: ReturnType): void { - // 飞书 - if (config.im.feishu.enabled || config.im.feishu.appId) { - const feishu = new FeishuAdapter(config.im.feishu.appId, config.im.feishu.appSecret); - this.imGateway.registerAdapter(feishu); - } - - // TODO: 其他 IM 适配器 (Telegram, QQ, WeChat) - } - - private setupMessageRouting(): void { - this.imGateway.onMessage(async (message) => { - log.info(`Processing message from ${message.channelType}/${message.userId}: ${message.content.slice(0, 80)}`); - - try { - // 记忆:记录用户消息 - await this.memory.remember(message.userId, { - id: message.id, - userId: message.userId, - type: 'im_message', - content: { text: message.content, channel: message.channelType }, - timestamp: new Date(), - }); - - // 判断消息类型并路由 - const response = await this.handleUserMessage(message.userId, message.content); - - // 回复 - await this.imGateway.send({ - channelType: message.channelType, - channelId: message.channelId, - userId: message.userId, - content: response, - contentType: 'text', - }); - - } catch (error: any) { - log.error(`Message processing error: ${error.message}`); - await this.imGateway.send({ - channelType: message.channelType, - channelId: message.channelId, - content: `处理消息时出错: ${error.message}`, - contentType: 'text', - }); - } - }); - } - - async handleUserMessage(userId: string, content: string): Promise { - // 获取用户记忆上下文 - const recentMemories = await this.memory.recall(userId, content, 5); - const context: Record = {}; - if (recentMemories.length > 0) { - context.recentHistory = recentMemories.map(m => m.content); - } - - // 判断是否需要多步骤编排 - const isComplex = this.isComplexTask(content); - - if (isComplex) { - // 复杂任务 -> 多 Agent 协作 - log.info(`Complex task detected, starting multi-agent execution`); - const result = await this.agentOrchestrator.executeGoal(content, context); - return result.success - ? result.data?.report || '任务已完成' - : `任务执行失败: ${result.error}`; - } else { - // 简单对话 -> 直接 AI 回复 - const profile = await this.memory.getProfile(userId); - const systemPrompt = `你是 ZCLAW,一个智能 AI 助手 🦞。你友善、专业、高效。 -${profile ? `用户偏好: ${JSON.stringify(profile.preferences)}` : ''} -请用中文简洁回复。`; - - return await this.ai.ask(content, systemPrompt); - } - } - - private isComplexTask(content: string): boolean { - const complexIndicators = [ - '帮我做', '市场调研', '写报告', '分析', - '自动化', '批量', '多步骤', '流程', - '调研', '搜索并整理', '对比', '综合', - '项目管理', '代码生成', '部署', - ]; - return complexIndicators.some(indicator => content.includes(indicator)); - } - - // 公开接口:供 Tauri 前端调用 - getAI(): AIManager { return this.ai; } - getAgentOrchestrator(): AgentOrchestrator { return this.agentOrchestrator; } - getRemoteExecution(): RemoteExecutionEngine { return this.remoteExecution; } - getTaskOrchestrator(): TaskOrchestrator { return this.taskOrchestrator; } - getMemory(): PersistentMemorySystem { return this.memory; } - getProactive(): ProactiveServiceSystem { return this.proactive; } - getIMGateway(): IMGateway { return this.imGateway; } - - async shutdown(): Promise { - log.info('Shutting down ZCLAW...'); - await this.agentOrchestrator.shutdown(); - await this.imGateway.disconnectAll(); - closeDatabase(); - log.info('ZCLAW shutdown complete'); - } -} diff --git a/src/config/index.ts b/src/config/index.ts deleted file mode 100644 index a9d6232..0000000 --- a/src/config/index.ts +++ /dev/null @@ -1,118 +0,0 @@ -// ZCLAW 配置管理 -import { z } from 'zod'; - -const ConfigSchema = z.object({ - // AI Provider - ai: z.object({ - provider: z.enum(['zhipu', 'openai', 'local']).default('zhipu'), - zhipuApiKey: z.string().default(''), - openaiApiKey: z.string().default(''), - openaiBaseUrl: z.string().default('https://api.openai.com/v1'), - defaultModel: z.string().default('glm-4-flash'), - maxTokens: z.number().default(4096), - temperature: z.number().default(0.7), - }), - - // Database - db: z.object({ - path: z.string().default('./data/zclaw.db'), - }), - - // Server - server: z.object({ - port: z.number().default(3721), - host: z.string().default('127.0.0.1'), - }), - - // IM Channels - im: z.object({ - feishu: z.object({ - appId: z.string().default(''), - appSecret: z.string().default(''), - enabled: z.boolean().default(false), - }), - telegram: z.object({ - botToken: z.string().default(''), - enabled: z.boolean().default(false), - }), - }), - - // Execution - execution: z.object({ - maxConcurrent: z.number().default(5), - taskTimeout: z.number().default(300000), // 5 minutes - retryAttempts: z.number().default(3), - }), - - // Memory - memory: z.object({ - maxEventsPerUser: z.number().default(10000), - embeddingModel: z.string().default('text-embedding-3-small'), - }), - - // Logging - log: z.object({ - level: z.enum(['debug', 'info', 'warn', 'error']).default('info'), - }), -}); - -export type ZClawConfig = z.infer; - -let _config: ZClawConfig | null = null; - -export function loadConfig(overrides?: Partial>): ZClawConfig { - const env = process.env; - - const raw = { - ai: { - provider: env.ZCLAW_AI_PROVIDER || 'zhipu', - zhipuApiKey: env.ZCLAW_ZHIPU_API_KEY || env.ZHIPU_API_KEY || '', - openaiApiKey: env.ZCLAW_OPENAI_API_KEY || env.OPENAI_API_KEY || '', - openaiBaseUrl: env.ZCLAW_OPENAI_BASE_URL || 'https://api.openai.com/v1', - defaultModel: env.ZCLAW_DEFAULT_MODEL || 'glm-4-flash', - maxTokens: parseInt(env.ZCLAW_MAX_TOKENS || '4096'), - temperature: parseFloat(env.ZCLAW_TEMPERATURE || '0.7'), - }, - db: { - path: env.ZCLAW_DB_PATH || './data/zclaw.db', - }, - server: { - port: parseInt(env.ZCLAW_PORT || '3721'), - host: env.ZCLAW_HOST || '127.0.0.1', - }, - im: { - feishu: { - appId: env.ZCLAW_FEISHU_APP_ID || '', - appSecret: env.ZCLAW_FEISHU_APP_SECRET || '', - enabled: env.ZCLAW_FEISHU_ENABLED === 'true', - }, - telegram: { - botToken: env.ZCLAW_TELEGRAM_BOT_TOKEN || '', - enabled: env.ZCLAW_TELEGRAM_ENABLED === 'true', - }, - }, - execution: { - maxConcurrent: parseInt(env.ZCLAW_MAX_CONCURRENT || '5'), - taskTimeout: parseInt(env.ZCLAW_TASK_TIMEOUT || '300000'), - retryAttempts: parseInt(env.ZCLAW_RETRY_ATTEMPTS || '3'), - }, - memory: { - maxEventsPerUser: parseInt(env.ZCLAW_MAX_EVENTS || '10000'), - embeddingModel: env.ZCLAW_EMBEDDING_MODEL || 'text-embedding-3-small', - }, - log: { - level: env.ZCLAW_LOG_LEVEL || 'info', - }, - ...overrides, - }; - - _config = ConfigSchema.parse(raw); - return _config; -} - -export function getConfig(): ZClawConfig { - if (!_config) { - return loadConfig(); - } - return _config; -} diff --git a/src/core/ai/index.ts b/src/core/ai/index.ts deleted file mode 100644 index e015313..0000000 --- a/src/core/ai/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type { AIProvider, ChatMessage, ChatRequest, ChatResponse, StreamChunk, EmbeddingRequest, EmbeddingResponse } from './types'; -export { AIManager, getAIManager } from './manager'; -export { ZhipuProvider } from './providers/zhipu'; -export { OpenAIProvider } from './providers/openai'; diff --git a/src/core/ai/manager.ts b/src/core/ai/manager.ts deleted file mode 100644 index 4ef92cc..0000000 --- a/src/core/ai/manager.ts +++ /dev/null @@ -1,142 +0,0 @@ -// AI 模型管理器 - 统一调用接口,支持多 Provider fallback -import type { AIProvider, ChatRequest, ChatResponse, ChatMessage, StreamChunk, EmbeddingRequest, EmbeddingResponse } from './types'; -import { ZhipuProvider } from './providers/zhipu'; -import { OpenAIProvider } from './providers/openai'; -import { getConfig } from '../../config'; -import { createLogger } from '../../utils/logger'; - -const log = createLogger('AIManager'); - -export class AIManager { - private providers: Map = new Map(); - private defaultProvider: string; - - constructor() { - const config = getConfig(); - this.defaultProvider = config.ai.provider; - - // 注册智谱 GLM - if (config.ai.zhipuApiKey) { - this.providers.set('zhipu', new ZhipuProvider(config.ai.zhipuApiKey)); - log.info('Zhipu GLM provider registered'); - } - - // 注册 OpenAI 兼容 - if (config.ai.openaiApiKey) { - this.providers.set('openai', new OpenAIProvider(config.ai.openaiApiKey, config.ai.openaiBaseUrl)); - log.info('OpenAI provider registered'); - } - - if (this.providers.size === 0) { - log.warn('No AI providers configured. Set ZCLAW_ZHIPU_API_KEY or ZCLAW_OPENAI_API_KEY.'); - } - } - - getProvider(name?: string): AIProvider { - const providerName = name || this.defaultProvider; - const provider = this.providers.get(providerName); - if (!provider) { - // fallback: 尝试其他可用 provider - const fallback = this.providers.values().next().value; - if (fallback) { - log.warn(`Provider '${providerName}' not available, falling back to '${fallback.name}'`); - return fallback; - } - throw new Error(`No AI provider available. Configure at least one API key.`); - } - return provider; - } - - async chat(request: ChatRequest, providerName?: string): Promise { - const provider = this.getProvider(providerName); - const config = getConfig(); - - const enrichedRequest: ChatRequest = { - ...request, - model: request.model || config.ai.defaultModel, - temperature: request.temperature ?? config.ai.temperature, - maxTokens: request.maxTokens ?? config.ai.maxTokens, - }; - - log.debug(`Chat via ${provider.name}`, { model: enrichedRequest.model, messages: enrichedRequest.messages.length }); - - try { - const response = await provider.chat(enrichedRequest); - log.debug(`Chat response: ${response.usage.totalTokens} tokens`); - return response; - } catch (error: any) { - log.error(`Chat failed via ${provider.name}: ${error.message}`); - // 尝试 fallback - for (const [name, fallbackProvider] of this.providers) { - if (name !== provider.name) { - log.info(`Retrying with fallback provider: ${name}`); - try { - return await fallbackProvider.chat(enrichedRequest); - } catch { - continue; - } - } - } - throw error; - } - } - - async chatStream(request: ChatRequest, providerName?: string): Promise> { - const provider = this.getProvider(providerName); - if (!provider.chatStream) { - throw new Error(`Provider '${provider.name}' does not support streaming`); - } - return provider.chatStream(request); - } - - async embed(request: EmbeddingRequest, providerName?: string): Promise { - const provider = this.getProvider(providerName); - if (!provider.embed) { - throw new Error(`Provider '${provider.name}' does not support embeddings`); - } - return provider.embed(request); - } - - // 便捷方法:单次对话 - async ask(prompt: string, systemPrompt?: string): Promise { - const messages: ChatMessage[] = []; - if (systemPrompt) { - messages.push({ role: 'system', content: systemPrompt }); - } - messages.push({ role: 'user', content: prompt }); - - const response = await this.chat({ messages }); - return response.content; - } - - // 便捷方法:带上下文的多轮对话 - async chatWithHistory(messages: ChatMessage[], systemPrompt?: string): Promise { - const allMessages: ChatMessage[] = []; - if (systemPrompt) { - allMessages.push({ role: 'system', content: systemPrompt }); - } - allMessages.push(...messages); - - const response = await this.chat({ messages: allMessages }); - return response.content; - } - - // 便捷方法:JSON 输出 - async askJson(prompt: string, systemPrompt?: string): Promise { - const jsonSystemPrompt = (systemPrompt || '') + '\n\n请严格以 JSON 格式输出,不要包含 markdown 代码块标记。'; - const content = await this.ask(prompt, jsonSystemPrompt); - - // 清理可能的 markdown 代码块包裹 - const cleaned = content.replace(/^```(?:json)?\s*\n?/i, '').replace(/\n?```\s*$/i, '').trim(); - return JSON.parse(cleaned) as T; - } -} - -let _manager: AIManager | null = null; - -export function getAIManager(): AIManager { - if (!_manager) { - _manager = new AIManager(); - } - return _manager; -} diff --git a/src/core/ai/providers/openai.ts b/src/core/ai/providers/openai.ts deleted file mode 100644 index f9781b1..0000000 --- a/src/core/ai/providers/openai.ts +++ /dev/null @@ -1,139 +0,0 @@ -// OpenAI Compatible Provider (also works for local models via API) -import type { AIProvider, ChatRequest, ChatResponse, StreamChunk, EmbeddingRequest, EmbeddingResponse } from '../types'; -import { createLogger } from '../../../utils/logger'; - -const log = createLogger('OpenAIProvider'); - -export class OpenAIProvider implements AIProvider { - name = 'openai'; - private apiKey: string; - private baseUrl: string; - - constructor(apiKey: string, baseUrl: string = 'https://api.openai.com/v1') { - this.apiKey = apiKey; - this.baseUrl = baseUrl.replace(/\/$/, ''); - } - - async chat(request: ChatRequest): Promise { - const model = request.model || 'gpt-4o-mini'; - log.debug(`Chat request to ${model}`); - - const response = await fetch(`${this.baseUrl}/chat/completions`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${this.apiKey}`, - }, - body: JSON.stringify({ - model, - messages: request.messages, - temperature: request.temperature ?? 0.7, - max_tokens: request.maxTokens ?? 4096, - stream: false, - }), - }); - - if (!response.ok) { - const errorText = await response.text(); - log.error(`OpenAI API error: ${response.status}`, errorText); - throw new Error(`OpenAI API error: ${response.status} - ${errorText}`); - } - - const data: any = await response.json(); - const choice = data.choices?.[0]; - - return { - content: choice?.message?.content || '', - model: data.model || model, - usage: { - promptTokens: data.usage?.prompt_tokens || 0, - completionTokens: data.usage?.completion_tokens || 0, - totalTokens: data.usage?.total_tokens || 0, - }, - finishReason: choice?.finish_reason || 'stop', - }; - } - - async *chatStream(request: ChatRequest): AsyncIterable { - const model = request.model || 'gpt-4o-mini'; - - const response = await fetch(`${this.baseUrl}/chat/completions`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${this.apiKey}`, - }, - body: JSON.stringify({ - model, - messages: request.messages, - temperature: request.temperature ?? 0.7, - max_tokens: request.maxTokens ?? 4096, - stream: true, - }), - }); - - if (!response.ok) { - throw new Error(`OpenAI API error: ${response.status}`); - } - - const reader = response.body?.getReader(); - if (!reader) throw new Error('No response body'); - - const decoder = new TextDecoder(); - let buffer = ''; - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - - buffer += decoder.decode(value, { stream: true }); - const lines = buffer.split('\n'); - buffer = lines.pop() || ''; - - for (const line of lines) { - if (line.startsWith('data: ')) { - const data = line.slice(6).trim(); - if (data === '[DONE]') { - yield { content: '', done: true }; - return; - } - try { - const parsed = JSON.parse(data); - const delta = parsed.choices?.[0]?.delta?.content || ''; - if (delta) { - yield { content: delta, done: false }; - } - } catch { - // skip - } - } - } - } - } - - async embed(request: EmbeddingRequest): Promise { - const input = Array.isArray(request.input) ? request.input : [request.input]; - const model = request.model || 'text-embedding-3-small'; - - const response = await fetch(`${this.baseUrl}/embeddings`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${this.apiKey}`, - }, - body: JSON.stringify({ model, input }), - }); - - if (!response.ok) { - throw new Error(`OpenAI Embedding API error: ${response.status}`); - } - - const data: any = await response.json(); - - return { - embeddings: data.data?.map((d: any) => d.embedding) || [], - model: data.model || model, - usage: { totalTokens: data.usage?.total_tokens || 0 }, - }; - } -} diff --git a/src/core/ai/providers/zhipu.ts b/src/core/ai/providers/zhipu.ts deleted file mode 100644 index 48b7bc8..0000000 --- a/src/core/ai/providers/zhipu.ts +++ /dev/null @@ -1,138 +0,0 @@ -// 智谱 GLM AI Provider -import type { AIProvider, ChatRequest, ChatResponse, StreamChunk, EmbeddingRequest, EmbeddingResponse } from '../types'; -import { createLogger } from '../../../utils/logger'; - -const log = createLogger('ZhipuProvider'); - -export class ZhipuProvider implements AIProvider { - name = 'zhipu'; - private apiKey: string; - private baseUrl = 'https://open.bigmodel.cn/api/paas/v4'; - - constructor(apiKey: string) { - this.apiKey = apiKey; - } - - async chat(request: ChatRequest): Promise { - const model = request.model || 'glm-4-flash'; - log.debug(`Chat request to ${model}`, { messageCount: request.messages.length }); - - const response = await fetch(`${this.baseUrl}/chat/completions`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${this.apiKey}`, - }, - body: JSON.stringify({ - model, - messages: request.messages, - temperature: request.temperature ?? 0.7, - max_tokens: request.maxTokens ?? 4096, - stream: false, - }), - }); - - if (!response.ok) { - const errorText = await response.text(); - log.error(`Zhipu API error: ${response.status}`, errorText); - throw new Error(`Zhipu API error: ${response.status} - ${errorText}`); - } - - const data: any = await response.json(); - const choice = data.choices?.[0]; - - return { - content: choice?.message?.content || '', - model: data.model || model, - usage: { - promptTokens: data.usage?.prompt_tokens || 0, - completionTokens: data.usage?.completion_tokens || 0, - totalTokens: data.usage?.total_tokens || 0, - }, - finishReason: choice?.finish_reason || 'stop', - }; - } - - async *chatStream(request: ChatRequest): AsyncIterable { - const model = request.model || 'glm-4-flash'; - - const response = await fetch(`${this.baseUrl}/chat/completions`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${this.apiKey}`, - }, - body: JSON.stringify({ - model, - messages: request.messages, - temperature: request.temperature ?? 0.7, - max_tokens: request.maxTokens ?? 4096, - stream: true, - }), - }); - - if (!response.ok) { - throw new Error(`Zhipu API error: ${response.status}`); - } - - const reader = response.body?.getReader(); - if (!reader) throw new Error('No response body'); - - const decoder = new TextDecoder(); - let buffer = ''; - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - - buffer += decoder.decode(value, { stream: true }); - const lines = buffer.split('\n'); - buffer = lines.pop() || ''; - - for (const line of lines) { - if (line.startsWith('data: ')) { - const data = line.slice(6).trim(); - if (data === '[DONE]') { - yield { content: '', done: true }; - return; - } - try { - const parsed = JSON.parse(data); - const delta = parsed.choices?.[0]?.delta?.content || ''; - if (delta) { - yield { content: delta, done: false }; - } - } catch { - // skip invalid JSON - } - } - } - } - } - - async embed(request: EmbeddingRequest): Promise { - const input = Array.isArray(request.input) ? request.input : [request.input]; - const model = request.model || 'embedding-3'; - - const response = await fetch(`${this.baseUrl}/embeddings`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${this.apiKey}`, - }, - body: JSON.stringify({ model, input }), - }); - - if (!response.ok) { - throw new Error(`Zhipu Embedding API error: ${response.status}`); - } - - const data: any = await response.json(); - - return { - embeddings: data.data?.map((d: any) => d.embedding) || [], - model: data.model || model, - usage: { totalTokens: data.usage?.total_tokens || 0 }, - }; - } -} diff --git a/src/core/ai/types.ts b/src/core/ai/types.ts deleted file mode 100644 index 783fedf..0000000 --- a/src/core/ai/types.ts +++ /dev/null @@ -1,48 +0,0 @@ -// AI 模型集成层 - 类型定义 - -export interface ChatMessage { - role: 'system' | 'user' | 'assistant'; - content: string; -} - -export interface ChatRequest { - messages: ChatMessage[]; - model?: string; - temperature?: number; - maxTokens?: number; - stream?: boolean; -} - -export interface ChatResponse { - content: string; - model: string; - usage: { - promptTokens: number; - completionTokens: number; - totalTokens: number; - }; - finishReason: string; -} - -export interface StreamChunk { - content: string; - done: boolean; -} - -export interface EmbeddingRequest { - input: string | string[]; - model?: string; -} - -export interface EmbeddingResponse { - embeddings: number[][]; - model: string; - usage: { totalTokens: number }; -} - -export interface AIProvider { - name: string; - chat(request: ChatRequest): Promise; - chatStream?(request: ChatRequest): AsyncIterable; - embed?(request: EmbeddingRequest): Promise; -} diff --git a/src/core/memory/index.ts b/src/core/memory/index.ts deleted file mode 100644 index e2151a9..0000000 --- a/src/core/memory/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './memory'; diff --git a/src/core/memory/memory.ts b/src/core/memory/memory.ts deleted file mode 100644 index 7917edd..0000000 --- a/src/core/memory/memory.ts +++ /dev/null @@ -1,70 +0,0 @@ -// 持续记忆系统 -import { generateId } from '../../utils/id'; -import { createLogger } from '../../utils/logger'; - -const log = createLogger('Memory'); - -export interface UserProfile { - id: string; - preferences: { - language: 'zh' | 'en'; - timezone: string; - responseStyle: 'concise' | 'detailed'; - }; - patterns: { - activeHours: number[]; - frequentCommands: string[]; - }; -} - -export interface MemoryEvent { - id: string; - userId: string; - type: string; - content: any; - timestamp: Date; - embedding?: number[]; -} - -export class PersistentMemorySystem { - private profiles: Map = new Map(); - private events: MemoryEvent[] = []; - - async remember(userId: string, event: MemoryEvent): Promise { - event.id = event.id || this.generateId(); - event.timestamp = new Date(); - this.events.push(event); - log.debug(`Event remembered: ${event.id} for user ${userId}`); - } - - async recall(userId: string, query: string, limit: number = 10): Promise { - // TODO: 实现向量搜索(后续实现) - return this.events.filter(e => e.userId === userId).slice(0, limit); - } - - async getProfile(userId: string): Promise { - return this.profiles.get(userId); - } - - async updateProfile(userId: string, updates: Partial): Promise { - let profile = this.profiles.get(userId); - if (!profile) { - profile = { - id: userId, - preferences: { language: 'zh', timezone: 'Asia/Shanghai', responseStyle: 'concise' }, - patterns: { activeHours: [], frequentCommands: [] }, - }; - this.profiles.set(userId, profile); - } - Object.assign(profile, updates); - log.debug(`Profile updated for user ${userId}`); - } - - async getEventCount(userId: string): Promise { - return this.events.filter(e => e.userId === userId).length; - } - - private generateId(): string { - return generateId('mem'); - } -} diff --git a/src/core/multi-agent/agents/combiner-agent.ts b/src/core/multi-agent/agents/combiner-agent.ts deleted file mode 100644 index 8e4bac1..0000000 --- a/src/core/multi-agent/agents/combiner-agent.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Combiner Agent - 整合多个 Agent 的执行结果 -import { BaseAgent } from '../base-agent'; -import type { AgentTask } from '../types'; - -const COMBINER_SYSTEM_PROMPT = `你是一个结果整合专家。你的职责是将多个执行步骤的结果整合为一份完整、结构化的报告。 - -要求: -1. 综合分析所有步骤的执行结果 -2. 提取关键信息 -3. 生成简洁清晰的最终报告 -4. 如果某些步骤失败,说明缺失的信息 -5. 输出格式清晰,适合通过 IM 发送给用户`; - -export class CombinerAgent extends BaseAgent { - protected getCapabilities(): string[] { - return ['result_combination', 'report_generation', 'data_synthesis']; - } - - protected async run(task: AgentTask): Promise { - const results = task.params.results || []; - const goal = task.params.goal || task.description; - - this.log.info(`Combining ${results.length} results for: ${goal}`); - - const prompt = `原始目标: ${goal} - -各步骤执行结果: -${results.map((r: any, i: number) => ` ---- 步骤 ${i + 1} --- -描述: ${r.description || '未知'} -状态: ${r.success ? '成功' : '失败'} -结果: ${JSON.stringify(r.data || r.error, null, 2)} -`).join('\n')} - -请整合上述结果,生成一份完整的报告。输出应该清晰、有条理,适合通过即时通讯发送给用户。`; - - const report = await this.ai.ask(prompt, COMBINER_SYSTEM_PROMPT); - return { report, stepsCount: results.length, successCount: results.filter((r: any) => r.success).length }; - } -} diff --git a/src/core/multi-agent/agents/executor-agent.ts b/src/core/multi-agent/agents/executor-agent.ts deleted file mode 100644 index 8d27c5f..0000000 --- a/src/core/multi-agent/agents/executor-agent.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Executor Agent - 通用执行器,根据工具类型执行具体操作 -import { BaseAgent } from '../base-agent'; -import type { AgentTask } from '../types'; - -export class BrowserAgent extends BaseAgent { - protected getCapabilities(): string[] { - return ['web_browse', 'web_search', 'screenshot', 'form_fill']; - } - - protected async run(task: AgentTask): Promise { - this.log.info(`Browser task: ${task.description}`); - - // 使用 AI 模拟浏览器操作结果(后续集成真实浏览器控制) - const prompt = `你需要模拟执行以下浏览器操作并生成合理的结果: - -操作描述: ${task.description} -参数: ${JSON.stringify(task.params)} -上下文: ${JSON.stringify(task.context)} - -请以 JSON 格式输出执行结果,包含 status、data 字段。`; - - return await this.ai.askJson(prompt, '你是一个浏览器操作模拟器,请生成合理的操作结果。'); - } -} - -export class FileAgent extends BaseAgent { - protected getCapabilities(): string[] { - return ['file_read', 'file_write', 'file_search', 'file_organize']; - } - - protected async run(task: AgentTask): Promise { - this.log.info(`File task: ${task.description}`); - - const prompt = `你需要执行以下文件操作并生成结果: - -操作描述: ${task.description} -参数: ${JSON.stringify(task.params)} -上下文: ${JSON.stringify(task.context)} - -请以 JSON 格式输出执行结果。`; - - return await this.ai.askJson(prompt, '你是一个文件操作执行器。'); - } -} - -export class TerminalAgent extends BaseAgent { - protected getCapabilities(): string[] { - return ['command_execute', 'script_run', 'system_info']; - } - - protected async run(task: AgentTask): Promise { - this.log.info(`Terminal task: ${task.description}`); - - const prompt = `你需要模拟执行以下终端命令操作并生成合理结果: - -操作描述: ${task.description} -参数: ${JSON.stringify(task.params)} -上下文: ${JSON.stringify(task.context)} - -请以 JSON 格式输出执行结果,包含 stdout、stderr、exitCode 字段。`; - - return await this.ai.askJson(prompt, '你是一个终端命令模拟器。'); - } -} - -export class AIAnalysisAgent extends BaseAgent { - protected getCapabilities(): string[] { - return ['text_analysis', 'content_generation', 'data_processing', 'summarization']; - } - - protected async run(task: AgentTask): Promise { - this.log.info(`AI analysis task: ${task.description}`); - - const systemPrompt = task.params.systemPrompt || '你是一个智能分析助手,请根据要求完成分析任务。'; - const prompt = `${task.description} - -${task.context ? `上下文数据:\n${JSON.stringify(task.context, null, 2)}` : ''} -${task.params.data ? `输入数据:\n${JSON.stringify(task.params.data, null, 2)}` : ''}`; - - const result = await this.ai.ask(prompt, systemPrompt); - return { analysis: result }; - } -} diff --git a/src/core/multi-agent/agents/planner-agent.ts b/src/core/multi-agent/agents/planner-agent.ts deleted file mode 100644 index 442202b..0000000 --- a/src/core/multi-agent/agents/planner-agent.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Planner Agent - 任务规划,将用户目标拆解为可执行步骤 -import { BaseAgent } from '../base-agent'; -import type { AgentTask } from '../types'; - -const PLANNER_SYSTEM_PROMPT = `你是一个高级任务规划专家。你的职责是将用户的目标拆解为可执行的步骤序列。 - -可用工具类型: -- browser: 浏览器操作(访问网页、截图、填表、搜索) -- file: 文件操作(读写、搜索、整理、生成文档) -- terminal: 终端命令(代码执行、系统操作、安装软件) -- api: API 调用(搜索引擎、天气、翻译等) -- ai: AI 分析(文本分析、内容生成、数据处理) - -输出要求: -严格输出 JSON 格式,不要包含 markdown 代码块标记。 -{ - "steps": [ - { - "id": "step_1", - "description": "步骤描述", - "tool": "browser", - "params": { "url": "https://example.com", "action": "search" }, - "dependencies": [] - }, - { - "id": "step_2", - "description": "步骤描述", - "tool": "ai", - "params": { "action": "analyze" }, - "dependencies": ["step_1"] - } - ] -} - -规则: -1. 每个步骤必须明确、可执行 -2. 标注步骤之间的依赖关系(dependencies 数组) -3. 无依赖的步骤可以并行执行 -4. 步骤数量控制在 3-10 个之间 -5. 最后一个步骤通常是整合/汇总结果`; - -export class PlannerAgent extends BaseAgent { - protected getCapabilities(): string[] { - return ['task_planning', 'task_decomposition', 'dependency_analysis']; - } - - protected async run(task: AgentTask): Promise { - const goal = task.params.goal || task.description; - const context = task.context || {}; - - this.log.info(`Planning task: ${goal}`); - - const prompt = `目标: ${goal} - -${Object.keys(context).length > 0 ? `上下文信息:\n${JSON.stringify(context, null, 2)}` : ''} - -请将上述目标拆解为可执行步骤。`; - - const response = await this.ai.askJson<{ steps: any[] }>(prompt, PLANNER_SYSTEM_PROMPT); - - this.log.info(`Plan generated: ${response.steps.length} steps`); - return response; - } -} diff --git a/src/core/multi-agent/base-agent.ts b/src/core/multi-agent/base-agent.ts deleted file mode 100644 index cb85437..0000000 --- a/src/core/multi-agent/base-agent.ts +++ /dev/null @@ -1,126 +0,0 @@ -// 多 Agent 协作系统 - Agent 基类 -import type { AgentType, AgentConfig, AgentInfo, AgentTask, AgentResult, AgentMessage, AgentStatus } from './types'; -import type { MessageBus } from './message-bus'; -import type { AIManager } from '../ai/manager'; -import { generateId } from '../../utils/id'; -import { createLogger, type Logger } from '../../utils/logger'; - -export abstract class BaseAgent { - readonly id: string; - readonly type: AgentType; - readonly name: string; - protected status: AgentStatus = 'idle'; - protected config: AgentConfig; - protected messageBus: MessageBus; - protected ai: AIManager; - protected log: Logger; - protected currentTaskId?: string; - protected createdAt: Date = new Date(); - - constructor( - type: AgentType, - config: AgentConfig, - messageBus: MessageBus, - ai: AIManager, - ) { - this.id = generateId('agent'); - this.type = type; - this.name = config.name || `${type}-agent`; - this.config = config; - this.messageBus = messageBus; - this.ai = ai; - this.log = createLogger(`Agent:${this.name}`); - - // 订阅消息 - this.messageBus.subscribe(this.id, (msg) => this.handleMessage(msg)); - - this.log.info(`Agent created: ${this.id}`); - } - - getInfo(): AgentInfo { - return { - id: this.id, - type: this.type, - name: this.name, - status: this.status, - capabilities: this.getCapabilities(), - currentTaskId: this.currentTaskId, - createdAt: this.createdAt, - }; - } - - async execute(task: AgentTask): Promise { - this.status = 'busy'; - this.currentTaskId = task.id; - const startTime = Date.now(); - - this.log.info(`Executing task: ${task.id} - ${task.description}`); - - // 通知开始执行 - await this.messageBus.send({ - from: this.id, - to: '*', - type: 'status', - payload: { taskId: task.id, status: 'running' }, - }); - - try { - const data = await this.run(task); - const result: AgentResult = { - taskId: task.id, - agentId: this.id, - success: true, - data, - duration: Date.now() - startTime, - }; - - // 通知完成 - await this.messageBus.send({ - from: this.id, - to: '*', - type: 'result', - payload: result, - }); - - this.status = 'idle'; - this.currentTaskId = undefined; - this.log.info(`Task completed: ${task.id} (${result.duration}ms)`); - return result; - - } catch (error: any) { - const result: AgentResult = { - taskId: task.id, - agentId: this.id, - success: false, - error: error.message, - duration: Date.now() - startTime, - }; - - await this.messageBus.send({ - from: this.id, - to: '*', - type: 'error', - payload: result, - }); - - this.status = 'error'; - this.currentTaskId = undefined; - this.log.error(`Task failed: ${task.id} - ${error.message}`); - return result; - } - } - - async terminate(): Promise { - this.status = 'terminated'; - this.messageBus.unsubscribe(this.id); - this.log.info(`Agent terminated: ${this.id}`); - } - - // 子类必须实现 - protected abstract run(task: AgentTask): Promise; - protected abstract getCapabilities(): string[]; - - protected async handleMessage(message: AgentMessage): Promise { - this.log.debug(`Received message from ${message.from}: ${message.type}`); - } -} diff --git a/src/core/multi-agent/index.ts b/src/core/multi-agent/index.ts deleted file mode 100644 index 0b13505..0000000 --- a/src/core/multi-agent/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type { AgentType, AgentConfig, AgentInfo, AgentTask, AgentResult, AgentMessage, AgentStatus, MultiAgentPlan } from './types'; -export { BaseAgent } from './base-agent'; -export { MessageBus } from './message-bus'; -export { AgentOrchestrator } from './orchestrator'; -export { PlannerAgent } from './agents/planner-agent'; -export { BrowserAgent, FileAgent, TerminalAgent, AIAnalysisAgent } from './agents/executor-agent'; -export { CombinerAgent } from './agents/combiner-agent'; diff --git a/src/core/multi-agent/message-bus.ts b/src/core/multi-agent/message-bus.ts deleted file mode 100644 index d712f80..0000000 --- a/src/core/multi-agent/message-bus.ts +++ /dev/null @@ -1,71 +0,0 @@ -// 多 Agent 消息总线 - Agent 间通信的核心 -import type { AgentMessage, MessageHandler } from './types'; -import { generateId } from '../../utils/id'; -import { createLogger } from '../../utils/logger'; - -const log = createLogger('MessageBus'); - -export class MessageBus { - private subscribers: Map = new Map(); - private broadcastHandlers: MessageHandler[] = []; - private messageLog: AgentMessage[] = []; - - subscribe(agentId: string, handler: MessageHandler): void { - if (!this.subscribers.has(agentId)) { - this.subscribers.set(agentId, []); - } - this.subscribers.get(agentId)!.push(handler); - log.debug(`Agent ${agentId} subscribed to message bus`); - } - - unsubscribe(agentId: string): void { - this.subscribers.delete(agentId); - log.debug(`Agent ${agentId} unsubscribed from message bus`); - } - - onBroadcast(handler: MessageHandler): void { - this.broadcastHandlers.push(handler); - } - - async send(message: Omit): Promise { - const fullMessage: AgentMessage = { - ...message, - id: generateId('msg'), - timestamp: new Date(), - }; - - this.messageLog.push(fullMessage); - log.debug(`Message: ${fullMessage.from} -> ${fullMessage.to} [${fullMessage.type}]`); - - if (fullMessage.to === '*') { - // 广播 - const allHandlers = [...this.broadcastHandlers]; - for (const [, handlers] of this.subscribers) { - allHandlers.push(...handlers); - } - await Promise.allSettled(allHandlers.map(h => h(fullMessage))); - } else { - // 定向发送 - const handlers = this.subscribers.get(fullMessage.to); - if (handlers) { - await Promise.allSettled(handlers.map(h => h(fullMessage))); - } else { - log.warn(`No handlers for agent ${fullMessage.to}`); - } - } - } - - getMessages(agentId?: string, limit: number = 50): AgentMessage[] { - let messages = this.messageLog; - if (agentId) { - messages = messages.filter(m => m.from === agentId || m.to === agentId || m.to === '*'); - } - return messages.slice(-limit); - } - - clear(): void { - this.subscribers.clear(); - this.broadcastHandlers = []; - this.messageLog = []; - } -} diff --git a/src/core/multi-agent/orchestrator.ts b/src/core/multi-agent/orchestrator.ts deleted file mode 100644 index f686c4f..0000000 --- a/src/core/multi-agent/orchestrator.ts +++ /dev/null @@ -1,262 +0,0 @@ -// 多 Agent 协作系统 - 编排器(核心协调器) -import type { AgentType, AgentConfig, AgentTask, AgentResult, MultiAgentPlan } from './types'; -import { BaseAgent } from './base-agent'; -import { MessageBus } from './message-bus'; -import { PlannerAgent } from './agents/planner-agent'; -import { BrowserAgent, FileAgent, TerminalAgent, AIAnalysisAgent } from './agents/executor-agent'; -import { CombinerAgent } from './agents/combiner-agent'; -import { AIManager } from '../ai/manager'; -import { generateId } from '../../utils/id'; -import { createLogger } from '../../utils/logger'; - -const log = createLogger('AgentOrchestrator'); - -type ProgressCallback = (plan: MultiAgentPlan, currentStep?: string) => void; - -export class AgentOrchestrator { - private agents: Map = new Map(); - private messageBus: MessageBus; - private ai: AIManager; - private activePlans: Map = new Map(); - - constructor(ai: AIManager) { - this.messageBus = new MessageBus(); - this.ai = ai; - log.info('AgentOrchestrator initialized'); - } - - // 创建 Agent - spawnAgent(type: AgentType, config: AgentConfig = {}): BaseAgent { - let agent: BaseAgent; - - switch (type) { - case 'planner': - agent = new PlannerAgent(type, config, this.messageBus, this.ai); - break; - case 'browser': - agent = new BrowserAgent(type, config, this.messageBus, this.ai); - break; - case 'file': - agent = new FileAgent(type, config, this.messageBus, this.ai); - break; - case 'terminal': - agent = new TerminalAgent(type, config, this.messageBus, this.ai); - break; - case 'combiner': - agent = new CombinerAgent(type, config, this.messageBus, this.ai); - break; - case 'custom': - default: - agent = new AIAnalysisAgent(type, config, this.messageBus, this.ai); - break; - } - - this.agents.set(agent.id, agent); - log.info(`Agent spawned: ${agent.id} (${type})`); - return agent; - } - - // 终止 Agent - async terminateAgent(agentId: string): Promise { - const agent = this.agents.get(agentId); - if (agent) { - await agent.terminate(); - this.agents.delete(agentId); - } - } - - // 核心方法:执行多 Agent 协作任务 - async executeGoal(goal: string, context: Record = {}, onProgress?: ProgressCallback): Promise { - const planId = generateId('plan'); - log.info(`Starting multi-agent execution: ${goal} (${planId})`); - - const plan: MultiAgentPlan = { - id: planId, - goal, - steps: [], - agentAssignments: new Map(), - status: 'planning', - results: [], - createdAt: new Date(), - }; - this.activePlans.set(planId, plan); - - try { - // Phase 1: 规划 - 使用 Planner Agent 拆解任务 - plan.status = 'planning'; - onProgress?.(plan, '正在规划任务...'); - - const planner = this.spawnAgent('planner', { name: 'task-planner' }); - const planResult = await planner.execute({ - id: generateId('task'), - type: 'plan', - description: '规划任务', - params: { goal }, - context, - dependencies: [], - }); - - if (!planResult.success || !planResult.data?.steps) { - throw new Error(`Planning failed: ${planResult.error || 'No steps generated'}`); - } - - const steps: AgentTask[] = planResult.data.steps.map((s: any) => ({ - id: s.id || generateId('step'), - type: s.tool || 'ai', - description: s.description, - params: s.params || {}, - context: {}, - dependencies: s.dependencies || [], - })); - - plan.steps = steps; - log.info(`Plan created with ${steps.length} steps`); - onProgress?.(plan, `已规划 ${steps.length} 个步骤`); - - // Phase 2: 执行 - 按依赖顺序执行各步骤 - plan.status = 'executing'; - const stepResults: Map = new Map(); - - // 拓扑排序 - const sortedSteps = this.topologicalSort(steps); - - for (const step of sortedSteps) { - // 等待依赖完成 - for (const depId of step.dependencies) { - const depResult = stepResults.get(depId); - if (depResult?.data) { - step.context[depId] = depResult.data; - } - } - - // 根据工具类型选择 Agent - const agentType = this.mapToolToAgentType(step.type); - const executor = this.spawnAgent(agentType, { name: `executor-${step.id}` }); - plan.agentAssignments.set(step.id, executor.id); - - onProgress?.(plan, `正在执行: ${step.description}`); - - const result = await executor.execute(step); - stepResults.set(step.id, result); - plan.results.push(result); - - // 执行完毕,终止 executor - await this.terminateAgent(executor.id); - - if (!result.success) { - log.warn(`Step failed: ${step.id} - ${result.error}`); - // 继续执行其他不依赖此步骤的任务 - } - } - - // Phase 3: 整合 - 使用 Combiner Agent 汇总结果 - onProgress?.(plan, '正在整合结果...'); - - const combiner = this.spawnAgent('combiner', { name: 'result-combiner' }); - const combineResult = await combiner.execute({ - id: generateId('task'), - type: 'combine', - description: '整合所有步骤的结果', - params: { - goal, - results: plan.results.map((r, i) => ({ - ...r, - description: steps[i]?.description, - })), - }, - context: {}, - dependencies: [], - }); - - // 清理 - await this.terminateAgent(planner.id); - await this.terminateAgent(combiner.id); - - plan.status = 'completed'; - onProgress?.(plan, '任务完成'); - - log.info(`Multi-agent execution completed: ${planId}`); - - return { - taskId: planId, - agentId: 'orchestrator', - success: combineResult.success, - data: { - plan: plan.goal, - stepsExecuted: plan.results.length, - stepsSucceeded: plan.results.filter(r => r.success).length, - report: combineResult.data?.report || '', - stepResults: plan.results, - }, - duration: Date.now() - plan.createdAt.getTime(), - }; - - } catch (error: any) { - plan.status = 'failed'; - log.error(`Multi-agent execution failed: ${error.message}`); - - // 清理所有 Agent - for (const [id] of this.agents) { - await this.terminateAgent(id); - } - - return { - taskId: planId, - agentId: 'orchestrator', - success: false, - error: error.message, - duration: Date.now() - plan.createdAt.getTime(), - }; - } - } - - // 获取活跃计划 - getActivePlans(): MultiAgentPlan[] { - return Array.from(this.activePlans.values()); - } - - // 获取所有 Agent - getAgents(): BaseAgent[] { - return Array.from(this.agents.values()); - } - - private mapToolToAgentType(tool: string): AgentType { - switch (tool) { - case 'browser': return 'browser'; - case 'file': return 'file'; - case 'terminal': return 'terminal'; - case 'ai': - case 'api': - default: return 'custom'; // AIAnalysisAgent - } - } - - private topologicalSort(steps: AgentTask[]): AgentTask[] { - const sorted: AgentTask[] = []; - const visited = new Set(); - - const visit = (step: AgentTask) => { - if (visited.has(step.id)) return; - visited.add(step.id); - - for (const depId of step.dependencies) { - const dep = steps.find(s => s.id === depId); - if (dep) visit(dep); - } - - sorted.push(step); - }; - - steps.forEach(visit); - return sorted; - } - - async shutdown(): Promise { - for (const [id] of this.agents) { - await this.terminateAgent(id); - } - this.messageBus.clear(); - this.activePlans.clear(); - log.info('AgentOrchestrator shutdown'); - } -} diff --git a/src/core/multi-agent/types.ts b/src/core/multi-agent/types.ts deleted file mode 100644 index 6d94550..0000000 --- a/src/core/multi-agent/types.ts +++ /dev/null @@ -1,63 +0,0 @@ -// 多 Agent 协作系统 - 类型定义 - -export type AgentType = 'planner' | 'browser' | 'file' | 'terminal' | 'combiner' | 'custom'; -export type AgentStatus = 'idle' | 'busy' | 'error' | 'terminated'; - -export interface AgentConfig { - name?: string; - systemPrompt?: string; - model?: string; - maxRetries?: number; - timeout?: number; -} - -export interface AgentInfo { - id: string; - type: AgentType; - name: string; - status: AgentStatus; - capabilities: string[]; - currentTaskId?: string; - createdAt: Date; -} - -export interface AgentTask { - id: string; - type: string; - description: string; - params: Record; - context: Record; - dependencies: string[]; -} - -export interface AgentResult { - taskId: string; - agentId: string; - success: boolean; - data?: any; - error?: string; - duration: number; -} - -// 消息总线 -export interface AgentMessage { - id: string; - from: string; - to: string; // agent ID 或 '*' 表示广播 - type: 'task' | 'result' | 'status' | 'data' | 'error' | 'control'; - payload: any; - timestamp: Date; -} - -export type MessageHandler = (message: AgentMessage) => void | Promise; - -// 多 Agent 任务 -export interface MultiAgentPlan { - id: string; - goal: string; - steps: AgentTask[]; - agentAssignments: Map; // taskId -> agentId - status: 'planning' | 'executing' | 'completed' | 'failed'; - results: AgentResult[]; - createdAt: Date; -} diff --git a/src/core/proactive/index.ts b/src/core/proactive/index.ts deleted file mode 100644 index 927bc4b..0000000 --- a/src/core/proactive/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './proactive'; diff --git a/src/core/proactive/proactive.ts b/src/core/proactive/proactive.ts deleted file mode 100644 index 581b449..0000000 --- a/src/core/proactive/proactive.ts +++ /dev/null @@ -1,90 +0,0 @@ -// 主动服务系统 -import { generateId } from '../../utils/id'; -import { createLogger } from '../../utils/logger'; - -const log = createLogger('Proactive'); - -export interface ScheduledTask { - id: string; - userId: string; - channel: string; - schedule: { - type: 'once' | 'daily' | 'weekly' | 'cron'; - time: string; - timezone: string; - }; - task: { - type: string; - prompt: string; - }; - status: 'active' | 'paused' | 'completed'; - lastRun?: Date; - nextRun?: Date; -} - -export class ProactiveServiceSystem { - private tasks: Map = new Map(); - private cronJobs: Map = new Map(); - - async scheduleTask(task: ScheduledTask): Promise { - task.id = task.id || this.generateId(); - task.status = 'active'; - - this.tasks.set(task.id, task); - - // node-cron 集成(可选依赖) - try { - const cron = require('node-cron'); - const cronExpr = this.toCronExpression(task); - if (cronExpr) { - const job = cron.schedule(cronExpr, () => { - log.info(`Cron triggered: ${task.id}`); - // TODO: 执行实际任务逻辑 - task.lastRun = new Date(); - }, { timezone: task.schedule.timezone }); - this.cronJobs.set(task.id, job); - } - } catch { - log.debug('node-cron not available, scheduling in-memory only'); - } - - log.info(`Task scheduled: ${task.id} (${task.schedule.type} at ${task.schedule.time})`); - } - - async cancelTask(taskId: string): Promise { - const task = this.tasks.get(taskId); - if (task) { - task.status = 'paused'; - // TODO: 取消 cron job - } - } - - async listTasks(userId: string): Promise { - return Array.from(this.tasks.values()).filter(t => t.userId === userId); - } - - private toCronExpression(task: ScheduledTask): string | null { - const { type, time } = task.schedule; - if (type === 'cron') return time; // already a cron expression - - // Parse HH:MM format - const parts = time.split(':'); - if (parts.length !== 2) return null; - const [hour, minute] = parts; - - switch (type) { - case 'daily': - return `${minute} ${hour} * * *`; - case 'weekly': - return `${minute} ${hour} * * 1`; // Monday - case 'once': - return null; // handled separately via setTimeout - default: - return null; - } - } - - private generateId(): string { - return generateId('cron'); - } -} diff --git a/src/core/remote-execution/engine.ts b/src/core/remote-execution/engine.ts deleted file mode 100644 index 464d727..0000000 --- a/src/core/remote-execution/engine.ts +++ /dev/null @@ -1,166 +0,0 @@ -// 远程执行系统 - 实现类 -import type { - RemoteExecutionSystem, - Device, - Task, - TaskStatus, - StatusHandler, - Result, - DeviceStatus -} from './types'; -import { generateId } from '../../utils/id'; -import { createLogger } from '../../utils/logger'; - -const log = createLogger('RemoteExecution'); - -export class RemoteExecutionEngine implements RemoteExecutionSystem { - private devices: Map = new Map(); - private tasks: Map = new Map(); - private subscriptions: Map = new Map(); - private runningCount = 0; - private maxConcurrent: number; - private pendingQueue: Task[] = []; - - constructor(maxConcurrent: number = 5) { - this.maxConcurrent = maxConcurrent; - } - - async registerDevice(device: Device): Promise { - this.devices.set(device.id, device); - log.info(`Device registered: ${device.id} (${device.platform})`); - } - - async heartbeat(deviceId: string): Promise { - const device = this.devices.get(deviceId); - if (!device) { - throw new Error(`Device not found: ${deviceId}`); - } - device.lastHeartbeat = new Date(); - return device.status; - } - - async submitTask(task: Task): Promise { - task.id = task.id || generateId('task'); - task.status = 'pending'; - task.createdAt = new Date(); - this.tasks.set(task.id, task); - - log.info(`Task submitted: ${task.id} (priority: ${task.priority})`); - - if (this.runningCount < this.maxConcurrent) { - this.executeTask(task).catch(err => log.error(`Task execution error: ${err.message}`)); - } else { - this.pendingQueue.push(task); - log.debug(`Task queued (${this.pendingQueue.length} pending)`); - } - - return task.id; - } - - async cancelTask(taskId: string): Promise { - const task = this.tasks.get(taskId); - if (!task) throw new Error(`Task not found: ${taskId}`); - task.status = 'cancelled'; - this.notifySubscribers(taskId, 'cancelled'); - log.info(`Task cancelled: ${taskId}`); - } - - async getStatus(taskId: string): Promise { - const task = this.tasks.get(taskId); - if (!task) throw new Error(`Task not found: ${taskId}`); - return task.status; - } - - getTask(taskId: string): Task | undefined { - return this.tasks.get(taskId); - } - - getDevice(deviceId: string): Device | undefined { - return this.devices.get(deviceId); - } - - listDevices(): Device[] { - return Array.from(this.devices.values()); - } - - listTasks(filter?: { status?: TaskStatus; userId?: string }): Task[] { - let tasks = Array.from(this.tasks.values()); - if (filter?.status) tasks = tasks.filter(t => t.status === filter.status); - if (filter?.userId) tasks = tasks.filter(t => t.userId === filter.userId); - return tasks.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()); - } - - subscribe(taskId: string, handler: StatusHandler): void { - if (!this.subscriptions.has(taskId)) { - this.subscriptions.set(taskId, []); - } - this.subscriptions.get(taskId)!.push(handler); - } - - async pushResult(taskId: string, result: Result): Promise { - const task = this.tasks.get(taskId); - if (!task) throw new Error(`Task not found: ${taskId}`); - task.result = result; - task.status = result.success ? 'completed' : 'failed'; - task.completedAt = new Date(); - this.notifySubscribers(taskId, task.status); - } - - getStats(): { total: number; running: number; pending: number; completed: number; failed: number } { - const tasks = Array.from(this.tasks.values()); - return { - total: tasks.length, - running: tasks.filter(t => t.status === 'running').length, - pending: tasks.filter(t => t.status === 'pending').length, - completed: tasks.filter(t => t.status === 'completed').length, - failed: tasks.filter(t => t.status === 'failed').length, - }; - } - - private async executeTask(task: Task): Promise { - this.runningCount++; - try { - task.status = 'running'; - task.startedAt = new Date(); - this.notifySubscribers(task.id, 'running'); - log.info(`Executing task: ${task.id}`); - - // TODO: 集成 OpenClaw SDK 实际执行 - await new Promise(resolve => setTimeout(resolve, 1000)); - - await this.pushResult(task.id, { - taskId: task.id, - success: true, - data: { message: 'Task completed successfully' } - }); - } catch (error: any) { - await this.pushResult(task.id, { - taskId: task.id, - success: false, - error: error.message - }); - } finally { - this.runningCount--; - this.processNextInQueue(); - } - } - - private processNextInQueue(): void { - if (this.pendingQueue.length > 0 && this.runningCount < this.maxConcurrent) { - // 按优先级排序 - this.pendingQueue.sort((a, b) => { - const priority: Record = { high: 0, normal: 1, low: 2 }; - return (priority[a.priority] ?? 1) - (priority[b.priority] ?? 1); - }); - const next = this.pendingQueue.shift()!; - this.executeTask(next).catch(err => log.error(`Queued task error: ${err.message}`)); - } - } - - private notifySubscribers(taskId: string, status: TaskStatus, progress?: number): void { - const handlers = this.subscriptions.get(taskId); - if (handlers) { - handlers.forEach(handler => handler(status, progress)); - } - } -} diff --git a/src/core/remote-execution/index.ts b/src/core/remote-execution/index.ts deleted file mode 100644 index dd9c331..0000000 --- a/src/core/remote-execution/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './engine'; diff --git a/src/core/remote-execution/types.ts b/src/core/remote-execution/types.ts deleted file mode 100644 index 55b68c4..0000000 --- a/src/core/remote-execution/types.ts +++ /dev/null @@ -1,46 +0,0 @@ -// 远程执行系统 - 核心接口 -export interface Device { - id: string; - name: string; - userId: string; - platform: 'macos' | 'windows' | 'linux'; - capabilities: string[]; - status: 'online' | 'offline' | 'busy'; - lastHeartbeat: Date; -} - -export interface Task { - id: string; - userId: string; - deviceId: string; - channel: string; - type: 'immediate' | 'scheduled'; - priority: 'high' | 'normal' | 'low'; - payload: any; - status: TaskStatus; - result?: any; - createdAt: Date; - startedAt?: Date; - completedAt?: Date; -} - -export type TaskStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'; - -export interface RemoteExecutionSystem { - registerDevice(device: Device): Promise; - heartbeat(deviceId: string): Promise; - submitTask(task: Task): Promise; - cancelTask(taskId: string): Promise; - getStatus(taskId: string): Promise; - subscribe(taskId: string, handler: StatusHandler): void; - pushResult(taskId: string, result: Result): Promise; -} - -export type StatusHandler = (status: TaskStatus, progress?: number) => void; -export type DeviceStatus = 'online' | 'offline' | 'busy'; -export interface Result { - taskId: string; - success: boolean; - data?: any; - error?: string; -} diff --git a/src/core/task-orchestration/index.ts b/src/core/task-orchestration/index.ts deleted file mode 100644 index 69ca71b..0000000 --- a/src/core/task-orchestration/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './orchestrator'; diff --git a/src/core/task-orchestration/orchestrator.ts b/src/core/task-orchestration/orchestrator.ts deleted file mode 100644 index a72e3f8..0000000 --- a/src/core/task-orchestration/orchestrator.ts +++ /dev/null @@ -1,196 +0,0 @@ -// 任务编排引擎 - 实现类 -import type { - TaskOrchestrationEngine, - TaskPlan, - TaskStep, - ExecutionResult, - Progress, - StepStatus -} from './types'; -import { generateId } from '../../utils/id'; -import { createLogger } from '../../utils/logger'; - -const log = createLogger('TaskOrchestrator'); - -export class TaskOrchestrator implements TaskOrchestrationEngine { - private plans: Map = new Map(); - - async plan(goal: string, context: any): Promise { - // TODO: 使用 AI 规划任务(后续实现) - // 这里先返回一个简单的示例计划 - const steps: TaskStep[] = [ - { - id: 'step_1', - description: '分析任务需求', - tool: 'ai', - params: { goal }, - dependencies: [], - status: 'pending' - }, - { - id: 'step_2', - description: '执行任务', - tool: 'executor', - params: { goal }, - dependencies: ['step_1'], - status: 'pending' - }, - { - id: 'step_3', - description: '整理结果', - tool: 'combiner', - params: {}, - dependencies: ['step_2'], - status: 'pending' - } - ]; - - const plan: TaskPlan = { - id: this.generateId(), - goal, - steps, - dependencies: new Map(), - context: new Map(Object.entries(context)), - status: 'planned', - progress: 0 - }; - - this.plans.set(plan.id, plan); - log.info(`Plan created: ${plan.id} with ${steps.length} steps`); - - return plan; - } - - async execute(plan: TaskPlan): Promise { - plan.status = 'executing'; - - try { - // 拓扑排序 - const sortedSteps = this.topologicalSort(plan.steps); - - for (const step of sortedSteps) { - // 检查依赖 - await this.waitForDependencies(step, plan); - - // 执行步骤 - step.status = 'running'; - plan.progress = this.calculateProgress(plan); - - log.info(`Executing step: ${step.id} - ${step.description}`); - - // TODO: 实际执行逻辑(后续实现) - await new Promise(resolve => setTimeout(resolve, 500)); - - step.status = 'completed'; - step.result = { message: 'Step completed' }; - - plan.progress = this.calculateProgress(plan); - } - - plan.status = 'completed'; - plan.progress = 1; - - return { - planId: plan.id, - status: 'completed', - results: plan.steps.map(s => s.result) - }; - - } catch (error: any) { - plan.status = 'failed'; - throw error; - } - } - - async getProgress(planId: string): Promise { - const plan = this.plans.get(planId); - if (!plan) { - throw new Error(`Plan not found: ${planId}`); - } - - const completed = plan.steps.filter(s => s.status === 'completed').length; - const percentage = (plan.progress * 100).toFixed(1) + '%'; - - return { - planId: plan.id, - goal: plan.goal, - total: plan.steps.length, - completed, - current: plan.steps.find(s => s.status === 'running')?.description || '', - percentage, - steps: plan.steps.map(s => ({ - description: s.description, - status: s.status, - result: s.result - })) - }; - } - - async pause(planId: string): Promise { - const plan = this.plans.get(planId); - if (plan) { - plan.status = 'paused'; - } - } - - async resume(planId: string): Promise { - const plan = this.plans.get(planId); - if (plan && plan.status === 'paused') { - plan.status = 'executing'; - // 继续执行(后续实现) - } - } - - async cancel(planId: string): Promise { - const plan = this.plans.get(planId); - if (plan) { - plan.status = 'failed'; - } - } - - private topologicalSort(steps: TaskStep[]): TaskStep[] { - // 简单实现:按依赖顺序排序 - const sorted: TaskStep[] = []; - const visited = new Set(); - - const visit = (step: TaskStep) => { - if (visited.has(step.id)) return; - visited.add(step.id); - - for (const depId of step.dependencies) { - const dep = steps.find(s => s.id === depId); - if (dep) visit(dep); - } - - sorted.push(step); - }; - - steps.forEach(visit); - return sorted; - } - - private async waitForDependencies(step: TaskStep, plan: TaskPlan): Promise { - for (const depId of step.dependencies) { - const dep = plan.steps.find(s => s.id === depId); - if (dep && dep.status !== 'completed') { - // 等待依赖完成(简单实现) - await new Promise(resolve => setTimeout(resolve, 100)); - } - } - } - - private calculateProgress(plan: TaskPlan): number { - const completed = plan.steps.filter(s => s.status === 'completed').length; - return completed / plan.steps.length; - } - - listPlans(filter?: { status?: string }): TaskPlan[] { - let plans = Array.from(this.plans.values()); - if (filter?.status) plans = plans.filter(p => p.status === filter.status); - return plans; - } - - private generateId(): string { - return generateId('plan'); - } -} diff --git a/src/core/task-orchestration/types.ts b/src/core/task-orchestration/types.ts deleted file mode 100644 index 19dd38e..0000000 --- a/src/core/task-orchestration/types.ts +++ /dev/null @@ -1,53 +0,0 @@ -// 任务编排引擎 - 类型定义 -export interface TaskPlan { - id: string; - goal: string; - steps: TaskStep[]; - dependencies: Map; - context: Map; - status: PlanStatus; - progress: number; -} - -export interface TaskStep { - id: string; - description: string; - tool: string; - params: any; - dependencies: string[]; - status: StepStatus; - result?: any; - error?: string; -} - -export type PlanStatus = 'planned' | 'executing' | 'completed' | 'failed' | 'paused'; -export type StepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped'; - -export interface ExecutionResult { - planId: string; - status: PlanStatus; - results: any[]; -} - -export interface Progress { - planId: string; - goal: string; - total: number; - completed: number; - current: string; - percentage: string; - steps: Array<{ - description: string; - status: StepStatus; - result?: any; - }>; -} - -export interface TaskOrchestrationEngine { - plan(goal: string, context: any): Promise; - execute(plan: TaskPlan): Promise; - getProgress(planId: string): Promise; - pause(planId: string): Promise; - resume(planId: string): Promise; - cancel(planId: string): Promise; -} diff --git a/src/db/database.ts b/src/db/database.ts deleted file mode 100644 index 2c8c32a..0000000 --- a/src/db/database.ts +++ /dev/null @@ -1,91 +0,0 @@ -// ZCLAW 数据库管理 -import Database from 'better-sqlite3'; -import { existsSync, mkdirSync } from 'fs'; -import { dirname } from 'path'; -import { SCHEMA_SQL } from './schema'; -import { createLogger } from '../utils/logger'; - -const log = createLogger('Database'); - -let _db: Database.Database | null = null; - -export function initDatabase(dbPath: string): Database.Database { - // 确保目录存在 - const dir = dirname(dbPath); - if (!existsSync(dir)) { - mkdirSync(dir, { recursive: true }); - } - - _db = new Database(dbPath); - - // 启用 WAL 模式提升性能 - _db.pragma('journal_mode = WAL'); - _db.pragma('foreign_keys = ON'); - - // 创建表 - _db.exec(SCHEMA_SQL); - - log.info(`Database initialized at ${dbPath}`); - return _db; -} - -export function getDatabase(): Database.Database { - if (!_db) { - throw new Error('Database not initialized. Call initDatabase() first.'); - } - return _db; -} - -export function closeDatabase(): void { - if (_db) { - _db.close(); - _db = null; - log.info('Database closed'); - } -} - -// 通用 CRUD 辅助 -export class BaseDAO> { - constructor( - protected tableName: string, - protected db: Database.Database = getDatabase() - ) {} - - findById(id: string): T | undefined { - return this.db.prepare(`SELECT * FROM ${this.tableName} WHERE id = ?`).get(id) as T | undefined; - } - - findAll(where?: string, params?: any[]): T[] { - const sql = where - ? `SELECT * FROM ${this.tableName} WHERE ${where}` - : `SELECT * FROM ${this.tableName}`; - return (params ? this.db.prepare(sql).all(...params) : this.db.prepare(sql).all()) as T[]; - } - - insert(data: Partial): void { - const keys = Object.keys(data); - const placeholders = keys.map(() => '?').join(', '); - const sql = `INSERT OR REPLACE INTO ${this.tableName} (${keys.join(', ')}) VALUES (${placeholders})`; - this.db.prepare(sql).run(...Object.values(data)); - } - - update(id: string, data: Partial): void { - const sets = Object.keys(data).map(k => `${k} = ?`).join(', '); - const sql = `UPDATE ${this.tableName} SET ${sets} WHERE id = ?`; - this.db.prepare(sql).run(...Object.values(data), id); - } - - delete(id: string): void { - this.db.prepare(`DELETE FROM ${this.tableName} WHERE id = ?`).run(id); - } - - count(where?: string, params?: any[]): number { - const sql = where - ? `SELECT COUNT(*) as count FROM ${this.tableName} WHERE ${where}` - : `SELECT COUNT(*) as count FROM ${this.tableName}`; - const result = params - ? this.db.prepare(sql).get(...params) as { count: number } - : this.db.prepare(sql).get() as { count: number }; - return result.count; - } -} diff --git a/src/db/index.ts b/src/db/index.ts deleted file mode 100644 index eb5e30c..0000000 --- a/src/db/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { initDatabase, getDatabase, closeDatabase, BaseDAO } from './database'; -export { SCHEMA_SQL } from './schema'; diff --git a/src/db/schema.ts b/src/db/schema.ts deleted file mode 100644 index 787a43f..0000000 --- a/src/db/schema.ts +++ /dev/null @@ -1,118 +0,0 @@ -// ZCLAW 数据库 Schema 定义 -export const SCHEMA_SQL = ` --- 用户表 -CREATE TABLE IF NOT EXISTS users ( - id TEXT PRIMARY KEY, - name TEXT NOT NULL, - avatar TEXT DEFAULT '', - preferences TEXT DEFAULT '{}', - patterns TEXT DEFAULT '{}', - created_at TEXT DEFAULT (datetime('now')), - updated_at TEXT DEFAULT (datetime('now')) -); - --- 设备表 -CREATE TABLE IF NOT EXISTS devices ( - id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - name TEXT NOT NULL, - platform TEXT NOT NULL CHECK (platform IN ('macos', 'windows', 'linux')), - capabilities TEXT DEFAULT '[]', - status TEXT DEFAULT 'offline' CHECK (status IN ('online', 'offline', 'busy')), - last_heartbeat TEXT, - created_at TEXT DEFAULT (datetime('now')), - FOREIGN KEY (user_id) REFERENCES users(id) -); - --- 任务表 -CREATE TABLE IF NOT EXISTS tasks ( - id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - device_id TEXT, - channel TEXT DEFAULT '', - type TEXT NOT NULL CHECK (type IN ('immediate', 'scheduled')), - priority TEXT DEFAULT 'normal' CHECK (priority IN ('high', 'normal', 'low')), - payload TEXT DEFAULT '{}', - status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'running', 'completed', 'failed', 'cancelled')), - result TEXT, - error TEXT, - created_at TEXT DEFAULT (datetime('now')), - started_at TEXT, - completed_at TEXT, - FOREIGN KEY (user_id) REFERENCES users(id) -); - --- 任务计划表 -CREATE TABLE IF NOT EXISTS task_plans ( - id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - goal TEXT NOT NULL, - steps TEXT DEFAULT '[]', - status TEXT DEFAULT 'planned' CHECK (status IN ('planned', 'executing', 'completed', 'failed', 'paused')), - progress REAL DEFAULT 0, - context TEXT DEFAULT '{}', - created_at TEXT DEFAULT (datetime('now')), - updated_at TEXT DEFAULT (datetime('now')), - FOREIGN KEY (user_id) REFERENCES users(id) -); - --- 记忆事件表 -CREATE TABLE IF NOT EXISTS memory_events ( - id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - type TEXT NOT NULL, - content TEXT NOT NULL, - metadata TEXT DEFAULT '{}', - timestamp TEXT DEFAULT (datetime('now')), - FOREIGN KEY (user_id) REFERENCES users(id) -); - --- 定时任务表 -CREATE TABLE IF NOT EXISTS scheduled_tasks ( - id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - channel TEXT DEFAULT '', - schedule_type TEXT NOT NULL CHECK (schedule_type IN ('once', 'daily', 'weekly', 'cron')), - schedule_time TEXT NOT NULL, - timezone TEXT DEFAULT 'Asia/Shanghai', - task_type TEXT NOT NULL, - task_prompt TEXT NOT NULL, - status TEXT DEFAULT 'active' CHECK (status IN ('active', 'paused', 'completed')), - last_run TEXT, - next_run TEXT, - created_at TEXT DEFAULT (datetime('now')), - FOREIGN KEY (user_id) REFERENCES users(id) -); - --- 对话历史表 -CREATE TABLE IF NOT EXISTS conversations ( - id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - agent_id TEXT DEFAULT 'zclaw', - role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system')), - content TEXT NOT NULL, - metadata TEXT DEFAULT '{}', - timestamp TEXT DEFAULT (datetime('now')), - FOREIGN KEY (user_id) REFERENCES users(id) -); - --- Agent 表 -CREATE TABLE IF NOT EXISTS agents ( - id TEXT PRIMARY KEY, - name TEXT NOT NULL, - type TEXT NOT NULL CHECK (type IN ('planner', 'browser', 'file', 'terminal', 'combiner', 'custom')), - config TEXT DEFAULT '{}', - status TEXT DEFAULT 'idle' CHECK (status IN ('idle', 'busy', 'error', 'terminated')), - created_at TEXT DEFAULT (datetime('now')) -); - --- 索引 -CREATE INDEX IF NOT EXISTS idx_tasks_user ON tasks(user_id); -CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); -CREATE INDEX IF NOT EXISTS idx_memory_user ON memory_events(user_id); -CREATE INDEX IF NOT EXISTS idx_memory_timestamp ON memory_events(timestamp); -CREATE INDEX IF NOT EXISTS idx_conversations_user ON conversations(user_id); -CREATE INDEX IF NOT EXISTS idx_conversations_timestamp ON conversations(timestamp); -CREATE INDEX IF NOT EXISTS idx_scheduled_user ON scheduled_tasks(user_id); -CREATE INDEX IF NOT EXISTS idx_devices_user ON devices(user_id); -`; diff --git a/src/im/adapters/feishu.ts b/src/im/adapters/feishu.ts deleted file mode 100644 index 94f04a4..0000000 --- a/src/im/adapters/feishu.ts +++ /dev/null @@ -1,124 +0,0 @@ -// 飞书 IM 适配器 -import type { IMAdapter, IMSendOptions, IMMessageHandler, IMMessage } from '../types'; -import { createLogger } from '../../utils/logger'; -import { generateId } from '../../utils/id'; - -const log = createLogger('FeishuAdapter'); - -export class FeishuAdapter implements IMAdapter { - name = 'feishu'; - private appId: string; - private appSecret: string; - private connected = false; - private accessToken = ''; - private handlers: IMMessageHandler[] = []; - private pollingInterval?: ReturnType; - - constructor(appId: string, appSecret: string) { - this.appId = appId; - this.appSecret = appSecret; - } - - async connect(): Promise { - if (!this.appId || !this.appSecret) { - log.warn('Feishu credentials not configured, running in mock mode'); - this.connected = true; - return; - } - - try { - // 获取 tenant_access_token - const response = await fetch('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - app_id: this.appId, - app_secret: this.appSecret, - }), - }); - - const data: any = await response.json(); - if (data.code === 0) { - this.accessToken = data.tenant_access_token; - this.connected = true; - log.info('Feishu connected successfully'); - } else { - throw new Error(`Feishu auth failed: ${data.msg}`); - } - } catch (error: any) { - log.error(`Feishu connection failed: ${error.message}`); - // 降级到 mock 模式 - this.connected = true; - log.warn('Running in mock mode'); - } - } - - async disconnect(): Promise { - if (this.pollingInterval) { - clearInterval(this.pollingInterval); - } - this.connected = false; - this.accessToken = ''; - log.info('Feishu disconnected'); - } - - async send(options: IMSendOptions): Promise { - if (!this.accessToken) { - log.warn(`[Mock] Send to ${options.channelId}: ${options.content.slice(0, 100)}`); - return; - } - - const msgType = options.contentType === 'card' ? 'interactive' : 'text'; - const content = msgType === 'text' - ? JSON.stringify({ text: options.content }) - : options.content; - - try { - const response = await fetch('https://open.feishu.cn/open-apis/im/v1/messages', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${this.accessToken}`, - }, - body: JSON.stringify({ - receive_id: options.channelId, - msg_type: msgType, - content, - }), - }); - - const data: any = await response.json(); - if (data.code !== 0) { - log.error(`Feishu send failed: ${data.msg}`); - } - } catch (error: any) { - log.error(`Feishu send error: ${error.message}`); - } - } - - onMessage(handler: IMMessageHandler): void { - this.handlers.push(handler); - } - - isConnected(): boolean { - return this.connected; - } - - // 模拟接收消息(用于本地测试) - async simulateMessage(content: string, userId: string = 'test_user'): Promise { - const message: IMMessage = { - id: generateId('msg'), - channelType: 'feishu', - channelId: 'test_channel', - userId, - userName: '测试用户', - content, - contentType: 'text', - timestamp: new Date(), - }; - - for (const handler of this.handlers) { - await handler(message); - } - } -} diff --git a/src/im/gateway.ts b/src/im/gateway.ts deleted file mode 100644 index 1c97a84..0000000 --- a/src/im/gateway.ts +++ /dev/null @@ -1,80 +0,0 @@ -// IM 网关 - 统一消息路由 -import type { IMAdapter, IMMessage, IMSendOptions, IMMessageHandler } from './types'; -import { createLogger } from '../utils/logger'; - -const log = createLogger('IMGateway'); - -export class IMGateway { - private adapters: Map = new Map(); - private messageHandlers: IMMessageHandler[] = []; - - registerAdapter(adapter: IMAdapter): void { - this.adapters.set(adapter.name, adapter); - - // 转发消息到全局处理器 - adapter.onMessage(async (message) => { - log.info(`Message from ${message.channelType}/${message.userId}: ${message.content.slice(0, 50)}...`); - for (const handler of this.messageHandlers) { - try { - await handler(message); - } catch (error: any) { - log.error(`Message handler error: ${error.message}`); - } - } - }); - - log.info(`IM adapter registered: ${adapter.name}`); - } - - onMessage(handler: IMMessageHandler): void { - this.messageHandlers.push(handler); - } - - async send(options: IMSendOptions): Promise { - const adapter = this.adapters.get(options.channelType); - if (!adapter) { - log.error(`No adapter for channel type: ${options.channelType}`); - throw new Error(`No adapter for channel type: ${options.channelType}`); - } - - if (!adapter.isConnected()) { - log.warn(`Adapter ${options.channelType} not connected, attempting reconnect...`); - await adapter.connect(); - } - - await adapter.send(options); - log.debug(`Message sent via ${options.channelType}`); - } - - async connectAll(): Promise { - for (const [name, adapter] of this.adapters) { - try { - await adapter.connect(); - log.info(`Connected: ${name}`); - } catch (error: any) { - log.error(`Failed to connect ${name}: ${error.message}`); - } - } - } - - async disconnectAll(): Promise { - for (const [name, adapter] of this.adapters) { - try { - await adapter.disconnect(); - log.info(`Disconnected: ${name}`); - } catch (error: any) { - log.error(`Failed to disconnect ${name}: ${error.message}`); - } - } - } - - getAdapter(name: string): IMAdapter | undefined { - return this.adapters.get(name); - } - - getConnectedAdapters(): string[] { - return Array.from(this.adapters.entries()) - .filter(([, adapter]) => adapter.isConnected()) - .map(([name]) => name); - } -} diff --git a/src/im/index.ts b/src/im/index.ts deleted file mode 100644 index e1758bb..0000000 --- a/src/im/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type { IMAdapter, IMMessage, IMSendOptions, IMMessageHandler } from './types'; -export { IMGateway } from './gateway'; -export { FeishuAdapter } from './adapters/feishu'; diff --git a/src/im/types.ts b/src/im/types.ts deleted file mode 100644 index 56d4f54..0000000 --- a/src/im/types.ts +++ /dev/null @@ -1,33 +0,0 @@ -// IM 网关 - 类型定义 - -export interface IMMessage { - id: string; - channelType: string; // 'feishu' | 'telegram' | 'qq' | 'wecom' - channelId: string; // 频道/群组 ID - userId: string; - userName?: string; - content: string; - contentType: 'text' | 'image' | 'file' | 'card'; - metadata?: Record; - timestamp: Date; -} - -export interface IMSendOptions { - channelType: string; - channelId: string; - userId?: string; - content: string; - contentType?: 'text' | 'card' | 'markdown'; - metadata?: Record; -} - -export type IMMessageHandler = (message: IMMessage) => void | Promise; - -export interface IMAdapter { - name: string; - connect(): Promise; - disconnect(): Promise; - send(options: IMSendOptions): Promise; - onMessage(handler: IMMessageHandler): void; - isConnected(): boolean; -} diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index cc79ec3..0000000 --- a/src/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -// ZCLAW 入口文件 -import { ZClawApp } from './app'; - -// 导出所有模块 -export * from './core/remote-execution'; -export * from './core/task-orchestration'; -export * from './core/memory'; -export * from './core/proactive'; -export * from './core/multi-agent'; -export * from './core/ai'; -export * from './im'; -export * from './db'; -export * from './config'; -export * from './utils'; -export { ZClawApp } from './app'; - -// 主启动流程 -const app = new ZClawApp(); - -app.start().catch((error) => { - console.error('ZCLAW failed to start:', error); - process.exit(1); -}); - -// 优雅退出 -process.on('SIGINT', async () => { - await app.shutdown(); - process.exit(0); -}); - -process.on('SIGTERM', async () => { - await app.shutdown(); - process.exit(0); -}); diff --git a/src/utils/id.ts b/src/utils/id.ts deleted file mode 100644 index b0a9b1c..0000000 --- a/src/utils/id.ts +++ /dev/null @@ -1,12 +0,0 @@ -// ZCLAW ID 生成工具 -import { randomBytes } from 'crypto'; - -export function generateId(prefix: string = ''): string { - const timestamp = Date.now().toString(36); - const random = randomBytes(4).toString('hex'); - return prefix ? `${prefix}_${timestamp}_${random}` : `${timestamp}_${random}`; -} - -export function generateShortId(): string { - return randomBytes(6).toString('base64url'); -} diff --git a/src/utils/index.ts b/src/utils/index.ts deleted file mode 100644 index 3b0d51e..0000000 --- a/src/utils/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { generateId, generateShortId } from './id'; -export { createLogger, setLogLevel } from './logger'; -export type { Logger } from './logger'; diff --git a/src/utils/logger.ts b/src/utils/logger.ts deleted file mode 100644 index e2a3b52..0000000 --- a/src/utils/logger.ts +++ /dev/null @@ -1,57 +0,0 @@ -// ZCLAW 日志系统 -type LogLevel = 'debug' | 'info' | 'warn' | 'error'; - -const LEVEL_PRIORITY: Record = { - debug: 0, - info: 1, - warn: 2, - error: 3, -}; - -const LEVEL_COLORS: Record = { - debug: '\x1b[36m', // cyan - info: '\x1b[32m', // green - warn: '\x1b[33m', // yellow - error: '\x1b[31m', // red -}; - -const RESET = '\x1b[0m'; - -let currentLevel: LogLevel = 'info'; - -export function setLogLevel(level: LogLevel): void { - currentLevel = level; -} - -function shouldLog(level: LogLevel): boolean { - return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[currentLevel]; -} - -function formatTimestamp(): string { - return new Date().toISOString().slice(11, 23); -} - -function log(level: LogLevel, module: string, message: string, data?: any): void { - if (!shouldLog(level)) return; - - const color = LEVEL_COLORS[level]; - const timestamp = formatTimestamp(); - const prefix = `${color}[${timestamp}] [${level.toUpperCase()}] [${module}]${RESET}`; - - if (data !== undefined) { - console.log(`${prefix} ${message}`, typeof data === 'object' ? JSON.stringify(data, null, 2) : data); - } else { - console.log(`${prefix} ${message}`); - } -} - -export function createLogger(module: string) { - return { - debug: (message: string, data?: any) => log('debug', module, message, data), - info: (message: string, data?: any) => log('info', module, message, data), - warn: (message: string, data?: any) => log('warn', module, message, data), - error: (message: string, data?: any) => log('error', module, message, data), - }; -} - -export type Logger = ReturnType;