Skip to content

feat(evaluator): taskset references for agent evaluation + Tasks/Tasksets docs#779

Open
SandyChapman wants to merge 3 commits into
mainfrom
schapman/evaluator-tasks-taskset-docs-7e3261
Open

feat(evaluator): taskset references for agent evaluation + Tasks/Tasksets docs#779
SandyChapman wants to merge 3 commits into
mainfrom
schapman/evaluator-tasks-taskset-docs-7e3261

Conversation

@SandyChapman

@SandyChapman SandyChapman commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What

Two related changes for stored evaluator Tasks & Tasksets:

1. Feature — taskset references on the agent-eval submit path

Previously an agent evaluation could only be submitted with an inline list of tasks; stored tasksets were CRUD-only with no consumer. This makes AgentEvalInputSpec.tasks a union:

AgentEvalInputSpec(tasks=TasksetRef("default/geography-suite"), target=...)
# or, as before:
AgentEvalInputSpec(tasks=[AgentEvalTaskInput(...), ...], target=...)

During AgentEvalJob.to_spec, a TasksetRef is loaded and its member tasks are expanded into inline task DTOs, then the existing metric-ref resolution runs — so a taskset-driven run hydrates to the same canonical AgentEvalSpec as an inline one.

  • New TasksetRef (api/schemas.py) and task_refs.py resolution helper (mirrors metric_refs.py).
  • Clear errors for: unknown taskset, missing/deleted member task, empty taskset, duplicate expanded task ids (same name across workspaces), and local runs with no entity store.
  • Known limitation (documented): stored tasks have no grader-only reference field (it lives only on inline AgentEvalTaskInput), so taskset-driven tasks run with an empty reference. Best for metrics that score output directly.
  • Regenerated the plugin OpenAPI spec (tasks becomes anyOf [TasksetRef, array]).

2. Docs — Manage Tasks & Tasksets

New page covering CRUD for stored tasks/tasksets via client.evaluator.tasks / .tasksets, field references, the REST API, and a Run an evaluation over a taskset section demonstrating the feature above. Registered in the Fern nav after SDK Resources.

Testing

  • plugins/nemo-evaluator/tests/test_task_refs.py (new) — resolution unit coverage; test_agent_evaluate.py — union-field schema tests.
  • Full evaluator unit suite: 495 passed.
  • ruff check / ruff format --check / ty check (CI script) clean on changed files.
  • make docs-check + make docs-broken-links pass.
  • Live-validated against a running evaluator plugin: created a metric + two tasks + a taskset, submitted AgentEvalInputSpec(tasks=TasksetRef(...)), and confirmed to_spec resolves to a hydrated AgentEvalSpec (2 tasks, inline metrics); unknown taskset errors cleanly. Also confirmed the doc's create/list/delete examples and the inline-metric normalization behavior end to end.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for running evaluations using stored tasksets, alongside inline task lists.
    • Added taskset reference validation and expansion, including clear errors for missing, empty, or duplicate tasks.
    • Added comprehensive documentation for creating, managing, and evaluating tasks and tasksets.
    • Added “Manage Tasks & Tasksets” to the Evaluator documentation navigation.
  • Bug Fixes

    • Prevented empty inline task lists from being submitted for evaluation.
    • Improved validation and resolution of taskset references.

@github-actions github-actions Bot added the docs label Jul 20, 2026
@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 26384/34035 77.5% 61.8%
Integration Tests 15177/32660 46.5% 18.7%

Add a Manage Tasks & Tasksets page covering the stored task/taskset
entities added in the AALGO-307 stack: concepts, create/retrieve/list/
delete via the nemo_platform SDK (client.evaluator.tasks / .tasksets),
field references, workspace/project handling, and the underlying REST
API. Registers the page in the published Fern nav after SDK Resources.

Fills a documented gap: there was no user-facing doc for task/taskset
management.

Signed-off-by: Sandy Chapman <schapman@nvidia.com>
@SandyChapman
SandyChapman force-pushed the schapman/evaluator-tasks-taskset-docs-7e3261 branch from bc9f1ae to fb31f70 Compare July 21, 2026 11:35
@SandyChapman SandyChapman changed the title docs(evaluator): document Tasks & Tasksets management feat(evaluator): taskset references for agent evaluation + Tasks/Tasksets docs Jul 21, 2026
@github-actions github-actions Bot added the feat label Jul 21, 2026
…path

AgentEvalInputSpec.tasks becomes a union: an inline list of tasks or a
TasksetRef naming a stored taskset. During to_spec a taskset reference is
loaded and its member tasks are expanded into inline task DTOs, then the
existing metric-ref resolution runs — so a taskset-driven run hydrates to
the same canonical AgentEvalSpec as an inline one.

- Add TasksetRef (schemas.py) and task_refs.py (resolution helper mirroring
  metric_refs.py): loads the taskset + member tasks, maps each stored task to
  an AgentEvalTaskInput, and raises clear errors for a missing taskset, a
  missing/deleted member, an empty taskset, duplicate expanded ids, or a
  local run with no entity store.
- Stored tasks carry no grader-only reference field, so taskset-driven tasks
  run with an empty reference (documented).
- Document the run-over-a-taskset flow in the Manage Tasks & Tasksets page.
- Regenerate the plugin OpenAPI spec for the new union + TasksetRef schema.

Tests: unit coverage for resolution + the union field; verified live end to
end that a TasksetRef resolves through to_spec into a hydrated AgentEvalSpec
with inline metrics.

Signed-off-by: Sandy Chapman <schapman@nvidia.com>
@SandyChapman
SandyChapman force-pushed the schapman/evaluator-tasks-taskset-docs-7e3261 branch from 09c8023 to 666f57e Compare July 21, 2026 12:39
Integration test (opt-in, RUN_AGENT_EVAL_INTEGRATION=1): stores a numeric
metric + two tasks + a taskset via the SDK, then submits an agent-evaluate
job whose `tasks` is a TasksetRef (no inline tasks) against a real spun
platform with an IGW mock model. Proves the server resolves the taskset ->
both member tasks -> each task's stored MetricRef -> inline, runs both, and
scores them: asserts nan_count == 0, count == 2, mean == 1.0 (both members
ran and scored, no failed samples).

Adds a numeric _OutputScoreMetric (continuous_score) so the run aggregate
carries a real count/mean; a boolean output would land in nan_count and
obscure whether scoring actually succeeded.

Signed-off-by: Sandy Chapman <schapman@nvidia.com>
@SandyChapman
SandyChapman marked this pull request as ready for review July 21, 2026 13:29
@SandyChapman
SandyChapman requested review from a team as code owners July 21, 2026 13:29
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Taskset references are now supported in agent evaluation inputs. Stored tasksets resolve into inline tasks and stored metric references before evaluation, with validation for missing, empty, or duplicate task entries. Documentation, OpenAPI schemas, navigation, unit tests, and integration coverage were added.

Taskset-backed agent evaluations

Layer / File(s) Summary
Taskset reference contract
plugins/nemo-evaluator/src/nemo_evaluator/api/schemas.py, plugins/nemo-evaluator/src/nemo_evaluator/jobs/agent_spec.py, plugins/nemo-evaluator/openapi/openapi.yaml
AgentEvalInputSpec.tasks accepts either inline tasks or a validated TasksetRef.
Submit-time taskset expansion
plugins/nemo-evaluator/src/nemo_evaluator/task_refs.py, plugins/nemo-evaluator/src/nemo_evaluator/jobs/agent_evaluate.py, plugins/nemo-evaluator/src/nemo_evaluator/jobs/{evaluate,metric_resolution}.py
Taskset and member task entities are loaded, converted to inline task inputs, and passed through metric resolution.
Resolution and evaluation validation
plugins/nemo-evaluator/tests/test_task_refs.py, plugins/nemo-evaluator/tests/test_agent_evaluate.py, plugins/nemo-evaluator/tests/integration/test_agent_evaluate_job.py
Tests cover expansion, workspace resolution, validation errors, serialization, and scoring across taskset members.
Task and taskset documentation
docs/evaluator/manage-tasks-tasksets.mdx, docs/fern/versions/latest.yml
Documents task and taskset management, taskset-based evaluations, SDK usage, REST endpoints, and navigation placement.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AgentEvalJob
  participant EntityClient
  participant MetricResolution
  Client->>AgentEvalJob: submit AgentEvalInputSpec with TasksetRef
  AgentEvalJob->>EntityClient: load taskset and member tasks
  EntityClient-->>AgentEvalJob: stored task entities
  AgentEvalJob->>MetricResolution: resolve metrics for expanded tasks
  MetricResolution-->>AgentEvalJob: canonical evaluation spec
  AgentEvalJob-->>Client: evaluation result
Loading

Suggested reviewers: ngoncharenko, svvarom

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title clearly summarizes the main change: taskset references for agent evaluation and new Tasks/Tasksets docs.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch schapman/evaluator-tasks-taskset-docs-7e3261

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
plugins/nemo-evaluator/src/nemo_evaluator/task_refs.py (1)

