Commit d48457acbe2d7e66651417d523e3705a11f00663
1 parent
9e586563
fix(auth): selfChat 自环唤醒漏带内部令牌,7 处调用全部静默 401
router.use(requireAuthOrInternal) 之后,agent-chat.js 自己的 selfChat() helper (TaskDispatch/TaskCallback/TaskTransition ×2/TaskReject/HumanRequest 共 7 处 调用)一直在用裸 http.request 自己打自己的 /api/agent/:id/chat,没带 x-internal-token,全部被 401 挡住——而且 chatRes 回调之前不看 statusCode, 401 也照样打印"✅ 已唤醒",症状是静默的(跟 claude-cli-session-leak.md 一个模式)。 实测复现:真实 dispatch 一个任务给 org-innovator,目标 agent 从未收到消息, 任务卡在 dispatched 状态没人执行。 修法:selfChat 加 x-internal-token header(跟 company.js/task-settle.js 的 自环调用同一套机制),并且真的检查 chatRes.statusCode,非 2xx 打日志说明失败, 不再假装成功。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Showing
1 changed file
with
19 additions
and
4 deletions
server/routes/agent-chat.js
| @@ -30,7 +30,7 @@ const companyService = new CompanyService(); | @@ -30,7 +30,7 @@ const companyService = new CompanyService(); | ||
| 30 | // 交付物归宿只有一份推导(28 §4.4),公司环境上下文与执行链路的运行时坐标共用它 | 30 | // 交付物归宿只有一份推导(28 §4.4),公司环境上下文与执行链路的运行时坐标共用它 |
| 31 | const { companyWorkspaceDir } = require('../src/core/prompt-builder'); | 31 | const { companyWorkspaceDir } = require('../src/core/prompt-builder'); |
| 32 | const systemConfig = require('../config'); | 32 | const systemConfig = require('../config'); |
| 33 | -const { requireAuthOrInternal } = require('../middleware/jwt-auth'); | 33 | +const { requireAuthOrInternal, INTERNAL_TOKEN, INTERNAL_TOKEN_HEADER } = require('../middleware/jwt-auth'); |
| 34 | const router = express.Router(); | 34 | const router = express.Router(); |
| 35 | 35 | ||
| 36 | // 38 号文档 Phase 1:全站要求登录,但这个文件同时承接三处服务端自环调用 | 36 | // 38 号文档 Phase 1:全站要求登录,但这个文件同时承接三处服务端自环调用 |
| @@ -80,10 +80,25 @@ function selfChat(req, agentId, message, conversationId, label = 'SelfChat') { | @@ -80,10 +80,25 @@ function selfChat(req, agentId, message, conversationId, label = 'SelfChat') { | ||
| 80 | port: req?.socket?.localPort || systemConfig.port, | 80 | port: req?.socket?.localPort || systemConfig.port, |
| 81 | path: `/api/agent/${agentId}/chat`, | 81 | path: `/api/agent/${agentId}/chat`, |
| 82 | method: 'POST', | 82 | method: 'POST', |
| 83 | - headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) }, | 83 | + // 本文件顶部 router.use(requireAuthOrInternal) 之后,这条自环 fetch 也要带内部令牌, |
| 84 | + // 否则 401——之前漏了这一处,TaskDispatch/TaskCallback/TaskTransition/TaskReject/ | ||
| 85 | + // HumanRequest 全部 7 个调用点静默失败(下面 chatRes 分支之前不看 statusCode, | ||
| 86 | + // 401 也照样打印"✅ 已唤醒",症状跟 claude-cli-session-leak.md 那次一样是静默的)。 | ||
| 87 | + headers: { | ||
| 88 | + 'Content-Type': 'application/json', | ||
| 89 | + 'Content-Length': Buffer.byteLength(postData), | ||
| 90 | + [INTERNAL_TOKEN_HEADER]: INTERNAL_TOKEN, | ||
| 91 | + }, | ||
| 84 | }, (chatRes) => { | 92 | }, (chatRes) => { |
| 85 | - chatRes.on('data', () => {}); | ||
| 86 | - chatRes.on('end', () => console.log(`[${label}] ✅ 已唤醒 ${agentId} (conv: ${conversationId})`)); | 93 | + let body = ''; |
| 94 | + chatRes.on('data', (c) => { body += c; }); | ||
| 95 | + chatRes.on('end', () => { | ||
| 96 | + if (chatRes.statusCode >= 400) { | ||
| 97 | + console.error(`[${label}] ❌ 唤醒 ${agentId} 失败: HTTP ${chatRes.statusCode} ${body.slice(0, 200)} (conv: ${conversationId})`); | ||
| 98 | + } else { | ||
| 99 | + console.log(`[${label}] ✅ 已唤醒 ${agentId} (conv: ${conversationId})`); | ||
| 100 | + } | ||
| 101 | + }); | ||
| 87 | }); | 102 | }); |
| 88 | chatReq.on('error', (err) => console.error(`[${label}] ❌ 回调失败: ${err.message}`)); | 103 | chatReq.on('error', (err) => console.error(`[${label}] ❌ 回调失败: ${err.message}`)); |
| 89 | chatReq.write(postData); | 104 | chatReq.write(postData); |