Skip to content

Add EnterpriseOps-Gym benchmark: resources server, benchmark registration, and per-turn telemetry agent - #2142

Open
mcuevas-nvidia wants to merge 37 commits into
mainfrom
mcuevas-nvidia-bench-integration-enterpriseops-signed
Open

mcuevas-nvidia wants to merge 37 commits into
mainfrom
mcuevas-nvidia-bench-integration-enterpriseops-signed

Conversation

@mcuevas-nvidia

Copy link
Copy Markdown

Summary

This PR integrates ServiceNow's EnterpriseOps-Gym (EOG) into NeMo Gym: a 649-task benchmark of stateful, multi-step enterprise tool use across 8 domains (calendar, CSM, drive, email, HR, ITSM, teams, and cross-domain hybrid), where an agent operates 512 tools against live MCP servers backed by SQL databases and is scored on final database state. The integration is eval-complete and RL-ready (token-ID capture, fractional reward mode, and a validated GRPO rollout-collection recipe), with no changes to NeMo Gym core.

What's included (46 files)

Component Path What it does
Resources server resources_servers/enterpriseops_gym/ Seeds a per-session database on the external EOG MCP containers, proxies tool calls (catch-all /{tool_name} route, pooled aiohttp, per-session x-database-id), runs verifiers concurrently, cleans up idempotently (TTL janitor + delete-on-verify). Supports replica pools (gym_url_pools), per-domain metrics, per-tool latency capture, and a strict_verifiers fractional-reward mode for RL.
Verifier engine .../verifier_engine.py Line-for-line port of EOG's scoring semantics, pinned by golden fixtures generated from the original implementation (33 cases, byte-identical).
Task converter .../convert_tasks.py + benchmarks/enterpriseops/ Converts the public HF dataset (ServiceNow-AI/EnterpriseOps-Gym) to Responses-API task rows at prepare.py time; benchmark registered with prompt_config: null (pre-baked rows). Dataset files are not committed.
Per-turn telemetry agent responses_api_agents/turn_logging_agent/ SimpleAgent subclass with an identical loop that records per-turn timestamps, durations, input/output/cached/reasoning tokens, and tool names, attaching turns to the verify response. Generic — not EOG-specific.
Tests 44 total (42 + 2) Fully offline: a sqlite-backed stub MCP gym (tests/stub_gym.py) plus golden parity fixtures. No containers or network needed to run CI.
Docs PARITY.md, PERF.md, RLPILOT.md Full parity evidence, throughput study, and RL rollout-collection pilot (methodology + measured numbers below).

Verification logic

Each task carries verifier_metadata with a list of verifiers. database_state verifiers
run a SQL query against the session's final database state (via the gym containers'
/api/sql-runner), extract a value, and compare it to the expected value using EOG's
comparison semantics; response_check verifiers score the agent's final message with an
LLM judge (defaults to the policy model, temperature pinned to 0.0, matching EOG). The
public oracle split is 100% database_state (3,496/3,496 verifiers), so scoring there is
fully deterministic given a final DB state. Reward = 1.0 iff all (name-collapsed) verifiers
pass, matching the upstream leaderboard; strict_verifiers: true switches to
every-verifier-counts and a fractional strict_pass_rate for RL shaping.

Scoring fidelity (PARITY.md)

The port is validated bug-for-bug against the upstream harness, preserving its quirks (verifier name-collapse, unknown-gym skips, loose comparison semantics) for leaderboard comparability:

  • Unit level: golden fixtures generated by running the original EOG engine — byte-identical extraction/comparison behavior.
  • Task level: 12/12 identical outcomes and verifier structures on live containers.
  • Full split (649 tasks): port 16.4% vs native 16.8% macro (gpt-4.1-mini, temp 0); per-task agreement 90.4%, disagreements symmetric (McNemar exact p = 0.90).
  • k=5 × both harnesses (6,480 rollouts): Δ −0.23 ± 0.7 pp, per-task preference exactly 67:67.
  • Cross-stack replication (k=5 on dedicated vLLM, Nemotron 3 Nano): formally equivalent within ±2 pp (TOST, α = 0.05).

