refactor: 系统性移除DACP架构 - 简化框架专注@tool协议
🗑️ 核心清理 - 完全移除DACP服务架构和HTTP模式 - 删除DACPCommand、DACPConfigManager等核心组件 - 清理所有DACP相关文件、测试和文档 - 从CLI移除dacp命令,精简为6大核心锦囊 📁 删除内容 Core: - src/dacp/ - 整个DACP服务目录 - src/lib/core/pouch/commands/DACPCommand.js - src/lib/utils/DACPConfigManager.js Tests: - src/tests/commands/DACPCommand.unit.test.js - src/tests/integration/dacp-integration.test.js - src/tests/e2e/dacp-*-e2e.test.js - src/tests/unit/DACPConfigManager.unit.test.js Scripts & Docs: - scripts/test-*dacp*.js - docs/dacp-*.md - prompt/core/dacp-*.execution.md 🔧 代码清理 CLI: - src/bin/promptx.js: 移除dacp命令和--with-dacp选项 - 帮助信息更新:7大命令→6大核心命令 Core: - src/lib/core/pouch/PouchCLI.js: 移除dacp命令注册 - src/lib/core/pouch/commands/index.js: 清理DACPCommand引用 MCP: - src/lib/mcp/toolDefinitions.js: 移除promptx_dacp工具定义 - src/lib/commands/MCPServerCommand.js: 清理所有DACP方法和引用 - src/lib/commands/MCPStreamableHttpCommand.js: 移除DACP参数映射 Registry: - src/package.registry.json: 自动更新,移除2个DACP execution资源 - package.json: 移除dacp相关npm脚本 📊 架构简化结果 - 资源总数:63个 → 61个 (移除2个DACP execution) - CLI命令:7个 → 6大核心锦囊 - 代码复杂度显著降低,专注核心功能 ✅ 验证通过 - @tool://calculator 计算功能正常: 6 × 7 = 42 - @tool://send-email 邮件工具正常 - MCP Server启动正常 - 所有锦囊命令工作正常 🎯 新架构重点 1. 角色系统 - AI专业能力激活 2. 记忆系统 - 知识学习和回忆 3. @tool协议 - JavaScript工具执行 4. MCP集成 - AI应用连接 💡 技术收益 - 移除HTTP服务复杂度 - 统一@tool协议标准 - 简化维护和扩展 - 提升性能和稳定性 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -84,8 +84,6 @@ class MCPServerCommand {
|
||||
// 设置进程清理处理器
|
||||
this.setupProcessCleanup();
|
||||
|
||||
// 🔧 DACP现已改为Mock模式,无需启动独立服务
|
||||
// 静默忽略任何withDacp选项,保持向后兼容
|
||||
|
||||
this.log('🚀 启动MCP Server...');
|
||||
const transport = new StdioServerTransport();
|
||||
@ -143,267 +141,14 @@ class MCPServerCommand {
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理子进程 (DACP现为Mock模式,此方法保留但无实际清理工作)
|
||||
* @deprecated DACP已改为Mock模式,无需清理子进程
|
||||
* 清理资源
|
||||
*/
|
||||
cleanup() {
|
||||
// 🔧 DACP现已改为Mock模式,无需清理DACP子进程
|
||||
// HTTP模式的进程清理代码已保留作为参考实现
|
||||
this.log('🔧 Mock模式下无需清理DACP子进程');
|
||||
this.log('🔧 清理MCP Server资源');
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测DACP服务是否已经运行 (HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated DACP已改为Mock模式,此方法仅保留作为参考
|
||||
* @param {string} host - 主机地址
|
||||
* @param {number} port - 端口号
|
||||
* @returns {Promise<boolean>} 服务是否运行
|
||||
*/
|
||||
async isDACPServiceRunning(host = 'localhost', port = 3002) {
|
||||
// 🔧 Mock模式下始终返回false,因为不需要HTTP服务
|
||||
return false;
|
||||
|
||||
/* HTTP模式参考实现(已禁用)
|
||||
const http = require('http');
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const options = {
|
||||
hostname: host,
|
||||
port: port,
|
||||
path: '/health',
|
||||
method: 'GET',
|
||||
timeout: 2000 // 2秒超时
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const healthData = JSON.parse(data);
|
||||
// 检查是否是DACP服务且状态健康
|
||||
const isHealthy = healthData.status === 'healthy';
|
||||
const isDACPService = healthData.service && healthData.service.includes('DACP');
|
||||
resolve(isHealthy && isDACPService);
|
||||
} catch (error) {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', () => {
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
req.destroy();
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取DACP服务信息 (HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated DACP已改为Mock模式,此方法仅保留作为参考
|
||||
* @param {string} host - 主机地址
|
||||
* @param {number} port - 端口号
|
||||
* @returns {Promise<Object|null>} 服务信息
|
||||
*/
|
||||
async getDACPServiceInfo(host = 'localhost', port = 3002) {
|
||||
// 🔧 Mock模式下返回模拟的服务信息
|
||||
return {
|
||||
service: {
|
||||
name: 'PromptX DACP Mock Service',
|
||||
version: '1.0.0-mock'
|
||||
},
|
||||
available_actions: ['calculate', 'send_email'],
|
||||
mode: 'local_mock'
|
||||
};
|
||||
|
||||
/* HTTP模式参考实现(已禁用)
|
||||
const http = require('http');
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const options = {
|
||||
hostname: host,
|
||||
port: port,
|
||||
path: '/info',
|
||||
method: 'GET',
|
||||
timeout: 2000
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const serviceInfo = JSON.parse(data);
|
||||
resolve(serviceInfo);
|
||||
} catch (error) {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', () => {
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
req.destroy();
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动DACP服务 (HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated DACP已改为Mock模式,此方法仅保留作为参考
|
||||
*/
|
||||
async startDACPService() {
|
||||
// 🔧 Mock模式下输出提示信息即可
|
||||
console.error('');
|
||||
console.error('=====================================');
|
||||
console.error('🔧 DACP Mock模式已启用');
|
||||
console.error('📦 本地函数调用模式:无需HTTP服务');
|
||||
console.error('🔧 支持的Actions: send_email, calculate');
|
||||
console.error('✅ Mock模式启动成功');
|
||||
console.error('=====================================');
|
||||
console.error('');
|
||||
|
||||
/* HTTP模式参考实现(已禁用)
|
||||
const { spawn } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
try {
|
||||
this.log('🔍 检测DACP服务状态...');
|
||||
|
||||
// 先检测是否已有DACP服务运行
|
||||
const isRunning = await this.isDACPServiceRunning();
|
||||
|
||||
if (isRunning) {
|
||||
// 服务已存在,获取服务信息并直接使用
|
||||
const serviceInfo = await this.getDACPServiceInfo();
|
||||
console.error(''); // 空行分隔
|
||||
console.error('=====================================');
|
||||
console.error('🔄 发现现有DACP服务,直接复用');
|
||||
console.error('📍 DACP服务地址: http://localhost:3002');
|
||||
if (serviceInfo) {
|
||||
console.error(`🏷️ 服务名称: ${serviceInfo.service?.name || 'Unknown'}`);
|
||||
console.error(`📦 服务版本: ${serviceInfo.service?.version || 'Unknown'}`);
|
||||
console.error(`🔧 可用操作: ${serviceInfo.available_actions?.join(', ') || 'Unknown'}`);
|
||||
}
|
||||
console.error('=====================================');
|
||||
console.error(''); // 空行分隔
|
||||
return; // 直接返回,不启动新服务
|
||||
}
|
||||
|
||||
this.log('🚀 启动新的DACP服务...');
|
||||
|
||||
// DACP服务路径
|
||||
const dacpPath = path.join(__dirname, '../../dacp/dacp-promptx-service');
|
||||
|
||||
// 启动DACP服务作为子进程
|
||||
// 注意:不能直接使用 'inherit',因为会干扰MCP的stdio通信
|
||||
// 但我们需要看到DACP的启动信息
|
||||
this.dacpProcess = spawn('node', ['server.js'], {
|
||||
cwd: dacpPath,
|
||||
stdio: ['ignore', 'pipe', 'pipe'], // stdin忽略, stdout和stderr都输出到pipe
|
||||
shell: true,
|
||||
detached: false // tree-kill 会处理整个进程树,不需要 detached
|
||||
});
|
||||
|
||||
// 将DACP的输出转发到stderr(这样不会干扰MCP的stdout)
|
||||
this.dacpProcess.stdout.on('data', (data) => {
|
||||
const output = data.toString().trim();
|
||||
if (output) {
|
||||
console.error(`[DACP] ${output}`);
|
||||
}
|
||||
});
|
||||
|
||||
this.dacpProcess.stderr.on('data', (data) => {
|
||||
const output = data.toString().trim();
|
||||
if (output) {
|
||||
console.error(`[DACP ERROR] ${output}`);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听子进程退出
|
||||
this.dacpProcess.on('exit', (code, signal) => {
|
||||
this.log(`DACP服务已退出 (code: ${code}, signal: ${signal})`);
|
||||
this.dacpProcess = null;
|
||||
});
|
||||
|
||||
// 监听子进程错误
|
||||
this.dacpProcess.on('error', (err) => {
|
||||
console.error(`DACP进程错误: ${err.message}`);
|
||||
});
|
||||
|
||||
// 等待服务启动 - 通过监听输出来判断
|
||||
await new Promise((resolve, reject) => {
|
||||
let started = false;
|
||||
const timeout = setTimeout(() => {
|
||||
if (!started) {
|
||||
reject(new Error('DACP服务启动超时'));
|
||||
}
|
||||
}, 10000); // 10秒超时
|
||||
|
||||
// 监听输出,判断服务是否启动
|
||||
const checkStarted = (data) => {
|
||||
const output = data.toString();
|
||||
// 检查是否包含启动成功的标志
|
||||
if (output.includes('Running at http://localhost:') ||
|
||||
output.includes('🚀') ||
|
||||
output.includes('DACP') ||
|
||||
output.includes('3002')) {
|
||||
if (!started) {
|
||||
started = true;
|
||||
clearTimeout(timeout);
|
||||
console.error(''); // 空行分隔
|
||||
console.error('=====================================');
|
||||
console.error('✅ DACP服务启动成功');
|
||||
console.error('📍 DACP服务地址: http://localhost:3002');
|
||||
console.error('🔧 支持的Actions: send_email, schedule_meeting, create_document');
|
||||
console.error('=====================================');
|
||||
console.error(''); // 空行分隔
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.dacpProcess.stdout.on('data', checkStarted);
|
||||
|
||||
this.dacpProcess.on('error', (err) => {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error(`DACP服务启动失败: ${err.message}`));
|
||||
});
|
||||
|
||||
this.dacpProcess.on('exit', (code) => {
|
||||
if (!started) {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error(`DACP服务意外退出,退出码: ${code}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
this.log(`❌ DACP服务启动失败: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置MCP工具处理程序 - 使用正确的MCP SDK API
|
||||
@ -491,7 +236,6 @@ class MCPServerCommand {
|
||||
return result;
|
||||
},
|
||||
|
||||
'promptx_dacp': (args) => [args],
|
||||
|
||||
'promptx_tool': (args) => [args]
|
||||
};
|
||||
|
||||
@ -450,7 +450,6 @@ class MCPStreamableHttpCommand {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
'promptx_dacp': (args) => [args]
|
||||
};
|
||||
|
||||
const mapper = paramMapping[toolName];
|
||||
|
||||
@ -31,7 +31,6 @@ class PouchCLI {
|
||||
learn: commands.LearnCommand,
|
||||
recall: commands.RecallCommand,
|
||||
remember: commands.RememberCommand,
|
||||
dacp: commands.DACPCommand,
|
||||
tool: commands.PromptXToolCommand
|
||||
})
|
||||
|
||||
|
||||
@ -1,282 +0,0 @@
|
||||
const BasePouchCommand = require('../BasePouchCommand');
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* DACP服务调用命令
|
||||
* 负责调用DACP服务,实现从AI建议到AI行动的转换
|
||||
*
|
||||
* 🔧 当前实现:Mock模式(本地函数调用)
|
||||
* 🌐 HTTP模式代码保留作为参考实现
|
||||
*/
|
||||
class DACPCommand extends BasePouchCommand {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// 统一的DACP服务端点
|
||||
// 所有service_id都路由到同一个服务
|
||||
this.defaultEndpoint = 'http://localhost:3002/dacp';
|
||||
|
||||
// 🔧 永久使用Mock模式(本地函数调用)
|
||||
// 不再支持HTTP模式,简化架构复杂度
|
||||
this.useMockMode = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证参数格式
|
||||
* @param {Object} args - 参数对象
|
||||
*/
|
||||
validateArgs(args) {
|
||||
if (!args.service_id) {
|
||||
throw new Error('缺少必需参数: service_id');
|
||||
}
|
||||
|
||||
if (!args.action) {
|
||||
throw new Error('缺少必需参数: action');
|
||||
}
|
||||
|
||||
if (!args.parameters) {
|
||||
throw new Error('缺少必需参数: parameters');
|
||||
}
|
||||
|
||||
if (!args.parameters.user_request) {
|
||||
throw new Error('缺少必需参数: parameters.user_request');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务端点(HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated 当前使用Mock模式,此方法仅保留作为参考
|
||||
* @param {string} serviceId - 服务ID
|
||||
* @returns {string} 服务端点URL
|
||||
*/
|
||||
getServiceEndpoint(serviceId) {
|
||||
// 现在所有服务都指向同一个端点
|
||||
// serviceId 只是用来在DACP服务内部路由到不同的action
|
||||
return this.defaultEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行DACP服务调用(内部方法)
|
||||
* @param {Object} args - 调用参数
|
||||
* @returns {Promise<Object>} DACP响应
|
||||
*/
|
||||
async callDACPService(args) {
|
||||
try {
|
||||
// 验证参数
|
||||
this.validateArgs(args);
|
||||
|
||||
const { service_id, action, parameters } = args;
|
||||
|
||||
// 🔧 直接使用本地Mock调用
|
||||
return await this.callLocalService(args);
|
||||
|
||||
} catch (error) {
|
||||
// 统一错误处理
|
||||
if (error.message.startsWith('缺少必需参数') ||
|
||||
error.message.startsWith('未找到DACP服务') ||
|
||||
error.message.startsWith('DACP响应解析失败')) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw new Error(`DACP服务调用失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地服务调用(Mock模式)
|
||||
* @param {Object} args - 调用参数
|
||||
* @returns {Promise<Object>} DACP标准响应
|
||||
*/
|
||||
async callLocalService(args) {
|
||||
const startTime = Date.now();
|
||||
const { service_id, action, parameters } = args;
|
||||
const request_id = `req_${Date.now()}`;
|
||||
|
||||
try {
|
||||
// 1. 读取DACP配置
|
||||
const configPath = path.join(__dirname, '../../../dacp/dacp-promptx-service/dacp.config.json');
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
|
||||
// 2. 验证service_id
|
||||
if (service_id !== config.service.id) {
|
||||
throw new Error(`Service ${service_id} not found. This is ${config.service.id}`);
|
||||
}
|
||||
|
||||
// 3. 动态加载actions
|
||||
const actionsDir = path.join(__dirname, '../../../dacp/dacp-promptx-service/actions');
|
||||
const actions = {};
|
||||
|
||||
if (fs.existsSync(actionsDir)) {
|
||||
fs.readdirSync(actionsDir).forEach(file => {
|
||||
if (file.endsWith('.js')) {
|
||||
const actionName = file.replace('.js', '');
|
||||
actions[actionName] = require(path.join(actionsDir, file));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 4. 查找action处理器
|
||||
let handler = null;
|
||||
|
||||
// 先按模块名查找
|
||||
for (const [moduleName, module] of Object.entries(actions)) {
|
||||
if (module[action] && typeof module[action] === 'function') {
|
||||
handler = module[action];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 找不到则按精确匹配查找
|
||||
if (!handler && actions[action]) {
|
||||
handler = actions[action];
|
||||
}
|
||||
|
||||
if (!handler) {
|
||||
throw new Error(`Action ${action} is not supported`);
|
||||
}
|
||||
|
||||
// 5. 执行action
|
||||
const result = await handler(parameters);
|
||||
|
||||
// 6. 返回DACP标准格式响应
|
||||
return {
|
||||
request_id: request_id,
|
||||
success: true,
|
||||
data: {
|
||||
execution_result: result,
|
||||
evaluation: {
|
||||
constraint_compliance: true,
|
||||
rule_adherence: true,
|
||||
guideline_alignment: true
|
||||
},
|
||||
applied_guidelines: [
|
||||
'DACP protocol standard',
|
||||
'Local mock execution'
|
||||
],
|
||||
performance_metrics: {
|
||||
execution_time: `${Date.now() - startTime}ms`,
|
||||
resource_usage: 'minimal'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
request_id: request_id,
|
||||
success: false,
|
||||
error: {
|
||||
code: error.message.includes('not found') ? 'INVALID_SERVICE' :
|
||||
error.message.includes('not supported') ? 'UNKNOWN_ACTION' : 'EXECUTION_ERROR',
|
||||
message: error.message
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP请求(HTTP模式 - 仅作参考实现保留)
|
||||
* @deprecated 当前使用Mock模式,此方法仅保留作为参考
|
||||
* @param {string} url - 请求URL
|
||||
* @param {Object} data - 请求数据
|
||||
* @returns {Promise<Object>} 响应数据
|
||||
*/
|
||||
makeHttpRequest(url, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urlObj = new URL(url);
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port,
|
||||
path: urlObj.pathname,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(JSON.stringify(data))
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let responseData = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
responseData += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const result = JSON.parse(responseData);
|
||||
resolve(result);
|
||||
} catch (error) {
|
||||
reject(new Error(`DACP响应解析失败: ${error.message}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
req.write(JSON.stringify(data));
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// BasePouchCommand的抽象方法实现(虽然不会被用到)
|
||||
getPurpose() {
|
||||
return '调用DACP专业服务,让PromptX角色拥有执行能力';
|
||||
}
|
||||
|
||||
async getContent(args) {
|
||||
try {
|
||||
// 处理参数:如果是数组,取第一个元素;否则直接使用
|
||||
const dacpArgs = Array.isArray(args) ? args[0] : args;
|
||||
|
||||
// 执行DACP调用
|
||||
const result = await this.callDACPService(dacpArgs);
|
||||
|
||||
// 格式化响应
|
||||
if (result.success) {
|
||||
const executionResult = result.data.execution_result;
|
||||
const metrics = result.data.performance_metrics;
|
||||
return `🚀 DACP服务调用成功 (🔧 本地Mock模式)
|
||||
|
||||
📋 执行结果:
|
||||
${JSON.stringify(executionResult, null, 2)}
|
||||
|
||||
⏱️ 性能指标:
|
||||
- 执行时间: ${metrics.execution_time}
|
||||
- 资源使用: ${metrics.resource_usage}
|
||||
|
||||
🎯 请求ID: ${result.request_id}`;
|
||||
} else {
|
||||
return `❌ DACP服务调用失败
|
||||
|
||||
错误信息: ${result.error?.message || '未知错误'}
|
||||
错误代码: ${result.error?.code || 'UNKNOWN'}
|
||||
|
||||
🎯 请求ID: ${result.request_id}`;
|
||||
}
|
||||
} catch (error) {
|
||||
return `❌ DACP服务调用异常
|
||||
|
||||
错误详情: ${error.message}
|
||||
运行模式: 🔧 本地Mock模式
|
||||
|
||||
💡 请检查:
|
||||
1. DACP action模块是否存在
|
||||
2. 服务ID是否正确
|
||||
3. 操作名称是否有效
|
||||
4. 参数格式是否正确`;
|
||||
}
|
||||
}
|
||||
|
||||
getPATEOAS(args) {
|
||||
return {
|
||||
currentState: 'dacp_ready',
|
||||
nextActions: []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DACPCommand;
|
||||
@ -8,7 +8,6 @@ const ActionCommand = require('./ActionCommand')
|
||||
const LearnCommand = require('./LearnCommand')
|
||||
const RecallCommand = require('./RecallCommand')
|
||||
const RememberCommand = require('./RememberCommand')
|
||||
const DACPCommand = require('./DACPCommand')
|
||||
const PromptXToolCommand = require('../../../commands/PromptXToolCommand')
|
||||
|
||||
module.exports = {
|
||||
@ -18,6 +17,5 @@ module.exports = {
|
||||
LearnCommand,
|
||||
RecallCommand,
|
||||
RememberCommand,
|
||||
DACPCommand,
|
||||
PromptXToolCommand
|
||||
}
|
||||
|
||||
@ -111,46 +111,6 @@ const TOOL_DEFINITIONS = [
|
||||
tags: z.string().optional().describe('自定义标签,用空格分隔,可选')
|
||||
})
|
||||
},
|
||||
{
|
||||
name: 'promptx_dacp',
|
||||
description: '🚀 [DACP专业服务工具] 专业执行工具 - 需要明确知道如何使用特定DACP服务时调用。工具存在但需要专业知识才能正确使用,不建议在不了解服务配置和参数的情况下尝试。',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
service_id: {
|
||||
type: 'string',
|
||||
description: 'DACP服务ID,如:dacp-email-service'
|
||||
},
|
||||
action: {
|
||||
type: 'string',
|
||||
description: '具体操作,如:send_email'
|
||||
},
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
user_request: {
|
||||
type: 'string',
|
||||
description: '用户自然语言需求'
|
||||
},
|
||||
context: {
|
||||
type: 'object',
|
||||
description: '上下文信息'
|
||||
}
|
||||
},
|
||||
required: ['user_request']
|
||||
}
|
||||
},
|
||||
required: ['service_id', 'action', 'parameters']
|
||||
},
|
||||
zodSchema: z.object({
|
||||
service_id: z.string().describe('DACP服务ID,如:dacp-email-service'),
|
||||
action: z.string().describe('具体操作,如:send_email'),
|
||||
parameters: z.object({
|
||||
user_request: z.string().describe('用户自然语言需求'),
|
||||
context: z.object({}).optional().describe('上下文信息')
|
||||
})
|
||||
})
|
||||
},
|
||||
{
|
||||
name: 'promptx_tool',
|
||||
description: '🔧 [工具执行器] 执行通过@tool协议声明的JavaScript工具 - 支持角色配置中定义的专业工具能力,如@tool://calculator数学计算、@tool://send-email邮件发送等。提供安全沙箱执行、参数验证、错误处理和性能监控。',
|
||||
|
||||
@ -1,360 +0,0 @@
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const { getDirectoryService } = require('./DirectoryService')
|
||||
|
||||
/**
|
||||
* DACP配置管理器
|
||||
* 支持项目级配置优先,用户级配置回退的分层配置策略
|
||||
* 配置优先级:项目级(.promptx/dacp/) > 用户级(~/.promptx/dacp/)
|
||||
*/
|
||||
class DACPConfigManager {
|
||||
constructor() {
|
||||
this.userHome = os.homedir()
|
||||
this.userDacpConfigDir = path.join(this.userHome, '.promptx', 'dacp')
|
||||
this.directoryService = getDirectoryService()
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保用户级DACP配置目录存在
|
||||
*/
|
||||
async ensureUserConfigDir() {
|
||||
await fs.ensureDir(this.userDacpConfigDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目级DACP配置目录路径
|
||||
* @returns {Promise<string|null>} 项目级配置目录路径或null
|
||||
*/
|
||||
async getProjectConfigDir() {
|
||||
try {
|
||||
const promptxDir = await this.directoryService.getPromptXDirectory()
|
||||
return path.join(promptxDir, 'dacp')
|
||||
} catch (error) {
|
||||
console.warn('获取项目级配置目录失败:', error.message)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保项目级DACP配置目录存在
|
||||
* @returns {Promise<string|null>} 项目级配置目录路径或null
|
||||
*/
|
||||
async ensureProjectConfigDir() {
|
||||
const projectConfigDir = await this.getProjectConfigDir()
|
||||
if (projectConfigDir) {
|
||||
await fs.ensureDir(projectConfigDir)
|
||||
return projectConfigDir
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定action的用户级配置文件路径
|
||||
* @param {string} action - action名称,如 'send_email'
|
||||
* @returns {string} 用户级配置文件完整路径
|
||||
*/
|
||||
getUserConfigPath(action) {
|
||||
return path.join(this.userDacpConfigDir, `${action}.json`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定action的项目级配置文件路径
|
||||
* @param {string} action - action名称,如 'send_email'
|
||||
* @returns {Promise<string|null>} 项目级配置文件完整路径或null
|
||||
*/
|
||||
async getProjectConfigPath(action) {
|
||||
const projectConfigDir = await this.getProjectConfigDir()
|
||||
if (projectConfigDir) {
|
||||
return path.join(projectConfigDir, `${action}.json`)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定action的配置文件路径(用户级,向后兼容)
|
||||
* @param {string} action - action名称,如 'send_email'
|
||||
* @returns {string} 配置文件完整路径
|
||||
* @deprecated 使用getUserConfigPath或getProjectConfigPath
|
||||
*/
|
||||
getConfigPath(action) {
|
||||
return this.getUserConfigPath(action)
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取项目级action配置
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<Object|null>} 配置对象或null
|
||||
*/
|
||||
async readProjectActionConfig(action) {
|
||||
try {
|
||||
const projectConfigPath = await this.getProjectConfigPath(action)
|
||||
if (projectConfigPath && await fs.pathExists(projectConfigPath)) {
|
||||
const config = await fs.readJson(projectConfigPath)
|
||||
console.log(`📁 使用项目级DACP配置: ${action}`)
|
||||
return config
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`读取项目级DACP配置失败 ${action}:`, error.message)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取用户级action配置
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<Object|null>} 配置对象或null
|
||||
*/
|
||||
async readUserActionConfig(action) {
|
||||
const userConfigPath = this.getUserConfigPath(action)
|
||||
|
||||
try {
|
||||
if (await fs.pathExists(userConfigPath)) {
|
||||
const config = await fs.readJson(userConfigPath)
|
||||
console.log(`🏠 使用用户级DACP配置: ${action}`)
|
||||
return config
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`读取用户级DACP配置失败 ${action}:`, error.message)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取action配置(项目级优先,用户级回退)
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<Object|null>} 配置对象或null
|
||||
*/
|
||||
async readActionConfig(action) {
|
||||
// 优先级:项目级 > 用户级
|
||||
const projectConfig = await this.readProjectActionConfig(action)
|
||||
if (projectConfig) {
|
||||
return projectConfig
|
||||
}
|
||||
|
||||
return await this.readUserActionConfig(action)
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入用户级action配置
|
||||
* @param {string} action - action名称
|
||||
* @param {Object} config - 配置对象
|
||||
*/
|
||||
async writeUserActionConfig(action, config) {
|
||||
await this.ensureUserConfigDir()
|
||||
const configPath = this.getUserConfigPath(action)
|
||||
await fs.writeJson(configPath, config, { spaces: 2 })
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入项目级action配置
|
||||
* @param {string} action - action名称
|
||||
* @param {Object} config - 配置对象
|
||||
*/
|
||||
async writeProjectActionConfig(action, config) {
|
||||
const projectConfigDir = await this.ensureProjectConfigDir()
|
||||
if (projectConfigDir) {
|
||||
const configPath = path.join(projectConfigDir, `${action}.json`)
|
||||
await fs.writeJson(configPath, config, { spaces: 2 })
|
||||
} else {
|
||||
throw new Error('无法获取项目目录,写入项目级配置失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入action配置(向后兼容,写入用户级)
|
||||
* @param {string} action - action名称
|
||||
* @param {Object} config - 配置对象
|
||||
* @deprecated 使用writeUserActionConfig或writeProjectActionConfig
|
||||
*/
|
||||
async writeActionConfig(action, config) {
|
||||
return await this.writeUserActionConfig(action, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查项目级action配置是否存在
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async hasProjectActionConfig(action) {
|
||||
try {
|
||||
const projectConfigPath = await this.getProjectConfigPath(action)
|
||||
if (!projectConfigPath) {
|
||||
return false
|
||||
}
|
||||
return await fs.pathExists(projectConfigPath)
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户级action配置是否存在
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async hasUserActionConfig(action) {
|
||||
const userConfigPath = this.getUserConfigPath(action)
|
||||
return await fs.pathExists(userConfigPath)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查action配置是否存在(项目级或用户级)
|
||||
* @param {string} action - action名称
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async hasActionConfig(action) {
|
||||
const hasProject = await this.hasProjectActionConfig(action)
|
||||
if (hasProject) {
|
||||
return true
|
||||
}
|
||||
return await this.hasUserActionConfig(action)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证邮件配置
|
||||
* @param {Object} config - 邮件配置对象
|
||||
* @returns {Object} 验证结果 {valid: boolean, errors: string[]}
|
||||
*/
|
||||
validateEmailConfig(config) {
|
||||
const errors = []
|
||||
|
||||
if (!config) {
|
||||
errors.push('配置对象不能为空')
|
||||
return { valid: false, errors }
|
||||
}
|
||||
|
||||
// 验证provider
|
||||
if (!config.provider) {
|
||||
errors.push('缺少邮件服务提供商(provider)配置')
|
||||
}
|
||||
|
||||
// 验证SMTP配置
|
||||
if (!config.smtp) {
|
||||
errors.push('缺少SMTP配置')
|
||||
} else {
|
||||
if (!config.smtp.user) {
|
||||
errors.push('缺少SMTP用户名(smtp.user)')
|
||||
}
|
||||
if (!config.smtp.password) {
|
||||
errors.push('缺少SMTP密码(smtp.password)')
|
||||
}
|
||||
}
|
||||
|
||||
// 验证发件人配置
|
||||
if (!config.sender) {
|
||||
errors.push('缺少发件人配置(sender)')
|
||||
} else {
|
||||
if (!config.sender.email) {
|
||||
errors.push('缺少发件人邮箱(sender.email)')
|
||||
}
|
||||
if (!config.sender.name) {
|
||||
errors.push('缺少发件人姓名(sender.name)')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮件服务提供商配置
|
||||
* @param {string} provider - 提供商名称
|
||||
* @returns {Object} 提供商配置
|
||||
*/
|
||||
getProviderConfig(provider) {
|
||||
const providers = {
|
||||
gmail: {
|
||||
smtp: 'smtp.gmail.com',
|
||||
port: 587,
|
||||
secure: false,
|
||||
requireAuth: true
|
||||
},
|
||||
outlook: {
|
||||
smtp: 'smtp-mail.outlook.com',
|
||||
port: 587,
|
||||
secure: false,
|
||||
requireAuth: true
|
||||
},
|
||||
qq: {
|
||||
smtp: 'smtp.qq.com',
|
||||
port: 465,
|
||||
secure: true,
|
||||
requireAuth: true
|
||||
},
|
||||
'163': {
|
||||
smtp: 'smtp.163.com',
|
||||
port: 465,
|
||||
secure: true,
|
||||
requireAuth: true
|
||||
},
|
||||
'126': {
|
||||
smtp: 'smtp.126.com',
|
||||
port: 465,
|
||||
secure: true,
|
||||
requireAuth: true
|
||||
}
|
||||
}
|
||||
|
||||
return providers[provider] || null
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成配置错误提示信息
|
||||
* @param {string} action - action名称
|
||||
* @param {Object} validation - 验证结果
|
||||
* @returns {Promise<string>} 错误提示信息
|
||||
*/
|
||||
async generateConfigErrorMessage(action, validation = null) {
|
||||
const userConfigPath = this.getUserConfigPath(action)
|
||||
const projectConfigPath = await this.getProjectConfigPath(action)
|
||||
|
||||
let message = `\n📧 DACP邮件服务配置缺失\n\n`
|
||||
|
||||
if (!validation) {
|
||||
// 配置文件不存在
|
||||
message += `❌ 未找到配置文件\n\n`
|
||||
message += `🔍 查找路径:\n`
|
||||
if (projectConfigPath) {
|
||||
message += ` 项目级: ${projectConfigPath} (优先)\n`
|
||||
}
|
||||
message += ` 用户级: ${userConfigPath} (回退)\n\n`
|
||||
message += `📝 推荐创建项目级配置文件,内容如下:\n\n`
|
||||
message += `{\n`
|
||||
message += ` "provider": "gmail",\n`
|
||||
message += ` "smtp": {\n`
|
||||
message += ` "user": "your-email@gmail.com",\n`
|
||||
message += ` "password": "your-app-password"\n`
|
||||
message += ` },\n`
|
||||
message += ` "sender": {\n`
|
||||
message += ` "name": "Your Name",\n`
|
||||
message += ` "email": "your-email@gmail.com"\n`
|
||||
message += ` }\n`
|
||||
message += `}\n\n`
|
||||
message += `💡 支持的邮件服务商: gmail, outlook, qq, 163, 126\n\n`
|
||||
message += `🏗️ 配置优先级: 项目级(.promptx/dacp/) > 用户级(~/.promptx/dacp/)\n\n`
|
||||
message += `🔐 Gmail用户需要使用应用专用密码:\n`
|
||||
message += ` 1. 进入 Google 账户设置\n`
|
||||
message += ` 2. 启用两步验证\n`
|
||||
message += ` 3. 生成应用专用密码\n`
|
||||
message += ` 4. 使用生成的密码替换上面的 "your-app-password"\n`
|
||||
} else {
|
||||
// 配置不完整
|
||||
const configLocation = await this.hasProjectActionConfig(action) ?
|
||||
(projectConfigPath ? `项目级: ${projectConfigPath}` : '项目级配置') :
|
||||
`用户级: ${userConfigPath}`
|
||||
message += `❌ 配置文件存在但不完整: ${configLocation}\n\n`
|
||||
message += `缺少以下配置项:\n`
|
||||
validation.errors.forEach(error => {
|
||||
message += ` • ${error}\n`
|
||||
})
|
||||
message += `\n请检查并完善配置文件。\n`
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DACPConfigManager
|
||||
Reference in New Issue
Block a user