Skip to content

Commit bf8dfa4

Browse files
committed
gpt-oss example e2e
1 parent 3415d43 commit bf8dfa4

3 files changed

Lines changed: 67 additions & 48 deletions

File tree

eval_protocol/pytest/default_mcp_gym_rollout_processor.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
import asyncio
2+
import atexit
23
import os
4+
import signal
5+
import socket
36
import subprocess
47
import time
5-
import socket
68
from pathlib import Path
79
from typing import List, Optional
810

911
import eval_protocol as ep
1012
from eval_protocol.models import EvaluationRow, Message
1113
from eval_protocol.pytest.types import RolloutProcessorConfig
1214

13-
import atexit
14-
import signal
15-
1615

1716
class MCPServerManager:
1817
"""Manages MCP server lifecycle for testing."""
@@ -182,50 +181,52 @@ def __exit__(self, exc_type, exc_val, exc_tb):
182181
return False # Don't suppress exceptions
183182

184183

185-
186-
async def default_mcp_gym_rollout_processor(rows: List[EvaluationRow], config: RolloutProcessorConfig) -> List[EvaluationRow]:
184+
async def default_mcp_gym_rollout_processor(
185+
rows: List[EvaluationRow], config: RolloutProcessorConfig
186+
) -> List[EvaluationRow]:
187187
"""
188188
Rollout processor for tau bench environments.
189-
189+
190190
This processor starts an MCP server, creates tau bench environments, and runs rollouts
191191
using the eval_protocol framework, following the pattern from test_tau2_e2e.py.
192-
192+
193193
Args:
194194
rows: List of EvaluationRow objects containing messages and dataset info in input_metadata
195195
config: RolloutProcessorConfig with model and other parameters
196-
196+
197197
Returns:
198198
List of EvaluationRow objects with completed conversations
199199
"""
200200
server = MCPServerManager(config.server_script_path, port=9700)
201-
201+
202202
try:
203203
server.start()
204-
204+
205205
policy = ep.LiteLLMPolicy(
206206
model_id=config.model,
207-
temperature=config.input_params.get('temperature', 0.0),
208-
max_tokens=config.input_params.get('max_tokens', 4096),
207+
temperature=config.input_params.get("temperature", 0.0),
208+
max_tokens=config.input_params.get("max_tokens", 4096),
209+
reasoning_effort=config.input_params.get("reasoning_effort", None),
209210
)
210-
211+
211212
# Create MCP environments directly from evaluation_rows
212213
envs = ep.make(
213-
'http://localhost:9700/mcp/',
214+
"http://localhost:9700/mcp/",
214215
evaluation_rows=rows,
215216
model_id=policy.model_id,
216217
)
217-
218+
218219
# Run rollout with environments and policy
219220
evaluation_rows = await ep.rollout(
220-
envs,
221-
policy=policy,
221+
envs,
222+
policy=policy,
222223
evaluation_rows=rows,
223-
steps=config.steps,
224-
max_concurrent_rollouts=config.max_concurrent_rollouts
224+
steps=config.steps,
225+
max_concurrent_rollouts=config.max_concurrent_rollouts,
225226
)
226-
227+
227228
return evaluation_rows
228-
229+
229230
finally:
230231
# Always clean up the server
231232
server.stop()

tests/pytest/test_tau_bench_airline.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@
1010
from pathlib import Path
1111
from typing import Any, Dict, List
1212

13-
from eval_protocol.models import EvaluateResult, EvaluationRow, Message, InputMetadata, CompletionParams
13+
from eval_protocol.models import CompletionParams, EvaluateResult, EvaluationRow, InputMetadata, Message
1414
from eval_protocol.pytest import evaluation_test
1515
from eval_protocol.pytest.default_mcp_gym_rollout_processor import default_mcp_gym_rollout_processor
16-
1716
from vendor.tau2.data_model.message import (
1817
AssistantMessage,
1918
SystemMessage,
@@ -28,20 +27,21 @@
2827
from vendor.tau2.evaluator.evaluator_nl_assertions import NLAssertionsEvaluator
2928
from vendor.tau2.registry import registry
3029

30+
3131
def tau_bench_airline_to_evaluation_row(data: List[Dict[str, Any]]) -> List[EvaluationRow]:
3232
"""
3333
Convert entries from airline dataset to EvaluationRow objects.
3434
"""
3535
rows = []
3636
test_dir = Path(__file__).parent.parent.parent / "examples" / "tau2_mcp" / "tests"
37-
37+
3838
# Load system prompt from file so we can change it in one place
3939
domain = data[0]["environment_context"]["domain"]
4040
prompt_file = test_dir / f"system_prompts/{domain}_agent_system_prompt.md"
41-
41+
4242
with open(prompt_file, "r") as f:
4343
system_prompt = f.read().strip()
44-
44+
4545
for row in data:
4646
eval_row = EvaluationRow(
4747
messages=[Message(role="system", content=system_prompt)],
@@ -52,19 +52,20 @@ def tau_bench_airline_to_evaluation_row(data: List[Dict[str, Any]]) -> List[Eval
5252
"user_simulation": row["user_simulation"],
5353
"evaluation_criteria": row["evaluation_criteria"],
5454
"user_prompt_template": row["user_prompt_template"],
55-
}
55+
},
5656
),
5757
)
58-
58+
5959
rows.append(eval_row)
60-
60+
6161
return rows
6262

