TalkingHeadBenchEnv / hackathon_changes.md
elix3r's picture
Upload folder using huggingface_hub
f755447 verified
|
Raw
History Blame Contribute Delete
13.1 kB
# 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 |