@@ -923,6 +923,90 @@ def _fetch_agent_config_dict(
923923 )
924924
925925
926+ def _get_resolved_location (api_client : Any ) -> Optional [str ]:
927+ """Returns the location configured on the API client."""
928+ return getattr (api_client , "location" , None )
929+
930+
931+ def _normalize_interaction_resource (
932+ interaction : str , agent : str , location : Optional [str ]
933+ ) -> str :
934+ """Normalizes an interaction id into a full resource name.
935+
936+ A bare interaction id is expanded to
937+ `projects/{project}/locations/{location}/interactions/{id}` using the
938+ project and location parsed from the agent resource name. Fully-qualified
939+ interaction resource names are returned unchanged.
940+ """
941+ if interaction .startswith ("projects/" ):
942+ return interaction
943+ parts = agent .split ("/" )
944+ project = parts [1 ]
945+ agent_location = parts [3 ] if len (parts ) > 3 else (location or "global" )
946+ return f"projects/{ project } /locations/{ agent_location } /interactions/{ interaction } "
947+
948+
949+ def _build_interaction_id_dataset (
950+ loaded_data : list [dict [str , Any ]],
951+ agent : Optional [str ],
952+ location : Optional [str ],
953+ ) -> Optional [types .EvaluationDataset ]:
954+ """Builds an EvaluationDataset from rows that carry an `interaction_id`.
955+
956+ When the dataset contains an `interaction_id` column, each row is turned
957+ into an EvalCase whose `interactions_data_source` references the interaction
958+ and the Gemini agent. The backend resolves the interaction trace and agent
959+ config; no client-side prompt/response is required. Returns None if the
960+ data does not contain interaction ids.
961+ """
962+ has_interaction_id = bool (loaded_data ) and any (
963+ _evals_constant .INTERACTION_ID in row for row in loaded_data
964+ )
965+ if not has_interaction_id :
966+ if agent :
967+ raise ValueError (
968+ "An `agent` was provided but the dataset does not contain an"
969+ " `interaction_id` column. The `agent` argument is only used to"
970+ " resolve an `interaction_id` dataset column (so the backend can"
971+ " fetch the interaction trace and Agent config). To evaluate"
972+ " with an agent, provide a dataset with an `interaction_id`"
973+ " column; otherwise omit `agent`."
974+ )
975+ return None
976+
977+ if not agent :
978+ raise ValueError (
979+ "An `agent` resource name is required when the dataset contains an"
980+ " `interaction_id` column, so the backend can resolve the Agent"
981+ " config for each interaction."
982+ )
983+ if not _is_gemini_agent_resource (agent ):
984+ raise ValueError (
985+ "`agent` must be a Gemini Agents API resource name of the form"
986+ " projects/{project}/locations/{location}/agents/{agent} when"
987+ f" evaluating interaction ids. Got: { agent } "
988+ )
989+
990+ gemini_agent_config = types .GeminiAgentConfig (gemini_agent = agent )
991+ eval_cases = []
992+ for i , row in enumerate (loaded_data ):
993+ interaction = row .get (_evals_constant .INTERACTION_ID )
994+ if not interaction :
995+ raise ValueError (f"Missing `interaction_id` value for row { i } ." )
996+ eval_cases .append (
997+ types .EvalCase (
998+ eval_case_id = f"eval_case_{ i } " ,
999+ interactions_data_source = types .InteractionsDataSource (
1000+ interaction = _normalize_interaction_resource (
1001+ str (interaction ), agent , location
1002+ ),
1003+ gemini_agent_config = gemini_agent_config ,
1004+ ),
1005+ )
1006+ )
1007+ return types .EvaluationDataset (eval_cases = eval_cases )
1008+
1009+
9261010def _add_evaluation_run_labels (
9271011 labels : Optional [dict [str , str ]] = None ,
9281012 agent : Optional [str ] = None ,
@@ -1939,6 +2023,8 @@ def _resolve_dataset_inputs(
19392023 dataset_schema : Optional [Literal ["GEMINI" , "FLATTEN" , "OPENAI" ]],
19402024 loader : "_evals_utils.EvalDatasetLoader" ,
19412025 agent_info : Optional [types .evals .AgentInfo ] = None ,
2026+ agent : Optional [str ] = None ,
2027+ api_client : Any = None ,
19422028) -> tuple [types .EvaluationDataset , int ]:
19432029 """Loads and processes single or multiple datasets for evaluation.
19442030
@@ -1988,6 +2074,21 @@ def _resolve_dataset_inputs(
19882074 ds_source_for_loader = _get_dataset_source (ds_item )
19892075 current_loaded_data = loader .load (ds_source_for_loader )
19902076
2077+ interaction_dataset = _build_interaction_id_dataset (
2078+ current_loaded_data , agent , _get_resolved_location (api_client )
2079+ )
2080+ if interaction_dataset is not None :
2081+ if dataset_schema :
2082+ raise ValueError (
2083+ "`dataset_schema` is not supported for datasets with an"
2084+ " `interaction_id` column. The interaction trace and agent"
2085+ " config are resolved by the backend, so no client-side"
2086+ " schema conversion is applied. Omit `dataset_schema` when"
2087+ " evaluating an interaction_id dataset."
2088+ )
2089+ parsed_evaluation_datasets .append (interaction_dataset )
2090+ continue
2091+
19912092 if dataset_schema :
19922093 current_schema = _evals_data_converters .EvalDatasetSchema (dataset_schema )
19932094 else :
@@ -2145,6 +2246,7 @@ def _execute_evaluation( # type: ignore[no-untyped-def]
21452246 api_client : Any ,
21462247 dataset : Union [types .EvaluationDataset , list [types .EvaluationDataset ]],
21472248 metrics : list [types .Metric ],
2249+ agent : Optional [str ] = None ,
21482250 dataset_schema : Optional [Literal ["GEMINI" , "FLATTEN" , "OPENAI" ]] = None ,
21492251 dest : Optional [str ] = None ,
21502252 location : Optional [str ] = None ,
@@ -2225,6 +2327,8 @@ def _execute_evaluation( # type: ignore[no-untyped-def]
22252327 dataset_schema = dataset_schema ,
22262328 loader = loader ,
22272329 agent_info = validated_agent_info ,
2330+ agent = agent ,
2331+ api_client = api_client ,
22282332 )
22292333
22302334 resolved_metrics = _resolve_metrics (metrics , api_client )
0 commit comments