fix: LLM endpoint full base URLs (from #1189) - #1237
Conversation
On-repo replacement of #1189 (surajsharan) for CI/merge into the 0.6.0 cut. Parse --llm-endpoint as a URL: append /v1 when pathless, append port only when the URL has none, reject bad schemes/hosts/credentials/query/fragment and out-of-range ports. Co-authored-by: surajsharan <surajsharan@users.noreply.github.com>
There was a problem hiding this comment.
Alignment Review Report
Two-tier review of the --llm-endpoint / OpenAIClient full-base-URL change (diff c32c317...48581f5).
Automated Checks
- Lint: PASS (changed files) —
usort check,ruff format --check, andruff checkare all clean on this PR'ssrc/andtests/files. The repo-wide hook reports only pre-existing failures (envs/*, and the two knowntests/envs/test_grid_world.py/test_julia_env.pyusort files), none touched here.examples/ttt_collect_with_llm.pyhas a pre-existing format/import-sort nit at ~line 217 that is outside this PR's hunks and outside the hook'ssrc/ tests/ envs/scope. CIlintjob: pass. - Debug code: CLEAN — no bare
print(),breakpoint(),pdb/ipdb, or newTODO/FIXMEin the changed files. The one addedconsole.print(...)is the established Rich logging pattern used throughoutcollect.py(aprint(-substring false positive from the hook).
Open RFCs Context
All RFCs are currently In Review or Draft (none Accepted/Implemented). Two are thematically adjacent:
- RFC 005 – Agentic Harness Integration (In Review, @Darktex):
collectdrives the MCP harness and RFC 005 lists an "LLM Endpoint (vLLM/Claude API)" component. This PR does not touch the harness architecture or/harnessendpoint → relevant context, no conflict. - RFC 012 – Harbor Capture Providers (In Review, @adithya-s-k): formalizes an upstream
providerdescriptor (openai|anthropic|hf|vllm), endpoint reachability, and credential-scoped client caching. See RFC Conflicts below.
Tier 1: Fixes Required
None. The change is well-contained and covered by ~313 lines of new tests (URL forms, malformed / credential / conflicting-port cases, and an end-to-end SDK request-path test via httpx.MockTransport). CI is green across lint, test (3.11), test (3.12), package smoke-test, and Docker runtime validation. Verified statically:
typer.BadParameterandconsoleare already imported/available incollect.py.- Moving the
model_stepbuild ahead ofserializer.write_metadata(...)is safe (all referenced vars are defined at the new position) and correctly makes a bad endpoint fail before any output is written. - Hosted providers are unaffected:
_HOSTED_PROVIDERSstill passes:443, socreate_llm_client("openai"/"anthropic")resolves to the same base URLs as before.
Tier 2: Alignment Discussion
Principle Conflicts
None identified. Core llm_client.py imports no server/ code; rewards/Gymnasium API are untouched; scope is teacher-LLM configuration only.
Positive alignment worth calling out:
- Upholds INVARIANT “No credential exposure” —
_redact_userinfo()stripsuser:password@before any endpoint is echoed in an error, and credentials embedded in--llm-endpointare rejected outright with a pointer toOPENAI_API_KEY. A dedicated test asserts the secret never leaks into the error string. This directly reinforces INVARIANTS.md §Security/3 (@Darktex).
RFC Conflicts
ALIGNMENT FLAG: Endpoint/provider handling overlaps RFC 012's upstream descriptor
- Principle/RFC at stake: RFC 012 – Harbor Capture Providers (In Review)
- The concern: This PR adds ad-hoc endpoint URL parsing/validation (
_join_endpoint_port,_openai_base_url) plus a lightweightprovidernotion in the localcollectpath. RFC 012 proposes a formal upstream descriptor withprovider ∈ {openai, anthropic, hf, vllm}, endpoint-reachability rules, and credential-identity-scoped client caching for the Harbor capture server. These are different subsystems (local rollout collection vs. Harbor capture), so this is not a direct conflict — but the team may want the two endpoint/provider models to converge rather than diverge (e.g. a futurevllmprovider, shared URL validation). - Suggested reviewer: @adithya-s-k (RFC 012 author); @Darktex (RFC 005 / security invariant)
Behavior-Change Note (for the 0.6.0 changelog)
--llm-portloses its implicit8000default and--llm-endpointis now a full base URL, so--llm-endpoint http://localhostresolves to port 80, not 8000. This is a CLI breaking change, documented in help text,docs/, and the harness README. Per INVARIANTS “Breaking Change Policy” (pre-1.0, documented) this is acceptable; the PR body notes it was explicitly approved and folded into the 0.6.0 cut. Flagging only so it lands in the release notes.
Summary
- 0 mechanical issues to fix (Tier 1 clean; CI green)
- 1 alignment point for human review (RFC 012 convergence) + 1 release-note behavior change
- 1 RFC area to discuss (RFC 012); RFC 005 relevant as context only
Note: this PR is already merged; posting as an informational review.
Sent by Cursor Automation: Pre-review
OpenEnv 0.6.0 Breaking change - `--llm-endpoint` / OpenAIClient now take a full base URL; the implicit port 8000 is gone. `http://localhost` means port 80; use `http://localhost:8000` or `--llm-port 8000` for the old behavior (#1189, landed via #1237). New - NovitaSandboxProvider: run an OpenEnv server in a Novita AI sandbox over wss://, from a registry image or a local Dockerfile; install with `pip install openenv[novita]` (#1191). - RFC 008 Level 2 validation building blocks: manifest-v2, report-v2 and runtime-plan schemas, the severity-v2 policy, and DockerValidationProvider (#1178, #1179). The `openenv validate` CLI is unchanged in this release. Fixes - A failed `new_session()` no longer leaves the provider's container or sandbox running (#1145). Repository and environment images (not in the wheel) - coding_env `additional_imports` now extends the default safe-import allowlist (#1147). - Environment lockfile security updates: anyio 4.14.2 and soupsieve 2.9.2 (#1196, #1197, #1201, #1202). - CI hardening: per-job GITHUB_TOKEN scopes and SHA-pinned actions (#1221, #1223, #1225, #1226, #1228, #1239, #1240); validation-lab toolchain pins (#1229, #1230, #1231); docs navigation and Miles integration docs (#1219, #1220). Known, accepted for this release: Novita provider debt (unbraced $ARG ordering in Dockerfile flattening, a tbench2 example readiness leak); fixes follow in #1235. Validated: exact-head CI 13/13 on 0034202; TestPyPI 0.6.0.dev141 (run 35854754769) byte-identical to the release wheel apart from Version; clean wheel/sdist install, CLI, and Echo reset/step smoke.


Summary
On-repo replacement of #1189 (surajsharan) so we can run repository CI and fold into the 0.6.0 cut per Ben’s ask.
--llm-endpoint/OpenAIClientnow parse the endpoint as a URL:/v1when pathless; keep an existing path (gateway/proxy)portonly when the URL has none; reject conflictsBen APPROVED the fork tip (
e421de47) including the documented removal of implicit port 8000.Type of Change
Alignment Checklist
Before submitting, verify:
.claude/docs/PRINCIPLES.mdand this PR aligns with our principles.claude/docs/INVARIANTS.mdand no invariants are violatedRFC Status
Test Plan
PYTHONPATH=src:envs uv run pytest tests/core/test_llm_client.py tests/test_cli/test_collect.py -q— 105 passedruff check/ruff format --checkon changed Python — cleanClaude Code Review
N/A — release-automation on-repo replacement of Ben-approved #1189.
Note
Medium Risk
Changes how self-hosted LLM URLs are resolved and removes the implicit port-8000 default, which can break existing scripts; rollout collection depends on correct endpoint parsing but is heavily tested.
Overview
Self-hosted teacher URLs for
openenv collectandOpenAIClientnow treat--llm-endpointas a fullhttp(s)base URL instead of host + fixed port./v1is added only when the URL has no path; gateway paths (e.g./openai/v1) are left unchanged.--llm-portis optional with no default (previously 8000), sohttp://localhostwithout a port uses 80.Invalid endpoints fail early with clear CLI errors: wrong scheme, credentials in the URL, query/fragment, conflicting ports, and out-of-range ports. Secrets are redacted in error messages.
openenv collectprints the resolved LLM endpoint and builds the teacher client before writing rollout metadata so bad URLs do not start a partial run.Docs and examples (CLI reference, SFT warmup, harness README,
ttt_collect_with_llm.py) are updated for vLLM/TGI/Ollama-style endpoints; tests cover URL resolution and request paths end-to-end.Reviewed by Cursor Bugbot for commit 48581f5. Bugbot is set up for automated code reviews on this repo. Configure here.