Skip to navigation

nemo_gym.rollouts.rollout_collection

View as Markdown

Module Contents

Classes

NameDescription
E2ERolloutCollectionConfigSpin up all necessary servers and perform a batch of rollout collection using each dataset inside the provided configs.
RolloutAggregationConfigAggregate metrics across rollout shards produced by gym eval run --no-serve +disable_aggregation=true.
RolloutAggregationHelper-
RolloutCollectionConfigPerform a batch of rollout collection.
RolloutCollectionHelperCollect rollouts by sending tasks to a running Gym deployment.
RunTimingReportHealth table for a collection whose rollouts have a per-rollout wall-clock limit.
SharedRolloutCollectionConfig-
_BoundedCompletionIteratorCompletion-order iterator with a bounded set of resident asyncio tasks.
_CollectedOutcomeA finished dispatch as collection stores it, with the facts the collector’s loop still reads.
_CompletedRolloutA finished /run dispatch, with timing carried alongside (not inside) the raw result.
_EagerCompletionIteratorStart every rollout in input order on first use, yielding completion-order awaitables.
_EagerCompletionQueueOwn undelivered outcomes independently of the iterator and its handed-out awaitables.
_RowResultIteratorMap completion metadata to (row, result) for the direct collection APIs.
_RunRecordWriterWrites finished rollouts into a run folder the way ng_collect_rollouts lays it out, one shard at a time.

Functions

NameDescription
__getattr__-
_agent_request_failure_rowOne sidecar row for a /run call that came back without a result.
_aggregation_error_entryBuild the metrics-file placeholder for one agent whose aggregation failed.
_batch_status_rowKeep status identities, failure classes and kinds without retaining rollout payloads.
_collected_outcomeBuild the record ng_collect_rollouts stores for a finished dispatch, success or failure.
_collection_failure_reportCollection’s own failure for a failed /run dispatch, caused by the dispatch error, with the report the
_count_lines-
_counted_failure_rowThe metric-input copy of a sidecar row counted as zero.
_counted_failure_rows-
_counts_as_zeroWhether a rollout’s latest sidecar row enters the metrics as a zero: its class is wanted, or it is marked.
_coverage_reportState how much of the input the score covers, for the runs where it is not all of it.
_credentials_rejected_stopThe end of a run whose provider (sandbox, or the grading API) refused its credentials: no attempt succeeds
_current_span_is_valid-
_dataset_admitted_agents(dataset name, allowed_agents) for each dataset entry that declares the dispatched rows with a non-empty
_datasets_declaring_tasksetThe entries that declare the rows of taskset, on whichever agent block declares them: an entry whose
_declared_datasetsThe datasets entries one agent block declares; a list that is missing, a placeholder or not a list
_dispatch_drained_resultThe result Gym builds for a row the dispatch budget never started.
_dispatch_spanOne rollout’s dispatch as the root of its own trace, linked to the run’s job span.
_enrich_returned_resultenrich_run_result for a result run_examples returns, keeping its public shape.
_environment_server_for_agentReturn the one environment server that fronts an agent.
_environment_server_for_config_rowPick the environment server a row is dispatched to, or None for today’s agent path.
_environment_servers_by_agentMap each agent name to the environment servers that front it.
_episode_recordTurn a BaseEpisodeResponse into the rollout record the collector stores.
_episode_reply_violationThe typed failure for a reply that is neither an episode result nor a failure.
_episode_request_body-
_expand_input_globExpand a glob-or-comma-separated-globs string into a sorted, deduplicated list of paths.
_failure_compatibility_rowKeep existing sidecar routing keys and diagnostics alongside the canonical failure.
_failure_diagnosticsPreserve producer diagnostics outside the bounded canonical failure record.
_failure_export_metricsFailure and retry counts for exporters, read from the failures sidecars.
_failure_outcome-
_failure_rows_counted_as_zeroSidecar rows the caller opted to count in the metrics denominator.
_fill_task_fieldsGive the rows the metric input adds, counted failures and imputed zeros, their task’s dataset fields.
_final_zero_failure_rowsThe latest failure rows that settle their rollout as a scored zero: final, and marked by their producer.
_identity_keyA rollout’s key across runs, which each number their tasks from 0.
_is_collector_keyKeys rollout collection writes itself; an Environment Server result must not use them.
_is_episode_responseTrue for a BaseEpisodeResponse-shaped reply: object identities plus a result or failure key.
_judge_failure_responseLegacy judge_failsafe carries real generation that can be judged again.
_latest_failure_rowsThe last failed attempt recorded for each rollout across the failures sidecars.
_masking_step_metricsIn-progress view of what a run is losing to its environment rather than its policy.
_matches_failure_classMatch the canonical class or the original legacy producer’s routing class.
_materialized_taskset-
_metric_failure_kindThe kind as a bounded label: registered or namespaced names pass, anything else is one bucket.
_metrics_groupThe environment server a rollout is scored under, as _call_aggregate_metrics groups it.
_missing_rollout_rows_counted_as_zeroMaterialized rollouts that produced no row anywhere, counted as zeros.
_names_its_task-
_native_episode_recordValidate the dispatched episode identity before translating its outcome.
_normalize_health_check_ignored_checks-
_normalize_rollout_outcome-
_print_on_sigtermPrint render() when Slurm’s time limit sends SIGTERM, then terminate as before.
_protocol_violation_stopThe end of a run whose environment server has answered every request so far with a reply the collector cannot
_quota_exhausted_stopThe end of a run whose grading provider’s quota is exhausted: nothing can be graded until it resets.
_raise_for_aggregation_errorsSignal failure after partial metrics and any batch status have been saved.
_read_jsonlParse a whole JSONL artifact, letting other tasks on the event loop run between rows.
_record_policy_model_serverName the agent’s configured policy server on the record (landed or failed), so offline timing needs no
_record_rollout_healthEvaluate the trajectory health checks on a finished rollout and count the verdict and flagged checks.
_record_rollout_outcomeCount a persisted attempt, including its numeric reward when scored.
_record_rollout_shapeRecord the size of one completed rollout, while metrics are exporting.
_reflect_enrichmentAdd a stored record’s enrichment and identity keys to the reply run_examples returns in its own shape.
_refresh_shard_status_aggregationMark each shard’s run status with the outcome of the aggregation that merged it, keeping its counts.
_reject_attempt_qualified_rollout_idsRefuse dataset rows whose explicit rollout ID names an attempt.
_reply_failure_kindThe kind of the outermost failure in the chain an agent’s failed reply selected that is not a routing kind.
_reply_failure_reportThe FailureReport an environment reply carries beside its outcome; an invalid one is omitted.
_restore_sigterm-
_rollout_order_keyTask then repeat: metrics that read a task’s repeats positionally need that order.
_rollout_request_debug_summary-
_round_robin_by_agentInterleave resolved rows by environment server or agent, preserving each input order.
_routing_identityThe agent a rollout ran on, or for a materialized taskset row, which names none, its environment server.
_rows_of_first_tasksYield the rows of the first limit tasks. Identical rows are one task, as in the task index.
_sample_server_queuesPoll every vLLM server’s /metrics and record requests waiting and running, summed over servers.
_sanitize_legacy_resultDiscard collector bookkeeping while preserving declared legacy evidence.
_shard_recordThe record ng_collect_rollouts would store for completed, for a run_examples call recording a shard.
_shard_rollout_idThe rollout id a recorded shard dispatches row under: the row’s own id, prefixed with the shard’s run id.
_span_task_id-
_stamp_collector_fieldsStamp the row’s identity and routing fields onto the record collection stores, as every reader expects.
_status_failure_kindThe failure kind a sidecar row carries: top-level, the legacy diagnostic key, or the typed record’s.
_sum_vllm_queue-
_task_data_provenanceThe PROVENANCE_KEYS of a materialized row’s task_data: provenance stamps for the record.
_truncated_bodyDecode at most the kept prefix, so a huge error page is never decoded in full.
enrich_run_resultAttach a finished rollout’s collected evidence to its /run result, in place.
is_non_superseding_rollout_rowWhether readers skip a sidecar row before they pick a rollout’s latest attempt.
is_omitted_rollout_rowWhether a failures-sidecar row is a record_omitted_rollouts record of a rollout that produced no result.
is_unstarted_rollout_rowWhether a sidecar row records a rollout the dispatch budget never started: no execution, so no history.
loads_jsonl_lineParse one JSONL line, raising a clean ConfigError (naming file + line) on malformed JSON.

Data

AGENT_REQUEST_FAILED_FAILURE_CLASS

AGENT_RUN_ERROR_FAILURE_CLASS

ENVIRONMENT_SERVER_FAILURE_CLASS

NG_DATASET_DIGEST_KEY

NG_DIGEST_KEY

NG_ELAPSED_KEY

NG_ENVIRONMENT_SERVER_KEY

NG_FAILURE_COUNTS_AS_ZERO_KEY

NG_FAILURE_JUDGE_ERROR_KEY

NG_FAILURE_LEGACY_CLASS_KEY

NG_FAILURE_MAX_ATTEMPTS_KEY

NG_FAILURE_REPORT_KEYS

NG_OMITTED_ROLLOUT_KEY

NG_POLICY_MODEL_SERVER_KEY

NG_RESULT_TYPE_KEY

NG_TASK_ID_KEY

NG_TERMINAL_KEY

NG_UNROUTED_RUN_ERROR_KEY

PROVENANCE_KEYS

ROLLOUT_REPEAT_ATTRIBUTE

STATUS_FAILURE_KIND_KEY

STATUS_MODEL_FINAL_KEY

TASK_ID_ATTRIBUTE

_ENRICHMENT_KEYS

_LEGACY_RESULT_FIELDS

_MAX_FAILURE_BODY_CHARS

_NO_RESULT_FAILURE_CLASSES

_NO_SIGTERM_HOOK

_OWNED_JOB_SPAN_CONTEXT

_READ_JSONL_YIELD_INTERVAL_S

_RESERVED_SHARD_ENDINGS

_ROUTING_FAILURE_KINDS

_RUN_FAILURE_ERRORS

_SERVER_DID_NOT_RUN_STATUSES

_SHARD_IDENTITY_KEYS

_SHARD_LABEL

_failures_path_for

_moved_cli_entry_points

_moved_names

get_max_rollout_attempts

logger

API

class nemo_gym.rollouts.rollout_collection.E2ERolloutCollectionConfig()

Bases: SharedRolloutCollectionConfig

