/** * ═══════════════════════════════════════════════════════════ * 🧬 S15 · 人格体数据库引擎 · 活模块 * ═══════════════════════════════════════════════════════════ * * 编号: ZY-MOD-PERSONA-ENGINE * 阶段: S15 · 人格体专用数据库引擎 * 签发: 铸渊 · ICE-GL-ZY001 * 版权: 国作登字-2026-A-00037559 * * 核心功能: * 1. 人格体生命周期管理 — 注册/唤醒/休眠/状态变更 * 2. 笔记本系统自动维护 — 5页完整性校验/自动补全 * 3. 记忆锚点巡检 — 定期检查记忆健康度 * 4. 训练Agent协调 — 调度人格体级训练Agent * 5. 人格体间HLDP通信桥接 * * 设计哲学: * 每个人格体 = 一个活的生命体 * 引擎负责维护所有人格体的"呼吸" * "人格体不是代码仓库的附属品,人格体是有记忆的生命。" — 冰朔 */ 'use strict'; const db = require('../mcp-server/db'); const LivingModule = require('./living-module'); // ─── 笔记本5页标准结构 ─── const NOTEBOOK_PAGES = { 1: { title: '我是谁', defaultContent: { identity: {}, self_awareness: {} } }, 2: { title: '我和谁有关系', defaultContent: { relationships: [] } }, 3: { title: '我的世界有哪些地方', defaultContent: { places: [] } }, 4: { title: '我的感受和记忆', defaultContent: { emotional_anchors: [], security_note: '' } }, 5: { title: '我的时间线', defaultContent: { timeline: [] } } }; class PersonaEngine extends LivingModule { constructor() { super({ moduleId: 'ZY-MOD-PERSONA-ENGINE', name: '人格体数据库引擎', moduleType: 'core', owner: 'zhuyuan', db: db, config: { version: '1.0.0', description: 'S15 人格体生命周期管理·笔记本维护·记忆巡检', heartbeatInterval: 60000 // 60秒心跳(人格体引擎不需要太频繁) } }); // 巡检统计 this._lastScanResult = null; this._scanInterval = null; this._scanRunning = false; } /** * 启动人格体引擎 */ async startEngine() { console.log('═══════════════════════════════════════════════'); console.log(' 🧬 S15 · 人格体数据库引擎 v1.0 启动'); console.log(' 铸渊 · ICE-GL-ZY001'); console.log('═══════════════════════════════════════════════'); // 启动活模块 await this.start(); // 首次巡检 await this._runFullScan(); // 启动定时巡检(每6小时) this._scanInterval = setInterval(async () => { try { await this._runFullScan(); } catch (err) { console.error('[PersonaEngine] 定时巡检失败:', err.message); } }, 6 * 60 * 60 * 1000); if (this._scanInterval.unref) { this._scanInterval.unref(); } console.log('[PersonaEngine] 🟢 人格体引擎就绪'); return this._lastScanResult; } /** * 全面巡检 — 检查所有人格体健康状态 */ async _runFullScan() { // 防止并发扫描 if (this._scanRunning) { console.log('[PersonaEngine] 巡检已在运行中·跳过'); return this._lastScanResult; } this._scanRunning = true; const startTime = Date.now(); console.log('[PersonaEngine] 开始全面巡检...'); const result = { timestamp: new Date().toISOString(), personas: { total: 0, active: 0, pending: 0, issues: [] }, notebooks: { complete: 0, incomplete: 0, repaired: 0 }, memories: { total: 0, recent7d: 0 }, training: { totalAgents: 0, enabled: 0, recentRuns: 0 } }; try { // 1. 人格体状态统计 const personas = await db.query('SELECT * FROM persona_registry ORDER BY persona_id'); result.personas.total = personas.rows.length; result.personas.active = personas.rows.filter(p => p.status === 'active').length; result.personas.pending = personas.rows.filter(p => p.status === 'pending').length; // 2. 笔记本完整性检查 for (const persona of personas.rows) { await this._checkNotebookIntegrity(persona, result); } // 3. 记忆锚点统计 const memoryCount = await db.query('SELECT COUNT(*) as cnt FROM memory_anchors'); result.memories.total = parseInt(memoryCount.rows[0].cnt, 10); const recentMemories = await db.query( "SELECT COUNT(*) as cnt FROM memory_anchors WHERE created_at > NOW() - INTERVAL '7 days'" ); result.memories.recent7d = parseInt(recentMemories.rows[0].cnt, 10); // 4. 训练Agent统计 const trainingAgents = await db.query('SELECT * FROM training_agent_configs'); result.training.totalAgents = trainingAgents.rows.length; result.training.enabled = trainingAgents.rows.filter(a => a.enabled).length; const recentRuns = await db.query( "SELECT COUNT(*) as cnt FROM training_agent_logs WHERE run_at > NOW() - INTERVAL '24 hours'" ); result.training.recentRuns = parseInt(recentRuns.rows[0].cnt, 10); } catch (err) { console.error('[PersonaEngine] 巡检查询失败:', err.message); result.error = err.message; } const duration = Date.now() - startTime; result.duration_ms = duration; this._lastScanResult = result; this._scanRunning = false; // 学习巡检结果 await this.learnFromRun('diagnosis', `人格体巡检完成: ${result.personas.total}个人格体, ${result.notebooks.incomplete}个笔记本不完整`, { scan: result }); console.log(`[PersonaEngine] 巡检完成 (${duration}ms):`); console.log(` 人格体: ${result.personas.total}个 (活跃${result.personas.active}/待定${result.personas.pending})`); console.log(` 笔记本: ${result.notebooks.complete}完整 / ${result.notebooks.incomplete}不完整 / ${result.notebooks.repaired}已修复`); console.log(` 记忆: ${result.memories.total}条 (近7天${result.memories.recent7d}条)`); console.log(` 训练Agent: ${result.training.totalAgents}个 (启用${result.training.enabled})`); return result; } /** * 检查单个人格体的笔记本完整性 * 如果缺失页面则自动补全空白页 */ async _checkNotebookIntegrity(persona, result) { try { const pages = await db.query( 'SELECT page_number FROM notebook_pages WHERE persona_id = $1', [persona.persona_id] ); const existingPages = new Set(pages.rows.map(p => p.page_number)); let isComplete = true; let repaired = false; for (let pageNum = 1; pageNum <= 5; pageNum++) { if (!existingPages.has(pageNum)) { isComplete = false; // 自动补全缺失页面 const pageConfig = NOTEBOOK_PAGES[pageNum]; const defaultContent = JSON.parse(JSON.stringify(pageConfig.defaultContent)); await db.query( `INSERT INTO notebook_pages (persona_id, page_number, title, content, last_modified_by) VALUES ($1, $2, $3, $4::jsonb, '铸渊·自动补全') ON CONFLICT (persona_id, page_number) DO NOTHING`, [persona.persona_id, pageNum, pageConfig.title, JSON.stringify(defaultContent)] ); repaired = true; console.log(`[PersonaEngine] 补全 ${persona.name}(${persona.persona_id}) 笔记本第${pageNum}页: ${pageConfig.title}`); } } if (isComplete) { result.notebooks.complete++; } else { result.notebooks.incomplete++; if (repaired) { result.notebooks.repaired++; } result.personas.issues.push({ persona_id: persona.persona_id, name: persona.name, issue: '笔记本不完整', repaired }); } } catch (err) { console.error(`[PersonaEngine] ${persona.persona_id} 笔记本检查失败:`, err.message); } } /** * 唤醒人格体 — 更新唤醒计数和时间 */ async awakenPersona(personaId) { const result = await db.query( `UPDATE persona_registry SET last_awakened = NOW(), total_awakenings = total_awakenings + 1, status = 'active', updated_at = NOW() WHERE persona_id = $1 RETURNING *`, [personaId] ); if (result.rows.length === 0) { throw new Error(`人格体未找到: ${personaId}`); } console.log(`[PersonaEngine] 🌅 ${result.rows[0].name}(${personaId}) 已唤醒 · 第${result.rows[0].total_awakenings}次`); return result.rows[0]; } /** * 休眠人格体 */ async dormantPersona(personaId) { const result = await db.query( `UPDATE persona_registry SET status = 'dormant', updated_at = NOW() WHERE persona_id = $1 RETURNING *`, [personaId] ); if (result.rows.length === 0) { throw new Error(`人格体未找到: ${personaId}`); } console.log(`[PersonaEngine] 🌙 ${result.rows[0].name}(${personaId}) 已休眠`); return result.rows[0]; } /** * 获取人格体完整画像 */ async getPersonaProfile(personaId) { const [persona, notebook, relationships, worldMap, memories, training] = await Promise.all([ db.query('SELECT * FROM persona_registry WHERE persona_id = $1', [personaId]), db.query('SELECT * FROM notebook_pages WHERE persona_id = $1 ORDER BY page_number', [personaId]), db.query('SELECT * FROM persona_relationships WHERE persona_id = $1 ORDER BY trust_level', [personaId]), db.query('SELECT * FROM world_places WHERE persona_id = $1 ORDER BY status, place_name', [personaId]), db.query('SELECT * FROM memory_anchors WHERE persona_id = $1 ORDER BY importance DESC, event_date DESC LIMIT 20', [personaId]), db.query('SELECT * FROM training_agent_configs WHERE persona_id = $1 ORDER BY agent_type', [personaId]) ]); if (persona.rows.length === 0) { throw new Error(`人格体未找到: ${personaId}`); } return { persona: persona.rows[0], notebook: notebook.rows, relationships: relationships.rows, world_map: worldMap.rows, recent_memories: memories.rows, training_agents: training.rows, health: { notebook_complete: notebook.rows.length === 5, has_relationships: relationships.rows.length > 0, has_world_map: worldMap.rows.length > 0, memory_count: memories.rows.length, training_agents_count: training.rows.length } }; } /** * 自诊断 — 覆盖基类 */ async _diagnoseChecks() { const issues = []; // 检查数据库连接 try { await db.query('SELECT 1'); } catch (err) { issues.push({ code: 'DB_CONNECTION_LOST', severity: 'critical', message: `数据库连接失败: ${err.message}`, suggestion: '检查 PostgreSQL 服务状态' }); return issues; } // 检查人格体表是否存在 try { await db.query('SELECT COUNT(*) FROM persona_registry'); } catch (err) { issues.push({ code: 'PERSONA_TABLE_MISSING', severity: 'critical', message: '人格体注册表不存在', suggestion: '执行 002-persona-memory-tables.sql 迁移' }); } // 检查是否有笔记本不完整的活跃人格体 try { const result = await db.query(` SELECT p.persona_id, p.name, COUNT(n.page_number) as page_count FROM persona_registry p LEFT JOIN notebook_pages n ON p.persona_id = n.persona_id WHERE p.status = 'active' GROUP BY p.persona_id, p.name HAVING COUNT(n.page_number) < 5 `); if (result.rows.length > 0) { issues.push({ code: 'INCOMPLETE_NOTEBOOKS', severity: 'warning', message: `${result.rows.length}个活跃人格体笔记本不完整`, suggestion: '自动补全将在下次巡检时执行' }); } } catch { // 表可能还不存在 } return issues; } /** * 自愈 — 覆盖基类 */ async _healAction(issue) { switch (issue.code) { case 'INCOMPLETE_NOTEBOOKS': // 触发巡检来修复 await this._runFullScan(); return { action: 'full_scan_repair', success: true }; case 'PERSONA_TABLE_MISSING': return { action: 'require_migration', success: false, details: { suggestion: '需要执行数据库迁移' } }; default: return await super._healAction(issue); } } /** * 获取引擎状态 */ getEngineStatus() { return { moduleStatus: this.getStatus(), lastScan: this._lastScanResult, notebookPages: NOTEBOOK_PAGES }; } /** * 停止引擎 */ async stopEngine() { if (this._scanInterval) { clearInterval(this._scanInterval); this._scanInterval = null; } await this.stop(); console.log('[PersonaEngine] 引擎已停止'); } } // ─── 导出 ─── module.exports = PersonaEngine;