// Rollouts: everything you've started, live or finished. Refreshes itself while anything is running. import { $, api, esc, dur, ago, statusPill, rewardBadge, LIVE_STATUSES, sk, emptyState, visibilityBadge } from "./util.js"; import { icon } from "./icons.js"; import { getSession } from "./session.js"; let timer = null, alive = true; const FAILED = ["failed", "cancelled", "interrupted"]; export function unmount() { alive = false; clearTimeout(timer); } const head = (stats = "") => `

My rollouts

Only yours, public and private. They keep going when you close the page. Everyone's public rollouts are under Community.

${stats}
`; export async function mount(el) { alive = true; if (!getSession().user) { el.innerHTML = `
${head()}
${emptyState("user", "Sign in to run rollouts", "Pick a task, choose an agent and a model from HF Inference Providers, and watch it work in an HF Sandbox. Runs are billed to your Hugging Face account.", ``)}
`; return; } el.innerHTML = `
${head(`
`)}
${Array.from({ length: 5 }, () => `
${sk.box(22, "width:90px;border-radius:99px")}
${sk.line(70)}${sk.line(40, 10)}
${sk.line(60)}${sk.line(60)}${sk.line(70)}${sk.line(80)}
`).join("")}
`; let filter = "all"; $("#rs-filters", el).addEventListener("click", (e) => { const b = e.target.closest("[data-f]"); if (b) { filter = b.dataset.f; draw(); } }); let runs = []; const draw = () => { const counts = { all: runs.length, live: runs.filter((r) => LIVE_STATUSES.includes(r.status)).length, done: runs.filter((r) => r.status === "done").length, failed: runs.filter((r) => FAILED.includes(r.status)).length }; $("#rs-filters", el).innerHTML = [["all", "All"], ["live", "Running"], ["done", "Finished"], ["failed", "Failed or stopped"]] .map(([k, l]) => ``).join(""); const shown = runs.filter((r) => filter === "all" || (filter === "live" ? LIVE_STATUSES.includes(r.status) : filter === "done" ? r.status === "done" : FAILED.includes(r.status))); $("#rs-list", el).innerHTML = shown.length ? `
StatusTaskModelRewardAgentStarted
${shown.map(row).join("")}
` : `
${runs.length ? emptyState("filter", "Nothing in this view", "Try another filter.") : emptyState("play", "No rollouts yet", "Open a task and run one. It shows up here with its live trajectory and reward.", `${icon("grid", 15)}Browse environments`)}
`; const scored = runs.filter((r) => r.reward != null); $("#rs-stats", el).innerHTML = `
${runs.length}rollouts
${scored.length}scored rollouts
`; }; const load = async () => { if (!alive) return; try { runs = (await api("/api/runs")).runs; if (alive) draw(); } catch (e) { $("#rs-list", el).innerHTML = `
${emptyState("alert", "Couldn't load your rollouts", esc(e.message))}
`; } if (alive && runs.some((r) => LIVE_STATUSES.includes(r.status))) timer = setTimeout(load, 3000); }; load(); } const COLL = { mimo: "grid", terminal: "terminal", data: "table", swe: "code", mixed: "flask" }; function row(r) { const end = r.finished_at || Date.now() / 1000; const model = r.endpoint ? r.model : (r.model || "").split("/")[1] || r.model; return ` ${statusPill(r.status)} ${visibilityBadge(r.visibility)} ${esc(r.title)}${icon(COLL[r.collection] || "database", 12)}${esc(r.dataset)} ${esc(model)} ${rewardBadge(r.reward, r.status)} ${esc(r.runner === "nemo-gym" ? "NeMo Gym prediction" : r.runner === "mimo" ? (r.domain === "music" ? "MiMo scorer" : "MiMo harness") : r.harness)} ${ago(r.created_at)}${dur(end - (r.started_at || r.created_at))}`; }