Skip to content

Proposal: map TaskDefinition/TaskRunResult/BenchmarkResult onto EvalPort's TestCase/Result/ResultSet #69

Description

@adhabnr-ux

I've been reading through clawbench/schemas.py and the trace-based scoring pipeline (completion/trajectory/behavior/judge axes, pass^k reliability, the 13-mode failure taxonomy) and think ClawBench's result data maps cleanly onto EvalPort — an open interchange format for portable eval datasets/results (JSON schema + a Python openeval SDK + a TS SDK). Wanted to check the mapping against the real field names before proposing anything, rather than show up with a guess.

Mapping, based on sdk/python/openeval/types.py and clawbench/schemas.py as they actually are today:

  • TaskDefinition → EvalPort TestCase: idid; simulated-user turns (SessionPhase.user.turns[].message via TaskDefinition.normalized_phases()) → input (list of turn strings); completion.execution_checkscode-type Graders (command + expected_exit_code as params); judge.rubric → an llm_judge Grader with params.rubric; tier/family/scenario/capabilities/etc. → metadata.

  • TaskRunResult → EvalPort Result: task_idtest_case_id; transcript.assistant_textactual_output; duration_msduration_ms; delivery_outcome.value == "pass"passed; errorerror. The four sub-results (completion_result, trajectory_result, behavior_result, judge_result) each become their own GraderResult (grader_id = gr_completion/gr_trajectory/gr_behavior/gr_judge, type="custom", score, passed = score >= pass_threshold) — the same pattern adapters/ragas-openeval-adapter in the EvalPort repo already uses to turn each independent metric into its own grader instead of collapsing everything into one number.

  • BenchmarkResult → EvalPort ResultSet: submission_idrun_id; {model, provider}provider; timestampstarted_at; task_results/tier_results/scenario_resultssummary.

Sketch — this would live as a standalone clawbench-openeval-adapter package (same playbook as the existing ragas-openeval-adapter/autogen-openeval-adapter: works against ClawBench's public Pydantic models from the outside, nothing needs to merge into ClawBench core):

from openeval.types import TestCase, Grader, Result, GraderResult, ResultSet
from clawbench.schemas import TaskDefinition, TaskRunResult

def task_to_testcase(task: TaskDefinition) -> TestCase:
    turns = [t.message for phase in task.normalized_phases() for t in phase.user.turns]
    graders: list[Grader] = [
        Grader(
            id=f"gr_exec_{c.name}",
            type="code",
            params={"command": c.command, "expected_exit_code": c.expected_exit_code},
        )
        for c in task.completion.execution_checks
    ]
    if task.judge:
        graders.append(Grader(id="gr_judge", type="llm_judge", params={"rubric": task.judge.rubric}))
    return TestCase(
        id=task.id,
        input=turns or [""],
        graders=graders,
        metadata={
            "tier": task.tier.value,
            "family": task.family.value,
            "scenario": task.scenario.value if task.scenario else "",
        },
    )

def run_to_result(run: TaskRunResult) -> Result:
    def gr(name: str, sub, score: float) -> GraderResult:
        return GraderResult(
            grader_id=f"gr_{name}", type="custom", score=score,
            passed=score >= 0.7, reason=getattr(sub, "reason", ""),
        )
    return Result(
        test_case_id=run.task_id,
        passed=run.delivery_outcome.value == "pass",
        grader_results=[
            gr("completion", run.completion_result, run.completion_result.score),
            gr("trajectory", run.trajectory_result, run.trajectory_result.score),
            gr("behavior", run.behavior_result, run.behavior_result.score),
            gr("judge", run.judge_result, run.judge_result.score),
        ],
        actual_output=run.transcript.assistant_text,
        duration_ms=run.duration_ms,
        error={"message": run.error} if run.error else None,
    )

Happy to build this out as an adapter if it's useful. Two things I'd rather ask than assume: (1) is ResultSet.summary the right place for the tier/scenario rollups, or should those stay ClawBench-specific and only per-run Results cross over? (2) Partner Trace Spec already defines a JSONL interchange for traces — is EvalPort's Result/ResultSet meant to be complementary to that (scores/verdicts) rather than overlapping with it (raw trace), or would this proposal be redundant with where PARTNER_TRACE_SPEC.md is headed?

— Sahi, independent contributor (not affiliated with this project)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low-risk cleanup, docs, polish, ergonomics, or speculative feature.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.issue-rating: 🌊 off-meta tidepoolIssue quality rating does not apply to this item.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions