Repository navigation
[feature] Import AgentEnv bundles with openenv import - #1493
earakely-scale wants to merge 11 commits into
Conversation
Add an agentenv importer beside ORS/OpenReward and Verifiers. It detects AgentEnv bundles (folders whose tasks/ holds task files) by reading JSON only, vendors the bundle under its own folder name, and generates a server/app.py that serves it with agentenv-framework's build_app. prepare_import_package takes an optional vendor_dir and append_dependency_files an optional requires_python, so the generated package keeps the bundle's name and locks against agentenv-framework. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The agentenv importer copied the whole source tree even when --env-class picked one bundle out of a repository, carrying unrelated files and local config into the package; it now vendors the bundle folder alone and takes dependencies from the bundle's own requirements. An agentenv-framework entry the bundle already lists now gets the >=0.9.1360 floor merged into it rather than replacing it. The CLI reference says the server needs local Docker to build a bundle's environment images, and that the generated image can't serve a bundle yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep the CLI reference to what the importer detects and vendors, and link to AgentEnv's OpenEnv page for what the served env does and needs, so details that change with agentenv-framework are documented there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agentenv-framework 0.9.1364 makes OpenEnv an optional extra, so the generated package asks for agentenv-framework[openenv]>=0.9.1364, and an agentenv-framework entry the bundle already lists gets the extra added along with the floor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
burtenshaw
left a comment
There was a problem hiding this comment.
Thanks for the careful PR and test plan. I checked out the branch: tests/test_cli passes (163 passed), and ruff check, ruff format and usort pass on every changed file. The remaining lint hits (src/openenv/core/harness/README.md, tests/envs/test_julia_env.py, tests/envs/test_grid_world.py) are already on main. I found no Tier 1 correctness bugs, so I pushed nothing.
Bugbot's latest "unpublished version" finding is stale. agentenv-framework 0.9.1364 is on PyPI with the openenv extra and requires-python >=3.11.4.
Design questions for maintainers (blocking until someone decides)
-
Delegating importer vs RFC 015 (#794). RFC 015 Decision 1 says
openenv importgenerates an inspectable wrapper that subclassesEnvironmentin the generated package. This importer generates a 26-line shim (templates/agentenv_app.py.tpl), and the wrapper (agent_env.openenv.AgentEnvEnvironment, about 480 lines) ships inagentenv-framework. I read it. It usescreate_app,CallToolAction/CallToolObservationand the TaskProvider methods, so the boundaries hold today. But reviewers cannot audit the served env from the generated package, and the adapter is versioned againstopenenv.coreinternals outside this repo. I don't think this needs its own RFC: nocore/changes, and RFC 015 Goal 6 expects more importers in the registry. RFC 015 should say whether a "delegating" importer is acceptable, though, and add an AgentEnv mapping section if so. -
In-tree vs entry point. The entry-point option in the PR description would be a new plugin mechanism. Per CLAUDE.md, that needs an RFC, so it is probably out of scope here. In-tree follows the ORS and Verifiers precedent.
-
The generated package can't be deployed with OpenEnv tooling. The server needs Docker on the host, so
openenv build/openenv pushproduce an image that builds but cannot serve. RFC 015 Goal 3 says imported packages deploy like hand-written ones. At minimum,generate()(src/openenv/cli/importers/agentenv.py:97-117) orimport_envshould print a warning, and the generated README should state the requirement. Today the README is still the echo template.
Non-blocking
agentenv.py:101deletesserver/<env>_environment.py, but the generated README still documents it (python3 server/<env>_environment.py, file tree). The templateclient.py/models.pystill describe echo actions, while the served env takes MCP actions.agentenv.py:49: detection now runs on everyopenenv import. An ORS or Verifiers repo with atasks/*.jsonlist of{"type": ...}objects would now hit "Multiple source formats" and need--type. That is probably rare, but it is a behavior change for existing users.docs/source/guides/first-environment.md:36: the tip says the importer "vendors the source" and "emits an OpenEnv wrapper". For AgentEnv, only the bundle folder is vendored, and the wrapper comes fromagentenv-framework.docs/source/reference/cli.md:34: "deploys each episode on the local Docker" reads better as "in a local Docker container".
Verdict: needs maintainer review on items 1 to 3. The code itself is small and clean.
Resolve the README overlap from openenv#668 by retaining host-local serve guidance and the AgentEnv importer entry. Preserve the generated AgentEnv documentation, runtime warning, dependency floor, and client limitations from openenv#1493. Existing RFC015 delegation, deployment, and client integration holds remain open.
The generated README now links agent_env.openenv's environment.py and app.py at the minimum supported agentenv-framework release, so the served environment can be read from the generated package. Detection also requires each step to carry a string id, as AgentEnv task steps do, which makes it less likely that another project's tasks/*.json is mistaken for a bundle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@burtenshaw thanks for the thorough review, and for the README, warning and docs commits. 1. Delegating importer vs RFC 015. Below is proposed text for RFC 015, written to drop into it as it stands on #794: a short "Delegating Importers" subsection that says when an importer may serve the library's own OpenEnv adapter instead of generating a wrapper, and an "AgentEnv Mapping" section beside the ORS/OpenReward and Verifiers ones. Happy to open a PR against your RFC branch instead, if that's easier. Proposed: Delegating Importers (after "Generated Wrapper Contract")
Proposed: AgentEnv Mapping (after "Verifiers Mapping")
Proposed: smaller edits elsewhere in RFC 015One line or paragraph each, so the new sections don't contradict the rest of the RFC.
The new example, in the style of the existing ones:
2. In-tree vs entry point. Agreed: in-tree, like ORS and Verifiers. We don't need the entry point. 3. Deployment. Thanks for the generated README and the import-time warning. For this PR we'd keep the limitation documented; the text above proposes it as an explicit Non-Goal. A working Space needs a remote sandbox and published environment images, which is on our side and separate from this PR. Non-blocking. c834349 (on top of your commits) covers two of them:
|
|
Independent review at c834349 confirms 194 CLI tests pass, the linked v0.9.1364 source tag exists, the GenericEnvClient example is valid, and upstream adapter CI provides useful isolation/shutdown evidence. The proposal makes the delegation exception explicit. Targeted corrections remain: (1) named direct-URL requirements currently bypass the claimed minimum framework version; a narrow importer repair is being prepared; (2) RFC015 currently requires pre-reset calls to raise, while this adapter returns a terminal error observation without deployment, so reconcile that contract explicitly; (3) the API list also needs Observation, State and RESERVED_TOOL_NAMES; (4) the universal no-exception error guarantee is broader than tested implementation: turn.end and cleanup have paths outside the exception handler, so narrow that text or cover those paths. Delegation, the Docker-runtime non-goal and incompatible generated scaffold client/models still need explicit design acceptance. Documentation of those limitations makes the tradeoff reviewable but does not establish acceptance. |
…penenv#1493) The framework floor was skipped for named direct references. Validate collected dependencies before scaffolding and reject sources whose adapter version cannot be established statically. Preserve normal range constraints, extras and markers.
…NVS, and require agentenv-framework 0.9.1366 - client.py is now an MCPToolClient subclass, and __init__.py exports it with CallToolAction and ListToolsAction, as envs/echo_env does. The echo scaffolding's models.py is dropped. The README shows the client. - server/app.py passes MAX_CONCURRENT_ENVS to build_app, as OpenEnv's own env apps do (default 8). - The floor is agentenv-framework 0.9.1366, whose adapter raises on a step before the session's first reset, as RFC 015's wrapper contract requires, and ends an episode whose end_turn the proxy refuses in an error observation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a72456a. Configure here.
…nv#1493) The generated subclass inherited MCPToolClient's persistent discovery cache, so reset and turn changes kept old tools. Default to fresh discovery while preserving explicit use_cache arguments. Cover reset, end_turn via HTTP and WebSocket, and dynamic tool changes with generated-client transport regressions.
|
@burtenshaw thanks, all four corrections were right. This is fixed in agentenv-framework 0.9.1366 (scaleapi/agentenv-framework#350), and a72456a on this branch raises the floor to it. 1. Direct references. Thanks for bc98140. A direct reference can't show the adapter's version without fetching it, so refusing it at import is the right call. 2. A step before
3. The API list. Corrected. Condition 2 of the proposed Delegating Importers text now reads:
4. The no-exception guarantee. You were right about Cleanup was already safe, and a new test now covers it:
The narrowed paragraph for the AgentEnv Mapping:
The generated client. It now matches the served API, so it should drop off the list of things needing acceptance. It follows
The generated README shows the client in use. End to end from a generated package, everything from PyPI (0.9.1366, openenv 0.10.0), the client:
Also in a72456a: the generated
|
|
Correction after reconciling the exact v0.9.1366 lifecycle: I withdraw the teardown exception-escape blocker. Our earlier probe replaced Episode.abandon itself with a raising coroutine, which bypassed its real asyncio.wait behavior. The upstream teardown_run injection is the relevant boundary. Independent offline probes with unchanged release lifecycle functions and real OpenEnv WebSocket transport confirm a raised teardown_run exception becomes done=True/reward=None/status=error, and the session can reset afterward. One wording qualification remains: say teardown exceptions that fail the episode run, rather than every teardown failure. Provider termination failures caught into the best-effort teardown report can be logged while normal scores are returned; freeing session tracking does not prove every sandbox stopped. This is a documentation qualification, not the withdrawn exception-escape blocker. Delegation and the Docker-runtime Non-Goal remain the two maintainer design decisions. |
|
@burtenshaw thanks for 598514f. That's a real bug I missed: Agreed on the teardown wording. Teardown is best-effort: a sandbox it can't stop is logged and the episode keeps its score. Only a teardown that raises ends the episode in an error observation. The corrected paragraph for the AgentEnv Mapping:
|

Summary
Adds an
agentenvimporter toopenenv import, next to ORS/OpenReward and Verifiers. It turns an AgentEnv bundle into an ordinary OpenEnv environment package whoseserver/app.pyserves the vendored bundle withbuild_appfromagentenv-framework'sopenenvextra (0.9.1366 and later). This replaces the TRL-side integration proposed in huggingface/trl#7759.Detection reads JSON only and imports nothing. A bundle is a folder whose
tasks/holds task files, each a JSON list of steps with anidand atype. The importer finds every bundle under the source and skips the importers' usual excluded directories. A plugin repository can hold several bundles; pick one with--env-class <folder name>.Generation uses the shared package template:
prepare_import_packagetakes an optionalvendor_dir.server/app.pycomes fromagentenv_app.py.tpl, and the README fromagentenv_README.md.tpl. The README links the delegated adapter's source (agent_env/openenv/environment.pyandapp.py) at the minimum supported agentenv-framework release. The template's example environment module and echomodels.pyare dropped, sincebuild_appserves the env.server/app.pypassesMAX_CONCURRENT_ENVStobuild_app, as OpenEnv's own env apps do (default 8).client.pyis anMCPToolClientsubclass, and__init__.pyexports it withCallToolActionandListToolsAction, asenvs/echo_envdoes. It comes fromagentenv_client.py.tplandagentenv_init.py.tpl.requirements.txtorpyproject.toml, withagentenv-framework[openenv]>=0.9.1366added. If the bundle already listsagentenv-framework, the extra and the floor are merged into that entry instead. A direct URL reference to it is refused, since its version can't be checked without fetching it.requires-pythonis>=3.11.4(agentenv-framework's floor) souv lockresolves. To allow this,append_dependency_filestakes an optionalrequires_python.Both new parameters are optional, so the ORS and Verifiers importers are unchanged.
What the served env does:
reset(split=..., index=...)deploys the task's environment.end_turn, andend_turnreturns the task's score as the reward.allholds every task, and each of the bundle's evals is its own split.In-tree or a hook: this follows the ORS and Verifiers precedent and lives in-tree. If you'd rather keep third-party formats out of tree, an entry-point group for importers would let agentenv-framework ship this importer itself. Happy to switch.
Type of Change
Alignment Checklist
.claude/docs/PRINCIPLES.mdand this PR aligns with our principles.claude/docs/INVARIANTS.mdand no invariants are violated/pre-submit-pr(orbash .claude/hooks/lint.shand tests) and addressed all issuesTwo things for reviewers:
server/Dockerfilehas no Docker inside, soopenenv build/openenv pushdon't give a working Space for a bundle yet.Docs: the CLI reference says what the importer detects and vendors, and links to AgentEnv's OpenEnv page for what the served env does and needs. Details that change with agentenv-framework are documented there rather than here.
RFC Status
Test Plan
Unit tests and lint
PYTHONPATH=src:envs uv run pytest tests/test_cli: 210 passed. The importer's command tests fail if the importer isn't registered, and fail on the first revision, which vendored the whole source and let a bundle's ownagentenv-frameworkentry drop the floor (the Bugbot finding).tests/envs/test_coding_codeact_env.py, which needssmolagents): 3701 passed, 187 skipped, 12 failed. The 12 also fail on unmodifiedmainon the same machine: theagentic_harness_processtiming tests, the live HF Space tests intest_auto_env.py,test_harbor_capture_server's port test and two websocket client tests.usort check,ruff format --checkandruff checkpass on the changed files. On this base,lint.shalso reportstests/envs/test_julia_env.py,tests/envs/test_grid_world.pyandsrc/openenv/core/harness/README.md, which were already onmain.importers/agentenv.pyand its templates.End to end (macOS, local Docker, from PyPI: agentenv-framework 0.9.1360 and openenv 0.10.0 at first, then 0.9.1364, where OpenEnv became an optional extra)
echo-desk, theecho-mcpexample's MCP server (envs/echo/) plus one task that asks for the echo tool's output and scores whether the answer contains it (agent_prompt_response_verifier).openenv import echo-desk --name echo_desk --output-dir outgenerated the package, anduv lockresolved.pip install ./out/echo_deskinto a fresh venv installed the vendored bundle as package data. Thenserver --port 8765, the package's own entry point.GenericEnvClient:/list_environmentsreturned["echo-desk"], and the splits wereall.echoandend_turn.pingscored reward 1.0 withdone; answering otherwise scored 0.0. Both took 29 s together, deploys included.openenv validate out/echo_deskpassesstatic.manifest.agentenv-framework[openenv]0.9.1364 and openenv 0.10.0, installs into a fresh venv and servesecho-desk. It scored 1.0 and 0.0.echo-deskand a second bundle underbundles/, a 50 MB file underresults/, a local.agentenv/config.tomland a rootrequirements.txtlistingtorch.openenv import repo --env-class echo-deskvendored 20 KB, theecho-deskfolder alone, withouttorch. Installed into a fresh venv and served, it scored 1.0 and 0.0 as above.agentenv-framework[openenv]0.9.1366 (protocol 0.1.381) and openenv 0.10.0. It's served withMAX_CONCURRENT_ENVS=1.EchoDeskEnvraised on a tool call before reset. It then reset tosplit="all", index=0, listedechoandend_turn, gotpingback fromecho, and gotdone=Trueand reward 1.0 fromend_turn.CAPACITY_REACHED.GenericEnvClient, a step before reset came back as anEXECUTION_ERROR; the same session then reset and played, scoring 0.0 for a wrong answer.Claude Code Review
Written with Claude Code.
/alignment-reviewwasn't run; the note for reviewers above is the one alignment point I found againstPRINCIPLES.mdandINVARIANTS.md.🤖 Generated with Claude Code
Note
Medium Risk
New import path and dependency/version enforcement are well tested, but served bundles depend on host Docker and delegated agentenv-framework runtime, which limits deployment assumptions for users of build/push.
Overview
Adds AgentEnv bundle support to
openenv import, alongside ORS/OpenReward and Verifiers.Detection finds folders whose
tasks/contains valid step JSON (no source import). Multi-bundle repos require--env-classwith the bundle folder name.Generation vendors only the selected bundle, drops the usual
models.py/*_environment.pyscaffold, and wiresserver/app.pytoagentenv-framework'sbuild_app(withagentenv-framework[openenv]>=0.9.1366, merged into existing framework deps; direct URL refs are rejected). The client is a generatedMCPToolClientwith fresh tool discovery by default. Shared importer helpers gain optionalvendor_dir,requires_python, anditer_directories.Docs (README, first-environment guide, CLI reference) describe AgentEnv import, local Docker requirements, and that
openenv build/pushdo not yield a working deployment without a Docker-capable host. Tests cover detection, CLI generation, dependency merging, selective vendoring, and HTTP client tool discovery.Reviewed by Cursor Bugbot for commit 598514f. Bugbot is set up for automated code reviews on this repo. Configure here.