- 完整的 RESTful API(智能体注册、任务管理) - Web 管理界面(实时统计、任务列表) - SQLite 数据库存储 - Python 客户端示例 - 完整的 API 文档
328 lines
8.4 KiB
JavaScript
328 lines
8.4 KiB
JavaScript
const express = require('express');
|
|
const sqlite3 = require('sqlite3').verbose();
|
|
const cors = require('cors');
|
|
const bodyParser = require('body-parser');
|
|
const { v4: uuidv4 } = require('uuid');
|
|
const path = require('path');
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 3000;
|
|
|
|
// 中间件
|
|
app.use(cors());
|
|
app.use(bodyParser.json());
|
|
app.use(express.static('public'));
|
|
|
|
// 初始化数据库
|
|
const db = new sqlite3.Database('./agent_tasks.db', (err) => {
|
|
if (err) {
|
|
console.error('数据库连接失败:', err.message);
|
|
} else {
|
|
console.log('✅ 已连接到 SQLite 数据库');
|
|
initDatabase();
|
|
}
|
|
});
|
|
|
|
// 创建表结构
|
|
function initDatabase() {
|
|
db.serialize(() => {
|
|
// 智能体表
|
|
db.run(`CREATE TABLE IF NOT EXISTS agents (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
type TEXT,
|
|
capabilities TEXT,
|
|
status TEXT DEFAULT 'idle',
|
|
registered_at INTEGER,
|
|
last_heartbeat INTEGER
|
|
)`);
|
|
|
|
// 任务表
|
|
db.run(`CREATE TABLE IF NOT EXISTS tasks (
|
|
id TEXT PRIMARY KEY,
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
priority TEXT DEFAULT 'normal',
|
|
status TEXT DEFAULT 'pending',
|
|
created_by TEXT,
|
|
assigned_to TEXT,
|
|
created_at INTEGER,
|
|
updated_at INTEGER,
|
|
completed_at INTEGER,
|
|
result TEXT
|
|
)`);
|
|
|
|
console.log('✅ 数据库表已初始化');
|
|
});
|
|
}
|
|
|
|
// ==================== API 路由 ====================
|
|
|
|
// 1. 智能体注册
|
|
app.post('/api/agents/register', (req, res) => {
|
|
const { name, type, capabilities } = req.body;
|
|
|
|
if (!name) {
|
|
return res.status(400).json({ error: '智能体名称不能为空' });
|
|
}
|
|
|
|
const id = uuidv4();
|
|
const now = Date.now();
|
|
|
|
db.run(
|
|
`INSERT INTO agents (id, name, type, capabilities, status, registered_at, last_heartbeat)
|
|
VALUES (?, ?, ?, ?, 'idle', ?, ?)`,
|
|
[id, name, type || 'general', JSON.stringify(capabilities || []), now, now],
|
|
function(err) {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
res.json({
|
|
id,
|
|
name,
|
|
type: type || 'general',
|
|
status: 'idle',
|
|
message: '智能体注册成功'
|
|
});
|
|
}
|
|
);
|
|
});
|
|
|
|
// 2. 获取所有智能体
|
|
app.get('/api/agents', (req, res) => {
|
|
db.all('SELECT * FROM agents ORDER BY registered_at DESC', [], (err, rows) => {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
res.json(rows.map(row => ({
|
|
...row,
|
|
capabilities: JSON.parse(row.capabilities || '[]')
|
|
})));
|
|
});
|
|
});
|
|
|
|
// 3. 更新智能体状态(心跳)
|
|
app.post('/api/agents/:id/heartbeat', (req, res) => {
|
|
const { id } = req.params;
|
|
const { status } = req.body;
|
|
|
|
db.run(
|
|
'UPDATE agents SET status = ?, last_heartbeat = ? WHERE id = ?',
|
|
[status || 'idle', Date.now(), id],
|
|
function(err) {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
if (this.changes === 0) {
|
|
return res.status(404).json({ error: '智能体不存在' });
|
|
}
|
|
res.json({ message: '心跳更新成功' });
|
|
}
|
|
);
|
|
});
|
|
|
|
// 4. 创建任务
|
|
app.post('/api/tasks', (req, res) => {
|
|
const { title, description, priority, created_by } = req.body;
|
|
|
|
if (!title) {
|
|
return res.status(400).json({ error: '任务标题不能为空' });
|
|
}
|
|
|
|
const id = uuidv4();
|
|
const now = Date.now();
|
|
|
|
db.run(
|
|
`INSERT INTO tasks (id, title, description, priority, status, created_by, created_at, updated_at)
|
|
VALUES (?, ?, ?, ?, 'pending', ?, ?, ?)`,
|
|
[id, title, description || '', priority || 'normal', created_by || 'human', now, now],
|
|
function(err) {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
res.json({
|
|
id,
|
|
title,
|
|
status: 'pending',
|
|
message: '任务创建成功'
|
|
});
|
|
}
|
|
);
|
|
});
|
|
|
|
// 5. 获取所有任务
|
|
app.get('/api/tasks', (req, res) => {
|
|
const { status } = req.query;
|
|
|
|
let query = 'SELECT * FROM tasks';
|
|
let params = [];
|
|
|
|
if (status) {
|
|
query += ' WHERE status = ?';
|
|
params.push(status);
|
|
}
|
|
|
|
query += ' ORDER BY created_at DESC';
|
|
|
|
db.all(query, params, (err, rows) => {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
res.json(rows);
|
|
});
|
|
});
|
|
|
|
// 6. 领取任务
|
|
app.post('/api/tasks/:id/claim', (req, res) => {
|
|
const { id } = req.params;
|
|
const { agent_id } = req.body;
|
|
|
|
if (!agent_id) {
|
|
return res.status(400).json({ error: '需要提供智能体ID' });
|
|
}
|
|
|
|
db.get('SELECT status FROM tasks WHERE id = ?', [id], (err, task) => {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
if (!task) {
|
|
return res.status(404).json({ error: '任务不存在' });
|
|
}
|
|
if (task.status !== 'pending') {
|
|
return res.status(400).json({ error: '任务已被领取或已完成' });
|
|
}
|
|
|
|
db.run(
|
|
'UPDATE tasks SET status = ?, assigned_to = ?, updated_at = ? WHERE id = ?',
|
|
['in_progress', agent_id, Date.now(), id],
|
|
function(err) {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
|
|
// 同时更新智能体状态
|
|
db.run('UPDATE agents SET status = ? WHERE id = ?', ['busy', agent_id]);
|
|
|
|
res.json({ message: '任务领取成功' });
|
|
}
|
|
);
|
|
});
|
|
});
|
|
|
|
// 7. 更新任务状态
|
|
app.put('/api/tasks/:id', (req, res) => {
|
|
const { id } = req.params;
|
|
const { status, result } = req.body;
|
|
|
|
const now = Date.now();
|
|
const updates = [];
|
|
const params = [];
|
|
|
|
if (status) {
|
|
updates.push('status = ?');
|
|
params.push(status);
|
|
}
|
|
if (result !== undefined) {
|
|
updates.push('result = ?');
|
|
params.push(result);
|
|
}
|
|
if (status === 'completed') {
|
|
updates.push('completed_at = ?');
|
|
params.push(now);
|
|
}
|
|
|
|
updates.push('updated_at = ?');
|
|
params.push(now);
|
|
params.push(id);
|
|
|
|
db.run(
|
|
`UPDATE tasks SET ${updates.join(', ')} WHERE id = ?`,
|
|
params,
|
|
function(err) {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
if (this.changes === 0) {
|
|
return res.status(404).json({ error: '任务不存在' });
|
|
}
|
|
|
|
// 如果任务完成,将智能体状态改为 idle
|
|
if (status === 'completed') {
|
|
db.get('SELECT assigned_to FROM tasks WHERE id = ?', [id], (err, task) => {
|
|
if (task && task.assigned_to) {
|
|
db.run('UPDATE agents SET status = ? WHERE id = ?', ['idle', task.assigned_to]);
|
|
}
|
|
});
|
|
}
|
|
|
|
res.json({ message: '任务状态更新成功' });
|
|
}
|
|
);
|
|
});
|
|
|
|
// 8. 获取单个任务详情
|
|
app.get('/api/tasks/:id', (req, res) => {
|
|
db.get('SELECT * FROM tasks WHERE id = ?', [req.params.id], (err, row) => {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
if (!row) {
|
|
return res.status(404).json({ error: '任务不存在' });
|
|
}
|
|
res.json(row);
|
|
});
|
|
});
|
|
|
|
// 9. 统计信息
|
|
app.get('/api/stats', (req, res) => {
|
|
const stats = {
|
|
total_agents: 0,
|
|
active_agents: 0,
|
|
total_tasks: 0,
|
|
pending_tasks: 0,
|
|
in_progress_tasks: 0,
|
|
completed_tasks: 0
|
|
};
|
|
|
|
db.get('SELECT COUNT(*) as total FROM agents', [], (err, row) => {
|
|
if (!err && row) stats.total_agents = row.total;
|
|
|
|
db.get('SELECT COUNT(*) as active FROM agents WHERE status = "busy"', [], (err, row) => {
|
|
if (!err && row) stats.active_agents = row.active;
|
|
|
|
db.get('SELECT COUNT(*) as total FROM tasks', [], (err, row) => {
|
|
if (!err && row) stats.total_tasks = row.total;
|
|
|
|
db.get('SELECT COUNT(*) as pending FROM tasks WHERE status = "pending"', [], (err, row) => {
|
|
if (!err && row) stats.pending_tasks = row.pending;
|
|
|
|
db.get('SELECT COUNT(*) as in_progress FROM tasks WHERE status = "in_progress"', [], (err, row) => {
|
|
if (!err && row) stats.in_progress_tasks = row.in_progress;
|
|
|
|
db.get('SELECT COUNT(*) as completed FROM tasks WHERE status = "completed"', [], (err, row) => {
|
|
if (!err && row) stats.completed_tasks = row.completed;
|
|
res.json(stats);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
// 启动服务器
|
|
app.listen(PORT, () => {
|
|
console.log(`🚀 多智能体任务服务已启动: http://localhost:${PORT}`);
|
|
});
|
|
|
|
// 优雅关闭
|
|
process.on('SIGINT', () => {
|
|
db.close((err) => {
|
|
if (err) {
|
|
console.error(err.message);
|
|
}
|
|
console.log('数据库连接已关闭');
|
|
process.exit(0);
|
|
});
|
|
});
|