Skip to content

Commit 3c54cc7

Browse files
committed
Changing the rollout processors
1 parent 062e448 commit 3c54cc7

36 files changed

Lines changed: 615 additions & 582 deletions

eval_protocol/benchmarks/suites/aime25.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from eval_protocol.benchmarks.registry import export_benchmark
44
from eval_protocol.models import EvaluateResult, EvaluationRow, Message, MetricResult
55
from eval_protocol.pytest.default_single_turn_rollout_process import (
6-
default_single_turn_rollout_processor,
6+
SingleTurnRolloutProcessor,
77
)
88
from eval_protocol.pytest.evaluation_test import evaluation_test
99

@@ -72,7 +72,7 @@ def aime2025_dataset_adapter(rows: List[Dict[str, Any]]) -> List[EvaluationRow]:
7272
"model": "fireworks_ai/accounts/fireworks/models/gpt-oss-120b",
7373
}
7474
],
75-
rollout_processor=default_single_turn_rollout_processor,
75+
rollout_processor=SingleTurnRolloutProcessor(),
7676
aggregation_method="mean",
7777
passed_threshold=None,
7878
num_runs=8,

eval_protocol/benchmarks/suites/gpqa.py

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88

99
from eval_protocol.benchmarks.registry import export_benchmark
1010
from eval_protocol.models import EvaluateResult, EvaluationRow, Message, MetricResult
11+
from eval_protocol.pytest.default_base_rollout_process import BaseRolloutProcessor
1112
from eval_protocol.pytest.default_single_turn_rollout_process import (
12-
default_single_turn_rollout_processor,
13+
SingleTurnRolloutProcessor,
1314
)
1415
from eval_protocol.pytest.evaluation_test import evaluation_test
16+
from eval_protocol.pytest.types import RolloutProcessorConfig
1517

