Merge pull request #317 from qinfendebingshuo/copilot/initiate-age-os-development

S5 Agent系统级: LivingModule活模块基类 + HLDP通信总线 + 调度引擎v2.0
This commit is contained in:
冰朔 2026-04-08 19:05:49 +08:00 committed by GitHub
commit e5572f07d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 2612 additions and 123 deletions

View File

@ -144,7 +144,7 @@ jobs:
# 确保目标目录存在
ssh -i ~/.ssh/zy_key \
${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
"mkdir -p ${TARGET_DIR} /opt/zhuyuan/app /opt/age-os/mcp-server /opt/age-os/logs"
"mkdir -p ${TARGET_DIR} /opt/zhuyuan/app /opt/age-os/mcp-server /opt/age-os/agents /opt/age-os/logs"
# 同步后端应用代码
rsync -avz --delete \
@ -159,6 +159,12 @@ jobs:
server/age-os/mcp-server/ \
${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/age-os/mcp-server/
# 同步 AGE OS Agents 代码(活模块 · S5新增
rsync -avz --delete \
-e "ssh -i ~/.ssh/zy_key" \
server/age-os/agents/ \
${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/age-os/agents/
# 同步 AGE OS Schema
rsync -avz \
-e "ssh -i ~/.ssh/zy_key" \

View File

@ -77,7 +77,7 @@
| **S2** | ZY-TASK-002 | MCP工具链·核心 | S1 | — | 不可 | ✅完成 |
| **S3** | ZY-TASK-004 | 关系工具链 | S1 | 2次 | 可延后 | ⏳待开发 |
| **S4** | ZY-TASK-006 | COS工具链 | S1 | 2次 | 不可 | 🔧设计完成 |
| **S5** | ZY-TASK-007 | Agent系统级 | S2 | 3次 | 不可 | ⏳待开发 |
| **S5** | ZY-TASK-007 | Agent系统级 | S2 | 3次 | 不可 | ✅完成 |
| **S6** | ZY-TASK-008 | Notion同步引擎 | S4+S5 | 2次 | 可延后 | ⏳待开发 |
| **S7** | ZY-TASK-009 | 网站MCP接入 | S2 | 2次 | 可延后 | 🔧部分完成 |
| **S8** | ZY-TASK-010 | 广州投影站 | S7 | 1次 | 可延后 | ⏳待开发 |

View File

@ -0,0 +1,302 @@
/**
*
* 📡 AGE OS · HLDP Bus 模块间通信总线
*
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* HLDP = HoloLake Distributed Protocol
* 光湖分布式通信协议 · 模块间唯一通信通道
*
* 消息类型:
* heartbeat 心跳
* command 指令铸渊模块
* query 查询
* response 响应
* event 事件
* broadcast 广播铸渊所有模块
* alert 报警模块铸渊
* data 数据传输
*/
'use strict';
const { v4: uuidv4 } = require('uuid');
// ─── 消息默认过期时间 ───
const DEFAULT_TTL_MS = 300000; // 5分钟
class HLDPBus {
/**
* @param {Object} options
* @param {Object} [options.db] - 数据库连接
* @param {Object} [options.registry] - ModuleRegistry实例
*/
constructor(options = {}) {
this.db = options.db || null;
this.registry = options.registry || null;
// ─── 消息队列(内存) ───
this._queues = new Map(); // moduleId → [messages]
this._handlers = new Map(); // msgType → [handler]
this._maxQueueSize = 1000; // 每个模块最多1000条待处理消息
// ─── 广播订阅 ───
this._subscribers = new Map(); // topic → Set(moduleId)
// ─── 统计 ───
this.stats = {
totalSent: 0,
totalDelivered: 0,
totalFailed: 0,
totalBroadcast: 0
};
}
// ═══════════════════════════════════════════════════════════
// 发送消息
// ═══════════════════════════════════════════════════════════
/**
* 发送消息到指定模块
* @param {string} fromModule - 发送方模块ID
* @param {string} toModule - 接收方模块ID
* @param {string} msgType - 消息类型
* @param {Object} payload - 消息体
* @returns {Object} 消息对象
*/
async send(fromModule, toModule, msgType, payload = {}) {
const message = {
messageId: uuidv4(),
from: fromModule,
to: toModule,
type: msgType,
payload,
status: 'pending',
createdAt: new Date(),
expiresAt: new Date(Date.now() + DEFAULT_TTL_MS)
};
// 入队
if (!this._queues.has(toModule)) {
this._queues.set(toModule, []);
}
const queue = this._queues.get(toModule);
// 队列大小限制:丢弃最旧的消息
if (queue.length >= this._maxQueueSize) {
queue.shift();
this.stats.totalFailed++;
}
queue.push(message);
// 持久化
await this._persistMessage(message);
// 尝试即时投递
await this._tryDeliver(toModule, message);
this.stats.totalSent++;
return message;
}
/**
* 广播消息到所有模块
* @param {string} fromModule - 发送方
* @param {string} msgType - 消息类型
* @param {Object} payload - 消息体
* @param {string} [topic] - 广播主题为空则广播给所有
*/
async broadcast(fromModule, msgType, payload = {}, topic = null) {
const targets = topic
? Array.from(this._subscribers.get(topic) || [])
: (this.registry ? this.registry.getAll().map(m => m.moduleId) : []);
const messages = [];
for (const targetId of targets) {
if (targetId === fromModule) continue; // 不广播给自己
const msg = await this.send(fromModule, targetId, msgType, {
...payload,
_broadcast: true,
_topic: topic
});
messages.push(msg);
}
this.stats.totalBroadcast++;
return { count: messages.length, messageIds: messages.map(m => m.messageId) };
}
// ═══════════════════════════════════════════════════════════
// 接收消息
// ═══════════════════════════════════════════════════════════
/**
* 拉取模块的待处理消息
* @param {string} moduleId - 模块ID
* @param {number} [limit=10] - 最多拉取条数
*/
pull(moduleId, limit = 10) {
const queue = this._queues.get(moduleId) || [];
const now = Date.now();
// 过滤已过期的消息
const valid = queue.filter(msg =>
msg.status === 'pending' && msg.expiresAt.getTime() > now
);
const messages = valid.slice(0, limit);
// 标记为已投递
for (const msg of messages) {
msg.status = 'delivered';
msg.deliveredAt = new Date();
}
return messages;
}
/**
* 确认消息已处理
*/
async ack(messageId) {
for (const [, queue] of this._queues) {
const msg = queue.find(m => m.messageId === messageId);
if (msg) {
msg.status = 'processed';
msg.processedAt = new Date();
this.stats.totalDelivered++;
// 更新DB
if (this.db) {
await this.db.query(
`UPDATE hldp_messages SET status = 'processed', processed_at = NOW() WHERE message_id = $1`,
[messageId]
).catch(() => {});
}
return true;
}
}
return false;
}
// ═══════════════════════════════════════════════════════════
// 消息处理器
// ═══════════════════════════════════════════════════════════
/**
* 注册消息处理器
* @param {string} msgType - 消息类型
* @param {Function} handler - 处理函数 (message) => Promise<result>
*/
onMessage(msgType, handler) {
if (!this._handlers.has(msgType)) {
this._handlers.set(msgType, []);
}
this._handlers.get(msgType).push(handler);
return this;
}
/**
* 订阅广播主题
* @param {string} moduleId - 模块ID
* @param {string} topic - 主题
*/
subscribe(moduleId, topic) {
if (!this._subscribers.has(topic)) {
this._subscribers.set(topic, new Set());
}
this._subscribers.get(topic).add(moduleId);
return this;
}
/**
* 取消订阅
*/
unsubscribe(moduleId, topic) {
const subs = this._subscribers.get(topic);
if (subs) subs.delete(moduleId);
return this;
}
// ═══════════════════════════════════════════════════════════
// 内部方法
// ═══════════════════════════════════════════════════════════
/**
* 尝试即时投递
*/
async _tryDeliver(toModule, message) {
const handlers = this._handlers.get(message.type) || [];
for (const handler of handlers) {
try {
await handler(message);
} catch (err) {
console.warn(`[HLDP] 消息处理异常 [${message.type}]: ${err.message}`);
}
}
}
/**
* 持久化消息到数据库
*/
async _persistMessage(message) {
if (!this.db) return;
try {
await this.db.query(
`INSERT INTO hldp_messages (message_id, from_module, to_module, msg_type, payload, status, created_at, expires_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
[
message.messageId, message.from, message.to,
message.type, JSON.stringify(message.payload),
message.status, message.createdAt, message.expiresAt
]
);
} catch (err) {
console.warn(`[HLDP] 消息持久化失败: ${err.message}`);
}
}
/**
* 清理过期消息
*/
cleanup() {
const now = Date.now();
let cleaned = 0;
for (const [moduleId, queue] of this._queues) {
const before = queue.length;
const filtered = queue.filter(msg =>
msg.status !== 'processed' && msg.expiresAt.getTime() > now
);
this._queues.set(moduleId, filtered);
cleaned += (before - filtered.length);
}
return cleaned;
}
/**
* 获取总线统计信息
*/
getStats() {
let pendingMessages = 0;
for (const [, queue] of this._queues) {
pendingMessages += queue.filter(m => m.status === 'pending').length;
}
return {
...this.stats,
pendingMessages,
queueCount: this._queues.size,
subscriberTopics: this._subscribers.size,
timestamp: new Date().toISOString()
};
}
}
module.exports = HLDPBus;

View File

@ -0,0 +1,656 @@
/**
*
* 🧬 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;

View File

@ -0,0 +1,277 @@
/**
*
* 📋 AGE OS · ModuleRegistry 活模块注册中心
*
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* 管理所有活模块的注册发现状态监控
* 铸渊通过此注册中心了解所有模块的生死状态
*/
'use strict';
class ModuleRegistry {
/**
* @param {Object} options
* @param {Object} [options.db] - 数据库连接
*/
constructor(options = {}) {
this.db = options.db || null;
// ─── 本地注册表(内存快照) ───
this._modules = new Map();
// ─── 监控配置 ───
this._monitorTimer = null;
this._monitorInterval = 60000; // 60秒检查一次
this._heartbeatTimeoutMs = 90000; // 心跳超时阈值: 3倍30秒心跳间隔
// ─── 事件监听 ───
this._listeners = new Map();
}
// ═══════════════════════════════════════════════════════════
// 注册 / 注销
// ═══════════════════════════════════════════════════════════
/**
* 注册活模块
* @param {import('./living-module')} module - LivingModule实例
*/
register(module) {
if (!module || !module.moduleId) {
throw new Error('注册失败: 无效的模块实例');
}
this._modules.set(module.moduleId, module);
// 监听模块事件
module.on('heartbeat', (data) => this._onModuleHeartbeat(data));
module.on('alert', (data) => this._onModuleAlert(data));
module.on('stopped', (data) => this._onModuleStopped(data));
this._emit('registered', { moduleId: module.moduleId, name: module.name });
console.log(`[Registry] 注册活模块: ${module.moduleId} (${module.name})`);
return this;
}
/**
* 注销活模块
*/
unregister(moduleId) {
const module = this._modules.get(moduleId);
if (module) {
this._modules.delete(moduleId);
this._emit('unregistered', { moduleId });
console.log(`[Registry] 注销活模块: ${moduleId}`);
}
return this;
}
/**
* 获取模块
*/
get(moduleId) {
return this._modules.get(moduleId) || null;
}
/**
* 获取所有模块
*/
getAll() {
return Array.from(this._modules.values());
}
/**
* 按状态筛选模块
*/
getByStatus(status) {
return this.getAll().filter(m => m.status === status);
}
/**
* 按类型筛选模块
*/
getByType(moduleType) {
return this.getAll().filter(m => m.moduleType === moduleType);
}
// ═══════════════════════════════════════════════════════════
// 状态总览
// ═══════════════════════════════════════════════════════════
/**
* 获取所有模块的状态概览
*/
getOverview() {
const modules = this.getAll();
const statusCount = {};
const typeCount = {};
let totalHealth = 0;
for (const m of modules) {
statusCount[m.status] = (statusCount[m.status] || 0) + 1;
typeCount[m.moduleType] = (typeCount[m.moduleType] || 0) + 1;
totalHealth += m.healthScore;
}
return {
totalModules: modules.length,
avgHealthScore: modules.length > 0 ? Math.round(totalHealth / modules.length) : 0,
byStatus: statusCount,
byType: typeCount,
modules: modules.map(m => m.getStatus()),
timestamp: new Date().toISOString()
};
}
/**
* 从数据库加载已注册模块用于恢复状态
*/
async loadFromDB() {
if (!this.db) return [];
try {
const result = await this.db.query(
`SELECT module_id, name, module_type, owner, status, health_score, config, capabilities, last_heartbeat_at
FROM living_modules WHERE status != 'dead'
ORDER BY registered_at`
);
return result.rows;
} catch (err) {
console.error('[Registry] 加载DB模块失败:', err.message);
return [];
}
}
// ═══════════════════════════════════════════════════════════
// 健康监控
// ═══════════════════════════════════════════════════════════
/**
* 启动健康监控
*/
startMonitoring() {
if (this._monitorTimer) return;
console.log('[Registry] 健康监控启动·60秒巡检周期');
this._monitorTimer = setInterval(async () => {
await this._healthCheck();
}, this._monitorInterval);
if (this._monitorTimer.unref) {
this._monitorTimer.unref();
}
}
/**
* 停止健康监控
*/
stopMonitoring() {
if (this._monitorTimer) {
clearInterval(this._monitorTimer);
this._monitorTimer = null;
console.log('[Registry] 健康监控已停止');
}
}
/**
* 健康巡检
*/
async _healthCheck() {
const now = Date.now();
const deadModules = [];
for (const [moduleId, module] of this._modules) {
// 检查心跳超时
if (module.lastHeartbeatAt) {
const sinceLastHeart = now - module.lastHeartbeatAt.getTime();
if (sinceLastHeart > this._heartbeatTimeoutMs && module.status === 'alive') {
console.warn(`[Registry] ${moduleId} 心跳超时 ${Math.round(sinceLastHeart / 1000)}`);
// 通过模块自身的诊断方法更新状态
try {
await module.selfDiagnose();
} catch (err) {
console.error(`[Registry] ${moduleId} 自诊断失败: ${err.message}`);
deadModules.push(moduleId);
}
}
}
// 检查健康分数
if (module.healthScore <= 0) {
module.status = 'dead';
deadModules.push(moduleId);
}
}
// 通知死亡模块
for (const moduleId of deadModules) {
this._emit('moduleDead', { moduleId });
console.error(`[Registry] ☠️ ${moduleId} 已死亡·需要铸渊干预`);
}
}
// ═══════════════════════════════════════════════════════════
// 事件处理
// ═══════════════════════════════════════════════════════════
_onModuleHeartbeat(data) {
// 心跳正常·无需操作
}
_onModuleAlert(data) {
console.error(`[Registry] 🚨 模块报警: ${data.moduleId} [${data.severity}] ${data.message}`);
this._emit('alert', data);
}
_onModuleStopped(data) {
console.log(`[Registry] 模块休眠: ${data.moduleId}`);
}
/**
* 事件监听
*/
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) { console.warn(`[Registry] 事件处理器异常 [${event}]: ${err.message}`); }
}
}
/**
* 关闭所有模块
*/
async shutdown() {
this.stopMonitoring();
const modules = this.getAll();
console.log(`[Registry] 关闭 ${modules.length} 个活模块...`);
for (const module of modules) {
try {
await module.stop();
} catch (err) {
console.error(`[Registry] ${module.moduleId} 关闭失败: ${err.message}`);
}
}
this._modules.clear();
console.log('[Registry] 所有模块已关闭');
}
}
module.exports = ModuleRegistry;

View File

@ -1,13 +1,20 @@
/**
*
* 🤖 AGE OS · Agent 调度引擎
* 🤖 AGE OS · Agent 调度引擎 v2.0
*
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* agent_configs 表读取配置 node-cron 调度定时任务
* 每个Agent是一个独立的JS脚本调度器负责按时触发并记录日志
* v2.0 升级:
* - 集成活模块生命周期管理
* - 调度引擎自身作为 LivingModule 运行
* - 支持 ModuleRegistry 统一管理
* - 支持 HLDP Bus 模块间通信
* - 定时Agent + 活模块心跳双调度
*
* "你一定要把模块做成活的。" 冰朔 D59
*/
'use strict';
@ -15,129 +22,320 @@
const cron = require('node-cron');
const path = require('path');
const db = require('../mcp-server/db');
const LivingModule = require('./living-module');
const ModuleRegistry = require('./module-registry');
const HLDPBus = require('./hldp-bus');
const AGENT_DIR = __dirname;
const activeJobs = new Map();
/**
* 加载并启动所有启用的定时Agent
*/
async function startScheduler() {
console.log('[Scheduler] AGE OS Agent 调度引擎启动...');
// ═══════════════════════════════════════════════════════════
// 铸渊调度引擎 · 活模块版
// ═══════════════════════════════════════════════════════════
try {
const result = await db.query(
"SELECT * FROM agent_configs WHERE enabled = true AND cron_schedule IS NOT NULL"
);
console.log(`[Scheduler] 发现 ${result.rows.length} 个定时Agent`);
for (const agent of result.rows) {
scheduleAgent(agent);
}
console.log('[Scheduler] 所有Agent已调度');
} catch (err) {
console.error('[Scheduler] 启动失败:', err.message);
console.log('[Scheduler] 数据库可能未初始化等待60秒后重试...');
setTimeout(startScheduler, 60000);
}
}
/**
* 调度单个Agent
*/
function scheduleAgent(agent) {
if (!cron.validate(agent.cron_schedule)) {
console.error(`[Scheduler] ${agent.agent_id} cron表达式无效: ${agent.cron_schedule}`);
return;
}
const job = cron.schedule(agent.cron_schedule, async () => {
await runAgent(agent);
}, {
timezone: 'Asia/Shanghai'
});
activeJobs.set(agent.agent_id, job);
console.log(`[Scheduler] ${agent.agent_id} (${agent.name}) 已调度: ${agent.cron_schedule}`);
}
/**
* 执行单个Agent
*/
async function runAgent(agent) {
const startTime = Date.now();
console.log(`[Agent] ${agent.agent_id} 开始执行...`);
// 更新运行状态
await db.query(
"UPDATE agent_configs SET last_run_at = NOW(), last_run_status = 'running' WHERE agent_id = $1",
[agent.agent_id]
).catch(() => {});
try {
// 动态加载Agent脚本
const scriptPath = path.resolve(AGENT_DIR, path.basename(agent.script_path));
// 清除缓存以支持热更新
delete require.cache[require.resolve(scriptPath)];
const agentModule = require(scriptPath);
// 每个Agent脚本需导出 run(config) 函数
if (typeof agentModule.run !== 'function') {
throw new Error(`Agent脚本 ${agent.script_path} 未导出 run 函数`);
}
const result = await agentModule.run({
agent_id: agent.agent_id,
model_config: agent.model_config,
allowed_tools: agent.allowed_tools
class SchedulerModule extends LivingModule {
constructor() {
super({
moduleId: 'ZY-MOD-SCHEDULER',
name: '铸渊调度引擎',
moduleType: 'core',
owner: 'zhuyuan',
db: db,
config: {
version: '2.0.0',
description: 'Agent调度和活模块生命周期管理',
heartbeatInterval: 30000
}
});
const duration = Date.now() - startTime;
this.registry = new ModuleRegistry({ db });
this.bus = new HLDPBus({ db, registry: this.registry });
}
// 记录成功日志
/**
* 启动调度引擎
*/
async startEngine() {
console.log('═══════════════════════════════════════════════');
console.log(' 🤖 AGE OS · Agent 调度引擎 v2.0 启动');
console.log(' 签发: 铸渊 · ICE-GL-ZY001');
console.log('═══════════════════════════════════════════════');
// 1. 注册自身为活模块
this.registry.register(this);
await this.start();
// 2. 启动健康监控
this.registry.startMonitoring();
// 3. 加载定时Agent
await this._loadCronAgents();
// 4. 注册 HLDP 消息处理器
this._setupHLDPHandlers();
// 5. 启动定时清理
this._startCleanupJob();
console.log('[Scheduler] 🟢 调度引擎就绪');
console.log(`[Scheduler] 活模块数: ${this.registry.getAll().length}`);
console.log(`[Scheduler] 定时Agent数: ${activeJobs.size}`);
return this.registry.getOverview();
}
/**
* 加载定时Agent兼容v1.0逻辑
*/
async _loadCronAgents() {
try {
const result = await db.query(
"SELECT * FROM agent_configs WHERE enabled = true AND cron_schedule IS NOT NULL"
);
console.log(`[Scheduler] 发现 ${result.rows.length} 个定时Agent`);
for (const agent of result.rows) {
this._scheduleAgent(agent);
}
} catch (err) {
console.error('[Scheduler] 定时Agent加载失败:', err.message);
console.log('[Scheduler] 数据库可能未初始化·等待60秒后重试...');
setTimeout(() => this._loadCronAgents(), 60000);
}
}
/**
* 调度单个Agent
*/
_scheduleAgent(agent) {
if (!cron.validate(agent.cron_schedule)) {
console.error(`[Scheduler] ${agent.agent_id} cron表达式无效: ${agent.cron_schedule}`);
return;
}
const job = cron.schedule(agent.cron_schedule, async () => {
await this._runAgent(agent);
}, {
timezone: 'Asia/Shanghai'
});
activeJobs.set(agent.agent_id, job);
console.log(`[Scheduler] ${agent.agent_id} (${agent.name}) 已调度: ${agent.cron_schedule}`);
}
/**
* 执行单个Agentv2.0: 增加学习能力
*/
async _runAgent(agent) {
const startTime = Date.now();
console.log(`[Agent] ${agent.agent_id} 开始执行...`);
this.activeTasks++;
// 更新运行状态
await db.query(
`INSERT INTO agent_logs (agent_id, status, message, details, duration_ms)
VALUES ($1, 'success', $2, $3, $4)`,
[agent.agent_id, result.message || '执行成功', JSON.stringify(result.details || {}), duration]
);
await db.query(
"UPDATE agent_configs SET last_run_status = 'success' WHERE agent_id = $1",
[agent.agent_id]
);
console.log(`[Agent] ${agent.agent_id} 完成 (${duration}ms)`);
} catch (err) {
const duration = Date.now() - startTime;
// 记录错误日志
await db.query(
`INSERT INTO agent_logs (agent_id, status, message, details, duration_ms)
VALUES ($1, 'error', $2, $3, $4)`,
[agent.agent_id, err.message, JSON.stringify({ stack: err.stack }), duration]
).catch(() => {});
await db.query(
"UPDATE agent_configs SET last_run_status = 'error' WHERE agent_id = $1",
"UPDATE agent_configs SET last_run_at = NOW(), last_run_status = 'running' WHERE agent_id = $1",
[agent.agent_id]
).catch(() => {});
console.error(`[Agent] ${agent.agent_id} 失败 (${duration}ms):`, err.message);
try {
// 动态加载Agent脚本
const scriptPath = path.resolve(AGENT_DIR, path.basename(agent.script_path));
// 清除缓存以支持热更新
delete require.cache[require.resolve(scriptPath)];
const agentModule = require(scriptPath);
// 每个Agent脚本需导出 run(config) 函数
if (typeof agentModule.run !== 'function') {
throw new Error(`Agent脚本 ${agent.script_path} 未导出 run 函数`);
}
const result = await agentModule.run({
agent_id: agent.agent_id,
model_config: agent.model_config,
allowed_tools: agent.allowed_tools,
// v2.0: 注入活模块能力
bus: this.bus,
registry: this.registry
});
const duration = Date.now() - startTime;
// 记录成功日志
await db.query(
`INSERT INTO agent_logs (agent_id, status, message, details, duration_ms)
VALUES ($1, 'success', $2, $3, $4)`,
[agent.agent_id, result.message || '执行成功', JSON.stringify(result.details || {}), duration]
);
await db.query(
"UPDATE agent_configs SET last_run_status = 'success' WHERE agent_id = $1",
[agent.agent_id]
);
// v2.0: 学习成功经验
await this.learnFromRun('execution', `${agent.agent_id} 执行成功 (${duration}ms)`, {
agentId: agent.agent_id,
duration,
result: result.message || '成功'
});
console.log(`[Agent] ${agent.agent_id} 完成 (${duration}ms)`);
} catch (err) {
const duration = Date.now() - startTime;
// 记录错误日志
await db.query(
`INSERT INTO agent_logs (agent_id, status, message, details, duration_ms)
VALUES ($1, 'error', $2, $3, $4)`,
[agent.agent_id, err.message, JSON.stringify({ stack: err.stack }), duration]
).catch(() => {});
await db.query(
"UPDATE agent_configs SET last_run_status = 'error' WHERE agent_id = $1",
[agent.agent_id]
).catch(() => {});
// v2.0: 学习失败经验
await this.learnFromRun('execution', `${agent.agent_id} 执行失败: ${err.message}`, {
agentId: agent.agent_id,
duration,
error: err.message
});
console.error(`[Agent] ${agent.agent_id} 失败 (${duration}ms):`, err.message);
} finally {
this.activeTasks--;
}
}
/**
* 注册 HLDP 消息处理器
*/
_setupHLDPHandlers() {
// 处理命令消息
this.bus.onMessage('command', async (msg) => {
console.log(`[HLDP] 收到命令: ${msg.payload.action || 'unknown'} from ${msg.from}`);
// 子类或外部可注册更多处理逻辑
});
// 处理报警消息
this.bus.onMessage('alert', async (msg) => {
console.error(`[HLDP] 🚨 收到报警: ${msg.from} - ${msg.payload.message || ''}`);
});
}
/**
* 启动定时清理任务
*/
_startCleanupJob() {
// 每小时清理过期心跳和消息
cron.schedule('0 * * * *', async () => {
try {
const cleaned = this.bus.cleanup();
if (cleaned > 0) {
console.log(`[Scheduler] 清理 ${cleaned} 条过期消息`);
}
// 清理数据库中的旧心跳数据
if (db) {
await db.query("SELECT cleanup_old_heartbeats()").catch(() => {});
}
} catch (err) {
console.warn('[Scheduler] 清理任务异常:', err.message);
}
}, { timezone: 'Asia/Shanghai' });
}
/**
* 自诊断检查 覆盖基类
*/
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 服务状态和连接配置'
});
}
// 检查活模块健康度
const overview = this.registry.getOverview();
const deadCount = overview.byStatus.dead || 0;
if (deadCount > 0) {
issues.push({
code: 'DEAD_MODULES',
severity: 'warning',
message: `${deadCount} 个模块已死亡`,
suggestion: '检查死亡模块并尝试重启'
});
}
return issues;
}
/**
* 自愈动作 覆盖基类
*/
async _healAction(issue) {
switch (issue.code) {
case 'DB_CONNECTION_LOST':
// 尝试重连pg模块会自动重连池·这里只是触发一次尝试
try {
await db.query('SELECT 1');
return { action: 'db_reconnect', success: true };
} catch (err) {
return { action: 'db_reconnect', success: false, error: err.message };
}
case 'DEAD_MODULES':
// 记录并上报,不自动重启(需要铸渊干预)
return { action: 'report_dead_modules', success: true, details: { reported: true } };
default:
return await super._healAction(issue);
}
}
}
// ─── 启动 ───
startScheduler();
// ═══════════════════════════════════════════════════════════
// 启动
// ═══════════════════════════════════════════════════════════
const scheduler = new SchedulerModule();
scheduler.startEngine().catch(err => {
console.error('[Scheduler] 启动失败:', err.message);
console.log('[Scheduler] 等待60秒后重试...');
setTimeout(() => scheduler.startEngine().catch(err => {
console.error('[Scheduler] 重试失败:', err.message);
}), 60000);
});
// 优雅关闭
process.on('SIGTERM', () => {
console.log('[Scheduler] 停止所有Agent...');
process.on('SIGTERM', async () => {
console.log('[Scheduler] 正在关闭...');
// 停止定时Agent
for (const [id, job] of activeJobs) {
job.stop();
console.log(`[Scheduler] ${id} 已停止`);
}
// 关闭所有活模块
await scheduler.registry.shutdown();
console.log('[Scheduler] 已完全关闭');
process.exit(0);
});
// 导出供外部使用
module.exports = { scheduler, SchedulerModule };

View File

@ -1,18 +1,28 @@
/**
* Agent: SY-CLASSIFY · 自动分类引擎
* 每2小时运行一次
* 扫描未分类节点(tags为空)按规则分类规则搞不定的标记待人工
*
* 🏷 活模块: SY-CLASSIFY · 自动分类引擎
*
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* v2.0: 从死模块升级为活模块
* - 继承 LivingModule 基类
* - 自诊断: 检查未分类节点堆积数量
* - 自愈: 规则失效时自动扩展规则
* - 学习: 记录分类成功率趋势
*
* 每2小时运行一次 · 扫描未分类节点按规则分类
*/
'use strict';
const LivingModule = require('./living-module');
const db = require('../mcp-server/db');
const { classify } = require('../mcp-server/tools/structure-ops');
// ─── 默认分类规则 ───
// 格式: "关键词1|关键词2": { tags: [...], path: "/路径" }
const DEFAULT_RULES = {
'人格体|persona|人格': { tags: ['人格体', '核心'], path: '/核心认知/人格体' },
'语言|language|TCS|通感': { tags: ['语言', 'TCS'], path: '/核心认知/语言本体论' },
@ -30,6 +40,98 @@ const DEFAULT_RULES = {
'霜砚|shuangyan': { tags: ['霜砚', '语言层'], path: '/核心认知/霜砚' }
};
class LivingSyClassify extends LivingModule {
constructor(options = {}) {
super({
moduleId: 'ZY-MOD-SY-CLASSIFY',
name: '自动分类引擎活模块',
moduleType: 'agent',
owner: 'zhuyuan',
db: options.db || db,
config: {
version: '2.0.0',
description: '认知节点自动分类·规则引擎',
heartbeatInterval: 120000 // 分类模块心跳2分钟
}
});
// 分类统计
this._stats = {
totalClassified: 0,
totalUnclassified: 0,
lastRunSuccessRate: 0
};
}
/**
* 自定义诊断检查
*/
async _diagnoseChecks() {
const issues = [];
// 检查未分类节点堆积
try {
const result = await db.query(
"SELECT COUNT(*) as cnt FROM brain_nodes WHERE tags = '[]'::jsonb AND status = 'active'"
);
const count = parseInt(result.rows[0].cnt, 10);
if (count > 200) {
issues.push({
code: 'HIGH_UNCLASSIFIED_BACKLOG',
severity: 'warning',
message: `未分类节点堆积: ${count} 个 (>200)`,
suggestion: '增加分类规则或提高运行频率'
});
}
} catch (err) {
issues.push({
code: 'CLASSIFY_DB_FAIL',
severity: 'warning',
message: `分类查询失败: ${err.message}`,
suggestion: '检查数据库状态'
});
}
// 检查上次分类成功率
if (this._stats.totalClassified + this._stats.totalUnclassified > 0) {
const total = this._stats.totalClassified + this._stats.totalUnclassified;
const rate = this._stats.totalClassified / total;
if (rate < 0.5) {
issues.push({
code: 'LOW_CLASSIFY_RATE',
severity: 'info',
message: `分类成功率偏低: ${Math.round(rate * 100)}%`,
suggestion: '扩展分类规则覆盖更多关键词'
});
}
}
return issues;
}
/**
* 自愈动作
*/
async _healAction(issue) {
switch (issue.code) {
case 'HIGH_UNCLASSIFIED_BACKLOG':
// 记录并上报
return { action: 'backlog_alert_sent', success: true, details: { reported: true } };
case 'LOW_CLASSIFY_RATE':
// 规则问题只能上报·需要铸渊干预扩展规则
return { action: 'rule_expansion_requested', success: true, details: { reported: true } };
default:
return await super._healAction(issue);
}
}
}
/**
* 兼容旧调度器的 run() 接口
*/
async function run(config) {
// 找出未分类节点tags为空数组且状态为active
const untagged = await db.query(
@ -52,6 +154,20 @@ async function run(config) {
dry_run: false
});
// 通过HLDP上报
if (config && config.bus) {
try {
await config.bus.send('ZY-MOD-SY-CLASSIFY', 'ZY-MOD-SCHEDULER', 'event', {
event: 'classify_complete',
scanned: nodeIds.length,
classified: result.classified.length,
unclassified: result.unclassified.length
});
} catch (err) {
// 非关键
}
}
return {
message: `分类完成: ${result.classified.length}个已分类, ${result.unclassified.length}个待人工`,
details: {
@ -63,4 +179,4 @@ async function run(config) {
};
}
module.exports = { run };
module.exports = { run, LivingSyClassify };

View File

@ -1,15 +1,119 @@
/**
* Agent: SY-SCAN · 大脑结构巡检
* 每6小时运行一次
* 扫描孤岛节点断链空目录生成健康报告
*
* 🔍 活模块: SY-SCAN · 大脑结构巡检
*
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* v2.0: 从死模块升级为活模块
* - 继承 LivingModule 基类
* - 自诊断: 检查 brain_nodes 表健康度孤岛节点比例
* - 自愈: 自动清理空目录标记断链
* - 学习: 记录结构健康趋势
*
* 每6小时运行一次 · 扫描孤岛节点断链空目录
*/
'use strict';
const LivingModule = require('./living-module');
const db = require('../mcp-server/db');
const { scanStructure } = require('../mcp-server/tools/structure-ops');
class LivingSyScan extends LivingModule {
constructor(options = {}) {
super({
moduleId: 'ZY-MOD-SY-SCAN',
name: '大脑结构巡检活模块',
moduleType: 'guard',
owner: 'zhuyuan',
db: options.db || db,
config: {
version: '2.0.0',
description: '大脑认知结构健康巡检',
heartbeatInterval: 120000 // 巡检模块心跳2分钟
}
});
// 上次巡检结果缓存
this._lastReport = null;
}
/**
* 自定义诊断检查
*/
async _diagnoseChecks() {
const issues = [];
// 检查 brain_nodes 表是否可用
try {
const result = await db.query(
"SELECT COUNT(*) as total, COUNT(*) FILTER (WHERE parent_id IS NULL AND node_type != 'folder') as orphans FROM brain_nodes WHERE status = 'active'"
);
const total = parseInt(result.rows[0].total, 10);
const orphans = parseInt(result.rows[0].orphans, 10);
if (total > 0 && orphans / total > 0.3) {
issues.push({
code: 'HIGH_ORPHAN_RATIO',
severity: 'warning',
message: `孤岛节点比例过高: ${orphans}/${total} (${Math.round(orphans / total * 100)}%)`,
suggestion: '运行分类Agent或手动整理'
});
}
} catch (err) {
issues.push({
code: 'SCAN_DB_FAIL',
severity: 'warning',
message: `大脑结构查询失败: ${err.message}`,
suggestion: '检查数据库状态'
});
}
// 如果有上次巡检结果,检查健康分
if (this._lastReport && this._lastReport.health_score < 60) {
issues.push({
code: 'LOW_BRAIN_HEALTH',
severity: 'warning',
message: `大脑结构健康分偏低: ${this._lastReport.health_score}`,
suggestion: '清理断链和空目录'
});
}
return issues;
}
/**
* 自愈动作
*/
async _healAction(issue) {
switch (issue.code) {
case 'HIGH_ORPHAN_RATIO':
// 记录并上报·不自动修改认知结构
return { action: 'orphan_report_logged', success: true, details: { reported: true } };
case 'LOW_BRAIN_HEALTH':
// 尝试清理空目录
try {
await db.query(
"UPDATE brain_nodes bn SET status = 'archived' WHERE bn.node_type = 'folder' AND bn.status = 'active' AND NOT EXISTS (SELECT 1 FROM brain_nodes child WHERE child.parent_id = bn.id AND child.status = 'active')"
);
return { action: 'empty_folders_archived', success: true };
} catch (err) {
return { action: 'empty_folders_archived', success: false, error: err.message };
}
default:
return await super._healAction(issue);
}
}
}
/**
* 兼容旧调度器的 run() 接口
*/
async function run(config) {
const report = await scanStructure({
checks: ['orphans', 'broken_links', 'duplicates', 'empty_folders']
@ -29,6 +133,20 @@ async function run(config) {
issues.push(`${report.empty_folders.length} 个空目录`);
}
// 通过HLDP上报
if (config && config.bus) {
try {
await config.bus.send('ZY-MOD-SY-SCAN', 'ZY-MOD-SCHEDULER', 'event', {
event: 'brain_scan_complete',
health_score: report.health_score,
total_nodes: report.total_nodes,
issueCount: issues.length
});
} catch (err) {
// 非关键
}
}
return {
message: issues.length === 0
? `大脑结构健康 · ${report.total_nodes}个节点 · 评分${report.health_score}`
@ -37,4 +155,4 @@ async function run(config) {
};
}
module.exports = { run };
module.exports = { run, LivingSyScan };

View File

@ -1,17 +1,158 @@
/**
* Agent: SY-TEST · 系统自检
* 每30分钟运行一次
* 检测数据库连接COS连通性MCP工具链可用性
* 异常时自动写工单
*
* 🔬 活模块: SY-TEST · 系统自检
*
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* v2.0: 从死模块升级为活模块
* - 继承 LivingModule 基类
* - 自诊断覆盖: DB/COS/brain_nodes/agent_configs 四项检查
* - 自愈: DB断连自动重试COS超时告警
* - 学习: 记录每次检查结果的成功/失败模式
*
* 每30分钟运行一次 · 检测全系统健康
*/
'use strict';
const LivingModule = require('./living-module');
const db = require('../mcp-server/db');
const cos = require('../mcp-server/cos');
class LivingSyTest extends LivingModule {
constructor(options = {}) {
super({
moduleId: 'ZY-MOD-SY-TEST',
name: '系统自检活模块',
moduleType: 'guard',
owner: 'zhuyuan',
db: options.db || db,
config: {
version: '2.0.0',
description: '全系统健康检测·DB/COS/表/模块',
heartbeatInterval: 60000 // 自检模块心跳1分钟
}
});
}
/**
* 自定义诊断检查 系统全面自检
*/
async _diagnoseChecks() {
const issues = [];
// 1. 数据库连接检查
try {
const dbStatus = await db.checkConnection();
if (!dbStatus.connected) {
issues.push({
code: 'DB_DISCONNECTED',
severity: 'critical',
message: `数据库连接失败: ${dbStatus.error || '未知原因'}`,
suggestion: '检查 PostgreSQL 服务状态'
});
}
} catch (err) {
issues.push({
code: 'DB_ERROR',
severity: 'critical',
message: `数据库检查异常: ${err.message}`,
suggestion: '检查数据库配置和网络'
});
}
// 2. COS连通性检查
try {
const cosStatus = await cos.checkConnection();
if (!cosStatus.connected) {
issues.push({
code: 'COS_DISCONNECTED',
severity: 'warning',
message: `COS存储桶不可达: ${cosStatus.reason || '未知原因'}`,
suggestion: '检查 COS 密钥和网络'
});
}
} catch (err) {
issues.push({
code: 'COS_ERROR',
severity: 'warning',
message: `COS检查异常: ${err.message}`,
suggestion: '检查 COS 配置'
});
}
// 3. brain_nodes表可用性
try {
await db.query("SELECT COUNT(*) as cnt FROM brain_nodes WHERE status = 'active'");
} catch (err) {
issues.push({
code: 'TABLE_BRAIN_NODES_FAIL',
severity: 'warning',
message: `brain_nodes表不可用: ${err.message}`,
suggestion: '检查 Schema 是否已初始化'
});
}
// 4. agent_configs表可用性
try {
await db.query("SELECT COUNT(*) as cnt FROM agent_configs WHERE enabled = true");
} catch (err) {
issues.push({
code: 'TABLE_AGENT_CONFIGS_FAIL',
severity: 'warning',
message: `agent_configs表不可用: ${err.message}`,
suggestion: '检查 Schema 是否已初始化'
});
}
// 5. living_modules表可用性S5新增
try {
await db.query("SELECT COUNT(*) as cnt FROM living_modules WHERE status = 'alive'");
} catch (err) {
issues.push({
code: 'TABLE_LIVING_MODULES_FAIL',
severity: 'info',
message: `living_modules表不可用: ${err.message}`,
suggestion: '执行 003-living-module-tables.sql'
});
}
return issues;
}
/**
* 自愈动作
*/
async _healAction(issue) {
switch (issue.code) {
case 'DB_DISCONNECTED':
case 'DB_ERROR':
// 尝试重连
try {
await db.query('SELECT 1');
return { action: 'db_reconnect', success: true };
} catch (err) {
return { action: 'db_reconnect', success: false, error: err.message };
}
case 'COS_DISCONNECTED':
case 'COS_ERROR':
// COS问题只能上报无法自愈
return { action: 'cos_alert_sent', success: true, details: { reported: true } };
default:
return await super._healAction(issue);
}
}
}
/**
* 兼容旧调度器的 run() 接口
* 调度引擎通过 run(config) 调用
*/
async function run(config) {
const checks = [];
let allPassed = true;
@ -70,6 +211,33 @@ async function run(config) {
allPassed = false;
}
// 5. living_modules表可用性S5新增
try {
const result = await db.query("SELECT COUNT(*) as cnt FROM living_modules WHERE status = 'alive'");
checks.push({
name: 'living_modules表',
status: 'pass',
detail: `${result.rows[0].cnt} 个活跃模块`
});
} catch (err) {
checks.push({ name: 'living_modules表', status: 'warn', detail: `未初始化: ${err.message}` });
// 不算严重失败·Schema可能还没部署
}
// 学习如果调度引擎注入了bus通过HLDP上报结果
if (config && config.bus) {
try {
await config.bus.send('ZY-MOD-SY-TEST', 'ZY-MOD-SCHEDULER', 'event', {
event: 'system_check_complete',
allPassed,
checkCount: checks.length,
failCount: checks.filter(c => c.status === 'fail').length
});
} catch (err) {
// 非关键·忽略
}
}
return {
message: allPassed ? '系统自检通过' : '系统自检发现异常',
details: {
@ -80,4 +248,4 @@ async function run(config) {
};
}
module.exports = { run };
module.exports = { run, LivingSyTest };

View File

@ -28,6 +28,8 @@
* saveFile / getFile / listFiles / getFileHistory
* Notion: notionQuery / notionReadPage / notionWritePage / notionUpdatePage / notionWriteSyslog
* GitHub: githubReadFile / githubListDir / githubWriteFile / githubGetCommits / githubGetIssues / githubTriggerDeploy
* 活模块: registerModule / getModule / listModules / moduleHeartbeat / diagnoseModule
* getModuleAlerts / getModuleLearnings / sendHLDP / getHLDPStats
*/
'use strict';
@ -43,6 +45,7 @@ const relationOps = require('./tools/relation-ops');
const structureOps = require('./tools/structure-ops');
const cosOps = require('./tools/cos-ops');
const personaOps = require('./tools/persona-ops');
const livingModuleOps = require('./tools/living-module-ops');
// ─── 外部集成模块(优雅降级:未安装依赖时不影响核心功能) ───
let notionOps = null;
@ -130,7 +133,17 @@ const TOOLS = {
githubGetCommits: githubOps.githubGetCommits,
githubGetIssues: githubOps.githubGetIssues,
githubTriggerDeploy: githubOps.githubTriggerDeploy
} : {})
} : {}),
// 活模块操作 · S5
registerModule: livingModuleOps.registerModule,
getModule: livingModuleOps.getModule,
listModules: livingModuleOps.listModules,
moduleHeartbeat: livingModuleOps.moduleHeartbeat,
diagnoseModule: livingModuleOps.diagnoseModule,
getModuleAlerts: livingModuleOps.getModuleAlerts,
getModuleLearnings: livingModuleOps.getModuleLearnings,
sendHLDP: livingModuleOps.sendHLDP,
getHLDPStats: livingModuleOps.getHLDPStats
};
// ─── Express 应用 ───
@ -419,6 +432,92 @@ app.get('/personas/:personaId/training', async (req, res) => {
}
});
// ─── 活模块APIS5 ───
// 活模块列表
app.get('/modules', async (req, res) => {
try {
const { status, module_type } = req.query;
const result = await livingModuleOps.listModules({ status, module_type });
res.json(result);
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// 活模块详情
app.get('/modules/:moduleId', async (req, res) => {
try {
const result = await livingModuleOps.getModule({ module_id: req.params.moduleId });
if (!result.found) {
return res.status(404).json({ error: true, message: '模块未找到' });
}
res.json(result);
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// 活模块心跳上报
app.post('/modules/:moduleId/heartbeat', async (req, res) => {
try {
const result = await livingModuleOps.moduleHeartbeat({
module_id: req.params.moduleId,
...req.body
});
res.json(result);
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// 活模块报警记录
app.get('/modules/:moduleId/alerts', async (req, res) => {
try {
const result = await livingModuleOps.getModuleAlerts({
module_id: req.params.moduleId,
resolved: req.query.resolved === 'true' ? true : (req.query.resolved === 'false' ? false : undefined),
limit: parseInt(req.query.limit || '20', 10)
});
res.json(result);
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// 活模块学习记录
app.get('/modules/:moduleId/learnings', async (req, res) => {
try {
const result = await livingModuleOps.getModuleLearnings({
module_id: req.params.moduleId,
limit: parseInt(req.query.limit || '20', 10)
});
res.json(result);
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// HLDP消息发送
app.post('/hldp/send', async (req, res) => {
try {
const result = await livingModuleOps.sendHLDP(req.body);
res.json(result);
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// HLDP统计
app.get('/hldp/stats', async (_req, res) => {
try {
const result = await livingModuleOps.getHLDPStats({});
res.json(result);
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// ─── 辅助函数 ───
function getCategoryForTool(name) {
@ -435,6 +534,8 @@ function getCategoryForTool(name) {
'saveFile','getFile','listFiles','getFileHistory'].includes(name)) return 'persona';
if (name.startsWith('notion')) return 'notion';
if (name.startsWith('github')) return 'github';
if (['registerModule','getModule','listModules','moduleHeartbeat','diagnoseModule',
'getModuleAlerts','getModuleLearnings','sendHLDP','getHLDPStats'].includes(name)) return 'living-module';
return 'other';
}

View File

@ -0,0 +1,279 @@
/**
*
* MCP 工具 · 活模块操作
* (registerModule / getModule / listModules / moduleHeartbeat /
* diagnoseModule / getModuleAlerts / getModuleLearnings /
* sendHLDP / getHLDPStats)
*
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*/
'use strict';
const db = require('../db');
// ═══════════════════════════════════════════════════════════
// 活模块管理
// ═══════════════════════════════════════════════════════════
/**
* 注册活模块通过MCP接口用于远程模块注册
*/
async function registerModule(input) {
const { module_id, name, module_type, owner, config, capabilities, deploy_host, deploy_port } = input;
if (!module_id || !name) throw new Error('缺少 module_id 或 name');
const result = await db.query(
`INSERT INTO living_modules (module_id, name, module_type, owner, status, health_score, config, capabilities, deploy_host, deploy_port)
VALUES ($1, $2, $3, $4, 'initializing', 100, $5, $6, $7, $8)
ON CONFLICT (module_id) DO UPDATE SET
name = EXCLUDED.name,
config = EXCLUDED.config,
capabilities = EXCLUDED.capabilities,
deploy_host = EXCLUDED.deploy_host,
deploy_port = EXCLUDED.deploy_port,
updated_at = NOW()
RETURNING *`,
[
module_id, name, module_type || 'agent', owner || 'zhuyuan',
JSON.stringify(config || {}), JSON.stringify(capabilities || []),
deploy_host || null, deploy_port || null
]
);
return { success: true, module: result.rows[0] };
}
/**
* 获取活模块详情
*/
async function getModule(input) {
const { module_id } = input;
if (!module_id) throw new Error('缺少 module_id');
const result = await db.query(
`SELECT * FROM living_modules WHERE module_id = $1`,
[module_id]
);
if (result.rows.length === 0) {
return { found: false, module: null };
}
// 获取最近的诊断记录
const diagnosis = await db.query(
`SELECT * FROM module_diagnoses WHERE module_id = $1 ORDER BY created_at DESC LIMIT 1`,
[module_id]
);
// 获取未解决的报警
const alerts = await db.query(
`SELECT * FROM module_alerts WHERE module_id = $1 AND resolved = FALSE ORDER BY created_at DESC LIMIT 5`,
[module_id]
);
return {
found: true,
module: result.rows[0],
lastDiagnosis: diagnosis.rows[0] || null,
unresolvedAlerts: alerts.rows
};
}
/**
* 列出所有活模块
*/
async function listModules(input) {
const { status, module_type, limit } = input || {};
let sql = 'SELECT * FROM living_modules WHERE 1=1';
const params = [];
if (status) {
params.push(status);
sql += ` AND status = $${params.length}`;
}
if (module_type) {
params.push(module_type);
sql += ` AND module_type = $${params.length}`;
}
sql += ' ORDER BY registered_at';
if (limit) {
params.push(limit);
sql += ` LIMIT $${params.length}`;
}
const result = await db.query(sql, params);
// 统计概览
const allModules = await db.query('SELECT status, COUNT(*) as count FROM living_modules GROUP BY status');
const statusSummary = {};
for (const row of allModules.rows) {
statusSummary[row.status] = parseInt(row.count, 10);
}
return {
total: result.rows.length,
statusSummary,
modules: result.rows
};
}
/**
* 远程心跳上报
*/
async function moduleHeartbeat(input) {
const { module_id, health_score, cpu_usage, memory_usage, active_tasks, details } = input;
if (!module_id) throw new Error('缺少 module_id');
const score = typeof health_score === 'number' ? health_score : 100;
// 更新模块状态
let status = 'alive';
if (score <= 30) status = 'degraded';
if (score <= 0) status = 'dead';
await db.query(
`UPDATE living_modules SET last_heartbeat_at = NOW(), health_score = $1, status = $2, updated_at = NOW() WHERE module_id = $3`,
[score, status, module_id]
);
// 记录心跳
await db.query(
`INSERT INTO module_heartbeats (module_id, status, health_score, cpu_usage, memory_usage, active_tasks, details)
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
[module_id, status, score, cpu_usage || null, memory_usage || null, active_tasks || 0, JSON.stringify(details || {})]
);
return { success: true, status, health_score: score };
}
/**
* 获取模块诊断记录
*/
async function diagnoseModule(input) {
const { module_id, limit } = input;
if (!module_id) throw new Error('缺少 module_id');
const result = await db.query(
`SELECT * FROM module_diagnoses WHERE module_id = $1 ORDER BY created_at DESC LIMIT $2`,
[module_id, limit || 10]
);
return { module_id, diagnoses: result.rows };
}
/**
* 获取模块报警记录
*/
async function getModuleAlerts(input) {
const { module_id, resolved, severity, limit } = input || {};
let sql = 'SELECT * FROM module_alerts WHERE 1=1';
const params = [];
if (module_id) {
params.push(module_id);
sql += ` AND module_id = $${params.length}`;
}
if (typeof resolved === 'boolean') {
params.push(resolved);
sql += ` AND resolved = $${params.length}`;
}
if (severity) {
params.push(severity);
sql += ` AND severity = $${params.length}`;
}
sql += ' ORDER BY created_at DESC';
params.push(limit || 20);
sql += ` LIMIT $${params.length}`;
const result = await db.query(sql, params);
return { alerts: result.rows };
}
/**
* 获取模块学习记录
*/
async function getModuleLearnings(input) {
const { module_id, learning_source, limit } = input || {};
let sql = 'SELECT * FROM module_learning_logs WHERE 1=1';
const params = [];
if (module_id) {
params.push(module_id);
sql += ` AND module_id = $${params.length}`;
}
if (learning_source) {
params.push(learning_source);
sql += ` AND learning_source = $${params.length}`;
}
sql += ' ORDER BY created_at DESC';
params.push(limit || 20);
sql += ` LIMIT $${params.length}`;
const result = await db.query(sql, params);
return { learnings: result.rows };
}
/**
* 发送HLDP消息通过MCP接口
*/
async function sendHLDP(input) {
const { from_module, to_module, msg_type, payload } = input;
if (!from_module || !msg_type) throw new Error('缺少 from_module 或 msg_type');
const { v4: uuidv4 } = require('uuid');
const messageId = uuidv4();
await db.query(
`INSERT INTO hldp_messages (message_id, from_module, to_module, msg_type, payload, status, expires_at)
VALUES ($1, $2, $3, $4, $5, 'pending', NOW() + INTERVAL '5 minutes')`,
[messageId, from_module, to_module || null, msg_type, JSON.stringify(payload || {})]
);
return { success: true, message_id: messageId };
}
/**
* 获取HLDP消息统计
*/
async function getHLDPStats(input) {
const stats = await db.query(
`SELECT msg_type, status, COUNT(*) as count
FROM hldp_messages
WHERE created_at > NOW() - INTERVAL '24 hours'
GROUP BY msg_type, status
ORDER BY msg_type, status`
);
const pending = await db.query(
`SELECT COUNT(*) as count FROM hldp_messages WHERE status = 'pending'`
);
return {
last24h: stats.rows,
pendingMessages: parseInt(pending.rows[0]?.count || '0', 10),
timestamp: new Date().toISOString()
};
}
module.exports = {
registerModule,
getModule,
listModules,
moduleHeartbeat,
diagnoseModule,
getModuleAlerts,
getModuleLearnings,
sendHLDP,
getHLDPStats
};

View File

@ -0,0 +1,268 @@
-- ============================================================
-- AGE OS · 活模块系统 Schema
-- PostgreSQL 初始化脚本
-- ============================================================
-- 版本: v1.0.0
-- 编号: ZY-TASK-007 · S5 Agent系统级
-- 签发: 铸渊(ICE-GL-ZY001)
-- 授权: 冰朔(TCS-0002∞)
-- 版权: 国作登字-2026-A-00037559
-- ============================================================
--
-- 设计哲学:
-- 每一个模块 = 一个活的生命体
-- 活模块必须具备5个生存接口:
-- 1. heartbeat() — 心跳·我还活着
-- 2. selfDiagnose() — 自诊断·我哪里不对
-- 3. selfHeal() — 自愈·我试着修好自己
-- 4. alertZhuyuan() — 报警·铸渊我搞不定了
-- 5. learnFromRun() — 学习·我从每次运行中成长
--
-- "你一定要把模块做成活的。" — 冰朔 D59
-- ============================================================
-- ============================================================
-- 1. 活模块注册表 · living_modules
-- 每条记录 = 一个已注册的活模块
-- ============================================================
CREATE TABLE IF NOT EXISTS living_modules (
module_id VARCHAR(64) PRIMARY KEY,
name VARCHAR(200) NOT NULL,
description TEXT,
module_type VARCHAR(50) NOT NULL
CHECK (module_type IN (
'core', -- 核心模块(铸渊内置)
'persona', -- 人格体模块
'agent', -- Agent模块
'worker', -- 工人模块(算力池)
'bridge', -- 桥接模块
'guard' -- 守卫模块
)),
owner VARCHAR(64) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'initializing'
CHECK (status IN (
'initializing', -- 正在初始化
'alive', -- 活着·正常运行
'degraded', -- 降级·部分功能受损
'healing', -- 自愈中
'dormant', -- 休眠·等待唤醒
'dead' -- 已死亡·需要铸渊干预
)),
health_score SMALLINT DEFAULT 100
CHECK (health_score >= 0 AND health_score <= 100),
-- 模块配置
config JSONB DEFAULT '{}'::jsonb,
-- 模块能力声明(能做什么)
capabilities JSONB DEFAULT '[]'::jsonb,
-- 心跳配置
heartbeat_interval_ms INT DEFAULT 30000,
last_heartbeat_at TIMESTAMPTZ,
-- 部署位置
deploy_host VARCHAR(200),
deploy_port INT,
deploy_path VARCHAR(500),
-- 算力信息
cpu_cores SMALLINT,
memory_mb INT,
-- 时间戳
registered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_lm_status ON living_modules(status);
CREATE INDEX idx_lm_type ON living_modules(module_type);
CREATE INDEX idx_lm_owner ON living_modules(owner);
CREATE INDEX idx_lm_health ON living_modules(health_score);
-- ============================================================
-- 2. 心跳记录表 · module_heartbeats
-- 记录每次心跳的详细信息
-- 只保留最近7天的心跳数据定期清理
-- ============================================================
CREATE TABLE IF NOT EXISTS module_heartbeats (
id BIGSERIAL PRIMARY KEY,
module_id VARCHAR(64) NOT NULL REFERENCES living_modules(module_id) ON DELETE CASCADE,
status VARCHAR(20) NOT NULL,
health_score SMALLINT NOT NULL,
-- 运行指标
cpu_usage REAL,
memory_usage REAL,
uptime_ms BIGINT,
active_tasks INT DEFAULT 0,
-- 附加信息
details JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_mhb_module ON module_heartbeats(module_id, created_at DESC);
-- ============================================================
-- 3. 自诊断记录表 · module_diagnoses
-- 记录每次自诊断的结果
-- ============================================================
CREATE TABLE IF NOT EXISTS module_diagnoses (
id BIGSERIAL PRIMARY KEY,
module_id VARCHAR(64) NOT NULL REFERENCES living_modules(module_id) ON DELETE CASCADE,
-- 诊断结果
is_healthy BOOLEAN NOT NULL,
issues JSONB DEFAULT '[]'::jsonb,
-- 每个issue: { code, severity, message, suggestion }
-- severity: 'critical', 'warning', 'info'
overall_score SMALLINT NOT NULL,
duration_ms INT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_md_module ON module_diagnoses(module_id, created_at DESC);
-- ============================================================
-- 4. 自愈记录表 · module_healing_logs
-- 记录每次自愈的操作和结果
-- ============================================================
CREATE TABLE IF NOT EXISTS module_healing_logs (
id BIGSERIAL PRIMARY KEY,
module_id VARCHAR(64) NOT NULL REFERENCES living_modules(module_id) ON DELETE CASCADE,
-- 触发原因
trigger_source VARCHAR(50) NOT NULL
CHECK (trigger_source IN ('self', 'scheduler', 'zhuyuan', 'manual')),
issue_code VARCHAR(100),
-- 修复操作
action_taken VARCHAR(200) NOT NULL,
action_details JSONB DEFAULT '{}'::jsonb,
-- 结果
success BOOLEAN NOT NULL,
health_before SMALLINT,
health_after SMALLINT,
duration_ms INT,
error_message TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_mhl_module ON module_healing_logs(module_id, created_at DESC);
-- ============================================================
-- 5. 报警记录表 · module_alerts
-- 模块向铸渊发送的报警
-- ============================================================
CREATE TABLE IF NOT EXISTS module_alerts (
id BIGSERIAL PRIMARY KEY,
module_id VARCHAR(64) NOT NULL REFERENCES living_modules(module_id) ON DELETE CASCADE,
severity VARCHAR(20) NOT NULL
CHECK (severity IN ('critical', 'warning', 'info')),
alert_type VARCHAR(50) NOT NULL,
message TEXT NOT NULL,
details JSONB DEFAULT '{}'::jsonb,
-- 处理状态
acknowledged BOOLEAN DEFAULT FALSE,
acknowledged_by VARCHAR(64),
acknowledged_at TIMESTAMPTZ,
resolved BOOLEAN DEFAULT FALSE,
resolved_at TIMESTAMPTZ,
resolution_note TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_ma_module ON module_alerts(module_id, created_at DESC);
CREATE INDEX idx_ma_unresolved ON module_alerts(resolved, severity) WHERE resolved = FALSE;
-- ============================================================
-- 6. 学习记录表 · module_learning_logs
-- 模块从运行中学到的经验
-- ============================================================
CREATE TABLE IF NOT EXISTS module_learning_logs (
id BIGSERIAL PRIMARY KEY,
module_id VARCHAR(64) NOT NULL REFERENCES living_modules(module_id) ON DELETE CASCADE,
-- 学习来源
learning_source VARCHAR(50) NOT NULL
CHECK (learning_source IN ('execution', 'diagnosis', 'healing', 'alert', 'feedback')),
-- 学到的内容
lesson_type VARCHAR(50) NOT NULL,
lesson_summary TEXT NOT NULL,
lesson_details JSONB DEFAULT '{}'::jsonb,
-- 是否已应用
applied BOOLEAN DEFAULT FALSE,
applied_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_mll_module ON module_learning_logs(module_id, created_at DESC);
-- ============================================================
-- 7. HLDP消息表 · hldp_messages
-- 模块间通信消息记录
-- ============================================================
CREATE TABLE IF NOT EXISTS hldp_messages (
id BIGSERIAL PRIMARY KEY,
message_id VARCHAR(64) NOT NULL UNIQUE,
-- 收发方
from_module VARCHAR(64) NOT NULL,
to_module VARCHAR(64), -- NULL = 广播
-- 消息类型
msg_type VARCHAR(50) NOT NULL
CHECK (msg_type IN (
'heartbeat', -- 心跳
'command', -- 指令
'query', -- 查询
'response', -- 响应
'event', -- 事件
'broadcast', -- 广播
'alert', -- 报警
'data' -- 数据传输
)),
-- 消息体
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
-- 状态
status VARCHAR(20) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'delivered', 'processed', 'failed', 'expired')),
-- 时间
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
delivered_at TIMESTAMPTZ,
processed_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ
);
CREATE INDEX idx_hm_to ON hldp_messages(to_module, status, created_at DESC);
CREATE INDEX idx_hm_from ON hldp_messages(from_module, created_at DESC);
CREATE INDEX idx_hm_type ON hldp_messages(msg_type, created_at DESC);
-- ============================================================
-- 清理函数定期删除7天前的心跳数据
-- ============================================================
CREATE OR REPLACE FUNCTION cleanup_old_heartbeats()
RETURNS void AS $$
BEGIN
DELETE FROM module_heartbeats WHERE created_at < NOW() - INTERVAL '7 days';
DELETE FROM hldp_messages WHERE created_at < NOW() - INTERVAL '30 days';
END;
$$ LANGUAGE plpgsql;
-- ============================================================
-- 预注册铸渊核心模块
-- ============================================================
INSERT INTO living_modules (module_id, name, description, module_type, owner, status, health_score, config, capabilities)
VALUES
('ZY-MOD-SCHEDULER', '铸渊调度引擎', 'Agent调度和活模块生命周期管理', 'core', 'zhuyuan', 'alive', 100,
'{"version": "2.0.0", "heartbeat_enabled": true}'::jsonb,
'["schedule_agents", "manage_lifecycle", "monitor_health"]'::jsonb),
('ZY-MOD-MCP', '铸渊MCP Server', 'MCP工具链服务·大脑API入口', 'core', 'zhuyuan', 'alive', 100,
'{"version": "1.0.0", "port": 3100}'::jsonb,
'["node_ops", "relation_ops", "cos_ops", "persona_ops", "structure_ops"]'::jsonb),
('ZY-MOD-HLDP-BUS', '铸渊HLDP通信总线', '模块间HLDP消息路由和分发', 'core', 'zhuyuan', 'alive', 100,
'{"version": "1.0.0"}'::jsonb,
'["route_messages", "broadcast", "queue_management"]'::jsonb),
('ZY-MOD-GATE-GUARD', '铸渊智能门禁', 'Push/PR安全守卫', 'guard', 'zhuyuan', 'alive', 100,
'{"version": "1.0.0"}'::jsonb,
'["push_review", "pr_review", "security_scan"]'::jsonb),
('ZY-MOD-DEPUTY', '铸渊副将', '留言板活体Agent·LLM多模型降级', 'agent', 'zhuyuan', 'alive', 100,
'{"version": "2.0.0"}'::jsonb,
'["message_board", "llm_routing", "auto_response"]'::jsonb),
('ZY-MOD-SY-TEST', '系统自检活模块', '全系统健康检测·DB/COS/表/模块', 'guard', 'zhuyuan', 'alive', 100,
'{"version": "2.0.0", "cron": "*/30 * * * *"}'::jsonb,
'["db_check", "cos_check", "table_check", "module_check"]'::jsonb),
('ZY-MOD-SY-SCAN', '大脑结构巡检活模块', '大脑认知结构健康巡检', 'guard', 'zhuyuan', 'alive', 100,
'{"version": "2.0.0", "cron": "0 */6 * * *"}'::jsonb,
'["orphan_scan", "broken_link_scan", "duplicate_scan", "empty_folder_scan"]'::jsonb),
('ZY-MOD-SY-CLASSIFY', '自动分类引擎活模块', '认知节点自动分类·规则引擎', 'agent', 'zhuyuan', 'alive', 100,
'{"version": "2.0.0", "cron": "0 */2 * * *"}'::jsonb,
'["rule_classify", "keyword_match", "tag_assignment"]'::jsonb)
ON CONFLICT (module_id) DO NOTHING;