UNPKG

blade-ai

Version:

🗡️ Blade - 智能 AI 助手命令行工具

1,742 lines (1,731 loc) 376 kB
#!/usr/bin/env node import { DEFAULT_CONFIG, defaults_exports, getModelDescription, getModelsWithDescriptions, getProviderConfig, getSupportedProviders, init_defaults, isProviderSupported, loadConfigFromEnv } from "./chunk-UJB5T2BL.js"; import { MCPClient, MCPConfig, MCPServer, ToolExecutionError, ToolManager, ToolRegistrationError, ToolValidationError, ToolValidator, mcpConfig } from "./chunk-KR6WKANV.js"; import { __toCommonJS } from "./chunk-7N7GSU6K.js"; // src/index.ts import { Command } from "commander"; import { readFileSync as readFileSync2 } from "fs"; import { dirname as dirname3, join as join4 } from "path"; import { fileURLToPath } from "url"; // src/commands/agent-llm.ts import chalk3 from "chalk"; import inquirer2 from "inquirer"; // src/agent/Agent.ts import { EventEmitter as EventEmitter4 } from "events"; // src/agent/ComponentManager.ts import { EventEmitter } from "events"; var ComponentManager = class extends EventEmitter { constructor(config = {}) { super(); this.components = /* @__PURE__ */ new Map(); this.isInitialized = false; this.isDestroyed = false; this.config = { debug: false, autoInit: true, ...config }; } /** * 初始化所有组件 */ async init() { if (this.isInitialized) { this.log("\u7EC4\u4EF6\u7BA1\u7406\u5668\u5DF2\u7ECF\u521D\u59CB\u5316"); return; } if (this.isDestroyed) { throw new Error("\u7EC4\u4EF6\u7BA1\u7406\u5668\u5DF2\u88AB\u9500\u6BC1\uFF0C\u65E0\u6CD5\u91CD\u65B0\u521D\u59CB\u5316"); } this.log("\u521D\u59CB\u5316\u7EC4\u4EF6\u7BA1\u7406\u5668..."); try { for (const [name, component] of this.components) { this.log(`\u521D\u59CB\u5316\u7EC4\u4EF6: ${name}`); try { await component.init(); this.emit("componentInitialized", { id: name, component }); } catch (error) { this.log(`\u7EC4\u4EF6 ${name} \u521D\u59CB\u5316\u5931\u8D25: ${error}`); this.emit("componentInitializationFailed", { id: name, component, error }); throw error; } } this.isInitialized = true; this.log("\u7EC4\u4EF6\u7BA1\u7406\u5668\u521D\u59CB\u5316\u5B8C\u6210"); this.emit("initialized"); } catch (error) { this.log(`\u7EC4\u4EF6\u7BA1\u7406\u5668\u521D\u59CB\u5316\u5931\u8D25: ${error}`); throw error; } } /** * 销毁所有组件 */ async destroy() { if (this.isDestroyed) { return; } this.log("\u9500\u6BC1\u7EC4\u4EF6\u7BA1\u7406\u5668..."); try { for (const [name, component] of this.components) { this.log(`\u9500\u6BC1\u7EC4\u4EF6: ${name}`); try { await component.destroy(); this.emit("componentDestroyed", { id: name, component }); } catch (error) { this.log(`\u7EC4\u4EF6 ${name} \u9500\u6BC1\u5931\u8D25: ${error}`); this.emit("componentDestructionFailed", { id: name, component, error }); } } this.isDestroyed = true; this.log("\u7EC4\u4EF6\u7BA1\u7406\u5668\u5DF2\u9500\u6BC1"); this.emit("destroyed"); } catch (error) { this.log(`\u7EC4\u4EF6\u7BA1\u7406\u5668\u9500\u6BC1\u5931\u8D25: ${error}`); throw error; } } /** * 注册组件 */ async registerComponent(component) { const id = component.getId(); if (this.components.has(id)) { throw new Error(`\u7EC4\u4EF6 "${id}" \u5DF2\u5B58\u5728`); } this.components.set(id, component); this.log(`\u7EC4\u4EF6 "${id}" \u5DF2\u6CE8\u518C`); this.emit("componentRegistered", { id, component }); if (this.isInitialized && this.config.autoInit) { try { await component.init(); this.log(`\u7EC4\u4EF6 "${id}" \u5DF2\u81EA\u52A8\u521D\u59CB\u5316`); this.emit("componentInitialized", { id, component }); } catch (error) { this.log(`\u7EC4\u4EF6 "${id}" \u81EA\u52A8\u521D\u59CB\u5316\u5931\u8D25: ${error}`); this.emit("componentInitializationFailed", { id, component, error }); throw error; } } } /** * 获取组件 */ getComponent(id) { return this.components.get(id); } /** * 检查组件是否存在 */ hasComponent(id) { return this.components.has(id); } /** * 移除组件 */ async removeComponent(id) { const component = this.components.get(id); if (!component) { return false; } try { if (this.isInitialized) { await component.destroy(); this.emit("componentDestroyed", { id, component }); } this.components.delete(id); this.log(`\u7EC4\u4EF6 "${id}" \u5DF2\u79FB\u9664`); this.emit("componentRemoved", { id }); return true; } catch (error) { this.log(`\u79FB\u9664\u7EC4\u4EF6 "${id}" \u5931\u8D25: ${error}`); this.emit("componentRemovalFailed", { id, component, error }); throw error; } } /** * 获取所有组件ID */ getComponentIds() { return Array.from(this.components.keys()); } /** * 获取所有组件 */ getAllComponents() { return new Map(this.components); } /** * 按类型获取组件 */ getComponentsByType(componentClass) { const result = []; for (const component of this.components.values()) { if (component instanceof componentClass) { result.push(component); } } return result; } /** * 搜索组件 */ searchComponents(predicate) { const result = []; for (const component of this.components.values()) { if (predicate(component)) { result.push(component); } } return result; } /** * 批量注册组件 */ async registerComponents(components) { for (const component of components) { await this.registerComponent(component); } } /** * 批量移除组件 */ async removeComponents(ids) { const results = {}; for (const id of ids) { try { results[id] = await this.removeComponent(id); } catch (error) { results[id] = false; } } return results; } /** * 重启组件 */ async restartComponent(id) { const component = this.components.get(id); if (!component) { return false; } try { this.log(`\u91CD\u542F\u7EC4\u4EF6: ${id}`); await component.destroy(); this.emit("componentDestroyed", { id, component }); await component.init(); this.emit("componentInitialized", { id, component }); this.log(`\u7EC4\u4EF6 "${id}" \u91CD\u542F\u5B8C\u6210`); this.emit("componentRestarted", { id, component }); return true; } catch (error) { this.log(`\u7EC4\u4EF6 "${id}" \u91CD\u542F\u5931\u8D25: ${error}`); this.emit("componentRestartFailed", { id, component, error }); throw error; } } /** * 获取组件状态 */ getComponentStatus(id) { const component = this.components.get(id); return { exists: !!component, initialized: this.isInitialized, component }; } /** * 获取管理器状态 */ getStatus() { return { isInitialized: this.isInitialized, isDestroyed: this.isDestroyed, componentCount: this.components.size, componentIds: this.getComponentIds(), config: this.config }; } /** * 获取健康状态 */ async getHealthStatus() { const components = {}; let overallHealthy = true; for (const [id] of this.components) { try { components[id] = { healthy: true }; } catch (error) { components[id] = { healthy: false, error: error.message }; overallHealthy = false; } } return { healthy: overallHealthy && this.isInitialized && !this.isDestroyed, components }; } /** * 等待组件初始化完成 */ async waitForInitialization(timeout = 3e4) { if (this.isInitialized) { return; } return new Promise((resolve4, reject) => { const timer = setTimeout(() => { reject(new Error("\u7EC4\u4EF6\u521D\u59CB\u5316\u8D85\u65F6")); }, timeout); this.once("initialized", () => { clearTimeout(timer); resolve4(); }); this.once("initializationFailed", (error) => { clearTimeout(timer); reject(error); }); }); } /** * 日志记录 */ log(message) { if (this.config.debug) { console.log(`[ComponentManager] ${message}`); } } }; // src/context/ContextManager.ts import * as crypto from "crypto"; // src/context/processors/ContextCompressor.ts var ContextCompressor = class { constructor(maxSummaryLength = 500, keyPointsLimit = 10, recentMessagesLimit = 20) { this.maxSummaryLength = maxSummaryLength; this.keyPointsLimit = keyPointsLimit; this.recentMessagesLimit = recentMessagesLimit; } /** * 压缩上下文数据 */ async compress(contextData) { const messages = contextData.layers.conversation.messages; const toolCalls = contextData.layers.tool.recentCalls; const systemMessages = messages.filter((m) => m.role === "system"); const conversationMessages = messages.filter((m) => m.role !== "system"); const recentMessages = this.getRecentMessages(conversationMessages); const olderMessages = conversationMessages.slice(0, -this.recentMessagesLimit); const summary = await this.generateSummary(olderMessages); const keyPoints = this.extractKeyPoints(olderMessages, toolCalls); const toolSummary = this.generateToolSummary(toolCalls); const tokenCount = this.estimateTokenCount(summary, keyPoints, recentMessages, toolSummary); return { summary, keyPoints, recentMessages: [...systemMessages, ...recentMessages], toolSummary, tokenCount }; } /** * 获取最近的消息 */ getRecentMessages(messages) { return messages.slice(-this.recentMessagesLimit); } /** * 生成对话摘要 */ async generateSummary(messages) { if (messages.length === 0) { return ""; } const topics = /* @__PURE__ */ new Set(); const actions = /* @__PURE__ */ new Set(); const decisions = /* @__PURE__ */ new Set(); for (const message of messages) { const content = message.content.toLowerCase(); const topicKeywords = ["\u5173\u4E8E", "\u8BA8\u8BBA", "\u95EE\u9898", "\u9879\u76EE", "\u529F\u80FD", "\u9700\u6C42"]; topicKeywords.forEach((keyword) => { if (content.includes(keyword)) { const context = this.extractContext(content, keyword, 50); if (context) topics.add(context); } }); const actionKeywords = ["\u521B\u5EFA", "\u5220\u9664", "\u4FEE\u6539", "\u66F4\u65B0", "\u5B9E\u73B0", "\u5F00\u53D1"]; actionKeywords.forEach((keyword) => { if (content.includes(keyword)) { const context = this.extractContext(content, keyword, 30); if (context) actions.add(context); } }); const decisionKeywords = ["\u51B3\u5B9A", "\u9009\u62E9", "\u786E\u5B9A", "\u91C7\u7528", "\u4F7F\u7528"]; decisionKeywords.forEach((keyword) => { if (content.includes(keyword)) { const context = this.extractContext(content, keyword, 40); if (context) decisions.add(context); } }); } let summary = `\u5BF9\u8BDD\u6D89\u53CA ${messages.length} \u6761\u6D88\u606F\u3002`; if (topics.size > 0) { summary += ` \u4E3B\u8981\u8BA8\u8BBA\uFF1A${Array.from(topics).slice(0, 3).join("\u3001")}\u3002`; } if (actions.size > 0) { summary += ` \u6267\u884C\u64CD\u4F5C\uFF1A${Array.from(actions).slice(0, 3).join("\u3001")}\u3002`; } if (decisions.size > 0) { summary += ` \u5173\u952E\u51B3\u7B56\uFF1A${Array.from(decisions).slice(0, 2).join("\u3001")}\u3002`; } return summary.length > this.maxSummaryLength ? summary.substring(0, this.maxSummaryLength) + "..." : summary; } /** * 提取关键要点 */ extractKeyPoints(messages, toolCalls) { const keyPoints = /* @__PURE__ */ new Set(); for (const message of messages) { if (message.role === "user") { const questions = this.extractQuestions(message.content); questions.forEach((q) => keyPoints.add(`\u7528\u6237\u95EE\u9898\uFF1A${q}`)); const requests = this.extractRequests(message.content); requests.forEach((r) => keyPoints.add(`\u7528\u6237\u8BF7\u6C42\uFF1A${r}`)); } else if (message.role === "assistant") { const solutions = this.extractSolutions(message.content); solutions.forEach((s) => keyPoints.add(`\u89E3\u51B3\u65B9\u6848\uFF1A${s}`)); } } const toolUsage = this.summarizeToolUsage(toolCalls); toolUsage.forEach((usage) => keyPoints.add(`\u5DE5\u5177\u4F7F\u7528\uFF1A${usage}`)); return Array.from(keyPoints).slice(0, this.keyPointsLimit); } /** * 生成工具调用摘要 */ generateToolSummary(toolCalls) { if (toolCalls.length === 0) { return ""; } const toolStats = /* @__PURE__ */ new Map(); const recentTime = Date.now() - 10 * 60 * 1e3; for (const call of toolCalls) { const stats = toolStats.get(call.name) || { count: 0, success: 0, recent: 0 }; stats.count++; if (call.status === "success") stats.success++; if (call.timestamp > recentTime) stats.recent++; toolStats.set(call.name, stats); } const summaryParts = []; for (const [toolName, stats] of Array.from(toolStats.entries())) { const successRate = Math.round(stats.success / stats.count * 100); summaryParts.push(`${toolName}(${stats.count}\u6B21,\u6210\u529F\u7387${successRate}%)`); } return `\u5DE5\u5177\u8C03\u7528\uFF1A${summaryParts.join("\u3001")}`; } /** * 估算 token 数量(简单估算) */ estimateTokenCount(summary, keyPoints, recentMessages, toolSummary) { let totalLength = summary.length + keyPoints.join(" ").length; if (toolSummary) { totalLength += toolSummary.length; } for (const message of recentMessages) { totalLength += message.content.length; } return Math.ceil(totalLength / 4); } /** * 从内容中提取上下文 */ extractContext(content, keyword, maxLength) { const index = content.indexOf(keyword); if (index === -1) return null; const start = Math.max(0, index - maxLength / 2); const end = Math.min(content.length, index + maxLength / 2); return content.substring(start, end).trim(); } /** * 提取问题 */ extractQuestions(content) { const questions = []; const questionMarkers = ["?", "\uFF1F", "\u5982\u4F55", "\u600E\u4E48", "\u4EC0\u4E48", "\u4E3A\u4EC0\u4E48"]; const sentences = content.split(/[。!.!]/); for (const sentence of sentences) { if (questionMarkers.some((marker) => sentence.includes(marker))) { const cleaned = sentence.trim(); if (cleaned.length > 5 && cleaned.length < 100) { questions.push(cleaned); } } } return questions.slice(0, 3); } /** * 提取请求 */ extractRequests(content) { const requests = []; const requestMarkers = ["\u8BF7", "\u5E2E\u6211", "\u9700\u8981", "\u60F3\u8981", "\u5E0C\u671B", "\u80FD\u5426"]; const sentences = content.split(/[。!.!]/); for (const sentence of sentences) { if (requestMarkers.some((marker) => sentence.includes(marker))) { const cleaned = sentence.trim(); if (cleaned.length > 5 && cleaned.length < 100) { requests.push(cleaned); } } } return requests.slice(0, 3); } /** * 提取解决方案 */ extractSolutions(content) { const solutions = []; const solutionMarkers = ["\u53EF\u4EE5", "\u5EFA\u8BAE", "\u63A8\u8350", "\u5E94\u8BE5", "\u6700\u597D", "\u89E3\u51B3\u65B9\u6848"]; const sentences = content.split(/[。!.!]/); for (const sentence of sentences) { if (solutionMarkers.some((marker) => sentence.includes(marker))) { const cleaned = sentence.trim(); if (cleaned.length > 10 && cleaned.length < 150) { solutions.push(cleaned); } } } return solutions.slice(0, 3); } /** * 总结工具使用情况 */ summarizeToolUsage(toolCalls) { const summary = []; const recentCalls = toolCalls.filter( (call) => Date.now() - call.timestamp < 30 * 60 * 1e3 // 最近30分钟 ); if (recentCalls.length > 0) { const toolGroups = /* @__PURE__ */ new Map(); recentCalls.forEach((call) => { const group = toolGroups.get(call.name) || []; group.push(call); toolGroups.set(call.name, group); }); for (const [toolName, calls] of Array.from(toolGroups.entries())) { const successCount = calls.filter((c) => c.status === "success").length; summary.push(`${toolName}(${calls.length}\u6B21,${successCount}\u6210\u529F)`); } } return summary.slice(0, 5); } /** * 检查是否需要压缩 */ shouldCompress(contextData, maxTokens) { const estimatedTokens = this.estimateCurrentTokens(contextData); return estimatedTokens > maxTokens * 0.8; } /** * 估算当前上下文的 token 数量 */ estimateCurrentTokens(contextData) { const messages = contextData.layers.conversation.messages; const totalLength = messages.reduce((sum, msg) => sum + msg.content.length, 0); return Math.ceil(totalLength / 4); } }; // src/context/processors/ContextFilter.ts var ContextFilter = class _ContextFilter { constructor(defaultOptions) { this.defaultOptions = { maxTokens: 4e3, maxMessages: 50, timeWindow: 24 * 60 * 60 * 1e3, // 24小时 priority: 1, includeTools: true, includeWorkspace: true, ...defaultOptions }; } /** * 过滤上下文数据 */ filter(contextData, options) { const filterOptions = { ...this.defaultOptions, ...options }; const filteredData = { layers: { system: contextData.layers.system, session: contextData.layers.session, conversation: this.filterConversation(contextData.layers.conversation, filterOptions), tool: filterOptions.includeTools ? this.filterTools(contextData.layers.tool, filterOptions) : { recentCalls: [], toolStates: {}, dependencies: {} }, workspace: filterOptions.includeWorkspace ? contextData.layers.workspace : { currentFiles: [], recentFiles: [], environment: {} } }, metadata: { ...contextData.metadata, lastUpdated: Date.now() } }; filteredData.metadata.totalTokens = this.estimateTokens(filteredData); return filteredData; } /** * 过滤对话上下文 */ filterConversation(conversation, options) { let filteredMessages = [...conversation.messages]; if (options.timeWindow > 0) { const cutoffTime = Date.now() - options.timeWindow; filteredMessages = filteredMessages.filter( (msg) => msg.timestamp >= cutoffTime || msg.role === "system" ); } if (options.priority > 1) { filteredMessages = this.filterByPriority(filteredMessages, options.priority); } if (options.maxMessages > 0) { filteredMessages = this.limitMessages(filteredMessages, options.maxMessages); } if (options.maxTokens > 0) { filteredMessages = this.limitByTokens(filteredMessages, options.maxTokens); } return { messages: filteredMessages, summary: conversation.summary, topics: this.updateTopics(filteredMessages, conversation.topics), lastActivity: conversation.lastActivity }; } /** * 过滤工具上下文 */ filterTools(toolContext, options) { let filteredCalls = [...toolContext.recentCalls]; if (options.timeWindow > 0) { const cutoffTime = Date.now() - options.timeWindow; filteredCalls = filteredCalls.filter((call) => call.timestamp >= cutoffTime); } const successCalls = filteredCalls.filter((call) => call.status === "success"); const failedCalls = filteredCalls.filter((call) => call.status === "error"); const maxSuccessfulCalls = Math.min(20, successCalls.length); const maxFailedCalls = Math.min(10, failedCalls.length); const limitedCalls = [ ...successCalls.slice(-maxSuccessfulCalls), ...failedCalls.slice(-maxFailedCalls) ].sort((a, b) => a.timestamp - b.timestamp); return { recentCalls: limitedCalls, toolStates: toolContext.toolStates, dependencies: toolContext.dependencies }; } /** * 按优先级过滤消息 */ filterByPriority(messages, minPriority) { return messages.filter((msg) => { if (msg.role === "system") return true; const priority = this.calculateMessagePriority(msg); return priority >= minPriority; }); } /** * 计算消息优先级 */ calculateMessagePriority(message) { let priority = 1; if (message.role === "system") priority += 3; else if (message.role === "assistant") priority += 1; const content = message.content.toLowerCase(); const importantKeywords = ["\u9519\u8BEF", "\u8B66\u544A", "\u91CD\u8981", "\u5173\u952E", "\u95EE\u9898", "\u89E3\u51B3"]; if (importantKeywords.some((keyword) => content.includes(keyword))) { priority += 2; } if (content.includes("```") || content.includes("function") || content.includes("class")) { priority += 1; } const ageInHours = (Date.now() - message.timestamp) / (60 * 60 * 1e3); if (ageInHours < 1) priority += 2; else if (ageInHours < 6) priority += 1; return priority; } /** * 限制消息数量 */ limitMessages(messages, maxMessages) { if (messages.length <= maxMessages) { return messages; } const systemMessages = messages.filter((msg) => msg.role === "system"); const otherMessages = messages.filter((msg) => msg.role !== "system"); const remainingSlots = maxMessages - systemMessages.length; const limitedOtherMessages = remainingSlots > 0 ? otherMessages.slice(-remainingSlots) : []; return [...systemMessages, ...limitedOtherMessages].sort((a, b) => a.timestamp - b.timestamp); } /** * 按 Token 数量限制消息 */ limitByTokens(messages, maxTokens) { if (maxTokens <= 0) return messages; let totalTokens = 0; const result = []; for (let i = messages.length - 1; i >= 0; i--) { const message = messages[i]; const messageTokens = this.estimateMessageTokens(message); if (message.role === "system") { if (totalTokens + messageTokens <= maxTokens) { result.unshift(message); totalTokens += messageTokens; } else { const compressedMessage = this.compressMessage(message, maxTokens - totalTokens); result.unshift(compressedMessage); totalTokens += this.estimateMessageTokens(compressedMessage); } } else if (totalTokens + messageTokens <= maxTokens) { result.unshift(message); totalTokens += messageTokens; } else { break; } } return result.sort((a, b) => a.timestamp - b.timestamp); } /** * 估算消息的 Token 数量 */ estimateMessageTokens(message) { return Math.ceil(message.content.length / 4); } /** * 压缩消息内容 */ compressMessage(message, maxTokens) { const maxLength = maxTokens * 4; if (message.content.length <= maxLength) { return message; } const compressed = message.content.substring(0, maxLength - 3) + "..."; return { ...message, content: compressed, metadata: { ...message.metadata, compressed: true, originalLength: message.content.length } }; } /** * 更新主题列表 */ updateTopics(messages, originalTopics) { const topics = new Set(originalTopics); for (const message of messages) { const extractedTopics = this.extractTopicsFromMessage(message); extractedTopics.forEach((topic) => topics.add(topic)); } return Array.from(topics).slice(0, 10); } /** * 从消息中提取主题 */ extractTopicsFromMessage(message) { const content = message.content.toLowerCase(); const topics = []; const topicKeywords = [ "\u9879\u76EE", "\u529F\u80FD", "\u6A21\u5757", "\u7EC4\u4EF6", "\u670D\u52A1", "\u63A5\u53E3", "\u6570\u636E\u5E93", "\u524D\u7AEF", "\u540E\u7AEF", "\u7B97\u6CD5", "\u67B6\u6784", "\u8BBE\u8BA1" ]; topicKeywords.forEach((keyword) => { if (content.includes(keyword)) { topics.push(keyword); } }); return topics; } /** * 估算上下文数据的总 Token 数量 */ estimateTokens(contextData) { let totalTokens = 0; for (const message of contextData.layers.conversation.messages) { totalTokens += this.estimateMessageTokens(message); } const systemContent = JSON.stringify(contextData.layers.system); totalTokens += Math.ceil(systemContent.length / 4); if (contextData.layers.tool.recentCalls.length > 0) { const toolContent = JSON.stringify(contextData.layers.tool); totalTokens += Math.ceil(toolContent.length / 8); } return totalTokens; } /** * 创建预设过滤器 */ static createPresets() { return { // 轻量级过滤器 - 适合快速响应 lightweight: new _ContextFilter({ maxTokens: 1e3, maxMessages: 10, timeWindow: 2 * 60 * 60 * 1e3, // 2小时 includeTools: false, includeWorkspace: false }), // 标准过滤器 - 平衡性能和功能 standard: new _ContextFilter({ maxTokens: 4e3, maxMessages: 30, timeWindow: 12 * 60 * 60 * 1e3, // 12小时 includeTools: true, includeWorkspace: true }), // 完整过滤器 - 包含所有上下文 comprehensive: new _ContextFilter({ maxTokens: 8e3, maxMessages: 100, timeWindow: 24 * 60 * 60 * 1e3, // 24小时 includeTools: true, includeWorkspace: true }), // 调试过滤器 - 专注于错误和工具调用 debug: new _ContextFilter({ maxTokens: 2e3, maxMessages: 20, timeWindow: 6 * 60 * 60 * 1e3, // 6小时 priority: 2, // 只包含高优先级消息 includeTools: true, includeWorkspace: false }) }; } }; // src/context/storage/CacheStore.ts var CacheStore = class { constructor(maxSize = 100, defaultTTL = 5 * 60 * 1e3) { this.cache = /* @__PURE__ */ new Map(); this.maxSize = maxSize; this.defaultTTL = defaultTTL; } /** * 设置缓存项 */ set(key, data, ttl) { const now = Date.now(); const item = { data, timestamp: now, accessCount: 0, lastAccess: now, ttl: ttl || this.defaultTTL }; if (this.cache.size >= this.maxSize && !this.cache.has(key)) { this.evictLeastUsed(); } this.cache.set(key, item); } /** * 获取缓存项 */ get(key) { const item = this.cache.get(key); if (!item) { return null; } const now = Date.now(); if (now - item.timestamp > item.ttl) { this.cache.delete(key); return null; } item.accessCount++; item.lastAccess = now; return item.data; } /** * 检查缓存项是否存在 */ has(key) { const item = this.cache.get(key); if (!item) { return false; } if (Date.now() - item.timestamp > item.ttl) { this.cache.delete(key); return false; } return true; } /** * 删除缓存项 */ delete(key) { return this.cache.delete(key); } /** * 清空缓存 */ clear() { this.cache.clear(); } /** * 获取缓存大小 */ size() { this.cleanExpired(); return this.cache.size; } /** * 缓存消息摘要 */ cacheMessageSummary(sessionId, messages, summary) { const key = `summary:${sessionId}:${messages.length}`; this.set( key, { summary, messageCount: messages.length, lastMessage: messages[messages.length - 1]?.timestamp || 0 }, 10 * 60 * 1e3 ); } /** * 获取缓存的消息摘要 */ getMessageSummary(sessionId, messageCount) { const key = `summary:${sessionId}:${messageCount}`; return this.get(key); } /** * 缓存工具调用结果 */ cacheToolResult(toolName, input, result) { const inputHash = this.hashInput(input); const key = `tool:${toolName}:${inputHash}`; this.set(key, result, 30 * 60 * 1e3); } /** * 获取缓存的工具调用结果 */ getToolResult(toolName, input) { const inputHash = this.hashInput(input); const key = `tool:${toolName}:${inputHash}`; return this.get(key); } /** * 缓存上下文压缩结果 */ cacheCompressedContext(contextHash, compressed) { const key = `compressed:${contextHash}`; this.set(key, compressed, 15 * 60 * 1e3); } /** * 获取缓存的压缩上下文 */ getCompressedContext(contextHash) { const key = `compressed:${contextHash}`; return this.get(key); } /** * 获取缓存统计信息 */ getStats() { this.cleanExpired(); let totalAccess = 0; let memoryUsage = 0; const keyStats = []; for (const [key, item] of Array.from(this.cache.entries())) { totalAccess += item.accessCount; memoryUsage += this.estimateItemSize(item); keyStats.push({ key, accessCount: item.accessCount, lastAccess: item.lastAccess }); } keyStats.sort((a, b) => b.accessCount - a.accessCount); return { size: this.cache.size, maxSize: this.maxSize, hitRate: totalAccess > 0 ? totalAccess / (totalAccess + this.cache.size) : 0, memoryUsage, topKeys: keyStats.slice(0, 10) // 返回前10个最常访问的键 }; } /** * 清理过期项 */ cleanExpired() { const now = Date.now(); const expiredKeys = []; for (const [key, item] of Array.from(this.cache.entries())) { if (now - item.timestamp > item.ttl) { expiredKeys.push(key); } } expiredKeys.forEach((key) => this.cache.delete(key)); } /** * 驱逐最不常用的项 */ evictLeastUsed() { let leastUsedKey = null; let leastScore = Infinity; const now = Date.now(); for (const [key, item] of Array.from(this.cache.entries())) { const recencyScore = 1 / (now - item.lastAccess + 1); const frequencyScore = item.accessCount; const score = recencyScore * frequencyScore; if (score < leastScore) { leastScore = score; leastUsedKey = key; } } if (leastUsedKey) { this.cache.delete(leastUsedKey); } } /** * 简单的输入哈希函数 */ hashInput(input) { const str = JSON.stringify(input); let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = (hash << 5) - hash + char; hash = hash & hash; } return Math.abs(hash).toString(36); } /** * 估算缓存项大小 */ estimateItemSize(item) { try { return JSON.stringify(item).length * 2; } catch { return 1e3; } } /** * 设置缓存项的TTL */ setTTL(key, ttl) { const item = this.cache.get(key); if (item) { item.ttl = ttl; item.timestamp = Date.now(); return true; } return false; } /** * 获取缓存项的剩余TTL */ getRemainingTTL(key) { const item = this.cache.get(key); if (!item) { return -1; } const remaining = item.ttl - (Date.now() - item.timestamp); return Math.max(0, remaining); } /** * 预热缓存(可用于启动时加载常用数据) */ warmup(data) { data.forEach(({ key, value, ttl }) => { this.set(key, value, ttl); }); } }; // src/context/storage/MemoryStore.ts var MemoryStore = class { constructor(maxSize = 1e3) { this.contextData = null; this.accessLog = /* @__PURE__ */ new Map(); this.maxSize = maxSize; } /** * 存储上下文数据 */ setContext(data) { this.contextData = { ...data }; this.contextData.metadata.lastUpdated = Date.now(); this.recordAccess("context"); } /** * 获取完整上下文数据 */ getContext() { if (this.contextData) { this.recordAccess("context"); } return this.contextData; } /** * 添加消息到对话上下文 */ addMessage(message) { if (!this.contextData) { throw new Error("\u4E0A\u4E0B\u6587\u6570\u636E\u672A\u521D\u59CB\u5316"); } this.contextData.layers.conversation.messages.push(message); this.contextData.layers.conversation.lastActivity = Date.now(); this.contextData.metadata.lastUpdated = Date.now(); this.enforceMemoryLimit(); this.recordAccess("messages"); } /** * 获取最近的消息 */ getRecentMessages(count = 10) { if (!this.contextData) { return []; } const messages = this.contextData.layers.conversation.messages; this.recordAccess("messages"); return messages.slice(-count); } /** * 添加工具调用记录 */ addToolCall(toolCall) { if (!this.contextData) { throw new Error("\u4E0A\u4E0B\u6587\u6570\u636E\u672A\u521D\u59CB\u5316"); } this.contextData.layers.tool.recentCalls.push(toolCall); this.contextData.metadata.lastUpdated = Date.now(); if (this.contextData.layers.tool.recentCalls.length > 50) { this.contextData.layers.tool.recentCalls = this.contextData.layers.tool.recentCalls.slice(-25); } this.recordAccess("tools"); } /** * 更新工具状态 */ updateToolState(toolName, state) { if (!this.contextData) { throw new Error("\u4E0A\u4E0B\u6587\u6570\u636E\u672A\u521D\u59CB\u5316"); } this.contextData.layers.tool.toolStates[toolName] = state; this.contextData.metadata.lastUpdated = Date.now(); this.recordAccess("tools"); } /** * 获取工具状态 */ getToolState(toolName) { if (!this.contextData) { return null; } this.recordAccess("tools"); return this.contextData.layers.tool.toolStates[toolName]; } /** * 更新工作空间信息 */ updateWorkspace(updates) { if (!this.contextData) { throw new Error("\u4E0A\u4E0B\u6587\u6570\u636E\u672A\u521D\u59CB\u5316"); } Object.assign(this.contextData.layers.workspace, updates); this.contextData.metadata.lastUpdated = Date.now(); this.recordAccess("workspace"); } /** * 清除内存数据 */ clear() { this.contextData = null; this.accessLog.clear(); } /** * 获取内存使用情况 */ getMemoryInfo() { if (!this.contextData) { return { hasData: false, messageCount: 0, toolCallCount: 0, lastUpdated: null }; } return { hasData: true, messageCount: this.contextData.layers.conversation.messages.length, toolCallCount: this.contextData.layers.tool.recentCalls.length, lastUpdated: this.contextData.metadata.lastUpdated }; } /** * 记录访问日志 */ recordAccess(key) { this.accessLog.set(key, Date.now()); } /** * 强制执行内存限制 */ enforceMemoryLimit() { if (!this.contextData) return; const messages = this.contextData.layers.conversation.messages; if (messages.length > this.maxSize) { const keepCount = Math.floor(this.maxSize * 0.8); this.contextData.layers.conversation.messages = messages.slice(-keepCount); } } /** * 估算内存使用量(以字符数为简单估算) */ getMemoryUsage() { if (!this.contextData) return 0; const contextString = JSON.stringify(this.contextData); return contextString.length; } }; // src/context/storage/PersistentStore.ts import * as fs from "fs/promises"; import * as path from "path"; var PersistentStore = class { constructor(storagePath = "./blade-context", maxSessions = 100) { this.storagePath = storagePath; this.maxSessions = maxSessions; } /** * 初始化存储目录 */ async initialize() { try { await fs.mkdir(this.storagePath, { recursive: true }); await fs.mkdir(path.join(this.storagePath, "sessions"), { recursive: true }); await fs.mkdir(path.join(this.storagePath, "conversations"), { recursive: true }); } catch (error) { console.warn("\u8B66\u544A\uFF1A\u65E0\u6CD5\u521B\u5EFA\u6301\u4E45\u5316\u5B58\u50A8\u76EE\u5F55:", error); } } /** * 保存会话上下文 */ async saveSession(sessionId, sessionContext) { try { const sessionPath = path.join(this.storagePath, "sessions", `${sessionId}.json`); const data = { ...sessionContext, lastSaved: Date.now() }; await fs.writeFile(sessionPath, JSON.stringify(data, null, 2), "utf-8"); } catch (error) { console.warn(`\u8B66\u544A\uFF1A\u65E0\u6CD5\u4FDD\u5B58\u4F1A\u8BDD ${sessionId}:`, error); } } /** * 加载会话上下文 */ async loadSession(sessionId) { try { const sessionPath = path.join(this.storagePath, "sessions", `${sessionId}.json`); const data = await fs.readFile(sessionPath, "utf-8"); return JSON.parse(data); } catch (error) { return null; } } /** * 保存对话上下文 */ async saveConversation(sessionId, conversation) { try { const conversationPath = path.join(this.storagePath, "conversations", `${sessionId}.json`); const data = { ...conversation, lastSaved: Date.now() }; await fs.writeFile(conversationPath, JSON.stringify(data, null, 2), "utf-8"); } catch (error) { console.warn(`\u8B66\u544A\uFF1A\u65E0\u6CD5\u4FDD\u5B58\u5BF9\u8BDD ${sessionId}:`, error); } } /** * 加载对话上下文 */ async loadConversation(sessionId) { try { const conversationPath = path.join(this.storagePath, "conversations", `${sessionId}.json`); const data = await fs.readFile(conversationPath, "utf-8"); return JSON.parse(data); } catch (error) { return null; } } /** * 保存完整上下文数据 */ async saveContext(sessionId, contextData) { await Promise.all([ this.saveSession(sessionId, contextData.layers.session), this.saveConversation(sessionId, contextData.layers.conversation) ]); } /** * 获取所有会话列表 */ async listSessions() { try { const sessionsDir = path.join(this.storagePath, "sessions"); const files = await fs.readdir(sessionsDir); return files.filter((file) => file.endsWith(".json")).map((file) => file.replace(".json", "")).sort(); } catch (error) { return []; } } /** * 获取会话摘要信息 */ async getSessionSummary(sessionId) { try { const [session, conversation] = await Promise.all([ this.loadSession(sessionId), this.loadConversation(sessionId) ]); if (!session || !conversation) { return null; } return { sessionId, lastActivity: conversation.lastActivity, messageCount: conversation.messages.length, topics: conversation.topics || [] }; } catch (error) { return null; } } /** * 删除会话数据 */ async deleteSession(sessionId) { try { const sessionPath = path.join(this.storagePath, "sessions", `${sessionId}.json`); const conversationPath = path.join(this.storagePath, "conversations", `${sessionId}.json`); await Promise.all([ fs.unlink(sessionPath).catch(() => { }), fs.unlink(conversationPath).catch(() => { }) ]); } catch (error) { console.warn(`\u8B66\u544A\uFF1A\u65E0\u6CD5\u5220\u9664\u4F1A\u8BDD ${sessionId}:`, error); } } /** * 清理旧会话(保持最近的N个会话) */ async cleanupOldSessions() { try { const sessions = await this.listSessions(); if (sessions.length <= this.maxSessions) { return; } const sessionSummaries = await Promise.all( sessions.map((sessionId) => this.getSessionSummary(sessionId)) ); const validSummaries = sessionSummaries.filter((summary) => summary !== null).sort((a, b) => b.lastActivity - a.lastActivity); const sessionsToDelete = validSummaries.slice(this.maxSessions).map((summary) => summary.sessionId); await Promise.all(sessionsToDelete.map((sessionId) => this.deleteSession(sessionId))); if (sessionsToDelete.length > 0) { console.log(`\u6E05\u7406\u4E86 ${sessionsToDelete.length} \u4E2A\u65E7\u4F1A\u8BDD`); } } catch (error) { console.warn("\u8B66\u544A\uFF1A\u6E05\u7406\u65E7\u4F1A\u8BDD\u65F6\u51FA\u9519:", error); } } /** * 获取存储统计信息 */ async getStorageStats() { try { const sessions = await this.listSessions(); if (sessions.length === 0) { return { totalSessions: 0, totalSize: 0, oldestSession: null, newestSession: null }; } let totalSize = 0; for (const sessionId of sessions) { try { const sessionPath = path.join(this.storagePath, "sessions", `${sessionId}.json`); const conversationPath = path.join( this.storagePath, "conversations", `${sessionId}.json` ); const [sessionStat, conversationStat] = await Promise.all([ fs.stat(sessionPath).catch(() => ({ size: 0 })), fs.stat(conversationPath).catch(() => ({ size: 0 })) ]); totalSize += sessionStat.size + conversationStat.size; } catch (error) { } } const sessionSummaries = await Promise.all( sessions.map((sessionId) => this.getSessionSummary(sessionId)) ); const validSummaries = sessionSummaries.filter((summary) => summary !== null).sort((a, b) => a.lastActivity - b.lastActivity); return { totalSessions: sessions.length, totalSize, oldestSession: validSummaries[0]?.sessionId || null, newestSession: validSummaries[validSummaries.length - 1]?.sessionId || null }; } catch (error) { console.warn("\u8B66\u544A\uFF1A\u83B7\u53D6\u5B58\u50A8\u7EDF\u8BA1\u4FE1\u606F\u65F6\u51FA\u9519:", error); return { totalSessions: 0, totalSize: 0, oldestSession: null, newestSession: null }; } } /** * 检查存储目录是否可用 */ async checkStorageHealth() { try { await fs.access(this.storagePath); const testFile = path.join(this.storagePath, ".test"); await fs.writeFile(testFile, "test"); await fs.unlink(testFile); return { isAvailable: true, canRead: true, canWrite: true }; } catch (error) { return { isAvailable: false, canRead: false, canWrite: false, error: error instanceof Error ? error.message : String(error) }; } } }; // src/context/ContextManager.ts var ContextManager = class { constructor(options = {}) { this.currentSessionId = null; this.initialized = false; this.options = { storage: { maxMemorySize: 1e3, persistentPath: "./blade-context", cacheSize: 100, compressionEnabled: true, ...options.storage }, defaultFilter: { maxTokens: 4e3, maxMessages: 50, timeWindow: 24 * 60 * 60 * 1e3, ...options.defaultFilter }, compressionThreshold: options.compressionThreshold || 6e3, enableVectorSearch: options.enableVectorSearch || false }; this.memory = new MemoryStore(this.options.storage.maxMemorySize); this.persistent = new PersistentStore(this.options.storage.persistentPath, 100); this.cache = new CacheStore( this.options.storage.cacheSize, 5 * 60 * 1e3 // 5分钟默认TTL ); this.compressor = new ContextCompressor(); this.filter = new ContextFilter(this.options.defaultFilter); } /** * 初始化上下文管理器 */ async initialize() { if (this.initialized) return; try { await this.persistent.initialize(); const health = await this.persistent.checkStorageHealth(); if (!health.isAvailable) { console.warn("\u8B66\u544A\uFF1A\u6301\u4E45\u5316\u5B58\u50A8\u4E0D\u53EF\u7528\uFF0C\u5C06\u4EC5\u4F7F\u7528\u5185\u5B58\u5B58\u50A8"); } this.initialized = true; console.log("\u4E0A\u4E0B\u6587\u7BA1\u7406\u5668\u521D\u59CB\u5316\u5B8C\u6210"); } catch (error) { console.error("\u4E0A\u4E0B\u6587\u7BA1\u7406\u5668\u521D\u59CB\u5316\u5931\u8D25:", error); throw error; } } /** * 创建新会话 */ async createSession(userId, preferences = {}, configuration = {}) { const sessionId = configuration.sessionId || this.generateSessionId(); const now = Date.now(); const contextData = { layers: { system: await this.createSystemContext(), session: { sessionId, userId, preferences, configuration, startTime: now }, conversation: { messages: [], topics: [], lastActivity: now }, tool: { recentCalls: [], toolStates: {}, dependencies: {} }, workspace: await this.createWorkspaceContext() }, metadata: { totalTokens: 0, priority: 1, lastUpdated: now } }; this.memory.setContext(contextData); await this.persistent.saveContext(sessionId, contextData); this.currentSessionId = sessionId; console.log(`\u65B0\u4F1A\u8BDD\u5DF2\u521B\u5EFA: ${sessionId}`); return sessionId; } /** * 加载现有会话 */ async loadSession(sessionId) { try { let contextData = this.memory.getContext(); if (!contextData || contextData.layers.session.sessionId !== sessionId) { const [session, conversation] = await Promise.all([ this.persistent.loadSession(sessionId), this.persistent.loadConversation(sessionId) ]); if (!session || !conversation) { return false; } contextData = { layers: { system: await this.createSystemContext(), session, conversation, tool: { recentCalls: [], toolStates: {}, dependencies: {} }, workspace: await this.createWorkspaceContext() }, metadata: { totalTokens: 0, priority: 1, lastUpdated: Date.now() } }; this.memory.setContext(contextData); } this.currentSessionId = sessionId; console.log(`\u4F1A\u8BDD\u5DF2\u52A0\u8F7D: ${sessionId}`); return true; } catch (error) { console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:", error); return false; } } /** * 添加消息到当前会话 */ async addMessage(role, content, metadata) { if (!this.currentSessionId) { throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD"); } const message = { id: this.generateMessageId(), role, content, timestamp: Date.now(), metadata }; this.memory.addMessage(message); const contextData = this.memory.getContext(); if (contextData && this.shouldCompress(contextData)) { await this.compressCurrentContext(); } this.saveCurrentSessionAsync(); } /** * 添加工具调用记录 */ async addToolCall(toolCall) { if (!this.currentSessionId) { throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD"); } this.memory.addToolCall(toolCall); if (toolCall.status === "success" && toolCall.output) { this.cache.cacheToolResult(toolCall.name, toolCall.input, toolCall.output); } this.saveCurrentSessionAsync(); } /** * 更新工具状态 */ updateToolState(toolName, state) { if (!this.currentSessionId) { throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD"); } this.memory.updateToolState(toolName, state); } /** * 更新工作空间信息 */ updateWorkspace(updates) { if (!this.currentSessionId) { throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD"); } this.memory.updateWorkspace(updates); } /** * 获取格式化的上下文用于 Prompt 构建 */ async getFormattedContext(filterOptions) { const contextData = this.memory.getContext(); if (!contextData) { throw new Error("\u6CA1\u6709\u53EF\u7528\u7684\u4E0A\u4E0B\u6587\u6570\u636E"); } const filteredContext = this.filter.filter(contextData, filterOptions); const shouldCompress = this.shouldCompress(filteredContext); let compressed; if (shouldCompress) { const contextHash = this.hashContext(filteredContext); compressed = this.cache.getCompressedContext(contextHash); if (!compressed) { compressed = await this.compressor.compress(filteredContext); this.cache.cacheCompressedContext(contextHash, compressed); } } return { context: filteredContext, compressed, tokenCount: compressed ? compressed.tokenCount : filteredContext.metadata.totalTokens }; } /** * 搜索历史会话 */ async searchSessions(query, limit = 10) { const sessions = await this.persistent.listSessions(); const results = []; for (const sessionId of sessions) { const summary = await this.persistent.getSessionSummary(sessionId); if (summary) { const relevanceScore = this.calculateRelevance(query, summary.topics); if (relevanceScore > 0) { results.push({ sessionId, summary: `${summary.messageCount}\u6761\u6D88\u606F\uFF0C\u4E3B\u9898\uFF1A${summary.topics.join("\u3001")}`, lastActivity: summary.lastActivity, relevanceScore }); } } } return results.sort((a, b) => b.relevanceScore - a.relevanceScore).slice(0, limit); } /** * 获取缓存的工具调用结果 */ getCachedToolResult(toolName, input) { return this.cache.getToolResult(toolName, input); } /** * 获取管理器统计信息 */ async getStats() { const [memoryInfo, cacheStats, storageStats] = await Promise.all([ Promise.resolve(this.memory.getMemoryInfo()), Promise.resolve(this.cache.getStats()), this.persistent.getStorageStats() ]); return { currentSession: this.currentSessionId, memory: memoryInfo, cache: cacheStats, storage: storageStats }; } /** * 清理资源 */ async cleanup() { if (this.currentSessionId) { await this.saveCurrentSession(); } this.memory.clear(); this.cache.clear(); await this.persistent.cleanupOldSessions(); this.currentSessionId = null; console.log("\u4E0A\u4E0B\u6587\u7BA1\u7406\u5668\u8D44\u6E90\u6E05\u7406\u5B8C\u6210"); } // 私有方法 generateSessionId() { return `session_${Date.no