Overhaul history: scores visible, optimization history, full run tracking
Archive list improvements: - Score column added to run list (color-coded: green 7+, amber 5+, red) - OPT badge on runs generated by optimization (shows parent run) - quality_score, score_method, tags, source, parent_run now in list query Detail panel score display: - Large color-coded score badge in header (e.g., "8.0/10" in green) - Shows scoring method (auto/thumbs up/thumbs down) - Persistent — visible every time you open the detail, not just once Full optimization history section: - Shows all optimization runs with timestamps, scores, call counts - Each run lists ranked variations with strategy, mode, score - Winner highlighted with star and green border - "View" button opens any variation's full detail - "Use" button on winner sends prompt to composer via sessionStorage - Always loads from /api/optimize-history — no stale data Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
856f584666
commit
462d81868f
171
llm_team_ui.py
171
llm_team_ui.py
@ -6406,12 +6406,13 @@ def get_runs():
|
||||
try:
|
||||
with get_db() as conn:
|
||||
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
|
||||
_cols = "id, mode, prompt, models_used, created_at, archived, quality_score, score_method, tags, notes, config->>'source' as source, config->>'parent_run' as parent_run"
|
||||
if show == "archived":
|
||||
cur.execute("SELECT id, mode, prompt, models_used, created_at, archived FROM team_runs WHERE archived = true ORDER BY created_at DESC LIMIT 200")
|
||||
cur.execute(f"SELECT {_cols} FROM team_runs WHERE archived = true ORDER BY created_at DESC LIMIT 200")
|
||||
elif show == "all":
|
||||
cur.execute("SELECT id, mode, prompt, models_used, created_at, archived FROM team_runs ORDER BY created_at DESC LIMIT 200")
|
||||
cur.execute(f"SELECT {_cols} FROM team_runs ORDER BY created_at DESC LIMIT 200")
|
||||
else:
|
||||
cur.execute("SELECT id, mode, prompt, models_used, created_at, archived FROM team_runs WHERE archived = false ORDER BY created_at DESC LIMIT 50")
|
||||
cur.execute(f"SELECT {_cols} FROM team_runs WHERE archived = false ORDER BY created_at DESC LIMIT 50")
|
||||
runs = cur.fetchall()
|
||||
for r in runs:
|
||||
r["created_at"] = r["created_at"].isoformat()
|
||||
@ -6746,7 +6747,8 @@ h1 span{color:var(--accent)}
|
||||
.spacer{flex:1}
|
||||
.count-badge{font-family:'JetBrains Mono',monospace;font-size:10px;color:var(--text2)}
|
||||
.run-table{width:100%}
|
||||
.run-row{display:grid;grid-template-columns:30px 50px 90px 1fr 80px 100px 80px;gap:8px;padding:8px 10px;border-bottom:1px solid rgba(42,45,53,0.3);align-items:center;font-size:11px;cursor:pointer;transition:background 0.1s}
|
||||
.run-row{display:grid;grid-template-columns:30px 50px 90px 1fr 80px 70px 100px 80px;gap:8px;padding:8px 10px;border-bottom:1px solid rgba(42,45,53,0.3);align-items:center;font-size:11px;cursor:pointer;transition:background 0.1s}
|
||||
.run-score{font-family:'JetBrains Mono',monospace;font-size:11px;display:flex;align-items:center;gap:3px}
|
||||
.run-row:hover{background:rgba(226,181,90,0.03)}
|
||||
.run-row.archived{opacity:0.4}
|
||||
.run-hdr{font-family:'JetBrains Mono',monospace;font-size:8px;text-transform:uppercase;letter-spacing:1px;color:var(--text2);cursor:default;border-bottom:2px solid var(--border)}
|
||||
@ -7029,6 +7031,21 @@ function renderTable(runs) {
|
||||
var tagsEl = document.createElement('span'); tagsEl.className = 'run-tags';
|
||||
(r.tags||[]).forEach(function(t){ var pill = document.createElement('span'); pill.className = 'tag-pill'; pill.textContent = t; tagsEl.appendChild(pill); });
|
||||
row.appendChild(tagsEl);
|
||||
// Score + badges
|
||||
var scoreEl = document.createElement('span'); scoreEl.className = 'run-score';
|
||||
if (r.quality_score) {
|
||||
scoreEl.textContent = r.quality_score.toFixed(1);
|
||||
scoreEl.style.color = r.quality_score >= 7 ? 'var(--green)' : r.quality_score >= 5 ? 'var(--accent)' : 'var(--red)';
|
||||
scoreEl.style.fontWeight = '700';
|
||||
}
|
||||
if (r.source === 'optimize') {
|
||||
var optPill = document.createElement('span');
|
||||
optPill.style.cssText = 'font-size:8px;background:rgba(79,70,229,0.1);color:var(--accent);padding:1px 5px;border-radius:2px;border:1px solid rgba(79,70,229,0.2);margin-left:4px';
|
||||
optPill.textContent = 'OPT';
|
||||
optPill.title = 'Generated by optimization from run #' + (r.parent_run||'?');
|
||||
scoreEl.appendChild(optPill);
|
||||
}
|
||||
row.appendChild(scoreEl);
|
||||
// Date
|
||||
var dateEl = document.createElement('span'); dateEl.className = 'run-date';
|
||||
var dt = new Date(r.created_at); dateEl.textContent = dt.toLocaleDateString()+' '+dt.toLocaleTimeString([],{hour:'2-digit',minute:'2-digit'});
|
||||
@ -7056,6 +7073,22 @@ async function openDetail(id) {
|
||||
modeTag.textContent = run.mode + ' #' + id; hdr.appendChild(modeTag);
|
||||
var dateTag = document.createElement('span'); dateTag.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:9px;color:var(--text2)';
|
||||
dateTag.textContent = new Date(run.created_at).toLocaleString(); hdr.appendChild(dateTag);
|
||||
// Score badge in header
|
||||
if (run.quality_score) {
|
||||
var scoreBadge = document.createElement('span');
|
||||
var sc = run.quality_score;
|
||||
scoreBadge.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:14px;font-weight:700;margin-left:auto;padding:4px 12px;border:2px solid;border-radius:2px;' +
|
||||
'color:' + (sc >= 7 ? 'var(--green)' : sc >= 5 ? 'var(--accent)' : 'var(--red)') + ';' +
|
||||
'border-color:' + (sc >= 7 ? 'var(--green)' : sc >= 5 ? 'var(--accent)' : 'var(--red)');
|
||||
scoreBadge.textContent = sc.toFixed(1) + '/10';
|
||||
if (run.score_method) {
|
||||
var method = document.createElement('span');
|
||||
method.style.cssText = 'font-size:8px;text-transform:uppercase;letter-spacing:0.5px;opacity:0.6;margin-left:6px';
|
||||
method.textContent = run.score_method === 'auto' ? 'auto' : run.score_method === 'user_up' ? '\u{1F44D}' : '\u{1F44E}';
|
||||
scoreBadge.appendChild(method);
|
||||
}
|
||||
hdr.appendChild(scoreBadge);
|
||||
}
|
||||
panel.appendChild(hdr);
|
||||
|
||||
// Prompt
|
||||
@ -7107,38 +7140,108 @@ async function openDetail(id) {
|
||||
actions.appendChild(optBtn);
|
||||
panel.appendChild(actions);
|
||||
|
||||
// Optimization history
|
||||
if (isOptimized) {
|
||||
var optSection = document.createElement('div');
|
||||
optSection.style.cssText = 'background:var(--glow);border:1px solid var(--accent);border-radius:2px;padding:12px;margin-bottom:12px';
|
||||
// Optimization history — always load, show if data exists
|
||||
var optSection = document.createElement('div');
|
||||
optSection.style.cssText = 'margin-bottom:12px';
|
||||
fetch('/api/optimize-history/' + id).then(function(r){return r.json()}).then(function(d){
|
||||
var results = d.results || [];
|
||||
var children = d.children || [];
|
||||
if (!results.length && !children.length) return;
|
||||
|
||||
optSection.style.cssText = 'background:var(--glow);border:1px solid var(--accent);border-radius:2px;padding:14px;margin-bottom:12px';
|
||||
|
||||
// Header with count
|
||||
var optHdr = document.createElement('div');
|
||||
optHdr.style.cssText = 'display:flex;align-items:center;gap:8px;margin-bottom:10px;cursor:pointer';
|
||||
var optTitle = document.createElement('div');
|
||||
optTitle.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:9px;text-transform:uppercase;letter-spacing:1.5px;color:var(--accent);margin-bottom:6px;font-weight:700';
|
||||
optTitle.textContent = 'Optimization Results';
|
||||
optSection.appendChild(optTitle);
|
||||
var optInfo = document.createElement('div');
|
||||
optInfo.style.cssText = 'font-size:12px;color:var(--text);line-height:1.6';
|
||||
var bestId = meta.best_variation_run;
|
||||
var jobId = meta.optimize_job || '';
|
||||
optInfo.textContent = 'Best variation: Run #' + (bestId||'?') + ' | Job: ' + jobId;
|
||||
optSection.appendChild(optInfo);
|
||||
if (bestId) {
|
||||
var viewBtn = document.createElement('button'); viewBtn.className = 'tool-btn';
|
||||
viewBtn.style.cssText = 'margin-top:8px;font-size:9px';
|
||||
viewBtn.textContent = 'View Best Variation (#' + bestId + ')';
|
||||
viewBtn.onclick = function(){ openDetail(bestId); };
|
||||
optSection.appendChild(viewBtn);
|
||||
}
|
||||
// Load pipeline results for more detail
|
||||
fetch('/api/optimize-history/' + id).then(function(r){return r.json()}).then(function(d){
|
||||
if (d.results && d.results.length) {
|
||||
var count = document.createElement('div');
|
||||
count.style.cssText = 'font-size:11px;color:var(--text2);margin-top:6px;font-family:JetBrains Mono,monospace';
|
||||
count.textContent = d.results.length + ' optimization(s) run | Best: ' + (d.results[0].best_score||'?') + '/10 | Original: ' + (d.results[0].original_score||'?') + '/10';
|
||||
optSection.appendChild(count);
|
||||
optTitle.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:10px;text-transform:uppercase;letter-spacing:1.5px;color:var(--accent);font-weight:700';
|
||||
optTitle.textContent = '\u26A1 Optimization History (' + results.length + ' run' + (results.length !== 1 ? 's' : '') + ', ' + children.length + ' variation' + (children.length !== 1 ? 's' : '') + ')';
|
||||
optHdr.appendChild(optTitle);
|
||||
optSection.appendChild(optHdr);
|
||||
|
||||
// Each optimization run
|
||||
results.forEach(function(res, ri) {
|
||||
var runCard = document.createElement('div');
|
||||
runCard.style.cssText = 'background:rgba(0,0,0,0.15);border:1px solid var(--border);border-radius:2px;padding:10px;margin-bottom:6px';
|
||||
var runHdr = document.createElement('div');
|
||||
runHdr.style.cssText = 'display:flex;align-items:center;gap:8px;font-family:JetBrains Mono,monospace;font-size:10px';
|
||||
var runLabel = document.createElement('span');
|
||||
runLabel.style.cssText = 'color:var(--accent);font-weight:700';
|
||||
runLabel.textContent = 'Run ' + (ri+1);
|
||||
runHdr.appendChild(runLabel);
|
||||
var bestBadge = document.createElement('span');
|
||||
bestBadge.style.cssText = 'color:var(--green);font-weight:700';
|
||||
bestBadge.textContent = 'Best: ' + (res.best_score||'?') + '/10';
|
||||
runHdr.appendChild(bestBadge);
|
||||
var origBadge = document.createElement('span');
|
||||
origBadge.style.cssText = 'color:var(--text2)';
|
||||
origBadge.textContent = 'Original: ' + (res.original_score||'?') + '/10';
|
||||
runHdr.appendChild(origBadge);
|
||||
if (res.improvement > 0) {
|
||||
var impBadge = document.createElement('span');
|
||||
impBadge.style.cssText = 'color:var(--green)';
|
||||
impBadge.textContent = '+' + res.improvement.toFixed(1);
|
||||
runHdr.appendChild(impBadge);
|
||||
}
|
||||
}).catch(function(){});
|
||||
panel.appendChild(optSection);
|
||||
}
|
||||
var callsBadge = document.createElement('span');
|
||||
callsBadge.style.cssText = 'color:var(--text2);margin-left:auto';
|
||||
callsBadge.textContent = (res.calls_used||'?') + ' calls';
|
||||
runHdr.appendChild(callsBadge);
|
||||
if (res.completed_at) {
|
||||
var dateBadge = document.createElement('span');
|
||||
dateBadge.style.cssText = 'color:var(--text2);font-size:9px';
|
||||
dateBadge.textContent = new Date(res.completed_at).toLocaleDateString();
|
||||
runHdr.appendChild(dateBadge);
|
||||
}
|
||||
runCard.appendChild(runHdr);
|
||||
|
||||
// Ranked variations for this run
|
||||
var ranked = res.ranked || [];
|
||||
ranked.forEach(function(v, vi) {
|
||||
var vRow = document.createElement('div');
|
||||
vRow.style.cssText = 'display:flex;align-items:center;gap:8px;padding:4px 0;font-size:11px;border-top:1px solid rgba(42,45,53,0.2);margin-top:4px';
|
||||
if (vi === 0) vRow.style.borderLeft = '2px solid var(--green)';
|
||||
var rank = document.createElement('span');
|
||||
rank.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:10px;font-weight:700;color:' + (vi === 0 ? 'var(--green)' : 'var(--text2)') + ';min-width:20px';
|
||||
rank.textContent = vi === 0 ? '\u2605' : '#' + (vi+1);
|
||||
vRow.appendChild(rank);
|
||||
var strat = document.createElement('span');
|
||||
strat.style.cssText = 'font-size:9px;color:var(--accent);font-family:JetBrains Mono,monospace;text-transform:uppercase;min-width:60px';
|
||||
strat.textContent = v.strategy || '?';
|
||||
vRow.appendChild(strat);
|
||||
var vMode = document.createElement('span');
|
||||
vMode.style.cssText = 'font-size:9px;color:var(--text2);font-family:JetBrains Mono,monospace;min-width:70px';
|
||||
vMode.textContent = v.mode || '';
|
||||
vRow.appendChild(vMode);
|
||||
var vScore = document.createElement('span');
|
||||
vScore.style.cssText = 'font-family:JetBrains Mono,monospace;font-weight:700;color:' + ((v.score||0) >= 7 ? 'var(--green)' : 'var(--accent)');
|
||||
vScore.textContent = v.score ? v.score.toFixed(1) : '?';
|
||||
vRow.appendChild(vScore);
|
||||
var vSnippet = document.createElement('span');
|
||||
vSnippet.style.cssText = 'flex:1;color:var(--text2);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
|
||||
vSnippet.textContent = (v.snippet || v.prompt || '').substring(0, 80);
|
||||
vRow.appendChild(vSnippet);
|
||||
if (v.run_id) {
|
||||
var viewBtn = document.createElement('button');
|
||||
viewBtn.style.cssText = 'font-size:8px;padding:2px 6px;cursor:pointer;background:none;border:1px solid var(--border);color:var(--text2);font-family:JetBrains Mono,monospace;border-radius:2px';
|
||||
viewBtn.textContent = 'View';
|
||||
viewBtn.onclick = function(e){ e.stopPropagation(); openDetail(v.run_id); };
|
||||
vRow.appendChild(viewBtn);
|
||||
}
|
||||
if (vi === 0 && v.prompt) {
|
||||
var useBtn = document.createElement('button');
|
||||
useBtn.style.cssText = 'font-size:8px;padding:2px 6px;cursor:pointer;background:none;border:1px solid var(--accent);color:var(--accent);font-family:JetBrains Mono,monospace;border-radius:2px';
|
||||
useBtn.textContent = 'Use';
|
||||
useBtn.onclick = function(e){ e.stopPropagation(); sessionStorage.setItem('pending-prompt', v.prompt); window.location.href = '/'; };
|
||||
vRow.appendChild(useBtn);
|
||||
}
|
||||
runCard.appendChild(vRow);
|
||||
});
|
||||
|
||||
optSection.appendChild(runCard);
|
||||
});
|
||||
}).catch(function(){});
|
||||
panel.appendChild(optSection);
|
||||
|
||||
// Responses
|
||||
var responses = run.responses || [];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user