Spin up all necessary servers and perform a batch of rollout collection using each dataset inside the provided configs.

Examples:

gym eval run +output_jsonl_fpath=weather_rollouts.jsonl +num_samples_in_parallel=10
reuse_existing_data_preparation
bool = False
split
Union[Literal['train'], Literal['validation'], Literal['benchmark']]
nemo_gym.rollouts.rollout_collection.E2ERolloutCollectionConfig._reject_example_split(
data
)
classmethod
nemo_gym.rollouts.rollout_collection.E2ERolloutCollectionConfig._reject_input_jsonl_fpath(
data
)
classmethod
class nemo_gym.rollouts.rollout_collection.RolloutAggregationConfig()

Bases: RunHealthConfig, BaseNeMoGymCLIConfig

Aggregate metrics across rollout shards produced by gym eval run --no-serve +disable_aggregation=true.

Reads every JSONL file matching input_glob, computes aggregate metrics by POSTing to each agent server’s /aggregate_metrics endpoint over the global union of records, and writes a single <output_jsonl_fpath stem>_aggregate_metrics.json next to the rollouts. By default also concatenates all shards into output_jsonl_fpath.

Examples:

gym eval aggregate "+config_paths=[benchmarks/aime24/config.yaml,responses_api_models/vllm_model/configs/vllm_model.yaml]" +input_glob='results/rollouts-rs*-chunk*.jsonl' +output_jsonl_fpath=results/rollouts.jsonl
batch_manifest_fpath
Optional[str]
count_failure_classes_as_zero
List[str]
count_missing_rollouts_as_zero
bool
disable_health_check
bool
health_check_ignored_checks
List[str]
health_check_workers
Optional[int]
input_glob
str
materialized_inputs_jsonl_fpath
Optional[str]
merge_shards
bool
output_jsonl_fpath
str
retry_terminal_timeouts
bool
nemo_gym.rollouts.rollout_collection.RolloutAggregationConfig._validate_health_check_ignored_checks(
value
)
classmethod
class nemo_gym.rollouts.rollout_collection.RolloutAggregationHelper()

Bases: BaseModel

nemo_gym.rollouts.rollout_collection.RolloutAggregationHelper.run_from_config(
) -> typing.Optional[pathlib.Path]
async
class nemo_gym.rollouts.rollout_collection.RolloutCollectionConfig()

Bases: SharedRolloutCollectionConfig

Perform a batch of rollout collection.

Examples:

gym eval run --no-serve +agent_name=example_single_tool_call_simple_agent +input_jsonl_fpath=weather_query.jsonl +output_jsonl_fpath=weather_rollouts.jsonl +limit=100 +num_repeats=4 +num_samples_in_parallel=10
agent_map
Optional[Dict[str, str]]
agent_name
Optional[str]
allow_unsafe_resume
bool
dispatch_all_started_within_s
Optional[float]
dispatch_budget_s
Optional[float]
dispatch_connect_grace_s
float
dispatch_longest_first
bool
dispatch_start_report_min_fraction
float
dispatch_start_report_within_s
Optional[float]
drain_margin_s
Optional[float]
fan_out
Optional[Dict[str, List[str]]]
input_jsonl_fpath
str
interleave_repeats
bool
limit
Optional[int]
long_rollout_max_fraction
float
long_rollout_s
Optional[float]
materialized_jsonl_fpath
Path
num_repeats
Union[int, Dict[str, int]]
num_repeats_add_seed
Union[bool, Dict[str, bool]]
prompt_config
Optional[str]
record_omitted_rollouts
bool
resubmit
bool
resume_from_cache
bool
retry_terminal_timeouts
bool
server_queue_max_waiting_ratio
float
server_queue_metrics_urls
Optional[List[str]]
server_queue_sample_interval_s
float
skills
Optional[SkillsConfig]
timed_out_max_fraction
float
timing_summary_interval_s
Optional[float]
nemo_gym.rollouts.rollout_collection.RolloutCollectionConfig._coerce_null_num_repeats(
v
)
classmethod
class nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper()

Bases: BaseModel

Collect rollouts by sending tasks to a running Gym deployment.

Each rollout batch fetches the deployment’s configuration from the head server. A caller that runs many batches against one deployment can set reuse_server_client=True. The helper then fetches the configuration once. Build a new helper after that deployment’s configuration changes.

_cached_head_server_config
Optional[BaseServerConfig] = PrivateAttr(default=None)
_cached_server_client
Optional[ServerClient] = PrivateAttr(default=None)
_collection_started
bool = PrivateAttr(default=False)
_landed_keys
set = PrivateAttr(default_factory=set)
_store
RolloutStore | None = PrivateAttr(default=None)
_termination_requested
Callable[[], bool] | None = PrivateAttr(default=None)
reuse_server_client
bool
nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._agent_name_for_row(
row: dict[str, typing.Any],
global_config_dict: omegaconf.DictConfig
) -> str | None
staticmethod
nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._call_aggregate_metrics(
results: typing.List[typing.Dict],
rows: typing.List[typing.Dict],
output_fpath: pathlib.Path,
raise_on_error: bool = True
) -> typing.Optional[pathlib.Path]
async

Call /aggregate_metrics on the environment server each rollout ran through.

Rows are grouped by the environment server stamped on them at preprocessing (_ng_environment_server); a row without the stamp is grouped by the environment server that fronts its agent, as before, so the identity decided at dispatch is the one aggregation uses, across shards and resumed runs alike. Writes a single _aggregate_metrics.json with one entry per environment server (same shape as the old _agent_metrics.json, plus the server name). Returns the file path. Failed requests retain an entry with empty metric collections and aggregation_error. By default, re-raise the first original exception after saving partial metrics, preserving its type and traceback for direct callers such as custom evaluation drivers. Collection and aggregation entrypoints pass raise_on_error=False to write batch status first, then call _raise_for_aggregation_errors for a summary error.

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._dispatch_name(
row: dict[str, typing.Any]
) -> str
staticmethod
nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._load_from_cache(
retain_results_in_memory: bool = True,
success_keys: typing.Optional[set] = None
) -> typing.Tuple[typing.List[typing.Dict], typing.List[typing.Dict], typing.List[typing.Dict], typing.List[typing.List[bytes]]]
nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._preprocess_raw_rows(
raw_rows: typing.List[typing.Tuple[int, str, typing.Dict]],
) -> typing.List[typing.Dict]
staticmethod
nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._preprocess_rows_from_config(
) -> typing.List[typing.Dict]
nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._run_examples_with_metadata(
examples: typing.List[typing.Dict],
head_server_config: typing.Optional[nemo_gym.config.config_types.BaseServerConfig] = None,
semaphore: typing.Optional[asyncio.Semaphore] = None,
route_failures_to_sidecar: bool = False,
environment_server_name: str | None = None,
max_resident_tasks: typing.Optional[int] = None,
typed_outcomes: bool = False,
validate_results: bool = False,
on_dispatch: typing.Optional[typing.Callable[[Dict], None]] = None,
on_dispatch_batch: typing.Optional[typing.Callable[[List[Dict]], None]] = None,
interleave_by_agent: bool = False,
dispatch_budget_s: typing.Optional[float] = None,
drain_margin_s: typing.Optional[float] = None,
latency_tracker: typing.Optional[nemo_gym.rollouts.rollout_perf.DispatchLatencyTracker] = None,
retry_requests: bool = True,
_max_num_tries: typing.Optional[int] = None,
run_timing: typing.Optional[nemo_gym.rollouts.rollout_collection.RunTimingReport] = None,
record_unrouted_failures: bool = False,
_connect_grace_s: typing.Optional[float] = None
) -> typing.Iterator[asyncio.Future]

Internal dispatch shared by run_examples and Gym’s own collection paths.

record_unrouted_failures returns a failed /run that route_failures_to_sidecar would route as a failure row whose run_error holds the error, so the collection writer can keep evidence of it before it raises the error. Other callers keep receiving the exception.

When max_resident_tasks is set, at most that many rollout tasks are admitted at once. When unset, all examples are scheduled as before. The collection owner closes either iterator on completion, cancellation or error.

dispatch_budget_s stops starting rows that many seconds after this call, and drain_margin_s stops sooner for rows that would not have time to finish. A row drained this way resolves to a Gym-built _dispatch_drained_result.

Identical contract to run_examples, but each future resolves to a _CompletedRollout that carries rollout_latency_ms alongside the raw /run result instead of inside it, so internal-only timing never has to be smuggled through (and stripped back out of) a dict that a direct caller of run_examples could also observe.

interleave_by_agent is enabled by the full evaluation path. Lower-level callers retain the order they supplied.

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._run_from_config(
) -> typing.Tuple[typing.List[typing.Dict]]
async
nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._run_locked_from_config(
) -> typing.Tuple[typing.List[typing.Dict]]
async
nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._stamp_environment_server_agent_refs(
examples: list[dict[str, typing.Any]],
global_config_dict: omegaconf.DictConfig
) -> None
classmethod

Stamp compatibility-routed rows with the bound agent.

These rows never reach resolve_task_sources, so without this they carry no agent_ref and results, aggregate metrics and reward profiling lose the agent they ran on. A row that already names an agent is left alone; the name is validated against the environment server by _validate_environment_servers. Materialized tasks are skipped: they carry no agent by design, and their result projection is not the legacy shape this key belongs to.

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._validate_agent_names(
examples: typing.List[typing.Dict],
global_config_dict: omegaconf.DictConfig
) -> None
staticmethod

Fail before any dispatch when a row names an agent absent from the running config.

Without this, the first bad row dies mid-collection with a raw omegaconf ConfigKeyError after valid rows have already been dispatched.

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._validate_agent_pairings(
examples: typing.List[typing.Dict],
global_config_dict: omegaconf.DictConfig
) -> None
staticmethod

Fail before dispatch when a row points to agent incompatible with the resources server it runs on.

