Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions metainfer/tasks/evolve_kernel/server/_state_readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from __future__ import annotations

import difflib
import json
from pathlib import Path
from typing import Any, Dict, List, Optional
Expand Down Expand Up @@ -213,3 +214,94 @@ def read_reference_kernel(workspace_dir: Path) -> Dict[str, Any]:
"path": str(path),
"lines": len(code.splitlines()),
}


# --------------------------------------------------------------------------- #
# Kernel source & diff
# --------------------------------------------------------------------------- #

# Metadata carried alongside a single kernel's source (the fields the diff
# view needs to explain a change: how fast it was, which iteration added it,
# and which library kernel it was derived from).
_KERNEL_META_KEYS = (
"exec_time_ms",
"complexity_score",
"combined_score",
"iteration_added",
"parent_id",
)


def read_kernel_source(workspace_dir: Path, kernel_id: str) -> Dict[str, Any]:
"""Return the full source + metadata for one library kernel, by id.

``read_kernel_library`` ships every kernel's code in one payload; this
resolves a single kernel so callers that already know the id (the diff
view) don't have to scan the list, and so the lookup has one definition.
"""
for k in read_kernel_library(workspace_dir)["kernels"]:
if str(k.get("id")) == str(kernel_id):
code = k.get("code") or ""
return {
"exists": True,
"id": k.get("id"),
"code": code,
"lines": len(code.splitlines()),
"meta": {key: k.get(key) for key in _KERNEL_META_KEYS},
}
return {"exists": False, "id": kernel_id, "code": "", "lines": 0, "meta": {}}


def read_kernel_diff(workspace_dir: Path, kernel_id: str,
base: str = "reference") -> Dict[str, Any]:
"""Unified diff of a library kernel against a baseline.

``base`` is ``"reference"`` (the original kernel the task started from)
or ``"parent"`` (the library kernel this one was derived from). Returns
the diff text plus added/removed line counts; a missing kernel, a root
kernel with no parent, or a parent that is no longer in the library
(the library evicts past ``MAX_LIBRARY_SIZE``) yields ``exists: False``
with an ``error`` reason rather than raising.
"""
src = read_kernel_source(workspace_dir, kernel_id)
if not src["exists"]:
return _diff_missing(base, f"unknown kernel {kernel_id!r}")

if base == "parent":
parent_id = src["meta"].get("parent_id")
if not parent_id:
return _diff_missing(base, "kernel has no parent")
base_src = read_kernel_source(workspace_dir, parent_id)
if not base_src["exists"]:
return _diff_missing(
base, f"parent {str(parent_id)[:8]} is no longer in the library")
base_code = base_src["code"]
base_label = f"kernel {str(parent_id)[:8]}"
else:
ref = read_reference_kernel(workspace_dir)
base_code = ref["code"] if ref["exists"] else ""
base_label = "reference"

diff_lines = list(difflib.unified_diff(
base_code.splitlines(), (src["code"] or "").splitlines(),
fromfile=f"a/{base_label}",
tofile=f"b/kernel {str(kernel_id)[:8]}",
lineterm="",
))
added = sum(1 for ln in diff_lines
if ln.startswith("+") and not ln.startswith("+++"))
removed = sum(1 for ln in diff_lines
if ln.startswith("-") and not ln.startswith("---"))
return {
"exists": True,
"base": base,
"base_label": base_label,
"diff": "\n".join(diff_lines),
"added": added,
"removed": removed,
}


def _diff_missing(base: str, error: str) -> Dict[str, Any]:
return {"exists": False, "base": base, "base_label": base,
"diff": "", "added": 0, "removed": 0, "error": error}
10 changes: 10 additions & 0 deletions metainfer/tasks/evolve_kernel/server/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ def ok_reference_kernel(task_id: str) -> Dict[str, Any]:
require_task_type(entry, PLUGIN_TYPE)
return _state_readers.read_reference_kernel(workspace_dir_for(entry))

# ---- Kernel diff ----

@router.get("/kernels/{kernel_id}/diff")
def ok_kernel_diff(task_id: str, kernel_id: str,
base: str = "reference") -> Dict[str, Any]:
entry = task_or_404(task_id)
require_task_type(entry, PLUGIN_TYPE)
return _state_readers.read_kernel_diff(
workspace_dir_for(entry), kernel_id, base)

