// A rollout on the MiMo release's own harness (app/mimo/runner), live: phases across the top, the agent's steps as a // timeline, and the grade when it lands. The MiMo RL Environment Explorer's run page; run.js hands MiMo rollouts here. import { $, api, esc, checkMsg, md, money, dur, ago, tokensShort, statusPill, toast, DOMAIN_NAME, LIVE_STATUSES, rewardClass, rewardText, sk, spinner, emptyState, confetti, openDialog, closeModal, visibilityBadge, PRIVATE_NOTE, reportUrl } from "./util.js"; import { icon, DOMAIN_ICON } from "./icons.js"; import { refreshActive } from "./session.js"; import { taskHref, compareHref } from "./task.js"; const taskOf = (r) => taskHref(r.dataset || "XiaomiMiMo/MiMo-V2.6-RL-oss", r.path || r.task_id); const PHASES = [["sandbox", "Sandbox"], ["setup", "Setup"], ["agent", "Agent"], ["verify", "Grading"], ["done", "Done"]]; const TOOL_ICON = { bash: "terminal", read: "file", write: "pencil", edit: "pencil", grep: "search", glob: "search", todowrite: "check", list: "list" }; let timer = null, tick = null, alive = true; export function unmount() { alive = false; clearTimeout(timer); clearInterval(tick); } const isLive = (r) => r && LIVE_STATUSES.includes(r.status); function skeleton() { return `
${sk.line(18)}
${sk.line(22, 22)}${sk.line(55, 24)}${sk.line(45)}
${PHASES.map(() => `
${sk.box(20, "width:20px;border-radius:50%")}${sk.line(60)}
`).join("")}
${[70, 90, 55, 85, 60].map((w) => `
${sk.box(28, "border-radius:8px")}${sk.box(30, `width:${w}%;border-radius:10px`)}
`).join("")}
${sk.card(sk.line(30, 14) + sk.line(25, 40) + sk.lines(90, 70))}${sk.card(sk.line(30, 14) + sk.line(35, 28) + sk.lines(80, 60))}
`; } export async function mount(el, id, first) { alive = true; const st = { id, after: 0, events: [], run: null, follow: true, steps: 0 }; if (!first) { el.innerHTML = skeleton(); try { first = await api(`/api/runs/${encodeURIComponent(id)}`); } catch (e) { if (!alive) return; el.innerHTML = `
${emptyState("search", "Rollout not found", e.status === 404 ? "It may be private, or the link is wrong." : esc(e.message), `${icon("arrowLeft")}Your rollouts`)}
`; return; } if (!alive) return; } el.innerHTML = `

