self-bench 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +0 -1
- package/Dockerfile +2 -1
- package/Dockerfile.sandbox +1 -1
- package/README.md +114 -170
- package/bun.lock +60 -12
- package/compose.yaml +11 -5
- package/dist/agent-smoke-main.js +3 -2
- package/dist/agent-smoke-main.js.map +1 -1
- package/dist/agent-smoke.d.ts +2 -1
- package/dist/agent-smoke.d.ts.map +1 -1
- package/dist/agent-smoke.js +6 -1
- package/dist/agent-smoke.js.map +1 -1
- package/dist/api.d.ts +24 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +65 -20
- package/dist/api.js.map +1 -1
- package/dist/artifacts.d.ts +0 -1
- package/dist/artifacts.d.ts.map +1 -1
- package/dist/artifacts.js +0 -3
- package/dist/artifacts.js.map +1 -1
- package/dist/build-metadata.js +1 -1
- package/dist/cli.js +75 -11
- package/dist/cli.js.map +1 -1
- package/dist/codex-review.d.ts +2 -1
- package/dist/codex-review.d.ts.map +1 -1
- package/dist/codex-review.js +26 -22
- package/dist/codex-review.js.map +1 -1
- package/dist/config.d.ts +36 -11
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +89 -17
- package/dist/config.js.map +1 -1
- package/dist/contracts.d.ts +23 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +31 -6
- package/dist/contracts.js.map +1 -1
- package/dist/eval-main.js +5 -4
- package/dist/eval-main.js.map +1 -1
- package/dist/evaluate.d.ts +2 -1
- package/dist/evaluate.d.ts.map +1 -1
- package/dist/evaluate.js +14 -8
- package/dist/evaluate.js.map +1 -1
- package/dist/harbor-environment.d.ts +2 -0
- package/dist/harbor-environment.d.ts.map +1 -0
- package/dist/harbor-environment.js +15 -0
- package/dist/harbor-environment.js.map +1 -0
- package/dist/harbor-results.d.ts.map +1 -1
- package/dist/harbor-results.js +2 -0
- package/dist/harbor-results.js.map +1 -1
- package/dist/process.d.ts +2 -1
- package/dist/process.d.ts.map +1 -1
- package/dist/process.js.map +1 -1
- package/dist/provenance.d.ts +0 -1
- package/dist/provenance.d.ts.map +1 -1
- package/dist/provenance.js.map +1 -1
- package/dist/providers.d.ts +8 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +14 -0
- package/dist/providers.js.map +1 -0
- package/dist/reaudit-main.js +14 -11
- package/dist/reaudit-main.js.map +1 -1
- package/dist/repair-main.js +12 -9
- package/dist/repair-main.js.map +1 -1
- package/dist/review/assets/index-CZ3G759O.js +1568 -0
- package/dist/review/assets/index-DgSLzX8l.css +1 -0
- package/dist/review/assets/{mojo-Blby8dQK.js → mojo-DJz3ZmWd.js} +1 -1
- package/dist/review/assets/typst-BUadGCkm.js +1 -0
- package/dist/review/index.html +2 -2
- package/dist/sandbox-author.bundle.js +40 -6
- package/dist/sandbox-repair.bundle.js +8 -7
- package/dist/sandbox-repair.js +7 -7
- package/dist/sandbox-repair.js.map +1 -1
- package/dist/sandbox-review.bundle.js +29 -25
- package/dist/sandbox-review.js +5 -3
- package/dist/sandbox-review.js.map +1 -1
- package/dist/sandbox-timeout.d.ts +11 -0
- package/dist/sandbox-timeout.d.ts.map +1 -0
- package/dist/sandbox-timeout.js +41 -0
- package/dist/sandbox-timeout.js.map +1 -0
- package/dist/sandbox-validation-repair.bundle.js +49 -15
- package/dist/sandbox-validation-repair.js +11 -9
- package/dist/sandbox-validation-repair.js.map +1 -1
- package/dist/sandbox.d.ts +2 -2
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +10 -3
- package/dist/sandbox.js.map +1 -1
- package/dist/subscription-auth.d.ts +12 -1
- package/dist/subscription-auth.d.ts.map +1 -1
- package/dist/subscription-auth.js +16 -16
- package/dist/subscription-auth.js.map +1 -1
- package/dist/{activities.d.ts → temporal/activities.d.ts} +3 -4
- package/dist/temporal/activities.d.ts.map +1 -0
- package/dist/{activities.js → temporal/activities.js} +51 -34
- package/dist/temporal/activities.js.map +1 -0
- package/dist/{temporal.d.ts → temporal/connection.d.ts} +2 -2
- package/dist/temporal/connection.d.ts.map +1 -0
- package/dist/{temporal.js → temporal/connection.js} +1 -1
- package/dist/temporal/connection.js.map +1 -0
- package/dist/{worker-main.d.ts.map → temporal/worker-main.d.ts.map} +1 -1
- package/dist/{worker-main.js → temporal/worker-main.js} +6 -10
- package/dist/temporal/worker-main.js.map +1 -0
- package/dist/{workflow.d.ts → temporal/workflow.d.ts} +1 -1
- package/dist/temporal/workflow.d.ts.map +1 -0
- package/dist/temporal/workflow.js.map +1 -0
- package/dist/terminal-prompts.d.ts +26 -0
- package/dist/terminal-prompts.d.ts.map +1 -0
- package/dist/terminal-prompts.js +137 -0
- package/dist/terminal-prompts.js.map +1 -0
- package/dist/terminal-reporter.d.ts +30 -0
- package/dist/terminal-reporter.d.ts.map +1 -0
- package/dist/terminal-reporter.js +90 -0
- package/dist/terminal-reporter.js.map +1 -0
- package/dist/validate-main.js +8 -2
- package/dist/validate-main.js.map +1 -1
- package/dist/vercel-cli.d.ts +64 -0
- package/dist/vercel-cli.d.ts.map +1 -0
- package/dist/vercel-cli.js +303 -0
- package/dist/vercel-cli.js.map +1 -0
- package/dist/vercel-command.d.ts +14 -0
- package/dist/vercel-command.d.ts.map +1 -0
- package/dist/vercel-command.js +93 -0
- package/dist/vercel-command.js.map +1 -0
- package/dist/vercel-executor.d.ts +14 -0
- package/dist/vercel-executor.d.ts.map +1 -0
- package/dist/vercel-executor.js +356 -0
- package/dist/vercel-executor.js.map +1 -0
- package/dist/vercel-fetch.d.ts +6 -0
- package/dist/vercel-fetch.d.ts.map +1 -0
- package/dist/vercel-fetch.js +39 -0
- package/dist/vercel-fetch.js.map +1 -0
- package/dist/vercel-profile.d.ts +34 -0
- package/dist/vercel-profile.d.ts.map +1 -0
- package/dist/vercel-profile.js +244 -0
- package/dist/vercel-profile.js.map +1 -0
- package/dist/vercel-runtime-image.d.ts +51 -0
- package/dist/vercel-runtime-image.d.ts.map +1 -0
- package/dist/vercel-runtime-image.js +123 -0
- package/dist/vercel-runtime-image.js.map +1 -0
- package/dist/vercel-setup-probe.d.ts +49 -0
- package/dist/vercel-setup-probe.d.ts.map +1 -0
- package/dist/vercel-setup-probe.js +151 -0
- package/dist/vercel-setup-probe.js.map +1 -0
- package/dist/vercel-setup.d.ts +42 -0
- package/dist/vercel-setup.d.ts.map +1 -0
- package/dist/vercel-setup.js +280 -0
- package/dist/vercel-setup.js.map +1 -0
- package/docs/evaluations.md +15 -12
- package/docs/operations.md +134 -21
- package/package.json +8 -6
- package/src/agent-smoke-main.ts +3 -2
- package/src/agent-smoke.ts +8 -2
- package/src/api.ts +71 -20
- package/src/artifacts.ts +0 -4
- package/src/cli.ts +81 -11
- package/src/codex-review.ts +63 -54
- package/src/config.ts +150 -28
- package/src/contracts.ts +33 -11
- package/src/eval-main.ts +5 -4
- package/src/evaluate.ts +18 -11
- package/src/harbor-environment.ts +17 -0
- package/src/harbor-results.ts +2 -0
- package/src/process.ts +3 -1
- package/src/provenance.ts +0 -1
- package/src/providers.ts +22 -0
- package/src/reaudit-main.ts +17 -11
- package/src/repair-main.ts +15 -9
- package/src/sandbox-repair.ts +7 -11
- package/src/sandbox-review.ts +5 -3
- package/src/sandbox-timeout.ts +56 -0
- package/src/sandbox-validation-repair.ts +13 -10
- package/src/sandbox.ts +15 -5
- package/src/subscription-auth.ts +30 -17
- package/src/{activities.ts → temporal/activities.ts} +53 -42
- package/src/{temporal.ts → temporal/connection.ts} +1 -1
- package/src/{worker-main.ts → temporal/worker-main.ts} +6 -10
- package/src/{workflow.ts → temporal/workflow.ts} +10 -10
- package/src/terminal-prompts.ts +197 -0
- package/src/terminal-reporter.ts +126 -0
- package/src/validate-main.ts +9 -3
- package/src/vercel-cli.ts +403 -0
- package/src/vercel-command.ts +127 -0
- package/src/vercel-executor.ts +448 -0
- package/src/vercel-fetch.ts +45 -0
- package/src/vercel-profile.ts +319 -0
- package/src/vercel-runtime-image.ts +204 -0
- package/src/vercel-setup-probe.ts +229 -0
- package/src/vercel-setup.ts +419 -0
- package/dist/activities.d.ts.map +0 -1
- package/dist/activities.js.map +0 -1
- package/dist/extensions/review.d.ts +0 -3
- package/dist/extensions/review.d.ts.map +0 -1
- package/dist/extensions/review.js +0 -44
- package/dist/extensions/review.js.map +0 -1
- package/dist/review/assets/index-Dq-6DFzI.css +0 -1
- package/dist/review/assets/index-DurW_RD7.js +0 -1567
- package/dist/review/assets/typst-DHCkPAjA.js +0 -1
- package/dist/temporal.d.ts.map +0 -1
- package/dist/temporal.js.map +0 -1
- package/dist/worker-main.js.map +0 -1
- package/dist/workflow.d.ts.map +0 -1
- package/dist/workflow.js.map +0 -1
- package/src/extensions/review.ts +0 -54
- /package/dist/{worker-main.d.ts → temporal/worker-main.d.ts} +0 -0
- /package/dist/{workflow.js → temporal/workflow.js} +0 -0
package/docs/operations.md
CHANGED
|
@@ -18,23 +18,29 @@ Temporal and artifact state live in the `selfbench_temporal-postgres` and `selfb
|
|
|
18
18
|
|
|
19
19
|
## Credentials
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
self-bench requires GitHub and model credentials:
|
|
22
22
|
|
|
23
23
|
- `gh auth login` supplies read access to merged pull requests. Export `GH_TOKEN="$(gh auth token)"` for the worker. Write access is not required.
|
|
24
|
-
-
|
|
25
|
-
- `~/.codex/auth.json` powers the constrained repair step and agent evaluation.
|
|
24
|
+
- `OPENAI_API_KEY` powers discovery, authoring, review, constrained repair, and model evaluation. This is the recommended model-authentication path.
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
Existing deployments may continue using ChatGPT subscription authentication by providing both `SELFBENCH_PI_AUTH_JSON` and `SELFBENCH_CODEX_AUTH_JSON`. API-key authentication takes precedence when `OPENAI_API_KEY` is set.
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
Sandbox-provider credentials are separate. Modal accepts its mounted profile or token pair. For a local Vercel worker, `self-bench setup vercel` stores a project-scoped token in an owner-only local profile. Unattended workers use the equivalent `VERCEL_TOKEN`, `VERCEL_TEAM_ID`, and `VERCEL_PROJECT_ID` environment variables. Keep provider credentials on the worker; the API does not need them.
|
|
29
|
+
|
|
30
|
+
## Execution backends and Harbor
|
|
31
|
+
|
|
32
|
+
SelfBench uses one provider for discovery, authoring, semantic review, and repair sandboxes. It separately invokes Harbor for nop/oracle validation. Docker and Modal default Harbor to the matching environment. Vercel has no Harbor environment, so `--harbor-environment docker|modal` is mandatory.
|
|
30
33
|
|
|
31
34
|
```bash
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
self-bench up
|
|
35
|
+
self-bench up --backend docker # Docker + Docker
|
|
36
|
+
self-bench up --backend modal # Modal + Modal
|
|
37
|
+
self-bench up --backend vercel --harbor-environment docker
|
|
38
|
+
self-bench up --backend vercel --harbor-environment modal
|
|
39
|
+
self-bench up --backend docker --harbor-environment modal
|
|
40
|
+
self-bench up --backend modal --harbor-environment docker
|
|
35
41
|
```
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
Use `--modal-config` whenever either side uses Modal. A worker has one fixed pairing; do not run workers with different provider settings on the same Temporal task queue. Run and export metadata record both choices, plus the effective Vercel timeout cap when applicable.
|
|
38
44
|
|
|
39
45
|
### Docker
|
|
40
46
|
|
|
@@ -59,10 +65,95 @@ self-bench up --backend modal
|
|
|
59
65
|
self-bench up --backend modal --modal-config /absolute/path/to/.modal.toml
|
|
60
66
|
```
|
|
61
67
|
|
|
62
|
-
|
|
68
|
+
When Modal is used for generation or Harbor, SelfBench mounts `~/.modal.toml` by default; `--modal-config` overrides that path. A secret manager may provide `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET` instead. Empty token environment variables are removed at worker startup so they cannot override a valid mounted profile.
|
|
63
69
|
|
|
64
70
|
Modal defaults to 20 concurrent worker activities. Discovery starts eight independently retryable shards, and candidate slots are continuously refilled. Discovery and authoring stop after eight minutes without process output; review stops after five. Discovery also has a 45-minute per-attempt deadline and up to three attempts per shard.
|
|
65
71
|
|
|
72
|
+
### Vercel Sandbox
|
|
73
|
+
|
|
74
|
+
Vercel is a generation backend only; choose Docker or Modal for Harbor. SelfBench supports both Vercel's 45-minute Hobby Sandbox ceiling and the longer paid-team ceiling. Discovery requests 45 minutes, review requests 15 minutes, and authoring and repair request two hours; setup detects the selected project's effective capability and caps every Vercel stage centrally when necessary. Sandbox use, VCR storage, memory, active CPU, and data transfer are metered by Vercel; configure Spend Management before unattended runs. Vercel Hobby use is intended for personal, non-commercial work.
|
|
75
|
+
|
|
76
|
+
#### Interactive local setup
|
|
77
|
+
|
|
78
|
+
Install the current Vercel CLI and make sure Docker is available for the runtime-image build:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install --global vercel@latest
|
|
82
|
+
self-bench setup vercel
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Interactive setup keeps long-running publication and capability checks compact, with a live elapsed timer that freezes when each step completes. Use `self-bench setup vercel --verbose` to stream the underlying Vercel CLI and Docker build output; compact mode reveals retained command output automatically when a step fails.
|
|
86
|
+
|
|
87
|
+
Setup uses Vercel CLI browser login for control-plane selection and VCR publication. It then:
|
|
88
|
+
|
|
89
|
+
1. shows a searchable team or personal-scope picker;
|
|
90
|
+
2. offers a searchable existing-project picker or creation of a dedicated project;
|
|
91
|
+
3. asks for a project name, defaulting to `selfbench-sandbox`, and retries rather than silently suffixing an unavailable name;
|
|
92
|
+
4. publishes the pinned `Dockerfile.sandbox` runtime to the project's `selfbench-runtime` VCR repository;
|
|
93
|
+
5. prints the Vercel token page and asks for a manually created access token restricted to the selected project, with terminal echo disabled;
|
|
94
|
+
6. creates and immediately deletes a one-vCPU, nonpersistent probe sandbox to verify the token, image, command execution, cleanup, and effective duration ceiling;
|
|
95
|
+
7. activates the profile only after every required check succeeds.
|
|
96
|
+
|
|
97
|
+
The project does not need a deployment. Its metered use is billed to its owning Vercel scope. CLI login and worker configuration are deliberately separate: CLI login selects and provisions resources, while the project-scoped token plus team and project IDs configure the SelfBench worker. Although the Vercel SDK supports ambient OIDC on Vercel infrastructure, SelfBench does not use it.
|
|
98
|
+
|
|
99
|
+
Profiles live in `~/.selfbench/config.json`; tokens live separately in `~/.selfbench/credentials.json`. The directory is mode `0700`, both files are mode `0600`, writes are atomic, and displayed setup output never includes the token. Override the directory with `SELFBENCH_CONFIG_DIR` when isolation is needed. To maintain more than one project profile:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
self-bench setup vercel --profile secondary
|
|
103
|
+
self-bench up --backend vercel --vercel-profile secondary --harbor-environment modal
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Without `--vercel-profile`, `self-bench up` uses the active profile most recently saved by setup. Rerunning setup revalidates the existing project and token by default. It fingerprints the exact Dockerfile—including its digest-pinned base and pinned tool defaults—plus the fingerprint schema and target platform; if the matching immutable VCR image is already ready, publication is skipped. A changed runtime produces a new content-derived tag and digest. The final image reference is always digest-pinned, and existing digests are not deleted automatically. If the default VCR repository contains unrelated images, setup leaves it untouched and asks for another name.
|
|
107
|
+
|
|
108
|
+
When rerunning setup for a named profile, the available actions are:
|
|
109
|
+
|
|
110
|
+
- **Revalidate** keeps the saved team, project, and token. It verifies current access, reuses a compatible ready image, republishes only if the runtime fingerprint changed, reruns the temporary Sandbox capability probe, and refreshes the saved image digest and timeout cap.
|
|
111
|
+
- **Replace the access token** keeps the saved team and project, requests a new project-scoped token, and activates it only after verification succeeds. It replaces only the locally stored credential; revoke the old token separately in Vercel if necessary.
|
|
112
|
+
- **Choose another team or project** repoints the same local profile name after the new project, image, and token pass verification. It does not delete the previous Vercel project or images. Use a different `--profile` name instead when both configurations should remain available.
|
|
113
|
+
|
|
114
|
+
If setup is interrupted after creating a project or VCR repository, it reports the failure and leaves the durable resource in place; rerun setup to continue. It never activates a partial profile. Vercel projects and VCR images are reusable across SelfBench runs and persist after `self-bench down`.
|
|
115
|
+
|
|
116
|
+
#### Start the local worker
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
self-bench up --backend vercel --harbor-environment modal
|
|
120
|
+
# self-bench up --backend vercel --harbor-environment docker
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Modal Harbor also needs the Modal profile or token pair. Vercel control credentials are removed from the Harbor child process for both Harbor environments. `self-bench up` resolves the profile, then validates the complete credential triple, digest-pinned image, and timeout cap before starting Compose.
|
|
124
|
+
|
|
125
|
+
The setup probe records a two-hour effective SelfBench ceiling when the requested two-hour sandbox is accepted. If Vercel returns its exact 45-minute limit response, setup verifies a 45-minute sandbox, explains the impact, and asks before saving that cap. Longer authoring and repair requests then run for at most 45 minutes and return exit 124 on timeout, so only the affected candidate is rejected. Discovery and review retain their shorter requested limits. The effective cap is included in run and export metadata.
|
|
126
|
+
|
|
127
|
+
#### Environment-only and unattended workers
|
|
128
|
+
|
|
129
|
+
`self-bench setup vercel` is intentionally interactive. CI and long-running workers can provide the same resolved values through environment variables or a secret manager:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
export VERCEL_TOKEN=...
|
|
133
|
+
export VERCEL_TEAM_ID=team_...
|
|
134
|
+
export VERCEL_PROJECT_ID=prj_...
|
|
135
|
+
export SELFBENCH_VERCEL_IMAGE='selfbench-runtime@sha256:...'
|
|
136
|
+
export SELFBENCH_VERCEL_TIMEOUT_CAP=2h # use 45m when that is the verified ceiling
|
|
137
|
+
|
|
138
|
+
self-bench up --backend vercel --harbor-environment modal
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The image must already have been published from `Dockerfile.sandbox` to the same project's VCR as `linux/amd64`. Use the bare repository-plus-digest form shown above; tags and rolling aliases are rejected. VCR repositories are project-scoped by default, so a sandbox in another project cannot use the image unless the repository is explicitly shared. Explicit token and image values take precedence over profile values, and a lower timeout cap may be supplied; an override cannot exceed the profile's verified ceiling. Supplying a complete credential/image environment requires no local profile; partial team or project overrides are rejected rather than combined across scopes.
|
|
142
|
+
|
|
143
|
+
Vercel defaults to four concurrent worker activities. A standard SelfBench sandbox requests 4 vCPUs, which Vercel pairs with 8 GB of memory, plus 32 GB of ephemeral disk. Unsupported CPU/memory combinations are rejected before allocation. Raise `SELFBENCH_ACTIVITY_CONCURRENCY` only after considering the team's allocation limits and budget. Lower it—often to `1`—when using Docker Harbor on a smaller local machine, because the Vercel-oriented default does not account for local Harbor capacity.
|
|
144
|
+
|
|
145
|
+
Each sandbox run uses a fresh nonpersistent sandbox (`persistent: false`). SelfBench does not create snapshots or resume stopped sandboxes, and it attempts to delete every sandbox when the run ends. If deletion cannot be confirmed, the activity fails so the cleanup problem remains visible. If the worker crashes before cleanup, compute may continue until the provider timeout; Vercel then discards the filesystem, although the stopped sandbox record may remain for up to 14 days unless manually deleted.
|
|
146
|
+
|
|
147
|
+
Cancel active workflows and let cleanup finish before stopping the stack.
|
|
148
|
+
|
|
149
|
+
Common failures:
|
|
150
|
+
|
|
151
|
+
- A newly changed paid plan may take time to propagate its longer timeout entitlement. Rerun `self-bench setup vercel` to repeat the short-lived capability probe and update the saved cap; if a correctly scoped paid project continues to detect 45 minutes, verify team/project ownership before contacting Vercel Support.
|
|
152
|
+
- `not_found` on create usually means the image belongs to another project or is private and unshared. Prefer the same project and a bare digest reference.
|
|
153
|
+
- `image_not_ready` means VCR has not finished optimizing the `linux/amd64` image.
|
|
154
|
+
- Repeated HTTP 429 allocation failures indicate project/team allocation pressure. The executor honors bounded `Retry-After` retries; reduce activity concurrency if pressure continues.
|
|
155
|
+
- Cleanup errors fail the activity rather than silently leaving reusable state and include the exact `selfbench-...` sandbox name for diagnosis.
|
|
156
|
+
|
|
66
157
|
## CLI behavior
|
|
67
158
|
|
|
68
159
|
`self-bench run` requires an absolute or relative path to a Git checkout whose `origin` is an HTTPS or SSH GitHub URL. It pins `HEAD`; uncommitted content is excluded.
|
|
@@ -121,21 +212,28 @@ SelfBench has no remote deletion route. Delete local artifact-volume data or GCS
|
|
|
121
212
|
| `SELFBENCH_ARTIFACT_DIR` | `.selfbench/artifacts` | Local artifact store |
|
|
122
213
|
| `SELFBENCH_GCS_BUCKET` | — | GCS artifact store |
|
|
123
214
|
| `SELFBENCH_GCS_PREFIX` | `selfbench` | GCS artifact store |
|
|
124
|
-
| `SELFBENCH_EXECUTION_BACKEND` | `docker` | Worker;
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
215
|
+
| `SELFBENCH_EXECUTION_BACKEND` | `docker` | Worker; `docker`, `modal`, or `vercel` |
|
|
216
|
+
| `SELFBENCH_DOCKER_IMAGE` | `selfbench-sandbox:local` | Docker worker |
|
|
217
|
+
| `SELFBENCH_HARBOR_ENVIRONMENT` | matching Docker/Modal backend | Worker; required as `docker` or `modal` for Vercel |
|
|
218
|
+
| `SELFBENCH_ACTIVITY_CONCURRENCY` | `1` Docker, `20` Modal, `4` Vercel | Worker |
|
|
127
219
|
| `SELFBENCH_MODAL_APP` | `selfbench` | Modal worker |
|
|
128
220
|
| `SELFBENCH_MODAL_ENVIRONMENT` | — | Modal worker |
|
|
129
221
|
| `SELFBENCH_MODAL_IMAGE` | `node:22-bookworm` | Modal worker |
|
|
130
222
|
| `SELFBENCH_MODAL_CONFIG_PATH` | `/dev/null` | Compose host mount; set by `self-bench up --modal-config` locally |
|
|
223
|
+
| `SELFBENCH_VERCEL_IMAGE` | profile or — | Required digest-pinned VCR image for Vercel execution |
|
|
224
|
+
| `SELFBENCH_VERCEL_TIMEOUT_CAP` | `2h` | Vercel worker and API; accepts integer milliseconds or `ms`, `s`, `m`, `h` units |
|
|
225
|
+
| `SELFBENCH_CONFIG_DIR` | `~/.selfbench` | Local CLI profile directory; not needed with a complete Vercel environment |
|
|
226
|
+
| `VERCEL_TOKEN` | profile or unset | Vercel worker; explicit project-scoped access token |
|
|
227
|
+
| `VERCEL_TEAM_ID` | profile or unset | Vercel worker |
|
|
228
|
+
| `VERCEL_PROJECT_ID` | profile or unset | Vercel worker; must be able to resolve the configured image |
|
|
131
229
|
| `SELFBENCH_TEMPORAL_ADDRESS` | `127.0.0.1:7233` | API and worker |
|
|
132
230
|
| `SELFBENCH_TEMPORAL_NAMESPACE` | `default` | API and worker |
|
|
133
231
|
| `SELFBENCH_TASK_QUEUE` | `selfbench-dev` | API and worker |
|
|
134
|
-
| `
|
|
135
|
-
| `SELFBENCH_PI_AUTH_JSON` | — |
|
|
136
|
-
| `
|
|
232
|
+
| `OPENAI_API_KEY` | — | Worker sandboxes and matrix harness |
|
|
233
|
+
| `SELFBENCH_PI_AUTH_JSON` | — | Optional Pi subscription-auth fallback |
|
|
234
|
+
| `SELFBENCH_CODEX_AUTH_JSON` | — | Optional Codex subscription-auth fallback |
|
|
137
235
|
| `GH_TOKEN` | — | Worker GitHub reads |
|
|
138
|
-
| `CODEX_AUTH_JSON_PATH` | `~/.codex/auth.json` |
|
|
236
|
+
| `CODEX_AUTH_JSON_PATH` | `~/.codex/auth.json` | Optional matrix subscription-auth file |
|
|
139
237
|
|
|
140
238
|
## Cloud topology
|
|
141
239
|
|
|
@@ -153,7 +251,7 @@ SELFBENCH_TEMPORAL_API_KEY=...
|
|
|
153
251
|
SELFBENCH_TEMPORAL_TLS=true
|
|
154
252
|
```
|
|
155
253
|
|
|
156
|
-
Run `node dist/worker-main.js` from the same image digest on a long-running container platform, not a scale-to-zero request service. Give it the same Temporal, task queue, and GCS configuration plus:
|
|
254
|
+
Run `node dist/temporal/worker-main.js` from the same image digest on a long-running container platform, not a scale-to-zero request service. Give it the same Temporal, task queue, and GCS configuration plus:
|
|
157
255
|
|
|
158
256
|
```text
|
|
159
257
|
SELFBENCH_EXECUTION_BACKEND=modal
|
|
@@ -161,11 +259,25 @@ SELFBENCH_HARBOR_ENVIRONMENT=modal
|
|
|
161
259
|
MODAL_TOKEN_ID=...
|
|
162
260
|
MODAL_TOKEN_SECRET=...
|
|
163
261
|
GH_TOKEN=...
|
|
164
|
-
|
|
262
|
+
OPENAI_API_KEY=...
|
|
165
263
|
```
|
|
166
264
|
|
|
167
265
|
The worker owns model, GitHub, Modal, and Harbor credentials. Use separate least-privilege service accounts and a secret manager. Grant GCS object access only to the configured prefix, use a TLS-enabled Temporal namespace, and keep API/worker image digests and `SELFBENCH_TASK_QUEUE` identical.
|
|
168
266
|
|
|
267
|
+
For Vercel generation, replace the execution settings above with:
|
|
268
|
+
|
|
269
|
+
```text
|
|
270
|
+
SELFBENCH_EXECUTION_BACKEND=vercel
|
|
271
|
+
SELFBENCH_HARBOR_ENVIRONMENT=modal # or docker
|
|
272
|
+
SELFBENCH_VERCEL_IMAGE=selfbench-runtime@sha256:...
|
|
273
|
+
SELFBENCH_VERCEL_TIMEOUT_CAP=2h # or the verified 45m ceiling
|
|
274
|
+
VERCEL_TOKEN=...
|
|
275
|
+
VERCEL_TEAM_ID=team_...
|
|
276
|
+
VERCEL_PROJECT_ID=prj_...
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Keep the Vercel credential triple on the worker only. A project-scoped token is sufficient when the runtime image belongs to that project. The API must also receive `SELFBENCH_EXECUTION_BACKEND`, `SELFBENCH_HARBOR_ENVIRONMENT`, `SELFBENCH_VERCEL_IMAGE`, and `SELFBENCH_VERCEL_TIMEOUT_CAP` because it stamps the generation backend, Harbor environment, image, and effective timeout cap into each run manifest; it never needs the credential triple.
|
|
280
|
+
|
|
169
281
|
This repository defines the application boundary, not turnkey cloud infrastructure. Project, region, ingress, IAM, GCS, and Temporal provisioning remain deployment-specific.
|
|
170
282
|
|
|
171
283
|
## Security boundary
|
|
@@ -173,6 +285,7 @@ This repository defines the application boundary, not turnkey cloud infrastructu
|
|
|
173
285
|
- Exports contain source snapshots, held-out tests, and reference solutions. They are sensitive and unencrypted.
|
|
174
286
|
- Artifact references carry byte length and SHA-256; reads verify integrity.
|
|
175
287
|
- Local artifact paths and GCS object names are confined to their configured roots. GCS IAM should enforce the same prefix independently.
|
|
176
|
-
-
|
|
288
|
+
- Sandboxes receive only the selected model credential: `OPENAI_API_KEY` by default, or a stage-specific subscription credential for compatibility deployments.
|
|
177
289
|
- Sandboxes contain both a source checkout and a short-lived model credential. Use SelfBench only with repositories you trust to execute; it is not a malware-analysis service.
|
|
178
|
-
- Docker uses disposable containers and volumes and removes them after normal completion. A host crash can leave resources for an operator to inspect and remove. Modal uses disposable Sandboxes.
|
|
290
|
+
- Docker uses disposable containers and volumes and removes them after normal completion. A host crash can leave resources for an operator to inspect and remove. Modal uses disposable Sandboxes. Vercel uses nonpersistent named sandboxes, attempts permanent deletion after each run, and fails the activity when deletion cannot be confirmed; inspect the project after worker crashes or cleanup failures.
|
|
291
|
+
- Vercel control credentials authenticate only the worker's Sandbox control plane and are stripped before Harbor starts. They are never workload command secrets.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "self-bench",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Turn completed repository changes into durable, private Harbor evaluations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -50,36 +50,38 @@
|
|
|
50
50
|
"check": "biome check . && tsc --noEmit -p tsconfig.json && bun run typecheck:review",
|
|
51
51
|
"dev:api": "tsx src/api-main.ts",
|
|
52
52
|
"dev:review": "vite --config review/vite.config.ts",
|
|
53
|
-
"dev:worker": "tsx src/worker-main.ts",
|
|
53
|
+
"dev:worker": "tsx src/temporal/worker-main.ts",
|
|
54
54
|
"format": "biome format --write .",
|
|
55
55
|
"start:api": "node dist/api-main.js",
|
|
56
|
-
"start:worker": "node dist/worker-main.js",
|
|
56
|
+
"start:worker": "node dist/temporal/worker-main.js",
|
|
57
57
|
"test": "bun test tests review/src",
|
|
58
58
|
"typecheck:review": "tsc --noEmit -p review/tsconfig.json",
|
|
59
59
|
"validate": "bun run check && bun run test && bun run build && bun run verify:package"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
+
"@clack/prompts": "1.7.0",
|
|
62
63
|
"@google-cloud/storage": "^7.17.0",
|
|
63
|
-
"@pierre/diffs": "1.2.12",
|
|
64
64
|
"@temporalio/activity": "^1.13.2",
|
|
65
65
|
"@temporalio/client": "^1.13.2",
|
|
66
66
|
"@temporalio/common": "^1.13.2",
|
|
67
67
|
"@temporalio/worker": "^1.13.2",
|
|
68
68
|
"@temporalio/workflow": "^1.13.2",
|
|
69
|
+
"@vercel/sandbox": "3.0.0",
|
|
69
70
|
"modal": "^0.9.0",
|
|
70
|
-
"react": "19.2.7",
|
|
71
|
-
"react-dom": "19.2.7",
|
|
72
71
|
"zod": "^4.1.12"
|
|
73
72
|
},
|
|
74
73
|
"devDependencies": {
|
|
75
74
|
"@biomejs/biome": "^2.2.6",
|
|
76
75
|
"@earendil-works/pi-coding-agent": "0.84.0",
|
|
76
|
+
"@pierre/diffs": "1.2.12",
|
|
77
77
|
"@sinclair/typebox": "0.34.41",
|
|
78
78
|
"@types/bun": "^1.3.14",
|
|
79
79
|
"@types/node": "24.10.13",
|
|
80
80
|
"@types/react": "19.2.14",
|
|
81
81
|
"@types/react-dom": "19.2.3",
|
|
82
82
|
"@vitejs/plugin-react": "4.7.0",
|
|
83
|
+
"react": "19.2.7",
|
|
84
|
+
"react-dom": "19.2.7",
|
|
83
85
|
"tsx": "^4.20.6",
|
|
84
86
|
"typescript": "5.9.3",
|
|
85
87
|
"vite": "7.3.1"
|
package/src/agent-smoke-main.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
4
|
import { smokeAllAdapters } from "./agent-smoke.js";
|
|
5
|
+
import { isHarborEnvironment } from "./providers.js";
|
|
5
6
|
|
|
6
7
|
const parsed = parseArgs({
|
|
7
8
|
options: {
|
|
@@ -27,8 +28,8 @@ Options:
|
|
|
27
28
|
-h, --help Show this help`);
|
|
28
29
|
process.exit(0);
|
|
29
30
|
}
|
|
30
|
-
const environment = parsed.values.environment;
|
|
31
|
-
if (environment
|
|
31
|
+
const environment = parsed.values.environment ?? "modal";
|
|
32
|
+
if (!isHarborEnvironment(environment)) {
|
|
32
33
|
throw new Error("--environment must be docker or modal");
|
|
33
34
|
}
|
|
34
35
|
const results = await smokeAllAdapters({
|
package/src/agent-smoke.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
+
import { harborChildEnvironment } from "./harbor-environment.js";
|
|
3
4
|
import { parallelMap } from "./parallel.js";
|
|
4
5
|
import { runCommand } from "./process.js";
|
|
6
|
+
import type { HarborEnvironment } from "./providers.js";
|
|
5
7
|
|
|
6
8
|
export const HARBOR_AGENT_ADAPTERS = [
|
|
7
9
|
"oracle",
|
|
@@ -48,7 +50,7 @@ export interface AdapterSmokeOptions {
|
|
|
48
50
|
readonly taskDirectory: string;
|
|
49
51
|
readonly jobsDirectory: string;
|
|
50
52
|
readonly harborPath?: string;
|
|
51
|
-
readonly environment?:
|
|
53
|
+
readonly environment?: HarborEnvironment;
|
|
52
54
|
readonly concurrency?: number;
|
|
53
55
|
}
|
|
54
56
|
|
|
@@ -99,7 +101,11 @@ export async function smokeAllAdapters(
|
|
|
99
101
|
"--yes",
|
|
100
102
|
"--quiet",
|
|
101
103
|
],
|
|
102
|
-
{
|
|
104
|
+
{
|
|
105
|
+
allowFailure: true,
|
|
106
|
+
env: harborChildEnvironment(),
|
|
107
|
+
timeoutMs: 60 * 60 * 1000,
|
|
108
|
+
},
|
|
103
109
|
);
|
|
104
110
|
const summary: AdapterSmokeResult = {
|
|
105
111
|
agent,
|
package/src/api.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
3
5
|
import { pipeline } from "node:stream/promises";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
4
7
|
import { Client } from "@temporalio/client";
|
|
5
8
|
import { z } from "zod";
|
|
6
9
|
import { createArtifactStore } from "./artifacts.js";
|
|
@@ -8,12 +11,13 @@ import type { SelfBenchConfig } from "./config.js";
|
|
|
8
11
|
import {
|
|
9
12
|
artifactRefSchema,
|
|
10
13
|
type RunPhase,
|
|
14
|
+
type RunRequest,
|
|
11
15
|
type RunStatus,
|
|
12
16
|
repositoryRefSchema,
|
|
13
17
|
runRequestSchema,
|
|
14
18
|
} from "./contracts.js";
|
|
15
|
-
import { connectTemporalClient } from "./temporal.js";
|
|
16
|
-
import { selfBenchRunWorkflow, statusQuery } from "./workflow.js";
|
|
19
|
+
import { connectTemporalClient } from "./temporal/connection.js";
|
|
20
|
+
import { selfBenchRunWorkflow, statusQuery } from "./temporal/workflow.js";
|
|
17
21
|
|
|
18
22
|
const submissionSchema = z.object({
|
|
19
23
|
runId: z.string().regex(/^[a-z0-9][a-z0-9-]{2,62}$/),
|
|
@@ -39,6 +43,13 @@ export async function startApi(config: SelfBenchConfig): Promise<() => Promise<v
|
|
|
39
43
|
sendJson(response, 200, { ok: true });
|
|
40
44
|
return;
|
|
41
45
|
}
|
|
46
|
+
if (
|
|
47
|
+
request.method === "GET" &&
|
|
48
|
+
(url.pathname === "/" || url.pathname.startsWith("/assets/"))
|
|
49
|
+
) {
|
|
50
|
+
await sendReviewAsset(response, url.pathname);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
42
53
|
if (!authorized(request, config.apiToken)) {
|
|
43
54
|
sendJson(response, 401, { error: "unauthorized" });
|
|
44
55
|
return;
|
|
@@ -58,26 +69,10 @@ export async function startApi(config: SelfBenchConfig): Promise<() => Promise<v
|
|
|
58
69
|
return;
|
|
59
70
|
}
|
|
60
71
|
if (request.method === "POST" && url.pathname === "/v1/runs") {
|
|
61
|
-
const
|
|
72
|
+
const workflowInput = buildRunRequest(
|
|
73
|
+
config,
|
|
62
74
|
JSON.parse((await readBody(request)).toString("utf8")),
|
|
63
75
|
);
|
|
64
|
-
const workflowInput = runRequestSchema.parse({
|
|
65
|
-
runId: submission.runId,
|
|
66
|
-
repository: submission.repository,
|
|
67
|
-
provenance: submission.provenance,
|
|
68
|
-
candidateCounts: submission.candidateCounts,
|
|
69
|
-
authoring: {
|
|
70
|
-
provider: "openai-codex",
|
|
71
|
-
model: submission.authoringModel,
|
|
72
|
-
reasoningEffort: "high",
|
|
73
|
-
},
|
|
74
|
-
version: {
|
|
75
|
-
selfbenchCommit: config.buildCommit ?? submission.selfbenchCommit,
|
|
76
|
-
executionBackend: config.execution.kind,
|
|
77
|
-
sandboxImage: config.execution.image,
|
|
78
|
-
schema: 1,
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
76
|
await client.workflow.start(selfBenchRunWorkflow, {
|
|
82
77
|
workflowId: workflowInput.runId,
|
|
83
78
|
taskQueue: config.temporal.taskQueue,
|
|
@@ -157,6 +152,34 @@ export async function startApi(config: SelfBenchConfig): Promise<() => Promise<v
|
|
|
157
152
|
};
|
|
158
153
|
}
|
|
159
154
|
|
|
155
|
+
export function buildRunRequest(
|
|
156
|
+
config: SelfBenchConfig,
|
|
157
|
+
submission: z.input<typeof submissionSchema>,
|
|
158
|
+
): RunRequest {
|
|
159
|
+
const parsed = submissionSchema.parse(submission);
|
|
160
|
+
return runRequestSchema.parse({
|
|
161
|
+
runId: parsed.runId,
|
|
162
|
+
repository: parsed.repository,
|
|
163
|
+
provenance: parsed.provenance,
|
|
164
|
+
candidateCounts: parsed.candidateCounts,
|
|
165
|
+
authoring: {
|
|
166
|
+
provider: "openai-codex",
|
|
167
|
+
model: parsed.authoringModel,
|
|
168
|
+
reasoningEffort: "high",
|
|
169
|
+
},
|
|
170
|
+
version: {
|
|
171
|
+
selfbenchCommit: config.buildCommit ?? parsed.selfbenchCommit,
|
|
172
|
+
executionBackend: config.execution.kind,
|
|
173
|
+
harborEnvironment: config.harborEnvironment,
|
|
174
|
+
sandboxImage: config.execution.image,
|
|
175
|
+
...(config.execution.kind === "vercel"
|
|
176
|
+
? { sandboxTimeoutCapMs: config.execution.timeoutCapMs }
|
|
177
|
+
: {}),
|
|
178
|
+
schema: 1,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
160
183
|
async function queryStatus(
|
|
161
184
|
handle: ReturnType<Client["workflow"]["getHandle"]>,
|
|
162
185
|
): Promise<RunStatus | object> {
|
|
@@ -229,6 +252,34 @@ function authorized(request: IncomingMessage, token: string | undefined): boolea
|
|
|
229
252
|
);
|
|
230
253
|
}
|
|
231
254
|
|
|
255
|
+
async function sendReviewAsset(response: ServerResponse, pathname: string): Promise<void> {
|
|
256
|
+
const relativePath = pathname === "/" ? "index.html" : pathname.slice(1);
|
|
257
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), "review");
|
|
258
|
+
const path = join(root, relativePath);
|
|
259
|
+
if (!path.startsWith(`${root}/`)) {
|
|
260
|
+
sendJson(response, 400, { error: "invalid asset path" });
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
const body = await readFile(path);
|
|
265
|
+
response.writeHead(200, {
|
|
266
|
+
"content-type": contentType(path),
|
|
267
|
+
"content-length": body.byteLength,
|
|
268
|
+
"cache-control": pathname === "/" ? "no-cache" : "public, max-age=31536000, immutable",
|
|
269
|
+
});
|
|
270
|
+
response.end(body);
|
|
271
|
+
} catch {
|
|
272
|
+
sendJson(response, 404, { error: "asset not found" });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function contentType(path: string): string {
|
|
277
|
+
if (path.endsWith(".html")) return "text/html; charset=utf-8";
|
|
278
|
+
if (path.endsWith(".css")) return "text/css; charset=utf-8";
|
|
279
|
+
if (path.endsWith(".js")) return "text/javascript; charset=utf-8";
|
|
280
|
+
return "application/octet-stream";
|
|
281
|
+
}
|
|
282
|
+
|
|
232
283
|
function sendJson(response: ServerResponse, status: number, value: unknown): void {
|
|
233
284
|
const body = `${JSON.stringify(value, null, 2)}\n`;
|
|
234
285
|
response.writeHead(status, {
|
package/src/artifacts.ts
CHANGED
|
@@ -355,7 +355,3 @@ function verifyArtifact(reference: ArtifactRef, value: Uint8Array): void {
|
|
|
355
355
|
throw new Error(`artifact integrity check failed: ${reference.uri}`);
|
|
356
356
|
}
|
|
357
357
|
}
|
|
358
|
-
|
|
359
|
-
export async function artifactSize(path: string): Promise<number> {
|
|
360
|
-
return (await stat(path)).size;
|
|
361
|
-
}
|
package/src/cli.ts
CHANGED
|
@@ -10,18 +10,29 @@ import type { ReadableStream as NodeReadableStream } from "node:stream/web";
|
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { parseArgs } from "node:util";
|
|
12
12
|
import { buildCommit } from "./build-metadata.js";
|
|
13
|
+
import { loadWorkerConfig } from "./config.js";
|
|
13
14
|
import { runCommand } from "./process.js";
|
|
14
15
|
import { collectGitHubPullRequestProvenance, collectRepositoryProvenance } from "./provenance.js";
|
|
16
|
+
import { isExecutionBackend, isHarborEnvironment, matchingHarborEnvironment } from "./providers.js";
|
|
15
17
|
import { type PolledRunStatus, waitForRun } from "./run-wait.js";
|
|
18
|
+
import { SetupCanceledError } from "./terminal-prompts.js";
|
|
19
|
+
import { applyVercelProfile } from "./vercel-profile.js";
|
|
20
|
+
import { setupVercel } from "./vercel-setup.js";
|
|
16
21
|
|
|
17
22
|
const [command, ...rest] = process.argv.slice(2);
|
|
18
23
|
switch (command) {
|
|
24
|
+
case "setup":
|
|
25
|
+
await setup(rest);
|
|
26
|
+
break;
|
|
19
27
|
case "up":
|
|
20
28
|
await up(rest);
|
|
21
29
|
break;
|
|
22
30
|
case "run":
|
|
23
31
|
await run(rest);
|
|
24
32
|
break;
|
|
33
|
+
case "down":
|
|
34
|
+
await down();
|
|
35
|
+
break;
|
|
25
36
|
case "status":
|
|
26
37
|
await passthrough("GET", `/v1/runs/${requiredArgument(rest, "run ID")}`);
|
|
27
38
|
break;
|
|
@@ -44,31 +55,74 @@ switch (command) {
|
|
|
44
55
|
throw new Error(`unknown command: ${command}`);
|
|
45
56
|
}
|
|
46
57
|
|
|
58
|
+
async function setup(args: string[]): Promise<void> {
|
|
59
|
+
const [provider, ...providerArgs] = args;
|
|
60
|
+
if (provider !== "vercel") {
|
|
61
|
+
fail("setup currently supports only: self-bench setup vercel");
|
|
62
|
+
}
|
|
63
|
+
const parsed = parseArgs({
|
|
64
|
+
args: providerArgs,
|
|
65
|
+
options: {
|
|
66
|
+
profile: { type: "string", default: "default" },
|
|
67
|
+
verbose: { type: "boolean", default: false },
|
|
68
|
+
},
|
|
69
|
+
strict: true,
|
|
70
|
+
});
|
|
71
|
+
try {
|
|
72
|
+
await setupVercel({
|
|
73
|
+
profileName: parsed.values.profile,
|
|
74
|
+
verbose: parsed.values.verbose,
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (error instanceof SetupCanceledError) {
|
|
78
|
+
process.exitCode = 130;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
47
85
|
async function up(args: string[]): Promise<void> {
|
|
48
86
|
const parsed = parseArgs({
|
|
49
87
|
args,
|
|
50
88
|
options: {
|
|
51
89
|
backend: { type: "string", default: "docker" },
|
|
90
|
+
"harbor-environment": { type: "string" },
|
|
52
91
|
"modal-config": { type: "string" },
|
|
92
|
+
"vercel-profile": { type: "string" },
|
|
53
93
|
},
|
|
54
94
|
strict: true,
|
|
55
95
|
});
|
|
56
|
-
if (parsed.values.backend
|
|
57
|
-
fail('--backend must be "docker" or "
|
|
96
|
+
if (!isExecutionBackend(parsed.values.backend)) {
|
|
97
|
+
fail('--backend must be "docker", "modal", or "vercel"');
|
|
58
98
|
}
|
|
59
|
-
if (
|
|
60
|
-
|
|
99
|
+
if (
|
|
100
|
+
parsed.values["harbor-environment"] !== undefined &&
|
|
101
|
+
!isHarborEnvironment(parsed.values["harbor-environment"])
|
|
102
|
+
) {
|
|
103
|
+
fail('--harbor-environment must be "docker" or "modal"');
|
|
61
104
|
}
|
|
62
105
|
|
|
63
106
|
const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
64
107
|
const composeFile = resolve(projectRoot, "compose.yaml");
|
|
65
108
|
const backend = parsed.values.backend;
|
|
66
|
-
const
|
|
109
|
+
const harborEnvironment =
|
|
110
|
+
parsed.values["harbor-environment"] ??
|
|
111
|
+
matchingHarborEnvironment(backend) ??
|
|
112
|
+
fail(`--harbor-environment is required with --backend ${backend}`);
|
|
113
|
+
const usesModal = backend === "modal" || harborEnvironment === "modal";
|
|
114
|
+
if (!usesModal && parsed.values["modal-config"] !== undefined) {
|
|
115
|
+
fail("--modal-config requires Modal generation or Harbor");
|
|
116
|
+
}
|
|
117
|
+
if (backend !== "vercel" && parsed.values["vercel-profile"] !== undefined) {
|
|
118
|
+
fail("--vercel-profile requires Vercel generation");
|
|
119
|
+
}
|
|
120
|
+
let environment: NodeJS.ProcessEnv = {
|
|
67
121
|
...process.env,
|
|
68
122
|
SELFBENCH_BUILD_COMMIT: await resolveSelfBenchCommit(),
|
|
69
123
|
SELFBENCH_EXECUTION_BACKEND: backend,
|
|
70
|
-
SELFBENCH_HARBOR_ENVIRONMENT:
|
|
71
|
-
...(
|
|
124
|
+
SELFBENCH_HARBOR_ENVIRONMENT: harborEnvironment,
|
|
125
|
+
...(usesModal
|
|
72
126
|
? {
|
|
73
127
|
SELFBENCH_MODAL_CONFIG_PATH: resolve(
|
|
74
128
|
parsed.values["modal-config"] ?? resolve(homedir(), ".modal.toml"),
|
|
@@ -76,6 +130,10 @@ async function up(args: string[]): Promise<void> {
|
|
|
76
130
|
}
|
|
77
131
|
: {}),
|
|
78
132
|
};
|
|
133
|
+
if (backend === "vercel") {
|
|
134
|
+
environment = await applyVercelProfile(environment, parsed.values["vercel-profile"]);
|
|
135
|
+
loadWorkerConfig(environment);
|
|
136
|
+
}
|
|
79
137
|
|
|
80
138
|
if (backend === "docker") {
|
|
81
139
|
await runCommand(
|
|
@@ -94,7 +152,14 @@ async function up(args: string[]): Promise<void> {
|
|
|
94
152
|
await runCommand("docker", ["compose", "--file", composeFile, "up", "-d", "--build"], {
|
|
95
153
|
env: environment,
|
|
96
154
|
});
|
|
97
|
-
console.log(
|
|
155
|
+
console.log(
|
|
156
|
+
`SelfBench is running with ${backend} generation and ${harborEnvironment} Harbor at http://127.0.0.1:8080`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function down(): Promise<void> {
|
|
161
|
+
const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
162
|
+
await runCommand("docker", ["compose", "--file", resolve(projectRoot, "compose.yaml"), "down"]);
|
|
98
163
|
}
|
|
99
164
|
|
|
100
165
|
async function run(args: string[]): Promise<void> {
|
|
@@ -332,7 +397,10 @@ function printHelp(): void {
|
|
|
332
397
|
console.log(`SelfBench creates durable tiered Harbor evaluations.
|
|
333
398
|
|
|
334
399
|
Usage:
|
|
335
|
-
self-bench
|
|
400
|
+
self-bench setup vercel [--profile NAME] [--verbose]
|
|
401
|
+
self-bench up [--backend docker|modal|vercel] [--harbor-environment docker|modal]
|
|
402
|
+
[--modal-config PATH] [--vercel-profile NAME]
|
|
403
|
+
self-bench down
|
|
336
404
|
self-bench run --repo PATH [--easy-count N] [--medium-count N] [--hard-count N]
|
|
337
405
|
[--model MODEL] [--run-id ID] [--wait] [--output OUTPUT.tar.gz]
|
|
338
406
|
self-bench status RUN_ID
|
|
@@ -340,8 +408,10 @@ Usage:
|
|
|
340
408
|
self-bench download RUN_ID OUTPUT.tar.gz
|
|
341
409
|
self-bench list
|
|
342
410
|
|
|
343
|
-
The up command starts the local stack and
|
|
344
|
-
|
|
411
|
+
The up command starts the local stack. Docker and Modal default Harbor to the matching backend; Vercel
|
|
412
|
+
requires --harbor-environment because Harbor does not support Vercel. Modal generation or Harbor uses
|
|
413
|
+
~/.modal.toml unless --modal-config overrides it. Run self-bench setup vercel once to create or select a
|
|
414
|
+
project, publish the pinned runtime image, verify access, and save an owner-only local profile.
|
|
345
415
|
|
|
346
416
|
The tier counts are candidate authoring budgets, not accepted-task targets. Rejected candidates are not
|
|
347
417
|
replaced, and the export contains only accepted tasks. The run command performs only repository metadata
|