Merge plan and panel toggles into one composer button
The composer had two separate mode buttons (plan + panel). Fold them into a
single #planModeBtn that cycles through every operating mode in one place:
Off -> Plan -> Fusion -> MoA -> Off. Cleaner UI, one affordance instead of two.
Plan stays transient (reset on session switch, never persisted) while
Fusion/MoA persist to the session via apiUpdateSession({multiModelMode}) and
are read server-side from ctx.MultiModelMode. The compat var _planModeActive
is kept in sync (true iff mode === 'plan') so sendMessage and modals.js read
it unchanged. No text label — icon + tint only.
- index.html: drop the separate panel button, reuse #planModeBtn
- chat.css: unified states (plan/fusion/moa tints) on #planModeBtn
- chat.js: cycleCompositeMode / initCompositeMode / _renderCompositeBtn
replace the split plan/panel functions
- chat-page.js: single wiring block, init from session.multiModelMode
- ARCHITECTURE_QUICK.md: document the unified toggle
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
47557c9724
commit
1b203707ec
5 files changed
+103
-20
No files matched your search
@@ -361,7 +361,7 @@ Zusätzlich zum Worker kann eine Session ein **Panel** aus mehreren Agenten habe
|
||||
|
||||
**SSE-Events:** `panel_start` (mode/layers), `panel_layer_start`/`panel_layer_done` (MoA-Runden), `panel_member_start` (mit `layer`), `panel_member_text`/`panel_member_tool_use`/`panel_member_tool_end`/`panel_member_tool` (live), `panel_member_done`, `panel_done`.
|
||||
|
||||
**Frontend:** `stream-ui.js` rendert pro Member eine `.panel-bubble`, gekeyt per `layer_index` (MoA: gleiche Member über mehrere Runden; aktive Runde pro Index wird bei `panel_member_start` gemerkt, da Runden sequenziell laufen). `panel_layer_start` zeigt bei >1 Runde einen `.panel-layer-divider`. History: `history.js _renderPanelMemberBubble` rendert `Tag="panel"`-Messages. Picker: `#multiModelMode`-Dropdown (Aus/Fusion/MoA) + `#moaLayers` + Mehrfach-Agenten-Picker (`_openMultiPickerModal`).
|
||||
**Frontend:** `stream-ui.js` rendert pro Member eine `.panel-bubble`, gekeyt per `layer_index` (MoA: gleiche Member über mehrere Runden; aktive Runde pro Index wird bei `panel_member_start` gemerkt, da Runden sequenziell laufen). `panel_layer_start` zeigt bei >1 Runde einen `.panel-layer-divider`. History: `history.js _renderPanelMemberBubble` rendert `Tag="panel"`-Messages. Picker: `#multiModelMode`-Dropdown (Aus/Fusion/MoA) + `#moaLayers` + Mehrfach-Agenten-Picker (`_openMultiPickerModal`). Vereinter Composer-Toggle: **ein** Button `#planModeBtn` (chat.js `cycleCompositeMode`) schaltet zyklisch Aus→Plan→Fusion→MoA durch. Plan ist transient (Compat-Var `_planModeActive`), Fusion/MoA werden sofort via `apiUpdateSession({multiModelMode})` persistiert – gleiche Quelle wie der Picker.
|
||||
|
||||
**Web-Search Sources:**
|
||||
- `web_search_result`-Messages in DB gespeichert (Sources als JSON-Array, leere werden übersprungen)
|
||||
|
||||
+11
-1
@@ -436,12 +436,22 @@
|
||||
color: var(--dangerous);
|
||||
}
|
||||
|
||||
/* Plan Mode Toggle */
|
||||
/* Unified Modus-Toggle: Aus / Plan / Fusion / MoA (ein einziger #planModeBtn) */
|
||||
#planModeBtn.plan-mode-active {
|
||||
color: var(--primary);
|
||||
background: color-mix(in srgb, var(--primary) 15%, transparent);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
#planModeBtn.panel-mode-fusion {
|
||||
color: var(--primary);
|
||||
background: color-mix(in srgb, var(--primary) 15%, transparent);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
#planModeBtn.panel-mode-moa {
|
||||
color: var(--primary);
|
||||
background: color-mix(in srgb, var(--primary) 28%, transparent);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
/* Emoji Picker */
|
||||
|
||||
|
||||
+1
-1
@@ -455,7 +455,7 @@
|
||||
<input type="file" id="fileInput" accept="image/jpeg,image/png,image/gif,image/webp,application/pdf" multiple hidden>
|
||||
<button id="fileBtn" class="icon-btn" title="Datei anhängen"><i class="fa fa-paperclip"></i></button>
|
||||
<button id="explorerBtn" class="icon-btn" title="Workspace durchsuchen"><i class="fa fa-folder"></i></button>
|
||||
<button id="planModeBtn" class="icon-btn" title="Plan-Modus umschalten"><i class="fa fa-map"></i></button>
|
||||
<button id="planModeBtn" class="icon-btn" title="Plan-Modus / Panel umschalten"><i class="fa fa-map"></i></button>
|
||||
<textarea id="input" placeholder="Nachricht..." rows="1"></textarea>
|
||||
<button id="emojiBtn" class="icon-btn" title="Emoji einfügen"><i class="fa fa-smile-o"></i></button>
|
||||
<button id="send" class="icon-btn"><i class="fa fa-paper-plane"></i></button>
|
||||
|
||||
+84
-10
@@ -223,20 +223,94 @@ function handleStreamEvent(eventType, data) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Plan Mode ──
|
||||
// ── Unified Modus-Toggle (Aus / Plan / Fusion / MoA) ──
|
||||
//
|
||||
// Ein einziger Button (#planModeBtn) schaltet zyklisch durch alle Betriebsmodi:
|
||||
// Aus → Plan-Modus → Fusion (Panel) → MoA (Panel) → Aus
|
||||
//
|
||||
// Plan-Modus ist transient (wird bei Session-Wechsel zurückgesetzt, nie in der Session
|
||||
// persistiert). Fusion/MoA werden in der Session persistiert (apiUpdateSession) und
|
||||
// server-seitig aus ctx.MultiModelMode gelesen – daher reicht ein PATCH.
|
||||
//
|
||||
// _planModeActive bleibt als Compat-Variable (sendMessage + modals.js lesen sie direkt).
|
||||
|
||||
let _planModeActive = false;
|
||||
let _compositeMode = 'off'; // 'off' | 'plan' | 'fusion' | 'moa'
|
||||
let _compositeHasAgents = false;
|
||||
|
||||
function togglePlanMode() {
|
||||
_planModeActive = !_planModeActive;
|
||||
// Compat-Variablen – werden durch cycleCompositeMode / initCompositeMode synchron gehalten
|
||||
let _planModeActive = false; // true genau wenn _compositeMode === 'plan'
|
||||
|
||||
const _COMPOSITE_ORDER = ['off', 'plan', 'fusion', 'moa'];
|
||||
|
||||
function _renderCompositeBtn() {
|
||||
var btn = $('#planModeBtn');
|
||||
if (btn) {
|
||||
btn.classList.toggle('plan-mode-active', _planModeActive);
|
||||
btn.title = _planModeActive ? 'Plan-Modus deaktivieren' : 'Plan-Modus aktivieren';
|
||||
}
|
||||
if (!btn) return;
|
||||
btn.classList.remove('plan-mode-active', 'panel-mode-fusion', 'panel-mode-moa');
|
||||
var icon = btn.querySelector('i');
|
||||
var input = $('#input');
|
||||
if (input) {
|
||||
input.placeholder = _planModeActive ? 'Plannen...' : 'Nachricht...';
|
||||
if (_compositeMode === 'plan') {
|
||||
btn.classList.add('plan-mode-active');
|
||||
if (icon) icon.className = 'fa fa-map';
|
||||
btn.title = 'Plan-Modus aktiv · klicken → Fusion';
|
||||
if (input) input.placeholder = 'Planen...';
|
||||
} else if (_compositeMode === 'fusion') {
|
||||
btn.classList.add('panel-mode-fusion');
|
||||
if (icon) icon.className = 'fa fa-users';
|
||||
btn.title = 'Fusion aktiv · klicken → MoA';
|
||||
if (input) input.placeholder = 'Nachricht...';
|
||||
} else if (_compositeMode === 'moa') {
|
||||
btn.classList.add('panel-mode-moa');
|
||||
if (icon) icon.className = 'fa fa-clone';
|
||||
btn.title = 'MoA aktiv · klicken → Aus';
|
||||
if (input) input.placeholder = 'Nachricht...';
|
||||
} else {
|
||||
if (icon) icon.className = 'fa fa-map';
|
||||
btn.title = 'Plan-Modus / Panel umschalten';
|
||||
if (input) input.placeholder = 'Nachricht...';
|
||||
}
|
||||
}
|
||||
|
||||
// Initialisiert den Button aus der geladenen Session (bei jedem Chat-Wechsel aufrufen).
|
||||
// Plan-Modus wird immer auf 'off' zurückgesetzt (transient).
|
||||
function initCompositeMode(panelMode, hasAgents) {
|
||||
_compositeHasAgents = !!hasAgents;
|
||||
_compositeMode = (panelMode === 'fusion' || panelMode === 'moa') ? panelMode : 'off';
|
||||
_planModeActive = false;
|
||||
_renderCompositeBtn();
|
||||
}
|
||||
|
||||
// Schaltet Aus → Plan → Fusion → MoA → Aus durch.
|
||||
// Fusion/MoA werden sofort in die Session persistiert; Plan-Modus ist transient (kein Server-Call).
|
||||
async function cycleCompositeMode() {
|
||||
var idx = _COMPOSITE_ORDER.indexOf(_compositeMode);
|
||||
_compositeMode = _COMPOSITE_ORDER[(idx + 1) % _COMPOSITE_ORDER.length];
|
||||
_planModeActive = (_compositeMode === 'plan');
|
||||
_renderCompositeBtn();
|
||||
|
||||
// Nur Fusion/MoA/Off brauchen einen Server-Call (Plan ist transient)
|
||||
if (_compositeMode !== 'plan') {
|
||||
var sid = getCurrentSessionId();
|
||||
if (sid) {
|
||||
try {
|
||||
await apiUpdateSession(sid, { multiModelMode: _compositeMode });
|
||||
} catch (e) {
|
||||
console.error('Modus speichern fehlgeschlagen:', e);
|
||||
if (typeof showToast === 'function') showToast('Modus konnte nicht gespeichert werden', 'error');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof showToast === 'function') {
|
||||
if (_compositeMode === 'off') {
|
||||
showToast('Modus: Aus', 'info');
|
||||
} else if (_compositeMode === 'plan') {
|
||||
showToast('Plan-Modus aktiv', 'info');
|
||||
} else if (!_compositeHasAgents) {
|
||||
showToast('Panel: ' + (_compositeMode === 'moa' ? 'MoA' : 'Fusion') + ' aktiv – aber keine Panel-Agenten konfiguriert (im Session-Bearbeiten festlegen)', 'info');
|
||||
} else {
|
||||
showToast('Panel: ' + (_compositeMode === 'moa' ? 'MoA' : 'Fusion') + ' aktiv', 'success');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -572,13 +572,12 @@ registerPage('chat', {
|
||||
});
|
||||
}
|
||||
|
||||
// Plan Mode Toggle
|
||||
const planModeBtn = document.getElementById('planModeBtn');
|
||||
if (planModeBtn) {
|
||||
// Plan-Modus bei Session-Wechsel zurücksetzen
|
||||
_planModeActive = false;
|
||||
planModeBtn.classList.remove('plan-mode-active');
|
||||
planModeBtn.addEventListener('click', togglePlanMode);
|
||||
// Unified Modus-Toggle (Aus / Plan / Fusion / MoA) – aus der Session initialisieren
|
||||
const compositeModeBtn = document.getElementById('planModeBtn');
|
||||
if (compositeModeBtn) {
|
||||
const hasPanelAgents = !!(session.panelAgentIds && String(session.panelAgentIds).trim());
|
||||
initCompositeMode(session.multiModelMode, hasPanelAgents);
|
||||
compositeModeBtn.addEventListener('click', cycleCompositeMode);
|
||||
}
|
||||
|
||||
// File Upload
|
||||
|
||||
Reference in new issue
Block a user