@@ -923,6 +923,122 @@ def _fetch_agent_config_dict(
923923 )
924924
925925
926+ def _resolve_interactions_for_display (
927+ api_client : BaseApiClient ,
928+ dataset_list : list [types .EvaluationDataset ],
929+ ) -> list [types .EvaluationDataset ]:
930+ """Resolves interactions_data_source on EvalCases for display.
931+
932+ For each EvalCase that has ``interactions_data_source`` set but no
933+ ``agent_data``, fetches the Interaction and Agent config from the
934+ API, converts to AgentData, and populates it on the EvalCase so
935+ that ``show()`` can render the System Topology and Conversation
936+ Trace sections.
937+
938+ Args:
939+ api_client: The API client used to fetch interactions and agents.
940+ dataset_list: The original evaluation datasets.
941+
942+ Returns:
943+ A list of EvaluationDatasets with agent_data populated from
944+ resolved interactions.
945+ """
946+ resolved_datasets = []
947+ for dataset in dataset_list :
948+ if not dataset .eval_cases :
949+ resolved_datasets .append (dataset )
950+ continue
951+
952+ resolved_cases = []
953+ any_resolved = False
954+ for case in dataset .eval_cases :
955+ ids = case .interactions_data_source
956+ if ids and not case .agent_data :
957+ interaction_name = ids .interaction
958+ gemini_cfg = ids .gemini_agent_config
959+ agent_name = gemini_cfg .gemini_agent if gemini_cfg else None
960+
961+ if interaction_name :
962+ try :
963+ # Extract the interaction short ID from the resource
964+ # name; handles both full resource names and bare IDs.
965+ interaction_id = interaction_name .split ("/" )[- 1 ]
966+
967+ logger .info (
968+ "Fetching interaction chain for %s for display." ,
969+ interaction_name ,
970+ )
971+ current_interaction_id = interaction_id
972+ interactions = []
973+ seen_ids = set ()
974+ for _ in range (10 ): # max depth
975+ if current_interaction_id in seen_ids :
976+ break
977+ seen_ids .add (current_interaction_id )
978+ path = f"interactions/{ current_interaction_id } "
979+ response = api_client .request ("get" , path , {}, None )
980+ if not response .body :
981+ if not interactions :
982+ logger .warning (
983+ "Empty response fetching interaction %s." ,
984+ interaction_name ,
985+ )
986+ break
987+ interaction_dict = json .loads (response .body )
988+ interactions .append (interaction_dict )
989+ prev_id_str = interaction_dict .get ("previousInteractionId" ) or interaction_dict .get ("previous_interaction_id" )
990+ if not prev_id_str :
991+ break
992+ current_interaction_id = prev_id_str .split ("/" )[- 1 ]
993+
994+ if not interactions :
995+ resolved_cases .append (case )
996+ continue
997+
998+ interactions .reverse () # chronological order
999+ all_steps = []
1000+ for i_dict in interactions :
1001+ all_steps .extend (i_dict .get ("steps" , []))
1002+
1003+ combined_interaction = interactions [- 1 ].copy ()
1004+ combined_interaction ["steps" ] = all_steps
1005+ agent_data = _interaction_dict_to_agent_data (combined_interaction )
1006+
1007+ # Best-effort: fetch agent config (instruction,
1008+ # tools, description) from the Agent API.
1009+ agent_config = _fetch_agent_config_dict (
1010+ api_client , agent_name or ""
1011+ )
1012+ agent_data .agents = {agent_config .agent_id : agent_config }
1013+
1014+ _merge_text_parts_in_agent_data (agent_data )
1015+
1016+ # Preserve all original EvalCase fields; only
1017+ # update agent_data.
1018+ resolved_cases .append (
1019+ case .model_copy (update = {"agent_data" : agent_data })
1020+ )
1021+ any_resolved = True
1022+ continue
1023+ except Exception as e : # pylint: disable=broad-exception-caught
1024+ logger .warning (
1025+ "Failed to resolve interaction %s for display: %s" ,
1026+ interaction_name ,
1027+ e ,
1028+ )
1029+
1030+ resolved_cases .append (case )
1031+
1032+ if any_resolved :
1033+ resolved_datasets .append (
1034+ dataset .model_copy (update = {"eval_cases" : resolved_cases })
1035+ )
1036+ else :
1037+ resolved_datasets .append (dataset )
1038+
1039+ return resolved_datasets
1040+
1041+
9261042def _add_evaluation_run_labels (
9271043 labels : Optional [dict [str , str ]] = None ,
9281044 agent : Optional [str ] = None ,
@@ -2245,6 +2361,11 @@ def _execute_evaluation( # type: ignore[no-untyped-def]
22452361 t2 = time .perf_counter ()
22462362 logger .info ("Evaluation took: %f seconds" , t2 - t1 )
22472363
2364+ # Resolve interactions_data_source to agent_data for display.
2365+ # This fetches Interaction trace data client-side so that show() can
2366+ # render the System Topology and Conversation Trace sections.
2367+ dataset_list = _resolve_interactions_for_display (api_client , dataset_list )
2368+
22482369 evaluation_result .evaluation_dataset = dataset_list
22492370 evaluation_result .agent_info = validated_agent_info
22502371
0 commit comments