UNPKG

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.

294 lines (249 loc) 7.87 kB
const logger = require('../../utils/logger') /** * EnhancedResourceRegistry - 增强的资源注册表 * * 按照DPML协议架构文档设计,支持: * 1. 资源元数据管理(source, priority, timestamp) * 2. 智能合并策略(优先级和时间戳) * 3. 发现源优先级管理 * 4. 批量操作支持 */ class EnhancedResourceRegistry { constructor() { // 主索引:resourceId -> reference this.index = new Map() // 元数据索引:resourceId -> metadata this.metadata = new Map() // 发现源优先级映射 this.sourcePriority = { 'USER': 1, // 最高优先级 'PROJECT': 2, 'PACKAGE': 3, 'INTERNET': 4 // 最低优先级 } } /** * 注册单个资源 * @param {Object} resource - 资源对象 * @param {string} resource.id - 资源ID * @param {string} resource.reference - 资源引用 * @param {Object} resource.metadata - 资源元数据 */ register(resource) { this._validateResource(resource) const { id, reference, metadata } = resource // 如果资源已存在,检查是否应该覆盖 if (this.has(id)) { const existingMetadata = this.metadata.get(id) if (!this._shouldOverride(existingMetadata, metadata)) { return // 不覆盖,保持现有资源 } } // 注册资源 this.index.set(id, reference) this.metadata.set(id, { ...metadata }) } /** * 批量注册资源 * @param {Array} resources - 资源数组 */ registerBatch(resources) { if (!Array.isArray(resources)) { throw new Error('Resources must be an array') } resources.forEach(resource => { try { if (resource && typeof resource === 'object') { this.register(resource) } } catch (error) { logger.warn(`[EnhancedResourceRegistry] Failed to register resource: ${error.message}`) } }) } /** * 合并另一个注册表 * @param {EnhancedResourceRegistry} otherRegistry - 另一个注册表实例 */ merge(otherRegistry) { if (!(otherRegistry instanceof EnhancedResourceRegistry)) { throw new Error('Can only merge with another EnhancedResourceRegistry instance') } // 获取所有资源并批量注册(会自动处理优先级) const otherResources = otherRegistry.list().map(id => ({ id, reference: otherRegistry.resolve(id), metadata: otherRegistry.getMetadata(id) })) this.registerBatch(otherResources) } /** * 解析资源ID到引用 * @param {string} resourceId - 资源ID * @returns {string} 资源引用 */ resolve(resourceId) { // 1. 直接查找 if (this.index.has(resourceId)) { return this.index.get(resourceId) } // 2. 向后兼容:尝试添加协议前缀 const protocols = ['role', 'thought', 'execution', 'memory'] for (const protocol of protocols) { const fullId = `${protocol}:${resourceId}` if (this.index.has(fullId)) { return this.index.get(fullId) } } throw new Error(`Resource '${resourceId}' not found`) } /** * 检查资源是否存在 * @param {string} resourceId - 资源ID * @returns {boolean} 是否存在 */ has(resourceId) { try { this.resolve(resourceId) return true } catch (error) { return false } } /** * 获取资源元数据 * @param {string} resourceId - 资源ID * @returns {Object|null} 元数据对象或null */ getMetadata(resourceId) { // 直接查找 if (this.metadata.has(resourceId)) { return { ...this.metadata.get(resourceId) } } // 向后兼容查找 const protocols = ['role', 'thought', 'execution', 'memory'] for (const protocol of protocols) { const fullId = `${protocol}:${resourceId}` if (this.metadata.has(fullId)) { return { ...this.metadata.get(fullId) } } } return null } /** * 列出所有资源ID * @param {string} [protocol] - 可选的协议过滤器 * @returns {Array<string>} 资源ID列表 */ list(protocol = null) { const allIds = Array.from(this.index.keys()) if (!protocol) { return allIds } return allIds.filter(id => id.startsWith(`${protocol}:`)) } /** * 获取注册表大小 * @returns {number} 资源数量 */ size() { return this.index.size } /** * 清空注册表 */ clear() { this.index.clear() this.metadata.clear() } /** * 移除资源 * @param {string} resourceId - 资源ID */ remove(resourceId) { // 尝试直接移除 if (this.index.has(resourceId)) { this.index.delete(resourceId) this.metadata.delete(resourceId) return } // 向后兼容移除 const protocols = ['role', 'thought', 'execution', 'memory'] for (const protocol of protocols) { const fullId = `${protocol}:${resourceId}` if (this.index.has(fullId)) { this.index.delete(fullId) this.metadata.delete(fullId) return } } } /** * 从发现管理器结果加载资源 * @param {Array} discoveryResults - 发现器返回的资源数组 */ loadFromDiscoveryResults(discoveryResults) { if (!Array.isArray(discoveryResults)) { logger.warn('[EnhancedResourceRegistry] Discovery results must be an array') return } this.registerBatch(discoveryResults) } /** * 验证资源对象 * @param {Object} resource - 资源对象 * @private */ _validateResource(resource) { if (!resource || typeof resource !== 'object') { throw new Error('Resource must be an object') } if (!resource.id || !resource.reference) { throw new Error('Resource must have id and reference') } if (!resource.metadata || typeof resource.metadata !== 'object') { throw new Error('Resource must have metadata with source and priority') } if (!resource.metadata.source || typeof resource.metadata.priority !== 'number') { throw new Error('Resource must have metadata with source and priority') } // 验证ID格式 if (typeof resource.id !== 'string' || !resource.id.includes(':')) { throw new Error('Resource id must be in format "protocol:resourcePath"') } // 验证引用格式 if (typeof resource.reference !== 'string' || !resource.reference.startsWith('@')) { throw new Error('Resource reference must be in DPML format "@protocol://path"') } } /** * 判断是否应该覆盖现有资源 * @param {Object} existingMetadata - 现有资源元数据 * @param {Object} newMetadata - 新资源元数据 * @returns {boolean} 是否应该覆盖 * @private */ _shouldOverride(existingMetadata, newMetadata) { // 1. 按发现源优先级比较 const existingSourcePriority = this.sourcePriority[existingMetadata.source] || 999 const newSourcePriority = this.sourcePriority[newMetadata.source] || 999 if (newSourcePriority < existingSourcePriority) { return true // 新资源优先级更高 } if (newSourcePriority > existingSourcePriority) { return false // 现有资源优先级更高 } // 2. 相同优先级,按数字优先级比较 if (newMetadata.priority < existingMetadata.priority) { return true // 数字越小优先级越高 } if (newMetadata.priority > existingMetadata.priority) { return false } // 3. 相同优先级,按时间戳比较(新的覆盖旧的) const existingTime = existingMetadata.timestamp ? new Date(existingMetadata.timestamp).getTime() : 0 const newTime = newMetadata.timestamp ? new Date(newMetadata.timestamp).getTime() : 0 return newTime >= existingTime } } module.exports = EnhancedResourceRegistry