Skip to content

Commit 7a5996b

Browse files
authored
refactor rubric hook helpers (#892)
1 parent 0d570fa commit 7a5996b

2 files changed

Lines changed: 59 additions & 165 deletions

File tree

src/openenv/core/rubrics/base.py

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,25 +81,35 @@ def __call__(self, action: Any, observation: Any):
8181

8282
def _call_sync(self, action: Any, observation: Any, result: float) -> float:
8383
"""Synchronous call path."""
84-
self.last_score = result
84+
return self._finish_forward(action, observation, result)
8585

86-
# Post-forward hooks
87-
for hook in self._forward_hooks:
88-
hook(self, action, observation, result)
89-
90-
return result
86+
def _run_forward_pre_hooks(self, action: Any, observation: Any) -> None:
87+
"""Run pre-forward hooks synchronously."""
88+
for hook in self._forward_pre_hooks:
89+
hook(self, action, observation)
9190

92-
async def _call_async(self, action: Any, observation: Any, result_coro) -> float:
93-
"""Asynchronous call path."""
94-
# Pre-forward hooks
91+
async def _run_forward_pre_hooks_async(self, action: Any, observation: Any) -> None:
92+
"""Run pre-forward hooks from an async call path."""
9593
for hook in self._forward_pre_hooks:
9694
if inspect.iscoroutinefunction(hook):
9795
await hook(self, action, observation)
9896
else:
9997
hook(self, action, observation)
10098

101-
# Await the forward result
102-
result = await result_coro
99+
def _finish_forward(self, action: Any, observation: Any, result: float) -> float:
100+
"""Store the result and run post-forward hooks synchronously."""
101+
self.last_score = result
102+
103+
# Post-forward hooks
104+
for hook in self._forward_hooks:
105+
hook(self, action, observation, result)
106+
107+
return result
108+
109+
async def _finish_forward_async(
110+
self, action: Any, observation: Any, result: float
111+
) -> float:
112+
"""Store the result and run post-forward hooks from an async call path."""
103113
self.last_score = result
104114

105115
# Post-forward hooks
@@ -111,6 +121,15 @@ async def _call_async(self, action: Any, observation: Any, result_coro) -> float
111121

112122
return result
113123

124+
async def _call_async(self, action: Any, observation: Any, result_coro) -> float:
125+
"""Asynchronous call path."""
126+
# Pre-forward hooks
127+
await self._run_forward_pre_hooks_async(action, observation)
128+
129+
# Await the forward result
130+
result = await result_coro
131+
return await self._finish_forward_async(action, observation, result)
132+
114133
@abstractmethod
115134
def forward(self, action: Any, observation: Any) -> float:
116135
"""Compute the reward. Implement this in subclasses.

src/openenv/core/rubrics/containers.py

Lines changed: 29 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,8 @@ def __call__(self, action: Any, observation: Any):
7575
if _in_async_context():
7676
return self._empty_async(action, observation)
7777
else:
78-
# Pre-hooks
79-
for hook in self._forward_pre_hooks:
80-
hook(self, action, observation)
81-
result = 1.0
82-
self.last_score = result
83-
for hook in self._forward_hooks:
84-
hook(self, action, observation, result)
85-
return result
78+
self._run_forward_pre_hooks(action, observation)
79+
return self._finish_forward(action, observation, 1.0)
8680

8781
# Call first rubric to see if it's async
8882
first_result = self._rubric_list[0](action, observation)
@@ -92,13 +86,8 @@ def __call__(self, action: Any, observation: Any):
9286
else:
9387
# Continue with sync path
9488
if first_result == 0.0:
95-
# Pre-hooks
96-
for hook in self._forward_pre_hooks:
97-
hook(self, action, observation)
98-
self.last_score = 0.0
99-
for hook in self._forward_hooks:
100-
hook(self, action, observation, 0.0)
101-
return 0.0
89+
self._run_forward_pre_hooks(action, observation)
90+
return self._finish_forward(action, observation, 0.0)
10291

10392
final_result = first_result
10493
for i, rubric in enumerate(self._rubric_list[1:], start=1):
@@ -109,150 +98,68 @@ def __call__(self, action: Any, observation: Any):
10998
return self._call_async_mid(
11099
action,
111100
observation,
112-
final_result,
113101
score,
114102
self._rubric_list[i + 1 :],
115103
)
116104
if score == 0.0:
117-
# Pre-hooks
118-
for hook in self._forward_pre_hooks:
119-
hook(self, action, observation)
120-
self.last_score = 0.0
121-
for hook in self._forward_hooks:
122-
hook(self, action, observation, 0.0)
123-
return 0.0
105+
self._run_forward_pre_hooks(action, observation)
106+
return self._finish_forward(action, observation, 0.0)
124107
final_result = score
125108

126109
# All sync - check if in async context
127110
if _in_async_context():
128111
return self._wrap_sync_result(action, observation, final_result)
129112
else:
130-
# Pre-hooks
131-
for hook in self._forward_pre_hooks:
132-
hook(self, action, observation)
133-
self.last_score = final_result
134-
for hook in self._forward_hooks:
135-
hook(self, action, observation, final_result)
136-
return final_result
113+
self._run_forward_pre_hooks(action, observation)
114+
return self._finish_forward(action, observation, final_result)
137115

138116
async def _empty_async(self, action, observation):
139117
"""Async path for empty sequential."""
140-
for hook in self._forward_pre_hooks:
141-
if inspect.iscoroutinefunction(hook):
142-
await hook(self, action, observation)
143-
else:
144-
hook(self, action, observation)
145-
146-
result = 1.0
147-
self.last_score = result
148-
149-
for hook in self._forward_hooks:
150-
if inspect.iscoroutinefunction(hook):
151-
await hook(self, action, observation, result)
152-
else:
153-
hook(self, action, observation, result)
154-
return result
118+
await self._run_forward_pre_hooks_async(action, observation)
119+
return await self._finish_forward_async(action, observation, 1.0)
155120

156121
async def _wrap_sync_result(self, action, observation, result):
157122
"""Wrap sync result for async context."""
158-
for hook in self._forward_pre_hooks:
159-
if inspect.iscoroutinefunction(hook):
160-
await hook(self, action, observation)
161-
else:
162-
hook(self, action, observation)
163-
164-
self.last_score = result
165-
166-
for hook in self._forward_hooks:
167-
if inspect.iscoroutinefunction(hook):
168-
await hook(self, action, observation, result)
169-
else:
170-
hook(self, action, observation, result)
171-
return result
123+
await self._run_forward_pre_hooks_async(action, observation)
124+
return await self._finish_forward_async(action, observation, result)
172125

173126
async def _call_async_detected(self, action, observation, first_coro):
174127
"""Async path when first child is async."""
175-
for hook in self._forward_pre_hooks:
176-
if inspect.iscoroutinefunction(hook):
177-
await hook(self, action, observation)
178-
else:
179-
hook(self, action, observation)
128+
await self._run_forward_pre_hooks_async(action, observation)
180129

181130
result = await first_coro
182131
if result == 0.0:
183-
self.last_score = 0.0
184-
for hook in self._forward_hooks:
185-
if inspect.iscoroutinefunction(hook):
186-
await hook(self, action, observation, result)
187-
else:
188-
hook(self, action, observation, result)
189-
return 0.0
132+
return await self._finish_forward_async(action, observation, result)
190133

191134
for rubric in self._rubric_list[1:]:
192135
score = rubric(action, observation)
193136
if inspect.iscoroutine(score):
194137
score = await score
195138
if score == 0.0:
196-
self.last_score = 0.0
197-
for hook in self._forward_hooks:
198-
if inspect.iscoroutinefunction(hook):
199-
await hook(self, action, observation, 0.0)
200-
else:
201-
hook(self, action, observation, 0.0)
202-
return 0.0
139+
return await self._finish_forward_async(action, observation, 0.0)
203140
result = score
204141

205-
self.last_score = result
206-
for hook in self._forward_hooks:
207-
if inspect.iscoroutinefunction(hook):
208-
await hook(self, action, observation, result)
209-
else:
210-
hook(self, action, observation, result)
211-
return result
142+
return await self._finish_forward_async(action, observation, result)
212143

213-
async def _call_async_mid(
214-
self, action, observation, current_result, first_async_coro, remaining
215-
):
144+
async def _call_async_mid(self, action, observation, first_async_coro, remaining):
216145
"""Async path when async detected mid-execution."""
217-
for hook in self._forward_pre_hooks:
218-
if inspect.iscoroutinefunction(hook):
219-
await hook(self, action, observation)
220-
else:
221-
hook(self, action, observation)
146+
await self._run_forward_pre_hooks_async(action, observation)
222147

223148
# Await the first async rubric (already called)
224149
result = await first_async_coro
225150
if result == 0.0:
226-
self.last_score = 0.0
227-
for hook in self._forward_hooks:
228-
if inspect.iscoroutinefunction(hook):
229-
await hook(self, action, observation, 0.0)
230-
else:
231-
hook(self, action, observation, 0.0)
232-
return 0.0
151+
return await self._finish_forward_async(action, observation, 0.0)
233152

234153
# Continue with remaining rubrics
235154
for rubric in remaining:
236155
score = rubric(action, observation)
237156
if inspect.iscoroutine(score):
238157
score = await score
239158
if score == 0.0:
240-
self.last_score = 0.0
241-
for hook in self._forward_hooks:
242-
if inspect.iscoroutinefunction(hook):
243-
await hook(self, action, observation, 0.0)
244-
else:
245-
hook(self, action, observation, 0.0)
246-
return 0.0
159+
return await self._finish_forward_async(action, observation, 0.0)
247160
result = score
248161

249-
self.last_score = result
250-
for hook in self._forward_hooks:
251-
if inspect.iscoroutinefunction(hook):
252-
await hook(self, action, observation, result)
253-
else:
254-
hook(self, action, observation, result)
255-
return result
162+
return await self._finish_forward_async(action, observation, result)
256163

257164
def __len__(self) -> int:
258165
return len(self._rubric_list)
@@ -304,33 +211,17 @@ def __call__(self, action: Any, observation: Any):
304211
return self._call_async(action, observation, score)
305212
else:
306213
# Child is sync
307-
# Pre-hooks
308-
for hook in self._forward_pre_hooks:
309-
hook(self, action, observation)
214+
self._run_forward_pre_hooks(action, observation)
310215
result = 0.0 if score < self.threshold else score
311-
self.last_score = result
312-
for hook in self._forward_hooks:
313-
hook(self, action, observation, result)
314-
return result
216+
return self._finish_forward(action, observation, result)
315217

316218
async def _call_async(self, action, observation, score_coro):
317219
"""Async path."""
318-
for hook in self._forward_pre_hooks:
319-
if inspect.iscoroutinefunction(hook):
320-
await hook(self, action, observation)
321-
else:
322-
hook(self, action, observation)
220+
await self._run_forward_pre_hooks_async(action, observation)
323221

324222
score = await score_coro
325223
result = 0.0 if score < self.threshold else score
326-
self.last_score = result
327-
328-
for hook in self._forward_hooks:
329-
if inspect.iscoroutinefunction(hook):
330-
await hook(self, action, observation, result)
331-
else:
332-
hook(self, action, observation, result)
333-
return result
224+
return await self._finish_forward_async(action, observation, result)
334225

335226

336227
class WeightedSum(Rubric):
@@ -395,24 +286,15 @@ def __call__(self, action: Any, observation: Any):
395286
return self._call_async(action, observation, results)
396287
else:
397288
# Sync path
398-
# Pre-hooks
399-
for hook in self._forward_pre_hooks:
400-
hook(self, action, observation)
289+
self._run_forward_pre_hooks(action, observation)
401290
total = 0.0
402291
for score, weight in zip(results, self._weights):
403292
total += score * weight
404-
self.last_score = total
405-
for hook in self._forward_hooks:
406-
hook(self, action, observation, total)
407-
return total
293+
return self._finish_forward(action, observation, total)
408294

409295
async def _call_async(self, action, observation, results):
410296
"""Async path with parallel execution."""
411-
for hook in self._forward_pre_hooks:
412-
if inspect.iscoroutinefunction(hook):
413-
await hook(self, action, observation)
414-
else:
415-
hook(self, action, observation)
297+
await self._run_forward_pre_hooks_async(action, observation)
416298

417299
# Separate sync and async results
418300
async_tasks = []
@@ -437,14 +319,7 @@ async def _call_async(self, action, observation, results):
437319
for score, weight in zip(scores, self._weights):
438320
total += score * weight
439321

440-
self.last_score = total
441-
442-
for hook in self._forward_hooks:
443-
if inspect.iscoroutinefunction(hook):
444-
await hook(self, action, observation, total)
445-
else:
446-
hook(self, action, observation, total)
447-
return total
322+
return await self._finish_forward_async(action, observation, total)
448323

449324
@property
450325
def weights(self) -> List[float]:

0 commit comments

Comments
 (0)