[rig-decomposition-bench] Daily rig decomposition benchmark — 2026-10-24 — no winner (picker failed)
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 2/5
- Geschätzter Aufwand
- 1-3 Stunden
- Anfängerfreundlichkeit
- 50/100
- Issue-Typ
- Bug
- Klarheit
- Größtenteils klar
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- github-actions, typescript
- Bereich
- ai-infra-agents, testing-qa
Rechercherichtung
Start with the task picker definition and the workflow call in the embedded bench.ts; inspect how call(picker, ...) handles a null result and how repair() is configured. Reproduce the run-once failure and identify a concrete change that lets the benchmark continue or report a useful failure. Done when the picker failure is handled as intended and a run records a clear outcome; the issue does not specify a fix or a test.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Result: benchmark failed at the task-picker step
The task picker (small agent with repair(), maxTurns: 2) returned null, so the workflow returned early. Per the run-once rule it was not retried.
Captured stdout (bench_output.json):
{
"error": "task picker returned null",
"status": "fail"
}
Captured stderr: empty (0 bytes). Exit code was 0.
Typecheck note: --typecheck reported no errors in the benchmark program itself. It did print errors from rig.ts and engines/* (missing @types/node / NodeJS types), and the same errors appear for a trivial one-agent program.
Task
Not chosen (picker returned null).
Timing comparison
| single-call (ms) | decomposed (ms) | decomposed status | |
|---|---|---|---|
| not run | not run | fail (never started) |
Decomposition attempts
None. There was no task to give the writer.
Grading
Not run. There are no scores, no winner and no rationale.
Single-call solution
Not produced.
Decomposed program source and solution
Not produced.
Benchmark program (bench.ts)
import { agent, workflow, s, configureAgent, copilotEngine, repair } from "rig";
configureAgent(copilotEngine());
const DEADLINE = Date.now() + 25 * 60_000;
const left = () => DEADLINE - Date.now();
const SKELETON = `import { agent, workflow, s } from "rig";
// Agent role: <role>
const analyze = agent({ model: "small", instructions: "...", output: s.string });
// Workflow role: combines the agents' outputs into the final solution
export default workflow({
meta: { name: "decomposed-solution", description: "..." },
body: async ({ call }) => {
const analysis = await call(analyze, "...");
return { solution: analysis ?? "" };
},
});`;
const RULES = `Rules for the rig program (you have no access to the library docs, follow these exactly):
- Import only from "rig". Export the root via \`export default\` and never invoke it. The root takes no required input.
- A workflow() spec accepts only meta, an optional input, and body. It has NO output or execute field; the final { solution } object is simply what body returns.
- An agent() root instead declares output: s.object({ solution: s.string }).
- agent() fields: name, instructions, input, output, model ("small" | "medium" | "large"), maxTurns, addons, agents, tools.
- Inside body({ call, parallel, pipeline }): call(agent, input) returns the output or null on failure; parallel([thunks]) runs thunks concurrently.
- Use at least two agents, each preceded by a "// Agent role: ..." comment; use "small" for simple sub-steps, "medium" or "large" for harder ones. Put a "// Workflow role: ..." comment above the workflow.
- The final answer must combine the agents' outputs, not come from one agent solving everything.
- Use s.string for every agent whose result is source text or free-form solution; do not make agents re-emit a large solution inside an object wrapper.
- Do not use console.log. Return ONLY the complete TypeScript source, optionally in one \`\`\`ts fence.
Required shape (abridged to one agent; you need at least two):
${SKELETON}`;
const picker = agent({
name: "picker",
model: "small",
maxTurns: 2,
addons: [repair()],
instructions:
"Pick ONE concrete, complicated task a person or team might face in a single day that would naturally benefit from being split across sub-agents running different models: multi-source research and synthesis, a multi-file coding task with design/implementation/review phases, a structured report combining independent analyses, or a multi-step data transformation pipeline. It must be self-contained (solvable from its description alone, no external files or live web access) and concrete enough to grade. Vary the domain; pick randomly. Return title, domain, description, and 3-6 concrete checkable success criteria.",
output: s.object({
title: s.string,
domain: s.string,
description: s.string,
criteria: s.array(s.string),
}),
});
// Agent role: solves the whole task alone in one turn
const solver = agent({
name: "solver",
model: "medium",
maxTurns: 1,
instructions:
"Solve the entire task yourself in one response, addressing every success criterion explicitly. No delegation, no tools. Return the complete solution verbatim.",
output: s.string,
});
// Agent role: writes (and fixes) the decomposed rig program
const writer = agent({
name: "writer",
model: "medium",
maxTurns: 1,
instructions:
"You write self-contained rig TypeScript programs that solve a task by splitting it across multiple agents.\n" + RULES,
output: s.string,
});
// Agent role: grades both solutions
const grader = agent({
name: "grader",
model: "large",
maxTurns: 1,
instructions:
"Score each solution 0-10 on how completely and correctly it satisfies the success criteria. Judge only correctness and completeness of content, not length and not which approach produced it. Pick winner single-call, decomposed, or tie and explain the comparison.",
output: s.object({
singleScore: s.number,
decomposedScore: s.number,
winner: s.enum("single-call", "decomposed", "tie"),
rationale: s.string,
}),
});
type Attempt = {
attempt: number;
generation: string;
typecheck: string;
execute: string;
error: string;
};
function stripFence(src: string): string {
const m = src.match(/```(?:ts|typescript|rig)?\s*\n([\s\S]*?)```/);
return (m ? m[1] : src).trim();
}
async function runCli(args: string[], input: string, timeoutMs: number) {
const modName: string = "node:child_process";
const { spawn } = (await import(modName)) as any;
const proc = (globalThis as any).process;
return new Promise<{ code: number | null; stdout: string; stderr: string; timedOut: boolean }>((resolve) => {
const child = spawn("node", ["rig.ts", ...args], { cwd: proc.cwd() });
let stdout = "";
let stderr = "";
let timedOut = false;
const t = setTimeout(() => {
timedOut = true;
child.kill("SIGKILL");
}, Math.max(1000, timeoutMs));
child.stdout.on("data", (d: any) => (stdout += d.toString()));
child.stderr.on("data", (d: any) => (stderr += d.toString()));
child.on("error", (e: Error) => {
clearTimeout(t);
resolve({ code: -1, stdout, stderr: stderr + String(e), timedOut });
});
child.on("close", (code: number | null) => {
clearTimeout(t);
resolve({ code, stdout, stderr, timedOut });
});
child.stdin.on("error", () => {});
child.stdin.end(input);
});
}
// Workflow role: pick a task, solve it two ways, grade, and return the report
export default workflow({
meta: { name: "decomposition-bench", description: "Single-call vs decomposed rig solution benchmark" },
body: async ({ call }) => {
const task = await call(picker, "Pick the task now.", { label: "pick" });
if (!task) return { error: "task picker returned null", status: "fail" };
const taskText = `Title: ${task.title}\nDomain: ${task.domain}\nDescription: ${task.description}\nSuccess criteria:\n${task.criteria.map((c: string, i: number) => `${i + 1}. ${c}`).join("\n")}`;
const t0 = Date.now();
const singleSolution = (await call(solver, taskText, { label: "single", timeout: Math.min(8 * 60_000, Math.max(30_000, left())) })) ?? "";
const singleMs = Date.now() - t0;
const d0 = Date.now();
const attempts: Attempt[] = [];
let source = "";
let decomposedSolution = "";
let status = "fail";
let prevSource = "";
let prevError = "";
for (let n = 1; n <= 2; n++) {
if (left() < 4 * 60_000) break;
let prompt: string;
if (n === 1) {
prompt = `Write the decomposed rig program for this task.\n\n${taskText}`;
} else if (prevSource.trim()) {
prompt = `Fix this rig program. Fix precisely what the error names and preserve what already worked.\n\nTask:\n${taskText}\n\nCurrent source:\n${prevSource}\n\nCaptured error:\n${prevError}\n\nRequired skeleton:\n${SKELETON}`;
} else {
prompt = `There is no source to fix: the previous attempt produced nothing. Generate the complete program from scratch.\n\nTask:\n${taskText}\n\nRequired skeleton:\n${SKELETON}`;
}
const raw = await call(writer, prompt, { label: `writer-${n}`, timeout: Math.min(6 * 60_000, Math.max(30_000, left())) });
const rec: Attempt = { attempt: n, generation: "", typecheck: "skipped", execute: "skipped", error: "" };
attempts.push(rec);
const src = raw ? stripFence(raw) : "";
if (!src.trim()) {
rec.generation = "empty/null";
prevSource = "";
prevError = "empty source";
continue;
}
rec.generation = "ok";
source = src;
prevSource = src;
const tc = await runCli(["--typecheck"], src, Math.min(2 * 60_000, left()));
if (tc.code !== 0 || tc.timedOut) {
rec.typecheck = tc.timedOut ? "timeout" : "fail";
rec.error = `${tc.stdout}\n${tc.stderr}`.trim() || "typecheck failed";
prevError = rec.error;
continue;
}
rec.typecheck = "pass";
if (left() < 30_000) { rec.execute = "skipped (no time)"; break; }
const ex = await runCli(["--server"], src, Math.min(5 * 60_000, left()));
if (ex.code !== 0 || ex.timedOut) {
rec.execute = ex.timedOut ? "timeout" : "fail";
rec.error = `${ex.stderr}\n${ex.stdout}`.trim() || "execute failed";
prevError = rec.error;
continue;
}
try {
const parsed = JSON.parse(ex.stdout);
const sol = parsed?.solution ?? parsed?.output?.solution ?? parsed?.result?.solution;
if (typeof sol === "string" && sol.trim()) {
rec.execute = "pass";
decomposedSolution = sol;
status = "pass";
break;
}
rec.execute = "fail";
rec.error = `No solution string in stdout: ${ex.stdout.slice(0, 4000)}`;
} catch (e) {
rec.execute = "fail";
rec.error = `Invalid JSON stdout: ${String(e)}\n${ex.stdout.slice(0, 4000)}`;
}
prevError = rec.error;
}
const decomposedMs = Date.now() - d0;
const decomposedForGrading = decomposedSolution.trim() || "(Decomposition produced no solution.)";
let grade: { singleScore: number; decomposedScore: number; winner: string; rationale: string } | null = null;
if (left() > 30_000) {
grade = await call(
grader,
`${taskText}\n\n=== SOLUTION A (single-call) ===\n${singleSolution || "(empty)"}\n\n=== SOLUTION B (decomposed) ===\n${decomposedForGrading}`,
{ label: "grade", timeout: Math.min(5 * 60_000, Math.max(30_000, left())) },
);
}
return {
task,
singleMs,
decomposedMs,
singleSolution,
decomposedSolution,
attempts,
status,
decomposedSource: source,
grade,
};
},
});
Verdict: no winner. The picker returned null on this run, so the benchmark produced no data.
Generated by Daily Rig Decomposition Benchmark · copilot · auto · ~37 AIC · ⌖ ~1 AIC · ⊞ 4.1K · ◷
- expires on Oct 31, 2026, 1:03 PM UTC
- Vorherrschende Sprache
- TypeScript
- Sterne
- 14
- Forks
- 0
- Ø Merge
- 9 Std. 27 Min.
- Gemergte PRs (30 T.)
- 34
Entwicklungsumgebung
Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus githubnext/rig
-
ai-agent automation
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 48/100
githubnext/rig#716 ·
Maintainer antworten meist innerhalb von 1 Tag
-
ai-agent automation
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 1/100
githubnext/rig#715 ·
Maintainer antworten meist innerhalb von 1 Tag
-
agentic-workflows
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 35/100
githubnext/rig#713 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
agentic-workflows
Schwierigkeit 4/5 1-2 Tage Anfängerfreundlichkeit 35/100
githubnext/rig#711 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
agentic-workflows
Schwierigkeit 4/5 1-2 Tage Anfängerfreundlichkeit 35/100
githubnext/rig#710 ·
Maintainer antworten meist innerhalb von 1 Tag
Ähnliche Issues
-
[Bug]: Device screenshot fails with 500 on iPhone Duo (Xcode 27.2): serve-sim calls simctl without --displayEvtl. vergeben Ein verknüpfter Pull Request ist offen oder bereits gemergt. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 66/100
pingdotgg/t3code#24900 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
inu-appcenter/UNIDorm-web#411 ·
Maintainer antworten meist innerhalb von 1 Tag
-
🐛 bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 75/100
ranxianglei/billion-context#4720 ·
Maintainer antworten meist innerhalb von 1 Tag
-
area:arcade game p3-medium ready-for-agent type:bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
fderuiter/deruiter.dev#2840 ·
Maintainer antworten meist innerhalb von 1 Tag