1618
SYSTEM_PROMPT = (
1719
"You are a helpful assistant. Read the question and options carefully. "
@@ -61,19 +63,31 @@ def _strip_gt_messages(msgs: List[Message]) -> List[Message]:
6163
return [m for m in msgs if not (m.role == "system" and (m.content or "").startswith("__GT__:"))]
6264

6365

64-
def gpqa_strip_gt_rollout_processor(rows: List[EvaluationRow], config) -> List[asyncio.Task[EvaluationRow]]:
65-
"""Preprocess rows to set ground_truth and remove __GT__ messages, then delegate to default processor."""
66-
processed: List[EvaluationRow] = []
67-
for r in rows:
68-
gt_tokens = [m.content for m in r.messages if m.role == "system" and (m.content or "").startswith("__GT__:")]
69-
if gt_tokens:
70-
gt_val = gt_tokens[-1].split(":", 1)[1].strip()
71-
r.ground_truth = gt_val
72-
r.messages = [
73-
m for m in r.messages if not (m.role == "system" and (m.content or "").startswith("__GT__:"))
66+
class GPQAStripGTRolloutProcessor(BaseRolloutProcessor):
67+
"""Preprocess rows to set ground_truth and remove __GT__ messages, then delegate to SingleTurnRolloutProcessor."""
68+
69+
def __init__(self):
70+
super().__init__()
71+
self.single_turn_processor = SingleTurnRolloutProcessor()
72+
73+
def __call__(self, rows: List[EvaluationRow], config: RolloutProcessorConfig) -> List[asyncio.Task[EvaluationRow]]:
74+
"""Preprocess rows and delegate to SingleTurnRolloutProcessor."""
75+
processed: List[EvaluationRow] = []
76+
77+
for r in rows:
78+
gt_tokens = [
79+
m.content for m in r.messages if m.role == "system" and (m.content or "").startswith("__GT__:")
7480
]
75-
processed.append(r)
76-
return default_single_turn_rollout_processor(processed, config)
81+
if gt_tokens:
82+
gt_val = gt_tokens[-1].split(":", 1)[1].strip()
83+
r.ground_truth = gt_val
84+
r.messages = [
85+
m for m in r.messages if not (m.role == "system" and (m.content or "").startswith("__GT__:"))
86+
]
87+
processed.append(r)
88+
89+
# Delegate to SingleTurnRolloutProcessor
90+
return self.single_turn_processor(processed, config)
7791

7892

7993
@export_benchmark("gpqa")
@@ -82,7 +96,7 @@ def gpqa_strip_gt_rollout_processor(rows: List[EvaluationRow], config) -> List[a
8296
completion_params=[
8397
{"extra_body": {"reasoning_effort": "low"}, "model": "fireworks_ai/accounts/fireworks/models/gpt-oss-120b"}
8498
],
85-
rollout_processor=gpqa_strip_gt_rollout_processor,
99+
rollout_processor=GPQAStripGTRolloutProcessor(),
86100
aggregation_method="mean",
87101
passed_threshold=None,
88102
num_runs=8,

eval_protocol/benchmarks/suites/livebench_data_analysis.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from eval_protocol.benchmarks.registry import export_benchmark, register_composite_benchmark
66
from eval_protocol.models import EvaluateResult, EvaluationRow, Message, MetricResult
77
from eval_protocol.pytest.default_single_turn_rollout_process import (
8-
default_single_turn_rollout_processor,
8+
SingleTurnRolloutProcessor,
99
)
1010
from eval_protocol.pytest.evaluation_test import evaluation_test
1111

@@ -375,7 +375,7 @@ def _extract_gt(row: EvaluationRow) -> Dict[str, Any]:
375375
completion_params=[{"model": "fireworks_ai/accounts/fireworks/models/gpt-oss-120b"}],
376376
input_messages=[[m for m in r.messages] for r in _CTA_ROWS],
377377
rollout_processor_kwargs=[{"extra_body": {"reasoning_effort": "low"}}],
378-
rollout_processor=default_single_turn_rollout_processor,
378+
rollout_processor=SingleTurnRolloutProcessor(),
379379
aggregation_method="mean",
380380
passed_threshold=None,
381381
num_runs=4,
@@ -418,7 +418,7 @@ def livebench_cta_pointwise(row: EvaluationRow) -> EvaluationRow:
418418
completion_params=[{"model": "fireworks_ai/accounts/fireworks/models/gpt-oss-120b"}],
419419
input_messages=[[m for m in r.messages] for r in _TABLEJOIN_ROWS],
420420
rollout_processor_kwargs=[{"extra_body": {"reasoning_effort": "low"}}],
421-
rollout_processor=default_single_turn_rollout_processor,
421+
rollout_processor=SingleTurnRolloutProcessor(),
422422
aggregation_method="mean",
423423
passed_threshold=None,
424424
num_runs=4,
@@ -462,7 +462,7 @@ def livebench_tablejoin_pointwise(row: EvaluationRow) -> EvaluationRow:
462462
completion_params=[{"model": "fireworks_ai/accounts/fireworks/models/gpt-oss-120b"}],
463463
input_messages=[[m for m in r.messages] for r in _TABLEREFORMAT_ROWS],
464464
rollout_processor_kwargs=[{"extra_body": {"reasoning_effort": "low"}}],
465-
rollout_processor=default_single_turn_rollout_processor,
465+
rollout_processor=SingleTurnRolloutProcessor(),
466466
aggregation_method="mean",
467467
passed_threshold=None,
468468
num_runs=4,

eval_protocol/benchmarks/suites/tau_bench_retail.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from eval_protocol.benchmarks.registry import export_benchmark
1414
from eval_protocol.models import EvaluateResult, EvaluationRow, InputMetadata, Message
1515
from eval_protocol.pytest import evaluation_test
16-
from eval_protocol.pytest.default_mcp_gym_rollout_processor import default_mcp_gym_rollout_processor
16+
from eval_protocol.pytest.default_mcp_gym_rollout_processor import MCPGymRolloutProcessor
1717
from vendor.tau2.data_model.message import (
1818
AssistantMessage,
1919
SystemMessage,
@@ -73,7 +73,7 @@ def tau_bench_retail_to_evaluation_row(data: List[Dict[str, Any]]) -> List[Evalu
7373
"model": "fireworks_ai/accounts/fireworks/models/gpt-oss-120b",
7474
}
7575
],
76-
rollout_processor=default_mcp_gym_rollout_processor,
76+
rollout_processor=MCPGymRolloutProcessor(),
7777
rollout_processor_kwargs={"domain": "retail"},
7878
num_runs=8,
7979
mode="pointwise",

eval_protocol/pytest/__init__.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
from .default_agent_rollout_processor import default_agent_rollout_processor
1+
from .default_agent_rollout_processor import AgentRolloutProcessor
2+
from .default_base_rollout_process import BaseRolloutProcessor
23
from .default_dataset_adapter import default_dataset_adapter
3-
from .default_mcp_gym_rollout_processor import default_mcp_gym_rollout_processor
4-
from .default_no_op_rollout_process import default_no_op_rollout_processor
5-
from .default_single_turn_rollout_process import default_single_turn_rollout_processor
4+
from .default_mcp_gym_rollout_processor import MCPGymRolloutProcessor
5+
from .default_single_turn_rollout_process import SingleTurnRolloutProcessor
66
from .evaluation_test import evaluation_test
7-
from .types import RolloutProcessor, RolloutProcessorConfig
7+
from .types import RolloutProcessorConfig
88

99
__all__ = [
10-
"default_agent_rollout_processor",
11-
"default_mcp_gym_rollout_processor",
12-
"default_no_op_rollout_processor",
13-
"default_single_turn_rollout_processor",
10+
"AgentRolloutProcessor",
11+
"MCPGymRolloutProcessor",
12+
"BaseRolloutProcessor",
13+
"SingleTurnRolloutProcessor",
1414
"default_dataset_adapter",
15-
"RolloutProcessor",
1615
"RolloutProcessorConfig",
1716
"evaluation_test",
1817
]

eval_protocol/pytest/default_agent_rollout_processor.py

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from eval_protocol.mcp.execution.policy import LiteLLMPolicy
1414
from eval_protocol.mcp.mcp_multi_client import MCPMultiClient
1515
from eval_protocol.models import EvaluationRow, Message
16+
from eval_protocol.pytest.default_base_rollout_process import BaseRolloutProcessor
1617
from eval_protocol.pytest.types import Dataset, RolloutProcessorConfig
1718

1819
logger = logging.getLogger(__name__)
@@ -115,32 +116,36 @@ def _get_content_from_tool_result(self, tool_result: CallToolResult) -> List[Tex
115116
return tool_result.content
116117

117118

118-
def default_agent_rollout_processor(
119-
rows: List[EvaluationRow], config: RolloutProcessorConfig
120-
) -> List[asyncio.Task[EvaluationRow]]:
121-
"""Create agent rollout tasks and return them for external handling."""
122-
123-
max_concurrent = getattr(config, "max_concurrent_rollouts", 8) or 8
124-
semaphore = asyncio.Semaphore(max_concurrent)
125-
126-
async def process_row(row: EvaluationRow) -> EvaluationRow:
127-
"""Process a single row with agent rollout."""
128-
agent = Agent(
129-
model=config.completion_params["model"], row=row, config_path=config.mcp_config_path, logger=config.logger
130-
)
131-
try:
132-
await agent.setup()
133-
await agent.call_agent()
134-
return agent.evaluation_row
135-
finally:
136-
if agent.mcp_client:
137-
await agent.mcp_client.cleanup()
138-
139-
async def _sem_wrapper(r: EvaluationRow) -> EvaluationRow:
140-
async with semaphore:
141-
result = await process_row(r)
142-
return result
143-
144-
# Create and return tasks for external handling
145-
tasks = [asyncio.create_task(_sem_wrapper(row)) for row in rows]
146-
return tasks
119+
class AgentRolloutProcessor(BaseRolloutProcessor):
120+
"""Agent rollout processor for tool-calling agents."""
121+
122+
def __call__(self, rows: List[EvaluationRow], config: RolloutProcessorConfig) -> List[asyncio.Task[EvaluationRow]]:
123+
"""Create agent rollout tasks and return them for external handling."""
124+
125+
max_concurrent = getattr(config, "max_concurrent_rollouts", 8) or 8
126+
semaphore = asyncio.Semaphore(max_concurrent)
127+
128+
async def process_row(row: EvaluationRow) -> EvaluationRow:
129+
"""Process a single row with agent rollout."""
130+
agent = Agent(
131+
model=config.completion_params["model"],
132+
row=row,
133+
config_path=config.mcp_config_path,
134+
logger=config.logger,
135+
)
136+
try:
137+
await agent.setup()
138+
await agent.call_agent()
139+
return agent.evaluation_row
140+
finally:
141+
if agent.mcp_client:
142+
await agent.mcp_client.cleanup()
143+
144+
async def _sem_wrapper(r: EvaluationRow) -> EvaluationRow:
145+
async with semaphore:
146+
result = await process_row(r)
147+
return result
148+
149+
# Create and return tasks for external handling
150+
tasks = [asyncio.create_task(_sem_wrapper(row)) for row in rows]
151+
return tasks
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import asyncio
2+
from typing import List
3+
4+
from eval_protocol.models import EvaluationRow
5+
from eval_protocol.pytest.types import RolloutProcessorConfig
6+
7+
8+
class BaseRolloutProcessor:
9+
"""
10+
Base rollout processor - minimal implementation that all others inherit from.
11+
12+
This is the Strategy pattern base class. It provides:
13+
1. __call__(rows, config) -> tasks (the main interface)
14+
2. cleanup() -> None (resource cleanup)
15+
16+
All other processors inherit from this and override as needed.
17+
"""
18+
19+
def __call__(self, rows: List[EvaluationRow], config: RolloutProcessorConfig) -> List[asyncio.Task[EvaluationRow]]:
20+
"""Process rows by returning them unchanged (no-op implementation)."""
21+
22+
async def return_row(row: EvaluationRow) -> EvaluationRow:
23+
return row
24+
25+
# Create tasks that immediately return the rows (no-op)
26+
tasks = [asyncio.create_task(return_row(row)) for row in rows]
27+
return tasks
28+
29+
def cleanup(self) -> None:
30+
"""No-op cleanup - override in subclasses if needed."""
31+
pass

0 commit comments

Comments
 (0)