nemo_gym.task_data

View as Markdown

Per-server task-data schemas.

A resources server ships a task_data.py module next to its app.py exporting a single symbol TaskData: either a Pydantic BaseModel subclass or a type (e.g. an Annotated[Union[...], Field(discriminator=...)] alias) accepted by pydantic.TypeAdapter. A self-contained agent (one that declares datasets but no resources_server reference) ships the same module under responses_api_agents/<implementation>/ and owns its rows’ schema; an agent WITH a reference uses that resources server’s schema instead. It describes the task-owned fields of that server’s dataset rows, written FLAT in the planned end-state shape: the fields as they will appear inside the unified task_data row key after the row-format migration. Framework-owned keys (see RESERVED_ROW_KEYS) are never part of TaskData, and neither is a verifier_metadata wrapper: rows that still carry one have its contents spliced up by normalize_task_fields before validation, so one flat schema validates both today’s rows and post-migration task_data contents. Fields that today’s wire reads EXCLUSIVELY from inside verifier_metadata should be annotated Field(..., json_schema_extra={"legacy_location": "verifier_metadata"}) — that reverse map is what the row-format migration and the dispatch compatibility shim consume, and validation flags rows that carry such a field only top-level (the server would not see it). Servers whose wire accepts both placements (e.g. via a before-validator that nests top-level fields itself) must not carry the marker.

This module is a dependency-light leaf: it may import only the standard library and Pydantic, and per-server task_data.py modules may import only the standard library, Pydantic, this module, and other servers’ task_data modules. That keeps schemas loadable by data tooling (collate, gym env schema, dataset import) without installing any server’s requirements.

Conventions for TaskData models:

  • model_config = ConfigDict(extra="allow") by default. extra="forbid" is opt-in for servers that are already fail-closed. Pydantic’s default extra="ignore" is banned: silently dropping row fields is the existing bug class this system exists to catch.
  • Required-ness mirrors the server’s wire contract (its verify/run request models), not what verify() happens to read. A field the wire requires stays required even if unread.
  • Fields may carry json_schema_extra={"consumed_by": [...]} with values from {"verify", "metrics", "prompt", "provenance"}. These tags are purely informational: they document what reads a field for humans inspecting gym env schema output, and no tooling consumes them. Fields that are JSON-encoded strings on the wire stay typed str.

Module Contents

Classes

NameDescription
TaskDataSchemaErrorA server’s task_data.py exists but does not satisfy the protocol.
TaskDataValidationReportAccumulated validation outcome for one dataset file against one server’s schema.
TaskDataValidatorValidates dataset rows against a server’s TaskData schema, accumulating a report.

Functions

NameDescription
find_server_dirLocate <base_folder>/<server_name> via the shared component search roots.
legacy_metadata_fieldsSchema fields annotated legacy_location: verifier_metadata (today’s wire reads them there).
load_task_data_schemaLoad <server_dir>/task_data.py and return a TypeAdapter for its TaskData.
normalize_task_fieldsThe task-owned subset of a dataset row, normalized to the flat end-state shape.
validate_jsonl_rowsValidate an iterable of JSONL lines against one schema; entry point for whole-file validation.

Data

LEGACY_METADATA_KEY

RESERVED_ROW_KEYS

TASK_DATA_EXPORT_NAME

TASK_DATA_MODULE_NAME

TASK_DATA_ROW_KEY

API

class nemo_gym.task_data.TaskDataSchemaError()
Exception

Bases: Exception

A server’s task_data.py exists but does not satisfy the protocol.

class nemo_gym.task_data.TaskDataValidationReport(
server_name: str,
dataset_fpath: str,
rows: int = 0,
error_rows: int = 0,
errors: typing.List[str] = list(),
unknown_keys: typing.Dict[str, int] = dict(),
conflicting_keys: typing.Dict[str, int] = dict(),
misplaced_keys: typing.Dict[str, int] = dict()
)
Dataclass

Accumulated validation outcome for one dataset file against one server’s schema.

MAX_RECORDED_ERRORS
= 5
clean
bool
conflicting_keys
Dict[str, int] = field(default_factory=dict)
dataset_fpath
str
error_rows
int = 0
errors
List[str] = field(default_factory=list)
misplaced_keys
Dict[str, int] = field(default_factory=dict)
rows
int = 0
server_name
str
unknown_keys
Dict[str, int] = field(default_factory=dict)
nemo_gym.task_data.TaskDataValidationReport.summary() -> str
class nemo_gym.task_data.TaskDataValidator(
server_name: str,
adapter: pydantic.TypeAdapter,
dataset_fpath: str
)

Validates dataset rows against a server’s TaskData schema, accumulating a report.

_legacy_fields
= legacy_metadata_fields(adapter)
report
nemo_gym.task_data.TaskDataValidator.validate_row(
row_index: int,
row: typing.Dict[str, typing.Any]
) -> None
nemo_gym.task_data.find_server_dir(
server_name: str,
base_folder: str = 'resources_servers'
) -> typing.Optional[pathlib.Path]

Locate <base_folder>/<server_name> via the shared component search roots.

Resolves against _resolve_under_cwd_or_install (extra plugin roots first, then cwd, then the Gym install root), without the CLI’s venv-marker requirement (a schema can exist for a server whose venv was never set up). Self-contained agents (which verify in-process) keep their schemas under responses_api_agents/<name>/.

nemo_gym.task_data.legacy_metadata_fields(
adapter: pydantic.TypeAdapter
) -> frozenset

Schema fields annotated legacy_location: verifier_metadata (today’s wire reads them there).

nemo_gym.task_data.load_task_data_schema(
server_dir: pathlib.Path
) -> typing.Optional[pydantic.TypeAdapter]

Load <server_dir>/task_data.py and return a TypeAdapter for its TaskData.

Returns None when the module does not exist (the server has not adopted schemas yet). Raises TaskDataSchemaError when the module exists but cannot be imported or does not export a usable TaskData.

nemo_gym.task_data.normalize_task_fields(
row: typing.Dict[str, typing.Any]
) -> tuple[typing.Dict[str, typing.Any], typing.List[str]]

The task-owned subset of a dataset row, normalized to the flat end-state shape.

Drops framework keys, then splices the contents of a legacy verifier_metadata dict and of a migrated task_data dict up to the top level (schemas are written flat, so fields validate the same whether a row is flat, legacy-nested, or migrated). A key present in two places with the same value is a harmless duplicate; with different values it is ambiguous data and gets reported. Returns (fields, conflicts).

nemo_gym.task_data.validate_jsonl_rows(
server_name: str,
adapter: pydantic.TypeAdapter,
dataset_fpath: str,
lines: typing.Iterable[str]
) -> nemo_gym.task_data.TaskDataValidationReport

Validate an iterable of JSONL lines against one schema; entry point for whole-file validation.

nemo_gym.task_data.LEGACY_METADATA_KEY = 'verifier_metadata'
nemo_gym.task_data.RESERVED_ROW_KEYS = frozenset({'responses_create_params', 'agent_ref', 'task_source', '_ng_task_inde...
nemo_gym.task_data.TASK_DATA_EXPORT_NAME = 'TaskData'
nemo_gym.task_data.TASK_DATA_MODULE_NAME = 'task_data'
nemo_gym.task_data.TASK_DATA_ROW_KEY = 'task_data'