feat: unified model selector below mode toggle

- Model dropdown below mode switch applies to active agents
- In work mode: changes model for Rex/Maddy/Coder/Research + subagents
- In lab mode: changes model for Eric
- /api/apply-model endpoint: swap model + VRAM in current mode
- /api/switch accepts optional model param
- Removed separate lab model card (consolidated into one selector)
This commit is contained in:
2026-02-18 19:51:02 +00:00
parent d678a4d3d4
commit 786a72c06d
2 changed files with 180 additions and 156 deletions

122
app.py
View File

@@ -194,12 +194,21 @@ def status():
.get("primary", "unknown")
)
# Determine active ollama model based on mode
if mode == "work":
active_ollama = agent_details[0]["model"] if agent_details else WORK_PRIMARY
elif mode == "lab":
active_ollama = lab_info["model"]
else:
active_ollama = "unknown"
return jsonify({
"ok": True,
"mode": mode,
"lab": lab_info,
"agents": agent_details,
"subagentsPrimary": subagents_primary,
"activeOllamaModel": active_ollama,
})
except Exception as e:
return jsonify({"ok": False, "error": str(e)}), 500
@@ -215,54 +224,76 @@ def ollama_status():
return jsonify(ps)
def apply_model_to_agents(config, ollama_model, mode):
"""Apply the selected ollama model to the appropriate agents based on mode.
In work mode: update work agents (rex, maddy, coder, research) + subagents default.
In lab mode: update lab agent.
"""
if mode == "work":
for agent_id in OLLAMA_AGENTS:
agent = find_agent(config, agent_id)
if agent:
agent.setdefault("model", {})["primary"] = ollama_model
config.setdefault("agents", {}).setdefault("defaults", {}).setdefault("subagents", {}).setdefault("model", {})
config["agents"]["defaults"]["subagents"]["model"]["primary"] = ollama_model
elif mode == "lab":
lab = find_agent(config, "lab")
if lab:
lab.setdefault("model", {})["primary"] = ollama_model
@app.route("/api/switch", methods=["POST"])
def switch():
try:
data = request.json or {}
target_mode = data.get("mode", "work")
selected_model = data.get("model", None)
if target_mode == "lab":
new_primary = LAB_PRIMARY
target_ollama_model = None # lab model is managed separately
elif target_mode == "work":
new_primary = WORK_PRIMARY
target_ollama_model = "qwen3-128k:14b"
else:
if target_mode not in ("work", "lab"):
return jsonify({"ok": False, "error": f"Unknown mode: {target_mode}"}), 400
config = read_config()
# Determine which ollama model to load based on mode
if target_mode == "lab":
# Move work agents to groq
for agent_id in OLLAMA_AGENTS:
agent = find_agent(config, agent_id)
if agent:
agent.setdefault("model", {})["primary"] = LAB_PRIMARY
config.setdefault("agents", {}).setdefault("defaults", {}).setdefault("subagents", {}).setdefault("model", {})
config["agents"]["defaults"]["subagents"]["model"]["primary"] = LAB_PRIMARY
# If a model was selected, set it as the lab model
if selected_model and "ollama/" in selected_model:
lab = find_agent(config, "lab")
if lab:
lab.setdefault("model", {})["primary"] = selected_model
# Determine which ollama model to load for lab
lab = find_agent(config, "lab")
if lab:
lab_model = lab.get("model", {}).get("primary", "")
if "ollama/" in lab_model:
target_ollama_model = lab_model.replace("ollama/", "")
lab_model = lab.get("model", {}).get("primary", "") if lab else ""
target_ollama_model = lab_model.replace("ollama/", "") if "ollama/" in lab_model else None
# Patch each agent's primary model
for agent_id in OLLAMA_AGENTS:
agent = find_agent(config, agent_id)
if agent:
if "model" not in agent:
agent["model"] = {}
agent["model"]["primary"] = new_primary
# Patch subagents default
config.setdefault("agents", {}).setdefault("defaults", {}).setdefault("subagents", {}).setdefault("model", {})
config["agents"]["defaults"]["subagents"]["model"]["primary"] = new_primary
elif target_mode == "work":
# Use selected model or default
work_model = selected_model if selected_model and "ollama/" in selected_model else WORK_PRIMARY
for agent_id in OLLAMA_AGENTS:
agent = find_agent(config, agent_id)
if agent:
agent.setdefault("model", {})["primary"] = work_model
config.setdefault("agents", {}).setdefault("defaults", {}).setdefault("subagents", {}).setdefault("model", {})
config["agents"]["defaults"]["subagents"]["model"]["primary"] = work_model
target_ollama_model = work_model.replace("ollama/", "")
write_config(config)
restarted = restart_gateway()
# Unload current models and load the target model
# Swap VRAM: unload old, load+pin new
if target_ollama_model:
# First unload anything currently loaded
ps = ollama_ps()
for m in ps.get("models", []):
if m["name"] != target_ollama_model:
ollama_unload_model(m["name"])
# Load and pin the target model async
load_model_async(target_ollama_model)
return jsonify({
@@ -275,43 +306,36 @@ def switch():
return jsonify({"ok": False, "error": str(e)}), 500
@app.route("/api/lab-model", methods=["POST"])
def set_lab_model():
@app.route("/api/apply-model", methods=["POST"])
def apply_model():
"""Change the ollama model for agents in the current mode and swap VRAM."""
try:
data = request.json or {}
model = data.get("model", "")
if not model:
return jsonify({"ok": False, "error": "No model specified"}), 400
if not model or "ollama/" not in model:
return jsonify({"ok": False, "error": "Must be an ollama model"}), 400
config = read_config()
lab = find_agent(config, "lab")
if not lab:
return jsonify({"ok": False, "error": "Lab agent not found"}), 404
if "model" not in lab:
lab["model"] = {}
lab["model"]["primary"] = model
mode = detect_mode(config)
apply_model_to_agents(config, model, mode)
write_config(config)
restarted = restart_gateway()
# If currently in lab mode, load the new model
mode = detect_mode(config)
ollama_model_name = None
if mode == "lab" and "ollama/" in model:
ollama_model_name = model.replace("ollama/", "")
# Unload old models first
ps = ollama_ps()
for m in ps.get("models", []):
if m["name"] != ollama_model_name:
ollama_unload_model(m["name"])
load_model_async(ollama_model_name)
# Swap VRAM
ollama_model = model.replace("ollama/", "")
ps = ollama_ps()
for m in ps.get("models", []):
if m["name"] != ollama_model:
ollama_unload_model(m["name"])
load_model_async(ollama_model)
return jsonify({
"ok": True,
"model": model,
"mode": mode,
"restarted": restarted,
"loading_model": ollama_model_name,
"loading_model": ollama_model,
})
except Exception as e:
return jsonify({"ok": False, "error": str(e)}), 500