Spaces:
Sleeping
Sleeping
File size: 4,393 Bytes
6ff09d1 2819b19 6ff09d1 | 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 | #!/usr/bin/env python
"""Phase 2 verification β drives the env through the real OpenEnv HTTP+WS surface.
Boots the FastAPI app in a background uvicorn, connects via the sync EnvClient
(same path training code will use), and walks through reset -> unauth probe
(expect 401) -> authed probe (expect 200) -> update_model -> finalize.
Set env var SPACE_URL to hit a remote HF Space instead of a local server.
"""
from __future__ import annotations
import os
import sys
import threading
import time
HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(HERE)
if ROOT not in sys.path:
sys.path.insert(0, ROOT)
def _start_local_server(port: int) -> threading.Thread:
"""Launch uvicorn in a background thread."""
import uvicorn
from server.app import app # noqa: F401 β import to ensure app is built
config = uvicorn.Config(app, host="127.0.0.1", port=port, log_level="warning")
server = uvicorn.Server(config)
thread = threading.Thread(target=server.run, daemon=True)
thread.start()
# Wait for the server to come up
import httpx
for _ in range(50):
try:
r = httpx.get(f"http://127.0.0.1:{port}/health", timeout=0.5)
if r.status_code == 200:
return thread
except Exception:
pass
time.sleep(0.1)
raise RuntimeError("server never came up")
def main() -> int:
from client import ProtocolOneEnv
from models import ProtocolOneAction
space_url = os.environ.get("SPACE_URL")
if space_url:
print(f"Using remote SPACE_URL={space_url}")
base_url = space_url
else:
port = 8765
print(f"Booting local uvicorn on :{port} β¦")
_start_local_server(port)
base_url = f"http://127.0.0.1:{port}"
env = ProtocolOneEnv(base_url=base_url).sync()
with env:
# 1. Reset
result = env.reset()
text = result.observation.text or ""
# Be lenient about the exact wording -- "reverse-engineer", "map the structure",
# or any other framing of the task is fine.
probes_remaining = result.observation.probes_remaining
assert probes_remaining > 0, f"expected positive probes_remaining, got {probes_remaining}"
print(f"β Reset β {len(text)} char initial observation, probes_remaining={probes_remaining}")
# 2. Unauth probe -> expect 401
result = env.step(ProtocolOneAction(
tool="probe",
args={"method": "GET", "path": "/users"},
))
assert "401" in (result.observation.text or ""), (
f"expected 401 in unauth probe, got: {result.observation.text[:200]}"
)
print("β Unauthenticated probe β 401")
# 3. Authed probe -> expect 200
result = env.step(ProtocolOneAction(
tool="probe",
args={"method": "GET", "path": "/users",
"headers": {"Authorization": "Bearer token_full"}},
))
assert "200" in (result.observation.text or ""), (
f"expected 200 in authed probe, got: {result.observation.text[:200]}"
)
print("β Authed probe β 200")
# 4. update_model
result = env.step(ProtocolOneAction(
tool="update_model",
args={"delta": {
"endpoints": [
{"method": "GET", "path": "/users",
"auth_required": True, "auth_scope": "users:read"},
],
"auth": {"type": "bearer", "scopes_observed": ["users:read"]},
}},
))
stats = result.observation.belief_graph_stats
assert stats.get("endpoints") == 1, f"expected 1 endpoint, got {stats}"
assert stats.get("auth_scopes_observed") == 1
print(f"β update_model merged β stats={stats}")
# 5. finalize -> expect reward > 0 but < 0.3 (we only submitted one endpoint)
result = env.step(ProtocolOneAction(tool="finalize", args={}))
assert result.done
assert result.reward is not None
assert 0.0 < result.reward < 0.3, (
f"unexpected reward {result.reward} for single-endpoint finalize"
)
print(f"β Finalized β reward={result.reward:.3f} (expected in (0, 0.3))")
print("\nPhase 2 verified.")
return 0
if __name__ == "__main__":
sys.exit(main())
|