What the agent did

    `; $("#rp-follow", el).addEventListener("change", (e) => (st.follow = e.target.checked)); $("#rp-expand", el).addEventListener("click", (e) => { const open = e.target.textContent === "Expand all"; el.querySelectorAll("#rp-tl details").forEach((d) => (d.open = open)); e.target.textContent = open ? "Collapse all" : "Expand all"; }); el.addEventListener("click", onClick(st)); apply(el, st, first); const poll = async () => { if (!alive) return; try { apply(el, st, await api(`/api/runs/${encodeURIComponent(id)}?after=${st.after}`)); } catch { /* retry next tick */ } if (alive && isLive(st.run)) timer = setTimeout(poll, 1500); else refreshActive(); }; if (isLive(st.run)) timer = setTimeout(poll, 1500); tick = setInterval(() => { if (isLive(st.run)) { renderHead(el, st); renderTail(el, st); } }, 1000); } function apply(el, st, d) { st.run = d.run; st.stream = d.stream; if (!st.navSet) { // someone else's public rollout belongs to Community, not to My rollouts st.navSet = true; const mine = !!d.run.is_owner; document.querySelectorAll("[data-nav]").forEach((a) => a.classList.toggle("on", a.dataset.nav === (mine ? "runs" : "community"))); const c = el.querySelector(".crumbs a"); if (c && !mine) { c.href = "/community"; c.textContent = "Community"; } } const fresh = d.events.filter((e) => e.i >= st.after); st.events.push(...fresh); st.after = st.events.length ? st.events[st.events.length - 1].i + 1 : st.after; renderHead(el, st); renderPhases(el, st); appendTimeline(el, st, fresh); // history appears at once; only steps that arrive while you watch slide in if (!st.primed) { el.querySelectorAll("#rp-tl .ev").forEach((li) => li.classList.add("still")); st.primed = true; } renderGrade(el, st); renderCost(el, st); renderMeta(el, st); renderTail(el, st); $("#rp-follow-wrap", el).hidden = !isLive(st.run); if (!st.run.is_owner) $("#rp-cost .fine", el)?.remove(); if (st.follow && fresh.length && isLive(st.run)) $("#rp-tail", el).scrollIntoView({ behavior: "smooth", block: "end" }); } // Built once and then only its text changes: re-rendering every second restarted the spinner and made it flicker. function renderTail(el, st) { const t = $("#rp-tail", el); if (!t) return; if (!isLive(st.run)) { t.innerHTML = ""; return; } let msg = $(".live-msg", t); if (!msg) { t.innerHTML = `
    1. ${spinner()}
    `; msg = $(".live-msg", t); } const text = liveHint(st); if (msg.textContent !== text) msg.textContent = text; } function liveHint(st) { const s = st.run.status; if (s === "queued") return "Queued…"; if (s === "starting") return "Starting a sandbox from the task's image. Big images take a minute or two."; if (s === "setup") return "Preparing the environment…"; if (s === "verifying") return "Grading…"; const last = st.events[st.events.length - 1]; if (last?.kind === "partial") return `Writing… ${last.chars.toLocaleString()} characters${last.thinking_chars ? `, ${last.thinking_chars.toLocaleString()} thinking` : ""}`; const sm = st.stream; if (sm) { const n = sm.text + sm.thinking + sm.tool; if (!n) return `Waiting for the model's reply · ${dur(sm.age)}`; const parts = [sm.thinking && `${sm.thinking.toLocaleString()} thinking`, sm.text && `${sm.text.toLocaleString()} message`, sm.tool && `${sm.tool.toLocaleString()} in a tool call`].filter(Boolean); return `The model is writing · ${n.toLocaleString()} characters so far (${parts.join(", ")}) · ${dur(sm.age)}`; } const since = last ? Math.max(0, (Date.now() / 1000 - (st.run.started_at || st.run.created_at)) - last.t) : 0; return since > 45 ? `The model is working · ${dur(since)} since the last step. Long files take a while to write.` : "The model is working…"; } function renderHead(el, st) { const r = st.run; if (!r) return; const start = r.started_at || r.created_at, end = r.finished_at || Date.now() / 1000; const owner = !!r.is_owner; const action = !owner ? `${icon("play", 13)}Run it yourself` : isLive(r) ? (st.stopping ? `` : ``) : `${icon("refresh", 13)}Run again`; const vis = owner ? `` : ""; $("#rp-head", el).innerHTML = `
    ${icon(DOMAIN_ICON[r.domain] || "cpu", 13)}${esc(DOMAIN_NAME[r.domain] || (r.runner === "nemo-gym" ? "NeMo Gym" : r.domain))}${statusPill(r.status)}${visibilityBadge(r.visibility)} ${owner ? "" : 'shared anonymously'} ${icon("clock", 13)}${dur(end - start)} · started ${ago(r.created_at)}

    ${esc(r.title)}

    ${icon("cpu", 14)}${esc(r.endpoint ? r.model : r.model.split("/")[1] || r.model)} via ${r.endpoint ? `your endpoint ${esc(r.endpoint.host)}` : esc(r.provider || "auto")} ${paramsText(r.params) ? `${icon("gauge", 14)}${esc(paramsText(r.params))}` : ""} ${r.judge ? `${icon("scale", 14)}judge ${esc(r.judge.split("/")[1] || r.judge)}` : ""} ${r.runner === "nemo-gym" ? `${icon("check", 14)}One prediction · NeMo Gym verifier` : r.domain === "music" ? `${icon("message", 14)}single model call` : `${icon("terminal", 14)}OpenCode on the MiMo harness`}${r.flavor ? `${icon("box", 14)}${esc(r.flavor)}` : ""}
    ${icon("flag", 13)}Report${vis} ${icon("columns", 13)}Compare ${icon("file", 13)}View task${action}
    ${r.error ? `
    ${icon("alert")}${esc(r.error)}
    ` : ""}`; } function renderPhases(el, st) { const seen = {}; st.events.filter((e) => e.kind === "phase").forEach((e) => { (seen[e.name] ||= {})[e.status] = e; }); const failed = ["failed", "cancelled", "interrupted"].includes(st.run.status); const noSandbox = st.run.domain === "music" || st.run.runner === "nemo-gym"; const list = PHASES.filter(([k]) => !(noSandbox && (k === "sandbox" || k === "setup"))); const box = $("#rp-phases", el); box.style.setProperty("--n", list.length); box.innerHTML = list.map(([k, label]) => { const p = seen[k] || {}; const state = p.done ? (p.done.status === "error" ? "bad" : "ok") : p.start ? (failed ? "bad" : "on") : "off"; const t = p.start && p.done ? dur(p.done.t - p.start.t) : ""; const detail = (p.done || p.start)?.detail || ""; const mk = state === "ok" ? icon("check", 12) : state === "bad" ? icon("x", 12) : ""; return `
    ${mk}${label}${esc(t)}${esc(detail)}
    `; }).join(""); } function appendTimeline(el, st, events) { const tl = $("#rp-tl", el); for (const e of events) { if (e.kind === "phase" && e.status === "start") st.phase = e.name; const html = item(e, st); if (html) { tl.insertAdjacentHTML("beforeend", html); if (e.kind === "tool" || e.kind === "text") st.steps++; } } $("#rp-n", el).textContent = st.steps ? `${st.steps} step${st.steps === 1 ? "" : "s"}` : ""; const empty = $(".tl-empty", el); if (!tl.children.length && !isLive(st.run)) { if (!empty) tl.insertAdjacentHTML("afterend", `

    No agent steps were recorded.

    `); } else if (empty) empty.remove(); } // A whole trace as timeline rows, for pages that show several at once (the comparison). `skip` leaves out kinds // the page shows elsewhere, such as the prompt when every rollout got the same one. export function traceHtml(id, events, { skip = [] } = {}) { const st = { id, phase: null }; let steps = 0; const html = events.map((e) => { if (e.kind === "phase" && e.status === "start") st.phase = e.name; if (skip.includes(e.kind)) return ""; const h = item(e, st); if (h && (e.kind === "tool" || e.kind === "text")) steps++; return h; }).join(""); return { html, steps }; } const row = (cls, ic, t, body) => `
  1. ${icon(ic, 14)}
    ${body}
    ${t}
  2. `; function item(e, st) { const t = dur(e.t); const summary = (inner) => `${icon("chevronRight", 13, "chev")}${inner}`; switch (e.kind) { case "prompt": return row("ev-prompt", "doc", t, `
    ${summary(`Instructions to the model${(e.text || "").length.toLocaleString()} characters`)}
    ${esc(e.text)}

    ${e.harness === "nemo-gym" || st.run.runner === "nemo-gym" ? "The native Responses request: conversation history and function definitions. The reference action is withheld." : e.harness === "opencode" ? "The task's instructions, sent as the first user message. OpenCode adds its own system prompt and tool definitions." : "The whole request: one user message, no system prompt."}

    `); case "text": return row("ev-text", "message", t, `
    ${md(e.text)}
    `); case "thinking": return row("ev-think", "brain", t, `
    ${summary(`Thinking${esc(e.text.replace(/\s+/g, " ").slice(0, 220))}`)}
    ${esc(e.text)}
    `); case "tool": { const inp = e.input || {}; const head = inp.command || inp.filePath || inp.pattern || inp.path || e.title || Object.values(inp).map(String).join(" ").slice(0, 160); const mcp = isMcpTool(e.tool); const cls = `ev-tool${mcp ? " mcp" : ""}${e.status === "error" ? " bad" : ""}`; return row(cls, mcp ? "plug" : TOOL_ICON[e.tool] || "terminal", t, `
    ${summary(`${esc(mcp ? prettyTool(e.tool) : e.tool)} ${esc(String(head).split("\n")[0].slice(0, 200))}${e.ms >= 1000 ? `${dur(e.ms / 1000)}` : ""}`)}
    ${Object.keys(inp).length ? `
    Input
    ${esc(JSON.stringify(inp, null, 2))}
    ` : ""}
    Output${e.truncated ? " (truncated)" : ""}
    ${esc(e.output || "(empty)")}
    `); } case "phase": return e.status === "error" && e.name !== "done" ? row("ev-err", "alert", t, `${esc(e.name)} failed: ${esc(e.detail)}`) : ""; case "error": return row("ev-err", "alert", t, `Error ${esc(e.text)}`); case "log": return row("ev-log", "terminal", t, `
    ${summary(`${({ sandbox: "Sandbox", setup: "Setup output", agent: "Agent output", verify: "Grader output" })[st.phase] || "Output"}${esc((e.text || "").split("\n")[0].slice(0, 160))}`)}
    ${esc(e.text)}
    `); case "diff": return row("ev-diff", "diff", t, `
    ${summary(`The agent's change${e.files.length} file${e.files.length === 1 ? "" : "s"}`)}
    ${diffHtml(e.text)}
    `); case "files": return row("ev-log", "folder", t, `
    ${summary(`${esc(e.title)}${e.files.length} files`)}
    ${esc(e.files.join("\n"))}
    `); case "image": { const src = `/api/runs/${encodeURIComponent(st.id)}/artifacts/${encodeURIComponent(e.name)}`; return row("ev-img", "image", t, `Rendered page ${e.width}×${e.height} Full-page screenshot of what the agent built`); } default: return ""; } } const paramsText = (p) => !p ? "" : [p.thinking && p.thinking !== "default" && `thinking ${p.thinking === "none" ? "off" : p.thinking}`, p.temperature != null && `temperature ${p.temperature}`, p.steps && `${p.steps} steps max`, p.timeout_min && `${p.timeout_min} min limit`, p.max_tokens && `${p.max_tokens.toLocaleString()} max tokens`].filter(Boolean).join(" · "); const humanize = (id) => { const t = String(id || "").replace(/[_-]+/g, " ").trim(); return t.charAt(0).toUpperCase() + t.slice(1); }; export const prettyTool = (name) => { const parts = name.split("_"); return parts.length > 3 ? parts.slice(-3).join("_") : name; }; export const isMcpTool = (name) => !(name in TOOL_ICON) && /_/.test(name || ""); export function diffHtml(text) { return (text || "").split("\n").slice(0, 3000).map((l) => { const c = l.startsWith("+++") || l.startsWith("---") || l.startsWith("diff ") ? "dh" : l.startsWith("+") ? "da" : l.startsWith("-") ? "dd" : l.startsWith("@@") ? "dc" : ""; return `${esc(l)}`; }).join("\n"); } function renderGrade(el, st) { const g = [...st.events].reverse().find((e) => e.kind === "checks") || (st.run.status === "done" && Number.isFinite(st.run.reward) ? { reward: st.run.reward, summary: "Recorded reward. Detailed grading events are unavailable." } : null); const box = $("#rp-grade", el); const h = `

    ${icon("scale", 14)}Grade

    `; if (!g) { box.innerHTML = `${h}

    ${isLive(st.run) ? "Appears here once the agent finishes and the task's grader has run." : "This rollout was not graded."}

    `; return; } const rw = g.reward ?? st.run.reward; const img = [...st.events].reverse().find((e) => e.kind === "image"); const src = img && `/api/runs/${encodeURIComponent(st.id)}/artifacts/${encodeURIComponent(img.name)}`; const long = (g.summary || "").length > 180; const zh = /[一-鿿]/.test(g.summary || ""); const cls = rewardClass(rw); // General rubric checks: each one's share of the reward (verify.py counts a missing weight as 1) const rubric = (g.checks || []).some((c) => c.method === "llm" || c.method === "rule"); const wt = (c) => (c.weight == null ? 1 : Number(c.weight)); const wsum = rubric ? g.checks.reduce((n, c) => n + wt(c), 0) || 1 : 1; box.innerHTML = `${h}
    ${src ? `What the judge saw` : ""}
    ${rewardText(rw)}${esc(st.run.reward_key || "reward")}
    ${g.formula ? `

    ${esc(g.formula)}

    ` : ""} ${long || !g.summary ? "" : `

    ${esc(g.summary)}

    `} ${(g.checks || []).length ? `` : ""} ${(g.checks || []).some((c) => c.method === "llm") ? `

    The task's grader keeps each check's verdict, not the judge's reasoning.

    ` : ""} ${long ? `
    ${icon("chevronRight", 14, "chev")}Judge's notes

    ${esc(g.summary)}

    ${zh ? `

    In Chinese because Xiaomi's grading rubric is written in Chinese; it is used unchanged so scores stay comparable with theirs.

    ` : ""}
    ` : ""}
    `; } function renderCost(el, st) { const r = st.run, c = r.cost || {}, t = r.tokens || {}; const tot = (c.model || 0) + (c.sandbox || 0) || 1; $("#rp-cost", el).innerHTML = `

    ${icon("coins", 14)}Cost

    ${isLive(r) ? ` live` : ""}
    ${money(c.total)}
    Model tokens${r.endpoint && r.endpoint.price_in == null && r.endpoint.price_out == null ? 'not metered' : money(c.model)}
    Sandbox time${money(c.sandbox)}
    ${r.judge ? `
    Judge callsnot metered
    ` : ""}
    Tokens in
    ${tokensShort((t.input || 0) + (t.cache_read || 0))}${t.cache_read ? ` (${tokensShort(t.cache_read)} cached)` : ""}
    Tokens out
    ${tokensShort(t.output)}${t.reasoning ? ` + ${tokensShort(t.reasoning)} thinking` : ""}

    ${r.endpoint ? `Tokens are billed by your endpoint (${esc(r.endpoint.host)}); the sandbox by Hugging Face.` : `Billed to your Hugging Face account at ${esc(r.provider || "the provider")}'s price.`}

    `; } async function setVisibility(el, st, to, btn) { try { await api(`/api/runs/${encodeURIComponent(st.id)}/visibility`, { method: "POST", body: { visibility: to } }); st.run.visibility = to; renderHead(el, st); if (to === "public") { const r = (btn || $("#rp-vis", el))?.getBoundingClientRect(); confetti(r ? r.left + r.width / 2 : innerWidth / 2, r ? r.top : innerHeight / 3); toast("Public: thank you for sharing with the community"); } else toast("Private: only you can see this rollout"); } catch (e) { toast(e.message); } } function renderMeta(el, st) { const r = st.run, p = r.params || {}, pv = r.provenance || {}; const row = (k, v) => (v == null || v === "" ? "" : `
    ${k}
    ${v}
    `); const code = (v) => `${esc(v)}`; const think = { none: "off", low: "low", medium: "medium", high: "high" }[p.thinking] || "model default"; $("#rp-meta", el).innerHTML = `

    ${icon("info", 14)}Run details

    ${row("Model", code(r.model))} ${row("Served by", r.endpoint ? "an OpenAI-compatible endpoint the runner brought" + (r.endpoint.host && r.is_owner ? ` (${code(r.endpoint.host)})` : "") : esc(r.provider || "HF router auto"))} ${row("Judge", r.judge ? code(r.judge) : "")} ${row("Thinking", esc(think))} ${row("Temperature", p.temperature != null ? esc(p.temperature) : "model default")} ${r.domain === "music" || r.runner === "nemo-gym" ? row("Max tokens", esc(p.max_tokens || p.max_tokens_used || 100000)) : row("Step cap", esc(p.steps || "task default")) + row("Time limit", p.timeout_min ? esc(p.timeout_min + " min") : "task default") + row("Max tokens / step", esc(p.max_tokens || "default"))} ${row("Harness", r.runner === "nemo-gym" ? "Single prediction; tool calls are not executed" : r.domain === "music" ? "single model call" : `OpenCode ${esc(pv.harness?.installed || pv.harness?.version || "")}`)} ${row("Verifier revision", r.runner === "nemo-gym" ? code(pv.commit || "unknown") : "")} ${row("Sandbox", r.flavor ? esc(r.flavor) : "")} ${row("Image", r.image ? code(r.image.replace("docker.io/", "")) : "")} ${row("Explorer", pv.app ? `v${esc(pv.app.version)} · ${code(pv.app.source)}` : "")} ${row("Dataset", pv.dataset ? `${esc(pv.dataset.repo)}${pv.dataset.revision ? " @ " + code(pv.dataset.revision.slice(0, 10)) : ""}` : "")} ${row("Reference", pv.reference ? Object.entries(pv.reference).map(([k, v]) => `${esc(k.split("/")[1])} ${code(v)}`).join(" · ") : "")} ${row("Rollout id", code(r.id))}
    `; } function onClick(st) { return async (ev) => { const vb = ev.target.closest("#rp-vis"); if (vb) { const el = vb.closest(".rp"); if (st.run.visibility === "public") { const dlg = openDialog(`

    Make this rollout private?

    ${esc(PRIVATE_NOTE)}

    `); dlg.addEventListener("click", async (e) => { if (e.target.closest("[data-close]")) closeModal(); if (e.target.closest("#vis-go")) { closeModal(); await setVisibility(el, st, "private"); } }); } else await setVisibility(el, st, "public", vb); return; } const b = ev.target.closest("#rp-cancel"); if (!b) return; st.stopping = true; b.disabled = true; b.innerHTML = `${spinner()}Stopping`; try { await api(`/api/runs/${encodeURIComponent(st.id)}/cancel`, { method: "POST" }); toast("Stopping the rollout…"); } catch (e) { st.stopping = false; toast(e.message); b.disabled = false; b.innerHTML = `${icon("stop", 13)}Stop`; } }; }