@@ -840,15 +840,28 @@ def _merge_text_parts_in_agent_data(
840840def _agent_tools_to_config_tools (
841841 agent_tools : Optional [list [Any ]],
842842) -> Optional [list [genai_types .Tool ]]:
843- """Maps Gemini Agents API tools to ``genai_types.Tool`` for an AgentConfig.
844-
845- The Gemini Agents API returns built-in tool variants (``google_search``,
846- ``code_execution``, ``url_context``) whose schema differs from
847- ``genai_types.Tool``. Each recognised built-in variant is mapped to the
848- matching ``genai_types.Tool`` field. Tools with a non-empty body after
849- stripping the ``type`` key (e.g. ``function_declarations``) are passed
850- through ``model_validate``. Variants without a ``genai_types.Tool``
851- equivalent (e.g. ``filesystem``, ``mcp_server``) are skipped.
843+ """Maps Gemini Agents API tools to ``genai_types.Tool`` for display.
844+
845+ NOTE: This is a low-fidelity, DISPLAY-ONLY mapping. The Gemini Agents API
846+ (``GET agents/{id}``) returns each tool as a bare type discriminator
847+ (e.g. ``{"type": "code_execution"}``) with no parameter schema or
848+ description. The authoritative, full-fidelity expansion of built-in tool
849+ types into function declarations (e.g. ``code_execution`` -> ``run_command``
850+ with parameters, ``filesystem`` -> file tools, sandbox tools) is performed
851+ server-side in ``interaction_converter.py`` whenever the server is handed a
852+ ``gemini_agent_config``. The result of this function must therefore only be
853+ used to render the local System Topology in ``show()`` and must never be
854+ sent to the server-side autorater or scenario generator (which resolve the
855+ agent's tools themselves).
856+
857+ Mapping rules:
858+ * Recognised built-in variants (``google_search``, ``code_execution``,
859+ ``url_context``) are mapped to the matching ``genai_types.Tool`` field.
860+ * Tools that already carry ``function_declarations`` are passed through
861+ via ``model_validate`` so real function tools keep their full schema.
862+ * Any other typed built-in (e.g. ``filesystem``, ``mcp_server``) is
863+ represented as a single named ``FunctionDeclaration`` so the tool is
864+ still shown by name in the display instead of being dropped.
852865
853866 Args:
854867 agent_tools: The ``tools`` list from a fetched Gemini agent dict.
@@ -864,6 +877,7 @@ def _agent_tools_to_config_tools(
864877 if not isinstance (tool , dict ):
865878 continue
866879 tool_type = tool .get ("type" )
880+ remainder = {k : v for k , v in tool .items () if k != "type" }
867881 if tool_type == "google_search" :
868882 tools .append (genai_types .Tool (google_search = genai_types .GoogleSearch ()))
869883 elif tool_type == "code_execution" :
@@ -872,12 +886,31 @@ def _agent_tools_to_config_tools(
872886 )
873887 elif tool_type == "url_context" :
874888 tools .append (genai_types .Tool (url_context = genai_types .UrlContext ()))
875- else :
876- # For non-built-in tools (e.g. function_declarations), strip the
877- # type key and validate through genai_types.Tool.
878- remainder = {k : v for k , v in tool .items () if k != "type" }
879- if remainder :
880- tools .append (genai_types .Tool .model_validate (remainder ))
889+ elif "function_declarations" in remainder :
890+ # Real function tool with explicit declarations: pass through so
891+ # the display shows the full name/parameter schema.
892+ tools .append (genai_types .Tool .model_validate (remainder ))
893+ elif tool_type :
894+ # Other built-in tool type with no genai_types.Tool variant (e.g.
895+ # "filesystem", "mcp_server"). Represent it as a named declaration
896+ # so it is shown by name rather than dropped. Full parameter
897+ # schemas are only available from the server-side expansion.
898+ description = None
899+ if tool_type == "mcp_server" :
900+ label = remainder .get ("name" ) or remainder .get ("url" )
901+ description = f"MCP server: { label } " if label else "MCP server."
902+ tools .append (
903+ genai_types .Tool (
904+ function_declarations = [
905+ genai_types .FunctionDeclaration (
906+ name = tool_type , description = description
907+ )
908+ ]
909+ )
910+ )
911+ elif remainder :
912+ # Untyped tool body: best-effort pass-through.
913+ tools .append (genai_types .Tool .model_validate (remainder ))
881914 return tools or None
882915
883916
@@ -988,33 +1021,6 @@ def _agent_data_response_text(agent_data: types.evals.AgentData) -> Optional[str
9881021 return "" .join (text_parts ) or None
9891022
9901023
991- def _agent_resource_to_agent_info (
992- agent : str , api_client : BaseApiClient
993- ) -> "types.evals.AgentInfo" :
994- """Builds an `AgentInfo` from a Gemini Agents API agent resource name.
995-
996- Fetches the agent through the SDK's `api_client` (so replay recording is
997- preserved) via `_fetch_agent_config_dict` and derives a single-agent
998- `AgentInfo`: the agent's short name is the agents-map key and
999- `root_agent_id`.
1000-
1001- Args:
1002- agent: The Gemini Agents API agent resource name
1003- (`projects/{p}/locations/{l}/agents/{name}`).
1004- api_client: The API client used to fetch the agent.
1005-
1006- Returns:
1007- An `AgentInfo` describing the fetched agent.
1008- """
1009- agent_config = _fetch_agent_config_dict (api_client , agent )
1010- short_name = agent_config .agent_id
1011- return types .evals .AgentInfo ( # pytype: disable=missing-parameter
1012- name = short_name ,
1013- agents = {short_name : agent_config },
1014- root_agent_id = short_name ,
1015- )
1016-
1017-
10181024_INTERACTION_TERMINAL_STATES = frozenset (
10191025 ["completed" , "failed" , "cancelled" , "incomplete" , "budget_exceeded" ]
10201026)
@@ -1109,6 +1115,12 @@ def _run_gemini_agent_inference(
11091115 interactions_client = _get_interactions_client (api_client )
11101116
11111117 agent_short_id = gemini_agent .split ("/" )[- 1 ]
1118+
1119+ # Best-effort: fetch the agent config (instruction, tools, description)
1120+ # once, so every row's agent_data carries the agents map and the display
1121+ # can render the System Topology section.
1122+ agent_config = _fetch_agent_config_dict (api_client , gemini_agent )
1123+
11121124 prompts : list [str ] = []
11131125 responses : list [Optional [str ]] = []
11141126 interaction_ids : list [Optional [str ]] = []
@@ -1128,6 +1140,7 @@ def _run_gemini_agent_inference(
11281140 )
11291141 interaction = _await_interaction (interactions_client , interaction )
11301142 agent_data_obj = _interaction_dict_to_agent_data (interaction )
1143+ agent_data_obj .agents = {agent_config .agent_id : agent_config }
11311144 _merge_text_parts_in_agent_data (agent_data_obj )
11321145 responses .append (_agent_data_response_text (agent_data_obj ))
11331146 interaction_ids .append (interaction .get ("id" ))
0 commit comments