43-93: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Parallelize member-task fetches.

resolve_taskset_ref awaits entity_client.get(TaskEntity, ...) once per member sequentially. For a taskset with many members this serializes N entity-store round trips. Dedup detection doesn't depend on fetch order, so gather the fetches concurrently.

⚡ Proposed fix: fetch members concurrently
+import asyncio
+
 async def resolve_taskset_ref(
     ref: TasksetRef,
     *,
     workspace: str,
     entity_client: EntityClient | None,
 ) -> list[AgentEvalTaskInput]:
     ...
-    tasks: list[AgentEvalTaskInput] = []
-    seen_ids: set[str] = set()
-    for task_ref in taskset.tasks:
-        task_workspace, task_name = parse_entity_ref(task_ref.root, ref_workspace)
-        try:
-            entity = await entity_client.get(TaskEntity, name=task_name, workspace=task_workspace)
-        except EntityNotFoundError as exc:
-            raise ValueError(
-                f"Task '{task_ref.root}' referenced by taskset '{ref.root}' was not found; "
-                "the stored task may have been deleted after the taskset was created."
-            ) from exc
-        if entity.name in seen_ids:
-            raise ValueError(
-                f"Taskset '{ref.root}' expands to more than one task named '{entity.name}'; "
-                "task ids must be unique within an evaluation."
-            )
-        seen_ids.add(entity.name)
-        tasks.append(_entity_to_task_input(entity))
-    return tasks
+    async def _fetch(task_ref: TaskRef) -> TaskEntity:
+        task_workspace, task_name = parse_entity_ref(task_ref.root, ref_workspace)
+        try:
+            return await entity_client.get(TaskEntity, name=task_name, workspace=task_workspace)
+        except EntityNotFoundError as exc:
+            raise ValueError(
+                f"Task '{task_ref.root}' referenced by taskset '{ref.root}' was not found; "
+                "the stored task may have been deleted after the taskset was created."
+            ) from exc
+
+    entities = await asyncio.gather(*(_fetch(task_ref) for task_ref in taskset.tasks))
+    tasks: list[AgentEvalTaskInput] = []
+    seen_ids: set[str] = set()
+    for entity in entities:
+        if entity.name in seen_ids:
+            raise ValueError(
+                f"Taskset '{ref.root}' expands to more than one task named '{entity.name}'; "
+                "task ids must be unique within an evaluation."
+            )
+        seen_ids.add(entity.name)
+        tasks.append(_entity_to_task_input(entity))
+    return tasks
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/nemo-evaluator/src/nemo_evaluator/task_refs.py` around lines 43 - 93,
Update resolve_taskset_ref to fetch all member TaskEntity records concurrently
rather than awaiting entity_client.get inside the sequential loop. Build the
member-reference requests first, use concurrent gathering while preserving each
taskset.tasks order, then retain the existing not-found error context and
seen_ids validation when converting the fetched entities.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@plugins/nemo-evaluator/src/nemo_evaluator/task_refs.py`:
- Around line 43-93: Update resolve_taskset_ref to fetch all member TaskEntity
records concurrently rather than awaiting entity_client.get inside the
sequential loop. Build the member-reference requests first, use concurrent
gathering while preserving each taskset.tasks order, then retain the existing
not-found error context and seen_ids validation when converting the fetched
entities.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: bc7a2b1c-9cd7-49a9-aca1-2fa3172c71b7

📥 Commits

Reviewing files that changed from the base of the PR and between 848ea33 and ea0c60f.

📒 Files selected for processing (12)
  • docs/evaluator/manage-tasks-tasksets.mdx
  • docs/fern/versions/latest.yml
  • plugins/nemo-evaluator/openapi/openapi.yaml
  • plugins/nemo-evaluator/src/nemo_evaluator/api/schemas.py
  • plugins/nemo-evaluator/src/nemo_evaluator/jobs/agent_evaluate.py
  • plugins/nemo-evaluator/src/nemo_evaluator/jobs/agent_spec.py
  • plugins/nemo-evaluator/src/nemo_evaluator/jobs/evaluate.py
  • plugins/nemo-evaluator/src/nemo_evaluator/jobs/metric_resolution.py
  • plugins/nemo-evaluator/src/nemo_evaluator/task_refs.py
  • plugins/nemo-evaluator/tests/integration/test_agent_evaluate_job.py
  • plugins/nemo-evaluator/tests/test_agent_evaluate.py
  • plugins/nemo-evaluator/tests/test_task_refs.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant