Skip to content

refactor(evaluator)!: make persisting an agent-eval run an explicit call - #1069

Merged
SandyChapman merged 1 commit into
mainfrom
explicit-run-persistence/schapman
Aug 9, 2026
Merged

refactor(evaluator)!: make persisting an agent-eval run an explicit call#1069
SandyChapman merged 1 commit into
mainfrom
explicit-run-persistence/schapman

Conversation

@SandyChapman

@SandyChapman SandyChapman commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Off latest main, independent of #1013 / #1065.

Why

AgentEvaluator.run() wrote a bundle and an HTML dashboard as a side effect whenever the run config carried an output_dir. Computing an evaluation and storing one are different decisions, and folding them together forced AgentEvalResult to declare two fields it could not populate:

output_dir: Path | None = None
dashboard_path: Path | None = None

Both were patched on after construction — persist_run returned a model_copy with output_dir set, and the dashboard writer patched dashboard_path after that. So a completed run was indistinguishable from one still being assembled, and the type permitted a dashboard_path with no output_dir — a state no code produces.

After

result = await AgentEvaluator().run(tasks=tasks, target=target, config=cfg)  # computes, writes nothing
location = result.persist()                                                  # stores it, says where
  • AgentEvalResult.persist(output_dir=None, *, write_dashboard=True) returns a BundleLocation (output_dir + optional dashboard_path). Holding one means the bundle exists — no optional to re-check, and a run that was never persisted simply has no location.
  • run() writes nothing. Same reasoning publish_to_intake already documents: "optionality is structural: you make the call or you don't."
  • output_dirwork_dir on the run config, and the result carries it. The old name was already inaccurate: seven runtimes use it as the root for trial evidence during the run. Unlike a bundle location it is known before the run starts, so it is never attached after the fact.
  • write_dashboard moves off the run config onto persist, where it belongs.

The one subtlety worth reviewing

persist() defaults to work_dir, and that default is load-bearing. Evidence is written under work_dir during the run, and persist_run rewrites evidence refs relative to the bundle so a bundle survives being moved. That only works when you persist into the tree the evidence is already under.

Persisting elsewhere is still allowed, because it is a supported scenario — a re-scored run may deliberately reference an earlier run's deliverables (see test_persist_and_read_keep_external_evidence_refs_absolute). But it produces a bundle whose evidence refs point back at the original directory: fine while that directory exists, silently dangling once it doesn't. I verified this behaviour directly rather than inferring it.

Making the safe path the default is the mitigation here. A louder signal — warning when evidence lands outside the bundle — is worth doing but is a separate change, since it needs to leave the deliberate case working.

Migration

before after
AgentEvalRunConfig(output_dir=d) AgentEvalRunConfig(work_dir=d)
AgentEvalRunConfig(write_dashboard=False) result.persist(write_dashboard=False)
bundle written by run() result.persist()
result.output_dir location.output_dir (or result.work_dir)
result.dashboard_path location.dashboard_path

All in-repo callers are updated: the evaluator job plugin, intake/publish.py, six examples, the Fabric notebook, and the tests.

Verification

  • 1855 passed / 25 failed, and all 25 are the pre-existing ragas + live-Fabric baseline (verified: zero failures outside it).
  • Ruff clean, formatter clean, ty at exactly the main baseline for these packages (536 both ways).
  • make vendor run; mirror included.

Notes for review

  • persist() lives on the model and imports persist_run inside the method — persistence imports results for the types it writes, so a module-level import would be circular. persist_run remains the underlying function.
  • Sets up a symmetric inverse for AALGO-448: AgentEvalResult.load(bundle).
  • persist() on a run with no work_dir and no explicit target raises rather than inventing a directory.

Summary by CodeRabbit

  • New Features

    • Evaluation results can be explicitly saved after a run, with the saved bundle location returned.
    • Dashboard generation can be enabled or disabled when saving results.
    • Aggregate scores now support medians, sample statistics, and standalone scalar values.
  • Updates

    • Evaluation workspaces and save locations are handled consistently.
    • Runs no longer automatically write output artifacts.
    • Evaluation comparisons now display scalar reported values correctly.
  • Documentation

    • Examples and workflows demonstrate the updated saving process and output locations.

