Files
PromptX/src/lib/tool/ToolExecutor.js
sean 70093018f8 WIP: promptx tools 开发中的代码
- 正在开发 promptx tools 功能
- 包含 bin、commands、DACP 相关修改
- 新增 tool 目录结构

🚧 这是开发中的代码,需要继续完善
2025-06-28 09:25:54 +08:00

292 lines
7.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const ToolValidator = require('./ToolValidator');
const { TOOL_ERROR_CODES } = require('./ToolInterface');
/**
* ToolExecutor 工具执行器
* 负责工具的加载、验证、执行和结果处理
*/
class ToolExecutor {
constructor(options = {}) {
this.options = {
timeout: 30000, // 默认30秒超时
maxConcurrency: 10, // 最大并发数
enableCache: true, // 启用工具缓存
...options
};
this.toolCache = new Map(); // 工具实例缓存
this.runningTasks = new Set(); // 正在执行的任务
}
/**
* 执行工具(从代码内容)
* @param {string} toolContent - 工具JavaScript代码内容
* @param {Object} parameters - 工具参数
* @param {Object} context - 执行上下文
* @returns {Promise<Object>} 执行结果
*/
async execute(toolContent, parameters = {}, context = {}) {
const executionId = this.generateExecutionId();
const startTime = Date.now();
try {
// 1. 并发控制
if (this.runningTasks.size >= this.options.maxConcurrency) {
throw new Error(`超出最大并发限制: ${this.options.maxConcurrency}`);
}
this.runningTasks.add(executionId);
// 2. 执行工具代码并创建实例
const tool = this.executeToolContent(toolContent, context.toolName || 'unknown');
// 3. 参数验证
const validation = this.validateParameters(tool, parameters);
if (!validation.valid) {
return this.formatError(TOOL_ERROR_CODES.VALIDATION_ERROR, '参数验证失败', {
errors: validation.errors,
parameters: parameters
});
}
// 4. 执行工具(带超时控制)
const result = await this.executeWithTimeout(tool, parameters);
const executionTime = Date.now() - startTime;
// 5. 格式化成功结果
return this.formatSuccess(result, {
executionId,
executionTime: `${executionTime}ms`,
tool: tool.getMetadata ? tool.getMetadata() : { name: context.toolName || 'unknown' }
});
} catch (error) {
const executionTime = Date.now() - startTime;
return this.formatError(
this.getErrorCode(error),
error.message,
{
executionId,
executionTime: `${executionTime}ms`,
stack: error.stack
}
);
} finally {
this.runningTasks.delete(executionId);
}
}
/**
* 执行工具内容并返回实例
* @param {string} toolContent - 工具代码内容
* @param {string} toolName - 工具名称
* @returns {Object} 工具实例
*/
executeToolContent(toolContent, toolName) {
try {
// 创建安全的执行环境
const sandbox = this.createSandbox();
// 执行工具代码
const vm = require('vm');
const script = new vm.Script(toolContent, { filename: `${toolName}.js` });
const context = vm.createContext(sandbox);
script.runInContext(context);
// 获取导出的工具类
const ToolClass = context.module.exports;
if (!ToolClass || typeof ToolClass !== 'function') {
throw new Error(`工具未正确导出类: ${toolName}`);
}
// 创建工具实例
return new ToolClass();
} catch (error) {
throw new Error(`工具代码执行失败 ${toolName}: ${error.message}`);
}
}
/**
* 创建安全的执行沙箱
* @returns {Object} 沙箱环境
*/
createSandbox() {
return {
require: require,
module: { exports: {} },
exports: {},
console: console,
Buffer: Buffer,
process: {
env: process.env,
hrtime: process.hrtime
},
setTimeout: setTimeout,
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval,
// 基础全局对象
Object: Object,
Array: Array,
String: String,
Number: Number,
Boolean: Boolean,
Date: Date,
JSON: JSON,
Math: Math,
RegExp: RegExp,
Error: Error
};
}
/**
* 带超时的工具执行
* @param {BaseTool} tool - 工具实例
* @param {Object} parameters - 参数
* @returns {Promise<*>} 执行结果
*/
async executeWithTimeout(tool, parameters) {
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
reject(new Error(`工具执行超时: ${this.options.timeout}ms`));
}, this.options.timeout);
tool.execute(parameters)
.then(result => {
clearTimeout(timeoutId);
resolve(result);
})
.catch(error => {
clearTimeout(timeoutId);
reject(error);
});
});
}
/**
* 生成执行ID
* @returns {string} 唯一执行ID
*/
generateExecutionId() {
return `exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/**
* 参数验证
* @param {Object} tool - 工具实例
* @param {Object} parameters - 参数
* @returns {Object} 验证结果
*/
validateParameters(tool, parameters) {
// 如果工具有自定义validate方法使用它
if (typeof tool.validate === 'function') {
return tool.validate(parameters);
}
// 否则使用默认验证
return ToolValidator.defaultValidate(tool, parameters);
}
/**
* 为工具增强默认实现
* @param {Object} tool - 工具实例
*/
enhanceToolWithDefaults(tool) {
// 如果没有validate方法提供默认实现
if (!tool.validate) {
tool.validate = (parameters) => ToolValidator.defaultValidate(tool, parameters);
}
// 如果没有cleanup方法提供空实现
if (!tool.cleanup) {
tool.cleanup = () => {};
}
// 如果没有init方法提供空实现
if (!tool.init) {
tool.init = () => {};
}
}
/**
* 获取错误代码
* @param {Error} error - 错误对象
* @returns {string} 错误代码
*/
getErrorCode(error) {
if (error.message.includes('超时')) return TOOL_ERROR_CODES.TIMEOUT_ERROR;
if (error.message.includes('不存在')) return 'TOOL_NOT_FOUND';
if (error.message.includes('验证失败')) return TOOL_ERROR_CODES.VALIDATION_ERROR;
if (error.message.includes('并发限制')) return 'CONCURRENCY_ERROR';
if (error.message.includes('接口不符合规范')) return 'INTERFACE_ERROR';
return TOOL_ERROR_CODES.EXECUTION_ERROR;
}
/**
* 格式化成功结果
* @param {*} data - 结果数据
* @param {Object} metadata - 元信息
* @returns {Object} 标准化结果
*/
formatSuccess(data, metadata = {}) {
return {
success: true,
data: data,
metadata: {
executor: 'ToolExecutor',
timestamp: new Date().toISOString(),
...metadata
}
};
}
/**
* 格式化错误结果
* @param {string} code - 错误代码
* @param {string} message - 错误消息
* @param {Object} details - 错误详情
* @returns {Object} 标准化错误
*/
formatError(code, message, details = {}) {
return {
success: false,
error: {
code: code,
message: message,
details: details
},
metadata: {
executor: 'ToolExecutor',
timestamp: new Date().toISOString()
}
};
}
/**
* 获取执行统计信息
* @returns {Object} 统计信息
*/
getStats() {
return {
runningTasks: this.runningTasks.size,
cachedTools: this.toolCache.size,
maxConcurrency: this.options.maxConcurrency,
timeout: this.options.timeout
};
}
/**
* 清理资源
*/
cleanup() {
this.toolCache.clear();
this.runningTasks.clear();
}
}
module.exports = ToolExecutor;