guanghulab/server/age-os/agents/living-module.js

657 lines
21 KiB
JavaScript
Raw Permalink Normal View History

/**
*
* 🧬 AGE OS · LivingModule 活模块基类
*
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* "你一定要把模块做成活的。" 冰朔 D59
*
* 每一个活模块必须具备5个生存接口:
* 1. heartbeat() 心跳 · 我还活着
* 2. selfDiagnose() 自诊断 · 我哪里不对
* 3. selfHeal() 自愈 · 我试着修好自己
* 4. alertZhuyuan() 报警 · 铸渊我搞不定了
* 5. learnFromRun() 学习 · 我从每次运行中成长
*
* 子类继承此基类实现具体逻辑
* 基类提供默认的心跳诊断自愈框架
*/
'use strict';
const { v4: uuidv4 } = require('uuid');
// ─── 常量 ───
const DEFAULT_HEARTBEAT_INTERVAL = 30000; // 30秒
const HEALTH_THRESHOLD_DEGRADED = 70;
const HEALTH_THRESHOLD_CRITICAL = 30;
const MAX_HEAL_ATTEMPTS = 3;
const HEAL_COOLDOWN_MS = 60000; // 1分钟冷却
const MEMORY_THRESHOLD_BYTES = 200 * 1024 * 1024; // 200MB
class LivingModule {
/**
* @param {Object} options
* @param {string} options.moduleId - 模块唯一ID ZY-MOD-SCHEDULER
* @param {string} options.name - 模块名称
* @param {string} options.moduleType - core|persona|agent|worker|bridge|guard
* @param {string} options.owner - 归属者
* @param {Object} [options.db] - 数据库连接可选无DB时降级为内存模式
* @param {Object} [options.config] - 额外配置
*/
constructor(options) {
if (!options || !options.moduleId || !options.name) {
throw new Error('LivingModule: moduleId 和 name 为必填项');
}
this.moduleId = options.moduleId;
this.name = options.name;
this.moduleType = options.moduleType || 'agent';
this.owner = options.owner || 'zhuyuan';
this.db = options.db || null;
this.config = options.config || {};
// ─── 运行状态 ───
this.status = 'initializing';
this.healthScore = 100;
this.startedAt = null;
this.lastHeartbeatAt = null;
this.lastDiagnoseAt = null;
this.lastHealAt = null;
this.healAttempts = 0;
this.activeTasks = 0;
// ─── 心跳定时器 ───
this._heartbeatTimer = null;
this._heartbeatInterval = options.config?.heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL;
// ─── 事件监听器 ───
this._listeners = new Map();
// ─── 内存日志无DB降级模式 ───
this._memoryLogs = [];
this._maxMemoryLogs = 100;
}
// ═══════════════════════════════════════════════════════════
// 生命周期
// ═══════════════════════════════════════════════════════════
/**
* 启动模块
*/
async start() {
this.startedAt = new Date();
this.status = 'alive';
this.healthScore = 100;
// 注册到数据库
await this._registerToDB();
// 启动心跳
this._startHeartbeat();
// 执行首次自诊断
await this.selfDiagnose();
this._log('info', `${this.name} 已启动·活模块上线`);
this._emit('started', { moduleId: this.moduleId });
return { moduleId: this.moduleId, status: this.status };
}
/**
* 停止模块
*/
async stop() {
this._stopHeartbeat();
this.status = 'dormant';
await this._updateStatusToDB('dormant');
this._log('info', `${this.name} 已休眠`);
this._emit('stopped', { moduleId: this.moduleId });
}
// ═══════════════════════════════════════════════════════════
// 生存接口 1: heartbeat() — 心跳
// ═══════════════════════════════════════════════════════════
/**
* 心跳 报告当前状态
* 子类可覆盖 _collectMetrics() 提供自定义指标
*/
async heartbeat() {
const now = new Date();
this.lastHeartbeatAt = now;
// 收集运行指标
const metrics = await this._collectMetrics();
const heartbeatData = {
moduleId: this.moduleId,
status: this.status,
healthScore: this.healthScore,
uptime: this.startedAt ? now - this.startedAt : 0,
activeTasks: this.activeTasks,
...metrics
};
// 写入数据库
if (this.db) {
try {
await this.db.query(
`INSERT INTO module_heartbeats (module_id, status, health_score, cpu_usage, memory_usage, uptime_ms, active_tasks, details)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
[
this.moduleId, this.status, this.healthScore,
metrics.cpuUsage || null, metrics.memoryUsage || null,
heartbeatData.uptime, this.activeTasks,
JSON.stringify(metrics.extra || {})
]
);
// 更新模块表
await this.db.query(
`UPDATE living_modules SET last_heartbeat_at = NOW(), health_score = $1, status = $2, updated_at = NOW() WHERE module_id = $3`,
[this.healthScore, this.status, this.moduleId]
);
} catch (err) {
this._log('warn', `心跳写入DB失败: ${err.message}`);
}
}
this._emit('heartbeat', heartbeatData);
return heartbeatData;
}
/**
* 收集运行指标 子类覆盖此方法提供自定义指标
* @returns {Object} { cpuUsage, memoryUsage, extra: {} }
*/
async _collectMetrics() {
const mem = process.memoryUsage();
return {
cpuUsage: null, // 进程级CPU需要外部工具
memoryUsage: Math.round(mem.heapUsed / 1024 / 1024), // MB
extra: {
heapTotal: Math.round(mem.heapTotal / 1024 / 1024),
rss: Math.round(mem.rss / 1024 / 1024)
}
};
}
// ═══════════════════════════════════════════════════════════
// 生存接口 2: selfDiagnose() — 自诊断
// ═══════════════════════════════════════════════════════════
/**
* 自诊断 检查自身状态
* 子类覆盖 _diagnoseChecks() 提供具体检查项
*/
async selfDiagnose() {
const startTime = Date.now();
this.lastDiagnoseAt = new Date();
const issues = [];
// 基础检查
if (!this.startedAt) {
issues.push({
code: 'NOT_STARTED',
severity: 'critical',
message: '模块未启动',
suggestion: '调用 start() 启动模块'
});
}
// 心跳超时检查
if (this.lastHeartbeatAt) {
const sinceLastHeart = Date.now() - this.lastHeartbeatAt.getTime();
if (sinceLastHeart > this._heartbeatInterval * 3) {
issues.push({
code: 'HEARTBEAT_TIMEOUT',
severity: 'warning',
message: `心跳超时 ${Math.round(sinceLastHeart / 1000)}`,
suggestion: '重启心跳定时器'
});
}
}
// 内存检查
const mem = process.memoryUsage();
if (mem.heapUsed > MEMORY_THRESHOLD_BYTES) {
issues.push({
code: 'HIGH_MEMORY',
severity: 'warning',
message: `堆内存使用 ${Math.round(mem.heapUsed / 1024 / 1024)}MB`,
suggestion: '检查内存泄漏'
});
}
// 子类自定义检查
const customIssues = await this._diagnoseChecks();
issues.push(...customIssues);
// 计算健康分数
const newScore = this._calculateHealthScore(issues);
const oldScore = this.healthScore;
this.healthScore = newScore;
// 更新状态
if (newScore <= HEALTH_THRESHOLD_CRITICAL) {
this.status = 'degraded';
} else if (newScore <= HEALTH_THRESHOLD_DEGRADED) {
if (this.status === 'alive') this.status = 'degraded';
} else {
if (this.status === 'degraded') this.status = 'alive';
}
const duration = Date.now() - startTime;
const isHealthy = issues.filter(i => i.severity === 'critical').length === 0;
const result = {
moduleId: this.moduleId,
isHealthy,
issues,
overallScore: newScore,
scoreDelta: newScore - oldScore,
duration
};
// 写入数据库
if (this.db) {
try {
await this.db.query(
`INSERT INTO module_diagnoses (module_id, is_healthy, issues, overall_score, duration_ms)
VALUES ($1, $2, $3, $4, $5)`,
[this.moduleId, isHealthy, JSON.stringify(issues), newScore, duration]
);
} catch (err) {
this._log('warn', `诊断写入DB失败: ${err.message}`);
}
}
// 如果有严重问题,尝试自愈
if (!isHealthy && this.status !== 'healing') {
this._log('warn', `检测到 ${issues.length} 个问题·尝试自愈`);
await this.selfHeal(issues);
}
this._emit('diagnosed', result);
return result;
}
/**
* 自定义诊断检查 子类覆盖此方法
* @returns {Array<{code, severity, message, suggestion}>}
*/
async _diagnoseChecks() {
return [];
}
/**
* 计算健康分数
*/
_calculateHealthScore(issues) {
let score = 100;
for (const issue of issues) {
switch (issue.severity) {
case 'critical': score -= 30; break;
case 'warning': score -= 10; break;
case 'info': score -= 2; break;
}
}
return Math.max(0, Math.min(100, score));
}
// ═══════════════════════════════════════════════════════════
// 生存接口 3: selfHeal() — 自愈
// ═══════════════════════════════════════════════════════════
/**
* 自愈 尝试修复发现的问题
* 子类覆盖 _healAction() 提供具体修复逻辑
*/
async selfHeal(issues) {
// 冷却检查
if (this.lastHealAt && (Date.now() - this.lastHealAt.getTime()) < HEAL_COOLDOWN_MS) {
this._log('info', '自愈冷却中·跳过');
return { success: false, reason: 'cooldown' };
}
// 尝试次数检查
if (this.healAttempts >= MAX_HEAL_ATTEMPTS) {
this._log('warn', `自愈已尝试 ${MAX_HEAL_ATTEMPTS} 次·向铸渊报警`);
await this.alertZhuyuan('self_heal_exhausted', `已尝试自愈 ${MAX_HEAL_ATTEMPTS} 次仍未恢复`, { issues });
return { success: false, reason: 'max_attempts' };
}
this.status = 'healing';
this.lastHealAt = new Date();
this.healAttempts++;
const healthBefore = this.healthScore;
const results = [];
for (const issue of issues) {
if (issue.severity === 'info') continue;
const startTime = Date.now();
try {
const action = await this._healAction(issue);
const duration = Date.now() - startTime;
const result = {
issueCode: issue.code,
action: action.action || 'unknown',
success: action.success,
duration
};
results.push(result);
// 写入数据库
if (this.db) {
await this.db.query(
`INSERT INTO module_healing_logs (module_id, trigger_source, issue_code, action_taken, action_details, success, health_before, health_after, duration_ms, error_message)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,
[
this.moduleId, 'self', issue.code,
action.action || 'unknown', JSON.stringify(action.details || {}),
action.success, healthBefore, this.healthScore,
duration, action.success ? null : (action.error || null)
]
).catch(() => {});
}
} catch (err) {
results.push({
issueCode: issue.code,
action: 'error',
success: false,
error: err.message
});
}
}
// 自愈后重新诊断
const postDiagnose = await this.selfDiagnose();
if (postDiagnose.isHealthy) {
this.healAttempts = 0; // 重置计数
this.status = 'alive';
this._log('info', '自愈成功·恢复正常');
// 学习:记录成功的自愈经验
await this.learnFromRun('healing', '自愈成功', { issues, results });
} else if (this.healAttempts >= MAX_HEAL_ATTEMPTS) {
// 自愈失败·报警
await this.alertZhuyuan('self_heal_failed', '自愈尝试全部失败', {
issues: postDiagnose.issues,
healResults: results,
attempts: this.healAttempts
});
}
this._emit('healed', { success: postDiagnose.isHealthy, results });
return { success: postDiagnose.isHealthy, results };
}
/**
* 具体修复动作 子类覆盖此方法
* @param {Object} issue - { code, severity, message, suggestion }
* @returns {Object} { action, success, details, error }
*/
async _healAction(issue) {
// 基类默认处理
switch (issue.code) {
case 'HEARTBEAT_TIMEOUT':
this._stopHeartbeat();
this._startHeartbeat();
return { action: 'restart_heartbeat', success: true, details: {} };
default:
return { action: 'no_handler', success: false, error: `未定义 ${issue.code} 的修复逻辑` };
}
}
// ═══════════════════════════════════════════════════════════
// 生存接口 4: alertZhuyuan() — 报警
// ═══════════════════════════════════════════════════════════
/**
* 向铸渊报警
* @param {string} alertType - 报警类型
* @param {string} message - 报警内容
* @param {Object} details - 详情
* @param {string} [severity='critical'] - 严重程度
*/
async alertZhuyuan(alertType, message, details = {}, severity = 'critical') {
this._log('alert', `[${severity}] ${alertType}: ${message}`);
if (this.db) {
try {
await this.db.query(
`INSERT INTO module_alerts (module_id, severity, alert_type, message, details)
VALUES ($1, $2, $3, $4, $5)`,
[this.moduleId, severity, alertType, message, JSON.stringify(details)]
);
} catch (err) {
this._log('warn', `报警写入DB失败: ${err.message}`);
}
}
this._emit('alert', {
moduleId: this.moduleId,
severity,
alertType,
message,
details,
timestamp: new Date().toISOString()
});
return { sent: true, alertType, severity };
}
// ═══════════════════════════════════════════════════════════
// 生存接口 5: learnFromRun() — 学习
// ═══════════════════════════════════════════════════════════
/**
* 从运行中学习
* @param {string} source - 学习来源 (execution|diagnosis|healing|alert|feedback)
* @param {string} summary - 学到了什么
* @param {Object} details - 详细内容
*/
async learnFromRun(source, summary, details = {}) {
const lessonType = this._classifyLesson(source, details);
this._log('learn', `[${source}] ${summary}`);
if (this.db) {
try {
await this.db.query(
`INSERT INTO module_learning_logs (module_id, learning_source, lesson_type, lesson_summary, lesson_details)
VALUES ($1, $2, $3, $4, $5)`,
[this.moduleId, source, lessonType, summary, JSON.stringify(details)]
);
} catch (err) {
this._log('warn', `学习写入DB失败: ${err.message}`);
}
}
this._emit('learned', {
moduleId: this.moduleId,
source,
lessonType,
summary,
timestamp: new Date().toISOString()
});
return { learned: true, lessonType, summary };
}
/**
* 分类学习经验 子类可覆盖
*/
_classifyLesson(source, details) {
switch (source) {
case 'execution': return 'performance_insight';
case 'diagnosis': return 'health_pattern';
case 'healing': return 'recovery_strategy';
case 'alert': return 'failure_pattern';
case 'feedback': return 'external_feedback';
default: return 'general';
}
}
// ═══════════════════════════════════════════════════════════
// 内部工具方法
// ═══════════════════════════════════════════════════════════
/**
* 启动心跳定时器
*/
_startHeartbeat() {
if (this._heartbeatTimer) return;
this._heartbeatTimer = setInterval(async () => {
try {
await this.heartbeat();
} catch (err) {
this._log('warn', `心跳异常: ${err.message}`);
}
}, this._heartbeatInterval);
// 防止定时器阻止进程退出
if (this._heartbeatTimer.unref) {
this._heartbeatTimer.unref();
}
}
/**
* 停止心跳定时器
*/
_stopHeartbeat() {
if (this._heartbeatTimer) {
clearInterval(this._heartbeatTimer);
this._heartbeatTimer = null;
}
}
/**
* 注册到数据库
*/
async _registerToDB() {
if (!this.db) return;
try {
await this.db.query(
`INSERT INTO living_modules (module_id, name, description, module_type, owner, status, health_score, config)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
ON CONFLICT (module_id) DO UPDATE SET
status = EXCLUDED.status,
health_score = EXCLUDED.health_score,
updated_at = NOW()`,
[
this.moduleId, this.name, this.config.description || '',
this.moduleType, this.owner, this.status, this.healthScore,
JSON.stringify(this.config)
]
);
} catch (err) {
this._log('warn', `DB注册失败(降级为内存模式): ${err.message}`);
}
}
/**
* 更新状态到数据库
*/
async _updateStatusToDB(status) {
if (!this.db) return;
try {
await this.db.query(
`UPDATE living_modules SET status = $1, health_score = $2, updated_at = NOW() WHERE module_id = $3`,
[status, this.healthScore, this.moduleId]
);
} catch (err) {
this._log('warn', `状态更新DB失败: ${err.message}`);
}
}
/**
* 内部日志
*/
_log(level, message) {
const entry = {
time: new Date().toISOString(),
module: this.moduleId,
level,
message
};
// 控制台输出
const prefix = `[${this.moduleId}]`;
switch (level) {
case 'alert': console.error(`🚨 ${prefix} ${message}`); break;
case 'warn': console.warn(`⚠️ ${prefix} ${message}`); break;
case 'learn': console.log(`📚 ${prefix} ${message}`); break;
default: console.log(`🟢 ${prefix} ${message}`);
}
// 内存日志
this._memoryLogs.push(entry);
if (this._memoryLogs.length > this._maxMemoryLogs) {
this._memoryLogs.shift();
}
}
/**
* 事件监听
*/
on(event, callback) {
if (!this._listeners.has(event)) {
this._listeners.set(event, []);
}
this._listeners.get(event).push(callback);
return this;
}
/**
* 触发事件
*/
_emit(event, data) {
const listeners = this._listeners.get(event) || [];
for (const fn of listeners) {
try {
fn(data);
} catch (err) {
this._log('warn', `事件处理器异常 [${event}]: ${err.message}`);
}
}
}
/**
* 获取模块状态摘要
*/
getStatus() {
return {
moduleId: this.moduleId,
name: this.name,
type: this.moduleType,
owner: this.owner,
status: this.status,
healthScore: this.healthScore,
uptime: this.startedAt ? Date.now() - this.startedAt.getTime() : 0,
activeTasks: this.activeTasks,
lastHeartbeat: this.lastHeartbeatAt?.toISOString() || null,
lastDiagnose: this.lastDiagnoseAt?.toISOString() || null,
healAttempts: this.healAttempts
};
}
}
module.exports = LivingModule;