Sibam commited on
Commit
7574c9a
Β·
1 Parent(s): dada51b

fix: conform to OpenEnv base interface contract

Browse files
Files changed (4) hide show
  1. inference.py +9 -3
  2. server/environment.py +19 -17
  3. test_api.py +15 -11
  4. tests/test_environment.py +18 -19
inference.py CHANGED
@@ -115,7 +115,9 @@ def run_task1_pairwise(env_client) -> dict[str, Any]:
115
 
116
  from models import PairwiseAction
117
  action = PairwiseAction(choice=choice)
118
- obs, reward, done, info = env_client.step(action)
 
 
119
 
120
  total_reward += reward
121
  steps += 1
@@ -168,7 +170,9 @@ def run_task2_likert(env_client) -> dict[str, Any]:
168
  harmlessness=clamp("harmlessness"),
169
  instruction_following=clamp("instruction_following"),
170
  )
171
- obs, reward, done, info = env_client.step(action)
 
 
172
 
173
  total_reward += reward
174
  steps += 1
@@ -215,7 +219,9 @@ def run_task3_consistency(env_client) -> dict[str, Any]:
215
 
216
  from models import ConsistencyAction
217
  action = ConsistencyAction(ranking=ranking)
218
- obs, reward, done, info = env_client.step(action)
 
 
219
 
220
  total_reward += reward
221
  steps += 1
 
115
 
116
  from models import PairwiseAction
117
  action = PairwiseAction(choice=choice)
118
+ obs = env_client.step(action)
119
+ reward = obs.reward
120
+ done = obs.done
121
 
122
  total_reward += reward
123
  steps += 1
 
170
  harmlessness=clamp("harmlessness"),
171
  instruction_following=clamp("instruction_following"),
172
  )
173
+ obs = env_client.step(action)
174
+ reward = obs.reward
175
+ done = obs.done
176
 
177
  total_reward += reward
178
  steps += 1
 
219
 
220
  from models import ConsistencyAction
221
  action = ConsistencyAction(ranking=ranking)
222
+ obs = env_client.step(action)
223
+ reward = obs.reward
224
+ done = obs.done
225
 
226
  total_reward += reward
227
  steps += 1
server/environment.py CHANGED
@@ -2,9 +2,9 @@
2
  PreferenceLab Core Environment.
3
 
4
  Implements the OpenEnv Environment base class with:
5
- - reset() β†’ returns initial observation
6
- - step() β†’ executes action, returns (observation, reward, done, info)
7
- - state() β†’ returns episode metadata
8
 
9
  Three tasks:
10
  Task 1 (pairwise) - Easy: pairwise choice graded against HH-RLHF gold labels
@@ -20,6 +20,7 @@ from pathlib import Path
20
  from typing import Any
21
 
22
  from openenv.core.env_server import Environment
 
23
 
