Commit 5d095609389de02ef65ea7f8a9d5c39e16a6f4ed

Authored by yibo
1 parent f0468e9b

fix(heartbeat): 两套心跳自环调用缺内部令牌,暗中 401(真实回归发现)

验证 46 号文档 Phase 3 v2(CEO 心跳发现并派发子任务)时,触发 CEO 心跳
直接撞上 401——company-heartbeat-service.js 的 _sendAgentChat 和
heartbeat-service.js 的 _triggerHeartbeat 都在自环调用
POST /api/agent/:agentId/chat(agent-chat.js 挂了 requireAuthOrInternal),
但两处都没有带 INTERNAL_TOKEN_HEADER——company.js/task-settle.js 的同类
自环调用早就在带,这两处漏了。

失败只落一行 console.warn,界面上什么都看不出来,影响的不只是 CEO 心跳:
两套心跳系统(per-agent 的 heartbeat-service 和公司级的
company-heartbeat-service,含它驱动的 pipeline/schedule 触发)都受影响。

按现成模式补上内部令牌头。全量单测 1189 passed(唯二失败与本次改动
无关),修完真实验证 CEO 心跳能正常跑完整段推理会话。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H85SS5hVC4u1PbVhjmrhH8
server/services/company-heartbeat-service.js
... ... @@ -473,6 +473,11 @@ class CompanyHeartbeatService {
473 473 * isHeartbeat 仍然发,但只对真心跳为真 —— 老的消费方(如果还有)行为不变。
474 474 */
475 475 _sendAgentChat(companyId, agentId, message, conversationId, kind = 'heartbeat') {
  476 + // agent-chat.js 挂了 requireAuthOrInternal(38 号文档 Phase 1)——这是一条服务端自环
  477 + // fetch,没有用户 cookie,不带内部令牌会被 401 挡住。company.js/task-settle.js 的自环
  478 + // 调用都带了这个头,这里漏了,是心跳(含 CEO 心跳、pipeline/schedule 触发)一直在暗中
  479 + // 401 的根因:失败只落一行 console.warn,界面上什么都看不出来。
  480 + const { INTERNAL_TOKEN, INTERNAL_TOKEN_HEADER } = require('../middleware/jwt-auth');
476 481 const postData = JSON.stringify({
477 482 message,
478 483 conversationId,
... ... @@ -488,6 +493,7 @@ class CompanyHeartbeatService {
488 493 headers: {
489 494 'Content-Type': 'application/json',
490 495 'Content-Length': Buffer.byteLength(postData),
  496 + [INTERNAL_TOKEN_HEADER]: INTERNAL_TOKEN,
491 497 },
492 498 };
493 499  
... ...
server/services/heartbeat-service.js
... ... @@ -228,6 +228,11 @@ class HeartbeatService {
228 228 `无需等待人类确认,请完全自主决策。`
229 229 ].join('\n');
230 230  
  231 + // agent-chat.js 挂了 requireAuthOrInternal(38 号文档 Phase 1)——这是一条服务端自环
  232 + // fetch,没有用户 cookie,不带内部令牌会被 401 挡住。company.js/task-settle.js 的自环
  233 + // 调用都带了这个头,这里漏了,是"心跳一直在暗中 401"的根因之一(另一处见
  234 + // company-heartbeat-service.js 的同款漏洞):失败只落一行 console.warn,界面上看不出来。
  235 + const { INTERNAL_TOKEN, INTERNAL_TOKEN_HEADER } = require('../middleware/jwt-auth');
231 236 const postData = JSON.stringify({
232 237 message: heartbeatMessage,
233 238 conversationId: convId,
... ... @@ -241,7 +246,8 @@ class HeartbeatService {
241 246 method: 'POST',
242 247 headers: {
243 248 'Content-Type': 'application/json',
244   - 'Content-Length': Buffer.byteLength(postData)
  249 + 'Content-Length': Buffer.byteLength(postData),
  250 + [INTERNAL_TOKEN_HEADER]: INTERNAL_TOKEN,
245 251 }
246 252 };
247 253  
... ...