Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

[rig-decomposition-bench] Daily rig decomposition benchmark — 2026-10-19 — no result (task picker failed)

Geschlossen
#678 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Anfängerfreundlichkeit
42/100
Issue-Typ
Bug
Klarheit
Größtenteils klar
Aktivitätsstatus
Aktiv
Tech-Stack
github-actions, node.js, typescript
Bereich
devtools, testing-qa

Rechercherichtung

Start with .github/skills/rig/bench.ts and the captured bench_output.json; the issue shows the task picker returned null with empty stderr. Check the skill’s dependency and Node version requirements, then trace how the picker call handles a null result and what repair() does. Done means the cause is identified and the workflow can produce a task and continue to its benchmark results.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

ai-agent automation

Result: benchmark did not produce data

The run completed (exit 0) but the task-picker agent returned null, so the workflow returned early. The task, timings, solutions, attempts and grading are all empty. Nothing below is invented.

Captured stdout (bench_output.json):

{"status":"failed: task picker returned null","task":null,"attempts":[]}

Captured stderr: empty (0 bytes).

Notes

  • The skill dir had no node_modules, so the first --typecheck failed on every program (even a trivial one) with missing node:* and @types/node errors. I ran npm install in .github/skills/rig (8 packages) and the typecheck then passed. The skill needs its deps installed for this workflow to work without a checkout.
  • The runner's Node is v22.23.3, but the skill requires Node >=24 (EBADENGINE warning). This may be related to the failure, but I did not debug it, as instructed.
  • The picker used small, maxTurns: 2 and repair(). The cause of the null is unknown, because stderr was empty.
  • The program was run exactly once, as instructed.
single-call decomposed
duration (ms) n/a n/a
status n/a not run

Decomposition attempts: none (no task was picked).
Grading: none.

Benchmark program (bench.ts)
import { agent, workflow, s, repair, configureAgent, copilotEngine } 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 CONTRACT = `You write a self-contained TypeScript program for the "rig" library. Rules:
- Import ONLY from "rig" (agent, workflow, s). No other imports, no console.log.
- Split the task across AT LEAST TWO agents, each preceded by a "// Agent role: ..." comment. Each agent sets model: "small" for simple sub-steps, "medium" or "large" for harder ones.
- Coordinate them so the final answer combines the agents' outputs rather than one agent solving everything.
- Root must be exported with "export default" and must NOT be invoked. It 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. body receives { call } (also pipeline, parallel, phase, log); call(agent, input) returns the agent output or null. An agent() root instead declares output: s.object({ solution: s.string }).
- Use s.string as output for every agent whose result is source text or free-form solution. Do not make any agent re-emit a large solution inside an object wrapper.
- Required shape (abridged to one agent; you need at least two):
${SKELETON}
Return ONLY the complete TypeScript source, with no commentary.`;

