Commit b095d3a73f72aa6509b1d03039bd36dbd3f86b11
1 parent
598bef1e
perf: reuse existing session for task callbacks to save ~30K tokens/callback
When a task completes and triggers a callback to the parent agent,
previously it always created a new convId (callback-{taskId}), spawning
a fresh CLI process with full system prompt re-injection.
Now it checks the sessions pool for an existing connected session of the
target agent and reuses its convId. This avoids creating a new CLI
process and saves the system prompt overhead (~30K tokens for master).
Falls back to creating new session if no active one exists.
Showing
1 changed file
with
25 additions
and
1 deletions
server/routes/agent-chat.js
| ... | ... | @@ -665,10 +665,25 @@ async function getOrCreateProtocol(agentId, convId) { |
| 665 | 665 | |
| 666 | 666 | const protocol = new ClaudeCliProtocol({ name: identity.name }, cliOptions); |
| 667 | 667 | |
| 668 | + const releaseLock = () => { | |
| 669 | + const lock = agentChatLocks.get(agentId); | |
| 670 | + if (lock && lock.convId === convId) { | |
| 671 | + agentChatLocks.delete(agentId); | |
| 672 | + console.log(`[AgentChat] 🔓 ${identity.name} 锁已释放 (conv: ${convId})`); | |
| 673 | + } | |
| 674 | + }; | |
| 675 | + | |
| 668 | 676 | // 绑定错误监听器,防止 EventEmitter 抛出未捕获异常导致整个 Node 进程奔溃 (例如 spawn claude ENOENT) |
| 669 | 677 | protocol.on('error', (err) => { |
| 670 | 678 | console.error(`[AgentChat] 🚨 ${identity.name} 协议级异常:`, err.message); |
| 671 | 679 | sessions.delete(key); // 下次提问将重建进程 |
| 680 | + releaseLock(); | |
| 681 | + }); | |
| 682 | + | |
| 683 | + protocol.on('disconnected', ({ code, signal }) => { | |
| 684 | + sessions.delete(key); | |
| 685 | + releaseLock(); | |
| 686 | + console.log(`[AgentChat] 💤 ${identity.name} 会话断开 (code=${code}, signal=${signal})`); | |
| 672 | 687 | }); |
| 673 | 688 | |
| 674 | 689 | await protocol.connect(null, agentDir); |
| ... | ... | @@ -1733,7 +1748,16 @@ router.post('/task/report', (req, res) => { |
| 1733 | 1748 | try { |
| 1734 | 1749 | // 读取 task 元数据获取上下文 |
| 1735 | 1750 | const taskMeta = loadTaskMeta(taskId); |
| 1736 | - const callbackConvId = `callback-${taskId}`; | |
| 1751 | + | |
| 1752 | + // 💰 Token 优化:尝试复用目标 Agent 的已有 session,避免创建新 CLI 进程 | |
| 1753 | + let callbackConvId = `callback-${taskId}`; | |
| 1754 | + for (const [key, entry] of sessions.entries()) { | |
| 1755 | + if (key.startsWith(`${to}:`) && entry.protocol.isConnected) { | |
| 1756 | + callbackConvId = entry.convId; | |
| 1757 | + console.log(`[TaskCallback] ♻️ 复用 ${to} 已有 session: ${callbackConvId}`); | |
| 1758 | + break; | |
| 1759 | + } | |
| 1760 | + } | |
| 1737 | 1761 | |
| 1738 | 1762 | const statusText = status === 'done' ? '✅ 已完成' : '❌ 失败'; |
| 1739 | 1763 | const callbackMessage = `[TASK_CALLBACK]\n任务编号: ${taskId}\n执行者: ${from}\n状态: ${statusText}\n摘要: ${summary || '(无摘要)'}\n产出文件: ${outputs.length > 0 ? outputs.join(', ') : '(无)'}\n${taskMeta ? `原始任务: ${taskMeta.task}` : ''}\n\n**去重提醒**:在 dispatch 任何新任务前,请务必先检查目标 Agent 的 todo.md 和全局任务状态。如果同一目标已有相似任务在进行中,直接跳过即可,绝对禁止重复分发。\n\n请检查上述任务的执行结果,然后根据你的 plan.md 继续执行下一步计划。`; | ... | ... |