@@ -1007,6 +1007,99 @@ def _build_interaction_id_dataset(
10071007 return types .EvaluationDataset (eval_cases = eval_cases )
10081008
10091009
1010+ def _resolve_interactions_for_display (
1011+ api_client : BaseApiClient ,
1012+ dataset_list : list [types .EvaluationDataset ],
1013+ ) -> list [types .EvaluationDataset ]:
1014+ """Resolves interactions_data_source on EvalCases for display.
1015+
1016+ For each EvalCase that has ``interactions_data_source`` set but no
1017+ ``agent_data``, fetches the Interaction and Agent config from the
1018+ API, converts to AgentData, and populates it on the EvalCase so
1019+ that ``show()`` can render the System Topology and Conversation
1020+ Trace sections.
1021+
1022+ Args:
1023+ api_client: The API client used to fetch interactions and agents.
1024+ dataset_list: The original evaluation datasets.
1025+
1026+ Returns:
1027+ A list of EvaluationDatasets with agent_data populated from
1028+ resolved interactions.
1029+ """
1030+ resolved_datasets = []
1031+ for dataset in dataset_list :
1032+ if not dataset .eval_cases :
1033+ resolved_datasets .append (dataset )
1034+ continue
1035+
1036+ resolved_cases = []
1037+ any_resolved = False
1038+ for case in dataset .eval_cases :
1039+ ids = case .interactions_data_source
1040+ if ids and not case .agent_data :
1041+ interaction_name = ids .interaction
1042+ gemini_cfg = ids .gemini_agent_config
1043+ agent_name = gemini_cfg .gemini_agent if gemini_cfg else None
1044+
1045+ if interaction_name :
1046+ try :
1047+ # Extract the interaction short ID from the resource
1048+ # name; handles both full resource names and bare IDs.
1049+ interaction_id = interaction_name .split ("/" )[- 1 ]
1050+
1051+ logger .info (
1052+ "Fetching interaction chain for %s for display." ,
1053+ interaction_name ,
1054+ )
1055+ path = f"interactions/{ interaction_id } "
1056+ response = api_client .request ("get" , path , {}, None )
1057+ if not response .body :
1058+ logger .warning (
1059+ "Empty response fetching interaction %s." ,
1060+ interaction_name ,
1061+ )
1062+ resolved_cases .append (case )
1063+ continue
1064+ interaction_dict = json .loads (response .body )
1065+
1066+ agent_data = _interaction_dict_to_agent_data (interaction_dict )
1067+
1068+ # Best-effort: fetch agent config (instruction,
1069+ # tools, description) from the Agent API.
1070+ agent_config = _fetch_agent_config_dict (
1071+ api_client , agent_name or ""
1072+ )
1073+ agent_data .agents = {agent_config .agent_id : agent_config }
1074+
1075+ _merge_text_parts_in_agent_data (agent_data )
1076+
1077+ # Preserve all original EvalCase fields; only
1078+ # update agent_data.
1079+ resolved_cases .append (
1080+ case .model_copy (update = {"agent_data" : agent_data })
1081+ )
1082+ any_resolved = True
1083+ continue
1084+ except Exception as e : # pylint: disable=broad-exception-caught
1085+ logger .warning (
1086+ "Failed to resolve interaction %s for display: %s" ,
1087+ interaction_name ,
1088+ e ,
1089+ )
1090+
1091+ resolved_cases .append (case )
1092+
1093+ if any_resolved :
1094+ resolved_datasets .append (
1095+ dataset .model_copy (update = {"eval_cases" : resolved_cases })
1096+ )
1097+ else :
1098+ resolved_datasets .append (dataset )
1099+
1100+ return resolved_datasets
1101+
1102+
10101103def _add_evaluation_run_labels (
10111104 labels : Optional [dict [str , str ]] = None ,
10121105 agent : Optional [str ] = None ,
@@ -2349,6 +2442,11 @@ def _execute_evaluation( # type: ignore[no-untyped-def]
23492442 t2 = time .perf_counter ()
23502443 logger .info ("Evaluation took: %f seconds" , t2 - t1 )
23512444
2445+ # Resolve interactions_data_source to agent_data for display.
2446+ # This fetches Interaction trace data client-side so that show() can
2447+ # render the System Topology and Conversation Trace sections.
2448+ dataset_list = _resolve_interactions_for_display (api_client , dataset_list )
2449+
23522450 evaluation_result .evaluation_dataset = dataset_list
23532451 evaluation_result .agent_info = validated_agent_info
23542452
0 commit comments