feat: Phase 3 model toggle — cycle chat-role slot models in UI
Replaces the role-cycle toggle with a slot model toggle in the Context & Memory panel. The active model label is shown on the button; clicking cycles through Primary → Backup 1 → Backup 2 slots configured for the Chat role. - app.js: remove activeRole()/availableRoles role-cycling; add activeChatModel()/chatModels slot cycling; update send/orchestrate payloads to send slot + chat_role:"chat"; fix updateSendBtnTitle and startRunTimer to use activeChatModel() - chat.py: add slot field to ChatRequest; pass slot= to complete(); resolve backend_label from slot config; add _chat_slot_models() helper; include chat_models in GET /backend response - HELP.md: update Model toggle description, tool count (62/16), Backends section, API chat payload example Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,7 @@ class ChatRequest(BaseModel):
|
||||
session_id: str | None = None
|
||||
tier: int | None = None
|
||||
model: str | None = None # legacy backend override ("claude"|"gemini"|"local")
|
||||
slot: str | None = None # Phase 3: explicit slot ("primary"|"backup_1"|"backup_2")
|
||||
chat_role: str = "chat" # active role: "chat"|"coder"|"research"|"distill" etc.
|
||||
include_long: bool = True
|
||||
include_mid: bool = True
|
||||
@@ -109,6 +110,7 @@ async def _stream_chat(req: ChatRequest):
|
||||
messages=history,
|
||||
model=req.model,
|
||||
role=req.chat_role,
|
||||
slot=req.slot,
|
||||
))
|
||||
|
||||
try:
|
||||
@@ -124,7 +126,11 @@ async def _stream_chat(req: ChatRequest):
|
||||
|
||||
try:
|
||||
response_text, actual_backend = task.result()
|
||||
backend_label = _role_model_label(user, req.chat_role, actual_backend)
|
||||
if req.slot:
|
||||
slot_cfg = model_registry.get_model_for_slot(user, req.chat_role, req.slot)
|
||||
backend_label = (slot_cfg or {}).get("label") or _role_model_label(user, req.chat_role, actual_backend)
|
||||
else:
|
||||
backend_label = _role_model_label(user, req.chat_role, actual_backend)
|
||||
host = platform.node()
|
||||
history.append({
|
||||
"role": "assistant",
|
||||
@@ -203,6 +209,25 @@ def _local_model_info(request: Request) -> dict | None:
|
||||
return None
|
||||
|
||||
|
||||
def _chat_slot_models(username: str) -> list[dict]:
|
||||
"""Return [{slot, label, type}] for each configured slot in the chat role, primary first."""
|
||||
registry = model_registry.get_registry(username)
|
||||
role_slots = registry.get("roles", {}).get("chat", {})
|
||||
result = []
|
||||
for slot_key in model_registry.PRIORITY_KEYS:
|
||||
model_id = role_slots.get(slot_key)
|
||||
if not model_id:
|
||||
continue
|
||||
resolved = model_registry._resolve_model(registry, model_id)
|
||||
if resolved:
|
||||
result.append({
|
||||
"slot": slot_key,
|
||||
"label": resolved.get("label") or resolved.get("model_name") or "",
|
||||
"type": resolved.get("type", ""),
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def _available_roles_for_toggle(username: str) -> list[dict]:
|
||||
"""Return roles with a primary model assigned (excluding orchestrator) for the UI toggle.
|
||||
|
||||
@@ -231,6 +256,7 @@ def _available_roles_for_toggle(username: str) -> list[dict]:
|
||||
@router.get("/backend")
|
||||
async def get_backend(request: Request) -> dict:
|
||||
username = _request_user(request)
|
||||
chat_models = _chat_slot_models(username) if username else []
|
||||
available_roles = _available_roles_for_toggle(username) if username else []
|
||||
p = settings.primary_backend
|
||||
|
||||
@@ -241,7 +267,8 @@ async def get_backend(request: Request) -> dict:
|
||||
orch_label = orch_cfg.get("label") or orch_cfg.get("model_name") or None
|
||||
|
||||
return {
|
||||
"available_roles": available_roles,
|
||||
"chat_models": chat_models, # Phase 3: [{slot, label, type}] for chat-role slots
|
||||
"available_roles": available_roles, # kept for banner + backward compat
|
||||
"orchestrator_model": orch_label,
|
||||
# Legacy fields kept for backward compat
|
||||
"primary": p,
|
||||
|
||||
Reference in New Issue
Block a user