Skip to content

Commit 5ec1e0d

Browse files
committed
Add resumable validated workflow and tarball-first scheme runbook
- Add `buildabench_workshop.run_validated_workflow`, a packaged resumable CLI that orchestrates `env_agent`, `synth_task`, `validate_task`, and `check_validated_tasks` end-to-end. - Implement interruption-safe resume behavior with checkpoint files (`tasks.jsonl`, `validated_tasks.jsonl`, `check_results.jsonl`, `workflow.log`) and a `--force-fresh` path for clean reruns. - Ensure the workflow runner passes the selected container explicitly to `validate_task` (`--container ...`) so tarball-based/manual runs stay consistent even when container names are overridden. - Add/extend tests in `tests/test_run_validated_workflow.py`, including coverage that validates container propagation to `validate_task`. - Update `.github/workflows/synth-eval-scheme-interpreter.yml` to execute the scheme-interpreter CI path in an isolated temporary git repo and clean it up after the job. - Simplify `README.md` workflow instructions to a tarballed-git-repo-first path (no `mktemp` workspace-copy flow), while preserving manual step-by-step commands. - Update `AGENTS.md` runbook with BOA launch guidance for `qwen3_coder_30b_a3b_instruct_fp8` and required vLLM tool-calling flags (`--enable-auto-tool-choice`, `--tool-call-parser qwen3_xml`, `--enable-prefix-caching`) on port `8000`. - Keep generated artifacts out of version control and retain only source/workflow/documentation updates required for the validated pipeline.
1 parent 7fa11db commit 5ec1e0d

6 files changed

Lines changed: 1128 additions & 15 deletions

File tree

‎.github/workflows/synth-eval-scheme-interpreter.yml‎

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,43 +17,68 @@ jobs:
1717
synth-eval:
1818
runs-on: self-hosted
1919
env:
20+
# This workflow assumes a vLLM server is already running on BOA
21+
# and reachable over the 192.168.50/24 VPN.
2022
OPENAI_MODEL: openai/boa
21-
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
22-
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
23-
CONTAINER_NAME: env_agent__scheme_interpreter_${{ github.run_id }}
23+
OPENAI_API_KEY: sk-local
24+
OPENAI_API_BASE: http://192.168.50.7:8080/v1
2425
steps:
2526
- name: Check out repository
2627
uses: actions/checkout@v4
2728

2829
- name: Add Codex CLI to PATH
2930
run: echo "/home/ci/codexcli/node_modules/.bin" >> "$GITHUB_PATH"
3031

