|
| 1 | +# Harbor adapter for Corbits Code |
| 2 | + |
| 3 | +Thin Harbor `BaseInstalledAgent` that runs headless product Corbits: |
| 4 | + |
| 5 | +```text |
| 6 | +corbits exec --cwd … --config … --provider … --model … |
| 7 | + --dangerously-skip-permissions <instruction> |
| 8 | +``` |
| 9 | + |
| 10 | +No second agent loop. Credentials are translated from Harbor kwargs/env into a |
| 11 | +temporary `settings.json` passed with `--config` — product Corbits still does |
| 12 | +not read API keys from the environment. |
| 13 | + |
| 14 | +## Layout |
| 15 | + |
| 16 | +| Path | Role | |
| 17 | +| ----------------------- | ------------------------------------------------------ | |
| 18 | +| `argv.py` | Pure settings + argv builders (unit-tested, no Harbor) | |
| 19 | +| `session.py` | Parse harvested `~/.corbits` usage (unit-tested) | |
| 20 | +| `agent.py` | `Corbits` installed agent (requires Harbor at import) | |
| 21 | +| `tasks/trivial/` | Minimal smoke task (`hello.txt`) | |
| 22 | +| `tests/test_argv.py` | Argv/settings unit tests | |
| 23 | +| `tests/test_session.py` | Session usage harvest unit tests | |
| 24 | + |
| 25 | +## Prerequisites |
| 26 | + |
| 27 | +1. **Harbor CLI** installed in the host Python env (`pip install harbor` / uv). |
| 28 | +2. **Linux ELF `corbits` binary** for the task container (Darwin host builds |
| 29 | + will not run inside Linux Docker). Acquire one of: |
| 30 | + - Build on Linux: `bun run build:bin` → `dist/corbits` |
| 31 | + - Release / CI tarball that unpacks a `corbits` binary |
| 32 | +3. **git** inside the task image (adapter also installs it via Harbor system |
| 33 | + packages). Corbits storage requires git — there is no git-less fallback. |
| 34 | +4. **Provider API key** for the model under test. |
| 35 | +5. **Provider `base_url`** — stock Harbor `-m xai/…` infers `https://api.x.ai/v1`. Override only when the catalog default is wrong. The adapter fail-closes if nothing resolves. |
| 36 | + |
| 37 | +## Secrets / credentials |
| 38 | + |
| 39 | +Pass a key through Harbor agent kwargs or env. The adapter writes it into the |
| 40 | +temp settings file only: |
| 41 | + |
| 42 | +| Source | Notes | |
| 43 | +| ----------------------- | ---------------------------------------------- | |
| 44 | +| `api_key=` agent kwarg | Preferred for one-off runs | |
| 45 | +| `CORBITS_API_KEY` | Generic adapter env | |
| 46 | +| `{PROVIDER}_API_KEY` | Only the selected provider, e.g. `XAI_API_KEY` | |
| 47 | +| Harbor model connection | Falls back to `model_connection.api_key` | |
| 48 | + |
| 49 | +### Required base URL |
| 50 | + |
| 51 | +`providers.<provider>.baseURL` is always written. Resolve it via one of: |
| 52 | + |
| 53 | +| Source | Notes | |
| 54 | +| ----------------------- | ----------------------------------------------------------------------------------------- | |
| 55 | +| `base_url=` agent kwarg | Preferred for one-off runs | |
| 56 | +| Harbor configured URL | `model_connection.configured_base_url` (`CORBITS_BASE_URL` / `XAI_BASE_URL` / …) | |
| 57 | +| Harbor inferred catalog | `model_connection.base_url` — e.g. xAI → `https://api.x.ai/v1` when an API key is present | |
| 58 | +| `CORBITS_BASE_URL` | Adapter env (also feeds Harbor configured URL) | |
| 59 | + |
| 60 | +Stock `harbor run -m xai/grok-4.5` with `XAI_API_KEY` therefore does **not** need an explicit `base_url`. The adapter still fail-closes if nothing resolves. |
| 61 | + |
| 62 | +Do **not** point Harbor cells at the grok-cli OAuth proxy (`https://cli-chat-proxy.grok.com/v1`). That URL only accepts OAuth tokens from `~/.corbits/xai-auth.json`, which Harbor containers do not have. Profile-qualified product cells (`xai/<profile>`, `codex/<profile>`) are OAuth; use an API-key provider name (`xai`, `openai`, …) inside Harbor. |
| 63 | + |
| 64 | +Example values: |
| 65 | + |
| 66 | +| Cell | Example `base_url` | |
| 67 | +| ----------------------------- | ------------------------------------------------------- | |
| 68 | +| xAI API key | `https://api.x.ai/v1` (Harbor infers this) | |
| 69 | +| Product OAuth / grok-cli path | Not usable in Harbor containers | |
| 70 | +| OpenAI-compatible | e.g. `https://api.openai.com/v1` or your cell's gateway | |
| 71 | + |
| 72 | +Optional: `shell_timeout_ms=` → `shell.timeoutMs` in settings. |
| 73 | + |
| 74 | +Default provider/model when Harbor does not pass `provider/model`: **xai** / |
| 75 | +**grok-4.5**. Codex cells typically use `--model openai/<id>` (or pass |
| 76 | +`provider=` / `model=` kwargs). |
| 77 | + |
| 78 | +## Linux binary acquisition |
| 79 | + |
| 80 | +The adapter installs the binary onto PATH from **one** of: |
| 81 | + |
| 82 | +| Kwarg | Behavior | |
| 83 | +| --------------------- | ------------------------------------------------- | |
| 84 | +| `corbits_binary_path` | Upload a host file into `/usr/local/bin/corbits` | |
| 85 | +| `corbits_binary_url` | `curl` a raw binary URL | |
| 86 | +| `corbits_tarball_url` | `curl` + extract; expects a `corbits` file inside | |
| 87 | + |
| 88 | +Archive vs raw binary is detected from the URL suffix (`.tar.gz`, `.tgz`, |
| 89 | +`.tar`) — the install script does not call `file(1)`. |
| 90 | + |
| 91 | +If none are set and `corbits` is not already on PATH in the environment, |
| 92 | +`install()` raises with this README pointer. |
| 93 | + |
| 94 | +## Invoke |
| 95 | + |
| 96 | +From the repo root (so `evals.harbor.agent` is importable): |
| 97 | + |
| 98 | +```bash |
| 99 | +# Unit tests (no Harbor package required; pytest may be absent) |
| 100 | +PYTHONPATH=. python3 -m unittest evals.harbor.tests.test_argv evals.harbor.tests.test_session -v |
| 101 | + |
| 102 | +# Dry-run trivial task (needs Harbor CLI + Linux binary + API key) |
| 103 | +export CORBITS_API_KEY=… # or XAI_API_KEY=… |
| 104 | +harbor run \ |
| 105 | + -p evals/harbor/tasks/trivial \ |
| 106 | + -a evals.harbor.agent:Corbits \ |
| 107 | + -m xai/grok-4.5 \ |
| 108 | + --ak corbits_binary_path=/absolute/path/to/linux/corbits |
| 109 | +``` |
| 110 | + |
| 111 | +Equivalent kwargs via Harbor job config: |
| 112 | + |
| 113 | +```yaml |
| 114 | +agents: |
| 115 | + - name: evals.harbor.agent:Corbits |
| 116 | + kwargs: |
| 117 | + provider: xai |
| 118 | + model: grok-4.5 |
| 119 | + api_key: ${CORBITS_API_KEY} |
| 120 | + base_url: https://api.x.ai/v1 |
| 121 | + corbits_binary_path: /absolute/path/to/linux/corbits |
| 122 | + # or: corbits_tarball_url: https://…/corbits-linux.tar.gz |
| 123 | +``` |
| 124 | + |
| 125 | +Harbor's own trial/job timeout is the only wall-clock cap. Do **not** wrap |
| 126 | +`harbor run` in a parent tool timeout — killing the CLI mid-trial wastes the |
| 127 | +tokens already spent and leaves no verifier result. |
| 128 | + |
| 129 | +After each trial Harbor copies `/logs/agent`. The adapter tars `~/.corbits` |
| 130 | +there as `corbits-home.tar.gz` and fills `AgentContext` token fields from |
| 131 | +session `metadata.json`. `cost_usd` is set only when the harvested |
| 132 | +`models-pricing.json` cache has that model; unknown cells stay `null` rather |
| 133 | +than inventing a rate. Tool traces are under |
| 134 | +`agent/corbits-home/.corbits/projects/…/turns-*.jsonl`. |
| 135 | + |
| 136 | +## Known gaps |
| 137 | + |
| 138 | +- Trivial Harbor dry-run has been run locally (`hello.txt`, verifier reward 1.0) |
| 139 | + with OpenCode Go `mimo-v2.5`. Cost-capped Terminal-Bench smoke is the parent |
| 140 | + ticket **CL-6922** (the old CL-6924 slice ticket was canceled). |
| 141 | +- This adapter does not convert Corbits trajectories into Harbor ATIF. Usage |
| 142 | + and the session tar are enough to audit a trial without that conversion. |
0 commit comments