Skip to content
Open
1 change: 0 additions & 1 deletion contributing/samples/gepa/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
from tau_bench.types import EnvRunResult
from tau_bench.types import RunConfig
import tau_bench_agent as tau_bench_agent_lib

import utils


Expand Down
1 change: 0 additions & 1 deletion contributing/samples/gepa/run_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from absl import flags
import experiment
from google.genai import types

import utils

_OUTPUT_DIR = flags.DEFINE_string(
Expand Down
2 changes: 1 addition & 1 deletion src/google/adk/tools/agent_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ async def run_async(

if not last_content:
return ''
merged_text = '\n'.join(p.text for p in last_content.parts if p.text)
merged_text = '\n'.join(p.text for p in (last_content.parts or []) if p.text)
if isinstance(self.agent, LlmAgent) and self.agent.output_schema:
tool_result = self.agent.output_schema.model_validate_json(
merged_text
Expand Down
2 changes: 1 addition & 1 deletion src/google/adk/tools/google_search_agent_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ async def run_async(

if not last_content:
return ''
merged_text = '\n'.join(p.text for p in last_content.parts if p.text)
merged_text = '\n'.join(p.text for p in (last_content.parts or []) if p.text)
if isinstance(self.agent, LlmAgent) and self.agent.output_schema:
tool_result = self.agent.output_schema.model_validate_json(
merged_text
Expand Down
58 changes: 58 additions & 0 deletions tests/unittests/tools/test_google_search_agent_tool_repro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from google.adk.agents.invocation_context import InvocationContext
from google.adk.agents.llm_agent import Agent
from google.adk.models.llm_response import LlmResponse
from google.adk.sessions.in_memory_session_service import InMemorySessionService
from google.adk.tools.google_search_agent_tool import GoogleSearchAgentTool
from google.adk.tools.tool_context import ToolContext
from google.genai import types
from google.genai.types import Part
from pytest import mark

from .. import testing_utils

function_call_no_schema = Part.from_function_call(
name='tool_agent', args={'request': 'test1'}
)


@mark.asyncio
async def test_run_async_handles_none_parts_in_response():
"""Verify run_async handles None parts in the response without crashing."""

# Mock model for the tool_agent that returns content with parts=None
# This simulates the condition causing the TypeError
tool_agent_model = testing_utils.MockModel.create(
responses=[
LlmResponse(
content=types.Content(parts=None),
)
]
)

tool_agent = Agent(
name='tool_agent',
model=tool_agent_model,
)

agent_tool = GoogleSearchAgentTool(agent=tool_agent)

session_service = InMemorySessionService()
session = await session_service.create_session(
app_name='test_app', user_id='test_user'
)

invocation_context = InvocationContext(
invocation_id='invocation_id',
agent=tool_agent,
session=session,
session_service=session_service,
)
tool_context = ToolContext(invocation_context=invocation_context)

# This should not raise TypeError: 'NoneType' object is not iterable
# It should ideally return an empty string or handle it gracefully
tool_result = await agent_tool.run_async(
args=function_call_no_schema.function_call.args, tool_context=tool_context
)

assert tool_result == ''