agent.js 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. 'use strict';
  2. // 智能问数智能体路由:运行生命周期(异步执行 + 轮询)与会话索引
  3. // POST /api/agent/runs 发起运行(agent/quick 双模式),立即返回 run 记录
  4. // GET /api/agent/runs 会话内运行摘要列表(?entity&sessionId)
  5. // GET /api/agent/runs/:id 运行详情(含步骤/产物;运行中为实时进度)
  6. // POST /api/agent/runs/:id/cancel 请求取消(回合间隙生效)
  7. // GET /api/agent/sessions 会话列表(?entity)
  8. const { sendJson, readBody } = require('../util.js');
  9. const { ASK_CLIENT_CODES } = require('../middleware.js');
  10. const { makeChatCfg } = require('../context.js');
  11. const naposService = require('../../napos-service.js');
  12. const aitableFactory = require('../services/aitable.js');
  13. const agent = require('../agent/index.js');
  14. const agentSkills = require('../agent/skills.js');
  15. function requireEntity(query, body) {
  16. const entity = (body && body.entity) || query.entity
  17. || (naposService.store.listEntities()[0] || {}).key;
  18. if (!entity) {
  19. const e = new Error('暂无数据主体,请先完成一次同步');
  20. e.code = 'ASK_NO_ENTITY';
  21. throw e;
  22. }
  23. return entity;
  24. }
  25. function register(app, ctx) {
  26. // 云端协同(湖↔云比对工具用):复用 server.js 装配的服务实例(无则兜底自建)
  27. const aitableSvc = ctx.aitable || aitableFactory.createAitableService(ctx);
  28. app.post('/api/agent/runs', async ({ req, res }) => {
  29. const body = await readBody(req);
  30. const entity = requireEntity({}, body);
  31. // 参数类错误(空问题/未配模型/无主体)→ 400;其余交给错误边界
  32. try {
  33. const rec = agent.startRun({
  34. entity,
  35. question: body.question,
  36. mode: ['quick', 'agent', 'auto'].includes(body.mode) ? body.mode : 'auto',
  37. sessionId: body.sessionId,
  38. skill: body.skill,
  39. cloud: aitableSvc,
  40. cfg: makeChatCfg(ctx),
  41. svc: naposService,
  42. });
  43. sendJson(res, 200, { run: rec });
  44. } catch (e) {
  45. if (!ASK_CLIENT_CODES.has(e.code)) e.status = 502;
  46. throw e;
  47. }
  48. });
  49. app.get('/api/agent/runs', async ({ res, query }) => {
  50. const entity = requireEntity(query);
  51. if (!query.sessionId) return sendJson(res, 400, { error: '缺少 sessionId 参数' });
  52. sendJson(res, 200, { entity, runs: agent.listRuns(entity, query.sessionId) });
  53. });
  54. app.get('/api/agent/runs/:id', async ({ res, query, params }) => {
  55. const entity = requireEntity(query);
  56. const rec = agent.getRun(entity, params.id);
  57. if (!rec) return sendJson(res, 404, { error: '运行记录不存在' });
  58. sendJson(res, 200, { run: rec });
  59. });
  60. app.post('/api/agent/runs/:id/cancel', async ({ req, res, params }) => {
  61. await readBody(req).catch(() => ({}));
  62. const rec = agent.cancelRun(params.id);
  63. if (!rec) return sendJson(res, 404, { error: '运行记录不存在' });
  64. sendJson(res, 200, { run: rec });
  65. });
  66. app.get('/api/agent/sessions', async ({ res, query }) => {
  67. const entity = requireEntity(query);
  68. sendJson(res, 200, { entity, sessions: agent.listSessions(entity) });
  69. });
  70. app.del('/api/agent/sessions/:id', async ({ res, query, params }) => {
  71. const entity = requireEntity(query);
  72. const ok = agent.deleteSession(entity, params.id);
  73. if (!ok) return sendJson(res, 404, { error: '会话不存在' });
  74. sendJson(res, 200, { ok: true });
  75. });
  76. app.get('/api/agent/skills', async ({ res }) => {
  77. sendJson(res, 200, { skills: agentSkills.SKILLS.map(({ key, name, desc }) => ({ key, name, desc })) });
  78. });
  79. }
  80. module.exports = { register };