dream.js
3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* dream —— 经验汇流的 REST 入口([29-DREAM](../../docs/done/system-design/29-dream-design.md))。
*
* 只做一件事:把 `dream-service.js` 已有的能力(`dreamOnce` / `dreamSweep` /
* `auditDistilled` / `definitionWritability`)从「只能靠脚本或定时器触发」
* 变成「REST 可查可触发」。不新增业务逻辑。
*/
const express = require('express');
const router = express.Router();
const { requireAdmin } = require('../middleware/jwt-auth');
const dream = require('../services/dream-service');
// 38 号文档 Phase 1:Dream 是系统级的跨公司经验汇流视图,只有 admin 能看,
// 不是"登录即可看"(普通用户不该看到别的公司提炼出的经验)。
router.use(requireAdmin);
// dreamSweep 串行跑几十个本体、每个可能起两次 LLM 调用,不能塞进一次 HTTP 请求里等。
// 用最小的内存态跟踪「在跑没在跑」+「上一轮结果」,够控制台轮询用。
let sweepState = { sweeping: false, startedAt: null, finishedAt: null, results: null, error: null };
// GET /api/dream/agents — 总览:每个可 dream 的本体,跑没跑过、上次沉淀了几条
router.get('/agents', (req, res) => {
try {
const list = dream.listDreamableAgents().map((agentId) => {
const state = dream.readState(agentId);
return {
agentId,
companies: dream.companiesOf(agentId).length,
lastRunAt: state.lastRunAt || null,
lastAccepted: state.lastAccepted || 0,
lastRejected: state.lastRejected || 0,
};
});
res.json({ agents: list });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// GET /api/dream/agents/:agentId — 详情:状态 + 定义文件能不能写 + 已沉淀经验的可回查列表
router.get('/agents/:agentId', (req, res) => {
try {
const { agentId } = req.params;
res.json({
agentId,
companies: dream.companiesOf(agentId),
state: dream.readState(agentId),
definitions: dream.definitionWritability(agentId),
experience: dream.auditDistilled(agentId), // 每条结论并排列出引用的原料原文,回查成本降到几秒
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// POST /api/dream/agents/:agentId/run — 手动跑一次(真会起 LLM 调用,dryRun 只想看会不会有新原料时用)
router.post('/agents/:agentId/run', async (req, res) => {
try {
const dryRun = req.body && req.body.dryRun === true;
const result = await dream.dreamOnce(req.params.agentId, { dryRun });
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// POST /api/dream/sweep — 手动触发全量扫描(后台跑,别等;串行跑完可能是几分钟到几十分钟)
router.post('/sweep', (req, res) => {
if (sweepState.sweeping) return res.status(409).json({ error: '上一轮扫描还没跑完', ...sweepState });
sweepState = { sweeping: true, startedAt: new Date().toISOString(), finishedAt: null, results: null, error: null };
dream.dreamSweep()
.then((results) => { sweepState = { ...sweepState, sweeping: false, finishedAt: new Date().toISOString(), results }; })
.catch((err) => { sweepState = { ...sweepState, sweeping: false, finishedAt: new Date().toISOString(), error: err.message }; });
res.status(202).json({ started: true, startedAt: sweepState.startedAt });
});
// GET /api/dream/sweep/status — 轮询上面那个后台任务
router.get('/sweep/status', (req, res) => res.json(sweepState));
module.exports = router;