# ---- QA ----

register_qa_routes(router, plugin, prefix="/qa")
Expand Down
107 changes: 100 additions & 7 deletions metainfer/tasks/evolve_kernel/static/ok-detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Timeline } from "app/timeline";
import {
getIterations, getCharts, getStateGraph,
getKernelLibrary, getCorrectnessHarness, getPerfHarness,
getReferenceKernel,
getReferenceKernel, getKernelDiff,
} from "app/ok-runtime-api";

const withTimeout = (p, ms = 8000) =>
Expand Down Expand Up @@ -140,6 +140,101 @@ function HarnessStatus({ harness, label }) {
return html`<span class="ok-harness-status fail">${label}: not generated</span>`;
}

// ---- Kernel source / diff inspector ----

// Line-numbered source rendering: the raw string in a <pre> gives no way to
// cite a line, so emit one <div> per line with a gutter number.
function SourceLines({ code }) {
const lines = (code || "").split("\n");
return html`<div class="ok-source">
${lines.map((ln, i) => html`
<div class="ok-source-row" key=${i}>
<span class="ok-source-num">${i + 1}</span>
<span class="ok-source-line">${ln}</span>
</div>
`)}
</div>`;
}

// Unified-diff rendering: classify each line by prefix so additions and
// deletions stand out; hunk headers (@@) get their own muted styling.
function DiffLines({ diff }) {
const lines = (diff || "").split("\n");
if (!lines.some((l) => l.length > 0)) {
return html`<div class="ok-diff empty muted">No differences.</div>`;
}
return html`<div class="ok-diff">
${lines.map((ln, i) => {
let cls = "ok-diff-ctx";
if (ln.startsWith("+++") || ln.startsWith("---")) cls = "ok-diff-meta";
else if (ln.startsWith("@@")) cls = "ok-diff-hunk";
else if (ln.startsWith("+")) cls = "ok-diff-add";
else if (ln.startsWith("-")) cls = "ok-diff-del";
return html`<div class=${"ok-diff-row " + cls} key=${i}>${ln || " "}</div>`;
})}
</div>`;
}

const DIFF_MODES = [
{ key: "source", label: "Source" },
{ key: "reference", label: "Diff vs reference" },
{ key: "parent", label: "Diff vs parent" },
];

function KernelInspector({ taskId, kernel, onClose }) {
const [mode, setMode] = useState("source");
const [diff, setDiff] = useState(null);
const [diffErr, setDiffErr] = useState(null);

useEffect(() => {
if (mode === "source" || !taskId || !kernel) return;
let cancelled = false;
setDiff(null);
setDiffErr(null);
withTimeout(getKernelDiff(taskId, kernel.id, mode))
.then((d) => { if (!cancelled) setDiff(d); })
.catch((e) => { if (!cancelled) setDiffErr(String(e.message || e)); });
return () => { cancelled = true; };
}, [taskId, kernel && kernel.id, mode]);

const code = kernel.code || kernel.code_preview || "";
const parentId = kernel.parent_id ? String(kernel.parent_id).slice(0, 8) : null;

return html`<section class="panel ok-panel-full">
<h2>Kernel: ${String(kernel.id).slice(0, 8)}…
<button class="btn btn-sm" style="float:right;" onClick=${onClose}>× close</button>
</h2>
<div class="ok-inspector-toolbar">
<div class="ok-inspector-modes">
${DIFF_MODES.map((m) => html`
<button key=${m.key}
class=${"btn btn-sm" + (mode === m.key ? " active" : "")}
disabled=${m.key === "parent" && !parentId}
title=${m.key === "parent" && !parentId ? "kernel has no parent" : ""}
onClick=${() => setMode(m.key)}>${m.label}</button>
`)}
</div>
${mode !== "source" && diff && diff.exists ? html`
<span class="ok-diff-stat">
<span class="ok-diff-stat-add">+${diff.added}</span>
<span class="ok-diff-stat-del">−${diff.removed}</span>
<span class="muted">vs ${diff.base_label}</span>
</span>
` : null}
</div>

${mode === "source"
? html`<${SourceLines} code=${code} />`
: diffErr
? html`<div class="ok-diff empty error">Failed to load diff: ${diffErr}</div>`
: !diff
? html`<div class="ok-diff empty muted">Loading diff…</div>`
: !diff.exists
? html`<div class="ok-diff empty muted">${diff.error || "No diff available."}</div>`
: html`<${DiffLines} diff=${diff.diff} />`}
</section>`;
}

