guanghulab/server/age-os/mcp-server/tools/living-module-ops.js

280 lines
7.9 KiB
JavaScript
Raw Permalink Normal View History

/**
*
* 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
};