Skip to content

Commit 86ec5d9

Browse files
committed
feat: add no_upgrade config option for environment installation
Add a `no_upgrade` field to EnvConfig that controls whether the `--no-upgrade` flag is passed to `prime env install`. This prevents the install command from upgrading existing packages, preserving locked dependencies (e.g., from uv.lock). Changes: - Add `no_upgrade: bool = False` to EnvConfig - Update install_env() to accept and pass --no-upgrade flag - Update get_env_ids_to_install() to return dict with no_upgrade settings - Update all callers (eval, orchestrator, synthesize) to use new API
1 parent 0e53e7f commit 86ec5d9

File tree

6 files changed

+38
-15
lines changed

6 files changed

+38
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ Documenting changes which affect configuration usage patterns (added/moved/remov
3737
- **`orchestrator.env.log`**: Removed. Use `orchestrator.log` for env worker logging instead (2026-01-15)
3838
- **`orchestrator.eval.retry.reraise`**: Changed default from `True` to `False`. When `False`, raises `tenacity.RetryError` after retries are exhausted instead of the original exception, allowing failed eval environments to be skipped with a warning (#1586, 2026-01-14)
3939
- **`model.ep`**: Expert parallelism now supported (with auto/custom impl only), changed from the old behaviour when `ep>1` was a no-op to a proper parallelization of the MoE layers. (#1595, 2026-01-15)
40+
- **`env.no_upgrade`**: Added flag (default `False`) to pass `--no-upgrade` to `prime env install`, preserving locked dependencies instead of upgrading packages (2026-01-19)

src/prime_rl/eval/eval.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ async def eval(config: OfflineEvalConfig):
3232

3333
# Install environments
3434
env_ids_to_install = get_env_ids_to_install(config.env)
35-
for env_id in env_ids_to_install:
36-
install_env(env_id)
35+
for env_id, no_upgrade in env_ids_to_install.items():
36+
install_env(env_id, no_upgrade=no_upgrade)
3737

3838
# Initialize the monitor
3939
logger.info(f"Initializing monitor ({config.wandb})")

src/prime_rl/orchestrator/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ class EnvConfig(BaseConfig):
303303
id: Annotated[str, Field(description="ID of the environment to use.")] = "reverse-text"
304304
args: Annotated[dict, Field(description="Arguments to pass to the environment.")] = {}
305305
name: Annotated[str | None, Field(description="Name of the environment to use.")] = None
306+
no_upgrade: Annotated[
307+
bool,
308+
Field(description="If True, don't upgrade existing packages during install. Useful with locked dependencies."),
309+
] = False
306310

307311

308312
class EvalEnvConfig(EnvConfig):

src/prime_rl/orchestrator/orchestrator.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,17 @@ async def orchestrate(config: OrchestratorConfig):
8383
tomli_w.dump(config.model_dump(exclude_none=True, mode="json"), f)
8484

8585
# Install environments
86-
env_ids_to_install = set()
87-
env_ids_to_install.update(get_env_ids_to_install(config.env))
86+
env_ids_to_install: dict[str, bool] = {}
87+
for env_id, no_upgrade in get_env_ids_to_install(config.env).items():
88+
existing = env_ids_to_install.get(env_id, False)
89+
env_ids_to_install[env_id] = existing or no_upgrade
8890
if config.eval is not None:
89-
env_ids_to_install.update(get_env_ids_to_install(config.eval.env))
91+
for env_id, no_upgrade in get_env_ids_to_install(config.eval.env).items():
92+
existing = env_ids_to_install.get(env_id, False)
93+
env_ids_to_install[env_id] = existing or no_upgrade
9094

91-
for env_id in env_ids_to_install:
92-
install_env(env_id)
95+
for env_id, no_upgrade in env_ids_to_install.items():
96+
install_env(env_id, no_upgrade=no_upgrade)
9397

9498
# Setup client
9599
logger.info(

src/prime_rl/synthesize/synthesize.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ async def synthesize(config: SynthesizeConfig):
3030

3131
# Install environments
3232
env_ids_to_install = get_env_ids_to_install(config.env)
33-
for env_id in env_ids_to_install:
34-
install_env(env_id)
33+
for env_id, no_upgrade in env_ids_to_install.items():
34+
install_env(env_id, no_upgrade=no_upgrade)
3535

3636
# Setup clients
3737
logger.info(

src/prime_rl/utils/utils.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,21 +281,35 @@ def default_dtype(dtype):
281281
torch.set_default_dtype(prev)
282282

283283

284-
def install_env(env_id: str) -> None:
285-
"""Install an environment in subprocess."""
284+
def install_env(env_id: str, no_upgrade: bool = False) -> None:
285+
"""Install an environment in subprocess.
286+
287+
Args:
288+
env_id: Environment ID to install.
289+
no_upgrade: If True, don't upgrade existing packages during install.
290+
"""
286291
logger = get_logger()
287292
logger.info(f"Installing environment {env_id}")
288293
install_cmd = ["uv", "run", "--no-sync", "prime", "env", "install", env_id]
294+
if no_upgrade:
295+
install_cmd.append("--no-upgrade")
289296
result = subprocess.run(install_cmd, capture_output=True, text=True)
290297
if result.returncode != 0:
291298
raise RuntimeError(f"Failed to install environment {env_id} (stdout={result.stdout}, stderr={result.stderr})")
292299
logger.info(f"Successfully installed environment {env_id}")
293300

294301

295-
def get_env_ids_to_install(env_configs: list[EnvConfig] | list[EvalEnvConfig]) -> set[str]:
296-
"""Get the list of environment IDs to install."""
297-
env_ids_to_install = set()
302+
def get_env_ids_to_install(env_configs: list[EnvConfig] | list[EvalEnvConfig]) -> dict[str, bool]:
303+
"""Get the environments to install with their no_upgrade settings.
304+
305+
Returns:
306+
Dict mapping env_id -> no_upgrade. If the same env appears multiple times
307+
with different settings, no_upgrade=True takes precedence.
308+
"""
309+
env_ids_to_install: dict[str, bool] = {}
298310
for env_config in env_configs:
299311
if "/" in env_config.id:
300-
env_ids_to_install.add(env_config.id)
312+
# If env already exists, preserve no_upgrade=True if either has it
313+
existing = env_ids_to_install.get(env_config.id, False)
314+
env_ids_to_install[env_config.id] = existing or env_config.no_upgrade
301315
return env_ids_to_install

0 commit comments

Comments
 (0)