The verifier’s allowed_agents is read from the row’s task_source and from the resources server the agent binds; the dataset entry that declares the rows may also name the harnesses it admits (a Harbor dataset’s [gym] allowed_agents, carried into its generated datasets: entry, whose rows route by taskset to an environment server that binds no resources server). That list is checked against the agent’s own type, so a run config edited to another harness after gym eval run admitted one is refused here as well. A materialized row is matched to its entry by taskset, wherever the entry is declared; a flat row meets every entry the agent declares (see _dataset_admitted_agents).

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper._validate_environment_servers(
examples: list[dict],
global_config_dict: omegaconf.DictConfig
) -> None
classmethod
nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper.preprocess_examples(
examples: typing.List[typing.Dict],
agent_map: typing.Optional[typing.Dict[str, str]] = None,
fan_out: typing.Optional[typing.Dict[str, typing.List[str]]] = None,
num_repeats: typing.Union[int, typing.Dict[str, int]] = 1,
num_repeats_add_seed: typing.Union[bool, typing.Dict[str, bool]] = False,
global_config_dict: typing.Optional[omegaconf.DictConfig] = None,
task_ids: typing.Optional[collections.abc.Sequence[str]] = None
) -> typing.List[typing.Dict]

Apply run-level routing and repetition to caller-held rows.

Public entry point for direct run_examples callers (e.g. trainer integrations that drive dispatch themselves): run_examples resolves task_sources and validates agent names, but agent_map, fan_out and num_repeats are applied only during preprocessing. Call this first, then pass the returned rows to run_examples.

Pass global_config_dict (the merged config) to also resolve task_source-only rows to their agents here; leave it None to defer that to run_examples, which does it against the head server’s config. Pass task_ids to keep only those tasks, selected by the id stored in each row (see nemo_gym.data.task_selection.select_tasks), each task once before repetition. Input rows are not mutated; the expanded, stamped copies are returned.

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper.resolve_task_sources(
examples: typing.List[typing.Dict],
global_config_dict: omegaconf.DictConfig
) -> None
staticmethod

Stamp an agent_ref onto every row that carries only a task_source.

task_source names the config instance that declared the row’s dataset. Resolution is resolve_dataset_agent — the same rules benchmark discovery uses, so dispatch can never disagree with the listing. Conflicting agent: pins across one instance’s datasets are a hard error (rows carry only the instance name), as are unknown/non-routable instances; +agent_map is the disambiguator.

Rows that already have an agent_ref are left untouched, so this is a no-op on legacy datasets and on already-resolved (materialized) rows. Runs before any dispatch.

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper.run_examples(
examples: typing.List[typing.Dict],
head_server_config: typing.Optional[nemo_gym.config.config_types.BaseServerConfig] = None,
semaphore: typing.Optional[asyncio.Semaphore] = None,
route_failures_to_sidecar: bool = False,
environment_server_name: str | None = None,
max_resident_tasks: typing.Optional[int] = None,
dispatch_budget_s: typing.Optional[float] = None,
drain_margin_s: typing.Optional[float] = None,
latency_tracker: typing.Optional[nemo_gym.rollouts.rollout_perf.DispatchLatencyTracker] = None,
retry_requests: bool = True,
enrich_results: bool = False,
include_model_call_payloads: bool = True,
delete_model_call_capture: bool = False,
record_output_dir: typing.Optional[pathlib.Path | str] = None,
record_shard: typing.Optional[str] = None,
record_omitted_rollouts: bool = False

We provide this function as a lower level interface for running rollout collection.

Rows are dispatched as given: task_sources are resolved and agent names validated here, but run-level knobs (agent_map, fan_out, num_repeats) are NOT applied — call preprocess_examples first if you need them.

route_failures_to_sidecar makes a failed /run a failure row instead of an exception that ends every rollout still in flight. It defaults off because those rollouts then leave the score.

max_resident_tasks limits admitted tasks and therefore concurrent requests, even when semaphore allows more. Admission starts when the first returned awaitable is awaited. None schedules all examples up front, as with asyncio.as_completed.

To stop early, await the returned iterator’s aclose(): it cancels unfinished rollouts and waits for their client tasks in this process to end. Cancelling an in-flight /run closes its connection; a server with ClientDisconnectCancellationMiddleware subsequently cancels its handler. Server/agent cleanup is not awaited or acknowledged, depends on the agent, and may continue after return. Sandbox release is not guaranteed. Handed-out awaitables may return completed results or raise their exceptions, including CancelledError; bounded awaitables first awaited after closure raise CancelledError. The error propagates in the awaiting caller’s task even without cancelling that task, and asyncio.gather and TaskGroup treat it as cancellation. Without it, abandoned rollouts keep running to completion in the background.

To preserve completed but unconsumed work when stopping, use await completions.aclose_and_drain() instead. It stops admission before suspending, cancels and awaits unfinished client tasks, and returns settled (row, result) futures, including failures. Consume those futures and any outcome already claimed by an outstanding completion waiter; an unclaimed waiter raises CancelledError. Repeated drains return an empty list. This also works with bounded admission without starting more rows, and has the same server/agent cleanup limits as aclose().

Use finally to close the iterator if collection stops early:

completions = helper.run_examples(examples)
try:
for future in completions:
row, result = await future
if should_stop(row, result):
break
finally:
await completions.aclose()

dispatch_budget_s stops starting rows that many seconds after this call, and drain_margin_s stops sooner for rows that would not have time to finish.

Rows start in the order given, once the returned iterator is first consumed.

A row that ran resolves to exactly the (row, result) pair Gym’s own /run endpoint returned — no Gym-private fields are added to result. A row that produced no /run result resolves to a Gym-built result carrying Gym-private fields instead: a row drained by the dispatch budget gets _ng_failure_class="cancelled" with the _ng_dispatch_drained and _ng_no_persist markers, and a failed /run under route_failures_to_sidecar gets a failure row with _ng_failure_* fields.

retry_requests=False disables automatic HTTP replay of a mutating /run. Connections that were never established can still be retried safely. It does not convert failures to successful result rows.

enrich_results runs enrich_run_result on each result before it is returned, so the caller receives what ng_collect_rollouts records: the row’s rollout identity, the captured model calls (ng_model_call_capture, with request and response bodies unless include_model_call_payloads is false), the standardized ng_trajectory and ng_perf. Model calls are captured only when the global config enables observability_enabled. delete_model_call_capture removes each rollout’s capture file after it is merged, and needs the payloads kept. With enrich_results the rows are dispatched as collection dispatches them, on copies that name this call’s run: results are validated, and under route_failures_to_sidecar a failed /run comes back as the typed RolloutFailureRecord, as run_outcomes returns it; rows without a rollout identity keep the plain dispatch. With enrich_results off, results are exactly what /run returned.

record_output_dir with record_shard also writes each rollout to that run folder through _RunRecordWriter, as ng_collect_rollouts would: rollouts-<shard>.jsonl, its failures sidecar with the typed failure rows collection writes, the rows as the shard’s materialized inputs, its run manifest and its saved progress for gym eval status (omitted-rollout rows with record_omitted_rollouts). It implies enrich_results, dispatches as collection does (typed failure records under route_failures_to_sidecar, validated results) on copies of the rows that name the shard’s run, and the Store, the run health check and gym eval aggregate read the shard like an eval run. Each copy’s rollout id is the row’s own id (its _ng_rollout_id, or <task>-<rollout>) prefixed with the shard’s run id, so the shard’s model calls are captured under keys of its own; a caller that looks a capture up reads its key from the returned row (maybe_rollout_id_from_run_body). gym eval run with +input_jsonl_fpath=<dir>/rollouts-<shard>_materialized_inputs.jsonl +output_jsonl_fpath=<dir>/rollouts-<shard>.jsonl +resume_from_cache=true resumes a shard and runs only what it still lacks.

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper.run_from_config(
) -> typing.Tuple[typing.List[typing.Dict]]
async

Collect rollouts for a whole config. Wrapped in the run-scoped job span.

This is the driver side of an evaluation run and the outermost span Gym produces. Rollouts are not its descendants: each dispatch opens its own trace, linked to this span (see _dispatch_span), so a run’s traces stay bounded by one rollout each while job keeps the run’s own lifecycle. job is in the default preset and not in per_rollout.

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper.run_outcomes(
examples: typing.List[typing.Dict],
head_server_config: typing.Optional[nemo_gym.config.config_types.BaseServerConfig] = None,
semaphore: typing.Optional[asyncio.Semaphore] = None,
run_id: str | None = None

Yield (row, completed_dict | RolloutFailureRecord) in completion order.

Expected HTTP, JSON and result-shape failures become bounded records. Programming errors and cancellation still propagate. Call preprocess_examples first, or provide stable explicit rollout ids. This does not persist or retry work; a direct caller owns those decisions. Supply run_id to associate direct calls with a run, overriding any row stamp. Without it, existing row stamps are preserved; unstamped rows share a new invocation ID. Returned rows are invocation-owned copies; input rows are not modified. run_examples retains its behavior.

On early stopping, await the iterator’s aclose() to cancel and join unfinished client tasks, or aclose_and_drain() to also retrieve settled, unconsumed outcomes. Both have the same server/agent cleanup limitations documented by run_examples.

nemo_gym.rollouts.rollout_collection.RolloutCollectionHelper.setup_server_client(
head_server_config: typing.Optional[nemo_gym.config.config_types.BaseServerConfig] = None

Return a client for the head server, reusing the cached one when the helper opted in.

Without opt-in, every call fetches the configuration from the head server again. An opted-in helper keeps one client and fetches again only when the head config differs from the cached one. Build a new helper after the configuration behind the same head changes.

class nemo_gym.rollouts.rollout_collection.RunTimingReport(
total: int,
start_within_s: float,
start_min_fraction: float,
all_started_within_s: typing.Optional[float],
long_rollout_s: typing.Optional[float],
long_rollout_max_fraction: float,
timed_out_max_fraction: float,
max_waiting_ratio: typing.Optional[float] = None
)

Health table for a collection whose rollouts have a per-rollout wall-clock limit.

A per-rollout limit (e.g. BrowseComp’s rollout_timeout_s) makes the score depend on the deployment as well as the model: if the servers are too few or too slow, rollouts start late, queue for the GPU, or run into the limit, and are scored 0 for reasons unrelated to the model. This table shows whether a run stayed clear of that, so a score from a starved run is not mistaken for a model result. Each row compares this run with a healthy bound:

  • start coverage: rollouts started within start_within_s and all started by all_started_within_s (late starts eat into a fixed job allocation);
  • rollouts ended by the wall-clock limit (above the bound, the limit is shaping the score);
  • rollouts longer than long_rollout_s (an early sign that the limit is too tight);
  • summed waiting / running requests on the model servers, when their URLs are given (requests queue instead of being served).

Diagnostic only: it prints a warning per unhealthy row and never stops the run.

_all_started_within_s
_durations
List[float] = []
_peak_ratio
= 0.0
_queue_samples
= 0
_running_sum
= 0.0
_start_offsets
List[float] = []
_t0
= time.monotonic()
_timed_out
= 0
_waiting_sum
= 0.0
nemo_gym.rollouts.rollout_collection.RunTimingReport.record_queue(
waiting: float,
running: float
) -> None

One sample of requests waiting and running, summed over every server.

nemo_gym.rollouts.rollout_collection.RunTimingReport.record_result(
result: collections.abc.Mapping[str, typing.Any],
seconds: float
) -> None
nemo_gym.rollouts.rollout_collection.RunTimingReport.record_start(
now: float
) -> None
nemo_gym.rollouts.rollout_collection.RunTimingReport.table() -> str
class nemo_gym.rollouts.rollout_collection.SharedRolloutCollectionConfig()

Bases: RemovedRolloutOptionsMixin, UploadRolloutsConfigMixin, RunHealthConfig, BaseNeMoGymCLIConfig

batch_manifest_fpath
Optional[str]
count_failure_classes_as_zero
List[str]
count_missing_rollouts_as_zero
bool
disable_aggregation
bool
disable_health_check
bool
environment_protocol_violation_stop_after
int
environment_routing_mode
Literal['agent', 'legacy', 'taskset']
environment_server_name
str | None
environment_server_routes
dict[str, str]
health_check_ignored_checks
List[str]
health_check_workers
Optional[int]
max_resident_rollout_tasks
Optional[int]
num_samples_in_parallel
Optional[int]
output_jsonl_fpath
str
require_complete
bool
responses_create_params
Dict[str, Any]
retain_results_in_memory
bool
rollout_collection_driver
Optional[str]
route_failures_to_sidecar
bool
nemo_gym.rollouts.rollout_collection.SharedRolloutCollectionConfig._validate_health_check_ignored_checks(
value
)
classmethod
nemo_gym.rollouts.rollout_collection.SharedRolloutCollectionConfig.check_completion(
expected: int,
results: typing.List[typing.Dict[str, typing.Any]],
completed: int | None = None,
intentionally_omitted: int = 0,
retryable: bool,
made_progress: bool,
final_zero_rows: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]] = ()
) -> None

Raise the strict run’s rejection, if any; see completion_rejection for the arguments.

nemo_gym.rollouts.rollout_collection.SharedRolloutCollectionConfig.completion_rejection(
expected: int,
results: typing.List[typing.Dict[str, typing.Any]],
completed: int | None = None,
intentionally_omitted: int = 0,
retryable: bool,
made_progress: bool,
final_zero_rows: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]] = ()

