@@ -420,6 +420,96 @@ def _extract_response_from_completed_trace(
420420 return event_dicts
421421
422422
423+ def _has_interactions_data_source (
424+ eval_cases : list [types .EvalCase ],
425+ ) -> bool :
426+ """Returns True if any EvalCase has interactions_data_source set."""
427+ return any (
428+ getattr (case , "interactions_data_source" , None ) is not None
429+ for case in eval_cases
430+ )
431+
432+
433+ def _resolve_interactions_to_eval_cases (
434+ api_client : BaseApiClient ,
435+ eval_cases : list [types .EvalCase ],
436+ ) -> list [types .EvalCase ]:
437+ """Resolves EvalCases with interactions_data_source to agent_data.
438+
439+ For each EvalCase that has interactions_data_source set, fetches the
440+ Interaction via the SDK's interactions.get() API, converts the steps
441+ to AgentData, and returns a new EvalCase with agent_data populated.
442+
443+ Args:
444+ api_client: The API client (must have an interactions module).
445+ eval_cases: EvalCases with interactions_data_source set.
446+
447+ Returns:
448+ New list of EvalCases with agent_data populated from resolved
449+ interactions.
450+
451+ Raises:
452+ ValueError: If eval_cases have missing interaction references.
453+ """
454+ # Validate all cases up front before making any API calls.
455+ for case in eval_cases :
456+ ids = case .interactions_data_source
457+ if ids is None :
458+ raise ValueError (
459+ "All eval_cases must have interactions_data_source set when"
460+ " using interaction resolution. Found a case without it. Do"
461+ " not mix interaction-based and prompt-based eval cases."
462+ )
463+ if not ids .interaction :
464+ raise ValueError (
465+ "interactions_data_source.interaction is required. Each"
466+ " EvalCase must reference an existing Interaction resource."
467+ )
468+
469+ resolved_cases = []
470+
471+ for case in eval_cases :
472+ ids = case .interactions_data_source
473+
474+ # Extract the interaction ID from the resource name.
475+ # Format: projects/{p}/locations/{l}/interactions/{id}
476+ parts = ids .interaction .split ("/" )
477+ if len (parts ) >= 6 and parts [4 ] == "interactions" :
478+ interaction_id = parts [5 ]
479+ else :
480+ interaction_id = ids .interaction
481+
482+ logger .info ("Fetching interaction: %s" , ids .interaction )
483+ path = f"interactions/{ interaction_id } "
484+ response = api_client .request ("get" , path , {}, None )
485+ interaction_dict = (
486+ {} if not response .body else json .loads (response .body )
487+ )
488+
489+ agent_data = _interaction_dict_to_agent_data (interaction_dict )
490+
491+ # Best-effort: fetch the agent config (instruction, tools,
492+ # description) from the Agent API so the display can render
493+ # the System Topology section.
494+ gemini_cfg = getattr (ids , "gemini_agent_config" , None )
495+ agent_name = (
496+ getattr (gemini_cfg , "gemini_agent" , None )
497+ if gemini_cfg else None
498+ )
499+ agent_config = _fetch_agent_config_dict (
500+ api_client , agent_name or ""
501+ )
502+ agent_data .agents = {agent_config .agent_id : agent_config }
503+
504+ # Merge consecutive text events and parts so multi-paragraph
505+ # responses render as a single block in the trace display.
506+ _merge_text_parts_in_agent_data (agent_data )
507+
508+ resolved_cases .append (types .EvalCase (agent_data = agent_data ))
509+
510+ return resolved_cases
511+
512+
423513def _resolve_dataset (
424514 api_client : BaseApiClient ,
425515 dataset : Union [types .EvaluationRunDataSource , types .EvaluationDataset ],
@@ -428,6 +518,15 @@ def _resolve_dataset(
428518) -> types .EvaluationRunDataSource :
429519 """Resolves dataset for the evaluation run."""
430520 if isinstance (dataset , types .EvaluationDataset ):
521+ # Resolve EvalCases with interactions_data_source by fetching
522+ # each interaction and converting it to agent_data, then flowing
523+ # through the normal DataFrame/GCS pipeline.
524+ if dataset .eval_cases and _has_interactions_data_source (dataset .eval_cases ):
525+ resolved_cases = _resolve_interactions_to_eval_cases (
526+ api_client , dataset .eval_cases
527+ )
528+ dataset = types .EvaluationDataset (eval_cases = resolved_cases )
529+
431530 candidate_name = _get_candidate_name (dataset , parsed_agent_info )
432531 eval_df = dataset .eval_dataset_df
433532 if eval_df is None and dataset .eval_cases :
0 commit comments