From 475024cdb47856cf97e1fab21e761062f5abe4f7 Mon Sep 17 00:00:00 2001 From: A Vertex SDK engineer Date: Mon, 27 Jul 2026 14:31:03 -0700 Subject: [PATCH] chore: Remove sandbox tool declarations from SDK AgentConfig display. PiperOrigin-RevId: 954831634 --- agentplatform/_genai/_evals_builtin_tools.py | 43 +++++----------- agentplatform/_genai/_evals_common.py | 8 +-- tests/unit/agentplatform/genai/test_evals.py | 54 ++++++++++---------- 3 files changed, 41 insertions(+), 64 deletions(-) diff --git a/agentplatform/_genai/_evals_builtin_tools.py b/agentplatform/_genai/_evals_builtin_tools.py index 5b2a868565..ee7a6355cc 100644 --- a/agentplatform/_genai/_evals_builtin_tools.py +++ b/agentplatform/_genai/_evals_builtin_tools.py @@ -26,9 +26,9 @@ **If the server catalog changes, this SDK-side copy must be updated to match.** -This module also provides sandbox-detection helpers -(``SANDBOX_TOOL_NAMES``, ``is_sandbox_only_turn``) used by the display -path (``_evals_common._interaction_dict_to_agent_data``). +Sandbox orchestration tools (``provision_sandbox``, ``load_sandbox``) are +intentionally excluded from the tool catalog. They are infrastructure +initialization, not user-facing agent capabilities. """ from typing import Any, Optional @@ -76,25 +76,13 @@ } -# Sandbox-environment orchestration tool declarations. -# -# Source of truth: interaction_converter.py, _SANDBOX_FUNCTION_DECLARATIONS -SANDBOX_DECLARATIONS: list[genai_types.FunctionDeclaration] = [ - genai_types.FunctionDeclaration( - name="provision_sandbox", - description="Provisions a sandbox environment.", - ), - genai_types.FunctionDeclaration( - name="load_sandbox", - description="Loads a previously provisioned sandbox environment.", - ), -] - - -# Names of sandbox orchestration tools, derived from ``SANDBOX_DECLARATIONS`` -# so there is a single source of truth. +# Sandbox-environment orchestration tools. +# Source of truth: interaction_converter.py, _SANDBOX_TOOL_NAMES SANDBOX_TOOL_NAMES: frozenset[str] = frozenset( - decl.name for decl in SANDBOX_DECLARATIONS if decl.name + { + "provision_sandbox", + "load_sandbox", + } ) @@ -146,7 +134,6 @@ def is_sandbox_only_turn( def agent_tools_to_config_tools( agent_tools: Optional[list[Any]], - has_environment: bool = False, ) -> Optional[list[genai_types.Tool]]: """Maps Gemini Agents API tools to ``genai_types.Tool`` for display. @@ -163,18 +150,19 @@ def agent_tools_to_config_tools( * ``mcp_server`` is represented as a named declaration with a human-readable label. * Tools carrying explicit ``function_declarations`` are passed through. - * When ``has_environment`` is True, sandbox orchestration tools - (``provision_sandbox``, ``load_sandbox``) are appended. + + Sandbox orchestration tools (``provision_sandbox``, ``load_sandbox``) + are intentionally excluded. They are infrastructure initialization, + not user-facing capabilities. Args: agent_tools: The ``tools`` list from a fetched Gemini agent dict. - has_environment: Whether the agent has a sandbox environment configured. Returns: A list of ``genai_types.Tool``, or ``None`` if there are no mappable tools. """ - if not agent_tools and not has_environment: + if not agent_tools: return None tools: list[genai_types.Tool] = [] for tool in agent_tools or []: @@ -218,7 +206,4 @@ def agent_tools_to_config_tools( elif remainder: tools.append(genai_types.Tool.model_validate(remainder)) - if has_environment: - tools.append(genai_types.Tool(function_declarations=list(SANDBOX_DECLARATIONS))) - return tools or None diff --git a/agentplatform/_genai/_evals_common.py b/agentplatform/_genai/_evals_common.py index 6aee2ffcf9..dd04f217ce 100644 --- a/agentplatform/_genai/_evals_common.py +++ b/agentplatform/_genai/_evals_common.py @@ -903,13 +903,7 @@ def _fetch_agent_config_dict( instruction = agent_dict.get("system_instruction") or None description = agent_dict.get("description") or None agent_type = agent_dict.get("base_agent") or None - has_environment = bool( - agent_dict.get("environment_config") - or agent_dict.get("base_environment") - ) - tools = _agent_tools_to_config_tools( - agent_dict.get("tools"), has_environment=has_environment - ) + tools = _agent_tools_to_config_tools(agent_dict.get("tools")) except Exception as e: # pylint: disable=broad-exception-caught logger.warning( "Failed to fetch agent config for '%s' (continuing without it): %s", diff --git a/tests/unit/agentplatform/genai/test_evals.py b/tests/unit/agentplatform/genai/test_evals.py index f91c101a36..af2b9be31e 100644 --- a/tests/unit/agentplatform/genai/test_evals.py +++ b/tests/unit/agentplatform/genai/test_evals.py @@ -11553,9 +11553,7 @@ def test_load_sandbox_is_sandbox_only(self): self._make_event( author="agent", part=genai_types.Part( - function_call=genai_types.FunctionCall( - name="load_sandbox", args={} - ) + function_call=genai_types.FunctionCall(name="load_sandbox", args={}) ), ), ] @@ -11566,9 +11564,7 @@ def test_non_sandbox_tool_is_not_sandbox_only(self): self._make_event( author="agent", part=genai_types.Part( - function_call=genai_types.FunctionCall( - name="run_command", args={} - ) + function_call=genai_types.FunctionCall(name="run_command", args={}) ), ), ] @@ -11670,7 +11666,10 @@ def test_sandbox_prefix_with_multi_turn(self): } result = _evals_common._interaction_dict_to_agent_data(interaction_dict) assert len(result.turns) == 2 - assert result.turns[0].events[0].content.parts[0].function_call.name == "provision_sandbox" + assert ( + result.turns[0].events[0].content.parts[0].function_call.name + == "provision_sandbox" + ) assert result.turns[0].events[-1].content.parts[0].text == "Reply 1" assert result.turns[1].events[0].content.parts[0].text == "Turn 2" @@ -12010,8 +12009,8 @@ def test_filesystem_expands_to_file_tools(self): "move_file", } - def test_environment_adds_sandbox_tools(self): - """When agent has environment_config, sandbox tools are appended.""" + def test_environment_does_not_add_sandbox_tools(self): + """Sandbox tools should NOT appear even when agent has environment.""" agent_json = { "tools": [{"type": "code_execution"}], "environment_config": {"some_field": "value"}, @@ -12022,8 +12021,8 @@ def test_environment_adds_sandbox_tools(self): mock_api_client, "projects/p/locations/l/agents/a", ) - # code_execution + sandbox tool - assert len(result.tools) == 2 + # Only code_execution, no sandbox tools. + assert len(result.tools) == 1 all_decl_names = { fd.name for t in result.tools @@ -12031,8 +12030,8 @@ def test_environment_adds_sandbox_tools(self): for fd in t.function_declarations } assert "run_command" in all_decl_names - assert "provision_sandbox" in all_decl_names - assert "load_sandbox" in all_decl_names + assert "provision_sandbox" not in all_decl_names + assert "load_sandbox" not in all_decl_names def test_mcp_server_kept_as_named_declaration(self): """mcp_server entries are kept as named declarations, not dropped.""" @@ -12062,11 +12061,15 @@ def test_mcp_server_kept_as_named_declaration(self): def test_catalog_in_sync_with_server(self): """SDK catalog keys and function names match the server-side catalog. - The SDK-side BUILTIN_TOOL_DECLARATIONS and SANDBOX_DECLARATIONS in - _evals_builtin_tools are a display-only copy of the authoritative - server-side catalog in interaction_converter.py. This test imports - both and asserts that tool-type keys and declaration names stay in - sync. If this test fails, update _evals_builtin_tools.py to match. + The SDK-side BUILTIN_TOOL_DECLARATIONS in _evals_builtin_tools is a + display-only copy of the authoritative server-side catalog in + interaction_converter.py. This test imports both and asserts that + tool-type keys and declaration names stay in sync. If this test + fails, update _evals_builtin_tools.py to match. + + Sandbox tool declarations (provision_sandbox, load_sandbox) are + intentionally excluded from both the SDK and server AgentConfig + tool catalogs, so no sync check is needed for them. """ # pylint: disable=g-import-not-at-top try: @@ -12104,17 +12107,12 @@ def test_catalog_in_sync_with_server(self): f" SDK: {sorted(sdk_names)}" ) - # --- Sandbox declarations: names must match --- - server_sandbox_names = { - fd.name for fd in interaction_converter.sandbox_function_declarations() - } - sdk_sandbox_names = { - fd.name for fd in _evals_builtin_tools.SANDBOX_DECLARATIONS - } - assert sdk_sandbox_names == server_sandbox_names, ( - f"SANDBOX_DECLARATIONS names out of sync.\n" + # --- Sandbox tool names: SDK names must match server names --- + server_sandbox_names = set(interaction_converter._SANDBOX_TOOL_NAMES) + assert _evals_builtin_tools.SANDBOX_TOOL_NAMES == server_sandbox_names, ( + f"SANDBOX_TOOL_NAMES out of sync.\n" f" Server: {sorted(server_sandbox_names)}\n" - f" SDK: {sorted(sdk_sandbox_names)}" + f" SDK: {sorted(_evals_builtin_tools.SANDBOX_TOOL_NAMES)}" )