Skip to content

Commit 8432bca

Browse files
vertex-sdk-botcopybara-github
authored andcommitted
feat: GenAI Client(evals): Add scenario generation function to eval components
PiperOrigin-RevId: 872110328
1 parent 7c661d7 commit 8432bca

File tree

6 files changed

+564
-0
lines changed

6 files changed

+564
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# pylint: disable=protected-access,bad-continuation,missing-function-docstring
16+
17+
from tests.unit.vertexai.genai.replays import pytest_helper
18+
from vertexai import types
19+
import pytest
20+
21+
def test_gen_user_scenarios(client):
22+
"""Tests that generate_user_scenarios() correctly calls the API and parses the response."""
23+
eval_dataset = client.evals.generate_user_scenarios(
24+
agents={
25+
"booking-agent": types.evals.AgentConfig(
26+
agent_id="booking-agent",
27+
agent_type="service_agent",
28+
description="An agent capable of booking flights and hotels.",
29+
instruction="You are a helpful travel assistant. Use tools to find flights.",
30+
tools=[
31+
{
32+
"function_declarations": [
33+
{
34+
"name": "search_flights",
35+
"description": "Search for available flights.",
36+
}
37+
]
38+
}
39+
],
40+
)
41+
},
42+
user_scenario_generation_config=types.evals.UserScenarioGenerationConfig(
43+
user_scenario_count=2,
44+
simulation_instruction=(
45+
"Generate scenarios where the user tries to book a flight but"
46+
" changes their mind about the destination."
47+
),
48+
environment_data="Today is Monday. Flights to Paris are available.",
49+
model_name="gemini-2.5-flash",
50+
),
51+
root_agent_id="booking-agent",
52+
)
53+
assert isinstance(eval_dataset, types.EvaluationDataset)
54+
assert len(eval_dataset.eval_cases) == 2
55+
assert (
56+
eval_dataset.eval_cases[0].user_scenario.starting_prompt
57+
== "I want to find a flight from New York to London."
58+
)
59+
assert (
60+
eval_dataset.eval_cases[0].user_scenario.conversation_plan
61+
== "Actually, I meant Paris, not London. Please search for flights to Paris."
62+
)
63+
64+
pytest_plugins = ("pytest_asyncio",)
65+
66+
@pytest.mark.asyncio
67+
async def test_gen_user_scenarios_async(client):
68+
"""Tests that generate_user_scenarios() async correctly calls the API and parses the response."""
69+
eval_dataset = await client.aio.evals.generate_user_scenarios(
70+
agents={
71+
"booking-agent": types.evals.AgentConfig(
72+
agent_id="booking-agent",
73+
agent_type="service_agent",
74+
description="An agent capable of booking flights and hotels.",
75+
instruction="You are a helpful travel assistant. Use tools to find flights.",
76+
tools=[
77+
{
78+
"function_declarations": [
79+
{
80+
"name": "search_flights",
81+
"description": "Search for available flights.",
82+
}
83+
]
84+
}
85+
],
86+
)
87+
},
88+
user_scenario_generation_config=types.evals.UserScenarioGenerationConfig(
89+
user_scenario_count=2,
90+
simulation_instruction=(
91+
"Generate scenarios where the user tries to book a flight but"
92+
" changes their mind about the destination."
93+
),
94+
environment_data="Today is Monday. Flights to Paris are available.",
95+
model_name="gemini-2.5-flash",
96+
),
97+
root_agent_id="booking-agent",
98+
)
99+
assert isinstance(eval_dataset, types.EvaluationDataset)
100+
assert len(eval_dataset.eval_cases) == 2
101+
assert (
102+
eval_dataset.eval_cases[1].user_scenario.starting_prompt
103+
== "Find me a flight from Boston to Rome for next month."
104+
)
105+
assert (
106+
eval_dataset.eval_cases[1].user_scenario.conversation_plan
107+
== "Wait, change of plans. I need to go to Milan instead, and it needs to be a round trip, returning two weeks after departure."
108+
)
109+
110+
pytestmark = pytest_helper.setup(
111+
file=__file__,
112+
globals_for_file=globals(),
113+
test_method="evals.generate_user_scenarios",
114+
)

