const fs = require('fs').promises;
const path = require('path');
const os = require('os');
const CognitionSystem = require('./CognitionSystem');
const Anchor = require('./Anchor');
const logger = require('@promptx/logger');
/**
* CognitionManager - 认知系统管理器
*
* 负责管理多个角色的认知系统实例
* 每个角色都有独立的 CognitionSystem 实例和存储路径
*
* 使用单例模式确保内存状态一致性
*
* 存储结构:
* ~/.promptx/cognition/
* ├── java-developer/
* │ └── mind.json
* ├── product-manager/
* │ └── mind.json
* └── copywriter/
* └── mind.json
*/
class CognitionManager {
constructor(resourceManager = null) {
this.resourceManager = resourceManager;
this.systems = new Map(); // roleId -> CognitionSystem
this.basePath = path.join(os.homedir(), '.promptx', 'cognition');
}
/**
* 获取单例实例
* @param {Object} resourceManager - 可选的资源管理器
* @returns {CognitionManager}
*/
static getInstance(resourceManager = null) {
if (!CognitionManager.instance) {
CognitionManager.instance = new CognitionManager(resourceManager);
logger.info('[CognitionManager] Created singleton instance');
}
return CognitionManager.instance;
}
/**
* 获取角色的存储路径
* @param {string} roleId - 角色ID
* @returns {string} 存储路径
*/
getRolePath(roleId) {
return path.join(this.basePath, roleId);
}
/**
* 获取角色的 network.json 文件路径
* @param {string} roleId - 角色ID
* @returns {string} network.json 文件路径
*/
getNetworkFilePath(roleId) {
return path.join(this.getRolePath(roleId), 'network.json');
}
/**
* 确保角色的存储目录存在
* @param {string} roleId - 角色ID
*/
async ensureRoleDirectory(roleId) {
const rolePath = this.getRolePath(roleId);
try {
await fs.mkdir(rolePath, { recursive: true });
logger.debug(`[CognitionManager] Ensured directory for role: ${roleId}`);
} catch (error) {
logger.error(`[CognitionManager] Failed to create directory for role ${roleId}:`, error);
throw error;
}
}
/**
* 获取或创建角色的认知系统实例
* @param {string} roleId - 角色ID
* @returns {CognitionSystem} 认知系统实例
*/
async getSystem(roleId) {
if (!this.systems.has(roleId)) {
logger.info(`[CognitionManager] Creating new CognitionSystem for role: ${roleId}`);
// 确保目录存在
await this.ensureRoleDirectory(roleId);
// 创建新的认知系统实例
const system = new CognitionSystem();
// 为Network添加必要的属性
system.network.roleId = roleId;
system.network.directory = this.getRolePath(roleId);
// 尝试加载已有的认知数据
const networkFilePath = this.getNetworkFilePath(roleId);
try {
await system.network.load(networkFilePath);
logger.info(`[CognitionManager] Loaded existing network data for role: ${roleId}`);
} catch (error) {
// 文件不存在或解析失败,使用空的认知系统
if (error.code !== 'ENOENT') {
logger.warn(`[CognitionManager] Failed to load network data for role ${roleId}:`, error.message);
} else {
logger.debug(`[CognitionManager] No existing network data for role: ${roleId}`);
}
}
this.systems.set(roleId, system);
}
return this.systems.get(roleId);
}
/**
* 保存角色的认知数据
* @param {string} roleId - 角色ID
*/
async saveSystem(roleId) {
const system = this.systems.get(roleId);
if (!system) {
logger.warn(`[CognitionManager] No system to save for role: ${roleId}`);
return;
}
try {
// 确保目录存在
await this.ensureRoleDirectory(roleId);
// 使用 Network 的 persist 方法直接保存
const networkFilePath = this.getNetworkFilePath(roleId);
await system.network.persist(networkFilePath);
logger.info(`[CognitionManager] Saved network data for role: ${roleId}`);
} catch (error) {
logger.error(`[CognitionManager] Failed to save network data for role ${roleId}:`, error);
throw error;
}
}
/**
* Prime - 获取角色的认知概览
* 优先从锚定状态恢复,如果没有则执行常规prime
* @param {string} roleId - 角色ID
* @returns {Mind} Mind 对象
*/
async prime(roleId) {
logger.info(`[CognitionManager] Prime for role: ${roleId}`);
const system = await this.getSystem(roleId);
logger.debug(`[CognitionManager] System network size before prime: ${system.network.size()}`);
// 尝试从锚定状态恢复
const anchor = new Anchor(system.network);
const anchoredState = await anchor.load();
let mind = null;
if (anchoredState && anchoredState.centerWord) {
// 从锚定状态恢复:执行recall(centerWord)
logger.info(`[CognitionManager] Prime from anchored state`, {
centerWord: anchoredState.centerWord,
timestamp: new Date(anchoredState.timestamp).toISOString(),
nodeCount: anchoredState.metadata?.nodeCount
});
mind = await system.recall(anchoredState.centerWord);
if (mind) {
logger.info(`[CognitionManager] Successfully primed from anchored state: "${anchoredState.centerWord}"`);
}
}
// 如果没有锚定状态或恢复失败,执行常规prime
if (!mind) {
logger.debug(`[CognitionManager] No anchored state or recovery failed, using regular prime`);
mind = await system.prime();
}
if (!mind) {
logger.warn(`[CognitionManager] Prime returned null for role: ${roleId}`);
return null;
}
logger.debug(`[CognitionManager] Prime returned Mind:`, {
hasMind: !!mind,
activatedCuesSize: mind?.activatedCues?.size || 0,
connectionsCount: mind?.connections?.length || 0
});
return mind;
}
/**
* Recall - 从角色的认知中检索相关记忆
* 每次recall后自动锚定状态
* @param {string} roleId - 角色ID
* @param {string} query - 查询词
* @param {Object} options - 可选参数
* @param {string} options.mode - 认知激活模式 ('creative' | 'balanced' | 'focused')
* @returns {Promise<Mind>} Mind 对象(包含engrams)
*/
async recall(roleId, query, options = {}) {
const mode = options.mode || 'balanced';
logger.info(`[CognitionManager] Recall for role: ${roleId}, query: "${query}", mode: ${mode}`);
const system = await this.getSystem(roleId);
// 执行recall(现在是异步的,会加载engrams),传入 mode 参数
const mind = await system.recall(query, { mode });
if (!mind) {
logger.warn(`[CognitionManager] Recall returned null for role: ${roleId}, query: ${query}`);
return null;
}
// 自动锚定当前认知状态(仅当recall成功激活了节点)
if (mind && mind.activatedCues && mind.activatedCues.size > 0) {
try {
const anchor = new Anchor(system.network);
await anchor.execute(query, mind);
logger.debug(`[CognitionManager] Auto-anchored state after recall: "${query}"`, {
activatedNodes: mind.activatedCues.size
});
} catch (error) {
logger.error(`[CognitionManager] Failed to auto-anchor state:`, error);
// 锚定失败不影响recall结果
}
} else {
logger.debug(`[CognitionManager] Skip anchoring - recall returned empty mind`, {
query,
hasActivatedCues: mind?.activatedCues?.size || 0
});
}
return mind;
}
/**
* Remember - 保存新的记忆到角色的认知系统
* @param {string} roleId - 角色ID
* @param {Array} engrams - 记忆数组
*/
async remember(roleId, engrams) {
logger.info(`[CognitionManager] Remember for role: ${roleId}, ${engrams.length} engrams`);
const system = await this.getSystem(roleId);
const Engram = require('./Engram');
for (const engramData of engrams) {
try {
// 创建Engram对象
const engram = new Engram({
content: engramData.content,
schema: engramData.schema,
strength: engramData.strength,
type: engramData.type, // 传递type字段
timestamp: Date.now() // 使用当前时间戳
});
if (!engram.isValid()) {
logger.warn(`[CognitionManager] Invalid engram (schema too short):`, engramData);
continue;
}
// CognitionSystem现在会自动处理Memory存储
await system.remember(engram);
logger.debug(`[CognitionManager] Processed engram:`, {
preview: engram.getPreview(),
strength: engram.strength
});
} catch (error) {
logger.error(`[CognitionManager] Failed to process engram:`, error);
// 重新抛出错误,让上层感知到失败
throw error;
}
}
// 保存更新后的认知数据
await this.saveSystem(roleId);
logger.info(`[CognitionManager] Successfully saved ${engrams.length} engrams for role: ${roleId}`);
}
/**
* 解析 schema 字符串为概念列表
* @param {string} schema - 结构化的知识表示
* @returns {Array<string>} 概念列表
*/
parseSchema(schema) {
if (!schema) return [];
// 支持多种分隔符:优先使用 - 分隔符
let concepts = [];
if (schema.includes(' - ')) {
// 用 - 分割(标准格式)
concepts = schema.split(/\s*-\s*/).filter(c => c.trim());
} else if (schema.includes('\n')) {
// 兼容旧格式:用换行符分割
const lines = schema.split('\n').filter(line => line.trim());
for (const line of lines) {
// 移除缩进和特殊符号,提取概念
const concept = line.trim().replace(/^[-*>#\s]+/, '').trim();
if (concept) {
concepts.push(concept);
}
}
} else {
// 如果没有分隔符,尝试用空格分割
concepts = schema.split(/\s+/).filter(c => c.trim());
}
return concepts;
}
/**
* 清理角色的认知数据
* @param {string} roleId - 角色ID
*/
async clearRole(roleId) {
logger.warn(`[CognitionManager] Clearing cognition data for role: ${roleId}`);
// 从内存中移除
this.systems.delete(roleId);
// 删除文件
try {
const networkFilePath = this.getNetworkFilePath(roleId);
await fs.unlink(networkFilePath);
logger.info(`[CognitionManager] Deleted network file for role: ${roleId}`);
} catch (error) {
if (error.code !== 'ENOENT') {
logger.error(`[CognitionManager] Failed to delete network file for role ${roleId}:`, error);
}
}
}
/**
* 获取所有已存储的角色列表
*/
async listRoles() {
try {
await fs.mkdir(this.basePath, { recursive: true });
const entries = await fs.readdir(this.basePath, { withFileTypes: true });
const roles = [];
for (const entry of entries) {
if (entry.isDirectory()) {
// 检查是否有 network.json 文件
const networkFilePath = this.getNetworkFilePath(entry.name);
try {
await fs.access(networkFilePath);
roles.push(entry.name);
} catch {
// 没有 network.json 文件,跳过
}
}
}
return roles;
} catch (error) {
logger.error('[CognitionManager] Failed to list roles:', error);
return [];
}
}
}
module.exports = CognitionManager;