32+
- name: Prepare isolated scheme interpreter repo
33+
run: |
34+
set -euo pipefail
35+
36+
WORK_REPO="$RUNNER_TEMP/scheme_interpreter_repo_${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}"
37+
mkdir -p "$WORK_REPO"
38+
cp -a test_projects/scheme_interpreter/. "$WORK_REPO/"
39+
40+
git -C "$WORK_REPO" init
41+
git -C "$WORK_REPO" config user.name "CI"
42+
git -C "$WORK_REPO" config user.email "ci@example.invalid"
43+
git -C "$WORK_REPO" add .
44+
git -C "$WORK_REPO" commit -m "Initial scheme interpreter fixture snapshot"
45+
46+
echo "SCHEME_REPO=$WORK_REPO" >> "$GITHUB_ENV"
47+
echo "TASKS_JSONL=$RUNNER_TEMP/ci_tasks_${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}.jsonl" >> "$GITHUB_ENV"
48+
echo "VALIDATED_JSONL=$RUNNER_TEMP/ci_validated_tasks_${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}.jsonl" >> "$GITHUB_ENV"
49+
echo "CONTAINER_NAME=env_agent__scheme_interpreter_${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
50+
3151
- name: Build container via env_agent
3252
run: |
3353
uv run python3 -m buildabench_workshop.env_agent \
34-
--repo test_projects/scheme_interpreter \
35-
--tips-path test_projects/scheme_interpreter/env_agent_tips.txt \
54+
--repo "$SCHEME_REPO" \
55+
--tips-path "$SCHEME_REPO/env_agent_tips.txt" \
3656
--agent codex \
3757
--container "$CONTAINER_NAME"
3858
59+
- name: Verify BOA vLLM endpoint
60+
run: |
61+
curl -fsS "$OPENAI_API_BASE/models"
62+
3963
- name: Synthesize 3 tasks
4064
run: |
4165
uv run python3 -m buildabench_workshop.synth_task \
4266
--json \
4367
--num-candidates 3 \
44-
--model openai/boa \
45-
test_projects/scheme_interpreter \
68+
--model "$OPENAI_MODEL" \
69+
"$SCHEME_REPO" \
4670
"src/scheme_interpreter/*.py" \
4771
"tests/*.py" \
48-
> test_projects/scheme_interpreter/ci_tasks.jsonl
72+
> "$TASKS_JSONL"
4973
5074
- name: Print synthesized tasks
5175
run: |
5276
uv run python3 - <<'PY'
5377
import json
78+
import os
5479
from pathlib import Path
5580
56-
tasks_path = Path("test_projects/scheme_interpreter/ci_tasks.jsonl")
81+
tasks_path = Path(os.environ["TASKS_JSONL"])
5782
for line in tasks_path.read_text().splitlines():
5883
if not line.strip():
5984
continue
@@ -77,8 +102,8 @@ jobs:
77102
import os
78103
from pathlib import Path
79104
80-
tasks_path = Path("test_projects/scheme_interpreter/ci_tasks.jsonl")
81-
validated_path = Path("test_projects/scheme_interpreter/ci_validated_tasks.jsonl")
105+
tasks_path = Path(os.environ["TASKS_JSONL"])
106+
validated_path = Path(os.environ["VALIDATED_JSONL"])
82107
container = os.environ["CONTAINER_NAME"]
83108
with validated_path.open("w") as out:
84109
for line in tasks_path.read_text().splitlines():
@@ -97,10 +122,11 @@ jobs:
97122
import json
98123
import subprocess
99124
import sys
125+
import os
100126
from pathlib import Path
101127
102-
tasks_path = Path("test_projects/scheme_interpreter/ci_tasks.jsonl")
103-
validated_path = Path("test_projects/scheme_interpreter/ci_validated_tasks.jsonl")
128+
tasks_path = Path(os.environ["TASKS_JSONL"])
129+
validated_path = Path(os.environ["VALIDATED_JSONL"])
104130
105131
failures = 0
106132
passes = 0
@@ -144,7 +170,9 @@ jobs:
144170
sys.exit(1)
145171
PY
146172
147-
- name: Cleanup container
173+
- name: Cleanup container and isolated repo
148174
if: always()
149175
run: |
150176
podman image rm -f "$CONTAINER_NAME" || true
177+
rm -rf "${SCHEME_REPO:-}" || true
178+
rm -f "${TASKS_JSONL:-}" "${VALIDATED_JSONL:-}" || true

