dpml-prompt
Version:
DPML-powered AI prompt framework - Revolutionary AI-First CLI system based on Deepractice Prompt Markup Language. Build sophisticated AI agents with structured prompts, memory systems, and execution frameworks.
582 lines (511 loc) • 18.9 kB
JavaScript
const BasePouchCommand = require('../BasePouchCommand')
const { getGlobalResourceManager } = require('../../resource')
const ToolSandbox = require('../../../tool/ToolSandbox')
const logger = require('../../../utils/logger')
/**
* Tool命令处理器
* 实现promptx_tool MCP工具,执行通过@tool协议声明的工具
*/
class ToolCommand extends BasePouchCommand {
constructor() {
super()
this.resourceManager = null
}
/**
* 获取或初始化ResourceManager
*/
async getResourceManager() {
if (!this.resourceManager) {
this.resourceManager = getGlobalResourceManager()
// 确保ResourceManager已初始化
if (!this.resourceManager.initialized) {
await this.resourceManager.initializeWithNewArchitecture()
}
}
return this.resourceManager
}
// BasePouchCommand的抽象方法实现
getPurpose() {
return '执行通过@tool协议声明的JavaScript工具'
}
async getContent(args) {
try {
// 处理参数:如果是数组格式,需要转换为对象格式
let toolArgs;
if (Array.isArray(args)) {
// 从CLI调用时,args是数组:[tool_resource, parameters, ...options]
if (args.length >= 2) {
toolArgs = {
tool_resource: args[0],
parameters: args[1],
rebuild: args.includes('--rebuild'),
timeout: this.extractTimeout(args)
};
} else {
throw new Error('Invalid arguments: expected [tool_resource, parameters]');
}
} else {
// 从其他方式调用时,args已经是对象格式
toolArgs = args;
}
// 执行工具调用
const result = await this.executeToolInternal(toolArgs)
// 格式化响应 - 检查工具内部执行状态
if (result.success) {
// 检查工具内部是否也成功
const actualToolResult = result.result
console.log('[DEBUG] actualToolResult structure:', JSON.stringify(actualToolResult, null, 2))
const isToolInternalSuccess = this.isToolInternalSuccess(actualToolResult)
console.log('[DEBUG] isToolInternalSuccess result:', isToolInternalSuccess)
if (isToolInternalSuccess) {
return `🔧 Tool执行成功
📋 工具资源: ${result.tool_resource}
📊 执行结果:
${JSON.stringify(actualToolResult, null, 2)}
⏱️ 性能指标:
- 执行时间: ${result.metadata.execution_time_ms}ms
- 时间戳: ${result.metadata.timestamp}
- 版本: ${result.metadata.version}`
} else {
// ToolSandbox成功,但工具内部失败
const internalError = this.extractToolInternalError(actualToolResult)
return this.formatToolInternalError(result.tool_resource, internalError, result.metadata)
}
} else {
return `❌ Tool执行失败
📋 工具资源: ${result.tool_resource}
❌ 错误信息: ${result.error.message}
🏷️ 错误类型: ${result.error.type}
🔢 错误代码: ${result.error.code}
⏱️ 执行时间: ${result.metadata.execution_time_ms}ms`
}
} catch (error) {
return `❌ Tool执行异常
错误详情: ${error.message}
💡 请检查:
1. 工具资源引用格式是否正确 (@tool://tool-name)
2. 工具参数是否有效
3. 工具文件是否存在并可执行`
}
}
getPATEOAS(args) {
return {
currentState: 'tool_executed',
nextActions: [
{
action: 'execute_another_tool',
description: '执行其他工具',
method: 'promptx tool'
},
{
action: 'view_available_tools',
description: '查看可用工具',
method: 'promptx welcome'
}
]
}
}
/**
* 内部工具执行方法 - 使用ToolSandbox三阶段执行流程
* @param {Object} args - 命令参数
* @param {string} args.tool_resource - 工具资源引用,格式:@tool://tool-name
* @param {Object} args.parameters - 传递给工具的参数
* @param {boolean} args.rebuild - 是否强制重建沙箱(默认false)
* @param {number} args.timeout - 工具执行超时时间(毫秒,默认30000ms)
* @returns {Promise<Object>} 执行结果
*/
async executeToolInternal(args) {
const startTime = Date.now()
let sandbox = null
try {
// 1. 参数验证
this.validateArguments(args)
const { tool_resource, parameters, rebuild = false, timeout = 30000 } = args
logger.debug(`[PromptXTool] 开始执行工具: ${tool_resource}`)
// 2. 构建沙箱选项并创建ToolSandbox实例
const sandboxOptions = { rebuild, timeout }
logger.debug(`[PromptXTool] 沙箱选项:`, sandboxOptions)
sandbox = new ToolSandbox(tool_resource, sandboxOptions)
// 3. 设置ResourceManager
const resourceManager = await this.getResourceManager()
sandbox.setResourceManager(resourceManager)
// 4. ToolSandbox三阶段执行流程
logger.debug(`[PromptXTool] Phase 1: 分析工具`)
const analysisResult = await sandbox.analyze()
logger.debug(`[PromptXTool] Phase 2: 准备依赖`, { dependencies: analysisResult.dependencies })
await sandbox.prepareDependencies()
logger.debug(`[PromptXTool] Phase 3: 执行工具`)
const result = await sandbox.execute(parameters)
// 5. 格式化成功结果
return this.formatSuccessResult(result, tool_resource, startTime)
} catch (error) {
// 6. 智能错误处理 - 检查是否可以自动重试
if (error.intelligentError && this.isAutoRetryable(error.intelligentError)) {
logger.info(`[PromptXTool] 检测到可自动恢复错误,尝试自动重试: ${error.intelligentError.type}`)
try {
// 清理当前沙箱
await sandbox.cleanup()
// 使用重试参数重新创建沙箱
const retryParameters = error.intelligentError.agentInstructions.retryParameters
const retryArgs = { ...args, ...retryParameters }
logger.debug(`[PromptXTool] 自动重试参数:`, retryArgs)
// 递归调用(但限制重试次数)
if (!args._retryCount) args._retryCount = 0
if (args._retryCount < 1) { // 最多重试1次
retryArgs._retryCount = args._retryCount + 1
logger.info(`[PromptXTool] 开始自动重试 (${retryArgs._retryCount}/1)`)
return await this.executeToolInternal(retryArgs)
} else {
logger.warn(`[PromptXTool] 已达到最大重试次数,停止重试`)
}
} catch (retryError) {
logger.error(`[PromptXTool] 自动重试失败: ${retryError.message}`)
// 使用重试错误而不是原始错误
error = retryError
}
}
// 7. 格式化错误结果
logger.error(`[PromptXTool] 工具执行失败: ${error.message}`, error)
return this.formatErrorResult(error, args.tool_resource, startTime)
} finally {
// 7. 清理沙箱资源
if (sandbox) {
try {
await sandbox.cleanup()
} catch (cleanupError) {
logger.warn(`[PromptXTool] 沙箱清理失败: ${cleanupError.message}`)
}
}
}
}
/**
* 验证命令参数
* @param {Object} args - 命令参数
*/
validateArguments(args) {
if (!args) {
throw new Error('Missing arguments')
}
if (!args.tool_resource) {
throw new Error('Missing required parameter: tool_resource')
}
if (!args.tool_resource.startsWith('@tool://')) {
throw new Error('Invalid tool_resource format. Must start with @tool://')
}
if (!args.parameters || typeof args.parameters !== 'object') {
throw new Error('Missing or invalid parameters. Must be an object')
}
}
/**
* 格式化成功结果 - 适配ToolSandbox返回格式
* @param {*} result - 工具执行结果
* @param {string} toolResource - 工具资源引用
* @param {number} startTime - 开始时间
* @returns {Object} 格式化的成功结果
*/
formatSuccessResult(result, toolResource, startTime) {
const duration = Date.now() - startTime
return {
success: true,
tool_resource: toolResource,
result: result, // ToolSandbox直接返回工具结果
metadata: {
executor: 'ToolSandbox',
execution_time_ms: duration,
timestamp: new Date().toISOString(),
version: '1.0.0'
}
}
}
/**
* 格式化错误结果 - 适配ToolSandbox智能错误格式
* @param {Error} error - 错误对象
* @param {string} toolResource - 工具资源引用(可能为空)
* @param {number} startTime - 开始时间
* @returns {Object} 格式化的错误结果
*/
formatErrorResult(error, toolResource, startTime) {
const duration = Date.now() - startTime
const executionId = this.generateExecutionId()
// 检查是否为智能错误
let errorCode, errorMessage, errorType = 'UNKNOWN_ERROR'
let agentInstructions = null
if (error.intelligentError) {
// 使用智能错误管理器提供的信息
errorType = error.intelligentError.type
errorCode = this.mapIntelligentErrorToCode(errorType)
errorMessage = error.intelligentError.formattedMessage
agentInstructions = error.intelligentError.agentInstructions
} else {
// 回退到传统错误处理
errorCode = this.getErrorCode(error)
errorMessage = error.message
}
const result = {
success: false,
tool_resource: toolResource || 'unknown',
error: {
code: errorCode,
type: errorType,
message: errorMessage,
details: {
executionId: executionId,
executionTime: `${duration}ms`,
stack: error.stack
}
},
metadata: {
executor: 'ToolSandbox',
timestamp: new Date().toISOString(),
execution_time_ms: duration
}
}
// 如果有Agent指令,添加到metadata中
if (agentInstructions) {
result.metadata.agentInstructions = agentInstructions
}
return result
}
/**
* 将智能错误类型映射到传统错误代码
* @param {string} intelligentErrorType - 智能错误类型
* @returns {string} 错误代码
*/
mapIntelligentErrorToCode(intelligentErrorType) {
const mapping = {
'DEPENDENCY_MISSING': 'DEPENDENCY_ERROR',
'UNDECLARED_DEPENDENCY': 'DEPENDENCY_ERROR',
'DEPENDENCY_INSTALL_FAILED': 'DEPENDENCY_ERROR',
'TOOL_LOADING_ERROR': 'ANALYSIS_ERROR',
'PARAMETER_VALIDATION_ERROR': 'VALIDATION_ERROR',
'SANDBOX_ENVIRONMENT_ERROR': 'EXECUTION_ERROR',
'NETWORK_TIMEOUT': 'EXECUTION_TIMEOUT',
'UNKNOWN_ERROR': 'UNKNOWN_ERROR'
}
return mapping[intelligentErrorType] || 'UNKNOWN_ERROR'
}
/**
* 根据错误类型获取错误代码 - 增强支持ToolSandbox错误
* @param {Error} error - 错误对象
* @returns {string} 错误代码
*/
getErrorCode(error) {
const message = error.message.toLowerCase()
// ToolSandbox特有错误
if (message.includes('analyze') || message.includes('analysis')) {
return 'ANALYSIS_ERROR'
}
if (message.includes('dependencies') || message.includes('pnpm')) {
return 'DEPENDENCY_ERROR'
}
if (message.includes('sandbox') || message.includes('execution')) {
return 'EXECUTION_ERROR'
}
if (message.includes('validation') || message.includes('validate')) {
return 'VALIDATION_ERROR'
}
// 通用错误
if (message.includes('not found')) {
return 'TOOL_NOT_FOUND'
}
if (message.includes('invalid tool_resource format')) {
return 'INVALID_TOOL_RESOURCE'
}
if (message.includes('missing')) {
return 'MISSING_PARAMETER'
}
if (message.includes('syntax')) {
return 'TOOL_SYNTAX_ERROR'
}
if (message.includes('timeout')) {
return 'EXECUTION_TIMEOUT'
}
return 'UNKNOWN_ERROR'
}
/**
* 生成执行ID
* @returns {string} 唯一的执行ID
*/
generateExecutionId() {
return `tool_exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
}
/**
* 从参数数组中提取timeout值
* @param {Array} args - 参数数组
* @returns {number|undefined} timeout值
*/
extractTimeout(args) {
const timeoutIndex = args.indexOf('--timeout');
if (timeoutIndex !== -1 && timeoutIndex < args.length - 1) {
const timeout = parseInt(args[timeoutIndex + 1]);
return isNaN(timeout) ? undefined : timeout;
}
return undefined;
}
/**
* 检查智能错误是否可以自动重试
* @param {Object} intelligentError - 智能错误对象
* @returns {boolean} 是否可自动重试
*/
isAutoRetryable(intelligentError) {
return intelligentError.agentInstructions &&
intelligentError.agentInstructions.autoRetryable === true &&
intelligentError.agentInstructions.retryParameters
}
/**
* 检查工具内部执行是否成功
* @param {*} toolResult - 工具返回的结果
* @returns {boolean} 工具内部是否成功
*/
isToolInternalSuccess(toolResult) {
// 优先检查是否有data字段,这可能是ToolSandbox包装的结果
if (toolResult && typeof toolResult === 'object' && toolResult.data) {
// 如果data是对象且包含success字段,检查data的success
if (typeof toolResult.data === 'object' && 'success' in toolResult.data) {
return toolResult.data.success === true
}
}
// 检查顶层success字段
if (toolResult && typeof toolResult === 'object' && 'success' in toolResult) {
return toolResult.success === true
}
// 如果工具返回结果不包含success字段,认为是成功的(兼容旧工具)
return true
}
/**
* 从工具内部结果中提取错误信息
* @param {*} toolResult - 工具返回的结果
* @returns {Object} 错误信息
*/
extractToolInternalError(toolResult) {
// 优先从data字段中提取错误信息
if (toolResult && typeof toolResult === 'object' && toolResult.data &&
typeof toolResult.data === 'object' && toolResult.data.error) {
return {
code: toolResult.data.error.code || 'TOOL_INTERNAL_ERROR',
message: toolResult.data.error.message || '工具内部执行失败',
details: toolResult.data.error.details || toolResult.data.error
}
}
// 检查顶层错误信息
if (toolResult && typeof toolResult === 'object' && toolResult.error) {
return {
code: toolResult.error.code || 'TOOL_INTERNAL_ERROR',
message: toolResult.error.message || '工具内部执行失败',
details: toolResult.error.details || toolResult.error
}
}
return {
code: 'TOOL_INTERNAL_ERROR',
message: '工具内部执行失败,但未提供错误详情',
details: JSON.stringify(toolResult)
}
}
/**
* 格式化工具内部错误
* @param {string} toolResource - 工具资源
* @param {Object} internalError - 内部错误信息
* @param {Object} metadata - 元数据
* @returns {string} 格式化的错误信息
*/
formatToolInternalError(toolResource, internalError, metadata) {
// 尝试应用智能错误分析
const intelligentError = this.analyzeToolInternalError(internalError, toolResource)
return `❌ Tool内部执行失败
📋 工具资源: ${toolResource}
❌ 错误信息: ${intelligentError.message}
🏷️ 错误类型: ${intelligentError.type}
🔢 错误代码: ${intelligentError.code}
💡 智能建议:
${intelligentError.suggestion}
⏱️ 执行时间: ${metadata.execution_time_ms}ms`
}
/**
* 分析工具内部错误并提供智能建议
* @param {Object} internalError - 内部错误
* @param {string} toolResource - 工具资源
* @returns {Object} 智能分析结果
*/
analyzeToolInternalError(internalError, toolResource) {
const message = internalError.message.toLowerCase()
const details = internalError.details || ''
// 依赖相关错误
if (message.includes('is not a function') || message.includes('cannot find module')) {
return {
code: 'DEPENDENCY_ERROR',
type: 'DEPENDENCY_USAGE_ERROR',
message: internalError.message,
suggestion: `🔧 依赖使用错误:
• 检查依赖的正确用法
• 确认依赖版本兼容性
• 可能需要使用 "rebuild": true 重建沙箱
💡 建议操作:
promptx_tool ${toolResource} {"rebuild": true, ...其他参数}`
}
}
// 参数验证错误
if (message.includes('validation') || message.includes('parameter')) {
return {
code: 'PARAMETER_ERROR',
type: 'PARAMETER_VALIDATION_ERROR',
message: internalError.message,
suggestion: `📝 参数错误:
• 检查传入的参数格式和类型
• 确认必需参数是否缺失
• 参考工具的schema定义`
}
}
// 网络或外部服务错误
if (message.includes('timeout') || message.includes('network') || message.includes('fetch')) {
return {
code: 'NETWORK_ERROR',
type: 'EXTERNAL_SERVICE_ERROR',
message: internalError.message,
suggestion: `🌐 网络服务错误:
• 检查网络连接状态
• 确认外部API服务可用性
• 稍后重试可能解决问题`
}
}
// 默认分析
return {
code: internalError.code || 'TOOL_INTERNAL_ERROR',
type: 'UNKNOWN_TOOL_ERROR',
message: internalError.message,
suggestion: `🔧 工具内部错误:
• 这可能是工具代码的逻辑问题
• 检查工具的实现是否正确
• 如果问题持续,请联系工具开发者
🐛 错误详情:
${typeof details === 'string' ? details : JSON.stringify(details, null, 2)}`
}
}
/**
* 获取工具命令的元信息 - ToolSandbox版本
* @returns {Object} 命令元信息
*/
getMetadata() {
return {
name: 'promptx_tool',
description: '使用ToolSandbox执行通过@tool协议声明的工具',
version: '2.0.0',
author: 'PromptX Framework',
executor: 'ToolSandbox',
supports: {
protocols: ['@tool://'],
formats: ['.tool.js'],
features: [
'ToolSandbox沙箱执行',
'自动依赖管理',
'三阶段执行流程',
'pnpm依赖安装',
'参数验证',
'错误处理',
'执行监控',
'资源清理'
]
}
}
}
}
module.exports = ToolCommand