Turing/ Playwright-based CUA environment with multi-provider adapter support - #946
Turing/ Playwright-based CUA environment with multi-provider adapter support#946raveedturing wants to merge 70 commits into
Conversation
d7d85c8 to
15592df
Compare
7aac8ea to
7ee7fb3
Compare
7ee7fb3 to
76d68fc
Compare
| max_num_tries += 1 | ||
|
|
||
| content = (await response.content.read()).decode() | ||
| backoff = min(2 ** (tries - 1), 30) + random.uniform(0, 1) |
There was a problem hiding this comment.
can we revert this backoff logic pls? if we are hitting rate limits, my suggestion is to lower the concurrency
| # From a gym URL (fetches all tasks): | ||
| ng_collect_rollouts \ | ||
| +agent_name=browser_openai_agent \ | ||
| +input_gym_url=https://your-gym-url.com \ |
There was a problem hiding this comment.
what's the reason we need input_gym_url ?
There was a problem hiding this comment.
Removed this, and introduced the prepare_data script for the gym.
|
|
||
| rows.append(row) | ||
| results.append(result) | ||
| result_strs.append([orjson.dumps(result)]) |
There was a problem hiding this comment.
if the issue is the size, let's fork on if W&B is available and only append to result_strs when it is
| ) | ||
|
|
||
| await asyncio.sleep(0.5) | ||
| backoff = min(2 ** (num_tries - 1), 30) + random.uniform(0, 1) |
There was a problem hiding this comment.
same as above, if we are being rate limited let's lower the concurrency via ++num_samples_in_parallel
| ) | ||
| return super().model_post_init(context) | ||
|
|
||
| async def responses(self, body: AnthropicProxyRequest = Body()): # type: ignore[override] |
There was a problem hiding this comment.
we need to strictly adhere to OpenAI responses format for this route
There was a problem hiding this comment.
what's the highest concurrency we've tested this at?
There was a problem hiding this comment.
Tested at 20 concurrent sessions with OpenAI, Anthropic, and Gemini. Higher concurrency is gated by provider API rate limits (per-org RPM/TPM) — CUA trajectories are particularly token-heavy since every turn includes a full screenshot as a base64 image, and each task requires its own Chromium instance for the duration of the trajectory (5–25 min).
There was a problem hiding this comment.
we can decide to make this generic or specific. if we want to make it generic, we need some major refactor on this implementation. if specific, let's rename this folder to something like "browser_gym_anthropic_model" or something
There was a problem hiding this comment.
Went with the generic approach — both model servers are now stateless translators (OpenAI format ↔ provider-native API) with no browser-gym-specific logic, reusable for any future agent. On the agent side, Anthropic and Gemini both use a single GenericCUAAdapter that speaks pure OpenAI format — provider SDKs are only dependencies of the respective model servers.
There was a problem hiding this comment.
In addition to the generic approach, the model server names have also been made specific, starting with turing-.
| body_dict["model"] = self.config.openai_model | ||
| openai_response_dict = await self._client.create_response(**body_dict) | ||
| return NeMoGymResponse.model_validate(openai_response_dict) | ||
| try: |
There was a problem hiding this comment.
can replace these try/excepts by setting ++global_aiohttp_client_request_debug=true
There was a problem hiding this comment.
Done — removed the try/except blocks and the _sanitize_error() utility.
06ae9e0 to
49ec2d2
Compare
This commit introduces the Browser Gym integration, enabling LLMs to interact with web applications through visual observations and browser actions. Key components include: - New `BrowserGymResourcesServer` for managing browser sessions. - `BrowserPool` to handle Playwright browser instances with concurrency control. - Schemas for browser actions, session requests, and responses. - API endpoints for session management, action execution, and local storage dumping. - Configuration files and example data for testing and demonstration. This integration enhances the capabilities of NeMo-Gym by allowing it to perform actions in web environments, capturing full trajectories for reinforcement learning training. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…bust context management - Move all Anthropic context management (conversation history, trimming, tool pair validation) from model server to adapter in agent layer - Replace sync Anthropic client with AsyncAnthropic in both adapter and model server to avoid blocking the event loop under concurrency - Add tool pair validation after trimming to prevent broken tool_use/ tool_result sequences from reaching the API - Add screenshot memory GC to replace base64 data in old messages with placeholders, reducing memory usage in long trajectories - Add 300s timeout on Anthropic client to prevent hung API calls - Clear pending tool IDs at step() entry to prevent stale IDs on retry - Only send model name from adapter when calling API directly; let model server use its own configured model when proxying - Add comprehensive Playwright key normalization (X11/xdotool names like Super_L, Control_L) with graceful fallback on unknown keys - Add anthropic dependency to browser_agent requirements.txt - Update README to reflect stateless proxy architecture, correct diagrams, provider table, data flow, and max_steps (250) Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
Cover all three model servers (OpenAI, Anthropic, Gemini), the browser agent adapters, and the resource server with 140 unit tests. Fix pre-existing test bugs: OpenAI drag test used wrong coordinate key, verify endpoint mocks used stale assertion format (isPassing vs result), and BrowserAction zoom test passed dict instead of list for region. New test files: - responses_api_models/anthropic_model/tests/test_app.py (11 tests) - responses_api_models/gemini_model/tests/test_app.py (22 tests) Expanded existing tests: - responses_api_agents/browser_agent/tests/test_app.py: rewrite Gemini adapter tests for coordinate denormalization, add tests for all 17 Gemini actions, denorm helpers, URL tracking, and scroll semantics - resources_servers/browser_gym/tests/test_app.py: add key normalization tests and BrowserAction clear_before_typing schema tests Also add "Running Tests" section to browser_gym README with per-server commands and coverage summary table. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
Extract input/output token counts from provider API responses, accumulate across CUA loop iterations, and return NeMoGymResponseUsage so rollout metrics are consistent across all three model providers (OpenAI, Anthropic, Gemini). Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
… gym URL input support Route all OpenAI, Anthropic, and Gemini API calls through model server proxies via injected api_caller, removing direct API clients and keys from adapters. Enforce model_server configuration requirement for all browser agent adapters. Add input_gym_url and input_gym_task_id options to rollout collection, enabling direct task fetching from gym /api/v1/get_expected_state endpoints as an alternative to JSONL files. Complete token usage tracking for OpenAI adapter path (extract input/output tokens from model server responses). Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…rios This commit modifies the example JSONL file to include a series of new tasks related to CRM operations, such as logging notes, updating lead information, creating static lists, and analyzing engagement data. Each task is accompanied by specific metadata for verification, enhancing the dataset for testing and demonstration purposes. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…mprove error logging in OpenAI model server This commit introduces a mechanism to track safety decisions in the Gemini and OpenAI adapters, ensuring that safety acknowledgments are included in function responses when applicable. Additionally, it enhances error logging in the OpenAI model server by sanitizing sensitive information from error messages. The timeout for verification requests in the BrowserGymResourcesServer is also increased to improve reliability. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
This commit introduces improved error handling in the BrowserGymResourcesServer, specifically in the `step` and `dump_local_storage` methods, to manage browser timeouts more effectively. It adds logging for timeout scenarios, ensuring that appropriate error messages are recorded when browser actions fail. Additionally, the BrowserPool class is updated to include per-action timeouts for various browser actions, enhancing the robustness of the browser interaction process. The README and configuration files are also updated to reflect these changes. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
This commit enhances the Browser Agent architecture by introducing the tracking of prompt and generation token IDs, along with their log probabilities, across various adapters (OpenAI, Anthropic, Gemini). The `extract_token_ids_from_response` function is added to facilitate the extraction of these token IDs from model server responses, ensuring consistent data handling. Additionally, the `_build_nemo_response` function is updated to utilize a new output message format when token ID data is present. Comprehensive tests are included to validate the new functionality and ensure robustness in token ID extraction and usage across the system. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
This commit introduces a retry mechanism for Gemini API calls in the `GeminiModelServer` class, allowing for transient errors to be retried up to a configurable maximum number of attempts. It adds a helper function to determine if an exception is retryable based on its type or status code. The logging has been improved to provide detailed feedback on retry attempts and failures, enhancing the robustness of the API interaction. Additionally, the `gemini_max_retries` configuration option is added to allow customization of retry behavior. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…lection This commit introduces a new Browser Gym entry in the README, detailing its purpose and configuration. It also updates the `rollout_collection.py` to improve the description of the `num_samples_in_parallel` parameter. Additionally, the `schemas.py` file is modified to streamline imports, and minor formatting adjustments are made in the `setup_playwright.py` and `browser_gym.yaml` files. The test files for the Browser Gym and model responses are updated to ensure consistency and clarity. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…ation updates This commit introduces the ability to fetch tasks directly from the Browser Gym API endpoints, allowing for more dynamic task management. It updates the configuration options to support this new functionality and improves the overall structure of the Browser Gym integration. Additionally, minor adjustments are made to related files to ensure consistency and clarity in the implementation. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
This commit introduces new `__init__.py` files in the test directories for both the Anthropic and Gemini models. These files are essential for Python to recognize the directories as packages, facilitating the organization and execution of tests. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…e autonomous execution instructions in adapters This commit introduces async locking in the BrowserPool class to ensure thread-safe access to session management methods. The `add_session` and `remove_session` methods are updated to use an async context manager for locking. Additionally, the autonomous execution instructions are added to the Anthropic, Gemini, and OpenAI adapters, emphasizing direct action execution without user confirmation. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
This commit introduces a comprehensive suite of tests for the trajectory writer in the browser agent. It includes tests for stripping base64 fields, validating base64 strings, initializing debug trajectories, appending debug steps, and finalizing debug trajectories. The tests ensure that the trajectory writer functions correctly, handling various scenarios and edge cases effectively. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
… documentation This commit modifies the output directory for debug trajectories from `/tmp/cua_debug_trajectories` to `results/cua_debug_trajectories` in the README and configuration files. The change ensures that debug outputs are stored in a project-relative path within the `results/` directory, aligning with other output artifacts. Additionally, the BrowserAgentConfig class is updated to resolve the debug output directory correctly, enhancing the overall organization of output files. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…ests accordingly This commit modifies the `GeminiModelServer` to directly call the asynchronous `generate_content` method from the `aio` client, removing the use of `asyncio.to_thread`. Corresponding updates are made to the test cases to mock the new asynchronous behavior, ensuring that the tests validate the correct model invocation and error handling. This change enhances the efficiency of API calls and aligns the implementation with asynchronous programming practices. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…es for async responses This commit adds comprehensive README files for both the Anthropic and Gemini models, detailing their configuration, usage, and dependencies. Additionally, it updates the test cases for the Anthropic model to remove unnecessary result assignments, ensuring cleaner asynchronous response handling. These changes enhance documentation clarity and improve the testing framework for the models. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
This commit introduces a new `example_rollouts.jsonl` file containing structured data for analyzing engagement metrics from recent campaigns. The data includes user prompts and model responses, providing insights on optimal timing for outreach emails based on engagement statistics. This addition enhances the dataset available for testing and improving outreach strategies. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
This commit introduces an async context manager for the lifespan of the Browser Gym server, ensuring that the browser pool is properly shut down when the server is stopped. The implementation includes tests to verify that the shutdown process is invoked correctly and handles errors gracefully. This enhancement improves resource management and stability during server operations. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
88466e4 to
bcd1eaa
Compare
…el servers - Added new action types for CUA including ActionTripleClick, ActionClickAt, ActionHoverAt, and others to enhance interaction capabilities. - Updated NeMoGymResponseComputerToolCall to utilize the new action types and modified the acknowledged safety checks to use the appropriate types. - Introduced the Anthropic model server, which translates OpenAI Responses API format to the Anthropic Messages API, and added configuration for the new server. - Updated README and configuration files to reflect changes in model server names and integration details for both Anthropic and Gemini. - Refactored action mapping in GenericCUAAdapter to accommodate the new action structure and ensure compatibility with the updated action types. - Enhanced tests to validate the new action mappings and server integrations. This commit enhances the functionality and flexibility of the browser gym environment, allowing for more complex interactions and improved model server integration. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…v-integration Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…v-integration # Conflicts: # README.md # nemo_gym/openai_utils.py # nemo_gym/rollout_collection.py # responses_api_models/openai_model/app.py # tests/unit_tests/test_rollout_collection.py
- Updated the `_load_from_cache` method to include an optional parameter `retain_result_strs` for controlling the retention of serialized result strings. - Adjusted the return signature to include `result_strs`, allowing for more flexible handling of cached rollouts. - Modified related logic in `run_from_config` to utilize the new parameter, improving memory efficiency when uploading results to W&B. - Updated unit tests to reflect changes in the method signature and validate new functionality. This change aims to optimize memory usage during rollout caching and improve integration with W&B uploads. --------- Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
…reporting - Introduced methods to extract expected assertion categories from the `get_expected_state` API and apply them to actual assertions during verification. - Implemented caching for expected categories to optimize repeated lookups. - Enhanced metrics computation to report pass rates for dynamically observed categories, improving the granularity of performance insights. - Updated README to reflect changes in CLI commands and usage instructions. - Added unit tests to validate new functionality and ensure robust category handling. This update aims to improve the accuracy and usability of the BrowserGym framework by integrating dynamic category mapping and detailed metrics reporting. Signed-off-by: raveedturing <ahmad.muhammad@turing.com>
e104274 to
7b5b5f9
Compare
…v-integration Signed-off-by: raveedturing <ahmad.muhammad@turing.com> # Conflicts: # README.md # nemo_gym/openai_utils.py # nemo_gym/rollout_collection.py # tests/unit_tests/test_openai_utils.py # tests/unit_tests/test_rollout_collection.py
…tional idle sweeper Gym's episode lifecycle is seed_session -> responses -> verify, with no teardown step, so environments release external resources inside verify() - the one call that does not happen when the training side aborts, cancels or times out. simple_agent shows the gap: /seed_session, then /v1/responses guarded by raise_for_status, then /verify, with no try/finally between them. Of 102 resources servers, 11 override seed_session and they use five mutually incompatible cleanup conventions; five have none at all. newton_bench independently wrote a TTL sweeper and NVIDIA-NeMo#946 ships a second one. * close_session on SimpleResourcesServer, default no-op, served at POST /close_session. Environments that hold something override it, and the contract requires idempotency - the same as SandboxProvider.close(). * session_scope() on the agent base pairs /seed_session with /close_session in a finally; simple_agent adopts it, so the guarantee is structural rather than per-environment discipline. * Optional idle sweeper behind session_ttl_s (default None = today's behavior), as a backstop for what no call can reach: a killed trainer, a dropped connection. Modelled on newton_bench's working implementation. This is the resource-reclaim half of NVIDIA-NeMo#23: cancelling the request is necessary but not sufficient, because a cancelled handler still leaves the session behind. Closes NVIDIA-NeMo#2609 Signed-off-by: waple0820 <232305951+waple0820@users.noreply.github.com>
…tional idle sweeper Gym's episode lifecycle is seed_session -> responses -> verify, with no teardown step, so environments release external resources inside verify() - the one call that does not happen when the training side aborts, cancels or times out. simple_agent shows the gap: /seed_session, then /v1/responses guarded by raise_for_status, then /verify, with no try/finally between them. Of 102 resources servers, 11 override seed_session and they use five mutually incompatible cleanup conventions; five have none at all. newton_bench independently wrote a TTL sweeper and NVIDIA-NeMo#946 ships a second one. * close_session on SimpleResourcesServer, default no-op, served at POST /close_session. Environments that hold something override it, and the contract requires idempotency - the same as SandboxProvider.close(). * session_scope() on the agent base pairs /seed_session with /close_session in a finally; simple_agent adopts it, so the guarantee is structural rather than per-environment discipline. * Optional idle sweeper behind session_ttl_s (default None = today's behavior), as a backstop for what no call can reach: a killed trainer, a dropped connection. Modelled on newton_bench's working implementation. This is the resource-reclaim half of NVIDIA-NeMo#23: cancelling the request is necessary but not sufficient, because a cancelled handler still leaves the session behind. Closes NVIDIA-NeMo#2609 Signed-off-by: waple0820 <232305951+waple0820@users.noreply.github.com>
…tional idle sweeper Gym's episode lifecycle is seed_session -> responses -> verify, with no teardown step, so environments release external resources inside verify() - the one call that does not happen when the training side aborts, cancels or times out. simple_agent shows the gap: /seed_session, then /v1/responses guarded by raise_for_status, then /verify, with no try/finally between them. Of 102 resources servers, 11 override seed_session and they use five mutually incompatible cleanup conventions; five have none at all. newton_bench independently wrote a TTL sweeper and NVIDIA-NeMo#946 ships a second one. * close_session on SimpleResourcesServer, default no-op, served at POST /close_session. Environments that hold something override it, and the contract requires idempotency - the same as SandboxProvider.close(). * session_scope() on the agent base pairs /seed_session with /close_session in a finally; simple_agent adopts it, so the guarantee is structural rather than per-environment discipline. * Optional idle sweeper behind session_ttl_s (default None = today's behavior), as a backstop for what no call can reach: a killed trainer, a dropped connection. Modelled on newton_bench's working implementation. This is the resource-reclaim half of NVIDIA-NeMo#23: cancelling the request is necessary but not sufficient, because a cancelled handler still leaves the session behind. Closes NVIDIA-NeMo#2609 Signed-off-by: waple0820 <232305951+waple0820@users.noreply.github.com>
…tional idle sweeper Gym's episode lifecycle is seed_session -> responses -> verify, with no teardown step, so environments release external resources inside verify() - the one call that does not happen when the training side aborts, cancels or times out. simple_agent shows the gap: /seed_session, then /v1/responses guarded by raise_for_status, then /verify, with no try/finally between them. Of 102 resources servers, 11 override seed_session and they use five mutually incompatible cleanup conventions; five have none at all. newton_bench independently wrote a TTL sweeper and NVIDIA-NeMo#946 ships a second one. * close_session on SimpleResourcesServer, default no-op, served at POST /close_session. Environments that hold something override it, and the contract requires idempotency - the same as SandboxProvider.close(). * session_scope() on the agent base pairs /seed_session with /close_session in a finally; simple_agent adopts it, so the guarantee is structural rather than per-environment discipline. * Optional idle sweeper behind session_ttl_s (default None = today's behavior), as a backstop for what no call can reach: a killed trainer, a dropped connection. Modelled on newton_bench's working implementation. This is the resource-reclaim half of NVIDIA-NeMo#23: cancelling the request is necessary but not sufficient, because a cancelled handler still leaves the session behind. Closes NVIDIA-NeMo#2609 Signed-off-by: waple0820 <232305951+waple0820@users.noreply.github.com>
…tional idle sweeper Gym's episode lifecycle is seed_session -> responses -> verify, with no teardown step, so environments release external resources inside verify() - the one call that does not happen when the training side aborts, cancels or times out. simple_agent shows the gap: /seed_session, then /v1/responses guarded by raise_for_status, then /verify, with no try/finally between them. Of 102 resources servers, 11 override seed_session and they use five mutually incompatible cleanup conventions; five have none at all. newton_bench independently wrote a TTL sweeper and NVIDIA-NeMo#946 ships a second one. * close_session on SimpleResourcesServer, default no-op, served at POST /close_session. Environments that hold something override it, and the contract requires idempotency - the same as SandboxProvider.close(). * session_scope() on the agent base pairs /seed_session with /close_session in a finally; simple_agent adopts it, so the guarantee is structural rather than per-environment discipline. * Optional idle sweeper behind session_ttl_s (default None = today's behavior), as a backstop for what no call can reach: a killed trainer, a dropped connection. Modelled on newton_bench's working implementation. This is the resource-reclaim half of NVIDIA-NeMo#23: cancelling the request is necessary but not sufficient, because a cancelled handler still leaves the session behind. Closes NVIDIA-NeMo#2609 Signed-off-by: waple0820 <232305951+waple0820@users.noreply.github.com>
Turing/ Browser Gym — Playwright-based CUA environment for web navigation training
What does this PR do?
Adds a complete Computer-Use Agent (CUA) training environment to NeMo-Gym. Models interact with live web pages via Playwright — receiving screenshots and executing browser actions (click, type, scroll, keypress, drag, navigate). The environment supports three CUA providers: OpenAI (
computer-use-preview), Anthropic (claude-sonnet-4-20250514/claude-opus-4-6), and Google Gemini (gemini-2.5-computer-use-preview-10-2025).This PR adds:
resources_servers/browser_gym/) — browser session lifecycle, Playwright action execution, session pooling with async locking, graceful error propagation, session reaper for stale sessions, standaloneprepare_data.pyCLI for offline task fetchingresponses_api_agents/browser_agent/) — CUA loop orchestration, provider-agnostic adapter architecture (OpenAICUAAdapter+GenericCUAAdapter), token ID tracking for RL training, debug trajectory outputresponses_api_models/turing_browser_agent_anthropic_model/,responses_api_models/turing_browser_agent_gemini_model/) — stateless translators that accept OpenAI Responses API format, translate to/from provider-native APIs, and return unifiedNeMoGymResponseretain_result_strs), CUA schema types (NeMoGymActionunion + SDK-subclassingcomputer_call/computer_call_output), OpenAI organization header supportArchitecture
Package layout
Data flow
Adapter pattern
All providers follow the same interface. The adapter manages context internally, and all API calls use the standardized OpenAI Responses API format — model servers translate to/from provider-native APIs:
OpenAICUAAdapterprevious_response_idopenai_model(proxies to api.openai.com)GenericCUAAdapterturing_browser_agent_anthropic_model(stateless translator: OpenAI format ↔ Anthropic Messages API)GenericCUAAdapterturing_browser_agent_gemini_model(stateless translator: OpenAI format ↔ Gemini generate_content API)Browser pool
browser_pool_size) with semaphore-bounded concurrency (max_concurrent_browsers)Error handling
Action errors (e.g., invalid key names in keypress) are caught at the Playwright layer in
browser_pool.py, returned throughCUAStepResponse.error, and forwarded to the model via adapter-specific tool result formatting:OpenAICUAAdapter): Error set incomputer_call_output.output.current_urlGenericCUAAdapter): Error set incomputer_call_output.output.current_url(same OpenAI format — model server handles native translation)This allows models to self-correct without crashing the trajectory. If the adapter's
initialize()call fails (e.g., API unreachable), an empty trajectory is returned gracefully instead of a 500 that would crash rollout collection.Verification
Verification uses localStorage assertions. After the CUA agent completes a task:
localStoragetaskId,localStorageDump,initialState,modelResponse) to the gym's/api/v1/get_actual_stateendpoint (with retry logic for transient 502/503/504 errors)1.0if all pass,0.0otherwiseCore framework changes
nemo_gym/rollout_collection.py— Rollout cache memory optimizationresult_strsretention in_load_from_cache(): Preserves the historical four-value return contract(input_rows, rows, results, result_strs)but adds a keyword-onlyretain_result_strs: bool = Trueparameter. When the caller will not upload to WandB, it skips keeping a second serialized copy (result_strs) of every cached rollout and parsesresultsdirectly — avoiding unnecessary memory for large base64-heavy trajectories.run_from_config()passesretain_result_strs=config.upload_rollouts_to_wandb, so the extra copy is only retained when it will actually be used. The WandBresult_strsare rebuilt at the end fromresults(upstream'srun_from_configWandB flow, unchanged by this PR).nemo_gym/openai_utils.py— CUA schemas + organization headerNeMoGymActionunion: Added a cross-provider computer-use action union (~20 types) covering the SDK actions (click,double_click,drag,keypress,move,screenshot,scroll,type,wait) plus the normalized browser actions the Anthropic/Gemini adapters emit (goto,go_back,go_forward,new_tab,switch_tab,close_tab,open_web_browser,search,click_at,hover_at,scroll_at,scroll_document,type_text_at,zoom,hold_key, …).NeMoGymResponseComputerToolCallandNeMoGymComputerCallOutputto theNeMoGymResponseInputItemunion. They inherit the upstream SDK types (ResponseComputerToolCall/ComputerCallOutput) — soissubclassholds and upstream's schema-drift tests keep passing — and only widen the fields CUA needs:action→ theNeMoGymActionunion (a superset of the SDK action union), andoutput→ a plainDict[str, Any]for the browser agent's screenshot/result payload.pending_safety_checkskeeps a default so callers may omit it.organizationfield toNeMoGymAsyncOpenAI— sendsOpenai-Organizationheader when set.responses_api_models/openai_model/app.py— Organization supportopenai_organizationconfig field, passed through toNeMoGymAsyncOpenAI.responses_api_models/turing_browser_agent_gemini_model/requirements.txt— Missing transitive dependenciescryptographyandcffias explicit dependencies. These are required bygoogle-auth(a transitive dependency ofgoogle-genai) but were not being resolved automatically byuvduring venv creation, causingModuleNotFoundErrorat server startup.tests/unit_tests/test_rollout_collection.py— Comprehensive coverage for rollout collection changes_load_from_cacheassertion for theretain_result_strs=Falsepath (memory-optimized load returns the same rows with an emptyresult_strs), alongside the existing four-tuple(input_rows, rows, results, result_strs)coverage.run_from_configedge case tests:resume_from_cachewith missing files,num_samples_in_parallelsemaphore creation._call_aggregate_metricsskipping rows withoutagent_ref.Configuration
env.yaml (required)
Running
Available agents:
browser_openai_agent,browser_anthropic_sonnet_agent,browser_anthropic_opus_agent,browser_gemini_agent.Testing
391 test functions across the new Browser Gym components, all passing, plus targeted additions to
test_rollout_collection.pyfor the core-library changes:resources_servers/browser_gymresponses_api_agents/browser_agentresponses_api_models/turing_browser_agent_gemini_modelresponses_api_models/turing_browser_agent_anthropic_modeltests/unit_tests/test_rollout_collection_load_from_cachefour-tuple return +retain_result_strs=Falsememory-opt path,resume_from_cacheedge cases,num_samples_in_parallelsemaphore, aggregate-metrics skip logic (alongside the existing upstream suite)Pre-commit hooks (ruff, ruff-format, verified flag, README table) all pass.