重构ActionCommand和LearnCommand,更新DPMLContentParser和SemanticRenderer的导入路径,确保模块结构一致性。删除不再使用的DPMLContentParser和SemanticRenderer文件,优化代码结构,提升可维护性。

This commit is contained in:
sean
2025-06-16 12:18:32 +08:00
parent 40c3b83854
commit 9972922067
43 changed files with 603 additions and 7653 deletions

View File

@ -1,179 +0,0 @@
/**
* DPML内容解析器
* 统一处理DPML标签内的混合内容@引用 + 直接内容)
* 确保标签语义完整性
*/
class DPMLContentParser {
/**
* 解析DPML标签的完整语义内容
* @param {string} content - 标签内的原始内容
* @param {string} tagName - 标签名称
* @returns {Object} 完整的语义结构
*/
parseTagContent(content, tagName) {
if (!content || !content.trim()) {
return {
fullSemantics: '',
references: [],
directContent: '',
metadata: {
tagName,
hasReferences: false,
hasDirectContent: false,
contentType: 'empty'
}
}
}
const cleanContent = content.trim()
const references = this.extractReferencesWithPosition(cleanContent)
const directContent = this.extractDirectContent(cleanContent)
return {
// 完整语义内容(用户看到的最终效果)
fullSemantics: cleanContent,
// 引用部分(需要解析和加载的资源)
references,
// 直接部分(用户原创内容)
directContent,
// 元数据
metadata: {
tagName,
hasReferences: references.length > 0,
hasDirectContent: directContent.length > 0,
contentType: this.determineContentType(cleanContent)
}
}
}
/**
* 提取所有@引用
* @param {string} content - 内容
* @returns {Array} 引用数组
*/
extractReferences(content) {
// 使用新的位置信息方法,但保持向下兼容
return this.extractReferencesWithPosition(content).map(ref => ({
fullMatch: ref.fullMatch,
priority: ref.priority,
protocol: ref.protocol,
resource: ref.resource,
isRequired: ref.isRequired,
isOptional: ref.isOptional
}))
}
/**
* 新增:获取引用的位置信息
* @param {string} content - 内容
* @returns {Array} 包含位置信息的引用数组
*/
extractReferencesWithPosition(content) {
if (!content) {
return []
}
const resourceRegex = /@([!?]?)([a-zA-Z][a-zA-Z0-9_-]*):\/\/([a-zA-Z0-9_\/.,-]+?)(?=[\s\)\],]|$)/g
const matches = []
let match
while ((match = resourceRegex.exec(content)) !== null) {
matches.push({
fullMatch: match[0],
priority: match[1],
protocol: match[2],
resource: match[3],
position: match.index, // 位置信息
isRequired: match[1] === '!',
isOptional: match[1] === '?'
})
}
return matches.sort((a, b) => a.position - b.position) // 按位置排序
}
/**
* 提取直接内容(移除@引用后的剩余内容)
* @param {string} content - 内容
* @returns {string} 直接内容
*/
extractDirectContent(content) {
// 移除所有@引用行,保留其他内容
const withoutReferences = content.replace(/^.*@[!?]?[a-zA-Z][a-zA-Z0-9_-]*:\/\/.*$/gm, '')
// 清理多余的空行
const cleaned = withoutReferences.replace(/\n{3,}/g, '\n\n').trim()
return cleaned
}
/**
* 检查是否包含引用
* @param {string} content - 内容
* @returns {boolean}
*/
hasReferences(content) {
return /@[!?]?[a-zA-Z][a-zA-Z0-9_-]*:\/\//.test(content)
}
/**
* 检查是否包含直接内容
* @param {string} content - 内容
* @returns {boolean}
*/
hasDirectContent(content) {
const withoutReferences = this.extractDirectContent(content)
return withoutReferences.length > 0
}
/**
* 确定内容类型
* @param {string} content - 内容
* @returns {string} 内容类型
*/
determineContentType(content) {
const hasRefs = this.hasReferences(content)
const hasDirect = this.hasDirectContent(content)
if (hasRefs && hasDirect) return 'mixed'
if (hasRefs) return 'references-only'
if (hasDirect) return 'direct-only'
return 'empty'
}
/**
* 从DPML文档中提取指定标签的内容
* @param {string} dpmlContent - 完整的DPML文档内容
* @param {string} tagName - 标签名称
* @returns {string} 标签内容
*/
extractTagContent(dpmlContent, tagName) {
const regex = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`, 'i')
const match = dpmlContent.match(regex)
return match ? match[1] : ''
}
/**
* 解析完整的DPML角色文档
* @param {string} roleContent - 角色文档内容
* @returns {Object} 解析后的角色语义结构
*/
parseRoleDocument(roleContent) {
const dpmlTags = ['personality', 'principle', 'knowledge']
const roleSemantics = {}
dpmlTags.forEach(tagName => {
const tagContent = this.extractTagContent(roleContent, tagName)
if (tagContent) {
roleSemantics[tagName] = this.parseTagContent(tagContent, tagName)
}
})
return roleSemantics
}
}
module.exports = DPMLContentParser

View File

@ -1,83 +0,0 @@
/**
* SemanticRenderer - DPML语义渲染器
*
* 核心理念:@引用 = 语义占位符
* 在标签的原始位置插入引用内容,保持完整的语义流程
*/
class SemanticRenderer {
/**
* 语义占位符渲染:将@引用替换为实际内容
* @param {Object} tagSemantics - 标签语义结构
* @param {string} tagSemantics.fullSemantics - 完整的语义内容
* @param {Array} tagSemantics.references - 引用列表
* @param {ResourceManager} resourceManager - 资源管理器
* @returns {string} 完整融合的语义内容
*/
async renderSemanticContent(tagSemantics, resourceManager) {
if (!tagSemantics || !tagSemantics.fullSemantics) {
return ''
}
let content = tagSemantics.fullSemantics
if (!tagSemantics.references || tagSemantics.references.length === 0) {
return content.trim()
}
// 按出现顺序处理每个@引用(保持位置语义)
// 需要按位置排序确保正确的替换顺序
const sortedReferences = [...tagSemantics.references].sort((a, b) => a.position - b.position)
for (const ref of sortedReferences) {
try {
// 解析引用内容
const result = await resourceManager.resolve(ref.fullMatch)
// 检查解析是否成功
if (result.success) {
// 提取标签内容去掉外层DPML标签
const cleanContent = this.extractTagInnerContent(result.content, ref.protocol)
// 用<reference>标签包装引用内容,标明这是占位符渲染
const wrappedContent = `<reference protocol="${ref.protocol}" resource="${ref.resource}">\n${cleanContent}\n</reference>`
// 在原始位置替换@引用为实际内容
const refIndex = content.indexOf(ref.fullMatch)
if (refIndex !== -1) {
content = content.substring(0, refIndex) + wrappedContent + content.substring(refIndex + ref.fullMatch.length)
} else {
content = content.replace(ref.fullMatch, wrappedContent)
}
} else {
// 解析失败时的优雅降级
content = content.replace(ref.fullMatch, `<!-- 引用解析失败: ${ref.fullMatch} - ${result.error?.message || 'Unknown error'} -->`)
}
} catch (error) {
// 引用解析失败时的优雅降级
content = content.replace(ref.fullMatch, `<!-- 引用解析失败: ${ref.fullMatch} - ${error.message} -->`)
}
}
return content.trim()
}
/**
* 提取DPML标签内的内容
* @param {string} content - 包含DPML标签的完整内容
* @param {string} protocol - 协议名称thought, execution等
* @returns {string} 标签内的纯内容
*/
extractTagInnerContent(content, protocol) {
// 根据协议类型确定标签名
const tagName = protocol
const regex = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`, 'i')
const match = content.match(regex)
if (match && match[1]) {
return match[1].trim()
}
// 如果没有匹配到标签,返回原内容(可能已经是纯内容)
return content.trim()
}
}
module.exports = SemanticRenderer