feat: replace backend/slot toggle with role selector
The backend toggle now cycles through configured roles (chat, coder, research, distill, etc.) instead of backup model slots within the chat role. Each role uses its own primary→backup chain from the registry. - ChatRequest.slot replaced by chat_role (default "chat") - GET /backend returns available_roles instead of chat_models - _available_roles_for_toggle() builds list from defined_roles, excluding orchestrator (which has its own Agent mode) - Model label on responses now reflects the actual role's assigned model - Toggle is inert when only one role is configured (avoids useless cycling) - Add "Clear browser cache" button to Account Settings (Connected Accounts) - Add _role_model_label() helper for cleaner response tag labeling Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -339,49 +339,48 @@
|
||||
document.addEventListener('click', () => personaDropEl.classList.remove('open'));
|
||||
}
|
||||
|
||||
// ── Backend toggle ───────────────────────────────────────────
|
||||
// Phase 3: cycles through the chat role's configured models by label.
|
||||
// Sends slot ("primary"|"backup_1"|"backup_2") in chat requests.
|
||||
// Falls back to legacy "auto" behavior when no models are configured.
|
||||
// ── Role toggle ──────────────────────────────────────────────
|
||||
// Cycles through roles that have a primary model assigned (excluding orchestrator).
|
||||
// Sends chat_role ("chat"|"coder"|"research"|...) in chat requests.
|
||||
// Falls back to "chat" when no roles are configured in the registry.
|
||||
|
||||
const TYPE_CLASS = { claude_cli: '', gemini_api: 'mem-on', gemini_cli: 'mem-on', local_openai: 'local-on' };
|
||||
const backendModelHint = document.getElementById('backend-model-hint');
|
||||
|
||||
let chatSlots = []; // [{slot, label, type}] from /backend
|
||||
let slotIdx = 0; // index into chatSlots; -1 = auto (no registry models)
|
||||
let availableRoles = []; // [{role, label, model_label, type}] from /backend
|
||||
let roleIdx = 0;
|
||||
|
||||
function activeSlot() {
|
||||
return chatSlots.length > 0 ? chatSlots[slotIdx] : null;
|
||||
function activeRole() {
|
||||
return availableRoles.length > 0 ? availableRoles[roleIdx] : null;
|
||||
}
|
||||
|
||||
function setToggleUI(entry) {
|
||||
function setRoleToggleUI(entry) {
|
||||
if (!entry) {
|
||||
backendToggle.textContent = 'auto';
|
||||
backendToggle.textContent = 'chat';
|
||||
backendToggle.className = 'ctx-btn';
|
||||
primaryBackend = null;
|
||||
} else {
|
||||
backendToggle.textContent = entry.label;
|
||||
backendToggle.className = 'ctx-btn ' + (TYPE_CLASS[entry.type] || '');
|
||||
primaryBackend = entry.slot; // used as legacy compat in payload
|
||||
}
|
||||
if (backendModelHint) {
|
||||
backendModelHint.textContent = '';
|
||||
backendModelHint.style.display = 'none';
|
||||
const hint = entry?.model_label || '';
|
||||
backendModelHint.textContent = hint;
|
||||
backendModelHint.style.display = hint ? '' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
fetch('/backend').then(r => r.json()).then(d => {
|
||||
chatSlots = d.chat_models || [];
|
||||
slotIdx = 0;
|
||||
setToggleUI(chatSlots[0] || null);
|
||||
availableRoles = d.available_roles || [];
|
||||
roleIdx = 0;
|
||||
setRoleToggleUI(availableRoles[0] || null);
|
||||
});
|
||||
|
||||
backendToggle.addEventListener('click', () => {
|
||||
if (chatSlots.length === 0) return;
|
||||
slotIdx = (slotIdx + 1) % chatSlots.length;
|
||||
const entry = chatSlots[slotIdx];
|
||||
setToggleUI(entry);
|
||||
addMessage('system', `Backend: ${entry.label}`);
|
||||
if (availableRoles.length <= 1) return;
|
||||
roleIdx = (roleIdx + 1) % availableRoles.length;
|
||||
const entry = availableRoles[roleIdx];
|
||||
setRoleToggleUI(entry);
|
||||
addMessage('system', `Role: ${entry.label} · ${entry.model_label}`);
|
||||
});
|
||||
|
||||
// ── Sessions panel ───────────────────────────────────────────
|
||||
@@ -1056,7 +1055,7 @@
|
||||
include_mid: memMid,
|
||||
include_short: memShort,
|
||||
off_record: current_mode === 'otr',
|
||||
slot: activeSlot()?.slot || null,
|
||||
chat_role: activeRole()?.role || 'chat',
|
||||
user: CORTEX_USER,
|
||||
persona: CORTEX_PERSONA,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user