hospital-ed / client.py
testingaccc's picture
Upload folder using huggingface_hub
0fe00d1 verified
Raw
History Blame Contribute Delete
4.55 kB
"""Typed OpenEnv client for the Hospital ED environment.
Maintains a persistent WebSocket connection to a running Hospital ED
server and exposes typed ``reset()`` / ``step()`` / ``state()`` methods
that return :class:`HospitalObservation` and :class:`HospitalState`.
Use this from the baseline ``inference.py`` or any other LLM agent
driver, either pointing it at a locally-running server or spinning up
a fresh Docker container via :meth:`HospitalEdEnv.from_docker_image`::
# Connect to a running server
with HospitalEdEnv(base_url="http://localhost:8000") as client:
result = client.reset(task="surge", seed=0)
while not result.done:
result = client.step(HospitalAction(action=0))
# Or launch a fresh container (hackathon inference pattern)
client = HospitalEdEnv.from_docker_image("hospital-ed-env:latest")
"""
from __future__ import annotations
from typing import Any, Dict
from openenv.core import EnvClient
from openenv.core.client_types import StepResult
from models import HospitalAction, HospitalObservation, HospitalState
class HospitalEdEnv(
EnvClient[HospitalAction, HospitalObservation, HospitalState]
):
"""Client for the Hospital Emergency Department OpenEnv environment.
This client maintains a persistent WebSocket connection to the
environment server, enabling efficient multi-step interactions with
lower latency. Each instance holds a dedicated session on the server.
"""
# ------------------------------------------------------------------
# OpenEnv EnvClient hooks
# ------------------------------------------------------------------
def _step_payload(self, action: HospitalAction) -> Dict[str, Any]:
"""Serialize ``action`` to the JSON payload expected by ``/step``."""
return {"action": int(action.action)}
def _parse_result(
self, payload: Dict[str, Any]
) -> StepResult[HospitalObservation]:
"""Parse a server response into a typed :class:`StepResult`."""
obs_data = payload.get("observation", payload) or {}
observation = HospitalObservation(
done=bool(payload.get("done", obs_data.get("done", False))),
reward=payload.get("reward", obs_data.get("reward")),
metadata=obs_data.get("metadata", {}) or {},
bed_occupancy=list(obs_data.get("bed_occupancy", [])),
icu_occupancy=list(obs_data.get("icu_occupancy", [])),
ventilator_status=list(obs_data.get("ventilator_status", [])),
waiting_queue=[
list(row) for row in obs_data.get("waiting_queue", [])
],
time_step=int(obs_data.get("time_step", 0) or 0),
stats=list(obs_data.get("stats", [])),
action_mask=[bool(x) for x in obs_data.get("action_mask", [])],
survival_rate=float(obs_data.get("survival_rate", 0.0) or 0.0),
critical_survival_rate=float(
obs_data.get("critical_survival_rate", 1.0) or 1.0
),
task_score=float(obs_data.get("task_score", 0.0) or 0.0),
task=obs_data.get("task"),
)
return StepResult(
observation=observation,
reward=payload.get("reward"),
done=bool(payload.get("done", False)),
)
def _parse_state(self, payload: Dict[str, Any]) -> HospitalState:
"""Parse a ``/state`` payload into a typed :class:`HospitalState`."""
return HospitalState(
episode_id=payload.get("episode_id"),
step_count=int(payload.get("step_count", 0) or 0),
total_treated=int(payload.get("total_treated", 0) or 0),
total_deaths=int(payload.get("total_deaths", 0) or 0),
total_admitted=int(payload.get("total_admitted", 0) or 0),
critical_total=int(payload.get("critical_total", 0) or 0),
critical_saved=int(payload.get("critical_saved", 0) or 0),
queue_len=int(payload.get("queue_len", 0) or 0),
general_occupancy=float(payload.get("general_occupancy", 0.0) or 0.0),
icu_occupancy=float(payload.get("icu_occupancy", 0.0) or 0.0),
ventilator_utilization=float(
payload.get("ventilator_utilization", 0.0) or 0.0
),
invalid_action_rate=float(
payload.get("invalid_action_rate", 0.0) or 0.0
),
episode_reward=float(payload.get("episode_reward", 0.0) or 0.0),
scenario=payload.get("scenario"),
)