feat(evaluator): aggregate agent-eval results natively and import Gym's own - #1065
Conversation
81903b3 to
7120a96
Compare
7120a96 to
dc95306
Compare
3d4a2ec to
de3d021
Compare
dc95306 to
03d1d26
Compare
ee5af9c to
45fb359
Compare
03d1d26 to
6a7da9f
Compare
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughChangesEvaluation results and aggregation
Sequence Diagram(s)sequenceDiagram
participant GymAgentTaskRunner
participant GymAggregateMetrics
participant AgentEvaluator
participant AgentEvalSummary
participant Dashboard
GymAgentTaskRunner->>GymAggregateMetrics: Read aggregate-metrics sidecar
GymAggregateMetrics-->>GymAgentTaskRunner: Return agent_metrics
GymAgentTaskRunner->>AgentEvaluator: Return run_aggregate_scores()
AgentEvaluator->>AgentEvalSummary: Pass extra_scores to from_scores()
AgentEvalSummary-->>Dashboard: Provide merged aggregate statistics
Dashboard-->>Dashboard: Render value, median, std dev, count, and NaN
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (3)
packages/nemo_evaluator_sdk/tests/agent_eval/test_pass_at_k.py (2)
73-95: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winCover boolean score outputs.
_scorelike_outputsinpackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.py, Lines 186-202, accepts continuous and boolean schemas. This test covers continuous and label outputs only. Add a boolean metric withTrueandFalsevalues and assert itspass@kresults.🤖 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_pass_at_k.py` around lines 73 - 95, The test test_task_pass_at_k_gated_and_uniform_across_metric_types should include a boolean-output metric with True/False scores, add corresponding task scores, and assert its pass@1 and pass@2 values alongside the existing continuous metrics. Ensure the boolean metric is treated as pass@k-eligible while the label metric remains excluded.
73-95: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winUse unequal attempt counts to verify per-task weighting.
Both tasks have two attempts. A pooled calculation produces the same
pass@1andpass@2values as the required per-task calculation. Add unequal trial counts, such as two versus four, and assert the mean of the task-level estimates.🤖 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_pass_at_k.py` around lines 73 - 95, Update test_task_pass_at_k_gated_and_uniform_across_metric_types to use unequal attempt counts between t1 and t2, such as two versus four, by adding the corresponding scores for the task with four attempts. Recalculate and assert pass@1 and pass@2 from the unweighted mean of each task’s pass@k estimate, ensuring the test distinguishes per-task weighting from pooled attempt weighting while keeping both reward metrics and the label exclusion covered.packages/nemo_evaluator_sdk/tests/agent_eval/test_gym_aggregate_scores.py (1)
114-114: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExclude bools by type, not by value.
value is not Trueonly filters the literalTrue. AFalseflag in the fixture would passisinstance(value, (int, float))and enternumeric_keys, then fail the assertion for the wrong reason._as_floatrejects all bools, so mirror that here.♻️ Proposed fix
- numeric_keys = {key for key, value in key_metrics.items() if isinstance(value, (int, float)) and value is not True} + numeric_keys = { + key + for key, value in key_metrics.items() + if isinstance(value, (int, float)) and not isinstance(value, bool) + }🤖 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_gym_aggregate_scores.py` at line 114, Update the numeric key filtering in the test’s key-metrics aggregation to exclude booleans by type, not by checking only whether the value is True. Mirror _as_float’s behavior so both True and False are excluded while numeric int and float values remain included.
🤖 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/examples/gym/inspect_results.py`:
- Around line 15-18: Update the usage text in inspect_results to show the script
being run through uv instead of invoking python directly. Keep the existing
repository-root context and bundle argument, but change the documented command
in the inspect_results example to use the uv run entrypoint so it matches the
coding guidelines.
In `@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.py`:
- Around line 23-25: Update the pass@k filtering in the results logic around
_PASS_AT_K_VALUE_SCHEMAS to use issubclass() against the allowed value-schema
classes instead of exact membership testing, while preserving the existing
eligibility behavior for ContinuousScore and BooleanValue.
In
`@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/gym_runtime.py`:
- Around line 766-773: Update the aggregate-metrics parsing logic around the
parsed-list handling to validate each entry and its agent_ref mapping before
accessing agent_ref["name"]. Return None, or otherwise follow the existing
unparseable-file behavior, when any entry has a missing or invalid agent
reference, preventing malformed Gym data from propagating exceptions through
run_tasks while preserving valid aggregations.
- Around line 366-373: Update the docstring on run_aggregate_scores to describe
the Gym field actually consumed by _aggregate_scores_from_gym, namely
agent_metrics rather than key_metrics. Keep the existing namespace and
reward-skip explanation intact, and align the summary line with the behavior
documented by _aggregate_scores_from_gym and
test_imports_read_agent_metrics_not_the_key_metrics_subset.
In `@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/metrics/aggregation.py`:
- Around line 403-404: Update aggregate_metrics in
packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/metrics/aggregation.py at
lines 403-404 to compute median from valid score values and pass it to
AggregateScoreBase, and at lines 430-431 pass median=percentiles.p50 for range
scores so native aggregates expose the correct median.
In `@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.py`:
- Around line 186-193: Update the result model’s serialize_nan configuration to
include both sample_variance and sample_stddev, ensuring NaN values serialize as
the string "NaN". Add unit tests covering float("nan") for each field and verify
the serialized output.
---
Nitpick comments:
In `@packages/nemo_evaluator_sdk/tests/agent_eval/test_gym_aggregate_scores.py`:
- Line 114: Update the numeric key filtering in the test’s key-metrics
aggregation to exclude booleans by type, not by checking only whether the value
is True. Mirror _as_float’s behavior so both True and False are excluded while
numeric int and float values remain included.
In `@packages/nemo_evaluator_sdk/tests/agent_eval/test_pass_at_k.py`:
- Around line 73-95: The test
test_task_pass_at_k_gated_and_uniform_across_metric_types should include a
boolean-output metric with True/False scores, add corresponding task scores, and
assert its pass@1 and pass@2 values alongside the existing continuous metrics.
Ensure the boolean metric is treated as pass@k-eligible while the label metric
remains excluded.
- Around line 73-95: Update
test_task_pass_at_k_gated_and_uniform_across_metric_types to use unequal attempt
counts between t1 and t2, such as two versus four, by adding the corresponding
scores for the task with four attempts. Recalculate and assert pass@1 and pass@2
from the unweighted mean of each task’s pass@k estimate, ensuring the test
distinguishes per-task weighting from pooled attempt weighting while keeping
both reward metrics and the label exclusion covered.
🪄 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: 58e41c8d-be79-4a0b-a562-f0404d7e75fe
⛔ Files ignored due to path filters (8)
sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/dashboard.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/evaluator.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/persistence.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/results.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/gym_runtime.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/trials.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/metrics/aggregation.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/values/results.pyis excluded by!sdk/**
📒 Files selected for processing (14)
packages/nemo_evaluator_sdk/examples/gym/inspect_results.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/dashboard.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/evaluator.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/gym_runtime.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/trials.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/metrics/aggregation.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_dashboard.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_gym_aggregate_scores.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_pass_at_k.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_runner_aggregations.pypackages/nemo_evaluator_sdk/tests/test_api.py
|
6a7da9f to
1972735
Compare
|
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. |
1972735 to
d505744
Compare
|
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. |
ngoncharenko
left a comment
There was a problem hiding this comment.
Three inline findings from the merge-base review.
d505744 to
a9b74f7
Compare
|
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. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/nemo_evaluator_sdk/tests/agent_eval/test_pass_at_k.py (1)
96-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd boolean score eligibility coverage.
This test covers continuous scores and labels, but not boolean scores. A regression that excludes boolean schemas from pass@k remains undetected. Add
TrueandFalseoutputs and assertpass@1andpass@2.As per coding guidelines, prefer writing unit tests when verifying solutions instead of executing ad hoc Python snippets.
🤖 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_pass_at_k.py` around lines 96 - 117, Extend test_task_pass_at_k_gated_and_uniform_across_metric_types with a boolean score metric and True/False outputs across the existing tasks and attempts. Include assertions verifying the boolean metric produces the expected pass@1 and pass@2 values, ensuring boolean schemas are eligible for pass@k alongside continuous metrics while labels remain excluded.Source: Coding guidelines
🤖 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/examples/gym/README.md`:
- Around line 55-67: Update the “Read the results” section in the README to
include a tested Python SDK example in a tab set alongside the existing CLI
commands. Show equivalent bundle-reading and result-access usage through the
SDK, while preserving the current CLI workflow and explanatory context.
In `@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/scores.py`:
- Line 28: Replace the generic TRIAL_STATUS_DETAIL value with an SDK-reserved
discriminator key, and update the trial-failure detection and diagnostic-writing
paths that use it consistently. Add a test covering a metric failure containing
“trial_status” and verify is_trial_failure() remains false so the unusable
measurement is excluded from pass@k.
---
Nitpick comments:
In `@packages/nemo_evaluator_sdk/tests/agent_eval/test_pass_at_k.py`:
- Around line 96-117: Extend
test_task_pass_at_k_gated_and_uniform_across_metric_types with a boolean score
metric and True/False outputs across the existing tasks and attempts. Include
assertions verifying the boolean metric produces the expected pass@1 and pass@2
values, ensuring boolean schemas are eligible for pass@k alongside continuous
metrics while labels remain excluded.
🪄 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: 23bd9dfd-c87c-49db-8c05-b40afd6a7296
⛔ Files ignored due to path filters (9)
sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/dashboard.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/evaluator.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/persistence.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/results.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/gym_runtime.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/scores.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/trials.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/metrics/aggregation.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/values/results.pyis excluded by!sdk/**
📒 Files selected for processing (17)
packages/nemo_evaluator_sdk/examples/gym/README.mdpackages/nemo_evaluator_sdk/examples/gym/inspect_results.pypackages/nemo_evaluator_sdk/examples/gym/run_gym_eval.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/dashboard.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/evaluator.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/gym_runtime.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/scores.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/trials.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/metrics/aggregation.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_dashboard.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_gym_aggregate_scores.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_pass_at_k.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_runner_aggregations.pypackages/nemo_evaluator_sdk/tests/test_api.py
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py
- packages/nemo_evaluator_sdk/tests/agent_eval/test_gym_aggregate_scores.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/metrics/aggregation.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/dashboard.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/trials.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/gym_runtime.py
a9b74f7 to
c74cbfb
Compare
|
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. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/examples/gym/inspect_results.py`:
- Around line 76-77: Update the score filtering logic around score.metric_type
and score.status to preserve failed trial attempts. Reuse the existing
is_trial_failure classification used by pass@k, excluding only failures
representing unmeasured metrics while retaining trial failures for task-solved
evaluation.
In
`@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/gym_runtime.py`:
- Around line 761-765: Update the sidecar parsing error handler in the Gym
aggregate metrics flow to also catch UnicodeDecodeError from Path.read_text,
alongside the existing JSONDecodeError and OSError handling. Preserve the
warning and None return so invalid UTF-8 sidecars are skipped without aborting
run_tasks.
- Around line 840-866: Update the incomplete-family fallback in the metric
aggregation loop to skip the `reward` metric before copying its statistics into
`scalars`. Preserve the existing standalone scalar behavior for other incomplete
families and leave complete-family handling unchanged.
🪄 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: 601114d8-52cc-44b2-8094-04bb6d9cda73
⛔ Files ignored due to path filters (9)
sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/dashboard.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/evaluator.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/persistence.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/results.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/runtimes/gym_runtime.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/scores.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/trials.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/metrics/aggregation.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/values/results.pyis excluded by!sdk/**
📒 Files selected for processing (17)
packages/nemo_evaluator_sdk/examples/gym/README.mdpackages/nemo_evaluator_sdk/examples/gym/inspect_results.pypackages/nemo_evaluator_sdk/examples/gym/run_gym_eval.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/dashboard.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/evaluator.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/runtimes/gym_runtime.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/scores.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/trials.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/metrics/aggregation.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_dashboard.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_gym_aggregate_scores.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_pass_at_k.pypackages/nemo_evaluator_sdk/tests/agent_eval/test_runner_aggregations.pypackages/nemo_evaluator_sdk/tests/test_api.py
🚧 Files skipped from review as they are similar to previous changes (13)
- packages/nemo_evaluator_sdk/examples/gym/README.md
- packages/nemo_evaluator_sdk/examples/gym/run_gym_eval.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/trials.py
- packages/nemo_evaluator_sdk/tests/agent_eval/test_gym_aggregate_scores.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/dashboard.py
- packages/nemo_evaluator_sdk/tests/agent_eval/test_dashboard.py
- packages/nemo_evaluator_sdk/tests/agent_eval/test_runner_aggregations.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/metrics/aggregation.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/evaluator.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/results.py
- packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/results.py
- packages/nemo_evaluator_sdk/tests/agent_eval/test_pass_at_k.py
…'s own Agent-eval reported a mean and little else, and a runner's own aggregations were discarded entirely — so a Gym run's headline numbers (pass@k, per-environment metrics) were visible in Gym's output files but not in the eval result. Native aggregation: - pass@k per task via the unbiased estimator (Chen et al. 2021), for every score-like metric output. A pass is full credit, deliberately not configurable. A failed trial is a failed attempt: it counts toward n and never toward c. A failed *metric* is not — it leaves the attempt unmeasured rather than unsuccessful, so charging it to the agent would let a judge timeout read as a task the agent failed. Tasks left with no usable attempt are reported as nan_count, uniform across k, so a shrinking denominator is never silent. - Percentiles on every aggregate, reusing the deterministic-metric helper (now public as `compute_percentiles`), which also gives each metric a median. - Both standard-deviation conventions, named explicitly: `std_dev`/`variance` stay population (divide by n), and `sample_std_dev`/`sample_variance` are new. Gym computes its spread with pandas (ddof=1), so naming both lets the two sets of numbers coexist without either changing meaning. Runner aggregations: - `RunAggregationsProvider` lets a runner surface run-level numbers it computed itself, mapped onto typed aggregates and merged into `summary.scores`. The `runner.<name>.` namespace is enforced, not merely documented: `summary.scores` is a flat list, so an un-namespaced name would not overwrite the SDK's own aggregate but sit beside it, leaving any lookup to pick one arbitrarily. Offending entries are dropped with a warning rather than raised on, since this runs after `run_tasks` and a naming bug must not sink a completed run. - Gym's flattened `agent_metrics` are imported under `runner.gym.<metric>` (`agent_metrics`, not `key_metrics`: the latter is a resources-server-chosen subset that by default keeps only the `mean/*` entries). A full mean/max/min/median/std family is re-assembled into one range score; anything else becomes an `AggregateScalarScore`. The full-family requirement matters because a resources-server may define a metric literally named `mean` — re-assembling on a partial match would rename a real metric into a statistic of a distribution that never existed. `reward` is skipped as redundant with the natively-computed `gym_reward.reward`; nothing else numeric is dropped, which a synthetic custom-environment payload pins as an invariant. `AggregateScalarScore` is a new variant for a single reported figure with no underlying sample, so a reader can tell "this is the whole story" from "this summarizes count samples" instead of seeing a range score with a count of 1. The dashboard and the new `inspect_results.py` example both render it by value. The dashboard reads `median` off the score before falling back to a percentile distribution, since a backend may report one without the samples behind it. Signed-off-by: Sandy Chapman <schapman@nvidia.com>
c74cbfb to
e364b7c
Compare
Mechanical regeneration, unrelated to this branch's feature work. #1065 added `median`, `sample_std_dev` and `sample_variance` to `AggregateScore` in `nemo_evaluator_sdk` and reworded the variance/std_dev descriptions, but did not regenerate the evaluator plugin spec that re-exports those types. Nothing was set up to catch it: the openapi pre-commit hook is `stages: [manual]` and its `files:` pattern does not cover `packages/nemo_evaluator_sdk/`, and CI's `tools/lint/lint-openapi.sh` only diffs the platform specs, never the per-plugin ones under `plugins/*/openapi/`. Regenerating here rather than leaving it for whoever next touches this file. No publication/intake schema changes are in this diff. Signed-off-by: Octavian Drulea <odrulea@nvidia.com>
Mechanical regeneration, unrelated to this branch's feature work. #1065 added `median`, `sample_std_dev` and `sample_variance` to `AggregateScore` in `nemo_evaluator_sdk` and reworded the variance/std_dev descriptions, but did not regenerate the evaluator plugin spec that re-exports those types. Nothing was set up to catch it: the openapi pre-commit hook is `stages: [manual]` and its `files:` pattern does not cover `packages/nemo_evaluator_sdk/`, and CI's `tools/lint/lint-openapi.sh` only diffs the platform specs, never the per-plugin ones under `plugins/*/openapi/`. Regenerating here rather than leaving it for whoever next touches this file. No publication/intake schema changes are in this diff. Signed-off-by: Octavian Drulea <odrulea@nvidia.com>
…IA-NeMo#1148) * feat(evaluator): wire publish_to_intake() to API surface Signed-off-by: Octavian Drulea <odrulea@nvidia.com> * feat(evaluator): fix error handling in ingest Signed-off-by: Octavian Drulea <odrulea@nvidia.com> * chore(evaluator): regenerate openapi spec for AggregateScore changes Mechanical regeneration, unrelated to this branch's feature work. NVIDIA-NeMo#1065 added `median`, `sample_std_dev` and `sample_variance` to `AggregateScore` in `nemo_evaluator_sdk` and reworded the variance/std_dev descriptions, but did not regenerate the evaluator plugin spec that re-exports those types. Nothing was set up to catch it: the openapi pre-commit hook is `stages: [manual]` and its `files:` pattern does not cover `packages/nemo_evaluator_sdk/`, and CI's `tools/lint/lint-openapi.sh` only diffs the platform specs, never the per-plugin ones under `plugins/*/openapi/`. Regenerating here rather than leaving it for whoever next touches this file. No publication/intake schema changes are in this diff. Signed-off-by: Octavian Drulea <odrulea@nvidia.com> * fix(evaluator): address comments Signed-off-by: Octavian Drulea <odrulea@nvidia.com> * fix(studio): update type aliases to match new sdk Signed-off-by: Octavian Drulea <odrulea@nvidia.com> * fix(evaluator): address PR feedback Signed-off-by: Octavian Drulea <odrulea@nvidia.com> --------- Signed-off-by: Octavian Drulea <odrulea@nvidia.com>
Closes AALGO-434.
Why
Agent-eval reported a mean and little else, and a runner's own aggregations were discarded entirely — so a Gym run's headline numbers (pass@k, per-environment metrics) were visible in Gym's output files but nowhere in the eval result.
Native aggregation
compute_percentiles) so both paths report distributions the same way.medianadded toAggregateScoreBase, populated natively fromp50, so the field means the same thing whether a score was computed here or imported from a backend that reports a median without a full distribution.std_dev/varianceremain population (÷n);sample_std_dev/sample_varianceare new (÷n−1,Nonewhen n<2). Gym computes its spread with pandas (ddof=1), so naming both lets the two sets of numbers coexist without either silently changing meaning. No existing value changes.Importing Gym's own numbers
RunAggregationsProvideris a single method —run_aggregate_scores()— returning typed aggregates that merge intosummary.scores. There is no parallel opaque passthrough: Gym already writes its rawrollouts_aggregate_metrics.jsoninside the run's work dir, so a second copy on the result would duplicate a file already in the bundle and re-introduce the untypeddict[str, Any]bag that #1013 removes.Names are
runner.gym.<metric>— namespaced by runner, not agent, since each run uses a single agent and what a reader needs to know is which backend produced the number. Falls back torunner.gym.<agent>.<metric>only if a run produced several. Gym'srewardis skipped: the SDK already scores it natively asgym_reward.rewardfrom the same rollouts.The part most worth reviewing
Imports read
agent_metrics, notkey_metrics. This matters:key_metricsis a subset ofagent_metricschosen by the resources-server, and Gym's defaultget_key_metricskeeps only themean/*entries — so max/min/median/std never appear there, and sourcing from it would degrade every distribution into a lonerunner.gym.mean/<name>scalar.test_imports_read_agent_metrics_not_the_key_metrics_subsetpins this.Gym flattens each distribution into
<stat>/<metric>keys. Itsdescribe_dataframeemitsmean/max/min/median/std/histogramtogether, andprepare_for_serializationstripshistogrambefore writing — so the family in the file is exactly those five, and re-assembly requires all five. That guard matters because 36 of Gym's ~97 resources-servers overridecompute_metrics, emitting keys in their own shapes (arena_elo/score,easy/pass@1/accuracy), and a server is free to define a metric literally namedmean. A partial match stays as standalone scalars rather than being renamed into a statistic of a distribution that never existed.test_nothing_numeric_is_dropped_from_a_custom_environment_payloadpins the invariant: importing is a renaming, never a filter. Onlyreward(redundant by construction) and non-numeric values may disappear.New
AggregateScalarScoreA single pre-computed value with no underlying sample. Distinct from
AggregateRangeScoreso a reader can tell "this is the whole story" from "this summarizescountsamples", instead of seeing a range score with a suspiciouscountof 1.countis nowint | None, and imported aggregates carryNone— Gym reports statistics without the n behind them, and0would assert that nothing was evaluated (besides being a division hazard). The dashboard and example renderNoneas an em dash while still showing a genuine0.Also
examples/gym/inspect_results.py— companion torun_gym_eval.py, showing how to reach each kind of result, with lift-and-paste accessors.Known scope boundary
Gym's
group_level_metrics(its per-task aggregation) is not imported.summary.scoresis run-level, so it has no home there yet — the SDK computes per-task groupings internally for pass@k but doesn't surface that granularity. Native per-task rollups plus importing Gym's into them is tracked separately; the raw data remains in Gym's own file inside the bundle.Verification
tyat exactly themainbaseline (198);make vendorrun with no drift.Summary by CodeRabbit
New Features
Bug Fixes
Documentation