// Agent role: pick a concrete benchmark task
const picker = agent({
  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) and concrete enough to grade. Vary the domain; today is ${new Date().toISOString().slice(0, 10)} so pick something unusual. Return a 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: solve the whole task in one turn
const solver = agent({
  model: "medium",
  maxTurns: 1,
  instructions: "Solve the whole task yourself in a single response, addressing every success criterion. No delegation, no tools. Return the complete solution.",
  output: s.string,
});

// Agent role: write or fix the decomposed rig program
const writer = agent({
  model: "medium",
  maxTurns: 1,
  instructions: CONTRACT,
  output: s.string,
});

// Agent role: grade both solutions
const grader = agent({
  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 RunResult = { code: number | null; stdout: string; stderr: string; timedOut: boolean };

function runCli(args: string[], input: string, timeoutMs: number): Promise<RunResult> {
  const cp = process.getBuiltinModule("node:child_process");
  return new Promise((resolve) => {
    let stdout = "";
    let stderr = "";
    let timedOut = false;
    const child = cp.spawn(process.execPath, ["rig.ts", ...args], { cwd: process.cwd(), stdio: ["pipe", "pipe", "pipe"] });
    const timer = setTimeout(() => { timedOut = true; child.kill("SIGKILL"); }, timeoutMs);
    child.stdout.on("data", (d: Buffer) => { stdout += d.toString(); });
    child.stderr.on("data", (d: Buffer) => { stderr += d.toString(); });
    child.on("error", (e: Error) => { stderr += String(e); });
    child.on("close", (code: number | null) => { clearTimeout(timer); resolve({ code, stdout, stderr, timedOut }); });
    child.stdin.on("error", () => {});
    child.stdin.end(input);
  });
}

type Attempt = { attempt: number; generation: string; typecheck: string; execute: string; error: string; note: string };

function stripFence(src: string): string {
  const m = src.match(/```(?:ts|typescript|rig)?\s*\n([\s\S]*?)```/);
  return (m ? m[1]! : src).trim();
}

// Workflow role: pick a task, solve it two ways, grade, and return the full report
export default workflow({
  meta: { name: "rig-decomposition-bench", description: "Compare single-call vs decomposed solving", phases: ["Pick", "Single", "Decompose", "Grade"] },
  body: async ({ call, phase, log }) => {
    phase("Pick");
    const task = await call(picker, "Pick the task now.", { timeout: Math.max(1000, Math.min(180_000, left())) });
    if (!task) return { status: "failed: task picker returned null", task: null, attempts: [] as Attempt[] };
    const taskText = `Title: ${task.title}\nDomain: ${task.domain}\nDescription: ${task.description}\nSuccess criteria:\n${task.criteria.map((c: string) => `- ${c}`).join("\n")}`;

    phase("Single");
    const t0 = Date.now();
    const single = await call(solver, taskText, { timeout: Math.max(1000, Math.min(480_000, left())) });
    const singleMs = Date.now() - t0;

    phase("Decompose");
    const d0 = Date.now();
    const attempts: Attempt[] = [];
    let source = "";
    let decomposed = "";
    let status = "fail";
    let prevSource = "";
    let prevError = "";
    for (let n = 1; n <= 2; n++) {
      if (left() < 120_000) { log("budget exhausted"); break; }
      let prompt: string;
      if (n === 1) prompt = `Write the program for this task:\n${taskText}`;
      else if (prevSource.trim()) prompt = `Fix the program below. Fix precisely what the error names and preserve what already worked.\n\nTask:\n${taskText}\n\nRequired shape:\n${SKELETON}\n\nSource:\n${prevSource}\n\nError:\n${prevError}`;
      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 shape:\n${SKELETON}`;
      const raw = await call(writer, prompt, { timeout: Math.max(1000, Math.min(300_000, left())) });
      const src = raw ? stripFence(raw) : "";
      const rec: Attempt = { attempt: n, generation: "", typecheck: "skipped", execute: "skipped", error: "", note: "" };
      attempts.push(rec);
      if (!src.trim()) {
        rec.generation = "empty/null";
        rec.error = "writer returned null or whitespace-only source";
        prevSource = ""; prevError = rec.error;
        rec.note = n < 2 ? "Next attempt generates the program from scratch (no source to fix)." : "";
        continue;
      }
      rec.generation = "non-empty";
      source = src;
      prevSource = src;
      const tc = await runCli(["--typecheck"], src, Math.max(1000, Math.min(120_000, left())));
      if (tc.code !== 0) {
        rec.typecheck = tc.timedOut ? "timeout" : "fail";
        rec.error = `${tc.stdout}\n${tc.stderr}`.trim();
        prevError = rec.error;
        rec.note = n < 2 ? "Next attempt passes source and typecheck error to the fixer." : "";
        continue;
      }
      rec.typecheck = "pass";
      if (left() < 30_000) { rec.execute = "skipped (budget)"; break; }
      const ex = await runCli(["--server"], src, Math.max(1000, Math.min(300_000, left())));
      if (ex.code !== 0 || ex.timedOut) {
        rec.execute = ex.timedOut ? "timeout" : "fail";
        rec.error = `exit=${ex.code}\n${ex.stdout}\n${ex.stderr}`.trim();
        prevError = rec.error;
        rec.note = n < 2 ? "Next attempt passes source and execution error to the fixer." : "";
        continue;
      }
      let parsed: { solution?: unknown } | null = null;
      try { parsed = JSON.parse(ex.stdout); } catch { parsed = null; }
      if (parsed && typeof parsed.solution === "string" && parsed.solution.trim()) {
        rec.execute = "pass";
        decomposed = parsed.solution;
        status = "pass";
        break;
      }
      rec.execute = "fail";
      rec.error = `stdout was not JSON with non-empty solution:\n${ex.stdout}\n${ex.stderr}`.trim();
      prevError = rec.error;
      rec.note = n < 2 ? "Next attempt passes source and the output error to the fixer." : "";
    }
    const decomposedMs = Date.now() - d0;

    phase("Grade");
    const placeholder = "[Decomposition produced no solution: the generated program failed to produce output.]";
    let grade = null;
    if (left() > 20_000) {
      grade = await call(grader, `${taskText}\n\n=== SOLUTION A (single-call) ===\n${single ?? "[no solution]"}\n\n=== SOLUTION B (decomposed) ===\n${decomposed.trim() ? decomposed : placeholder}`, { timeout: Math.max(1000, Math.min(300_000, left())) });
    }
    return { task, singleMs, decomposedMs, singleSolution: single ?? "", decomposedSolution: decomposed, attempts, status, grade, decomposedSource: source };
  },
});

Verdict: no winner — the benchmark produced no data because the task picker returned null (empty stderr), so no solutions were generated or graded.

Generated by Daily Rig Decomposition Benchmark · copilot · auto · 34.9 AIC · ⌖ 0.679 AIC · ⊞ 10.1K · ◷

  • expires on Oct 26, 2026, 1:12 PM UTC
Vorherrschende Sprache
TypeScript
Sterne
14
Forks
0
Ø Merge
9 Std. 44 Min.
Gemergte PRs (30 T.)
33

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

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus githubnext/rig

Alle Issues in githubnext/rig

Ähnliche Issues

Weitere Issues zu TypeScript

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.