Spaces:
Sleeping
Sleeping
File size: 13,121 Bytes
f755447 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | # TalkingHeadBench β Hackathon Compliance Change Plan
A file-by-file breakdown of every change needed to fully comply with the
[OpenEnv hackathon requirements](./hackathon_requirements.md).
---
## 1. `inference.py` (ROOT) β MISSING, MUST CREATE
**Status: Does not exist.** This is an immediate disqualification condition.
### What it needs to do
- Connect to the running TalkingHeadBench environment at a configurable URL.
- Run a full benchmark episode across **all 3 task tiers** (image audit, clip audit,
weight audit) using test-set cases loaded from `tests/test_set/`.
- Use the **OpenAI Python client** (`from openai import OpenAI`) for LLM calls
β not the current raw `urllib`/`httpx` approach.
- Pull LLM config exclusively from the three required environment variables:
- `API_BASE_URL`
- `MODEL_NAME`
- `HF_TOKEN`
- Print a structured score report at the end: per-sub-env scores and the
weighted final score.
- Complete in under **20 minutes** on 2 vCPU / 8 GB RAM.
### Required structure (pseudocode)
```
inference.py
βββ Load API_BASE_URL, MODEL_NAME, HF_TOKEN from os.environ
βββ Instantiate: client = OpenAI(api_key=HF_TOKEN, base_url=API_BASE_URL)
βββ For each task: "image", "clips", "weights"
β βββ Call env.reset(mode=<task>) β via HTTP to the running server
β βββ Read observation, construct LLM prompt
β βββ Call client.chat.completions.create(model=MODEL_NAME, ...)
β βββ Parse structured JSON action
β βββ Call env.step(action)
β βββ Record reward / scores
βββ Print final score report
```
### Why `examples/simple_agent.py` does NOT qualify
- Uses raw `httpx` and manually constructed HF Inference Router calls instead of
the OpenAI Python client.
- Reads API key from `HF_API_KEY` / `HUGGINGFACEHUB_API_TOKEN`, not from the
required `HF_TOKEN` / `API_BASE_URL` / `MODEL_NAME` variables.
- Is not named `inference.py` and is not in the root directory.
- Does not iterate over all 3 task tiers with per-sub-env scoring output.
---
## 2. `server/llm_adapter.py` β LLM Client Replace
**Status: Uses raw `urllib.request` for HTTP calls β no OpenAI client.**
### Lines affected
- `_call_openai()` (L627β667): uses `_http_post_json()` via `urllib`. Must be
replaced with `client.chat.completions.create(...)`.
- `_call_anthropic()` (L669β697): same issue.
- `_call_huggingface()` (L700β776): same issue β currently uses `urllib`
directly to `router.huggingface.co`.
- All calls to `_http_post_json()` from provider functions should be replaced.
### Changes needed
1. Add `from openai import OpenAI` at the top.
2. Replace `_call_openai()` to use the OpenAI client:
```python
client = OpenAI(api_key=api_key, base_url=base_url or "https://api.openai.com/v1")
response = client.chat.completions.create(model=model_id, messages=..., ...)
return response.choices[0].message.content
```
3. Replace `_call_huggingface()` to also use OpenAI client pointed at
`https://router.huggingface.co/v1`:
```python
client = OpenAI(api_key=api_key, base_url="https://router.huggingface.co/v1")
```
4. Replace `_call_anthropic()` β either use the Anthropic SDK or the OpenAI
client via the Anthropic OpenAI-compatible endpoint.
5. Add `openai>=1.0` to `server/requirements.txt` and root `requirements.txt`.
### Why this matters
The hackathon rules explicitly state: **"Participants must use OpenAI Client for
all LLM calls"**. Using raw `urllib.request` violates this even if the wire
protocol is identical.
---
## 3. `server/requirements.txt` β ADD `openai`
**Status: Missing `openai` package.**
```diff
openenv-core[core]>=0.2.2,<0.3
fastapi>=0.115.0
pydantic>=2.0
uvicorn>=0.24.0
+ openai>=1.0
numpy
torch
scipy
safetensors
opencv-python
mediapipe
```
---
## 4. `requirements.txt` (ROOT) β ADD `openai`
**Status: Missing `openai` package.**
```diff
numpy
torch
pydantic>=2.0
scipy
safetensors
opencv-python
mediapipe>=0.10.33
+ openai>=1.0
pytest
```
---
## 5. `pyproject.toml` β ADD `openai` to dependencies
**Status: `openai` is absent from the package's dependency list.**
```diff
dependencies = [
"openenv-core[core]>=0.2.2,<0.3",
"fastapi>=0.115.0",
"pydantic>=2.0",
"uvicorn>=0.24.0",
"numpy",
"torch",
"scipy",
"safetensors",
"opencv-python",
"mediapipe",
+ "openai>=1.0",
]
```
---
## 6. `server/Dockerfile` β VALIDATE ENV VAR PASSTHROUGH
**Status: Partially compliant. Does not explicitly declare required env vars.**
The Dockerfile currently just copies files and runs uvicorn. No issue with the
build itself, but the following should be verified / added:
```dockerfile
# Add explicit ARG/ENV declarations so evaluators can see the required
# environment variables are expected and forwarded at runtime.
ENV API_BASE_URL=""
ENV MODEL_NAME=""
ENV HF_TOKEN=""
```
Also confirm the image actually builds without network access to pip:
- `torch` is very heavy. Consider using `torch --index-url
https://download.pytorch.org/whl/cpu` for a CPU-only build since the
infrastructure constraint is 2 vCPU / 8 GB RAM (no GPU). This will also
substantially reduce image size.
```diff
- RUN pip install --no-cache-dir -r /app/requirements.txt
+ RUN pip install --no-cache-dir -r /app/requirements.txt \
+ --extra-index-url https://download.pytorch.org/whl/cpu
```
---
## 7. `openenv.yaml` β OPTIONALLY CLEAN UP CUSTOM VARS
**Status: Mostly fine. Contains two non-standard env vars that may confuse validators.**
```yaml
# Current:
env_vars:
- API_BASE_URL
- MODEL_NAME
- HF_TOKEN
- THB_ALLOW_CUSTOM_BASE_URLS # <-- custom, not required by spec
- THB_ALLOWED_BASE_URL_PREFIXES # <-- custom, not required by spec
```
These two extra env vars are not harmful, but if the validator script only
checks for the three required ones, they may be flagged as unexpected. Consider
moving them to a comment block or keeping them with a clear inline explanation.
---
## 8. `examples/simple_agent.py` β DOES NOT USE OPENAI CLIENT
**Status: Uses raw `httpx` + custom HF URL. Needs to be converted but is NOT
the `inference.py` required by the hackathon.**
- This file uses `httpx.Client` with a manually constructed HF router URL.
- It reads from `HF_API_KEY` / `HUGGINGFACEHUB_API_TOKEN` instead of the
required variable names.
This file should either:
1. Be **left as-is** (fine, it's an example), but `inference.py` at root
level must be written from scratch using the OpenAI client **and** the
correct env var names (`API_BASE_URL`, `MODEL_NAME`, `HF_TOKEN`).
2. Or be **upgraded** to use the OpenAI client as well to avoid confusion.
---
## 9. `server/talking_head_environment.py` β COMBINED EPISODE REWARD FORMULA
**Status: The per-episode reward formula for individual task modes is correct.
However, the COMBINED reward formula hardcoded in `_handle_node8_action()` does
NOT match the REWARD_LOGIC.md documentation.**
### The discrepancy
- `REWARD_LOGIC.md` (and `models.py` docstring, line 12) states the final reward
across ALL three sub-envs is:
```
final_reward = 0.25 * subenv1 + 0.35 * subenv2 + 0.40 * subenv3
```
- But `_handle_node8_action()` (L590β591) uses:
```python
final_score = 0.50 * s2 + 0.50 * s3
```
β¦for `clips_and_weights` mode, which is a different formula and excludes subenv1.
If the hackathon evaluators run a full-episode combined audit and compare
reported scores against your REWARD_LOGIC.md, this inconsistency will be
flagged.
### Fix needed
Either:
- Update `REWARD_LOGIC.md` to explicitly document the per-mode formulas (it
currently only documents the "global" combined formula), OR
- Implement a proper 3-way episode type that runs `subenv1 + subenv2 + subenv3`
with the full `0.25/0.35/0.40` weighting.
---
## 10. `server/app.py` β `MODEL_NAME` / `API_BASE_URL` NOT USED BY SERVER ITSELF
**Status: The server reads LLM settings from the `AnalyzeIngestionRequest`
body (per-request model override), not from the required standard env vars.**
The hackathon spec requires `API_BASE_URL`, `MODEL_NAME`, and `HF_TOKEN` to be
defined in the environment configuration and used for all LLM calls. Currently:
- `API_BASE_URL` and `MODEL_NAME` are declared in `openenv.yaml` as expected vars
but the server's `analyze_ingestion` endpoint ignores them β it reads
`request.model_id` and `request.base_url` from the request body instead.
- The env vars are never fetched with `os.environ.get("MODEL_NAME")` etc.
### Fix needed
In `server/app.py` (or `server/llm_adapter.py`), the `analyze_ingested_bundle`
function should default to the env vars when the request body fields are absent:
```python
import os
model_id = request.model_id or os.environ.get("MODEL_NAME")
api_key = request.api_key or os.environ.get("HF_TOKEN")
base_url = request.base_url or os.environ.get("API_BASE_URL")
```
---
## 11. README.md β MISSING ACTION/OBSERVATION SPACE TABLE
**Status: The README documents architecture, scoring, and deployment. However,
it lacks a dedicated, explicit Action Space / Observation Space section.**
The hackathon spec requires:
> "README with environment description, action/observation spaces, setup instructions"
The current README has architecture diagrams and episode flow tables but no
clean, dedicated section labelled "Action Space" / "Observation Space" that
clearly lists all fields, types, and ranges in a format a new agent developer
could immediately use.
### Add a section like:
```markdown
## Action & Observation Spaces
### Observation Space (reset output per mode)
| Mode | Schema | Key Fields |
|---------|-----------------------------|-----------------------------------------|
| image | ImageDiagnosticsObservation | face_occupancy_ratio, yaw_degrees, ... |
| clips | ClipDispositionObservation | evidence_dossier, marginal_drift, ... |
| weights | PhonemeRiskObservation | layer_entropy, rank_utilization, ... |
### Action Space (step input per mode)
| Mode | Schema | Key Fields |
|---------|-------------------------|----------------------------------------------|
| image | ImageDiagnosticsAction | regime_classification, risk_factors, score |
| clips | ClipDispositionAction | disposition, fix_instructions, override |
| weights | PhonemeRiskAction | phoneme_risk_ranking, mitigation_recs, ... |
All numeric reward outputs are bounded in [0.0, 1.0].
```
---
## 12. `examples/simple_agent.py` β ESCAPE SEQUENCES BUG
**Status: Minor but causes broken prompts at runtime.**
Lines 282β288: The `build_user_prompt()` function uses Python literal `\\n`
(escaped backslash + n) inside a regular string, which means the actual prompt
string will contain the two characters `\n` instead of a real newline:
```python
# Current (BROKEN β sends literal \n characters):
f"Environment step index: {step_index}\\n"
# Should be:
f"Environment step index: {step_index}\n"
```
This affects all agent prompts and will cause the LLM to receive mangled
single-line instructions rather than well-structured multi-line prompts.
---
## 13. `server/llm_adapter.py` β `_call_local()` FALLS THROUGH TO OLLAMA FORMAT
**Status: When no `base_url` is provided for the `local` provider, it sends
requests to the Ollama native API format (`/api/generate`) with a `prompt` key
rather than the OpenAI-compatible chat completions format.**
This means if evaluators provide `API_BASE_URL` pointing to any OpenAI-compatible
local server (vLLM, LM Studio, etc.), the request format will be wrong.
### Fix needed
`_call_local()` should always use the OpenAI-compatible endpoint:
```python
client = OpenAI(api_key="local", base_url=base_url or "http://localhost:11434/v1")
response = client.chat.completions.create(...)
```
---
## Summary Priority Table
| Priority | File | Change |
|----------|------|--------|
| π¨ CRITICAL | `inference.py` | CREATE from scratch using OpenAI client + correct env vars |
| π¨ CRITICAL | `server/llm_adapter.py` | Replace all `urllib`/`httpx` calls with OpenAI Python client |
| π¨ CRITICAL | `server/requirements.txt` | Add `openai>=1.0` |
| π¨ CRITICAL | `requirements.txt` | Add `openai>=1.0` |
| π¨ CRITICAL | `pyproject.toml` | Add `openai>=1.0` to dependencies |
| π΄ HIGH | `server/app.py` | Default `model_id`, `api_key`, `base_url` from env vars |
| π΄ HIGH | `README.md` | Add explicit Action/Observation Space section |
| π‘ MEDIUM | `server/Dockerfile` | Declare ENV vars; switch to CPU torch wheel |
| π‘ MEDIUM | `server/talking_head_environment.py` | Clarify/fix reward formula discrepancy vs REWARD_LOGIC.md |
| π‘ MEDIUM | `examples/simple_agent.py` | Fix `\\n` escape sequence bug in prompt builder |
| π’ LOW | `openenv.yaml` | Annotate/clean up non-standard env vars |
| π’ LOW | `examples/simple_agent.py` | Switch to OpenAI client + correct env var names |
|