ec2b666284
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
459 lines
14 KiB
Python
459 lines
14 KiB
Python
# Copyright 2026 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Tests for example_util."""
|
|
|
|
from google.adk.examples import base_example_provider
|
|
from google.adk.examples import example
|
|
from google.adk.examples import example_util
|
|
from google.genai import types
|
|
import pytest
|
|
|
|
BASIC_INPUT = types.Content(role="user", parts=[types.Part(text="test_input")])
|
|
|
|
BASIC_OUTPUT = [
|
|
types.Content(role="model", parts=[types.Part(text="test_output")])
|
|
]
|
|
|
|
BASIC_EXAMPLE = example.Example(input=BASIC_INPUT, output=BASIC_OUTPUT)
|
|
|
|
|
|
class MockExampleProvider(base_example_provider.BaseExampleProvider):
|
|
"""Mocks an ExampleProvider object.
|
|
|
|
This class provides mock implementation of the get_examples() function,
|
|
allowing the user to test functions that rely on an ExampleProvider
|
|
without creating a real ExampleProvider class and check that the correct
|
|
inputs are being passed to it.
|
|
"""
|
|
|
|
def __init__(
|
|
self, test_examples: list[example.Example], test_query: str
|
|
) -> None:
|
|
"""Initializes a MockExampleProvider.
|
|
|
|
Args:
|
|
test_examples: The list of examples to be returned on a successful query.
|
|
test_query: The query necessary to return a correct output.
|
|
"""
|
|
self.test_examples = test_examples
|
|
self.test_query = test_query
|
|
|
|
def get_examples(self, query: str) -> list[example.Example]:
|
|
"""Mocks querying the ExampleProvider for examples.
|
|
Verifies the query is correct, and returns an empty list if not.
|
|
|
|
Args:
|
|
query: The query to check examples for.
|
|
"""
|
|
if query == self.test_query:
|
|
return self.test_examples
|
|
else:
|
|
return []
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_text_only_example_conversion(model):
|
|
"""Tests converting a text-only Example object to a string for use in a system instruction."""
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}test_output\n"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.convert_examples_to_text(
|
|
examples=[BASIC_EXAMPLE], model=model
|
|
)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_multi_part_text_example_conversion(model):
|
|
"""Tests converting an Example object with multiple text Parts to a string for use in a system instruction."""
|
|
output_content = [
|
|
types.Content(
|
|
role="model",
|
|
parts=[
|
|
types.Part(text="test_output_1"),
|
|
types.Part(text="test_output_2"),
|
|
types.Part(text="test_output_3"),
|
|
],
|
|
)
|
|
]
|
|
test_example = example.Example(input=BASIC_INPUT, output=output_content)
|
|
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}test_output_1\ntest_output_2\ntest_output_3\n"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.convert_examples_to_text(
|
|
examples=[test_example], model=model
|
|
)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_example_conversion_prefix_insertion(model):
|
|
"""Tests if user and model prefixes are properly alternated when converting an Example object to text for use in a system instruction."""
|
|
output_content = [
|
|
types.Content(role="model", parts=[types.Part(text="test_output_1")]),
|
|
types.Content(role="user", parts=[types.Part(text="test_output_2")]),
|
|
types.Content(role="model", parts=[types.Part(text="test_output_3")]),
|
|
]
|
|
test_example = example.Example(input=BASIC_INPUT, output=output_content)
|
|
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}test_output_1\n"
|
|
f"{example_util._USER_PREFIX}test_output_2\n"
|
|
f"{example_util._MODEL_PREFIX}test_output_3\n"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.convert_examples_to_text(
|
|
examples=[test_example], model=model
|
|
)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_example_conversion_output_clumping(model):
|
|
"""Tests whether user and model inputs are properly clumped when converting an Example object to text for use in a system instruction."""
|
|
output_content = [
|
|
types.Content(role="model", parts=[types.Part(text="test_output_1")]),
|
|
types.Content(role="model", parts=[types.Part(text="test_output_2")]),
|
|
types.Content(role="user", parts=[types.Part(text="test_output_3")]),
|
|
types.Content(role="user", parts=[types.Part(text="test_output_4")]),
|
|
]
|
|
test_example = example.Example(input=BASIC_INPUT, output=output_content)
|
|
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}test_output_1\ntest_output_2\n"
|
|
f"{example_util._USER_PREFIX}test_output_3\ntest_output_4\n"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.convert_examples_to_text(
|
|
examples=[test_example], model=model
|
|
)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_empty_examples_list_conversion(model):
|
|
"""Tests Example conversion to text if the examples list is empty."""
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.convert_examples_to_text(examples=[], model=model)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_example_conversion_with_function_call(model):
|
|
"""Tests converting an Example object containing a function call to a string for use in a system instruction."""
|
|
test_function_call = types.FunctionCall(
|
|
name="test_function",
|
|
args={"test_string_argument": "test_value", "test_int_argument": 1},
|
|
)
|
|
output_content = [
|
|
types.Content(
|
|
role="model", parts=[types.Part(function_call=test_function_call)]
|
|
)
|
|
]
|
|
test_example = example.Example(input=BASIC_INPUT, output=output_content)
|
|
|
|
gemini2 = model is None or "gemini-2" in model
|
|
prefix = (
|
|
example_util._FUNCTION_PREFIX
|
|
if gemini2
|
|
else example_util._FUNCTION_CALL_PREFIX
|
|
)
|
|
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}{prefix}"
|
|
"test_function(test_string_argument='test_value', test_int_argument=1)"
|
|
f"{example_util._FUNCTION_CALL_SUFFIX}"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.convert_examples_to_text(
|
|
examples=[test_example], model=model
|
|
)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_example_conversion_with_function_response(model):
|
|
"""Tests converting an Example object containing a function response to a string for use in a system instruction."""
|
|
test_function_response = types.FunctionResponse(
|
|
name="test_function",
|
|
response={"test_string_argument": "test_value", "test_int_argument": 1},
|
|
)
|
|
output_content = [
|
|
types.Content(
|
|
role="model",
|
|
parts=[types.Part(function_response=test_function_response)],
|
|
)
|
|
]
|
|
test_example = example.Example(input=BASIC_INPUT, output=output_content)
|
|
|
|
gemini2 = model is None or "gemini-2" in model
|
|
prefix = (
|
|
example_util._FUNCTION_PREFIX
|
|
if gemini2
|
|
else example_util._FUNCTION_RESPONSE_PREFIX
|
|
)
|
|
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}{prefix}"
|
|
f"{test_function_response.__dict__}"
|
|
f"{example_util._FUNCTION_RESPONSE_SUFFIX}"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.convert_examples_to_text(
|
|
examples=[test_example], model=model
|
|
)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_example_conversion_with_function_call_response(model):
|
|
"""Tests converting an Example object containing a function call and response to a string for use in a system instruction."""
|
|
test_function_call = types.FunctionCall(
|
|
name="test_function",
|
|
args={"test_string_argument": "test_value", "test_int_argument": 1},
|
|
)
|
|
test_function_response = types.FunctionResponse(
|
|
name="test_function",
|
|
response={"test_string_argument": "test_value", "test_int_argument": 1},
|
|
)
|
|
output_content = [
|
|
types.Content(
|
|
role="model",
|
|
parts=[
|
|
types.Part(function_call=test_function_call),
|
|
types.Part(function_response=test_function_response),
|
|
],
|
|
)
|
|
]
|
|
test_example = example.Example(input=BASIC_INPUT, output=output_content)
|
|
|
|
gemini2 = model is None or "gemini-2" in model
|
|
response_prefix = (
|
|
example_util._FUNCTION_PREFIX
|
|
if gemini2
|
|
else example_util._FUNCTION_RESPONSE_PREFIX
|
|
)
|
|
call_prefix = (
|
|
example_util._FUNCTION_PREFIX
|
|
if gemini2
|
|
else example_util._FUNCTION_CALL_PREFIX
|
|
)
|
|
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}{call_prefix}"
|
|
"test_function(test_string_argument='test_value', test_int_argument=1)"
|
|
f"{example_util._FUNCTION_CALL_SUFFIX}"
|
|
f"{response_prefix}"
|
|
f"{test_function_response.__dict__}"
|
|
f"{example_util._FUNCTION_RESPONSE_SUFFIX}"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.convert_examples_to_text(
|
|
examples=[test_example], model=model
|
|
)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_example_conversion_with_text_and_function_call_response(model):
|
|
"""Tests converting an Example object containing text, a function call, and a function response to a string for use in a system instruction."""
|
|
test_function_call = types.FunctionCall(
|
|
name="test_function",
|
|
args={"test_string_argument": "test_value", "test_int_argument": 1},
|
|
)
|
|
test_function_response = types.FunctionResponse(
|
|
name="test_function",
|
|
response={"test_string_argument": "test_value", "test_int_argument": 1},
|
|
)
|
|
output_content = [
|
|
types.Content(
|
|
role="model",
|
|
parts=[
|
|
types.Part(text="test_output"),
|
|
types.Part(function_call=test_function_call),
|
|
types.Part(function_response=test_function_response),
|
|
],
|
|
)
|
|
]
|
|
test_example = example.Example(input=BASIC_INPUT, output=output_content)
|
|
|
|
gemini2 = model is None or "gemini-2" in model
|
|
response_prefix = (
|
|
example_util._FUNCTION_PREFIX
|
|
if gemini2
|
|
else example_util._FUNCTION_RESPONSE_PREFIX
|
|
)
|
|
call_prefix = (
|
|
example_util._FUNCTION_PREFIX
|
|
if gemini2
|
|
else example_util._FUNCTION_CALL_PREFIX
|
|
)
|
|
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}test_output\n"
|
|
f"{call_prefix}"
|
|
"test_function(test_string_argument='test_value', test_int_argument=1)"
|
|
f"{example_util._FUNCTION_CALL_SUFFIX}"
|
|
f"{response_prefix}"
|
|
f"{test_function_response.__dict__}"
|
|
f"{example_util._FUNCTION_RESPONSE_SUFFIX}"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.convert_examples_to_text(
|
|
examples=[test_example], model=model
|
|
)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_building_si_from_list(model):
|
|
"""Tests building System Information from a list of examples."""
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}test_output\n"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
assert (
|
|
example_util.build_example_si(
|
|
examples=[BASIC_EXAMPLE], query="", model=model
|
|
)
|
|
== expected_output
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"model",
|
|
["gemini-2.5-flash", "llama3_vertex_agent", None],
|
|
)
|
|
def test_building_si_from_base_example_provider(model):
|
|
"""Tests building System Information from an example provider."""
|
|
expected_output = (
|
|
f"{example_util._EXAMPLES_INTRO}"
|
|
f"{example_util._EXAMPLE_START.format(1)}"
|
|
f"{example_util._USER_PREFIX}test_input\n"
|
|
f"{example_util._MODEL_PREFIX}test_output\n"
|
|
f"{example_util._EXAMPLE_END}"
|
|
f"{example_util._EXAMPLES_END}"
|
|
)
|
|
|
|
example_provider = MockExampleProvider(
|
|
test_examples=[BASIC_EXAMPLE], test_query="test_query"
|
|
)
|
|
|
|
assert (
|
|
example_util.build_example_si(
|
|
examples=example_provider, query="test_query", model=model
|
|
)
|
|
== expected_output
|
|
)
|