Skip to content

feat(bird_interact): run BIRD-Interact in its Environment Server, with no Resources Server - #5409

Draft
ffrujeri wants to merge 1 commit into
ffrujeri/simple-agent-session-continuationfrom
ffrujeri/bird-interact-environment-server
Draft

ffrujeri wants to merge 1 commit into
ffrujeri/simple-agent-session-continuationfrom
ffrujeri/bird-interact-environment-server

Conversation

@ffrujeri

@ffrujeri ffrujeri commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #5465 (simple_agent continuation), which is on #5350, the top of the BaseEnvironmentServerWithTools stack (#5346 → #5347 → #5348 → #5349 → #5350). Review those first; this PR's diff against #5465 is environment_servers/bird_interact only.

What changed

BIRD-Interact runs in one Environment Server for each mode, with no Resources Server. This is approach A of the BIRD-Interact RFC; #5202 is the prototype of approach B, which splits each episode between an Environment Server and a Resources Server.

environment_servers/bird_interact subclasses BaseEnvironmentServerWithTools (#5347) directly, with no user-simulation base class. Its run_episode starts the database sandbox, serves the a-Interact tools, seeds the agent session (agent_session.py), runs the turns and grades them. The server owns the database sandbox, the two-stage user simulator, the grader, the phase and BIRD-COIN rules and the turns.

#5202 (approach B) This PR (approach A)
Servers in an episode Environment Server + Resources Server Environment Server
c-Interact ask and submit Calls to /c_interact/ routes In-process
a-Interact tools Resources Server routes, MCP auto-exposure A TypedToolset of the episode, over direct HTTP, MCP or both
Agent's credential The Environment Server's Resources Server cookie, which reaches every route A signed episode token, for the tool routes of one episode
Who knows the mode Both servers The Environment Server
Several workers Resources Server session routing Routing on the episode token (#5350)
  • Agent session. Seeded with the episode's grants; above one turn it must resume across turns, so each turn sends only the user's new message. A turn over turn_timeout_seconds fails the episode for a retry, the optional interaction_timeout_seconds stops the turns and still grades, and the agent is closed before grading. A failure keeps the completed turns, the tool calls and the agent's evidence.
  • Sandbox. Each episode starts its sandbox and registers its stop, so it stops on every path, including shutdown (feat(environment): finish running episodes' cleanups when a BaseEnvironmentServerWithTools shuts down #5348). A command that fails for infrastructure reasons runs again on a fresh sandbox; then c-Interact fails the episode for a retry and a-Interact masks the sample (bird_interact:sandbox_failed), as does a simulator failure in an a-Interact ask (bird_interact:user_simulator_failed).
  • Tools. Over direct_http the first request declares the nine tools as strict function tools; over mcp alone it declares none, because Codex refuses a request that declares tools.
  • Data. The example datasets are declared on the agent, one taskset for each mode, and validated by the server's task_data.py, the Harbor layout. grading.py, simulator.py, task_data.py and the example data come from feat(environment): add a user-simulation base class and BIRD-Interact on it #5202 unchanged apart from module paths and wording. data/example_rollouts.jsonl is regenerated from the smoke run below.

Tracking: GYMINT-646 (Linear).

Validation

Command Result
pytest environment_servers/bird_interact/tests/test_app.py 48 passed: the 37 episode tests from before, unchanged, plus the agent session's (each turn on one session through the capture route, with its activation header and cookie; the tool grant ends with the episode, then 410; an agent that cannot resume fails the seed and is still closed; a turn timeout fails for a retry; the interaction deadline stops and grades; a failed turn, verification or close keeps the turns and evidence; token capture moves the turns to the training path; max_turns must be positive). The episode tests run with a scripted agent and user model and real database sandboxes on the host (local provider)
ng_test +entrypoint=environment_servers/bird_interact +should_validate_data=true 48 passed in the server's own venv (mcp 2.3; the core venv has mcp 1.29, and the MCP test runs under both)
gym dataset collate "+config_paths=[environment_servers/bird_interact/configs/bird_interact.yaml]" --mode example_validation --output-dir <tmp> Passed; example_metrics.json already up to date
pytest -n 12 tests/unit_tests at this PR's head 15,081 passed, 26 failed. The same 26 fail on main at dda609f86 on the same machine (OpenSandbox compose, sandbox transfer and stop retry, Harbor validation, tasks and run summary, benchmark listing)
pre-commit run --files on every file both stacks change Passed

Rollout evidence

These runs are from before the rebase onto main at dda609f86 and the move of the turns into this server, which keep the behavior (the 37 episode tests pass unchanged); they have not been rerun since. Docker database sandboxes, num_workers: 4 on each BIRD Environment Server, the five example tasks, two repeats. Policy azure/openai/eccn-gpt-6.1-sol; simulator openai/openai/eccn-gpt-6-luna.

Run Rollouts Failed Masked Mean reward #5202's run
c-Interact, simple_agent 10 0 0 0.71 0.40
a-Interact, simple_agent over direct HTTP 10 0 0 0.82 0.82
a-Interact, Codex over MCP (tool_transports: [mcp]) 10 0 0 0.82 0.80 (3 tasks)

What I checked in the rollouts:

  • No tool call returned an error, and no tool output other than ask contained a task's hidden knowledge entry.
  • The one failed c-Interact episode (bookshop_2) is the known simulator issue the RFC records: the simulator calls a fraction a percentage, so the agent's ×100 answer fails.
  • Codex's own observations show only BIRD's tools; it never used its shell.
  • No BIRD sandbox container was left after the runs.
  • The servers log no per-worker access lines, so the runs show four workers and no routing errors, not which worker served each call; feat(environment): route BaseEnvironmentServerWithTools tool calls to the worker that runs the episode #5350's e2e test covers that.

Compatibility

New server; existing servers do not change. #5202 stays open as the approach B prototype until these stacks are reviewed.

Not yet covered: gym env test's data and catalog checks still run only for Resources Servers (GYMINT-643), PostgreSQL (Lite and Full), and rows with custom test_cases.

🤖 Generated with Claude Code

@copy-pr-bot

copy-pr-bot Bot commented Oct 31, 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.

@ffrujeri

Copy link
Copy Markdown
Contributor Author

/ok to test cef7fc5

@ffrujeri
ffrujeri added this pull request to stack #5352 October 31, 2026 13:59
@svcnvidia-nemo-ci svcnvidia-nemo-ci added feature New capabilities, enhancements, or enablement work area:environment Individual environments, benchmarks, verifiers, and environment-specific resources servers labels Nov 1, 2026
@ffrujeri
ffrujeri force-pushed the ffrujeri/bird-interact-environment-server branch from cef7fc5 to 1ba7db8 Compare November 2, 2026 22:21
@ffrujeri

ffrujeri commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 1ba7db8

@ffrujeri
ffrujeri force-pushed the ffrujeri/bird-interact-environment-server branch from 1ba7db8 to 8ae6ea8 Compare November 2, 2026 23:01
@ffrujeri
ffrujeri removed this pull request from stack #5352 November 2, 2026 23:03
@ffrujeri
ffrujeri changed the base branch from ffrujeri/self-contained-session-routing to ffrujeri/agent-session-client November 2, 2026 23:03
@ffrujeri
ffrujeri added this pull request to stack #5468 November 2, 2026 23:03
@ffrujeri

ffrujeri commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 8ae6ea8

@ffrujeri
ffrujeri changed the base branch from ffrujeri/agent-session-client to ffrujeri/simple-agent-session-continuation November 2, 2026 23:37
@ffrujeri
ffrujeri added this pull request to stack #5470 November 2, 2026 23:37
@ffrujeri

ffrujeri commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 0bb3a5e

@ffrujeri

ffrujeri commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test b14c4bc

…h no Resources Server

BIRD-Interact moves into one Environment Server for each mode, as
approach A of the BIRD-Interact RFC proposes. The server subclasses
BaseEnvironmentServerWithTools directly: its run_episode starts the
database sandbox, serves the a-Interact tools, seeds the agent session,
runs the turns and grades them. The #5202 prototype splits each episode
between an Environment Server and a Resources Server; here the
Environment Server owns the database sandbox, the user simulator, the
grader, the phase and BIRD-COIN rules and the turns.

- The agent session (agent_session.py) is seeded with the episode's
  grants, resumes across c-Interact turns, and is closed before grading.
  A turn over turn_timeout_seconds fails the episode for a retry, the
  optional interaction deadline stops the turns and still grades, and a
  failure keeps the completed turns, the tool calls and the agent's
  evidence.
- c-Interact: a question or a submission in each agent reply becomes
  an in-process call. No routes between two servers, and no session
  cookie that reaches every route.
- a-Interact: the nine tools are a TypedToolset of the episode, served
  over direct HTTP, MCP or both (tool_transports), with the signed
  episode token, on any of several workers. The first request declares
  them as strict function tools over direct HTTP, and none over MCP
  alone.
- Each episode starts its database sandbox and registers its stop, so
  the sandbox stops on every path, including shutdown. A command that
  fails for infrastructure reasons runs again on a fresh sandbox; then
  c-Interact fails the episode for a retry and a-Interact masks the
  sample, as does a simulator failure in an a-Interact ask.
- A task without sol_sql, with custom test cases or without its
  database fails at seed, for good.
- The example datasets are declared on the agent, one taskset for each
  mode, and validated by the Environment Server's task_data.py (the
  Harbor layout). gym env test's data and catalog checks still cover
  only Resources Servers (GYMINT-643).

grading.py, simulator.py, task_data.py and the example data come from
#5202 unchanged, apart from module paths and wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Felipe Vieira Frujeri <ffrujeri@nvidia.com>
@ffrujeri
ffrujeri force-pushed the ffrujeri/bird-interact-environment-server branch from b14c4bc to 81e2d19 Compare November 6, 2026 17:23
@ffrujeri

ffrujeri commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 81e2d19

This branch was previously deployed

1 inactive deployment
public — 81e2d19d Deployed Nov 6, 2026 by copy-pr-bot[bot] via release / finalize / notify #10677
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 feature New capabilities, enhancements, or enablement work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants