更新资源管理器和命令逻辑:新增角色创建和生成相关功能,优化资源加载流程,支持用户自定义资源的发现与合并,同时增强错误处理和描述提取逻辑,提升系统的灵活性和用户体验。
This commit is contained in:
220
src/tests/core/resource/ResourceManager.unit.test.js
Normal file
220
src/tests/core/resource/ResourceManager.unit.test.js
Normal file
@ -0,0 +1,220 @@
|
||||
const ResourceManager = require('../../../lib/core/resource/resourceManager')
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
|
||||
describe('ResourceManager - 用户资源发现', () => {
|
||||
let resourceManager
|
||||
let tempDir
|
||||
let mockPackageRoot
|
||||
|
||||
beforeEach(async () => {
|
||||
// 创建临时测试目录
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'promptx-test-'))
|
||||
mockPackageRoot = tempDir
|
||||
|
||||
// 模拟用户资源目录结构
|
||||
await fs.ensureDir(path.join(tempDir, '.promptx', 'resource', 'domain'))
|
||||
|
||||
resourceManager = new ResourceManager()
|
||||
|
||||
// Mock packageProtocol module
|
||||
jest.doMock('../../../lib/core/resource/protocols/PackageProtocol', () => {
|
||||
return class MockPackageProtocol {
|
||||
async getPackageRoot() {
|
||||
return mockPackageRoot
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
// 清理临时目录
|
||||
await fs.remove(tempDir)
|
||||
jest.restoreAllMocks()
|
||||
})
|
||||
|
||||
describe('discoverUserResources', () => {
|
||||
it('应该返回空对象当用户资源目录不存在时', async () => {
|
||||
// 删除用户资源目录
|
||||
await fs.remove(path.join(tempDir, '.promptx'))
|
||||
|
||||
const result = await resourceManager.discoverUserResources()
|
||||
|
||||
expect(result).toEqual({})
|
||||
})
|
||||
|
||||
it('应该发现用户创建的角色文件', async () => {
|
||||
// 创建测试角色文件
|
||||
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'test-sales-analyst')
|
||||
await fs.ensureDir(roleDir)
|
||||
|
||||
const roleContent = `<role>
|
||||
<personality>
|
||||
# 销售数据分析师思维模式
|
||||
## 核心思维特征
|
||||
- **数据敏感性思维**:善于从数字中发现故事和趋势模式
|
||||
</personality>
|
||||
|
||||
<principle>
|
||||
# 销售数据分析师行为原则
|
||||
## 核心工作原则
|
||||
- **数据驱动决策**:所有分析建议必须有可靠数据支撑
|
||||
</principle>
|
||||
|
||||
<knowledge>
|
||||
# 销售数据分析专业知识体系
|
||||
## 数据处理技能
|
||||
- **数据清洗方法**:缺失值处理、异常值识别
|
||||
</knowledge>
|
||||
</role>`
|
||||
|
||||
await fs.writeFile(path.join(roleDir, 'test-sales-analyst.role.md'), roleContent)
|
||||
|
||||
const result = await resourceManager.discoverUserResources()
|
||||
|
||||
expect(result).toHaveProperty('role')
|
||||
expect(result.role).toHaveProperty('test-sales-analyst')
|
||||
expect(result.role['test-sales-analyst']).toMatchObject({
|
||||
file: expect.stringContaining('test-sales-analyst.role.md'),
|
||||
name: expect.stringContaining('销售数据分析师'),
|
||||
source: 'user-generated',
|
||||
format: 'dpml',
|
||||
type: 'role'
|
||||
})
|
||||
})
|
||||
|
||||
it('应该支持多种资源类型发现', async () => {
|
||||
// 创建角色和相关资源
|
||||
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'test-role')
|
||||
await fs.ensureDir(roleDir)
|
||||
await fs.ensureDir(path.join(roleDir, 'thought'))
|
||||
await fs.ensureDir(path.join(roleDir, 'execution'))
|
||||
|
||||
// 创建角色文件
|
||||
await fs.writeFile(path.join(roleDir, 'test-role.role.md'), '<role><personality>Test</personality><principle>Test</principle><knowledge>Test</knowledge></role>')
|
||||
|
||||
// 创建思维文件
|
||||
await fs.writeFile(path.join(roleDir, 'thought', 'test.thought.md'), '<thought><exploration>Test exploration</exploration><reasoning>Test reasoning</reasoning></thought>')
|
||||
|
||||
// 创建执行文件
|
||||
await fs.writeFile(path.join(roleDir, 'execution', 'test.execution.md'), '<execution><constraint>Test constraint</constraint></execution>')
|
||||
|
||||
const result = await resourceManager.discoverUserResources()
|
||||
|
||||
expect(result).toHaveProperty('role')
|
||||
expect(result).toHaveProperty('thought')
|
||||
expect(result).toHaveProperty('execution')
|
||||
expect(result.role).toHaveProperty('test-role')
|
||||
expect(result.thought).toHaveProperty('test')
|
||||
expect(result.execution).toHaveProperty('test')
|
||||
})
|
||||
|
||||
it('应该处理DPML格式错误的文件', async () => {
|
||||
// 创建格式错误的角色文件
|
||||
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'invalid-role')
|
||||
await fs.ensureDir(roleDir)
|
||||
|
||||
const invalidContent = `这不是有效的DPML格式`
|
||||
await fs.writeFile(path.join(roleDir, 'invalid-role.role.md'), invalidContent)
|
||||
|
||||
const result = await resourceManager.discoverUserResources()
|
||||
|
||||
// 应该跳过格式错误的文件,但不应该抛出错误
|
||||
expect(result.role || {}).not.toHaveProperty('invalid-role')
|
||||
})
|
||||
|
||||
it('应该跨平台正确处理路径', async () => {
|
||||
// 在不同平台上创建角色文件
|
||||
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'cross-platform-role')
|
||||
await fs.ensureDir(roleDir)
|
||||
|
||||
const roleContent = '<role><personality>Test</personality><principle>Test</principle><knowledge>Test</knowledge></role>'
|
||||
await fs.writeFile(path.join(roleDir, 'cross-platform-role.role.md'), roleContent)
|
||||
|
||||
const result = await resourceManager.discoverUserResources()
|
||||
|
||||
expect(result.role).toHaveProperty('cross-platform-role')
|
||||
|
||||
// 验证文件路径使用正确的分隔符
|
||||
const roleInfo = result.role['cross-platform-role']
|
||||
expect(roleInfo.file).toBe(path.normalize(roleInfo.file))
|
||||
})
|
||||
})
|
||||
|
||||
describe('loadUnifiedRegistry', () => {
|
||||
it('应该合并系统资源和用户资源', async () => {
|
||||
// 模拟系统资源
|
||||
const mockSystemResources = {
|
||||
role: {
|
||||
'assistant': {
|
||||
file: '@package://prompt/domain/assistant/assistant.role.md',
|
||||
name: '🙋 智能助手',
|
||||
source: 'system',
|
||||
format: 'dpml',
|
||||
type: 'role'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mock fs.readJSON for system registry
|
||||
jest.spyOn(fs, 'readJSON')
|
||||
.mockImplementation((filePath) => {
|
||||
if (filePath.includes('resource.registry.json')) {
|
||||
return Promise.resolve(mockSystemResources)
|
||||
}
|
||||
return Promise.resolve({})
|
||||
})
|
||||
|
||||
// 创建用户资源
|
||||
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'user-role')
|
||||
await fs.ensureDir(roleDir)
|
||||
await fs.writeFile(
|
||||
path.join(roleDir, 'user-role.role.md'),
|
||||
'<role><personality>User</personality><principle>User</principle><knowledge>User</knowledge></role>'
|
||||
)
|
||||
|
||||
const result = await resourceManager.loadUnifiedRegistry()
|
||||
|
||||
expect(result.role).toHaveProperty('assistant') // 系统资源
|
||||
expect(result.role).toHaveProperty('user-role') // 用户资源
|
||||
})
|
||||
|
||||
it('应该让用户资源覆盖同名系统资源', async () => {
|
||||
// 模拟系统资源
|
||||
const mockSystemResources = {
|
||||
role: {
|
||||
'assistant': {
|
||||
file: '@package://prompt/domain/assistant/assistant.role.md',
|
||||
name: '🙋 智能助手',
|
||||
source: 'system',
|
||||
format: 'dpml',
|
||||
type: 'role'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mock fs.readJSON for system registry
|
||||
jest.spyOn(fs, 'readJSON')
|
||||
.mockImplementation((filePath) => {
|
||||
if (filePath.includes('resource.registry.json')) {
|
||||
return Promise.resolve(mockSystemResources)
|
||||
}
|
||||
return Promise.resolve({})
|
||||
})
|
||||
|
||||
// 创建同名的用户资源
|
||||
const roleDir = path.join(tempDir, '.promptx', 'resource', 'domain', 'assistant')
|
||||
await fs.ensureDir(roleDir)
|
||||
await fs.writeFile(
|
||||
path.join(roleDir, 'assistant.role.md'),
|
||||
'<role><personality># 自定义助手\n用户定制的助手</personality><principle>Custom</principle><knowledge>Custom</knowledge></role>'
|
||||
)
|
||||
|
||||
const result = await resourceManager.loadUnifiedRegistry()
|
||||
|
||||
expect(result.role.assistant.source).toBe('user-generated')
|
||||
expect(result.role.assistant.name).toContain('自定义助手')
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user