Performance (PERF.md)

Scale-tested end-to-end at five client concurrencies (c = 8, 16, 32, 64, 128) with a full
649-task pass per level per harness (10 passes, 4×H100 vLLM, identical endpoint): the port
completed 649/649 tasks at every level with zero retries, with success rates flat
across levels. At matched concurrency the port is 1.14–1.71× faster (largest at low
concurrency, nearest the native harness's documented defaults). The gap narrows by design:
both harnesses converge toward the same GPU throughput floor — and reaching it is the key
result. The port saturates the hardware at c=64; the native harness never reaches the
floor in the tested range and needs ~4× the client concurrency for equal throughput.

Net cost: a full-split eval is 1h27m of 4×H100 time (port) vs 4h40m at native's documented
settings — 3.2× GPU-hours. Mechanism: pooled connections, persistent MCP sessions, and
concurrent verifiers keep vLLM's continuous batch fed. (Since the gap is client dead time
relative to GPU service time, it is expected to widen on faster serving hardware, where
saturation demands even more effective concurrency.)

RL readiness (RLPILOT.md)

A config-only pilot (zero code changes) validated GRPO rollout collection end-to-end: 100% token-ID/logprob coverage via return_token_id_information, 15/20 task groups with mixed binary reward at k=8 (mean within-group std 0.341) on a curriculum selected from repeat-run data, plus a measured deployment-sizing guide (sequence-length distribution, memory budget, recommended node shapes).

How to run

# Start the stack (external EOG MCP containers must be running; see resources server README)
ng_run "+config_paths=[resources_servers/enterpriseops_gym/configs/enterpriseops_gym.yaml,responses_api_models/openai_model/configs/openai_model.yaml]" \
  "++enterpriseops_gym.resources_servers.enterpriseops_gym.seed_sql_root=/path/to/EnterpriseOps-Gym"

# Prepare the benchmark data (downloads the public HF dataset) and collect
ng_prepare_benchmark +benchmark_name=enterpriseops
ng_collect_rollouts +agent_name=enterpriseops_gym_simple_agent \
  +input_jsonl_fpath=benchmarks/enterpriseops/data/enterpriseops_oracle_benchmark.jsonl \
  +output_jsonl_fpath=results/enterpriseops.jsonl \
  +responses_create_params.temperature=0.0 +responses_create_params.max_output_tokens=16384

# Tests (offline, no containers needed)
gym env test --resources-server enterpriseops_gym
ng_test +entrypoint=responses_api_agents/turn_logging_agent

Validation on this exact branch state

  • 42/42 + 2/2 tests green after rebase onto current main
  • ruff check + ruff format --check clean; README environment table regenerated via scripts/update_env_list.py
  • Config stack boots via ng_run dry run
  • Live smoke on real MCP containers + gateway model: 5/5 rollouts completed across both agents, all verifiers scored, turn telemetry attached
  • All commits DCO signed-off

Contribution-guide compliance