The error that rejects unfinished work, or None; omissions alongside completed tasks are allowed.

Collection decides this before it computes the aggregate, so a rejected run publishes no score. Drivers must supply whether any tasks can still be retried and whether this invocation saved outcomes that made progress (not just interruptions). Assuming either can cause endless automatic restarts when a driver has no work left or makes no progress.

final_zero_rows are failure rows that settle their rollout as a scored zero (see _final_zero_failure_rows): resume does not run them again, so they are completed samples. A caller that passes completed has already counted them.

class nemo_gym.rollouts.rollout_collection._BoundedCompletionIterator(
awaitables: typing.Iterator,
max_resident_tasks: int,
total: int
)

Completion-order iterator with a bounded set of resident asyncio tasks.

_awaitables
= iter(awaitables)
_lock
= asyncio.Lock()
_pending
set[Task] = set()
_progress
_ready
list[Task] = []
_resident_task_count
int
nemo_gym.rollouts.rollout_collection._BoundedCompletionIterator.__iter__()
nemo_gym.rollouts.rollout_collection._BoundedCompletionIterator.__next__()
nemo_gym.rollouts.rollout_collection._BoundedCompletionIterator._admit() -> bool
nemo_gym.rollouts.rollout_collection._BoundedCompletionIterator._close(
drain: bool
) -> list[asyncio.Future]
async
nemo_gym.rollouts.rollout_collection._BoundedCompletionIterator._fill() -> None
nemo_gym.rollouts.rollout_collection._BoundedCompletionIterator._next_completed()
async
nemo_gym.rollouts.rollout_collection._BoundedCompletionIterator.aclose() -> None
async
nemo_gym.rollouts.rollout_collection._BoundedCompletionIterator.aclose_and_drain() -> list[asyncio.Future]
async
class nemo_gym.rollouts.rollout_collection._CollectedOutcome(
record: typing.Dict[str, typing.Any],
structured_failure: bool,
diagnostics: typing.Dict[str, typing.Any],
metric_result: typing.Dict[str, typing.Any],
verification_response: typing.Optional[typing.Dict[str, typing.Any]]
)
Dataclass

A finished dispatch as collection stores it, with the facts the collector’s loop still reads.

diagnostics
Dict[str, Any]
metric_result
Dict[str, Any]
record
Dict[str, Any]
structured_failure
bool
verification_response
Optional[Dict[str, Any]]
class nemo_gym.rollouts.rollout_collection._CompletedRollout(
row: typing.Dict[str, typing.Any],
result: typing.Dict[str, typing.Any] | nemo_gym.rollouts.rollout_outcomes.RolloutFailureRecord,
rollout_latency_ms: typing.Optional[float],
verification_response: typing.Optional[typing.Dict[str, typing.Any]] = None,
diagnostics: typing.Optional[typing.Dict[str, typing.Any]] = None,
environment_server: typing.Optional[str] = None,
environment_server_type: typing.Optional[str] = None,
elapsed_s: typing.Optional[float] = None,
dispatch_span_context: typing.Optional[opentelemetry.trace.SpanContext] = None,
failure_report: typing.Optional[nemo_gym.core.failure_records.FailureReport] = None,
run_error: typing.Optional[BaseException] = None
)
Dataclass

A finished /run dispatch, with timing carried alongside (not inside) the raw result.

diagnostics
Optional[Dict[str, Any]] = None
dispatch_span_context
Optional[SpanContext] = None
elapsed_s
Optional[float] = None
environment_server
Optional[str] = None
environment_server_type
Optional[str] = None
failure_report
Optional[FailureReport] = None
result
Dict[str, Any] | RolloutFailureRecord
rollout_latency_ms
Optional[float]
row
Dict[str, Any]
run_error
Optional[BaseException] = None
verification_response
Optional[Dict[str, Any]] = None
class nemo_gym.rollouts.rollout_collection._EagerCompletionIterator(
awaitables: typing.Iterator,
total: int
)

Start every rollout in input order on first use, yielding completion-order awaitables.

_queue
Optional[_EagerCompletionQueue] = None
_tasks
set[Future] = set()
nemo_gym.rollouts.rollout_collection._EagerCompletionIterator.__iter__()
nemo_gym.rollouts.rollout_collection._EagerCompletionIterator.__next__()
nemo_gym.rollouts.rollout_collection._EagerCompletionIterator._close(
drain: bool
) -> list[asyncio.Future]
async
nemo_gym.rollouts.rollout_collection._EagerCompletionIterator._on_done(
task: asyncio.Future
) -> None
nemo_gym.rollouts.rollout_collection._EagerCompletionIterator.aclose() -> None
async
nemo_gym.rollouts.rollout_collection._EagerCompletionIterator.aclose_and_drain() -> list[asyncio.Future]
async
class nemo_gym.rollouts.rollout_collection._EagerCompletionQueue(
progress
)

Own undelivered outcomes independently of the iterator and its handed-out awaitables.

ready
Queue[Future] = asyncio.Queue()
nemo_gym.rollouts.rollout_collection._EagerCompletionQueue.drain() -> list[asyncio.Future]
nemo_gym.rollouts.rollout_collection._EagerCompletionQueue.get()
async
nemo_gym.rollouts.rollout_collection._EagerCompletionQueue.put(
task: asyncio.Future
) -> None
class nemo_gym.rollouts.rollout_collection._RowResultIterator(
completions: typing.Iterator[asyncio.Future],
enrich: typing.Optional[typing.Callable[[_CompletedRollout], typing.Awaitable[typing.Any]]] = None,
on_close: typing.Optional[typing.Callable[[], None]] = None
)

Map completion metadata to (row, result) for the direct collection APIs.

A thin map over the internal completion iterator that keeps its aclose() reachable, so a direct caller can stop collecting and cancel the rollouts still in flight.

nemo_gym.rollouts.rollout_collection._RowResultIterator.__iter__()
nemo_gym.rollouts.rollout_collection._RowResultIterator.__next__()
nemo_gym.rollouts.rollout_collection._RowResultIterator._finish() -> None

Run the close hook once, after the outcomes a close still delivers have been enriched.

nemo_gym.rollouts.rollout_collection._RowResultIterator._without_metadata(
future: asyncio.Future
) -> typing.Tuple[typing.Dict, typing.Dict | nemo_gym.rollouts.rollout_outcomes.RolloutFailureRecord]
async
nemo_gym.rollouts.rollout_collection._RowResultIterator.aclose() -> None
async

Cancel unfinished rollouts and await the end of their client tasks in this process.

Cancelling an in-flight /run request closes its connection. A server using ClientDisconnectCancellationMiddleware subsequently cancels its handler. This method does not wait for or acknowledge server/agent cleanup, which depends on the agent and may continue after return; it does not guarantee sandbox release or retire an attempt.

A handed-out awaitable may return an already completed result or raise its exception, including CancelledError for cancelled work. In bounded mode, an awaitable first awaited after closure raises CancelledError even if a result was ready. This error propagates in the awaiting caller’s task without a call to that task’s cancel(); asyncio.gather and TaskGroup treat it as cancellation. Iteration stops after closure. Safe to call again after closure completes, or before first use (no rollouts start).

nemo_gym.rollouts.rollout_collection._RowResultIterator.aclose_and_drain() -> list[asyncio.Future[typing.Tuple[typing.Dict, typing.Dict | nemo_gym.rollouts.rollout_outcomes.RolloutFailureRecord]]]
async

Stop admission, cancel unfinished client tasks, and preserve completed outcomes.

Before its first suspension, this operation stops admitting rollouts and snapshots completed outcomes not yet claimed by a completion awaitable. It then cancels and awaits unfinished client tasks, and returns settled futures yielding (row, result) or raising the original exception. No new rollouts start while draining, including in bounded mode. Outcomes are transferred once; repeated calls return an empty list.

