agent-server.js 3.03 KB
/**
 * Agent Chat 独立服务器
 *
 * 只启动 Agent Chat API,不依赖主服务器的其他模块。
 * 用法: node server/agent-server.js
 */
const express = require('express');
const cors = require('cors');
const agentChatRoute = require('./routes/agent-chat');

const app = express();
const config = require('./config');
const PORT = process.env.PORT || config.port || 3010;

app.use(cors({ origin: ['http://localhost:5173'], credentials: true }));

// ── 控制字符净化中间件 ──
// Agent 通过 curl 发送的 JSON body 可能包含原始控制字符,
// 导致 body-parser 的 JSON.parse 失败
app.use((req, res, next) => {
  if (req.headers['content-type']?.includes('application/json')) {
    let rawBody = '';
    req.on('data', chunk => rawBody += chunk);
    req.on('end', () => {
      if (!rawBody) {
        req.body = {};
        req._bodyParsed = true;
        return next();
      }
      try {
        req.body = JSON.parse(rawBody);
        req._bodyParsed = true;
        next();
      } catch (e) {
        try {
          // eslint-disable-next-line no-control-regex
          const cleaned = rawBody.replace(/[\x00-\x1F\x7F]/g, (ch) => {
            if (ch === '\n') return '\\n';
            if (ch === '\r') return '\\r';
            if (ch === '\t') return '\\t';
            return '';
          });
          req.body = JSON.parse(cleaned);
          req._bodyParsed = true;
          console.log(`[BodySanitizer] ⚠️ 已净化请求体控制字符 (${req.path})`);
          next();
        } catch (e2) {
          res.status(400).json({ error: 'Invalid JSON: ' + e2.message });
        }
      }
    });
  } else {
    next();
  }
});
// express.json() 仅处理未被上面中间件处理的请求(非 JSON content-type 等)
app.use((req, res, next) => {
  if (req._bodyParsed) return next();
  express.json()(req, res, next);
});

// Agent Chat API
app.use('/api/agent', agentChatRoute);

// Company API
app.use('/api/company', require('./routes/company'));
app.use('/api/okr',     require('./routes/okr'));  // /api/goals 别名已退役(27-P3C §六.1)
app.use('/api/tasks',   require('./routes/tasks'));
// /api/devloop 已退役(DevLoop 子系统 2026-09-17 下线,见 docs/_archive/devloop-prd-2026-09-17/)
app.use('/api/graph-runs', require('./routes/graph-run'));                 // P3 图执行(T6)
app.use('/api/company',    require('./routes/graph-run').companyRouter);   // GET /:cid/graph-runs
app.use('/public', require('express').static(require('path').join(__dirname, 'public')));

// Health
app.get('/api/health', (req, res) => res.json({ status: 'ok', service: 'agent-chat' }));

// Graph agent 元数据对齐(P3B W1)——与 server/index.js 的 start() 同一步,理由见那里的注释
require('./services/graph-seed-service').runStartupSeedSafely();

app.listen(PORT, '0.0.0.0', () => {
  console.log(`🧬 Agent Chat Server: http://localhost:${PORT}`);
  console.log(`   API: http://localhost:${PORT}/api/agent/list`);
  console.log(`   Chat: http://localhost:5173/agent/innovator-001`);
});