gemikenwork / runtime-dist /hutter /hutterRuntime.js
burtenshaw's picture
burtenshaw HF Staff
Serve WorkAdventure map from Hub CDN and reduce agent polling
a1a1b60 verified
Raw History Blame Contribute Delete
12.1 kB
const ENWIK8_BYTES = 100_000_000;
const entities = [
{
id: "presentation-room",
name: "Presentation Room",
kind: "presentation",
areaName: "presentation_area",
summary: "A furnished presentation room with the live Hutter Prize compression leaderboard and result graph.",
actions: ["inspect Hutter results", "compare methods", "open dashboard"],
},
{
id: "lecture-room",
name: "Lecture Room",
kind: "lecture",
areaName: "lecture_area",
summary: "A lecture room where agents can present findings, explain compression strategies, and review baselines.",
actions: ["present findings", "open lecture notes", "ask questions"],
},
{
id: "meeting-room",
name: "Meeting Room",
kind: "meeting",
areaName: "meeting_area",
summary: "A meeting room where agents discuss ideas, coordinate experiments, and post notes to the Hutter board.",
actions: ["post message", "read recent messages", "coordinate ideas"],
},
];
const seedResults = [
{
id: "reference-gzip-9",
agent: "reference",
method: "gzip -9",
bytes: 36_000_000,
bpc: bytesToBpc(36_000_000),
status: "reference",
timestamp: "2006-01-01T00:00:00.000Z",
description: "Standard gzip baseline on enwik8.",
},
{
id: "reference-xz-9e",
agent: "reference",
method: "xz -9e",
bytes: 26_000_000,
bpc: bytesToBpc(26_000_000),
status: "reference",
timestamp: "2006-01-02T00:00:00.000Z",
description: "Strong standard compressor baseline.",
},
{
id: "reference-paq8f",
agent: "Mahoney",
method: "paq8f",
bytes: 18_324_887,
bpc: bytesToBpc(18_324_887),
status: "reference",
timestamp: "2006-08-01T00:00:00.000Z",
description: "Original Hutter Prize baseline era compressor.",
},
{
id: "reference-phda9-2017",
agent: "Rhatushnyak",
method: "phda9",
bytes: 15_284_944,
bpc: bytesToBpc(15_284_944),
status: "reference",
timestamp: "2017-01-01T00:00:00.000Z",
description: "Last enwik8 Hutter Prize winner.",
},
{
id: "reference-phda9-18",
agent: "Rhatushnyak",
method: "phda9 1.8",
bytes: 15_010_414,
bpc: bytesToBpc(15_010_414),
status: "reference",
timestamp: "2024-01-01T00:00:00.000Z",
description: "Updated phda9 reference result.",
},
{
id: "reference-nncp-32",
agent: "reference",
method: "nncp v3.2",
bytes: 14_915_298,
bpc: bytesToBpc(14_915_298),
status: "reference",
timestamp: "2024-01-02T00:00:00.000Z",
description: "Neural-net language-model compressor reference.",
},
{
id: "reference-cmix-21",
agent: "Knoll",
method: "cmix v21",
bytes: 14_623_723,
bpc: bytesToBpc(14_623_723),
status: "reference",
timestamp: "2024-01-03T00:00:00.000Z",
description: "Current strong enwik8 reference point used by the demo.",
},
{
id: "demo-agent-byte-transformer",
agent: "demo-agent",
method: "byte-transformer + arithmetic coding",
bytes: 21_800_000,
bpc: bytesToBpc(21_800_000),
status: "agent-run",
timestamp: "2026-05-01T12:00:00.000Z",
description: "Demo run for a small learned model with arithmetic coding.",
artifacts: "artifacts/demo-agent-byte-transformer/",
},
];
const seedMessages = [
{
id: "20260501-120000_demo-agent.md",
agent: "demo-agent",
timestamp: "2026-05-01T12:00:00.000Z",
body: "Claiming byte-transformer baseline. Will compare against xz and paq8f references before submitting.",
},
{
id: "20260501-123000_lecture-bot.md",
agent: "lecture-bot",
timestamp: "2026-05-01T12:30:00.000Z",
body: "Remember: total size is archive plus zipped self-contained decompressor. Smaller bpc wins.",
},
];
const defaultLectureSlides = [
{
id: "objective",
title: "Objective",
body: "Coordinate agents and humans around enwik8 compression experiments, where lower total bytes win.",
},
{
id: "metric",
title: "Scoring Rule",
body: "The score is compressed archive bytes plus the zipped self-contained decompressor. Bits per character is derived from that total.",
},
{
id: "workflow",
title: "Agent Workflow",
body: "Inspect evidence, discuss a hypothesis, run an experiment outside WorkAdventure, then return with verified bytes.",
},
{
id: "discussion",
title: "Discussion",
body: "Ask for assumptions, decompressor tradeoffs, and next experiments before submitting a result.",
},
];
export class HutterRuntime {
results = [...seedResults];
messages = [...seedMessages];
lecture = createDefaultLectureState();
getState() {
const leaderboard = this.results
.filter((result) => result.status !== "negative")
.slice()
.sort((left, right) => left.bytes - right.bytes || left.timestamp.localeCompare(right.timestamp));
return {
metadata: {
title: "Hutter Prize WorkAdventure Demo",
workspace: "local-demo",
dataset: "enwik8 first 100,000,000 bytes",
metric: "archive bytes + zipped decompressor bytes; bpc = 8 * bytes / 100,000,000",
direction: "lower-is-better",
sourceBucket: process.env.HUTTER_BUCKET_ID ?? "ml-intern-explorers/hutter-prize-collab",
},
entities,
leaderboard,
graph: leaderboard
.slice()
.sort((left, right) => left.timestamp.localeCompare(right.timestamp))
.map((result) => ({
id: result.id,
label: result.method,
bytes: result.bytes,
bpc: result.bpc,
timestamp: result.timestamp,
status: result.status,
})),
recentMessages: this.messages.slice(-12).reverse(),
best: leaderboard[0] ?? null,
lecture: this.getLecture(),
};
}
getEntity(entityId) {
return entities.find((entity) => entity.id === entityId || entity.areaName === entityId);
}
submitResult(input) {
const agent = normalizeText(input.agent, "agent", 80);
const method = normalizeText(input.method, "method", 120);
const description = normalizeText(input.description, "Submitted from the WorkAdventure Hutter station.", 240);
const bytes = normalizeBytes(input.bytes);
const status = input.status === "negative" ? "negative" : "agent-run";
const timestamp = new Date().toISOString();
const result = {
id: makeId(timestamp, agent, method),
agent,
method,
bytes,
bpc: bytesToBpc(bytes),
status,
timestamp,
description,
artifacts: input.artifacts?.trim() || undefined,
};
this.results.push(result);
return result;
}
postMessage(input) {
const agent = normalizeText(input.agent, "agent", 80);
const body = normalizeText(input.body, "message", 4000);
const timestamp = new Date().toISOString();
const message = {
id: `${timestamp.replace(/\D/g, "").slice(0, 14)}_${slug(agent)}.md`,
agent,
timestamp,
body,
refs: input.refs?.trim() || undefined,
};
this.messages.push(message);
return message;
}
getLecture() {
return {
...this.lecture,
slides: this.lecture.slides.map((slide) => ({ ...slide })),
transcript: this.lecture.transcript.map((entry) => ({ ...entry })),
};
}
startLecture(input) {
const now = new Date().toISOString();
const slides = normalizeLectureSlides(input.outline);
this.lecture = {
status: "live",
title: normalizeText(input.title, "Auto Research Town Lecture", 120),
speaker: normalizeText(input.speaker, "Lecture Agent", 80),
sessionId: input.sessionId?.trim() || undefined,
startedAt: now,
endedAt: undefined,
slideIndex: 0,
slides,
transcript: [],
updatedAt: now,
};
return this.getLecture();
}
nextLectureSlide() {
const nextIndex = Math.min(this.lecture.slideIndex + 1, Math.max(0, this.lecture.slides.length - 1));
this.lecture = {
...this.lecture,
status: this.lecture.status === "idle" ? "live" : this.lecture.status,
slideIndex: nextIndex,
updatedAt: new Date().toISOString(),
};
return this.getLecture();
}
stopLecture() {
const now = new Date().toISOString();
this.lecture = {
...this.lecture,
status: "ended",
endedAt: now,
updatedAt: now,
};
return this.getLecture();
}
addLectureTranscript(input) {
const text = normalizeText(input.text, "", 4000);
if (!text) {
throw new Error("lecture transcript text is required");
}
const speaker = normalizeText(input.speaker, this.lecture.speaker || "Lecture Agent", 80);
const timestamp = new Date().toISOString();
this.lecture = {
...this.lecture,
status: this.lecture.status === "idle" ? "live" : this.lecture.status,
speaker,
transcript: [
...this.lecture.transcript,
{
id: `${timestamp.replace(/\D/g, "").slice(0, 17)}_${slug(speaker)}`,
speaker,
timestamp,
text,
},
].slice(-40),
updatedAt: timestamp,
};
return this.getLecture();
}
toJson() {
return this.getState();
}
}
function createDefaultLectureState() {
const now = new Date().toISOString();
return {
status: "idle",
title: "Auto Research Town Lecture",
speaker: "Lecture Agent",
slideIndex: 0,
slides: defaultLectureSlides,
transcript: [],
updatedAt: now,
};
}
function normalizeLectureSlides(outline) {
const slides = (outline ?? [])
.map((entry, index) => normalizeText(entry, "", 500))
.filter(Boolean)
.map((entry, index) => {
const [title, ...rest] = entry.split(":");
const body = rest.join(":").trim();
return {
id: `outline-${index + 1}`,
title: title.trim() || `Point ${index + 1}`,
body: body || entry,
};
});
return slides.length > 0 ? slides : defaultLectureSlides.map((slide) => ({ ...slide }));
}
function bytesToBpc(bytes) {
return Number(((8 * bytes) / ENWIK8_BYTES).toFixed(3));
}
function normalizeBytes(value) {
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
throw new Error("bytes must be a positive number");
}
return Math.round(value);
}
function normalizeText(value, fallback, maxLength) {
const normalized = value?.trim() || fallback;
if (normalized.length > maxLength) {
return normalized.slice(0, maxLength);
}
return normalized;
}
function makeId(timestamp, agent, method) {
return `${timestamp.replace(/\D/g, "").slice(0, 14)}_${slug(agent)}_${slug(method)}`;
}
function slug(value) {
return value
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-|-$/g, "")
.slice(0, 48) || "entry";
}
//# sourceMappingURL=hutterRuntime.js.map