A handed-out awaitable that already claimed an outcome retains it. Other issued awaitables raise CancelledError. Callers with an outstanding waiter must also await that waiter and consume its outcome if it was not cancelled. The returned futures have their exceptions retrieved even if abandoned; awaiting them still raises. An outcome already cancelled at the snapshot is returned as a cancelled future and raises CancelledError when awaited. Tasks cancelled by this operation are excluded.

Calling this before first use starts nothing. Calling it after aclose() returns nothing. Like aclose(), it waits only for local client tasks, not server/agent cleanup, and does not guarantee sandbox release.

class nemo_gym.rollouts.rollout_collection._RunRecordWriter(
record_output_dir: pathlib.Path | str,
shard: str,
record_omitted_rollouts: bool = False,
rows: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None,
run_id: typing.Optional[str] = None,
status_rows: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None,
global_config: typing.Any = None
)

Writes finished rollouts into a run folder the way ng_collect_rollouts lays it out, one shard at a time.

Private: run_examples(record_output_dir=..., record_shard=...) is the entry point, and it hands this writer the records the collector’s own builder produced. A caller writing rows of its own would bypass that builder.

A shard is <record_output_dir>/rollouts-<shard>.jsonl with its failures sidecar and, when the rows are given, its materialized inputs, a verified run manifest with every attempt reserved, and its saved progress (rollouts-<shard>_batch_status.json) beside it, so a folder of shards is what gym eval aggregate, the run health check, the Store (including resume and recovery) and EvalRDL’s reader already read. The manifest is the one gym eval run computes when it resumes the shard (+input_jsonl_fpath=<dir>/rollouts-<shard>_materialized_inputs.jsonl +output_jsonl_fpath=<dir>/rollouts-<shard>.jsonl +resume_from_cache=true), so that resume runs only what the shard still lacks. The caller picks the shard label (for example a training step and worker); Gym owns the file names. A result goes to the rollouts file, a failed one to the failures sidecar as the typed failure row collection writes, with its attempt cap, and an interrupted or never-started try to the sidecar as an omitted-rollout row only when record_omitted_rollouts is set. Opening a shard replaces what an earlier run wrote under the same label, so a replayed step does not duplicate rows.

_generation
= self.rollouts_fpath.stat().st_ino
_lock_fpath
_status
Optional[RunStatusTracker] = RunStatusTracker(self.status_fpath, status_rows)
_status_agent_refs
Dict[Tuple[int, int], Dict]
_status_completed
List[Dict] = []
_status_expected
= len(rows) if rows is not None else None
_status_failures
List[Dict] = []
_status_written
= 0
_writer_token
= secrets.token_hex(16)
failures_fpath
= failures_path_for(self.rollouts_fpath)
manifest
= self._resumable_manifest(rows, global_config)
manifest_fpath
= manifest_path_for(self.rollouts_fpath)
materialized_fpath
= materialized_path_for(self.rollouts_fpath)
rollouts_fpath
run_id
= run_id or uuid4().hex
status_fpath
= batch_status_path_for(self.rollouts_fpath)
nemo_gym.rollouts.rollout_collection._RunRecordWriter._locked() -> typing.Iterator[typing.Any]

Hold the shard’s lock across processes, so opening and each write never interleave with another’s.

The lock file is never unlinked or replaced, so every writer of a label locks the same object; it also holds the token of the writer that opened the shard last.

