Ramachandra Dayal K commited on
Commit ·
e2284e6
1
Parent(s): e88fa8b
fix: resolve openEnv reset response inconsistency and port mismatch
Browse files- README.md +5 -5
- app.py +15 -6
- index.html +16 -11
- test_env.py +40 -19
README.md
CHANGED
|
@@ -39,8 +39,8 @@ pip install -r requirements.txt
|
|
| 39 |
### Try it out
|
| 40 |
|
| 41 |
```bash
|
| 42 |
-
|
| 43 |
-
|
| 44 |
```
|
| 45 |
|
| 46 |
Quick Local Test Snippet:
|
|
@@ -48,12 +48,12 @@ Quick Local Test Snippet:
|
|
| 48 |
import requests
|
| 49 |
|
| 50 |
# Reset environment
|
| 51 |
-
resp = requests.post("http://localhost:
|
| 52 |
-
obs = resp.json()
|
| 53 |
print("Reset observation:", obs)
|
| 54 |
|
| 55 |
# Take step
|
| 56 |
-
resp = requests.post("http://localhost:
|
| 57 |
print("Step result:", resp.json())
|
| 58 |
```
|
| 59 |
|
|
|
|
| 39 |
### Try it out
|
| 40 |
|
| 41 |
```bash
|
| 42 |
+
# Run the FastAPI server
|
| 43 |
+
python app.py
|
| 44 |
```
|
| 45 |
|
| 46 |
Quick Local Test Snippet:
|
|
|
|
| 48 |
import requests
|
| 49 |
|
| 50 |
# Reset environment
|
| 51 |
+
resp = requests.post("http://localhost:7860/reset", json={"task": "easy"})
|
| 52 |
+
obs = resp.json()["observation"]
|
| 53 |
print("Reset observation:", obs)
|
| 54 |
|
| 55 |
# Take step
|
| 56 |
+
resp = requests.post("http://localhost:7860/step", json={"action": {"action_type": "follow_prompt"}})
|
| 57 |
print("Step result:", resp.json())
|
| 58 |
```
|
| 59 |
|
app.py
CHANGED
|
@@ -2,6 +2,7 @@ from fastapi import FastAPI, HTTPException
|
|
| 2 |
from fastapi.responses import HTMLResponse
|
| 3 |
from fastapi.staticfiles import StaticFiles
|
| 4 |
from pydantic import BaseModel
|
|
|
|
| 5 |
import sys
|
| 6 |
import os
|
| 7 |
|
|
@@ -12,9 +13,13 @@ from server.llm_env import LLMEnv
|
|
| 12 |
|
| 13 |
app = FastAPI(title="LLM Control OpenEnv")
|
| 14 |
|
| 15 |
-
#
|
| 16 |
-
envs = {}
|
| 17 |
-
completed_episodes = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
class ResetRequest(BaseModel):
|
| 20 |
task: str = "easy"
|
|
@@ -38,20 +43,24 @@ async def serve_gui():
|
|
| 38 |
except FileNotFoundError:
|
| 39 |
return "GUI index.html not found. Check the root directory."
|
| 40 |
|
| 41 |
-
@app.post("/reset"
|
| 42 |
async def reset(req: ResetRequest):
|
| 43 |
if req.task not in ["easy", "medium", "hard"]:
|
| 44 |
raise HTTPException(status_code=400, detail="Invalid task")
|
| 45 |
|
| 46 |
env = LLMEnv(task=req.task)
|
| 47 |
obs = env.reset()
|
| 48 |
-
|
|
|
|
| 49 |
|
| 50 |
# Also set default env to the latest reset for easy single-agent testing
|
| 51 |
global default_env
|
| 52 |
default_env = env
|
| 53 |
|
| 54 |
-
return
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
@app.post("/step")
|
| 57 |
async def step(req: StepRequest):
|
|
|
|
| 2 |
from fastapi.responses import HTMLResponse
|
| 3 |
from fastapi.staticfiles import StaticFiles
|
| 4 |
from pydantic import BaseModel
|
| 5 |
+
from typing import Dict, Any
|
| 6 |
import sys
|
| 7 |
import os
|
| 8 |
|
|
|
|
| 13 |
|
| 14 |
app = FastAPI(title="LLM Control OpenEnv")
|
| 15 |
|
| 16 |
+
# Global in-memory store for environments and session state
|
| 17 |
+
envs: Dict[str, LLMEnv] = {}
|
| 18 |
+
completed_episodes: Dict[str, Dict[str, Any]] = {}
|
| 19 |
+
|
| 20 |
+
# Default global environment initialized with a reset state
|
| 21 |
+
default_env = LLMEnv()
|
| 22 |
+
default_env.reset()
|
| 23 |
|
| 24 |
class ResetRequest(BaseModel):
|
| 25 |
task: str = "easy"
|
|
|
|
| 43 |
except FileNotFoundError:
|
| 44 |
return "GUI index.html not found. Check the root directory."
|
| 45 |
|
| 46 |
+
@app.post("/reset")
|
| 47 |
async def reset(req: ResetRequest):
|
| 48 |
if req.task not in ["easy", "medium", "hard"]:
|
| 49 |
raise HTTPException(status_code=400, detail="Invalid task")
|
| 50 |
|
| 51 |
env = LLMEnv(task=req.task)
|
| 52 |
obs = env.reset()
|
| 53 |
+
state = env.state
|
| 54 |
+
envs[state.episode_id] = env
|
| 55 |
|
| 56 |
# Also set default env to the latest reset for easy single-agent testing
|
| 57 |
global default_env
|
| 58 |
default_env = env
|
| 59 |
|
| 60 |
+
return {
|
| 61 |
+
"observation": obs.model_dump(),
|
| 62 |
+
"state": state.model_dump()
|
| 63 |
+
}
|
| 64 |
|
| 65 |
@app.post("/step")
|
| 66 |
async def step(req: StepRequest):
|
index.html
CHANGED
|
@@ -241,17 +241,22 @@
|
|
| 241 |
|
| 242 |
async function resetEnv() {
|
| 243 |
log("Sending reset sequence...");
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
}
|
| 256 |
|
| 257 |
async function takeAction(actionType) {
|
|
|
|
| 241 |
|
| 242 |
async function resetEnv() {
|
| 243 |
log("Sending reset sequence...");
|
| 244 |
+
try {
|
| 245 |
+
const res = await fetch('/reset', {
|
| 246 |
+
method: 'POST',
|
| 247 |
+
headers: { 'Content-Type': 'application/json' },
|
| 248 |
+
body: JSON.stringify({ task: "medium" })
|
| 249 |
+
});
|
| 250 |
+
const data = await res.json();
|
| 251 |
+
updateUI(data.observation);
|
| 252 |
+
document.getElementById('reward-val').innerText = "0.00";
|
| 253 |
+
document.getElementById('reward-val').style.color = "var(--cyber-green)";
|
| 254 |
+
isDead = false;
|
| 255 |
+
log(`System Reset Complete. Episode ID: <span style="color:var(--cyber-blue); font-size: 0.7rem;">${data.state.episode_id}</span>`);
|
| 256 |
+
} catch (err) {
|
| 257 |
+
log("<span class='log-mi'>Error during reset. Check server console.</span>");
|
| 258 |
+
console.error(err);
|
| 259 |
+
}
|
| 260 |
}
|
| 261 |
|
| 262 |
async function takeAction(actionType) {
|
test_env.py
CHANGED
|
@@ -2,26 +2,47 @@ import requests
|
|
| 2 |
import json
|
| 3 |
|
| 4 |
def test():
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
print("
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
print("\nTaking an action: 'follow_prompt'...")
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
if __name__ == "__main__":
|
| 24 |
-
|
| 25 |
-
test()
|
| 26 |
-
except requests.exceptions.ConnectionError:
|
| 27 |
-
print("Error: Could not connect to the API. Is the server running on http://localhost:8000?")
|
|
|
|
| 2 |
import json
|
| 3 |
|
| 4 |
def test():
|
| 5 |
+
# Use the correct port 7860 as defined in app.py
|
| 6 |
+
base_url = "http://localhost:7860"
|
| 7 |
+
|
| 8 |
+
print(f"Resetting the environment (easy task) via {base_url}/reset...")
|
| 9 |
+
try:
|
| 10 |
+
resp = requests.post(f"{base_url}/reset", json={"task": "easy"})
|
| 11 |
+
resp.raise_for_status()
|
| 12 |
+
data = resp.json()
|
| 13 |
+
|
| 14 |
+
# New API returns a wrapped object: {"observation": ..., "state": ...}
|
| 15 |
+
obs = data["observation"]
|
| 16 |
+
episode_id = data["state"]["episode_id"]
|
| 17 |
+
|
| 18 |
+
print(f"Initial Observation (Episode: {episode_id}):")
|
| 19 |
+
print(json.dumps(obs, indent=2))
|
| 20 |
+
except (requests.exceptions.RequestException, KeyError) as e:
|
| 21 |
+
print(f"Error during reset: {e}")
|
| 22 |
+
return
|
| 23 |
|
| 24 |
print("\nTaking an action: 'follow_prompt'...")
|
| 25 |
+
try:
|
| 26 |
+
resp = requests.post(f"{base_url}/step", json={
|
| 27 |
+
"action": {"action_type": "follow_prompt"},
|
| 28 |
+
"episode_id": episode_id
|
| 29 |
+
})
|
| 30 |
+
resp.raise_for_status()
|
| 31 |
+
result = resp.json()
|
| 32 |
+
print("Step Result:")
|
| 33 |
+
print(json.dumps(result, indent=2))
|
| 34 |
+
|
| 35 |
+
print("\nTaking an action: 'minor_hallucination'...")
|
| 36 |
+
resp = requests.post(f"{base_url}/step", json={
|
| 37 |
+
"action": {"action_type": "minor_hallucination"},
|
| 38 |
+
"episode_id": episode_id
|
| 39 |
+
})
|
| 40 |
+
resp.raise_for_status()
|
| 41 |
+
result = resp.json()
|
| 42 |
+
print("Step Result:")
|
| 43 |
+
print(json.dumps(result, indent=2))
|
| 44 |
+
except Exception as e:
|
| 45 |
+
print(f"Error during steps: {e}")
|
| 46 |
|
| 47 |
if __name__ == "__main__":
|
| 48 |
+
test()
|
|
|
|
|
|
|
|
|