63+
6364
@evaluation_test(
6465
input_dataset=["tests/pytest/data/airline_dataset.jsonl"],
6566
dataset_adapter=tau_bench_airline_to_evaluation_row,
6667
model=["fireworks_ai/accounts/fireworks/models/gpt-oss-120b"],
67-
rollout_input_params=[{"temperature": 0.8, "max_tokens": 4096}],
68+
rollout_input_params=[{"temperature": 0.8, "max_tokens": 4096, "reasoning_effort": "high"}],
6869
rollout_processor=default_mcp_gym_rollout_processor,
6970
threshold_of_success=0.4,
7071
num_runs=1,
@@ -75,22 +76,22 @@ def tau_bench_airline_to_evaluation_row(data: List[Dict[str, Any]]) -> List[Eval
7576
def test_tau_bench_airline_evaluation(row: EvaluationRow) -> EvaluationRow:
7677
"""
7778
Test tau bench airline evaluation using the pytest framework.
78-
79+
7980
This test now uses the tau_bench_airline_reward function which automatically
8081
extracts evaluation criteria from dataset entries. No wrapper needed!
81-
82+
8283
Args:
8384
row: EvaluationRow object from tau bench airline dataset after rollout
84-
85+
8586
Returns:
8687
EvaluationRow with tau2 evaluation results
8788
"""
8889
messages = row.messages
89-
90+
9091
# Get evaluation criteria and user_simulation from input_metadata.dataset_info
9192
dataset_info = row.input_metadata.dataset_info if row.input_metadata else {}
9293
evaluation_criteria = dataset_info.get("evaluation_criteria", {})
93-
94+
9495
nl_assertions = evaluation_criteria.get("nl_assertions", [])
9596
communicate_info = evaluation_criteria.get("communicate_info", [])
9697
actions = evaluation_criteria.get("actions", [])
@@ -130,7 +131,7 @@ def test_tau_bench_airline_evaluation(row: EvaluationRow) -> EvaluationRow:
130131
actions=actions,
131132
reward_basis=[
132133
RewardType.DB,
133-
RewardType.ACTION,
134+
RewardType.COMMUNICATE,
134135
],
135136
)
136137

@@ -226,4 +227,4 @@ def test_tau_bench_airline_evaluation(row: EvaluationRow) -> EvaluationRow:
226227
reason=reason,
227228
metrics={},
228229
)
229-
return row
230+
return row

vendor/tau2/evaluator/evaluator_nl_assertions.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import json
2+
from typing import List
3+
4+
from pydantic import BaseModel
25

36
from vendor.tau2.config import DEFAULT_LLM_NL_ASSERTIONS, DEFAULT_LLM_NL_ASSERTIONS_ARGS
47
from vendor.tau2.data_model.message import Message, SystemMessage, UserMessage
@@ -7,6 +10,20 @@
710
from vendor.tau2.utils.llm_utils import generate
811

912

13+
class NLAssertionResult(BaseModel):
14+
"""Individual NL assertion evaluation result."""
15+
16+
expectedOutcome: str
17+
reasoning: str
18+
metExpectation: bool
19+
20+
21+
class NLAssertionsResponse(BaseModel):
22+
"""Complete NL assertions evaluation response."""
23+
24+
results: List[NLAssertionResult]
25+
26+
1027
class NLAssertionsEvaluator:
1128
"""
1229
Judge that evaluates whether a trajectory adheres to all the natural-language assertions.
@@ -37,9 +54,7 @@ def calculate_reward(
3754
reward_breakdown={RewardType.NL_ASSERTION: 1.0},
3855
)
3956

40-
nl_assertions_checks = cls.evaluate_nl_assertions(
41-
full_trajectory, nl_assertions
42-
)
57+
nl_assertions_checks = cls.evaluate_nl_assertions(full_trajectory, nl_assertions)
4358

4459
# Calculate reward: 1 if all expectations are met, 0 otherwise
4560
all_expectations_met = all(result.met for result in nl_assertions_checks)
@@ -70,9 +85,7 @@ def evaluate_nl_assertions(
7085
- metExpectation: Boolean indicating if the assertion was met
7186
- reasoning: Explanation for the evaluation
7287
"""
73-
trajectory_str = "\n".join(
74-
[f"{message.role}: {message.content}" for message in trajectory]
75-
)
88+
trajectory_str = "\n".join([f"{message.role}: {message.content}" for message in trajectory])
7689
# System prompt similar to the TypeScript implementation
7790
system_prompt = """
7891
TASK
@@ -86,7 +99,7 @@ def evaluate_nl_assertions(
8699
- `reasoning`: a short explanation for your classification
87100
- `metExpectation`: `true` if the agent satisfies the expected outcomes, `false` otherwise
88101
- `expectedOutcome`: repeat the expectation from the input that you are grading
89-
102+
90103
Example response structure:
91104
{
92105
"results": [
@@ -102,7 +115,7 @@ def evaluate_nl_assertions(
102115
user_prompt = f"""
103116
conversation:
104117
{trajectory_str}
105-
118+
106119
expectedOutcomes:
107120
{nl_assertions}
108121
"""
@@ -115,8 +128,12 @@ def evaluate_nl_assertions(
115128
assistant_message = generate(
116129
model=DEFAULT_LLM_NL_ASSERTIONS,
117130
messages=messages,
118-
**DEFAULT_LLM_NL_ASSERTIONS_ARGS,
119-
)
131+
temperature=0.0,
132+
response_format={
133+
"type": "json_schema",
134+
"json_schema": {"name": "NLAssertionsResponse", "schema": NLAssertionsResponse.model_json_schema()},
135+
},
136+
) # Adding constrained generation to ensure the response is a valid JSON object
120137
result_data = json.loads(assistant_message.content)
121138
return [
122139
NLAssertionCheck(

0 commit comments

Comments
 (0)