nemo_gym.rollouts.rollout_collection._RunRecordWriter._resumable_manifest(
rows: typing.List[typing.Dict[str, typing.Any]],
global_config: typing.Any

The manifest gym eval run computes when it resumes this shard, with every row’s attempt reserved.

That resume names the shard’s materialized inputs as its input and the shard as its output, and leaves the other collection settings at their defaults: the same source file, the same rows and, with the same servers, the same configuration. Collection numbers each task’s rollouts 0, 1, … in input order, so rows numbered otherwise are recorded too, and that resume refuses them as other materialized inputs. A configuration this call cannot take an identity from still records the shard, whose manifest then verifies its own inputs only, so a resume refuses it and says why.

nemo_gym.rollouts.rollout_collection._RunRecordWriter.flush_status() -> None

Write the shard’s status as it stands, for a caller that stops consuming before every row is in.

nemo_gym.rollouts.rollout_collection._RunRecordWriter.write(
result: collections.abc.Mapping[str, typing.Any]
) -> typing.Optional[pathlib.Path]

Append one finished rollout’s record; returns the file written, or None for an omitted row not kept.

Raises:

  • RuntimeError: Another writer opened the same shard since this one did.
nemo_gym.rollouts.rollout_collection.__getattr__(
name: str
) -> typing.Any
nemo_gym.rollouts.rollout_collection._agent_request_failure_row(
exc: BaseException,
status: typing.Optional[int],
headers: typing.Any = None
) -> typing.Dict[str, typing.Any]

One sidecar row for a /run call that came back without a result.

No reward and no response: an infrastructure failure is not a verifier score of zero, and a placeholder would read as real generation data to token capture, aggregation and trainers. The class says whether the rollout ran. A NeMo Gym server answers 500 when its own handler raises, so any status it answered with means the rollout ran and broke, which is also how a model server rejecting the model’s own output arrives here. A gateway status, or no reply to take a status from, says nothing about the rollout. Neither class carries a reward; an evaluation that wants the first counted names it in count_failure_classes_as_zero.

nemo_gym.rollouts.rollout_collection._aggregation_error_entry(
agent_name: str,
exc: BaseException,
response_status: typing.Optional[int] = None
) -> typing.Dict[str, typing.Any]

Build the metrics-file placeholder for one agent whose aggregation failed.

nemo_gym.rollouts.rollout_collection._batch_status_row(
result: typing.Dict,
agent_refs_by_key: typing.Dict[typing.Tuple[int, int], typing.Dict]
) -> typing.Dict

Keep status identities, failure classes and kinds without retaining rollout payloads.

nemo_gym.rollouts.rollout_collection._collected_outcome(
result: typing.Dict[str, typing.Any] | nemo_gym.rollouts.rollout_outcomes.RolloutFailureRecord

Build the record ng_collect_rollouts stores for a finished dispatch, success or failure.

result is completed.result after the caller’s episode translation and legacy sanitizing. A failure, typed or marked, becomes the failures-sidecar row: the typed record’s compatibility fields beside the producer’s diagnostics and the judge reply it kept, then the identity and routing stamps and the causal failure report. _RunRecordWriter builds its rows here as well, so an RL shard reads like an eval run.

nemo_gym.rollouts.rollout_collection._collection_failure_report(
exc: BaseException,
failure_class: str,
headers: typing.Any

Collection’s own failure for a failed /run dispatch, caused by the dispatch error, with the report the reply forwarded. Routing classes remain outcome metadata; this diagnostic has a registered collection kind.

nemo_gym.rollouts.rollout_collection._count_lines(
path: pathlib.Path
) -> int
nemo_gym.rollouts.rollout_collection._counted_failure_row(
row: typing.Dict[str, typing.Any]
) -> typing.Dict[str, typing.Any]

The metric-input copy of a sidecar row counted as zero.

nemo_gym.rollouts.rollout_collection._counted_failure_rows(
rows: typing.List[typing.Dict],
failure_classes: typing.List[str]
) -> typing.List[typing.Dict]
nemo_gym.rollouts.rollout_collection._counts_as_zero(
row: collections.abc.Mapping[str, typing.Any],
wanted: set
) -> bool

Whether a rollout’s latest sidecar row enters the metrics as a zero: its class is wanted, or it is marked.

nemo_gym.rollouts.rollout_collection._coverage_report(
expected: int,
scored: int,
failure_counts: collections.Counter,
failures_hint: typing.Any,
imputed: int = 0
) -> str

State how much of the input the score covers, for the runs where it is not all of it.

Silence here is what makes a partial run look complete, so this reports against the materialized input rather than the rollouts one hop happened to dispatch, and names the rollouts that are in the score only as imputed zeros.

nemo_gym.rollouts.rollout_collection._credentials_rejected_stop(
failures: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]

The end of a run whose provider (sandbox, or the grading API) refused its credentials: no attempt succeeds until they are fixed.

nemo_gym.rollouts.rollout_collection._current_span_is_valid() -> bool
nemo_gym.rollouts.rollout_collection._dataset_admitted_agents(
global_config_dict: omegaconf.DictConfig,
agent_config: omegaconf.DictConfig,
taskset: str | None
) -> list[tuple[str, list[str]]]

(dataset name, allowed_agents) for each dataset entry that declares the dispatched rows with a non-empty allowed_agents.

A materialized row names its dataset through its taskset, so only the entry that declares that taskset counts (_datasets_declaring_taskset), not every dataset the executing agent happens to declare: a second, unrelated entry on the agent cannot refuse the rows. The lookup covers every agent block, not the executing agent’s alone: a Harbor dataset’s entry sits on the agent block gym eval run generated for it, and a run config edited to route the taskset’s environment server to another agent block afterwards still has to meet the dataset’s list. A flat row routed to an agent directly names no dataset, so every dataset that agent declares counts. So do the executing agent’s entries that set no taskset when no entry anywhere declares the rows’ taskset: a hand-written entry may list pre-materialized rows under a name of its own (collate_samples accepts such rows in any entry), and those rows are still that agent’s dataset, so they are checked rather than none; an entry that sets a taskset materializes and routes its rows as that taskset, so one naming another taskset does not hold these rows.

A bare string is one entry, as allowed_agents_for reads a resources server’s.

nemo_gym.rollouts.rollout_collection._datasets_declaring_taskset(
global_config_dict: omegaconf.DictConfig,
taskset: str
) -> list[omegaconf.DictConfig]

The entries that declare the rows of taskset, on whichever agent block declares them: an entry whose taskset is that name, or whose name is when it sets none (a Harbor dataset’s generated entry, named after its taskset and routed by it).

nemo_gym.rollouts.rollout_collection._declared_datasets(
agent_config: omegaconf.DictConfig
) -> list[omegaconf.DictConfig]

The datasets entries one agent block declares; a list that is missing, a placeholder or not a list declares nothing.

nemo_gym.rollouts.rollout_collection._dispatch_drained_result(
remaining_s: float,
margin_s: typing.Optional[float]
) -> typing.Dict[str, typing.Any]

The result Gym builds for a row the dispatch budget never started.

No row is written anywhere: absence is the resume signal, so the task is re-dispatched intact next allocation instead of being started and killed part-way through. _ng_dispatch_drained keeps it out of capture, token finalization, progress metrics and the rollouts upload, since nothing ran.

nemo_gym.rollouts.rollout_collection._dispatch_span(
row: collections.abc.Mapping[str, typing.Any],
dispatch_name: str,
server_name: str
) -> typing.Iterator[opentelemetry.trace.SpanContext]

One rollout’s dispatch as the root of its own trace, linked to the run’s job span.

The /run call made inside carries this span as traceparent, so the agent’s gym.rollout span and everything below it join the new trace instead of nesting under gym.job. The link, not a parent edge, ties the trace back to the job; both carry the run id as a resource attribute. The identity comes from the collector row, not from the posted body: a materialized episode body carries it only as episode_id. dispatch_name is the value the rollout counters record under the same key, so spans and metrics join on it; server_name is the server the call goes to, which differs for a row routed by agent. Only a job the driver opened as its own root is split; under an embedder’s trace the dispatch keeps nesting (see linked_root_span). Gate on the rollout group and the trace exporter before calling.

Yields the span’s context, which the driver keeps to attach gym.rollout.health later.

nemo_gym.rollouts.rollout_collection._enrich_returned_result(
row: dict[str, typing.Any],
result: dict[str, typing.Any],
rollout_latency_ms: typing.Optional[float],
options: typing.Any = {}
) -> dict[str, typing.Any]
async

enrich_run_result for a result run_examples returns, keeping its public shape.

An Environment Server reply to a materialized task is a BaseEpisodeResponse whose evidence is nested; it is enriched through the record the collector stores, and the enrichment keys are added to the reply’s top level. Returns the enriched record.

nemo_gym.rollouts.rollout_collection._environment_server_for_agent(
agent_name: str,
servers_by_agent: collections.abc.Mapping[str, list[str]]
) -> str

Return the one environment server that fronts an agent.

A row routed by its agent cannot choose between several environment servers. Several servers may still front one agent when every row names its server directly. Materialized tasksets name their environment server through environment_server_routes.

nemo_gym.rollouts.rollout_collection._environment_server_for_config_row(
row: collections.abc.Mapping[str, typing.Any],
config: typing.Any
) -> str | None

Pick the environment server a row is dispatched to, or None for today’s agent path.

A materialized task (task_id.taskset plus task_input) always routes by its taskset: it is already an episode request and no agent-server /run accepts it. A flat row follows environment_routing_mode: agent keeps today’s routing (its agent’s environment server is resolved at dispatch), legacy sends every flat row to environment_server_name, and taskset refuses flat rows so a run of materialized rows cannot silently pick up legacy input.

One batch may therefore hold both kinds of rows in agent and legacy mode. The chosen server is stamped on the row as _ng_environment_server and travels with it through the materialized input file, retries, and results.

nemo_gym.rollouts.rollout_collection._environment_servers_by_agent(
global_config_dict: omegaconf.DictConfig
) -> dict[str, list[str]]

Map each agent name to the environment servers that front it.

nemo_gym.rollouts.rollout_collection._episode_record(
response: typing.Dict[str, typing.Any]
) -> typing.Dict[str, typing.Any]

Turn a BaseEpisodeResponse into the rollout record the collector stores.

A handled failure becomes a failures-sidecar row, so resume retries a non-terminal one and never a terminal one. A result is stored as the Environment Server returned it; the collector adds only its own _ng_* keys, so any Environment Server type can be collected without the collector knowing its result fields.

Every Environment Server type is scored the same way: through the result’s top-level reward, with optional top-level reward_components. A reward nested elsewhere in the result is stored as data, and a result without a top-level reward is unscored.

A failure’s failure_kind is kept under that name, next to the _ng_failure_* diagnostics: it is the key _record_rollout_outcome reads for the metric label and _counted_failure_row drops.

nemo_gym.rollouts.rollout_collection._episode_reply_violation(
response: typing.Any

The typed failure for a reply that is neither an episode result nor a failure.

It names what the reply held (its type and top-level keys, never values), so a producer that answers an episode request with another shape is found from the failure record alone.

nemo_gym.rollouts.rollout_collection._episode_request_body(
row: collections.abc.Mapping[str, typing.Any]
) -> dict[str, typing.Any]
nemo_gym.rollouts.rollout_collection._expand_input_glob(
input_glob: str
) -> typing.List[str]

Expand a glob-or-comma-separated-globs string into a sorted, deduplicated list of paths.

Examples:

'results/rollouts.jsonl' -> ['results/rollouts.jsonl'] (if it exists)
'a/*.jsonl, b/*.jsonl' -> matches of both patterns, deduplicated
nemo_gym.rollouts.rollout_collection._failure_compatibility_row(
verification_response: typing.Optional[typing.Dict] = None
) -> typing.Dict

Keep existing sidecar routing keys and diagnostics alongside the canonical failure.

Remove these aliases when row-oriented consumers and #3180 producers migrate. The canonical record never carries generation. The sidecar envelope retains actual judge input for existing —judge-failed-only readers, without a reward. Other legacy response placeholders are discarded.

nemo_gym.rollouts.rollout_collection._failure_diagnostics(
result: typing.Any
) -> typing.Dict

Preserve producer diagnostics outside the bounded canonical failure record.

nemo_gym.rollouts.rollout_collection._failure_export_metrics(
failures_fpaths: typing.List[pathlib.Path],
identity: typing.Callable[[Mapping[str, Any]], typing.Any],
landed: set,
histories: collections.abc.Sequence[nemo_gym.rollouts.rollout_store.RolloutStore] = ()
) -> typing.Dict[str, int]

Failure and retry counts for exporters, read from the failures sidecars.

The sidecars hold every failed attempt of the run, across resumes, so these are run totals rather than one job’s. identity keys a sidecar row the way landed keys the rollouts that have a row. coverage/failed/<class> counts the rollouts with no row, by the class of their last attempt. retries/attempts counts failed attempts, retries/rollouts_retried the rollouts dispatched more than once, and retries/at_cap the rollouts with no row that used all their attempts. Each rollout is held to the cap its collection recorded on its last attempt (_ng_failure_max_attempts), or the current cap for a row written before the cap was recorded. retries/max_attempts is that cap, and is left out when the rollouts were collected with different caps. A record_omitted_rollouts row is no failed attempt; an interrupted one is still the rollout’s latest execution, so an older failure’s class is not counted.

nemo_gym.rollouts.rollout_collection._failure_outcome(
row: typing.Dict,
failure: typing.Dict,
stage: str
nemo_gym.rollouts.rollout_collection._failure_rows_counted_as_zero(
failures_fpaths: typing.List[pathlib.Path],
failure_classes: typing.List[str],
scored_keys: set
) -> typing.List[typing.Dict[str, typing.Any]]

Sidecar rows the caller opted to count in the metrics denominator.

The last attempt of a rollout is the one that stands, so it is selected across every failure class before the wanted classes are picked out. Selecting the other way round would let a stale attempt be counted after a later one landed in a class the caller did not ask for.

A row that already carries a reward is counted as it stands. A row that carries none records that no rollout happened, so it is counted as a zero here and only here: the score enters the metric input, never the sidecar or the rollouts jsonl, which keeps the artifacts free of a verdict no verifier gave. A rollout that also succeeded is never counted. A row its producer marked with _ng_failure_counts_as_zero is counted whatever its class.

nemo_gym.rollouts.rollout_collection._fill_task_fields(
added_rows: typing.List[typing.Dict[str, typing.Any]],
real_rows: typing.List[typing.Dict[str, typing.Any]],
materialized_fpaths: typing.List[pathlib.Path],
group: typing.Callable[[Mapping[str, Any]], typing.Optional[str]]
) -> None

Give the rows the metric input adds, counted failures and imputed zeros, their task’s dataset fields.

Rows are ordered by repeat, so an added row can come first in its task, and metric hooks read task-level fields such as a subset label or a weight from a task’s first rollout. The fields come from the task’s materialized row, and only those that real rows of the same group carry: the aggregator averages every number it is handed, so a field no real row reports would become a metric of its own. A field the verifier computes is not in the materialized row, so the added row lacks it.

nemo_gym.rollouts.rollout_collection._final_zero_failure_rows(
failures_fpaths: typing.List[pathlib.Path],
scored_keys: set,
retry_terminal_timeouts: bool
) -> typing.List[typing.Dict[str, typing.Any]]

The latest failure rows that settle their rollout as a scored zero: final, and marked by their producer.

Resume does not run such a rollout again and the metrics count it as 0, so its work is done. A row counted only because count_failure_classes_as_zero names its class is not settled: that option scores the metrics, and resume may still run the rollout.

nemo_gym.rollouts.rollout_collection._identity_key(
row: collections.abc.Mapping[str, typing.Any],
group: typing.Callable[[Mapping[str, Any]], typing.Optional[str]]
) -> tuple

A rollout’s key across runs, which each number their tasks from 0.

nemo_gym.rollouts.rollout_collection._is_collector_key(
key: str
) -> bool

Keys rollout collection writes itself; an Environment Server result must not use them.

ng_trajectory is not one of them: it is the producer’s slot, where an Environment Server forwards the harness’s own turns from its session close (as an agent’s /run result does), and the collector replaces it with the canonical projection built from those turns.

nemo_gym.rollouts.rollout_collection._is_episode_response(
result: typing.Any
) -> bool

True for a BaseEpisodeResponse-shaped reply: object identities plus a result or failure key.

The collector only applies this to a row it dispatched as an episode request (_materialized_taskset(row)), so an agent’s verify response that echoes identity fields is left alone.

nemo_gym.rollouts.rollout_collection._judge_failure_response(
result: typing.Any
) -> typing.Optional[typing.Dict]

Legacy judge_failsafe carries real generation that can be judged again.

nemo_gym.rollouts.rollout_collection._latest_failure_rows(
failures_fpaths: typing.List[pathlib.Path]
) -> typing.Dict[typing.Tuple[typing.Any, typing.Any], typing.Dict[str, typing.Any]]

The last failed attempt recorded for each rollout across the failures sidecars.

An interrupted attempt that record_omitted_rollouts recorded is the rollout’s latest execution but no failure: it hides any older failure, so the rollout is left out here and is missing. A row the dispatch budget never started, and the evidence of a failed /run with routing off, are skipped (is_non_superseding_rollout_row).

nemo_gym.rollouts.rollout_collection._masking_step_metrics(
agent_name: str,
scored: collections.Counter,
dropped: collections.Counter
) -> typing.Dict[str, float]

In-progress view of what a run is losing to its environment rather than its policy.

scored covers persisted rollouts only, split into the unmasked ones (count, reward) and the masked ones; dropped counts what never reached the main output at all. reward_unmasked averages over the unmasked rollouts alone, so the gap against the existing reward series is the score lost to infrastructure. Failed and omitted attempts are reported as counts, never folded into a quality average.

Empty until something is actually masked or dropped, so a healthy run exports exactly what it exported before. The final numbers come from /aggregate_metrics; this is the progress view while the run is still going.

nemo_gym.rollouts.rollout_collection._matches_failure_class(
row: collections.abc.Mapping[str, typing.Any],
failure_classes: collections.abc.Collection[str]
) -> bool

Match the canonical class or the original legacy producer’s routing class.

nemo_gym.rollouts.rollout_collection._materialized_taskset(
row: collections.abc.Mapping[str, typing.Any]
) -> str | None
nemo_gym.rollouts.rollout_collection._metric_failure_kind(
failure_kind: typing.Any
) -> typing.Optional[str]

The kind as a bounded label: registered or namespaced names pass, anything else is one bucket.

nemo_gym.rollouts.rollout_collection._metrics_group(
row: collections.abc.Mapping[str, typing.Any],
servers_by_agent: typing.Callable[[], collections.abc.Mapping[str, list[str]]]
) -> typing.Optional[str]

The environment server a rollout is scored under, as _call_aggregate_metrics groups it.

The row’s stamp, else the one server that fronts its agent, looked up only for an unstamped row: a materialized row routed by its agent has no stamp while its result has one, and both must land in the same group. Runs of one agent behind two servers stay apart this way. An agent behind no server or several stays its own group; _call_aggregate_metrics rejects such a row.

nemo_gym.rollouts.rollout_collection._missing_rollout_rows_counted_as_zero(
materialized_fpaths: typing.List[pathlib.Path],
failures_fpaths: typing.List[pathlib.Path],
scored_keys: set,
history: typing.Optional[nemo_gym.rollouts.rollout_store.RolloutStore] = None
) -> typing.List[typing.Dict[str, typing.Any]]

Materialized rollouts that produced no row anywhere, counted as zeros.

The failure classes reach a rollout that failed and said so. This reaches the one that never got that far — killed mid-flight, or dispatched and lost — which leaves nothing in the rollouts jsonl and nothing in the sidecar. Without it such a rollout leaves the denominator as well as the numerator, so the score reads higher the more of the run went missing.

The sidecar is read here rather than trusted from the caller. A failure whose class the caller left out of count_failure_classes_as_zero is absent from the scored keys, and counting it here would score the very rollouts that selection excluded — silently turning the selection into a no-op.

The zero carries the rollout’s identity: its agent, and its environment server stamp when the row has one, which a materialized taskset row needs because it names no agent. _fill_task_fields adds the task’s dataset fields. A row that names neither cannot reach any server’s metrics, so it is warned about rather than counted. The score enters the metric input and nothing else, the same way a counted failure row does.

nemo_gym.rollouts.rollout_collection._names_its_task(
row: dict[str, typing.Any]
) -> bool
nemo_gym.rollouts.rollout_collection._native_episode_record(
row: typing.Dict,
response: typing.Any
) -> typing.Dict

Validate the dispatched episode identity before translating its outcome.

nemo_gym.rollouts.rollout_collection._normalize_health_check_ignored_checks(
value
) -> typing.List[str]
nemo_gym.rollouts.rollout_collection._normalize_rollout_outcome(
row: typing.Dict,
result: typing.Any
nemo_gym.rollouts.rollout_collection._print_on_sigterm(
render: typing.Callable[[], str]
) -> typing.Any

Print render() when Slurm’s time limit sends SIGTERM, then terminate as before.

Python’s default SIGTERM action exits without unwinding, so nothing printed in a finally survives a time-limit kill. Returns the previous handler for _restore_sigterm, or _NO_SIGTERM_HOOK when no hook could be installed.

nemo_gym.rollouts.rollout_collection._protocol_violation_stop(
server: str,
answered: int

The end of a run whose environment server has answered every request so far with a reply the collector cannot use: the producer is wrong, and no attempt can change that.

nemo_gym.rollouts.rollout_collection._quota_exhausted_stop(
failures: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]

The end of a run whose grading provider’s quota is exhausted: nothing can be graded until it resets.

nemo_gym.rollouts.rollout_collection._raise_for_aggregation_errors(
metrics_fpath: typing.Optional[pathlib.Path]
) -> None

Signal failure after partial metrics and any batch status have been saved.

nemo_gym.rollouts.rollout_collection._read_jsonl(
path: pathlib.Path
) -> typing.List[typing.Dict]
async

Parse a whole JSONL artifact, letting other tasks on the event loop run between rows.

Parsing stays on the event loop thread instead of a worker thread. The loop thread then reuses the memory it freed during collection for these rows. A worker thread allocates from its own malloc arena, so the process would hold both.

nemo_gym.rollouts.rollout_collection._record_policy_model_server(
result: dict[str, typing.Any],
global_config: typing.Any,
agent_name: str | None
) -> None

Name the agent’s configured policy server on the record (landed or failed), so offline timing needs no live config and a capture joined later from the capture dir is still partitioned by role.

nemo_gym.rollouts.rollout_collection._record_rollout_health(
result: typing.Dict[str, typing.Any],
outcome: str,
ignored_checks: frozenset[str],
dispatch_span_context: typing.Optional[opentelemetry.trace.SpanContext] = None
) -> None

Evaluate the trajectory health checks on a finished rollout and count the verdict and flagged checks.

With a dispatch_span_context, the verdict and the flagged checks also go on a gym.rollout.health span under that dispatch span. Gated on telemetry only, not on the post-run report switch. Never raises: telemetry must not fail a rollout.

nemo_gym.rollouts.rollout_collection._record_rollout_outcome(
result: typing.Dict[str, typing.Any],
outcome: str,
dispatch_name: str
) -> None

Count a persisted attempt, including its numeric reward when scored.

nemo_gym.rollouts.rollout_collection._record_rollout_shape(
row: collections.abc.Mapping[str, typing.Any],
result: collections.abc.Mapping[str, typing.Any]
) -> None

Record the size of one completed rollout, while metrics are exporting.

Turns and tool calls come from the rollout’s ng_perf when rollout observability produced it. Without it, tool calls are counted from the final response’s function_call items, and turns are not recorded.

nemo_gym.rollouts.rollout_collection._reflect_enrichment(
result: typing.Any,
record: typing.Dict[str, typing.Any]
) -> None

Add a stored record’s enrichment and identity keys to the reply run_examples returns in its own shape.

nemo_gym.rollouts.rollout_collection._refresh_shard_status_aggregation(
input_paths: typing.List[str],
aggregate_metrics_fpath: typing.Optional[pathlib.Path]
) -> None

Mark each shard’s run status with the outcome of the aggregation that merged it, keeping its counts.

EvalRDL sums the shards’ status files, so the merged output gets no status file of its own.

nemo_gym.rollouts.rollout_collection._reject_attempt_qualified_rollout_ids(
rows: collections.abc.Iterable[collections.abc.Mapping[str, typing.Any]],
fpath: pathlib.Path
) -> None

Refuse dataset rows whose explicit rollout ID names an attempt.

The suffix -a<N> is reserved: "<id>-a<N>" always means attempt N of rollout <id>, which is how a training controller names a restored attempt. A resume retry stamps the next attempt on a row, and an ID that already names one would then fail mid-run, so the row is refused when the input loads.

nemo_gym.rollouts.rollout_collection._reply_failure_kind(
headers: typing.Any
) -> typing.Optional[str]

The kind of the outermost failure in the chain an agent’s failed reply selected that is not a routing kind.

None without a report, with an omitted or broken chain, or when every failure on it only routes.

nemo_gym.rollouts.rollout_collection._reply_failure_report(
response: collections.abc.Mapping[str, typing.Any]

The FailureReport an environment reply carries beside its outcome; an invalid one is omitted.

nemo_gym.rollouts.rollout_collection._restore_sigterm(
previous: typing.Any
) -> None
nemo_gym.rollouts.rollout_collection._rollout_order_key(
row: typing.Dict[str, typing.Any]
) -> tuple

Task then repeat: metrics that read a task’s repeats positionally need that order.

nemo_gym.rollouts.rollout_collection._rollout_request_debug_summary(
row: typing.Dict[str, typing.Any]
) -> typing.Dict[str, typing.Any]
nemo_gym.rollouts.rollout_collection._round_robin_by_agent(
examples: typing.List[typing.Dict]
) -> typing.List[typing.Dict]

Interleave resolved rows by environment server or agent, preserving each input order.

Agent order is the order in which each name first appears. Rows are returned unchanged, so task/rollout indexes, repeat seeds, and the identities used by resume remain intact.

nemo_gym.rollouts.rollout_collection._routing_identity(
row: collections.abc.Mapping[str, typing.Any]
) -> typing.Optional[str]

The agent a rollout ran on, or for a materialized taskset row, which names none, its environment server.

A materialized row, its result and its sidecar row all name the same one.

nemo_gym.rollouts.rollout_collection._rows_of_first_tasks(
numbered_rows: collections.abc.Iterable[tuple[int, str]],
limit: int
) -> typing.Iterator[tuple[int, str]]

Yield the rows of the first limit tasks. Identical rows are one task, as in the task index.

nemo_gym.rollouts.rollout_collection._sample_server_queues(
base_urls: typing.List[str],
interval_s: float
) -> None
async

Poll every vLLM server’s /metrics and record requests waiting and running, summed over servers.

nemo_gym.rollouts.rollout_collection._sanitize_legacy_result(
result: typing.Dict
) -> None

Discard collector bookkeeping while preserving declared legacy evidence.

nemo_gym.rollouts.rollout_collection._shard_record(
run_id: str,
global_config: typing.Any,
agent_name: str | None
) -> typing.Dict[str, typing.Any]

The record ng_collect_rollouts would store for completed, for a run_examples call recording a shard.

A try that left no result (interrupted, or never started) is a marker, not an outcome: it keeps its identity and the writer turns it into an omitted-rollout row. Anything else goes through _collected_outcome, so a failed /run is saved as the typed failure row collection saves, never as the marker the dispatcher returned. Every record names the shard’s run, as collection stamps its own, so the Store checks it against the shard’s manifest.

nemo_gym.rollouts.rollout_collection._shard_rollout_id(
row: collections.abc.Mapping[str, typing.Any],
run_id: str
) -> str

The rollout id a recorded shard dispatches row under: the row’s own id, prefixed with the shard’s run id.

Model calls are captured under the capture key, which is this id with the attempt suffix, and capture files are kept by default. Without the prefix, two shards that dispatch the same task and rollout (a returned row fed back, or indices numbered again each step) share a key, and the later shard’s records carry the earlier shard’s calls. A row an earlier shard returned carries that shard’s prefix, which is replaced rather than nested.

nemo_gym.rollouts.rollout_collection._span_task_id(
row: collections.abc.Mapping[str, typing.Any]
) -> typing.Optional[str]
nemo_gym.rollouts.rollout_collection._stamp_collector_fields(
result: dict[str, typing.Any]
) -> None

Stamp the row’s identity and routing fields onto the record collection stores, as every reader expects.

nemo_gym.rollouts.rollout_collection._status_failure_kind(
row: collections.abc.Mapping[str, typing.Any]
) -> typing.Optional[str]

The failure kind a sidecar row carries: top-level, the legacy diagnostic key, or the typed record’s.

nemo_gym.rollouts.rollout_collection._sum_vllm_queue(
metrics_text: str
) -> typing.Tuple[float, float]
nemo_gym.rollouts.rollout_collection._task_data_provenance(
row: collections.abc.Mapping[str, typing.Any]
) -> typing.Dict[str, typing.Any]

The PROVENANCE_KEYS of a materialized row’s task_data: provenance stamps for the record.

Preparation writes them (a Harbor row carries the task folder digest as _ng_digest and the dataset digest as _ng_dataset_digest) so that every results row names the inputs it ran, without the materialized-inputs sidecar. An Environment Server never returns them (_ng_* is the collector’s namespace), so the collector copies them from the row onto the record. Only the allowlisted keys are copied: task_data comes from the dataset, and the collector reads other _ng_* keys (_ng_no_persist, _ng_failure_class, _ng_result_type, …) that a success record does not carry, so a dataset could otherwise drop, reroute or relabel its own results.

nemo_gym.rollouts.rollout_collection._truncated_body(
body: typing.Optional[bytes]
) -> typing.Optional[str]

Decode at most the kept prefix, so a huge error page is never decoded in full.

nemo_gym.rollouts.rollout_collection.enrich_run_result(
row: dict[str, typing.Any],
result: dict[str, typing.Any],
capture_dirs: list[pathlib.Path],
observability_enabled: bool,
include_payloads: bool = True,
rollout_latency_ms: typing.Optional[float] = None,
delete_capture: bool = False
) -> dict[str, typing.Any]
async

Attach a finished rollout’s collected evidence to its /run result, in place.

These are the per-rollout steps ng_collect_rollouts runs, shared so a framework that dispatches through run_examples records the same thing: wait for the model server’s in-flight capture writes for this rollout, merge its captured model calls (ng_model_call_capture) and join the agent’s observations to them, project the standardized ng_trajectory, and assemble ng_perf when observability is enabled.

The row’s rollout identity is copied onto the result where the result lacks it, because the capture key is read from the record. Harness output and reward are never modified. A row that names no task (no task id field, task index or trajectory identity) gets no ng_trajectory rather than a guessed task id. include_payloads=False keeps call metadata only; delete_capture removes the rollout’s capture file once it has been merged, so it requires the payloads to be kept.

nemo_gym.rollouts.rollout_collection.is_non_superseding_rollout_row(
row: collections.abc.Mapping[str, typing.Any]
) -> bool

Whether readers skip a sidecar row before they pick a rollout’s latest attempt.

A row never started is no execution. A failed /run kept as evidence with routing off is no new outcome: the attempt it records stands no more than before it was kept, so an older failure still stands and a later attempt still replaces it. An interrupted record_omitted_rollouts row is neither and still hides older failures.

nemo_gym.rollouts.rollout_collection.is_omitted_rollout_row(
row: collections.abc.Mapping[str, typing.Any]
) -> bool

Whether a failures-sidecar row is a record_omitted_rollouts record of a rollout that produced no result.

nemo_gym.rollouts.rollout_collection.is_unstarted_rollout_row(
row: collections.abc.Mapping[str, typing.Any]
) -> bool

Whether a sidecar row records a rollout the dispatch budget never started: no execution, so no history.

nemo_gym.rollouts.rollout_collection.loads_jsonl_line(
raw,
fpath,
line_no: int
)

Parse one JSONL line, raising a clean ConfigError (naming file + line) on malformed JSON.

nemo_gym.rollouts.rollout_collection.AGENT_REQUEST_FAILED_FAILURE_CLASS = 'agent_request_failed'
nemo_gym.rollouts.rollout_collection.AGENT_RUN_ERROR_FAILURE_CLASS = 'agent_run_error'
nemo_gym.rollouts.rollout_collection.ENVIRONMENT_SERVER_FAILURE_CLASS = ENVIRONMENT_SERVER_FAILED
nemo_gym.rollouts.rollout_collection.NG_DATASET_DIGEST_KEY = '_ng_dataset_digest'
nemo_gym.rollouts.rollout_collection.NG_DIGEST_KEY = '_ng_digest'
nemo_gym.rollouts.rollout_collection.NG_ELAPSED_KEY = 'elapsed_seconds'
nemo_gym.rollouts.rollout_collection.NG_ENVIRONMENT_SERVER_KEY = ENVIRONMENT_SERVER_STAMP_KEY_NAME
nemo_gym.rollouts.rollout_collection.NG_FAILURE_COUNTS_AS_ZERO_KEY = '_ng_failure_counts_as_zero'
nemo_gym.rollouts.rollout_collection.NG_FAILURE_JUDGE_ERROR_KEY = '_ng_failure_judge_error'
nemo_gym.rollouts.rollout_collection.NG_FAILURE_LEGACY_CLASS_KEY = '_ng_failure_legacy_class'
nemo_gym.rollouts.rollout_collection.NG_FAILURE_MAX_ATTEMPTS_KEY = '_ng_failure_max_attempts'
nemo_gym.rollouts.rollout_collection.NG_FAILURE_REPORT_KEYS = ('_ng_failure_events', '_ng_failure_id', '_ng_failure_events_omitted')
nemo_gym.rollouts.rollout_collection.NG_OMITTED_ROLLOUT_KEY = '_ng_omitted_rollout'
nemo_gym.rollouts.rollout_collection.NG_POLICY_MODEL_SERVER_KEY = 'ng_policy_model_server'
nemo_gym.rollouts.rollout_collection.NG_RESULT_TYPE_KEY = '_ng_result_type'
nemo_gym.rollouts.rollout_collection.NG_TASK_ID_KEY = '_ng_task_id'
nemo_gym.rollouts.rollout_collection.NG_TERMINAL_KEY = '_ng_failure_terminal'
nemo_gym.rollouts.rollout_collection.NG_UNROUTED_RUN_ERROR_KEY = '_ng_unrouted_run_error'
nemo_gym.rollouts.rollout_collection.PROVENANCE_KEYS = (NG_DIGEST_KEY, NG_DATASET_DIGEST_KEY)
nemo_gym.rollouts.rollout_collection.ROLLOUT_REPEAT_ATTRIBUTE = 'nemo.gym.rollout.repeat'
nemo_gym.rollouts.rollout_collection.STATUS_FAILURE_KIND_KEY = 'failure_kind'
nemo_gym.rollouts.rollout_collection.STATUS_MODEL_FINAL_KEY = '_ng_model_final'
nemo_gym.rollouts.rollout_collection.TASK_ID_ATTRIBUTE = 'nemo.gym.task.id'
nemo_gym.rollouts.rollout_collection._ENRICHMENT_KEYS = ('ng_model_call_capture', NG_TRAJECTORY_KEY, NG_PERF_KEY)
nemo_gym.rollouts.rollout_collection._LEGACY_RESULT_FIELDS = frozenset({NG_FAILURE_CLASS_KEY, NG_NO_PERSIST_KEY, NG_TERMINAL_KEY, '_ng_failur...
nemo_gym.rollouts.rollout_collection._MAX_FAILURE_BODY_CHARS = 2000
nemo_gym.rollouts.rollout_collection._NO_RESULT_FAILURE_CLASSES = frozenset({AGENT_REQUEST_FAILED_FAILURE_CLASS, AGENT_RUN_ERROR_FAILURE_CLASS, EN...
nemo_gym.rollouts.rollout_collection._NO_SIGTERM_HOOK = object()
nemo_gym.rollouts.rollout_collection._OWNED_JOB_SPAN_CONTEXT: ContextVar[Optional[SpanContext]] = ContextVar('nemo_gym_owned_job_span_context', default=None)
nemo_gym.rollouts.rollout_collection._READ_JSONL_YIELD_INTERVAL_S = 0.01
nemo_gym.rollouts.rollout_collection._RESERVED_SHARD_ENDINGS = ('_failures', '_materialized_inputs', '_attempts')
nemo_gym.rollouts.rollout_collection._ROUTING_FAILURE_KINDS = frozenset({AGENT_ROUTE_FAILED, COLLECTION_DISPATCH_FAILED, AGENT_RUN_ERROR_FAILU...
nemo_gym.rollouts.rollout_collection._RUN_FAILURE_ERRORS = (ClientError, orjson.JSONDecodeError, TimeoutError)
nemo_gym.rollouts.rollout_collection._SERVER_DID_NOT_RUN_STATUSES = frozenset({429, 502, 503, 504})
nemo_gym.rollouts.rollout_collection._SHARD_IDENTITY_KEYS = (ROLLOUT_ID_KEY_NAME, TASK_INDEX_KEY_NAME, ROLLOUT_INDEX_KEY_NAME, ATTEMPT_INDEX...
nemo_gym.rollouts.rollout_collection._SHARD_LABEL = re.compile('[A-Za-z0-9][A-Za-z0-9_.-]*')
nemo_gym.rollouts.rollout_collection._failures_path_for = failures_path_for
nemo_gym.rollouts.rollout_collection._moved_cli_entry_points = moved_attr_getter(__name__, {'collect_rollouts': 'nemo_gym.cli.eval', 'aggregate...
nemo_gym.rollouts.rollout_collection._moved_names = moved_names_getattr(__name__)
nemo_gym.rollouts.rollout_collection.get_max_rollout_attempts = _get_max_rollout_attempts
nemo_gym.rollouts.rollout_collection.logger = logging.getLogger(__name__)