Skip to content

[3/6][misc] feat: package rollout projects into installable wheel bundles - #285

Merged
mathewjhan merged 1 commit into
mainfrom
mathew/packaging
Aug 6, 2026
Merged

[3/6][misc] feat: package rollout projects into installable wheel bundles#285
mathewjhan merged 1 commit into
mainfrom
mathew/packaging

Conversation

@mathewjhan

@mathewjhan mathewjhan commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Part of splitting #272 into reviewable pieces (3/6).

What this adds

osmosis_ai/packaging.py: builds a standard Python wheel from a user's rollout project so the project can be installed inside a task container with one pip install.

  • build_bundle(project_dir, workflow=..., grader=...) produces a wheel containing the project's package plus a generated bundle_main.py shim. The shim imports the user's classes directly (from my_harness.solver import MyWorkflow) and exposes two console scripts, <package>-agent and <package>-grade, which call the runner entrypoints from [2/6][rollout] feat: container contract, workflow output types, in-container runner #284. Nothing is resolved dynamically at runtime; the class binding happens at build time.
  • Wheels are cached by a content hash of the project files under the user cache directory (platformdirs), so rebuilding an unchanged project is free.
  • inspect_bundle(wheel) reads the wheel's metadata with importlib.metadata and returns the declared dependencies (keeping environment markers, dropping extras-gated entries) plus the two script names. The Harbor backend (next in the stack) uses this list to pre-install dependencies into the task image.

Also includes the bench_harness fixture project the packaging tests build against, and the platformdirs dependency.

Example

from osmosis_ai.packaging import build_bundle, inspect_bundle

wheel = build_bundle(
    Path("my_rollout_project"),
    workflow="my_harness.solver:MyWorkflow",
    grader="my_harness.grade:MyGrader",
)
info = inspect_bundle(wheel)
info.agent_script    # "my-harness-agent"
info.requirements    # ["strands-agents>=1.0", "httpx>=0.27", ...]

Inside a container, pip install my_harness-0.1.0-py3-none-any.whl followed by running my-harness-agent executes the user's workflow with no other setup.

@mathewjhan mathewjhan changed the title [misc] feat: package rollout projects into installable wheel bundles [3/6][misc] feat: package rollout projects into installable wheel bundles Aug 6, 2026
Base automatically changed from mathew/container-contract to main August 6, 2026 22:31
Co-authored-by: Cursor <cursoragent@cursor.com>
@mathewjhan
mathewjhan merged commit 91b0157 into main Aug 6, 2026
1 check passed
@mathewjhan
mathewjhan deleted the mathew/packaging branch August 6, 2026 22:31
mathewjhan added a commit that referenced this pull request Aug 6, 2026
Part of splitting #272 into reviewable pieces (4/6). Builds on #284
(container contract) and #285 (packaging).

## What this adds

`HarborBackendV2`: runs each rollout as a Harbor trial. The agent can be
either a user workflow (packaged into a wheel and installed in the
container at trial start) or a registered native Harbor agent
(`terminus-2`, `mini-swe-agent`, `oracle`) with the rollout endpoint
injected into its environment.

How a rollout flows through it:

1. **Task selection** (`tasks.py`): template mode uses one task
directory for every rollout; dataset mode routes by
`metadata["harbor_task_id"]` to a folder under `tasks_dir` (path escapes
rejected); `metadata["harbor_task"]` fetches a task from a local path,
git checkout, or registry package, with per-ref locks so concurrent
rollouts download once.
2. **Materialization**: the task is copied into a per-rollout directory;
the rollout's input file is staged; if the task has no `tests/` and a
grader exists, a `test.sh` is generated that installs and runs the
grader. The ground-truth label is staged only into `tests/`, which
Harbor uploads at verification time — the agent phase cannot read it.
3. **Image preparation**: `patch_dockerfile_with_sdk` appends a block to
the task's Dockerfile that installs a static `uv` binary and creates
`/opt/osmosis/venv` with the bundle's dependencies pre-installed.
Per-trial installs then only add the user's own code (`--no-deps`),
which cuts container startup from minutes to seconds. The patch is
deterministic, so identical tasks keep identical image content hashes
and share builds.
4. **Execution** (`harness_agent.py`): the installed agent uploads the
wheel, installs it into the venv, backfills an empty prompt from the
task's `instruction.md`, runs the agent script, and returns the result
through the trial's agent metadata.
5. **Callbacks**: the workflow-complete callback fires when verification
starts (agent phase over); the grader-complete callback fires at trial
end with the reward parsed from Harbor's verifier result. Callback
delivery failures are logged and never abort trial archival.
6. **Observability and lifecycle**: per-phase timings and failure phases
in every result (`diagnostics.py`), native-agent ATIF parsing with
secret redaction, artifact relocation, `prewarm()` /
`prewarm_lifespan()` to build task images before serving traffic,
`cancel_rollouts(ids | prefix | all)`, `rollout_status()` with terminal
outcomes retained in a `TtlCache` (#283), and admission control via
`max_queue_depth`.

## Example

```python
backend = HarborBackendV2(
    orchestrator=TrialQueue(n_concurrent=100),
    tasks_dir=Path("tasks"),           # 300 task folders
    task_mode="dataset",
    agent=MyWorkflow,                  # or agent="mini-swe-agent"
    workflow_config=my_config,
    environment_config=EnvironmentConfig(type=EnvironmentType.SKYPILOT),
)
app = create_rollout_server(
    backend=backend,
    lifespan=backend.prewarm_lifespan(task_ids=["task-0000"]),
)
```

A trainer then POSTs rollouts with `metadata={"harbor_task_id":
"task-0042"}`; each one runs in its own sandbox and reports back through
the callbacks.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added the enhancement New feature or request label Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants