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:
122
app.py
122
app.py
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user