thomasm6m6 commited on
Commit
de55468
·
verified ·
1 Parent(s): 432be03

Restore minimal OpenEnv app with logs

Browse files
Files changed (1) hide show
  1. minimal_openenv_app.py +155 -0
minimal_openenv_app.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import time
5
+ from pathlib import Path
6
+ from typing import Literal
7
+ from uuid import uuid4
8
+
9
+ from fastapi import Request
10
+ from fastapi.responses import PlainTextResponse, RedirectResponse
11
+ from openenv.core.env_server import create_app
12
+ from openenv.core.env_server.interfaces import Environment
13
+ from openenv.core.env_server.types import Action, Observation, State
14
+ from pydantic import Field
15
+
16
+
17
+ LOG_PATH = Path("/tmp/minimal-space.log")
18
+ START_TS = time.strftime("%Y-%m-%dT%H:%M:%S%z")
19
+
20
+
21
+ def log(message: str) -> None:
22
+ line = f"[{time.strftime('%Y-%m-%dT%H:%M:%S%z')}] {message}"
23
+ print(line, flush=True)
24
+ try:
25
+ with LOG_PATH.open("a", encoding="utf-8") as f:
26
+ f.write(line + "\n")
27
+ except Exception:
28
+ pass
29
+
30
+
31
+ class MinimalAction(Action):
32
+ action_type: Literal["noop", "increment", "finish"] = "noop"
33
+ amount: int = Field(default=1, ge=1, le=3)
34
+
35
+
36
+ class MinimalObservation(Observation):
37
+ status: str
38
+ counter: int
39
+ summary: str
40
+ reward: float = 0.0
41
+ done: bool = False
42
+
43
+
44
+ class MinimalState(State):
45
+ counter: int = 0
46
+
47
+
48
+ class MinimalEnvironment(Environment[MinimalAction, MinimalObservation, MinimalState]):
49
+ SUPPORTS_CONCURRENT_SESSIONS = False
50
+
51
+ def __init__(self):
52
+ super().__init__()
53
+ log("MinimalEnvironment.__init__ begin")
54
+ self._done = False
55
+ self._state = MinimalState(episode_id=str(uuid4()), step_count=0, counter=0)
56
+ log("MinimalEnvironment.__init__ end")
57
+
58
+ def reset(self, seed: int | None = None, episode_id: str | None = None, **kwargs) -> MinimalObservation:
59
+ log(f"reset begin seed={seed} episode_id={episode_id} kwargs={kwargs}")
60
+ self._done = False
61
+ self._state = MinimalState(
62
+ episode_id=episode_id or str(uuid4()),
63
+ step_count=0,
64
+ counter=0,
65
+ )
66
+ obs = self._observation(status="ready", reward=0.0, done=False)
67
+ log(f"reset end episode_id={self._state.episode_id}")
68
+ return obs
69
+
70
+ def step(self, action: MinimalAction, timeout_s: float | None = None, **kwargs) -> MinimalObservation:
71
+ log(f"step begin action={action.model_dump()} timeout_s={timeout_s} kwargs={kwargs}")
72
+ if self._done:
73
+ obs = self._observation(status="done", reward=0.0, done=True)
74
+ log("step end already done")
75
+ return obs
76
+
77
+ self._state.step_count += 1
78
+ reward = 0.0
79
+ status = "ok"
80
+
81
+ if action.action_type == "increment":
82
+ self._state.counter += action.amount
83
+ reward = float(action.amount)
84
+ elif action.action_type == "finish":
85
+ self._done = True
86
+ status = "finished"
87
+
88
+ if self._state.step_count >= 8:
89
+ self._done = True
90
+ status = "finished"
91
+
92
+ obs = self._observation(status=status, reward=reward, done=self._done)
93
+ log(f"step end counter={self._state.counter} step_count={self._state.step_count} done={self._done}")
94
+ return obs
95
+
96
+ @property
97
+ def state(self) -> MinimalState:
98
+ log("state property")
99
+ return self._state
100
+
101
+ def close(self) -> None:
102
+ log("close")
103
+
104
+ def _observation(self, *, status: str, reward: float, done: bool) -> MinimalObservation:
105
+ return MinimalObservation(
106
+ status=status,
107
+ counter=self._state.counter,
108
+ summary=(
109
+ f"Minimal OpenEnv demo. Counter={self._state.counter}. "
110
+ f"Step={self._state.step_count}. "
111
+ f"Choose noop, increment, or finish."
112
+ ),
113
+ reward=reward,
114
+ done=done,
115
+ )
116
+
117
+
118
+ log("minimal_openenv_app module import begin")
119
+ app = create_app(MinimalEnvironment, MinimalAction, MinimalObservation, env_name="minimal_openenv")
120
+ log("openenv app created")
121
+
122
+
123
+ @app.on_event("startup")
124
+ async def startup() -> None:
125
+ log("startup event begin")
126
+ log(f"python={os.sys.version.split()[0]}")
127
+ log(f"cwd={os.getcwd()}")
128
+ log(f"enable_web={os.getenv('ENABLE_WEB_INTERFACE')}")
129
+ log("startup event end")
130
+
131
+
132
+ @app.middleware("http")
133
+ async def request_logger(request: Request, call_next):
134
+ log(f"request start method={request.method} path={request.url.path}")
135
+ response = await call_next(request)
136
+ log(f"request end method={request.method} path={request.url.path} status={response.status_code}")
137
+ return response
138
+
139
+
140
+ @app.get("/", include_in_schema=False)
141
+ def root() -> RedirectResponse:
142
+ log("root redirect")
143
+ return RedirectResponse(url="/web")
144
+
145
+
146
+ @app.get("/logs", include_in_schema=False)
147
+ def logs() -> PlainTextResponse:
148
+ log("logs handler")
149
+ try:
150
+ return PlainTextResponse(LOG_PATH.read_text(encoding="utf-8"))
151
+ except FileNotFoundError:
152
+ return PlainTextResponse("no log file yet\n")
153
+
154
+
155
+ log("minimal_openenv_app module import end")