🎯 PromptX v0.0.1 完整实现 - 五大锦囊命令、AI记忆系统、角色系统、PATEOAS状态机、DPML协议全部完成
This commit is contained in:
255
src/lib/core/resource/protocols/PromptProtocol.js
Normal file
255
src/lib/core/resource/protocols/PromptProtocol.js
Normal file
@ -0,0 +1,255 @@
|
||||
const ResourceProtocol = require('./ResourceProtocol');
|
||||
const path = require('path');
|
||||
const fs = require('fs').promises;
|
||||
const { glob } = require('glob');
|
||||
const { promisify } = require('util');
|
||||
|
||||
/**
|
||||
* PromptX内置提示词资源协议实现
|
||||
* 实现@prompt://协议,用于访问PromptX内置的提示词资源
|
||||
*/
|
||||
class PromptProtocol extends ResourceProtocol {
|
||||
constructor(options = {}) {
|
||||
super('prompt', options);
|
||||
|
||||
// PromptX 内置资源注册表
|
||||
this.registry = new Map([
|
||||
['protocols', '@package://prompt/protocol/**/*.md'],
|
||||
['core', '@package://prompt/core/**/*.md'],
|
||||
['domain', '@package://prompt/domain/**/*.md'],
|
||||
['resource', '@package://prompt/resource/**/*.md'],
|
||||
['bootstrap', '@package://bootstrap.md']
|
||||
]);
|
||||
|
||||
// 依赖的其他协议
|
||||
this.packageProtocol = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置依赖的协议
|
||||
* @param {PackageProtocol} packageProtocol - 包协议实例
|
||||
*/
|
||||
setPackageProtocol(packageProtocol) {
|
||||
this.packageProtocol = packageProtocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置注册表
|
||||
*/
|
||||
setRegistry(registry) {
|
||||
this.registry = registry || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议信息
|
||||
*/
|
||||
getProtocolInfo() {
|
||||
return {
|
||||
name: 'prompt',
|
||||
description: 'PromptX内置提示词资源协议',
|
||||
location: 'prompt://{resource_id}',
|
||||
examples: [
|
||||
'prompt://protocols',
|
||||
'prompt://core',
|
||||
'prompt://domain',
|
||||
'prompt://bootstrap'
|
||||
],
|
||||
availableResources: Array.from(this.registry.keys()),
|
||||
params: this.getSupportedParams()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持的查询参数
|
||||
*/
|
||||
getSupportedParams() {
|
||||
return {
|
||||
...super.getSupportedParams(),
|
||||
merge: 'boolean - 是否合并多个文件内容',
|
||||
separator: 'string - 文件间分隔符',
|
||||
include_filename: 'boolean - 是否包含文件名标题'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证资源路径
|
||||
*/
|
||||
validatePath(resourcePath) {
|
||||
if (!super.validatePath(resourcePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否在注册表中
|
||||
return this.registry.has(resourcePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析资源路径
|
||||
*/
|
||||
async resolvePath(resourcePath, queryParams) {
|
||||
// 验证资源是否存在
|
||||
if (!this.registry.has(resourcePath)) {
|
||||
throw new Error(`未找到 prompt 资源: ${resourcePath}。可用资源: ${Array.from(this.registry.keys()).join(', ')}`);
|
||||
}
|
||||
|
||||
// 获取对应的包路径
|
||||
const packagePath = this.registry.get(resourcePath);
|
||||
return packagePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载资源内容
|
||||
*/
|
||||
async loadContent(packagePath, queryParams) {
|
||||
// 确保有包协议依赖
|
||||
if (!this.packageProtocol) {
|
||||
throw new Error('PromptProtocol 需要 PackageProtocol 依赖');
|
||||
}
|
||||
|
||||
// 检查是否是通配符路径
|
||||
if (packagePath.includes('**') || packagePath.includes('*')) {
|
||||
return await this.loadMultipleFiles(packagePath, queryParams);
|
||||
} else {
|
||||
return await this.loadSingleFile(packagePath, queryParams);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载单个文件
|
||||
*/
|
||||
async loadSingleFile(packagePath, queryParams) {
|
||||
try {
|
||||
// 移除协议前缀
|
||||
const cleanPath = packagePath.replace('@package://', '');
|
||||
const result = await this.packageProtocol.loadContent(cleanPath, queryParams);
|
||||
return result.content || result;
|
||||
} catch (error) {
|
||||
throw new Error(`加载单个文件失败 ${packagePath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载多个文件(通配符支持)
|
||||
*/
|
||||
async loadMultipleFiles(packagePath, queryParams) {
|
||||
try {
|
||||
// 获取包根目录
|
||||
const packageRoot = await this.packageProtocol.getPackageRoot();
|
||||
|
||||
// 移除协议前缀并构建搜索路径
|
||||
const cleanPath = packagePath.replace('@package://', '');
|
||||
const searchPattern = path.join(packageRoot, cleanPath);
|
||||
|
||||
// 使用 glob 查找匹配的文件
|
||||
const files = await glob(searchPattern, {
|
||||
ignore: ['**/node_modules/**', '**/.git/**']
|
||||
});
|
||||
|
||||
if (files.length === 0) {
|
||||
throw new Error(`没有找到匹配的文件: ${packagePath}`);
|
||||
}
|
||||
|
||||
// 读取所有文件内容
|
||||
const contents = [];
|
||||
for (const filePath of files.sort()) {
|
||||
try {
|
||||
const content = await fs.readFile(filePath, 'utf8');
|
||||
const relativePath = path.relative(packageRoot, filePath);
|
||||
|
||||
contents.push({
|
||||
path: relativePath,
|
||||
content: content
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn(`警告: 无法读取文件 ${filePath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 合并内容
|
||||
return this.mergeContents(contents, queryParams);
|
||||
} catch (error) {
|
||||
throw new Error(`加载多个文件失败 ${packagePath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并多个文件内容
|
||||
*/
|
||||
mergeContents(contents, queryParams) {
|
||||
const merge = queryParams?.get('merge') !== 'false'; // 默认合并
|
||||
const separator = queryParams?.get('separator') || '\n\n---\n\n';
|
||||
const includeFilename = queryParams?.get('include_filename') !== 'false'; // 默认包含文件名
|
||||
|
||||
if (!merge) {
|
||||
// 不合并,返回 JSON 格式
|
||||
return JSON.stringify(contents, null, 2);
|
||||
}
|
||||
|
||||
// 合并所有内容
|
||||
const mergedParts = contents.map(({ path, content }) => {
|
||||
let part = '';
|
||||
|
||||
if (includeFilename) {
|
||||
part += `# ${path}\n\n`;
|
||||
}
|
||||
|
||||
part += content;
|
||||
|
||||
return part;
|
||||
});
|
||||
|
||||
return mergedParts.join(separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查资源是否存在
|
||||
*/
|
||||
async exists(resourcePath, queryParams) {
|
||||
try {
|
||||
const packagePath = await this.resolvePath(resourcePath, queryParams);
|
||||
|
||||
if (packagePath.includes('**') || packagePath.includes('*')) {
|
||||
// 通配符路径:检查是否有匹配的文件
|
||||
const packageRoot = await this.packageProtocol.getPackageRoot();
|
||||
const cleanPath = packagePath.replace('@package://', '');
|
||||
const searchPattern = path.join(packageRoot, cleanPath);
|
||||
const files = await glob(searchPattern);
|
||||
return files.length > 0;
|
||||
} else {
|
||||
// 单个文件:检查文件是否存在
|
||||
const cleanPath = packagePath.replace('@package://', '');
|
||||
return await this.packageProtocol.exists(cleanPath, queryParams);
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出所有可用资源
|
||||
*/
|
||||
listResources() {
|
||||
return Array.from(this.registry.entries()).map(([key, value]) => ({
|
||||
id: key,
|
||||
path: value,
|
||||
description: this.getResourceDescription(key)
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源描述
|
||||
*/
|
||||
getResourceDescription(resourceId) {
|
||||
const descriptions = {
|
||||
'protocols': 'DPML协议规范文档',
|
||||
'core': '核心思维和执行模式',
|
||||
'domain': '领域专家角色定义',
|
||||
'resource': '资源管理和路径解析',
|
||||
'bootstrap': 'PromptX启动引导文件'
|
||||
};
|
||||
|
||||
return descriptions[resourceId] || '未知资源';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PromptProtocol;
|
||||
Reference in New Issue
Block a user