feat(v1): Environment consumes the Agent — single-agent as the default program#1946
Draft
hallerite wants to merge 1 commit into
Draft
feat(v1): Environment consumes the Agent — single-agent as the default program#1946hallerite wants to merge 1 commit into
hallerite wants to merge 1 commit into
Conversation
…t program The Environment is now framed as a program of agent interactions over a taskset, running the simplest one: every episode's rollouts are built through an internal Agent, so an eval run and a hand-written agent program resolve placement, timeouts, and pairing through one path. - verifiers/v1/resolve.py (new): per-run resolution — TimeoutConfig, resolve_runtime_config, validate_pairing, cap_remote_harness_timeout — moved below both consumers (breaks the agent <- env import cycle). - Agent.run splits into rollout() (resolve-only, returns the Rollout; accepts the eval's serving resources) + run() (rollout + await). - Rollout.run stamps trace.info["agent"] itself: every trace — eval or program — carries provenance now. - Environment drops its mirrored resolution (runtime_for, per-stage timeout fields); episode() goes through Agent.rollout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| return resolve_runtime_config( | ||
| self.harness.config.runtime, task, self._warned_resources | ||
| ) | ||
| def agent(self, ctx: ModelContext) -> Agent: |
There was a problem hiding this comment.
🟡 Medium v1/env.py:214
Environment.agent() caches the first Agent it builds and ignores every later ctx passed by the caller. env.agent(ctx2) returns the cached agent bound to ctx1, so when downstream code uses the returned agent without re-passing ctx, runs silently go to the original model/client/sampling config. Consider updating the cached agent's context (or returning a new agent) when ctx differs from the cached one.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @verifiers/v1/env.py around line 214:
`Environment.agent()` caches the first `Agent` it builds and ignores every later `ctx` passed by the caller. `env.agent(ctx2)` returns the cached agent bound to `ctx1`, so when downstream code uses the returned agent without re-passing `ctx`, runs silently go to the original model/client/sampling config. Consider updating the cached agent's context (or returning a new agent) when `ctx` differs from the cached one.
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.
What
Stacked on #1939. The
Environmentbecomes the first consumer of theAgent: it is now a program of agent interactions over a taskset, running the simplest program — a single agent on the task,ntimes. Every episode's rollouts are built through an internalAgent, so a config-driven eval and a hand-written agent program resolve placement, stage timeouts, and pairing validation through one path. This is the substrate for pattern envs (proposer→solver, same-box judging, debate) asEnvironmentsubclasses that contribute only their role bindings and a program body — the machinery (episodes, serving, scoring, provenance) stays in the base.Changes
verifiers/v1/resolve.py(new): per-run resolution —TimeoutConfig,resolve_runtime_config,validate_pairing,cap_remote_harness_timeout— moved out ofenv.pyto sit below both consumers (also breaks theagent ← envimport cycle). Pure move, no behavior change.Agent.rollout(): the resolve-only half ofrun()— placement (task-resolved runtime or borrowed box), timeouts (agent > task, remote cap), pairing validation — returning the un-runRollout.run()is nowrollout(...)+ await. The eval's serving resources (shared_urls, interception pool) inject here, so they never appear on the program-facingrun().Rollout.run()stamps provenance itself:trace.info["agent"](harness, model, runtime type + descriptor, borrowed flag) moves fromAgent.runinto the rollout — every trace, eval or program, now carries it. One descriptor per rollout, queryable after the objects are gone.Environment: drops its mirrored resolution (runtime_for, the four per-stage timeout fields);episode()builds rollouts viaEnvironment.agent(ctx)— one cached internal Agent per env (resolution state spans the eval;ctxstill passes per rollout, so the env-server's per-request contexts keep working).ARCHITECTURE.mdwiring sentence, and an "the eval runs on the same primitive" section indocs/agent-programs.md.Net: 9 files, +224/−194 — mostly the move;
Environment.episodeshrinks from ~55 lines of resolution to a list comprehension.Not in this PR (deliberately)
The pattern-env contract itself — role bindings as config (
--solver.model ...), an overridable program hook,trainable-trace marking for training one role of a multi-agent program. Those decisions overlap with #1941's topology tier and should land after that synthesis; this PR only puts the seam in place so they become subclass surface, not new machinery.Validation
ruff+pytest tests/v1(non-e2e) pass.-m "e2e and not docker and not prime and not modal"): 19 passed intest_e2e.py(incl. the shared-tool cases that run through the env-server worker pool — prime-rl's path) and all oftest_envs.py— real model calls end-to-end through the rewiredEnvironment.echo-v1eval returnreward=1.0with per-rollout provenance stamps on their traces.examples/agent_programs/smoke.pyre-run live: the agent-program path unchanged, stamp intact (now emitted by the rollout).🤖 Generated with Claude Code
Note
Make Environment consume an internal Agent for building episode rollouts
Environmentnow lazily constructs and caches an internalAgent(viaEnvironment.agent), and delegates rollout construction toAgent.rolloutrather than handling it directly. This aligns episode resolution behavior with agent programs.Agentgains a newrolloutmethod that returns a configuredRolloutobject without executing it, accepting optionalshared_urlsandinterceptionoverrides.Agent.runnow delegates to this method.trace.info["agent"]) moves fromAgent.runtoRollout.run, so all rollouts (including env-internal ones) carry consistent harness, model, and runtime metadata.TimeoutConfig,resolve_runtime_config,validate_pairing, andcap_remote_harness_timeoutare extracted from env.py into a new resolve.py module, and imports across the codebase are updated accordingly.Environmentno longer exposes per-timeout attributes or aruntime_for(task)method; callers needing per-task runtime resolution must useresolve_runtime_configfromverifiers.v1.resolvedirectly.📊 Macroscope summarized 59b2ca1. 6 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.