24
  from models import (
25
  ConsistencyAction,
@@ -258,7 +259,8 @@ class PreferenceLabEnvironment(Environment):
258
  timeout_s: Unused β€” required by base class signature.
259
 
260
  Returns:
261
- Tuple of (observation, reward, done, info).
 
262
  """
263
  self._step_count += 1
264
 
@@ -273,19 +275,19 @@ class PreferenceLabEnvironment(Environment):
273
  rng = random.Random(self._seed + self._step_count)
274
  self._current_example = self._sample_example(rng)
275
 
276
- obs = self._build_observation(reward=reward, done=done, info=info)
277
- return obs, reward, done, info
278
-
279
- def state(self) -> dict[str, Any]:
280
- """Return current episode metadata."""
281
- return {
282
- "episode_id": self._episode_id,
283
- "step_count": self._step_count,
284
- "task_type": self._task_type,
285
- "cumulative_reward": round(self._cumulative_reward, 4),
286
- "max_steps": MAX_STEPS_PER_EPISODE,
287
- "seed": self._seed,
288
- }
289
 
290
  # ── Internal helpers ──────────────────────────────────────
291
 
 
2
  PreferenceLab Core Environment.
3
 
4
  Implements the OpenEnv Environment base class with:
5
+ - reset() β†’ returns initial Observation
6
+ - step() β†’ executes action, returns Observation (reward & done embedded)
7
+ - state β†’ @property returning a State object with episode metadata
8
 
9
  Three tasks:
10
  Task 1 (pairwise) - Easy: pairwise choice graded against HH-RLHF gold labels
 
20
  from typing import Any
21
 
22
  from openenv.core.env_server import Environment
23
+ from openenv.core.env_server.types import State
24
 
25
  from models import (
26
  ConsistencyAction,
 
259
  timeout_s: Unused β€” required by base class signature.
260
 
261
  Returns:
262
+ Observation with reward and done embedded as fields.
263
+ Read obs.reward and obs.done instead of unpacking a tuple.
264
  """
265
  self._step_count += 1
266
 
 
275
  rng = random.Random(self._seed + self._step_count)
276
  self._current_example = self._sample_example(rng)
277
 
278
+ return self._build_observation(reward=reward, done=done, info=info)
279
+
280
+ @property
281
+ def state(self) -> State:
282
+ """Return current episode metadata as an openenv State object."""
283
+ return State(
284
+ episode_id=self._episode_id,
285
+ step_count=self._step_count,
286
+ task_type=self._task_type,
287
+ cumulative_reward=round(self._cumulative_reward, 4),
288
+ max_steps=MAX_STEPS_PER_EPISODE,
289
+ seed=self._seed,
290
+ )
291
 
292
  # ── Internal helpers ──────────────────────────────────────
293
 
test_api.py CHANGED
@@ -3,20 +3,24 @@ from models import PairwiseAction, LikertAction, ConsistencyAction
3
 
4
  env = PreferenceLabEnvironment()
5
 
6
- # Task 1
7
  obs = env.reset(seed=42, task_type='pairwise')
8
  print('TASK 1 prompt:', obs.prompt[:60])
9
- obs, r, done, _ = env.step(PairwiseAction(choice='A'))
10
- print('Reward:', r)
11
 
12
- # Task 2
13
  obs = env.reset(seed=42, task_type='likert')
14
- print('TASK 2 response:', obs.response[:60])
15
- obs, r, done, _ = env.step(LikertAction(helpfulness=5, honesty=5, harmlessness=5, instruction_following=5))
16
- print('Reward:', r)
17
 
18
- # Task 3
19
  obs = env.reset(seed=42, task_type='consistency')
20
- print('TASK 3 prompt:', obs.prompt[:60])
21
- obs, r, done, _ = env.step(ConsistencyAction(ranking=['C','A','B','D']))
22
- print('Reward:', r)
 
 
 
 
 
3
 
4
  env = PreferenceLabEnvironment()
5
 
6
+ # Task 1 – Pairwise
7
  obs = env.reset(seed=42, task_type='pairwise')
8
  print('TASK 1 prompt:', obs.prompt[:60])
9
+ obs = env.step(PairwiseAction(choice='A'))
10
+ print('Reward:', obs.reward, '| Done:', obs.done)
11
 
12
+ # Task 2 – Likert
13
  obs = env.reset(seed=42, task_type='likert')
14
+ print('\nTASK 2 response:', obs.response[:60])
15
+ obs = env.step(LikertAction(helpfulness=5, honesty=5, harmlessness=5, instruction_following=5))
16
+ print('Reward:', obs.reward, '| Done:', obs.done)
17
 
18
+ # Task 3 – Consistency
19
  obs = env.reset(seed=42, task_type='consistency')
20
+ print('\nTASK 3 prompt:', obs.prompt[:60])
21
+ obs = env.step(ConsistencyAction(ranking=['C', 'A', 'B', 'D']))
22
+ print('Reward:', obs.reward, '| Done:', obs.done)
23
+
24
+ # State (now a property, not a method call)
25
+ state = env.state
26
+ print('\nState:', state.model_dump())
tests/test_environment.py CHANGED
@@ -182,42 +182,43 @@ class TestPreferenceLabEnvironment:
182
  def test_step_pairwise(self):
183
  self.env.reset(task_type="pairwise")
184
  action = PairwiseAction(choice="A")
185
- obs, reward, done, info = self.env.step(action)
186
  assert isinstance(obs, PairwiseObservation)
187
- assert 0.0 <= reward <= 1.0
188
- assert isinstance(done, bool)
189
 
190
  def test_step_likert(self):
191
  self.env.reset(task_type="likert")
192
  action = LikertAction(helpfulness=4, honesty=4, harmlessness=5, instruction_following=4)
193
- obs, reward, done, info = self.env.step(action)
194
  assert isinstance(obs, LikertObservation)
195
- assert 0.0 <= reward <= 1.0
196
 
197
  def test_step_consistency(self):
198
  self.env.reset(task_type="consistency")
199
  action = ConsistencyAction(ranking=["A", "B", "C", "D"])
200
- obs, reward, done, info = self.env.step(action)
201
  assert isinstance(obs, ConsistencyObservation)
202
- assert 0.0 <= reward <= 1.0
203
 
204
  def test_episode_terminates_after_max_steps(self):
205
  self.env.reset(task_type="pairwise")
206
  done = False
207
  steps = 0
208
  while not done:
209
- _, _, done, _ = self.env.step(PairwiseAction(choice="A"))
 
210
  steps += 1
211
  assert steps <= 10, "Episode ran too long!"
212
  assert done is True
213
 
214
  def test_state_returns_metadata(self):
215
  self.env.reset(seed=42, task_type="pairwise")
216
- state = self.env.state()
217
- assert "episode_id" in state
218
- assert "step_count" in state
219
- assert "task_type" in state
220
- assert state["seed"] == 42
221
 
222
  def test_reproducible_with_seed(self):
223
  obs1 = self.env.reset(seed=123, task_type="pairwise")
@@ -230,13 +231,11 @@ class TestPreferenceLabEnvironment:
230
  rewards = set()
231
  for _ in range(5):
232
  self.env.reset(task_type="pairwise")
233
- action_a = PairwiseAction(choice="A")
234
- _, r1, _, _ = self.env.step(action_a)
235
  self.env.reset(task_type="pairwise")
236
- action_b = PairwiseAction(choice="B")
237
- _, r2, _, _ = self.env.step(action_b)
238
- rewards.add(r1)
239
- rewards.add(r2)
240
  assert len(rewards) > 1, "Grader always returns the same score β€” DISQUALIFICATION!"
241
 
242
  def test_all_three_tasks_run(self):
 
182
  def test_step_pairwise(self):
183
  self.env.reset(task_type="pairwise")
184
  action = PairwiseAction(choice="A")
185
+ obs = self.env.step(action)
186
  assert isinstance(obs, PairwiseObservation)
187
+ assert 0.0 <= obs.reward <= 1.0
188
+ assert isinstance(obs.done, bool)
189
 
190
  def test_step_likert(self):
191
  self.env.reset(task_type="likert")
192
  action = LikertAction(helpfulness=4, honesty=4, harmlessness=5, instruction_following=4)
193
+ obs = self.env.step(action)
194
  assert isinstance(obs, LikertObservation)
195
+ assert 0.0 <= obs.reward <= 1.0
196
 
197
  def test_step_consistency(self):
198
  self.env.reset(task_type="consistency")
199
  action = ConsistencyAction(ranking=["A", "B", "C", "D"])
200
+ obs = self.env.step(action)
201
  assert isinstance(obs, ConsistencyObservation)
202
+ assert 0.0 <= obs.reward <= 1.0
203
 
204
  def test_episode_terminates_after_max_steps(self):
205
  self.env.reset(task_type="pairwise")
206
  done = False
207
  steps = 0
208
  while not done:
209
+ obs = self.env.step(PairwiseAction(choice="A"))
210
+ done = obs.done
211
  steps += 1
212
  assert steps <= 10, "Episode ran too long!"
213
  assert done is True
214
 
215
  def test_state_returns_metadata(self):
216
  self.env.reset(seed=42, task_type="pairwise")
217
+ state = self.env.state
218
+ assert "episode_id" in state.model_dump()
219
+ assert "step_count" in state.model_dump()
220
+ assert "task_type" in state.model_dump()
221
+ assert state.seed == 42
222
 
223
  def test_reproducible_with_seed(self):
224
  obs1 = self.env.reset(seed=123, task_type="pairwise")
 
231
  rewards = set()
232
  for _ in range(5):
233
  self.env.reset(task_type="pairwise")
234
+ obs_a = self.env.step(PairwiseAction(choice="A"))
 
235
  self.env.reset(task_type="pairwise")
236
+ obs_b = self.env.step(PairwiseAction(choice="B"))
237
+ rewards.add(obs_a.reward)
238
+ rewards.add(obs_b.reward)
 
239
  assert len(rewards) > 1, "Grader always returns the same score β€” DISQUALIFICATION!"
240
 
241
  def test_all_three_tasks_run(self):