From 2b943aed188f670798eb3cc2194dee102f8fe0a4 Mon Sep 17 00:00:00 2001 From: Jeuners Date: Mon, 15 Jun 2026 03:15:53 +0200 Subject: [PATCH] Show current LLM model next to each agent in the UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - engine/agents.all_agents() now enriches each agent row with its currently-assigned model (model_for_agent) and provider (provider_for_model). Same source of truth as the LLM client. - web/app.js refreshAgentCards() shows a coloured tag next to the agent name: a green '๐Ÿ’ป ' badge for local Ollama models, a yellow 'โ˜ ' badge for OpenRouter models. The full model name is in the title attribute (hover). - web/style.css: .model-tag.local / .cloud colour palette. - Short name helper strips 'org/' prefix and ':latest' suffix for readability (e.g. 'anthropic/claude-3.5-haiku' -> 'claude-3.5-haiku'). All 100 tests still pass. Live: Anchor + Flora show 'โ˜ claude-3.5-haiku' / 'โ˜ gpt-4o-mini', Lovely + Spark show '๐Ÿ’ป gemma4' (running on 192.168.1.245). --- engine/agents.py | 11 +++++++++++ web/app.js | 18 +++++++++++++++++- web/style.css | 4 ++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/engine/agents.py b/engine/agents.py index 01dfc65..0aa72c2 100644 --- a/engine/agents.py +++ b/engine/agents.py @@ -58,6 +58,17 @@ def bootstrap(): def all_agents(): + """Return live agents with their currently-assigned LLM model.""" + from . import llm as llm_mod + agents = _all_agents_raw() + for a in agents: + a["model"] = llm_mod.model_for_agent(a["id"]) + a["provider"] = llm_mod.provider_for_model(a["model"]) + return agents + + +def _all_agents_raw(): + import sqlite3 c = sqlite3.connect(db.DB_PATH, check_same_thread=False) c.row_factory = sqlite3.Row try: diff --git a/web/app.js b/web/app.js index 644d269..cb41cca 100644 --- a/web/app.js +++ b/web/app.js @@ -80,6 +80,21 @@ function draw() { } } +function shortModel(name) { + if (!name) return ''; + // Strip org/ prefix and :tag for compactness + const s = name.replace(/^.*\//, '').replace(/:latest$/, ''); + return s; +} + +function modelTag(m, provider) { + if (!m) return ''; + const isCloud = provider === 'openrouter' || (m || '').includes('/'); + const cls = isCloud ? 'cloud' : 'local'; + const label = isCloud ? 'โ˜ ' + shortModel(m) : '๐Ÿ’ป ' + shortModel(m); + return `${label}`; +} + function refreshAgentCards() { const wrap = document.getElementById('agentList'); wrap.innerHTML = ''; @@ -87,7 +102,8 @@ function refreshAgentCards() { const div = document.createElement('div'); div.className = 'agent-card'; div.innerHTML = ` -

${a.name} ยท ${a.role}

+

${a.name}${modelTag(a.model, a.provider)}

+
${a.role}
at (${a.x}, ${a.y}) ยท ${a.mood}
diff --git a/web/style.css b/web/style.css index aded9d0..fbea403 100644 --- a/web/style.css +++ b/web/style.css @@ -53,6 +53,10 @@ aside h2 { font-size: 12px; text-transform: uppercase; letter-spacing: 1px; #feed li .why { color: #6c8aa6; font-style: italic; } .agent-card { background: #0a1018; border: 1px solid #1c2733; padding: 8px; margin: 6px 0; } .agent-card h3 { margin: 0 0 4px; font-size: 13px; } +.agent-card .model-tag { display: inline-block; font-size: 9px; padding: 1px 5px; border-radius: 3px; margin-left: 4px; vertical-align: middle; font-weight: normal; } +.agent-card .model-tag.local { background: #1a2a1a; color: #6cf0c2; border: 1px solid #2a3a2a; } +.agent-card .model-tag.cloud { background: #2a2a1a; color: #ffd166; border: 1px solid #3a3a1a; } +.agent-card .model-tag.short { background: #1c2733; color: #8aa1b6; } .agent-card .bar { height: 4px; background: #1c2733; margin: 2px 0; border-radius: 2px; } .agent-card .bar > i { display: block; height: 100%; border-radius: 2px; } .bar.energy > i { background: #ffd166; }