mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-14 03:30:19 +00:00
fdb4f37053
* ♻️ refactor(hetero-agent): shared subagent-run coordinator + fix device-mode subagent streaming Remote-device (gateway) hetero runs corrupted SubAgent text on the wire: the CLI `SerialServerIngester`'s main-agent text-snapshot coalescing was subagent- unaware, so subagent full-block text got mixed into the main accumulator and re-`append`ed as `replace` snapshots server-side. Fix: exclude `data.subagent` text from the coalescer so it forwards raw (the server appends it once). The deeper cause was duplication: the renderer executor and the server persistence handler each hand-wrote the SAME subagent-run state machine (lazy thread create, turn-boundary cut, finalize, orphan drain, chain parenting) — the epicenter of past hetero subagent bugs. Extract it into ONE pure, transactional reducer (`reduceSubagentRuns`) in `@lobechat/heterogeneous-agents` that emits declarative intents; each engine keeps a thin interpreter for its own I/O (renderer: messageService + live store dispatch; server: messageModel). The reducer pre-allocates ids so intents carry parentId chains with no create→backfill round-trip; this needs `messageService.createMessage` to accept a caller id (threaded through; the model already supported it). Also widened the message nanoid 14→18 for the higher per-run id volume. Behavior unifications (vs the two old copies): - transactional commit-on-success subsumes the renderer's `pendingFlushTarget` (a failed flush leaves the run intact for the onComplete-drain retry; the renderer keeps a local pending-flush map pinned to the original assistant). - finalize DELETES the run (server-style); a second finalize / orphan drain is a clean no-op with the same DB end-state. Scoped to subagent runs only; main-agent persistence stays per-engine. A future pass can absorb the main-agent path into a unified agent-event reducer. Tests: reducer 13, CLI hetero 22, server hetero 84, renderer executor 58. Refs: LOBE-10175 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ✅ test(hetero-agent): strengthen subagent flush-retry assertion The earlier rewrite of this assertion (caused by ids moving from server- generated to caller-pre-allocated) weakened it to "all streamed writes share one id", which would also pass if they all wrongly hit the terminal row. Pin it back to the test's real intent: resolve the FIRST streaming-turn assistant by its create payload and assert every streamed write targets it AND that it differs from the terminal assistant's id — so `resultContent` is never clobbered. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * 🐛 fix(hetero-agent): honor commit-on-success for renderer subagent intents + fix stale id-length tests - renderer interpreter: createThread / createMessage failures now rethrow so reduceAndApplySubagent skips the state commit — the next event retries the lazy create / turn boundary instead of orphaning the run (review P2) - catch around the intent loop so a failed intent can't poison persistQueue - regression test: transient createThread failure retries on next event - update message id length assertions 18 → 22 (nanoid widened 14→18 + msg_) - update messageService.createMessage spy assertions for the new (params, id) call Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>