mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-13 19:20:04 +00:00
f47e65d215
* 🐛 fix(server): rehydrate subagent runs from DB on cold replica Server-side hetero persistence kept per-operation state in a module-level map. On a cold serverless replica (or any cross-replica batch), the main agent state is rebuilt from DB but `MainAgentRunState.subagents` was seeded empty. A continuing subagent event then hit the `!existing` branch of `ensureRun` and forked a brand-new isolation thread for a parentToolCallId that already had one — producing piles of generic "Subagent" threads that were never attached to the right thread. Desktop never hit this (one long-lived run-state closure). Rebuild `state.main.subagents` from DB the same way the main half is rehydrated: add `rehydrateSubagentRunsState` to @lobechat/heterogeneous-agents and call a new `refreshSubagentRunsFromDb` each ingest. Only runs MISSING from memory are rehydrated (warm accumulators win); finalized (Active) threads are excluded so completed spawns are never resurrected. Sibling of #15783 (main message chaining) — same root cause, subagent half. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(server): scope subagent rehydration to operation + de-dupe inner tools Two follow-up fixes on the cold-replica subagent rehydration: - P1: de-dupe inner tool creation against the run-lifetime tool set, not just the per-turn `persistedIds`. Per-turn state is reset on every turn boundary and starts empty after a rehydration, so a replayed / continued tools_calling on a cold replica minted a SECOND tool message for an id the run already wrote. `lifetimeToolCallIds` survives boundaries and is restored from DB, so it is the durable de-dupe key. Mirrors the main-agent retry protection. - P2: scope `refreshSubagentRunsFromDb` to the current operation. Topics are reused across turns; a prior crashed/cancelled run can leave a subagent thread stuck `Processing`. Rehydrating purely by topic+status would merge that unrelated thread into the new operation's reducer state and finalize it on the new run's terminal drain. Stamp `operationId` on the subagent thread metadata at creation and filter rehydration by it. Adds regression cases for both (each verified to fail without its fix). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>