Add multi-model panel with Fusion mode
Panel agents answer the user prompt in parallel (read-only, non-streaming); their responses are merged into the worker's last user message as a <panel_responses> block, and the session agent synthesizes one final streamed answer. The RunPanel engine is built layer-ready for future MoA. - New session fields: multi_model_mode (off/fusion), panel_agent_ids (CSV) with idempotent column migration - New partial Services/AnthropicService.Panel.cs holding the RunPanel engine - Provider-agnostic members: Anthropic RunNonStreamingToolLoop / OpenAI CompleteText / CLI plan-mode; all forced read-only, persisted with Tag=panel - SSE events: panel_start, panel_member_start, panel_member_done, panel_done - Frontend: multi-agent picker, live panel bubbles, history rendering - Graceful degradation: panel errors fall back to worker-only Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
b23eba32b4
commit
268f11fa6d
20 files changed
+647
-35
No files matched your search
+13
-1
@@ -88,7 +88,7 @@ User 1──* TelegramBot 1──* Session (via telegram_bot_id)
|
||||
| `users` | Login, DisplayName, IsAdmin, Persona, Settings (JSON), DefaultPath |
|
||||
| `tokens` | Auth-Tokens → User |
|
||||
| `agents` | AI-Agenten (Model – z.B. `claude-sonnet-4-6` oder `nvidia:model-id`, CustomCommands, AutoCommit, UseSoul/Identity/UserInfo/Memory/AutoContext, UseGitHubSearch, UseSerperSearch, WebSearch, AllowUserChoice, TaskInstruction, Effort, AvatarScale/Offset, AvatarSmall, IsPublic) |
|
||||
| `sessions` | Chat-Sessions (Description, Image, ImageSmall, Workspace, Context, CustomCommands, TelegramBotId, TelegramChatId, AvatarScale/Offset, PreparerAgentId, ReviewAgentId, MaxReviewIterations, FinalizerAgentId) |
|
||||
| `sessions` | Chat-Sessions (Description, Image, ImageSmall, Workspace, Context, CustomCommands, TelegramBotId, TelegramChatId, AvatarScale/Offset, PreparerAgentId, ReviewAgentId, MaxReviewIterations, FinalizerAgentId, MultiModelMode, PanelAgentIds) |
|
||||
| `chains` | Ein Request-Response-Zyklus (Tokens, Timing, Iterations, PlanMode, ToolChoice, ToolNames, StreamErrorInfo, ArchiveId) |
|
||||
| `messages` | Einzelne Nachrichten (text / tool_use / tool_result / error / web_search_result / auto_context), Tag für Sub-Agent-Markierung oder Import-Herkunft (`openclaw-import`), thought_signature (Gemini) |
|
||||
| `attachments` | Base64-Anhänge (Bilder, Dokumente) |
|
||||
@@ -347,6 +347,18 @@ Eine Session kann bis zu **vier Agents** haben: Worker (Pflicht), Preparer (opti
|
||||
- History: `renderMarkdown` parst `[Preparer: AgentName]`, `[Vorbereitet von AgentName]`, `[Review: AgentName]`, `[Finalizer: AgentName]`, filtert `[APPROVED]`, `[FORWARD]`, `[QUESTION]`
|
||||
- Bubble-Klassen: `.preparer-bubble` (Info-Farbe), `.review-bubble` (sekundäre Farbe), `.finalizer-bubble` (grüne Farbe)
|
||||
|
||||
## Multi-Modell-Panel (Fusion)
|
||||
|
||||
Zusätzlich zum Worker kann eine Session ein **Panel** aus mehreren Agenten haben (`multi_model_mode = "fusion"`, `panel_agent_ids` = CSV der Agent-IDs). Bei jeder Nachricht antworten alle Panel-Agenten **parallel** auf die Anfrage; ihre Antworten werden dem **Worker** als `<panel_responses>`-Block in die letzte User-Message gemergt, der daraus **eine** Gesamtantwort synthetisiert und normal streamt (Fusion = OpenRouter-Fusion-/Mixture-of-Agents-Muster). Mehrschichtiges MoA ist als Aufbau geplant.
|
||||
|
||||
**Member laufen read-only** (Anthropic: `FilterReadOnlyTools` via `PlanMode`, CLI: `--permission-mode plan`, OpenAI: tool-los via `OpenAiService.CompleteText`) → keine parallelen Schreibkonflikte. Concurrency-Cap (3) begrenzt parallele CLI-Children.
|
||||
|
||||
**Backend:** `ChatService.PrepareContext` baut `ChatContext.PanelAgents` (`List<SubAgentContext>`) aus `panel_agent_ids`. `RunPanel()` (AnthropicService.Panel.cs) läuft im ChatEndpoint-try VOR dem Worker-Dispatch: Member parallel (`Task.WhenAll` + `SemaphoreSlim`), Provider-Weiche pro Member, jede Proposal als `[Panel: Name]`-Message mit `Tag="panel"` persistiert (aus Worker-History gefiltert, überlebt F5). `NonStreamingLoopCallbacks.Persist=false` verhindert Doppel-Persistenz der Member-Arbeit. Der Synthese-Block wird in den **bestehenden** Text-Block der letzten User-Message gemergt (damit auch der CLI-Worker via `ExtractLastUserText` ihn sieht). Panel-Fehler sind graceful (Worker läuft ohne Synthese weiter).
|
||||
|
||||
**SSE-Events:** `panel_start`, `panel_member_start`, `panel_member_done` (voller Text), `panel_done`.
|
||||
|
||||
**Frontend:** `stream-ui.js` rendert pro Member eine `.panel-bubble` (keyed by index; non-streaming → Bubble wird bei `_done` gefüllt). History: `history.js _renderPanelMemberBubble` rendert `Tag="panel"`-Messages als Panel-Bubbles. Picker: `#multiModelMode`-Dropdown + Mehrfach-Agenten-Picker (`_openMultiPickerModal`) in der Session-Bearbeitung.
|
||||
|
||||
**Web-Search Sources:**
|
||||
- `web_search_result`-Messages in DB gespeichert (Sources als JSON-Array, leere werden übersprungen)
|
||||
- History + Shared-Page: Tool-Box mit klickbaren Source-Links (Domain + Title)
|
||||
|
||||
Reference in new issue
Block a user