fix: Allow string values for ToolTrajectoryCriterion.match_type

Adds a Pydantic field validator to ToolTrajectoryCriterion to automatically convert string inputs for the match_type field into the corresponding MatchType enum member

Close #3711

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 852415560
This commit is contained in:
George Weale
2026-01-05 12:43:53 -08:00
committed by Copybara-Service
parent e850e9c9ba
commit 93d6e4c888
2 changed files with 78 additions and 0 deletions
+12
View File
@@ -24,6 +24,7 @@ from pydantic import alias_generators
from pydantic import BaseModel
from pydantic import ConfigDict
from pydantic import Field
from pydantic import field_validator
from pydantic.json_schema import SkipJsonSchema
from typing_extensions import TypeAlias
@@ -225,6 +226,17 @@ class ToolTrajectoryCriterion(BaseCriterion):
),
)
@field_validator("match_type", mode="before")
@classmethod
def _coerce_match_type(cls, value: object) -> object:
if isinstance(value, cls.MatchType):
return value
if isinstance(value, str):
normalized = value.strip().upper().replace("-", "_").replace(" ", "_")
if normalized in cls.MatchType.__members__:
return cls.MatchType[normalized]
return value
class LlmBackedUserSimulatorCriterion(LlmAsAJudgeCriterion):
"""Criterion for LLM-backed User Simulator Evaluators."""
@@ -23,6 +23,7 @@ from google.adk.evaluation.eval_metrics import ToolTrajectoryCriterion
from google.adk.evaluation.evaluator import EvalStatus
from google.adk.evaluation.trajectory_evaluator import TrajectoryEvaluator
from google.genai import types as genai_types
from pydantic import ValidationError
import pytest
_USER_CONTENT = genai_types.Content(
@@ -30,6 +31,71 @@ _USER_CONTENT = genai_types.Content(
)
def test_tool_trajectory_criterion_accepts_string_match_type():
criterion = ToolTrajectoryCriterion(threshold=0.5, match_type="in_order")
assert criterion.match_type == ToolTrajectoryCriterion.MatchType.IN_ORDER
@pytest.mark.parametrize(
("match_type", "expected"),
[
("exact", ToolTrajectoryCriterion.MatchType.EXACT),
("EXACT", ToolTrajectoryCriterion.MatchType.EXACT),
(" exact ", ToolTrajectoryCriterion.MatchType.EXACT),
("in order", ToolTrajectoryCriterion.MatchType.IN_ORDER),
("IN ORDER", ToolTrajectoryCriterion.MatchType.IN_ORDER),
("In OrDeR", ToolTrajectoryCriterion.MatchType.IN_ORDER),
("in-order", ToolTrajectoryCriterion.MatchType.IN_ORDER),
("IN-ORDER", ToolTrajectoryCriterion.MatchType.IN_ORDER),
("in_order", ToolTrajectoryCriterion.MatchType.IN_ORDER),
("any order", ToolTrajectoryCriterion.MatchType.ANY_ORDER),
("ANY ORDER", ToolTrajectoryCriterion.MatchType.ANY_ORDER),
("any-order", ToolTrajectoryCriterion.MatchType.ANY_ORDER),
("ANY-ORDER", ToolTrajectoryCriterion.MatchType.ANY_ORDER),
("any_order", ToolTrajectoryCriterion.MatchType.ANY_ORDER),
],
)
def test_tool_trajectory_criterion_normalizes_string_match_type(
match_type: str, expected: ToolTrajectoryCriterion.MatchType
):
criterion = ToolTrajectoryCriterion(threshold=0.5, match_type=match_type)
assert criterion.match_type == expected
def test_tool_trajectory_criterion_rejects_unknown_string_match_type():
with pytest.raises(ValidationError):
ToolTrajectoryCriterion(threshold=0.5, match_type="random string")
def test_trajectory_evaluator_accepts_string_match_type_from_eval_metric_dict():
eval_metric = EvalMetric(
threshold=0.5,
metric_name=PrebuiltMetrics.TOOL_TRAJECTORY_AVG_SCORE.value,
criterion={
"threshold": 0.5,
"match_type": "ANY_ORDER",
},
)
evaluator = TrajectoryEvaluator(eval_metric=eval_metric)
tool_call1 = genai_types.FunctionCall(name="test_func1", args={})
tool_call2 = genai_types.FunctionCall(name="test_func2", args={})
actual_invocation = Invocation(
user_content=_USER_CONTENT,
intermediate_data=IntermediateData(tool_uses=[tool_call1, tool_call2]),
)
expected_invocation = Invocation(
user_content=_USER_CONTENT,
intermediate_data=IntermediateData(tool_uses=[tool_call2, tool_call1]),
)
result = evaluator.evaluate_invocations(
[actual_invocation], [expected_invocation]
)
assert result.overall_score == 1.0
@pytest.fixture
def evaluator() -> TrajectoryEvaluator:
"""Returns a TrajectoryEvaluator."""