Stream panel member responses live with a parallel SSE write-lock

Panel members now stream token-by-token and show tool uses in real time
(like the session agent) instead of delivering text only at completion.
The key constraint is byte-level safety: N members flushing SSE frames
concurrently on the shared HttpResponse would interleave and corrupt the
stream, so a SemaphoreSlim gate serializes the writes (not the model work).

- SseHelper.TryWriteSse takes an optional write-lock (default null, backward
  compatible)
- NonStreamingLoopCallbacks carries SseGate + MemberIndex; _text/_tool/_error
  events are tagged with the member index (review/finalizer stay at -1, no gate)
- CLI members forward TextDelta/ToolStart/ToolResult live instead of
  discarding everything but the final text
- Anthropic-API members stream per tool-round via the loop callbacks; OpenAI
  members fall back to collected text at panel_member_done
- Frontend demuxes by member index into per-bubble interleaved text/tool
  rendering

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MelekiandClaude Opus 4.8 committed 2026-06-18 13:18:13 +02:00
1 parent 268f11fa6d
commit f21ed9ff9f
5 files changed
+183 -34

No files matched your search

+18 -1
View File
@@ -128,7 +128,7 @@ function handleStreamEvent(eventType, data) {
finalizeReviewBubble('done', data, 'finalizer');
break;
// Multi-Modell-Panel (Fusion): mehrere Member parallel, non-streaming
// Multi-Modell-Panel (Fusion): mehrere Member streamen parallel LIVE
case 'panel_start':
startPanel(data);
break;
@@ -137,6 +137,23 @@ function handleStreamEvent(eventType, data) {
addPanelMemberBubble(data);
break;
case 'panel_member_text':
appendPanelMemberText(data);
break;
case 'panel_member_tool_use':
addPanelMemberToolUse(data);
break;
// tool_end = CLI (offene Box füllen); tool = Anthropic-Loop (kombiniert → fertige Box)
case 'panel_member_tool_end': case 'panel_member_tool':
finishPanelMemberTool(data);
break;
case 'panel_member_error':
appendPanelMemberText({ index: data.index, text: '\n\n_[Fehler: ' + (data.error || 'unbekannt') + ']_' });
break;
case 'panel_member_done':
finalizePanelMember(data);
break;