Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

165 lines
6.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* ═══════════════════════════════════════════════════════════
* 成员Agent路由 · /api/zhiku/agent
* ═══════════════════════════════════════════════════════════
*
* 智库节点 Phase 3 · ZY-SVR-006
* 守护: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* 端点:
* GET / — 列出所有Agent
* GET /:memberId — 获取Agent详情
* POST /:memberId — 注册/获取Agent
* POST /:memberId/chat — 对话
* GET /:memberId/chat — 获取对话历史
* GET /:memberId/memories — 获取记忆
* POST /:memberId/memories — 添加记忆
* GET /:memberId/notes — 获取笔记
* POST /:memberId/notes — 添加笔记
* GET /stats — Agent统计
*
* ═══════════════════════════════════════════════════════════
*/
'use strict';
const express = require('express');
const router = express.Router();
const engine = require('../services/member-agent-engine');
/* ─── GET /stats — 统计 (放在 /:memberId 前面) ─── */
router.get('/stats', (req, res) => {
res.json({ error: false, data: engine.getStats() });
});
/* ─── GET / — 列出所有Agent ─── */
router.get('/', (req, res) => {
const agents = engine.listAgents();
res.json({ error: false, data: agents, total: agents.length });
});
/* ─── GET /:memberId — 获取Agent详情 ─── */
router.get('/:memberId', (req, res) => {
const agent = engine.getAgent(req.params.memberId);
if (!agent) return res.status(404).json({ error: true, code: 'NOT_FOUND', message: 'Agent不存在' });
// 返回摘要(不暴露全部记忆)
res.json({
error: false,
data: {
member_id: agent.member_id,
nickname: agent.nickname,
role: agent.role,
memory_count: agent.memory ? agent.memory.length : 0,
note_count: agent.notes ? agent.notes.length : 0,
chat_count: agent.chat_history ? agent.chat_history.length : 0,
preferences: agent.preferences,
last_active: agent.last_active,
created_at: agent.created_at
}
});
});
/* ─── POST /:memberId — 注册/获取Agent ─── */
router.post('/:memberId', (req, res) => {
try {
const { nickname, role } = req.body;
const agent = engine.getOrCreateAgent(req.params.memberId, { nickname, role });
res.json({
error: false,
data: {
member_id: agent.member_id,
nickname: agent.nickname,
role: agent.role,
last_active: agent.last_active,
created_at: agent.created_at
}
});
} catch (err) {
res.status(400).json({ error: true, code: 'CREATE_FAILED', message: err.message });
}
});
/* ─── POST /:memberId/chat — 对话 ─── */
router.post('/:memberId/chat', async (req, res) => {
try {
const { message, use_ai } = req.body;
if (!message || !message.trim()) {
return res.status(400).json({ error: true, code: 'EMPTY_MESSAGE', message: '消息不能为空' });
}
// 默认使用AIuse_ai=false 时使用本地快速回复
let result;
if (use_ai === false) {
result = engine.chat(req.params.memberId, message);
} else {
// 优先尝试异步AI对话
try {
result = await engine.chatAsync(req.params.memberId, message);
} catch {
// AI失败时降级为本地回复
result = engine.chat(req.params.memberId, message);
}
}
res.json({ error: false, data: result });
} catch (err) {
res.status(400).json({ error: true, code: 'CHAT_FAILED', message: err.message });
}
});
/* ─── GET /:memberId/chat — 对话历史 ─── */
router.get('/:memberId/chat', (req, res) => {
const limit = req.query.limit ? parseInt(req.query.limit) : undefined;
const history = engine.getChatHistory(req.params.memberId, limit);
res.json({ error: false, data: history, total: history.length });
});
/* ─── GET /:memberId/memories — 记忆列表 ─── */
router.get('/:memberId/memories', (req, res) => {
const { type, limit } = req.query;
const memories = engine.getMemories(req.params.memberId, {
type, limit: limit ? parseInt(limit) : undefined
});
res.json({ error: false, data: memories, total: memories.length });
});
/* ─── POST /:memberId/memories — 添加记忆 ─── */
router.post('/:memberId/memories', (req, res) => {
try {
const { type, content, source, tags } = req.body;
if (!content || !content.trim()) {
return res.status(400).json({ error: true, code: 'EMPTY_CONTENT', message: 'content 不能为空' });
}
const result = engine.addMemory(req.params.memberId, { type, content, source, tags });
res.json({ error: false, data: result });
} catch (err) {
res.status(400).json({ error: true, code: 'ADD_MEMORY_FAILED', message: err.message });
}
});
/* ─── GET /:memberId/notes — 笔记列表 ─── */
router.get('/:memberId/notes', (req, res) => {
const { book_id, limit } = req.query;
const notes = engine.getNotes(req.params.memberId, {
book_id, limit: limit ? parseInt(limit) : undefined
});
res.json({ error: false, data: notes, total: notes.length });
});
/* ─── POST /:memberId/notes — 添加笔记 ─── */
router.post('/:memberId/notes', (req, res) => {
try {
const { title, content, book_id } = req.body;
if (!content || !content.trim()) {
return res.status(400).json({ error: true, code: 'EMPTY_CONTENT', message: 'content 不能为空' });
}
const result = engine.addNote(req.params.memberId, { title, content, book_id });
res.json({ error: false, data: result });
} catch (err) {
res.status(400).json({ error: true, code: 'ADD_NOTE_FAILED', message: err.message });
}
});
module.exports = router;