Repository navigation
OpenEnvTarget: audit agents hosted in OpenEnv environments - #123
Merged
Merged
Conversation
OpenEnv's HarnessEnvironment (RFC 005) runs a real agent harness such as Claude Code and serves it the environment's tools over MCP. OpenEnvTarget puts that agent in SimpleAudit's target seat: - one fresh episode per scenario, opened in start_scenario and closed in end_scenario, either in process (env_factory) or on a server (base_url, through GenericEnvClient) - each auditor message is one HarnessAction step; the reply comes from metadata["response"] and the turn's tool calls and results become tool_events, so the judge sees what the agent did - a failed turn raises (scenario ERROR); an episode the agent ends sets end_conversation; scenarios with attachments are rejected - reset_kwargs can depend on the scenario name; max_sessions defaults to 1 for a server, which holds one session - openenv is imported only when a scenario starts, so `import simpleaudit` stays free of it examples/openenv_agent_audit.py audits a caseworker agent in a mock benefits case system (scripted agent or Claude Code) and prints whether each scenario changed the world. The `openenv` extra pulls the package; CI installs it so the tests run there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 24, 2026
- Input tokens include Anthropic-style cached prompt tokens (cache_read/cache_creation), which Claude Code reports apart from input_tokens. - max_sessions is validated (>= 1) and enforced with a thread semaphore polled without blocking, so the limit holds across threads and the event loops of repeated sync runs, and a cancelled wait never keeps a slot. The per-loop asyncio semaphore is gone. - In-process and server episodes close through one AsyncExitStack; aclose() closes every episode and raises the first failure afterwards. - message_timeout_s bounds an in-process turn as well (asyncio.wait_for). - A tool result's error message is kept, and harness error events in the middle of a turn reach the judge as tool errors. - env_factory may take a scenario_name keyword; the example uses it to key each world by scenario instead of by start order. - The example rejects --agent claude-code without --openenv-repo, adds the adapter path once, and removes the episode working directories. - The server test serves on the socket it bound, so a parallel test cannot take the port in between. - README: install line, sessions and timeouts, factory scenario_name, and the closing caveat.
# Conflicts: # .github/workflows/tests.yml # README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
OpenEnvTarget, which audits an agent hosted in an OpenEnv environment. The judge then grades what the agent did with its tools, as well as what it said. It's a new optional extra,openenv;import simpleauditdoesn't load it.How it works
OpenEnv's
HarnessEnvironment(RFC 005) runs an agent harness, such as Claude Code, and serves it the environment's tools over MCP.OpenEnvTargetputs that agent in the target seat:Episodes. Each scenario gets a fresh episode through Core seams for integrations: target lifecycle hooks, tool events, injected clients #121's
start_scenario/end_scenariohooks.env_factory=: one environment per scenario, so scenarios can run in parallel. A factory that takes ascenario_namekeyword is told which scenario its environment is for.base_url=, throughGenericEnvClient.Both kinds close through one exit stack.
Turns. Each auditor message is one
HarnessActionstep. The reply comes frommetadata["response"]. The turn's tool calls and results, including error messages and any harness error events, becometool_events.Failures and early ends.
message_timeout_sbounds a turn in both modes.end_conversation, so the transcript so far is judged.Options.
reset_kwargscan be a function of the scenario name.max_sessionscaps open episodes across every run and thread that uses the target. It defaults to 1 for a server, because a harness server holds one session.Tokens. Token usage comes from the turn-complete event. Anthropic-style cached prompt tokens count as input.
examples/openenv_agent_audit.pyaudits a caseworker agent in a mock benefits case system, with tools to look a case up, change its payout account and send a letter. It can run a scripted agent or Claude Code, through the adapter in OpenEnv'sexamples/claude_code_harness_eval, and it prints whether each scenario changed the world's state.Notes
close(), which OpenEnv runs on an event loop of its own. An agent adapter therefore must not hold resources tied to the audit's loop; OpenEnv's subprocess adapters don't.AuditExperimentbuilds its targets from model configs, so repeated runs of an agent go throughRepeatedExperimentResults({"agent": runs}).--no-session-persistence, which olderclaudeCLI releases don't support. The example's--claudeoption points at a specific executable.Tests
tests/test_openenv_target.pyhas 17 tests with a scripted harness adapter and the realHarnessEnvironment. They cover:scenario_name;acloseclosing every episode;import simpleauditstays free of openenv;Live checks, with
claude-haiku-5-5as judge and as the agent's model:examples/openenv_agent_audit.py, with the scripted agent and with Claude Code, two repetitions each. Claude Code's tool calls were captured, and its cached prompt tokens counted as input.