tests/unit/vertexai/genai/test_evals.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import re
2121
import statistics
2222
import sys
23+
import unittest
2324
from unittest import mock
2425

2526
import google.auth.credentials
@@ -5500,3 +5501,70 @@ def read_file_contents_side_effect(src: str) -> str:
55005501
}
55015502
),
55025503
)
5504+
5505+
5506+
class TestEvalsGenerateUserScenarios(unittest.TestCase):
5507+
"""Unit tests for the Evals generate_user_scenarios method."""
5508+
5509+
def setUp(self):
5510+
self.addCleanup(mock.patch.stopall)
5511+
self.mock_client = mock.MagicMock(spec=client.Client)
5512+
self.mock_client.vertexai = True
5513+
self.mock_api_client = mock.MagicMock()
5514+
self.mock_client._api_client = self.mock_api_client
5515+
5516+
self.mock_response = mock.MagicMock()
5517+
self.mock_response.body = json.dumps(
5518+
{
5519+
"userScenarios": [
5520+
{"startingPrompt": "Prompt 1", "conversationPlan": "Plan 1"},
5521+
{"startingPrompt": "Prompt 2", "conversationPlan": "Plan 2"},
5522+
]
5523+
}
5524+
)
5525+
self.mock_api_client.request.return_value = self.mock_response
5526+
5527+
def test_generate_user_scenarios(self):
5528+
"""Tests that generate_user_scenarios correctly calls the API and parses the response."""
5529+
evals_module = evals.Evals(api_client_=self.mock_api_client)
5530+
5531+
eval_dataset = evals_module.generate_user_scenarios(
5532+
agents={"agent_1": {}},
5533+
user_scenario_generation_config={"user_scenario_count": 2},
5534+
root_agent_id="agent_1",
5535+
)
5536+
assert isinstance(eval_dataset, vertexai_genai_types.EvaluationDataset)
5537+
assert len(eval_dataset.eval_cases) == 2
5538+
assert eval_dataset.eval_cases[0].user_scenario.starting_prompt == "Prompt 1"
5539+
assert eval_dataset.eval_cases[0].user_scenario.conversation_plan == "Plan 1"
5540+
assert eval_dataset.eval_cases[1].user_scenario.starting_prompt == "Prompt 2"
5541+
assert eval_dataset.eval_cases[1].user_scenario.conversation_plan == "Plan 2"
5542+
5543+
assert eval_dataset.eval_dataset_df is not None
5544+
assert len(eval_dataset.eval_dataset_df) == 2
5545+
assert eval_dataset.eval_dataset_df.iloc[0]["starting_prompt"] == "Prompt 1"
5546+
5547+
self.mock_api_client.request.assert_called_once()
5548+
5549+
@pytest.mark.asyncio
5550+
async def test_async_generate_user_scenarios(self):
5551+
"""Tests that async generate_user_scenarios correctly calls the API and parses the response."""
5552+
5553+
self.mock_api_client.async_request = mock.AsyncMock(
5554+
return_value=self.mock_response
5555+
)
5556+
async_evals_module = evals.AsyncEvals(api_client_=self.mock_api_client)
5557+
5558+
eval_dataset = await async_evals_module.generate_user_scenarios(
5559+
agents={"agent_1": {}},
5560+
user_scenario_generation_config={"user_scenario_count": 2},
5561+
root_agent_id="agent_1",
5562+
)
5563+
assert isinstance(eval_dataset, vertexai_genai_types.EvaluationDataset)
5564+
assert len(eval_dataset.eval_cases) == 2
5565+
assert eval_dataset.eval_cases[0].user_scenario.starting_prompt == "Prompt 1"
5566+
5567+
assert eval_dataset.eval_dataset_df is not None
5568+
assert len(eval_dataset.eval_dataset_df) == 2
5569+
5570+
self.mock_api_client.async_request.assert_called_once()

0 commit comments

Comments
 (0)