Mapped to the environment /
benchmark guides:

  • Required files — all present: app.py, configs/*.yaml (valid domain: agent),
    tests/test_app.py (42 tests), data/example.jsonl (5 tasks),
    data/example_rollouts.jsonl (5 pre-generated rollouts against live containers; note
    these samples are CSM-domain, the benchmark's hardest — near-zero rewards on them are
    expected and consistent with the full-split CSM rate of ~4%), requirements.txt,
    README.md with licensing information.
  • Reward profiling — run on a closed model (gpt-4.1-mini: 16.4% macro) and an open
    thinking model (Nemotron 3 Nano, reasoning on: 22–25%), i.e. the instruct+thinking
    mixture the guide asks for. Scores sit inside the official leaderboard's published range
    (Qwen3-4B 13.6% … GPT-5-Mini 22.0%) with a coherent domain pattern (email easiest, CSM
    hardest, matching the leaderboard). This benchmark is legitimately hard — no public model
    reaches 30%.
  • Variance — k=5 repeat runs on both stacks; mean@5 resolves ±0.7 pp (< 1% as required).
    Calibration guidance for users is included in PARITY.md.
  • Failure-case analysis — performed extensively across parity, perf, and RL-pilot runs
    (documented in the three reports).
  • Original-repo reproduction — instead of reproducing a leaderboard model's published
    number (leaderboard models weren't available on our serving), we ran the original EOG
    harness side-by-side
    on identical models, containers, and endpoints: per-task agreement
    with symmetric disagreements (McNemar p = 0.90) and formal TOST equivalence within ±2 pp.
    This isolates harness fidelity even more directly; happy to additionally run a listed
    leaderboard model if reviewers want the published-number check.
  • Stacked PRs — per the development-setup guide, happy to restack this as layers
    (resources server + tests → benchmark registration → turn-logging agent → reports) if
    reviewers prefer; presented as one PR first since the layers are tightly coupled by the
    parity evidence.

Design decisions & notes for reviewers

  • Hand-rolled MCP client instead of the official SDK (rationale in mcp_client.py docstring): the SDK's transport is httpx-based (banned for async here), EOG needs session-level and per-call x-database-id headers, and half the surface is non-MCP REST (/api/seed-database etc.).
  • Upstream EOG quirks intentionally preserved and documented (PARITY.md §1) rather than fixed, to keep leaderboard comparability; strict_verifiers: true opts into every-verifier-counts scoring for RL.
  • turn_logging_agent is separable — it's a general-purpose agent; happy to split it into its own PR if preferred.
  • verified: false per convention for new resources servers.
  • External dependency: the benchmark requires the EOG Docker containers (from the upstream EOG repo) at eval time; unit tests do not.
  • Operational findings that affect large runs (MCP container fd leak ~5/task, upstream runner's silent task drops) are documented in PARITY.md §6; we plan to file these upstream against EOG.

Data provenance & licensing

EnterpriseOps-Gym is Apache 2.0 (code) with a public HF dataset (ServiceNow-AI/EnterpriseOps-Gym). This PR commits only: tool-schema snapshots captured from the public EOG containers (7 JSON files, 512 tools), 13 sample tasks derived from the EOG repo's task files, 5 example rollouts generated against live containers, one synthetic hybrid task hand-authored for tests (written with LLM assistance against live container schemas — disclosed per the synthetic-data guideline), and golden verifier fixtures generated by running the EOG engine. The full benchmark dataset is downloaded at prepare.py time and gitignored.

mcuevas-nvidia and others added 10 commits July 24, 2026 21:43
…er-turn telemetry

Adapts the ServiceNow EnterpriseOps-Gym benchmark (Apache 2.0; 8 enterprise
domains, external MCP gym servers, SQL verifiers over final DB state) to
NeMo Gym:

- resources_servers/enterpriseops_gym: per-rollout DB seeding (SQL content
  cache + per-gym seed semaphores), catch-all /{tool_name} MCP proxy with
  EOG-parity observations and per-tool latency capture, idempotent /verify
  with guaranteed DB deletion, TTL janitor for killed rollouts, replica
  pools (gym_url_pools) for horizontal MCP scale-out, and per-domain
  aggregate metrics (leaderboard-style macro average).
- verifier_engine.py is a line-for-line port of the upstream engine,
  preserving its quirks for score parity (verifier name-collapse where
  duplicate-named verifiers overwrite; loose comparison semantics; skipped
  unknown-gym verifiers), pinned by golden fixtures generated from the
  original implementation. strict_verifiers=true switches the reward to
  every-verifier-counts for RL shaping.
- convert_tasks.py / snapshot_tools.py convert EOG tasks (local or the
  ServiceNow-AI/EnterpriseOps-Gym HF dataset) into NeMo Gym JSONL, baking
  tool schemas from live tools/list snapshots with per-task gym-order
  merge semantics (hybrid parity).
- benchmarks/enterpriseops: oracle public split (649 tasks) with HF
  download and offline local fallbacks.
- responses_api_agents/turn_logging_agent: behaviorally identical
  simple_agent variant that records per-turn telemetry (timestamps,
  input/output/cached tokens, tool names) and attaches it to verify
  responses; export_eval_telemetry.py emits the eval team's 21-field
  per-turn JSONL schema.

Validated at full scale against the native harness on the same 649 tasks,
model, and containers: macro success 16.4-17.8% across three runs, 90-94%
per-task agreement, McNemar p>=0.21 (no detectable harness bias), and
100% identical collapsed-verifier scoring structure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Consolidates the equivalence case vs the native harness: golden-fixture
unit parity, 12/12 live task parity, full-public-split single-run
comparisons (McNemar p>=0.21, 100% scoring-structure agreement), and the
k=5 interleaved variance experiment (6,480 rollouts): mean@5 macro
16.54+/-0.73 vs 16.76+/-0.99 (delta -0.23pp), per-task preference 67:67,
and a direction-free gateway serving-path effect (+3.49pp outcome-flip
excess, permutation p<0.002) attributed to Responses-vs-ChatCompletions
serving rather than either harness. Includes calibration guidance
(report mean@k; ~6.3% of outcomes flip on any rerun) and upstream-relevant
operational findings (container fd leak, silent task drops, resume mode).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Upstream #1682 made the MCP Python SDK a core dependency, but for
Gym-as-MCP-server (the inverse of this module's Gym-as-MCP-client role).
Records why the SDK client is not a fit here: httpx transport (banned for
high-concurrency async), session-level vs required per-call isolation
headers, non-MCP REST endpoints comprising half the surface, and frozen
upstream protocol version.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
…ed GPU

Full oracle-split sweep (649 tasks x 2 harnesses x c in {8,16,32,64,128})
on 4xH100 TP=4 serving Nemotron 3 Nano FP8 locally, both harnesses on the
identical chat-completions endpoint. The port is 1.14-1.71x faster at
matched concurrency (largest at realistic low-c settings), needs ~4x less
client concurrency for equal throughput, and saturates the hardware at
c=64 while native never reaches the throughput floor in the tested range.
Success rates identical within noise at every level. Mechanism: GPU batch
starvation from native's per-request connections, per-task handshakes,
and sequential verifiers (GPU 98% busy both sides, client CPU idle).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Treats the 4xH100 performance sweep as an independent k=5 replication on
dedicated vLLM serving (Nemotron 3 Nano FP8, both harnesses on one
endpoint). Confirms the serving-path attribution via its designed
falsification test (cross-harness trajectory excess 3.49 -> 1.57pp, 55%
-> 11% of the noise floor), establishes formal TOST equivalence within
+/-2pp at alpha=0.05 with direction-free residuals (112:106 task
preference, sign p=0.735), and adds a determinism calibration for
reasoning models (41% flaky tasks vs 20% non-reasoning; report mean@5).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Config-only GRPO readiness validation on the 4xH100 stack: token-ID
capture via return_token_id_information, curriculum selection from
repeat-run sweep data, and group-mixing results (15/20 binary-mixed
at k=8, mean group std 0.341). Documents the unshuffled-benchmark
+limit pitfall and operational notes for long collection runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Measured train-sequence lengths (exact from v3 token IDs, band-wide via
calibrated estimate): curriculum yield is 63% at a 32k cap vs 94% at
64k, which drives the shape ranking (B300/B200 single node > H200 >
2x8 H100 disaggregated > single 8x H100 > LoRA fallback). Includes
trainer memory budget, step-time model, node layout, and the
pre-registered proof-point run sketch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Generated by scripts/update_env_list.py; the turnlog overlay config gains
a metadata block (a no-op merge over the inherited server) so the table
generator can render its row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Per the environment contribution guide: data/example_rollouts.jsonl
(5 pre-generated rollouts from example.jsonl against live containers)
and a licensing/data-provenance section in the server README.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Jul 25, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

mcuevas-nvidia and others added 2 commits July 26, 2026 22:13
Generated via gym dataset collate +mode=example_validation; CI's
should_validate_data gate requires it alongside example.jsonl and
example_rollouts.jsonl.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
…h-integration-enterpriseops

Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@github-actions github-actions Bot added the sla:triage-overdue Review assignment is over the one-business-day SLA label Jul 27, 2026
The five flagged strings in enterpriseops_gym/data/tools/drive.json are
example Google Drive document IDs from the upstream EOG container's tool
schemas (one is the sample spreadsheet ID from Google's own API docs),
not credentials. Baseline updated with detect-secrets 1.5.0 to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@mcuevas-nvidia
mcuevas-nvidia requested a review from a team as a code owner July 27, 2026 01:29
gym env test discovery only treats modules with a README.md as
testable; with fail_on_total_and_test_mismatch=true the missing README
failed CI's shared server-tests job (found 137 modules, tested 136).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@@ -0,0 +1,3436 @@
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can these long files be pulled from somewhere like huggingface instead of committed?

@cmunley1

Copy link
Copy Markdown
Contributor

/claude review

@github-actions github-actions Bot removed the sla:triage-overdue Review assignment is over the one-business-day SLA label Jul 27, 2026
@claude

claude Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

SHIP WITH CARE — no BLOCKERs. The verifier port and reward aggregation are the highest-risk surface here and they're the most carefully done part of the PR: EOG parity quirks (name-collapse, unknown-gym skips, loose comparisons) are documented and pinned by golden fixtures, strict_verifiers cleanly separates leaderboard-parity reward from RL reward, verify is idempotent and deletes DBs in a finally, the MCP client correctly routes all async HTTP through nemo_gym.server_utils.request() (no httpx, no ray.get()), and per-call x-database-id isolation is the right call over the SDK's session-level headers. No core changes, tests are fully offline, deps declared. Good work.

Two non-blocking findings, both inline:

  1. RISK (turn_logging_agent/app.py): the agent hardcodes bare /v1/responses where simple_agent uses url_path_for_request/url_path_for_run, dropping the /ng-rollout/<id> capture-correlation prefix. No-op when observability is off, so eval/reward and inline return_token_id_information are unaffected — but this agent's whole purpose is RL telemetry, which is where capture gets enabled. The docstring even claims step-for-step parity; this is the divergence.

  2. RISK (app.py verify): all([]) is True, so a fully empty or all-skipped verifier set scores reward 1.0. A gym_name/pool misconfig silently converts every task to a false pass — inflates eval macro-rates and feeds spurious positive reward into GRPO. Guard the strict path (bool(strict_passed) and all(...)) and at least log.warning on num_verifiers_scored == 0.

Neither blocks merge; #2 is the one I'd want resolved before this feeds a training run.

mcuevas-nvidia and others added 2 commits July 28, 2026 18:13
Mirror simple_agent's url_path_for_request/url_path_for_run so
/ng-rollout/<id>-prefixed self-calls keep per-rollout observability
correlation on downstream model calls. Adds a regression test driving
the prefixed route. Addresses PR #2142 review feedback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
all([]) is True, so a task with zero scorable verifiers awarded
strict reward 1.0. Guard the strict path (which feeds RL rewards);
the collapsed parity path intentionally keeps upstream's all([])
semantics for leaderboard comparability, now documented in place.
Addresses PR #2142 review feedback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@mcuevas-nvidia

mcuevas-nvidia commented Jul 28, 2026 via email

Copy link
Copy Markdown
Author

…h-integration-enterpriseops

Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@ritaneves
ritaneves requested a review from Glorf July 30, 2026 08:24
@github-actions github-actions Bot added the sla:review-overdue Review response is over the one-business-day SLA label Jul 31, 2026
@zyzhou5 zyzhou5 added waiting-on-maintainers Waiting on maintainers to respond ready-to-merge PR is approved, current, and waiting for final CI or merge complexity:high Cross-component or shared-contract change with a large review surface labels Oct 12, 2026
Regenerate the README environment table to retain EnterpriseOps and
all entries added on main.

Signed-off-by: Zeyu Zhou <zezhou@nvidia.com>
@zyzhou5 zyzhou5 added waiting-on-customer Waiting on the original author to respond and removed waiting-on-maintainers Waiting on maintainers to respond labels Oct 12, 2026
@zyzhou5

zyzhou5 commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

/ok to test a25f0e4

turn_record["output_end_index"] = len(new_outputs)
break

if not all_fn_calls and all_output_messages:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This forks a July SimpleAgent and misses later fixes on main: a reasoning-only turn doesn't end the loop here, so it runs to max_steps (#3536). SimpleAgent's trajectory capture already records per-turn and per-tool timing. If cached/reasoning token sums are missing, can we add them there and drop this agent.

json=parsed_arguments,
cookies=resources_server_cookies,
)
resources_server_cookies = api_response.cookies

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This replaces the cookie jar instead of merging it (#4449).

return_code = proc.returncode if proc.returncode is not None else SANDBOX_RUNTIME_RETURN_CODE
return return_code, stdout_b.decode(errors="replace"), stderr_b.decode(errors="replace")

def _reserve_service_ports(self, ports: tuple[int, ...]) -> list[TextIO]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would suggest to make core provider change its own PR. endpoint() also returns loopback for any port without checking it was declared.

argv += _resource_passthrough_flags(spec.resources)
argv += start_args
if spec.ports and _uses_isolated_network(start_args, self._subprocess_env):
raise ValueError("SandboxSpec.ports require the host network; remove --net or --netns-path")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rejecting --net/--netns-path whenever ports are declared means services can never be network-isolated. We block egress by default, so this probably needs another way e.g. a netns with port forwarding.



def _image(domain: str, digest: str) -> str:
return f"shivakrishnareddyma225/enterpriseops-gym-mcp-{domain}@{digest}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Images come from a personal Docker Hub account. Please mirror them to an org-owned registry (keeping the digests).

tool_call_timeout_seconds: 30
sql_timeout_seconds: 30

# EOG judges response_check verifiers with the policy model itself; keep that

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would suggest using something other than the policy as the judge


# Route the tool to its gym: dataset-provided mapping, else the only gym.
gym_name = state.tool_to_gym.get(tool_name)
if gym_name is None and len(state.gyms) == 1:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The proxy doesn't enforce restricted_tools / selected_tools, so a model can call any tool the gym exposes.

gym_servers_config = body.verifier_metadata.get("gym_servers_config") or []

# Seed all gyms' databases concurrently (bounded by per-gym-server semaphores).
await asyncio.gather(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If one gym's seed fails, are the databases already seeded for the other never cleaned up?

@zyzhou5 zyzhou5 removed the ready-to-merge PR is approved, current, and waiting for final CI or merge label Oct 13, 2026
@d-molinari

Copy link
Copy Markdown
Contributor

Some potentially useful cleanup hardening to be considered:

#4774

@svcnvidia-nemo-ci svcnvidia-nemo-ci added area:environment Individual environments, benchmarks, verifiers, and environment-specific resources servers feature New capabilities, enhancements, or enablement work benchmark-onboarding Self-contained benchmark onboarding labels Oct 20, 2026

This branch was previously deployed

1 inactive deployment
public — a25f0e4b Deployed Oct 12, 2026 by copy-pr-bot[bot] via release / finalize / notify #5081
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:environment Individual environments, benchmarks, verifiers, and environment-specific resources servers benchmark-onboarding Self-contained benchmark onboarding complexity:high Cross-component or shared-contract change with a large review surface feature New capabilities, enhancements, or enablement work sla:review-overdue Review response is over the one-business-day SLA waiting-on-customer Waiting on the original author to respond

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants