diff --git a/llm_team_ui.py b/llm_team_ui.py
index 3424a27..316ce10 100644
--- a/llm_team_ui.py
+++ b/llm_team_ui.py
@@ -4229,8 +4229,10 @@ LAB_HTML = r"""
.btn-r:hover{background:rgba(224,82,82,0.06)}
.btn-o{border-color:rgba(245,158,11,0.3);color:var(--orange)}
.btn-o:hover{background:rgba(245,158,11,0.06)}
- .exp-item{background:rgba(0,0,0,0.25);border:2px solid var(--border);border-radius:2px;padding:14px;margin-bottom:8px;cursor:pointer;transition:border-color .15s}
+ .exp-item{background:rgba(0,0,0,0.25);border:2px solid var(--border);border-radius:2px;padding:14px;margin-bottom:8px;cursor:pointer;transition:all .15s}
.exp-item:hover{border-color:var(--accent)}
+ .exp-item.selected{border-color:var(--accent);background:var(--glow);box-shadow:0 0 12px rgba(226,181,90,0.08)}
+ .live-status{font-family:'JetBrains Mono',monospace;font-size:10px;color:var(--text2);margin-top:6px;min-height:14px;font-style:italic}
.exp-item .name{font-weight:600;font-size:14px}
.exp-item .meta{font-size:10px;color:var(--text2);display:flex;gap:12px;margin-top:4px;font-family:'JetBrains Mono',monospace}
.status-pill{display:inline-block;padding:2px 8px;border-radius:2px;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.5px;font-family:'JetBrains Mono',monospace;border:1px solid}
@@ -4349,12 +4351,13 @@ LAB_HTML = r"""
-
+
Status: idle
Trials: 0
Best: 0.0/10
Improvements: 0
+
Score Progression
@@ -4408,7 +4411,8 @@ function renderExpList() {
if (!experiments.length) { el.innerHTML = '
No experiments yet. Create one to get started.
'; return; }
el.innerHTML = experiments.map(e => {
const rate = e.total_trials > 0 ? ((e.improvements / e.total_trials) * 100).toFixed(0) : 0;
- return `
+ const sel = activeExp && activeExp.id === e.id ? ' selected' : '';
+ return `
${e.name} ${e.status}
Trials: ${e.total_trials}Best: ${(e.best_score||0).toFixed(1)}/10Improvements: ${e.improvements} (${rate}%)${e.metric}
`;
@@ -4421,7 +4425,16 @@ async function selectExp(id) {
trialData = activeExp.trials || [];
updateMonitor();
updateConfigEditor();
- toast('Loaded: ' + activeExp.name);
+ renderExpList();
+ // Auto-navigate to the relevant tab
+ if (activeExp.status === 'running') {
+ labTab('monitor');
+ startStream();
+ } else if (activeExp.status === 'idle' && activeExp.total_trials === 0) {
+ labTab('config');
+ } else {
+ labTab('monitor');
+ }
}
function updateMonitor() {
@@ -4507,12 +4520,21 @@ function startStream() {
activeExp.best_score = d.best;
if (d.improved) activeExp.improvements = (activeExp.improvements||0) + 1;
updateMonitor();
+ renderExpList();
+ } else if (d.type === 'status') {
+ var liveEl = document.getElementById('live-status');
+ if (liveEl) liveEl.textContent = d.message || '';
} else if (d.type === 'done') {
activeExp.status = 'paused';
updateMonitor();
+ renderExpList();
+ var liveEl = document.getElementById('live-status');
+ if (liveEl) liveEl.textContent = 'Completed';
es.close();
} else if (d.type === 'error') {
toast(d.message, false);
+ var liveEl = document.getElementById('live-status');
+ if (liveEl) liveEl.textContent = 'Error: ' + (d.message||'').substring(0,100);
}
};
es.onerror = function() { es.close(); };
@@ -7800,9 +7822,10 @@ def _ratchet_loop(exp_id):
# Pick meta-model (largest in pool)
meta_model = models_pool[-1] if models_pool else "qwen2.5:latest"
judge_model = models_pool[0] if models_pool else "llama3.2:latest"
- max_trials = 50 # safety cap — prevents runaway experiments
+ max_new_trials = 50 # safety cap — max trials per start
+ trials_this_run = 0
- while trial_num < max_trials:
+ while trials_this_run < max_new_trials:
# Check if still running
with get_db() as conn:
with conn.cursor() as cur:
@@ -7812,8 +7835,9 @@ def _ratchet_loop(exp_id):
break
trial_num += 1
+ trials_this_run += 1
trial_start = time.time()
- _lab_emit(exp_id, {"type": "status", "trial": trial_num, "message": "Proposing change..."})
+ _lab_emit(exp_id, {"type": "status", "trial": trial_num, "message": f"Proposing change... (trial {trials_this_run}/{max_new_trials})"})
# Step 1: Meta-model proposes a change
history_hint = ""
@@ -9721,6 +9745,14 @@ _sentinel_thread.start()
if __name__ == "__main__":
+ # Cleanup stale lab experiments on startup
+ try:
+ with get_db() as conn:
+ with conn.cursor() as cur:
+ cur.execute("UPDATE lab_experiments SET status = 'paused' WHERE status = 'running'")
+ conn.commit()
+ except Exception:
+ pass
print("\n LLM Team UI running at http://localhost:5000\n")
print(f" AI Sentinel active: {SENTINEL_MODEL} scanning every {SENTINEL_INTERVAL}s\n")
app.run(host="127.0.0.1", port=5000, debug=False, threaded=True)