‎AGENTS.md‎

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# AGENTS.md
2+
3+
## BOA + LiteLLM Runbook (Scheme Interpreter CI Path)
4+
5+
This runbook documents how to run the Scheme interpreter synth/eval flow against a BOA-hosted vLLM model via LiteLLM, while ensuring BOA only has one active vLLM server.
6+
7+
### 1. Verify BOA access and current vLLM state
8+
9+
Check BOA server alias from MCP, then inspect running vLLM processes and listeners:
10+
11+
```bash
12+
# On BOA
13+
ps -eo pid,ppid,cmd | grep -E 'vllm serve|VLLM::EngineCore' | grep -v grep
14+
ss -ltnp | grep -E ':8000|:8005|:8080' || true
15+
```
16+
17+
Goal: exactly one active vLLM server listener.
18+
19+
### 2. Ensure there is at most one vLLM server on BOA
20+
21+
If multiple vLLM instances exist, stop extras. Keep only the intended `boa` server.
22+
23+
```bash
24+
# On BOA (example: stop old qwen3_coder_30b_a3b_instruct_fp8 launch)
25+
pkill -f 'vllm serve ~arjun/models/qwen3_coder_30b_a3b_instruct_fp8' || true
26+
```
27+
28+
Re-check:
29+
30+
```bash
31+
ps -eo pid,ppid,cmd | grep -E 'vllm serve|VLLM::EngineCore' | grep -v grep
32+
ss -ltnp | grep -E ':8000|:8005|:8080' || true
33+
```
34+
35+
### 3. Pick the BOA port/model naming that LiteLLM expects
36+
37+
For `litellm.guha-anderson.com` routing to model group `boa`, use:
38+
39+
- `--served-model-name boa`
40+
- `--host 0.0.0.0`
41+
- `--port 8000`
42+
- `--enable-auto-tool-choice`
43+
- `--tool-call-parser qwen3_xml`
44+
- `--enable-prefix-caching`
45+
46+
(Using port `8080` worked for direct VPN calls but did not route through LiteLLM in our validated run.)
47+
48+
### 4. Launch vLLM on BOA in background with log file
49+
50+
Use `nohup` and a dedicated log:
51+
52+
```bash
53+
# On BOA
54+
nohup env CUDA_VISIBLE_DEVICES=3 \
55+
uvx --from vllm==0.15.0 vllm serve ~arjun/models/qwen3_coder_30b_a3b_instruct_fp8 \
56+
--host 0.0.0.0 \
57+
--port 8000 \
58+
--served-model-name boa \
59+
--enable-auto-tool-choice \
60+
--tool-call-parser qwen3_xml \
61+
--enable-prefix-caching \
62+
> ~/vllm_boa_8000.log 2>&1 < /dev/null &
63+
```
64+
65+
Wait for readiness:
66+
67+
```bash
68+
# On BOA
69+
curl -s --max-time 3 http://localhost:8000/v1/models
70+
tail -n 120 ~/vllm_boa_8000.log
71+
```
72+
73+
### 5. Verify connectivity from this host
74+
75+
Direct VPN path (fallback):
76+
77+
```bash
78+
curl -sS --max-time 8 http://192.168.50.7:8000/v1/models
79+
```
80+
81+
LiteLLM path (preferred for this workflow):
82+
83+
```bash
84+
curl -sS --max-time 20 https://litellm.guha-anderson.com/v1/chat/completions \
85+
-H "Authorization: Bearer $OPENAI_API_KEY" \
86+
-H "Content-Type: application/json" \
87+
-d '{"model":"boa","messages":[{"role":"user","content":"Reply with OK only."}],"max_tokens":8}'
88+
```
89+
90+
### 6. Run full validated workflow from this repo
91+
92+
Always run against an isolated working copy so the checked-in fixture under
93+
`test_projects/` stays unchanged:
94+
95+
```bash
96+
WORK_REPO=$(mktemp -d /tmp/scheme_interpreter_work.XXXXXX)
97+
cp -a test_projects/scheme_interpreter/. "$WORK_REPO/"
98+
git -C "$WORK_REPO" init
99+
git -C "$WORK_REPO" config user.name "workflow"
100+
git -C "$WORK_REPO" config user.email "workflow@example.invalid"
101+
git -C "$WORK_REPO" add .
102+
git -C "$WORK_REPO" commit -m "Initial scheme interpreter fixture snapshot"
103+
```
104+
105+
Then use the packaged resumable runner:
106+
107+
```bash
108+
OPENAI_API_BASE=https://litellm.guha-anderson.com \
109+
OPENAI_API_KEY=$OPENAI_API_KEY \
110+
uv run python3 -m buildabench_workshop.run_validated_workflow \
111+
--env-tips-path "$WORK_REPO/env_agent_tips.txt" \
112+
--validate-tips-path "$WORK_REPO/validate_task_tips.txt" \
113+
--agent codex \
114+
--model openai/boa \
115+
--num-candidates 3 \
116+
--state-dir workflow_state/scheme_interpreter \
117+
"$WORK_REPO" \
118+
"src/scheme_interpreter/*.py" \
119+
"tests/*.py"
120+
```
121+
122+
What resume means in this script:
123+
124+
1. If container already exists, it skips `env_agent`.
125+
2. If `tasks.jsonl` already has `N` tasks, it only asks `synth_task` for the remaining `num_candidates - N`.
126+
3. If `validated_tasks.jsonl` already contains some task IDs, it only runs `validate_task` for missing IDs.
127+
4. If `check_results.jsonl` already contains checked task IDs, it only runs `check_validated_tasks` for unchecked IDs.
128+
129+
Force a fresh run:
130+
131+
```bash
132+
OPENAI_API_BASE=https://litellm.guha-anderson.com \
133+
OPENAI_API_KEY=$OPENAI_API_KEY \
134+
uv run python3 -m buildabench_workshop.run_validated_workflow \
135+
--force-fresh \
136+
--env-tips-path "$WORK_REPO/env_agent_tips.txt" \
137+
--validate-tips-path "$WORK_REPO/validate_task_tips.txt" \
138+
--agent codex \
139+
--model openai/boa \
140+
--num-candidates 3 \
141+
--state-dir workflow_state/scheme_interpreter \
142+
"$WORK_REPO" \
143+
"src/scheme_interpreter/*.py" \
144+
"tests/*.py"
145+
```
146+
147+
State files created in `--state-dir`:
148+
149+
1. `tasks.jsonl`
150+
2. `validated_tasks.jsonl`
151+
3. `check_results.jsonl`
152+
4. `workflow.log`
153+
154+
Cleanup:
155+
156+
```bash
157+
rm -rf "$WORK_REPO"
158+
```
159+
160+
### 7. Manual validated workflow (human step-by-step)
161+
162+
If you want to run the pipeline manually and inspect each stage:
163+
164+
```bash
165+
export OPENAI_API_BASE=https://litellm.guha-anderson.com
166+
export OPENAI_API_KEY=$OPENAI_API_KEY
167+
export CONTAINER_NAME=env_agent__scheme_interpreter_manual
168+
export WORK_REPO=$(mktemp -d /tmp/scheme_interpreter_manual.XXXXXX)
169+
cp -a test_projects/scheme_interpreter/. "$WORK_REPO/"
170+
git -C "$WORK_REPO" init
171+
git -C "$WORK_REPO" config user.name "workflow"
172+
git -C "$WORK_REPO" config user.email "workflow@example.invalid"
173+
git -C "$WORK_REPO" add .
174+
git -C "$WORK_REPO" commit -m "Initial scheme interpreter fixture snapshot"
175+
```
176+
177+
1. Build container only if missing:
178+
179+
```bash
180+
podman image exists "$CONTAINER_NAME" || \
181+
uv run python3 -m buildabench_workshop.env_agent \
182+
--repo "$WORK_REPO" \
183+
--tips-path "$WORK_REPO/env_agent_tips.txt" \
184+
--agent codex \
185+
--container "$CONTAINER_NAME"
186+
```
187+
188+
2. Synthesize tasks:
189+
190+
```bash
191+
uv run python3 -m buildabench_workshop.synth_task \
192+
--json \
193+
--num-candidates 3 \
194+
--model openai/boa \
195+
"$WORK_REPO" \
196+
"src/scheme_interpreter/*.py" \
197+
"tests/*.py" \
198+
> tasks.jsonl
199+
```
200+
201+
3. Validate tasks sequentially:
202+
203+
```bash
204+
start=$(( $(wc -l < validated_tasks.jsonl 2>/dev/null || echo 0) + 1 ))
205+
end=$(wc -l < tasks.jsonl)
206+
for i in $(seq "$start" "$end"); do
207+
sed -n "${i}p" tasks.jsonl | \
208+
uv run python3 -m buildabench_workshop.validate_task \
209+
--tips-path "$WORK_REPO/validate_task_tips.txt" \
210+
--agent codex \
211+
--input-json \
212+
--output-json \
213+
>> validated_tasks.jsonl
214+
done
215+
```
216+
217+
4. LLM-free validation:
218+
219+
```bash
220+
uv run python3 -m buildabench_workshop.check_validated_tasks validated_tasks.jsonl
221+
```
222+
223+
5. Cleanup the isolated repo and container:
224+
225+
```bash
226+
podman image rm -f "$CONTAINER_NAME" || true
227+
rm -rf "$WORK_REPO"
228+
```
229+
### 8. Quick diagnostics if LiteLLM fails for `model=boa`
230+
231+
1. Confirm BOA server is on `:8000` and model name is exactly `boa`.
232+
2. Confirm only one BOA vLLM server is running.
233+
3. Validate BOA local endpoint:
234+
- `curl http://localhost:8000/v1/models`
235+
4. Validate from this host over VPN:
236+
- `curl http://192.168.50.7:8000/v1/models`
237+
5. Retry LiteLLM completion call with `model=boa`.

‎Makefile‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
.PHONY: test
1+
.PHONY: test dep
2+
3+
dep:
4+
uv sync
25

36
test:
47
uv run -m pytest tests -v

0 commit comments

Comments
 (0)