// ---- Main view ----

export default function OptKernelDetailView({
Expand Down Expand Up @@ -185,12 +280,10 @@ export default function OptKernelDetailView({
</div>

${selectedKernel ? html`
<section class="panel ok-panel-full">
<h2>Kernel: ${selectedKernel.id.slice(0, 8)}…
<button class="btn btn-sm" style="float:right;" onClick=${() => setSelectedKernel(null)}>× close</button>
</h2>
<div class="ok-code-preview large">${selectedKernel.code || selectedKernel.code_preview || "Code not available"}</div>
</section>
<${KernelInspector}
taskId=${taskId}
kernel=${selectedKernel}
onClose=${() => setSelectedKernel(null)} />
` : null}

<div class="ok-grid">
Expand Down
8 changes: 8 additions & 0 deletions metainfer/tasks/evolve_kernel/static/ok-runtime-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ export async function getReferenceKernel(taskId) {
return res.json();
}

export async function getKernelDiff(taskId, kernelId, base = "reference") {
const res = await fetch(
`${BASE(taskId)}/kernels/${encodeURIComponent(kernelId)}/diff` +
`?base=${encodeURIComponent(base)}`);
if (!res.ok) throw new Error(`kernel diff: ${res.status}`);
return res.json();
}

export async function getRetrospective(taskId, n) {
const res = await fetch(`${BASE(taskId)}/iterations/${n}/retrospective`);
if (!res.ok) throw new Error(`retrospective ${n}: ${res.status}`);
Expand Down
104 changes: 104 additions & 0 deletions metainfer/tasks/evolve_kernel/static/ok.css
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,107 @@
color: var(--muted, #8b949e);
margin-top: 0.25rem;
}

/* ---- Kernel source / diff inspector ---- */

.ok-inspector-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
margin-bottom: 0.75rem;
flex-wrap: wrap;
}

.ok-inspector-modes {
display: flex;
gap: 0.4rem;
}

.ok-inspector-modes .btn.active {
background: var(--accent-bg, rgba(88, 166, 255, 0.15));
color: var(--accent, #58a6ff);
border-color: var(--accent, #58a6ff);
}

.ok-diff-stat {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-size: 0.8rem;
font-family: monospace;
}

.ok-diff-stat-add {
color: #3fb950;
font-weight: 600;
}

.ok-diff-stat-del {
color: #f85149;
font-weight: 600;
}

.ok-source,
.ok-diff {
max-height: 600px;
overflow: auto;
background: var(--code-bg, #0d1117);
border: 1px solid var(--border-color, #30363d);
border-radius: 6px;
font-family: monospace;
font-size: 0.8rem;
line-height: 1.45;
}

.ok-diff.empty {
padding: 1rem;
}

.ok-diff.empty.error {
color: #f85149;
}

.ok-source-row,
.ok-diff-row {
display: flex;
white-space: pre;
}

.ok-source-num {
flex: 0 0 auto;
width: 3.5rem;
padding: 0 0.6rem;
text-align: right;
color: var(--muted, #8b949e);
user-select: none;
border-right: 1px solid var(--border-color, #30363d);
}

.ok-source-line {
flex: 1 1 auto;
padding: 0 0.6rem;
}

.ok-diff-row {
padding: 0 0.75rem;
}

.ok-diff-add {
background: rgba(63, 185, 80, 0.15);
color: #3fb950;
}

.ok-diff-del {
background: rgba(248, 81, 73, 0.15);
color: #f85149;
}

.ok-diff-hunk {
color: var(--accent, #58a6ff);
background: var(--accent-bg, rgba(88, 166, 255, 0.08));
}

.ok-diff-meta {
color: var(--muted, #8b949e);
}
Loading
Loading