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.
374 lines (316 loc) • 10.6 kB
JavaScript
const { TOOL_INTERFACE, TOOL_ERROR_CODES } = require('./ToolInterface');
/**
* ToolValidator - 工具接口验证器
* 使用鸭子类型验证工具是否符合PromptX接口规范
*/
class ToolValidator {
/**
* 验证工具是否符合接口规范
* @param {any} tool - 待验证的工具对象
* @returns {Object} 验证结果 {valid: boolean, errors: [], warnings: []}
*/
static validateTool(tool) {
const errors = [];
const warnings = [];
// 基础类型检查
if (!tool || typeof tool !== 'object') {
errors.push('工具必须是对象类型');
return { valid: false, errors, warnings };
}
// 验证必需方法
for (const methodSpec of TOOL_INTERFACE.required) {
const methodName = methodSpec.name;
if (!(methodName in tool)) {
errors.push(`缺少必需方法: ${methodName}`);
continue;
}
if (typeof tool[methodName] !== 'function') {
errors.push(`${methodName} 必须是函数类型`);
continue;
}
// 方法签名验证
try {
const validationResult = this.validateMethod(tool, methodSpec);
if (!validationResult.valid) {
errors.push(...validationResult.errors);
warnings.push(...validationResult.warnings);
}
} catch (error) {
warnings.push(`${methodName} 方法验证时出错: ${error.message}`);
}
}
// 验证可选方法
for (const methodSpec of TOOL_INTERFACE.optional) {
const methodName = methodSpec.name;
if (methodName in tool) {
if (typeof tool[methodName] !== 'function') {
warnings.push(`${methodName} 应该是函数类型`);
} else {
try {
const validationResult = this.validateMethod(tool, methodSpec);
if (!validationResult.valid) {
warnings.push(...validationResult.errors);
}
} catch (error) {
warnings.push(`${methodName} 方法验证时出错: ${error.message}`);
}
}
}
}
return {
valid: errors.length === 0,
errors,
warnings
};
}
/**
* 验证特定方法
* @param {Object} tool - 工具对象
* @param {Object} methodSpec - 方法规范
* @returns {Object} 验证结果
*/
static validateMethod(tool, methodSpec) {
const errors = [];
const warnings = [];
const methodName = methodSpec.name;
try {
switch (methodName) {
case 'getMetadata':
return this.validateGetMetadata(tool);
case 'getSchema':
return this.validateGetSchema(tool);
case 'execute':
return this.validateExecute(tool);
case 'validate':
return this.validateValidateMethod(tool);
default:
return { valid: true, errors: [], warnings: [] };
}
} catch (error) {
errors.push(`${methodName} 方法调用失败: ${error.message}`);
return { valid: false, errors, warnings };
}
}
/**
* 验证getMetadata方法
* @param {Object} tool - 工具对象
* @returns {Object} 验证结果
*/
static validateGetMetadata(tool) {
const errors = [];
const warnings = [];
try {
const metadata = tool.getMetadata();
if (!metadata || typeof metadata !== 'object') {
errors.push('getMetadata() 必须返回对象');
return { valid: false, errors, warnings };
}
// 验证必需字段
if (!metadata.name || typeof metadata.name !== 'string') {
errors.push('metadata.name 必须是非空字符串');
}
if (!metadata.description || typeof metadata.description !== 'string') {
errors.push('metadata.description 必须是非空字符串');
}
if (!metadata.version || typeof metadata.version !== 'string') {
errors.push('metadata.version 必须是非空字符串');
}
// 验证可选字段
if (metadata.category && typeof metadata.category !== 'string') {
warnings.push('metadata.category 应该是字符串类型');
}
if (metadata.author && typeof metadata.author !== 'string') {
warnings.push('metadata.author 应该是字符串类型');
}
} catch (error) {
errors.push(`getMetadata() 执行失败: ${error.message}`);
}
return { valid: errors.length === 0, errors, warnings };
}
/**
* 验证getSchema方法
* @param {Object} tool - 工具对象
* @returns {Object} 验证结果
*/
static validateGetSchema(tool) {
const errors = [];
const warnings = [];
try {
const schema = tool.getSchema();
if (!schema || typeof schema !== 'object') {
errors.push('getSchema() 必须返回对象');
return { valid: false, errors, warnings };
}
// 基础JSON Schema验证
if (!schema.type) {
warnings.push('schema.type 建议定义');
}
if (schema.type && typeof schema.type !== 'string') {
errors.push('schema.type 必须是字符串');
}
if (schema.properties && typeof schema.properties !== 'object') {
errors.push('schema.properties 必须是对象');
}
if (schema.required && !Array.isArray(schema.required)) {
errors.push('schema.required 必须是数组');
}
} catch (error) {
errors.push(`getSchema() 执行失败: ${error.message}`);
}
return { valid: errors.length === 0, errors, warnings };
}
/**
* 验证execute方法
* @param {Object} tool - 工具对象
* @returns {Object} 验证结果
*/
static validateExecute(tool) {
const errors = [];
const warnings = [];
// 检查方法签名
const executeMethod = tool.execute;
if (executeMethod.length === 0) {
warnings.push('execute() 方法建议接受parameters参数');
}
// 注意:这里不实际调用execute方法,因为可能有副作用
// 只进行静态检查
return { valid: errors.length === 0, errors, warnings };
}
/**
* 验证validate方法(可选)
* @param {Object} tool - 工具对象
* @returns {Object} 验证结果
*/
static validateValidateMethod(tool) {
const errors = [];
const warnings = [];
try {
// 测试validate方法的返回格式
const testParams = {};
const result = tool.validate(testParams);
if (!result || typeof result !== 'object') {
errors.push('validate() 必须返回对象');
return { valid: false, errors, warnings };
}
if (typeof result.valid !== 'boolean') {
errors.push('validate() 返回值必须包含valid(boolean)字段');
}
if (result.errors && !Array.isArray(result.errors)) {
errors.push('validate() 返回值的errors字段必须是数组');
}
} catch (error) {
warnings.push(`validate() 方法测试失败: ${error.message}`);
}
return { valid: errors.length === 0, errors, warnings };
}
/**
* 为工具提供默认的validate方法实现
* @param {Object} tool - 工具对象
* @param {Object} parameters - 待验证参数
* @returns {Object} 验证结果
*/
static defaultValidate(tool, parameters) {
const errors = [];
try {
// 获取schema
const schema = tool.getSchema();
// 基础类型检查
if (!parameters || typeof parameters !== 'object') {
errors.push('参数必须是对象类型');
return { valid: false, errors };
}
// 必需参数检查
if (schema.required && Array.isArray(schema.required)) {
for (const field of schema.required) {
if (!(field in parameters)) {
errors.push(`缺少必需参数: ${field}`);
}
}
}
// 基础字段类型检查
if (schema.properties && typeof schema.properties === 'object') {
for (const [field, fieldSchema] of Object.entries(schema.properties)) {
if (field in parameters) {
const value = parameters[field];
const expectedType = fieldSchema.type;
if (expectedType && !this.validateType(value, expectedType)) {
errors.push(`参数 ${field} 类型错误,期望 ${expectedType},实际 ${typeof value}`);
}
}
}
}
} catch (error) {
errors.push(`参数验证失败: ${error.message}`);
}
return { valid: errors.length === 0, errors };
}
/**
* 类型验证辅助方法
* @param {*} value - 待验证值
* @param {string} expectedType - 期望类型
* @returns {boolean} 是否匹配
*/
static validateType(value, expectedType) {
switch (expectedType) {
case 'string':
return typeof value === 'string';
case 'number':
return typeof value === 'number';
case 'boolean':
return typeof value === 'boolean';
case 'object':
return typeof value === 'object' && value !== null;
case 'array':
return Array.isArray(value);
default:
return true; // 未知类型,跳过验证
}
}
/**
* 生成工具接口报告
* @param {Object} tool - 工具对象
* @returns {Object} 接口报告
*/
static generateInterfaceReport(tool) {
const validation = this.validateTool(tool);
const report = {
toolName: 'unknown',
valid: validation.valid,
errors: validation.errors,
warnings: validation.warnings,
implementedMethods: {
required: [],
optional: []
},
metadata: null,
schema: null
};
try {
// 获取工具名称
if (tool.getMetadata) {
const metadata = tool.getMetadata();
report.toolName = metadata.name || 'unknown';
report.metadata = metadata;
}
// 获取schema
if (tool.getSchema) {
report.schema = tool.getSchema();
}
// 检查已实现的方法
for (const methodSpec of TOOL_INTERFACE.required) {
if (typeof tool[methodSpec.name] === 'function') {
report.implementedMethods.required.push(methodSpec.name);
}
}
for (const methodSpec of TOOL_INTERFACE.optional) {
if (typeof tool[methodSpec.name] === 'function') {
report.implementedMethods.optional.push(methodSpec.name);
}
}
} catch (error) {
report.warnings.push(`生成报告时出错: ${error.message}`);
}
return report;
}
}
module.exports = ToolValidator;