@github-actions github-actions Bot added breaking breaking change (!-marked title) refactor labels Aug 4, 2026
@SandyChapman
SandyChapman marked this pull request as ready for review August 4, 2026 15:28
@SandyChapman
SandyChapman requested review from a team as code owners August 4, 2026 15:28
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The SDK replaces output_dir with work_dir, defers bundle persistence until AgentEvalResult.persist(), returns BundleLocation metadata, updates integrations and runtimes, and adds aggregate scalar-score support.

Changes

Evaluation persistence migration

Layer / File(s) Summary
Persistence contract
packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/{tasks.py,results.py,persistence.py}
AgentEvalRunConfig uses work_dir. AgentEvalResult.persist() returns BundleLocation. Persistence controls dashboard generation and manifest paths.
Workspace and runtime handling
packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/{evaluator.py,runtimes/*}, packages/nemo_evaluator_sdk/examples/run_agent_eval/*
Evaluation no longer persists automatically. Runtime evidence paths use work_dir.
Integration migration
packages/nemo_evaluator_sdk/examples/**, plugins/nemo-evaluator/**, plugins/nemo-optimization/**
Examples, pipelines, and plugins pass work_dir and persist results explicitly.
Validation
packages/nemo_evaluator_sdk/tests/agent_eval/*, plugins/nemo-optimization/tests/*
Tests cover deferred persistence, bundle locations, dashboard suppression, and workspace paths.

Aggregate score schema updates

Layer / File(s) Summary
Aggregate score contracts
plugins/nemo-evaluator/openapi/openapi.yaml, packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.py, web/packages/studio/src/api/evaluation/agent-evaluations.ts
Range and rubric scores add median and sample statistics. Count semantics and requirements change. AggregateScalarScore is added to aggregated metric results and Studio types.
Scalar score normalization
web/packages/studio/src/components/dataViews/EvalComparisonTable/{utils.ts,utils.test.ts}
Normalization preserves mean, uses scalar value when mean is absent, and returns null when neither exists.

Sequence Diagram(s)

sequenceDiagram
  participant EvaluationCaller
  participant AgentEvaluator
  participant AgentEvalResult
  participant persist_run
  EvaluationCaller->>AgentEvaluator: run(config)
  AgentEvaluator-->>EvaluationCaller: AgentEvalResult(work_dir)
  EvaluationCaller->>AgentEvalResult: persist(write_dashboard)
  AgentEvalResult->>persist_run: persist bundle
  persist_run-->>EvaluationCaller: BundleLocation
Loading

Possibly related PRs

Suggested reviewers: arpitsardhana, ngoncharenko

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.88% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main breaking change: agent-evaluation persistence is now explicit.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch explicit-run-persistence/schapman

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py (1)

149-156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover explicit persistence for in-memory results.

The test covers only the failure path. Add a success case that calls result.persist(tmp_path) when work_dir is unset and asserts the returned BundleLocation.output_dir.

Based on the persistence contract, an in-memory result must accept an explicit persistence target.

🤖 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 `@packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py` around
lines 149 - 156, Add a success case to the test after the existing failure
assertion that calls result.persist(tmp_path) with an explicit persistence
target and asserts the returned BundleLocation.output_dir equals tmp_path. This
covers the contract that in-memory AgentEvalResult instances accept explicit
persistence targets even when work_dir is unset, complementing the existing
failure-path coverage.
🤖 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.

Inline comments:
In
`@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/codex/runtime.py`:
- Line 264: Update the evidence-root selection in Codex runtime.py at lines
264-264 and Fabric runtime.py at lines 514-514 to prefer config.work_dir over
self._work_root when both are set, ensuring evidence remains inside
AgentEvalResult.work_dir for persistence and rescoring. Add a regression test
covering both paths being configured and persisting the result.

In `@plugins/nemo-evaluator/src/nemo_evaluator/intake/publish.py`:
- Line 197: Update the location message in the publish flow to use the
BundleLocation returned by persist() as the persisted bundle path; do not
present result.work_dir as the bundle location. Describe work_dir only as trial
evidence, and explicitly indicate when no bundle was persisted for in-memory
results.

---

Nitpick comments:
In `@packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py`:
- Around line 149-156: Add a success case to the test after the existing failure
assertion that calls result.persist(tmp_path) with an explicit persistence
target and asserts the returned BundleLocation.output_dir equals tmp_path. This
covers the contract that in-memory AgentEvalResult instances accept explicit
persistence targets even when work_dir is unset, complementing the existing
failure-path coverage.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 69bc9009-35bc-47c8-8990-7cde3de192b0

📥 Commits

Reviewing files that changed from the base of the PR and between 2eb952f and dafe316.

⛔ Files ignored due to path filters (10)
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/evaluator.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/persistence.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/results.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/codex/runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/docker_sandbox.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/fabric/container_runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/fabric/runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/gym_runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/harbor_runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/tasks.py is excluded by !sdk/**
📒 Files selected for processing (29)
  • packages/nemo_evaluator_sdk/examples/agentic_eval_with_fabric.ipynb
  • packages/nemo_evaluator_sdk/examples/codex_docker/example.py
  • packages/nemo_evaluator_sdk/examples/fabric_container/run_e2e.py
  • packages/nemo_evaluator_sdk/examples/gym/run_gym_eval.py
  • packages/nemo_evaluator_sdk/examples/profbench/runner.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/pipeline.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/platform_runtime.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/run_agent_eval.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/workflow_runtime.py
  • packages/nemo_evaluator_sdk/examples/skill_eval/run_skill_eval.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/evaluator.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/codex/runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/docker_sandbox.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/fabric/container_runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/fabric/runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/gym_runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/harbor_runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/tasks.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_codex_docker_example.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_docker_sandbox_runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_evaluator.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_fabric_container_runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_fabric_integration.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_harbor_runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py
  • plugins/nemo-evaluator/src/nemo_evaluator/intake/publish.py
  • plugins/nemo-evaluator/src/nemo_evaluator/jobs/agent_evaluate.py

Comment thread plugins/nemo-evaluator/src/nemo_evaluator/intake/publish.py Outdated
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 31770/40384 78.7% 63.4%
Integration Tests 18455/38314 48.2% 20.8%

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/nemo-evaluator/openapi/openapi.yaml (1)

2740-2740: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve count in v2 result responses.

count was required in the previous v2 schema, but is now optional. The v2 list/get routes omit None values, so unknown counts disappear and break generated clients that require count. Keep required integer semantics in v2, or move nullable/omittable semantics to a new API version and regenerate clients.

🤖 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/openapi/openapi.yaml` at line 2740, Update the v2
result response schemas at plugins/nemo-evaluator/openapi/openapi.yaml:2740-2740
and 2825-2825 to preserve required integer count semantics, ensuring v2 list/get
responses always include count even when the value is unknown; do not make count
nullable or omittable in v2, or otherwise move that behavior to a new API
version before regenerating clients.

Source: Linters/SAST tools

🤖 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.

Inline comments:
In `@plugins/nemo-evaluator/openapi/openapi.yaml`:
- Around line 2669-2672: Update the three count descriptions in
plugins/nemo-evaluator/openapi/openapi.yaml at lines 2669-2672, 2752-2755, and
2837-2840, replacing “None when the sample size is unknown” with “Omitted when
the sample size is unknown” while preserving the remaining wording.

---

Outside diff comments:
In `@plugins/nemo-evaluator/openapi/openapi.yaml`:
- Line 2740: Update the v2 result response schemas at
plugins/nemo-evaluator/openapi/openapi.yaml:2740-2740 and 2825-2825 to preserve
required integer count semantics, ensuring v2 list/get responses always include
count even when the value is unknown; do not make count nullable or omittable in
v2, or otherwise move that behavior to a new API version before regenerating
clients.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ff260ffb-6e5a-48e0-9db5-a1277cc46200

📥 Commits

Reviewing files that changed from the base of the PR and between 648152c and 8c44bcb.

⛔ Files ignored due to path filters (10)
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/evaluator.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/persistence.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/results.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/codex/runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/docker_sandbox.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/fabric/container_runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/fabric/runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/gym_runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/harbor_runtime.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/tasks.py is excluded by !sdk/**
📒 Files selected for processing (34)
  • packages/nemo_evaluator_sdk/examples/agentic_eval_with_fabric.ipynb
  • packages/nemo_evaluator_sdk/examples/codex_docker/example.py
  • packages/nemo_evaluator_sdk/examples/fabric_container/run_e2e.py
  • packages/nemo_evaluator_sdk/examples/gym/run_gym_eval.py
  • packages/nemo_evaluator_sdk/examples/profbench/README.md
  • packages/nemo_evaluator_sdk/examples/profbench/runner.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/pipeline.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/platform_runtime.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/run_agent_eval.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/workflow_runtime.py
  • packages/nemo_evaluator_sdk/examples/skill_eval/run_skill_eval.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/evaluator.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/codex/runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/docker_sandbox.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/fabric/container_runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/fabric/runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/gym_runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/harbor_runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/tasks.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_codex_docker_example.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_codex_runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_docker_sandbox_runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_evaluator.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_fabric_container_runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_fabric_integration.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_harbor_runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py
  • plugins/nemo-evaluator/openapi/openapi.yaml
  • plugins/nemo-evaluator/src/nemo_evaluator/intake/publish.py
  • plugins/nemo-evaluator/src/nemo_evaluator/jobs/agent_evaluate.py
  • plugins/nemo-optimization/src/nemo_optimization/backends/optuna/fabric_trial.py
  • plugins/nemo-optimization/tests/test_fabric_trial.py
🚧 Files skipped from review as they are similar to previous changes (28)
  • plugins/nemo-evaluator/src/nemo_evaluator/jobs/agent_evaluate.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/docker_sandbox.py
  • packages/nemo_evaluator_sdk/examples/fabric_container/run_e2e.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/gym_runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/codex/runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_fabric_container_runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/harbor_runtime.py
  • plugins/nemo-evaluator/src/nemo_evaluator/intake/publish.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/tasks.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/fabric/runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_fabric_integration.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/evaluator.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_codex_docker_example.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_docker_sandbox_runtime.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_evaluator.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_harbor_runtime.py
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/fabric/container_runtime.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/workflow_runtime.py
  • packages/nemo_evaluator_sdk/examples/gym/run_gym_eval.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/run_agent_eval.py
  • packages/nemo_evaluator_sdk/examples/codex_docker/example.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/pipeline.py
  • packages/nemo_evaluator_sdk/examples/run_agent_eval/platform_runtime.py
  • packages/nemo_evaluator_sdk/examples/profbench/runner.py
  • packages/nemo_evaluator_sdk/examples/agentic_eval_with_fabric.ipynb
  • packages/nemo_evaluator_sdk/examples/skill_eval/run_skill_eval.py

Comment thread plugins/nemo-evaluator/openapi/openapi.yaml Outdated

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@plugins/nemo-evaluator/openapi/openapi.yaml`:
- Around line 2714-2722: Update the sample variance and related range statistics
descriptions in plugins/nemo-evaluator/openapi/openapi.yaml:2714-2722, rubric
statistics at plugins/nemo-evaluator/openapi/openapi.yaml:2799-2807, and scalar
statistics at plugins/nemo-evaluator/openapi/openapi.yaml:2886-2894 to state
that values are omitted when fewer than two scores are available, rather than
saying they are None or null. Apply the same wording consistently across all
three schema sections.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 087f5223-80ef-4d1e-89a3-d90bc96993a9

📥 Commits

Reviewing files that changed from the base of the PR and between 66490c3 and 42d5f9d.

⛔ Files ignored due to path filters (1)
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/values/results.py is excluded by !sdk/**
📒 Files selected for processing (2)
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.py
  • plugins/nemo-evaluator/openapi/openapi.yaml

Comment thread plugins/nemo-evaluator/openapi/openapi.yaml Outdated

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@plugins/nemo-evaluator/openapi/openapi.yaml`:
- Around line 2913-2929: Update the scalar-statistics model documentation around
the shown description to state that mean, min, and max are optional metadata,
including that mean may be preserved alongside value when both are provided.
Regenerate the OpenAPI artifact from the updated SDK schema/docstring rather
than editing generated output alone.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e37a4d11-2257-420a-b580-1b50aa4aa48b

📥 Commits

Reviewing files that changed from the base of the PR and between 42d5f9d and 069e764.

⛔ Files ignored due to path filters (1)
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/values/results.py is excluded by !sdk/**
📒 Files selected for processing (2)
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.py
  • plugins/nemo-evaluator/openapi/openapi.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.py

Comment thread plugins/nemo-evaluator/openapi/openapi.yaml Outdated
@SandyChapman
SandyChapman force-pushed the explicit-run-persistence/schapman branch from 069e764 to 8b923d7 Compare August 7, 2026 16:03
@arpitsardhana

Copy link
Copy Markdown
Contributor

Wil docs update be seprate MR? It fixes examples but i guess we have user facing docs which may need to reflect same behaviour

@SandyChapman
SandyChapman force-pushed the explicit-run-persistence/schapman branch from 8b923d7 to 0f6a5d5 Compare August 7, 2026 17:32
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

@SandyChapman

Copy link
Copy Markdown
Contributor Author

Wil docs update be seprate MR? It fixes examples but i guess we have user facing docs which may need to reflect same behaviour

I added the docs updates. Good callout.

@SandyChapman
SandyChapman enabled auto-merge August 7, 2026 19:20
@SandyChapman
SandyChapman added this pull request to the merge queue Aug 7, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 7, 2026
`AgentEvaluator.run()` wrote a bundle and an HTML dashboard as a side effect
whenever the run config carried an `output_dir`. Computing an evaluation and
storing one are different decisions, and folding them together forced
`AgentEvalResult` to declare two fields it could not populate:

    output_dir: Path | None = None
    dashboard_path: Path | None = None

Both were patched on after construction — `persist_run` returned a `model_copy`
with `output_dir` set, and the dashboard writer patched `dashboard_path` after
that. A completed run was therefore indistinguishable from one still being
assembled, and the type permitted a `dashboard_path` with no `output_dir`, a
state no code produces.

- `AgentEvalResult.persist(output_dir=None, *, write_dashboard=True)` stores the
  run and returns a `BundleLocation` (`output_dir` plus an optional
  `dashboard_path`). Holding one means the bundle exists, so there is no
  optional to re-check; a run that was never persisted simply has no location.
- `run()` computes and returns; it writes nothing. This matches
  `publish_to_intake`, which is already explicit for the same reason.
- `AgentEvalRunConfig.output_dir` becomes `work_dir`, and the result carries it.
  The name was already inaccurate: seven runtimes use it as the root for trial
  evidence *during* the run, not as an output. Unlike a bundle location it is
  known before the run starts, so it is never attached after the fact.
- `write_dashboard` moves off the run config to `persist`, where it belongs.

`persist()` defaults to `work_dir` because that is where the trials' evidence
already lives, so `persist_run` can rewrite the evidence refs bundle-relative
and the bundle survives being moved. Persisting somewhere else leaves those refs
pointing at the original directory — supported (a re-scored run may reference an
earlier run's deliverables) but only resolvable while that directory exists.

BREAKING CHANGE: `AgentEvalRunConfig.output_dir` is renamed to `work_dir` and no
longer causes `run()` to persist; call `result.persist()` instead.
`AgentEvalRunConfig.write_dashboard` is removed — pass `write_dashboard` to
`persist()`. `AgentEvalResult.output_dir` and `.dashboard_path` are gone; read
them from the `BundleLocation` that `persist()` returns.

Signed-off-by: Sandy Chapman <schapman@nvidia.com>
@SandyChapman
SandyChapman force-pushed the explicit-run-persistence/schapman branch from 0f6a5d5 to da12b50 Compare August 9, 2026 20:03
@SandyChapman
SandyChapman added this pull request to the merge queue Aug 9, 2026
Merged via the queue into main with commit 0c4dc81 Aug 9, 2026
56 checks passed
@SandyChapman
SandyChapman deleted the explicit-run-persistence/schapman branch August 9, 2026 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking breaking change (!-marked title) refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants