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:
|
try:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
|
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":
|
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":
|
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:
|
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()
|
runs = cur.fetchall()
|
||||||
for r in runs:
|
for r in runs:
|
||||||
r["created_at"] = r["created_at"].isoformat()
|
r["created_at"] = r["created_at"].isoformat()
|
||||||
@ -6746,7 +6747,8 @@ h1 span{color:var(--accent)}
|
|||||||
.spacer{flex:1}
|
.spacer{flex:1}
|
||||||
.count-badge{font-family:'JetBrains Mono',monospace;font-size:10px;color:var(--text2)}
|
.count-badge{font-family:'JetBrains Mono',monospace;font-size:10px;color:var(--text2)}
|
||||||
.run-table{width:100%}
|
.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:hover{background:rgba(226,181,90,0.03)}
|
||||||
.run-row.archived{opacity:0.4}
|
.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)}
|
.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';
|
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); });
|
(r.tags||[]).forEach(function(t){ var pill = document.createElement('span'); pill.className = 'tag-pill'; pill.textContent = t; tagsEl.appendChild(pill); });
|
||||||
row.appendChild(tagsEl);
|
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
|
// Date
|
||||||
var dateEl = document.createElement('span'); dateEl.className = 'run-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'});
|
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);
|
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)';
|
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);
|
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);
|
panel.appendChild(hdr);
|
||||||
|
|
||||||
// Prompt
|
// Prompt
|
||||||
@ -7107,38 +7140,108 @@ async function openDetail(id) {
|
|||||||
actions.appendChild(optBtn);
|
actions.appendChild(optBtn);
|
||||||
panel.appendChild(actions);
|
panel.appendChild(actions);
|
||||||
|
|
||||||
// Optimization history
|
// Optimization history — always load, show if data exists
|
||||||
if (isOptimized) {
|
var optSection = document.createElement('div');
|
||||||
var optSection = document.createElement('div');
|
optSection.style.cssText = 'margin-bottom:12px';
|
||||||
optSection.style.cssText = 'background:var(--glow);border:1px solid var(--accent);border-radius:2px;padding:12px;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');
|
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.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 = 'Optimization Results';
|
optTitle.textContent = '\u26A1 Optimization History (' + results.length + ' run' + (results.length !== 1 ? 's' : '') + ', ' + children.length + ' variation' + (children.length !== 1 ? 's' : '') + ')';
|
||||||
optSection.appendChild(optTitle);
|
optHdr.appendChild(optTitle);
|
||||||
var optInfo = document.createElement('div');
|
optSection.appendChild(optHdr);
|
||||||
optInfo.style.cssText = 'font-size:12px;color:var(--text);line-height:1.6';
|
|
||||||
var bestId = meta.best_variation_run;
|
// Each optimization run
|
||||||
var jobId = meta.optimize_job || '';
|
results.forEach(function(res, ri) {
|
||||||
optInfo.textContent = 'Best variation: Run #' + (bestId||'?') + ' | Job: ' + jobId;
|
var runCard = document.createElement('div');
|
||||||
optSection.appendChild(optInfo);
|
runCard.style.cssText = 'background:rgba(0,0,0,0.15);border:1px solid var(--border);border-radius:2px;padding:10px;margin-bottom:6px';
|
||||||
if (bestId) {
|
var runHdr = document.createElement('div');
|
||||||
var viewBtn = document.createElement('button'); viewBtn.className = 'tool-btn';
|
runHdr.style.cssText = 'display:flex;align-items:center;gap:8px;font-family:JetBrains Mono,monospace;font-size:10px';
|
||||||
viewBtn.style.cssText = 'margin-top:8px;font-size:9px';
|
var runLabel = document.createElement('span');
|
||||||
viewBtn.textContent = 'View Best Variation (#' + bestId + ')';
|
runLabel.style.cssText = 'color:var(--accent);font-weight:700';
|
||||||
viewBtn.onclick = function(){ openDetail(bestId); };
|
runLabel.textContent = 'Run ' + (ri+1);
|
||||||
optSection.appendChild(viewBtn);
|
runHdr.appendChild(runLabel);
|
||||||
}
|
var bestBadge = document.createElement('span');
|
||||||
// Load pipeline results for more detail
|
bestBadge.style.cssText = 'color:var(--green);font-weight:700';
|
||||||
fetch('/api/optimize-history/' + id).then(function(r){return r.json()}).then(function(d){
|
bestBadge.textContent = 'Best: ' + (res.best_score||'?') + '/10';
|
||||||
if (d.results && d.results.length) {
|
runHdr.appendChild(bestBadge);
|
||||||
var count = document.createElement('div');
|
var origBadge = document.createElement('span');
|
||||||
count.style.cssText = 'font-size:11px;color:var(--text2);margin-top:6px;font-family:JetBrains Mono,monospace';
|
origBadge.style.cssText = 'color:var(--text2)';
|
||||||
count.textContent = d.results.length + ' optimization(s) run | Best: ' + (d.results[0].best_score||'?') + '/10 | Original: ' + (d.results[0].original_score||'?') + '/10';
|
origBadge.textContent = 'Original: ' + (res.original_score||'?') + '/10';
|
||||||
optSection.appendChild(count);
|
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(){});
|
var callsBadge = document.createElement('span');
|
||||||
panel.appendChild(optSection);
|
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
|
// Responses
|
||||||
var responses = run.responses || [];
|
var responses = run.responses || [];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user