You need to sign in before continuing.
Commit 5d095609389de02ef65ea7f8a9d5c39e16a6f4ed
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
Showing
2 changed files
with
13 additions
and
1 deletions
server/services/company-heartbeat-service.js
| @@ -473,6 +473,11 @@ class CompanyHeartbeatService { | @@ -473,6 +473,11 @@ class CompanyHeartbeatService { | ||
| 473 | * isHeartbeat 仍然发,但只对真心跳为真 —— 老的消费方(如果还有)行为不变。 | 473 | * isHeartbeat 仍然发,但只对真心跳为真 —— 老的消费方(如果还有)行为不变。 |
| 474 | */ | 474 | */ |
| 475 | _sendAgentChat(companyId, agentId, message, conversationId, kind = 'heartbeat') { | 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 | const postData = JSON.stringify({ | 481 | const postData = JSON.stringify({ |
| 477 | message, | 482 | message, |
| 478 | conversationId, | 483 | conversationId, |
| @@ -488,6 +493,7 @@ class CompanyHeartbeatService { | @@ -488,6 +493,7 @@ class CompanyHeartbeatService { | ||
| 488 | headers: { | 493 | headers: { |
| 489 | 'Content-Type': 'application/json', | 494 | 'Content-Type': 'application/json', |
| 490 | 'Content-Length': Buffer.byteLength(postData), | 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,6 +228,11 @@ class HeartbeatService { | ||
| 228 | `无需等待人类确认,请完全自主决策。` | 228 | `无需等待人类确认,请完全自主决策。` |
| 229 | ].join('\n'); | 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 | const postData = JSON.stringify({ | 236 | const postData = JSON.stringify({ |
| 232 | message: heartbeatMessage, | 237 | message: heartbeatMessage, |
| 233 | conversationId: convId, | 238 | conversationId: convId, |
| @@ -241,7 +246,8 @@ class HeartbeatService { | @@ -241,7 +246,8 @@ class HeartbeatService { | ||
| 241 | method: 'POST', | 246 | method: 'POST', |
| 242 | headers: { | 247 | headers: { |
| 243 | 'Content-Type': 'application/json', | 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 |