Skip to content

Commit 8ee8193

Browse files
seanzhougooglecopybara-github
authored andcommitted
fix: Add response schema for agent tool function declaration even when it's return None
PiperOrigin-RevId: 783610166
1 parent 33ac838 commit 8ee8193

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

src/google/adk/tools/agent_tool.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def populate_name(cls, data: Any) -> Any:
6161
@override
6262
def _get_declaration(self) -> types.FunctionDeclaration:
6363
from ..agents.llm_agent import LlmAgent
64+
from ..utils.variant_utils import GoogleLLMVariant
6465

6566
if isinstance(self.agent, LlmAgent) and self.agent.input_schema:
6667
result = _automatic_function_calling_util.build_function_declaration(
@@ -80,6 +81,17 @@ def _get_declaration(self) -> types.FunctionDeclaration:
8081
description=self.agent.description,
8182
name=self.name,
8283
)
84+
85+
# Set response schema for non-GEMINI_API variants
86+
if self._api_variant != GoogleLLMVariant.GEMINI_API:
87+
# Determine response type based on agent's output schema
88+
if isinstance(self.agent, LlmAgent) and self.agent.output_schema:
89+
# Agent has structured output schema - response is an object
90+
result.response = types.Schema(type=types.Type.OBJECT)
91+
else:
92+
# Agent returns text - response is a string
93+
result.response = types.Schema(type=types.Type.STRING)
94+
8395
result.name = self.name
8496
return result
8597

tests/unittests/tools/test_agent_tool.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
from google.adk.agents import SequentialAgent
1717
from google.adk.agents.callback_context import CallbackContext
1818
from google.adk.tools.agent_tool import AgentTool
19+
from google.adk.utils.variant_utils import GoogleLLMVariant
20+
from google.genai import types
1921
from google.genai.types import Part
2022
from pydantic import BaseModel
2123
from pytest import mark
@@ -209,3 +211,147 @@ class CustomOutput(BaseModel):
209211
# The second request is the tool agent request.
210212
assert mock_model.requests[1].config.response_schema == CustomOutput
211213
assert mock_model.requests[1].config.response_mime_type == 'application/json'
214+
215+
216+
@mark.parametrize(
217+
'env_variables',
218+
[
219+
'VERTEX', # Test VERTEX_AI variant
220+
],
221+
indirect=True,
222+
)
223+
def test_agent_tool_response_schema_no_output_schema_vertex_ai():
224+
"""Test AgentTool with no output schema has string response schema for VERTEX_AI."""
225+
tool_agent = Agent(
226+
name='tool_agent',
227+
model=testing_utils.MockModel.create(responses=['test response']),
228+
)
229+
230+
agent_tool = AgentTool(agent=tool_agent)
231+
declaration = agent_tool._get_declaration()
232+
233+
assert declaration.name == 'tool_agent'
234+
assert declaration.parameters.type == 'OBJECT'
235+
assert declaration.parameters.properties['request'].type == 'STRING'
236+
# Should have string response schema for VERTEX_AI
237+
assert declaration.response is not None
238+
assert declaration.response.type == types.Type.STRING
239+
240+
241+
@mark.parametrize(
242+
'env_variables',
243+
[
244+
'VERTEX', # Test VERTEX_AI variant
245+
],
246+
indirect=True,
247+
)
248+
def test_agent_tool_response_schema_with_output_schema_vertex_ai():
249+
"""Test AgentTool with output schema has object response schema for VERTEX_AI."""
250+
251+
class CustomOutput(BaseModel):
252+
custom_output: str
253+
254+
tool_agent = Agent(
255+
name='tool_agent',
256+
model=testing_utils.MockModel.create(responses=['test response']),
257+
output_schema=CustomOutput,
258+
)
259+
260+
agent_tool = AgentTool(agent=tool_agent)
261+
declaration = agent_tool._get_declaration()
262+
263+
assert declaration.name == 'tool_agent'
264+
# Should have object response schema for VERTEX_AI when output_schema exists
265+
assert declaration.response is not None
266+
assert declaration.response.type == types.Type.OBJECT
267+
268+
269+
@mark.parametrize(
270+
'env_variables',
271+
[
272+
'GOOGLE_AI', # Test GEMINI_API variant
273+
],
274+
indirect=True,
275+
)
276+
def test_agent_tool_response_schema_gemini_api():
277+
"""Test AgentTool with GEMINI_API variant has no response schema."""
278+
279+
class CustomOutput(BaseModel):
280+
custom_output: str
281+
282+
tool_agent = Agent(
283+
name='tool_agent',
284+
model=testing_utils.MockModel.create(responses=['test response']),
285+
output_schema=CustomOutput,
286+
)
287+
288+
agent_tool = AgentTool(agent=tool_agent)
289+
declaration = agent_tool._get_declaration()
290+
291+
assert declaration.name == 'tool_agent'
292+
# GEMINI_API should not have response schema
293+
assert declaration.response is None
294+
295+
296+
@mark.parametrize(
297+
'env_variables',
298+
[
299+
'VERTEX', # Test VERTEX_AI variant
300+
],
301+
indirect=True,
302+
)
303+
def test_agent_tool_response_schema_with_input_schema_vertex_ai():
304+
"""Test AgentTool with input and output schemas for VERTEX_AI."""
305+
306+
class CustomInput(BaseModel):
307+
custom_input: str
308+
309+
class CustomOutput(BaseModel):
310+
custom_output: str
311+
312+
tool_agent = Agent(
313+
name='tool_agent',
314+
model=testing_utils.MockModel.create(responses=['test response']),
315+
input_schema=CustomInput,
316+
output_schema=CustomOutput,
317+
)
318+
319+
agent_tool = AgentTool(agent=tool_agent)
320+
declaration = agent_tool._get_declaration()
321+
322+
assert declaration.name == 'tool_agent'
323+
assert declaration.parameters.type == 'OBJECT'
324+
assert declaration.parameters.properties['custom_input'].type == 'STRING'
325+
# Should have object response schema for VERTEX_AI when output_schema exists
326+
assert declaration.response is not None
327+
assert declaration.response.type == types.Type.OBJECT
328+
329+
330+
@mark.parametrize(
331+
'env_variables',
332+
[
333+
'VERTEX', # Test VERTEX_AI variant
334+
],
335+
indirect=True,
336+
)
337+
def test_agent_tool_response_schema_with_input_schema_no_output_vertex_ai():
338+
"""Test AgentTool with input schema but no output schema for VERTEX_AI."""
339+
340+
class CustomInput(BaseModel):
341+
custom_input: str
342+
343+
tool_agent = Agent(
344+
name='tool_agent',
345+
model=testing_utils.MockModel.create(responses=['test response']),
346+
input_schema=CustomInput,
347+
)
348+
349+
agent_tool = AgentTool(agent=tool_agent)
350+
declaration = agent_tool._get_declaration()
351+
352+
assert declaration.name == 'tool_agent'
353+
assert declaration.parameters.type == 'OBJECT'
354+
assert declaration.parameters.properties['custom_input'].type == 'STRING'
355+
# Should have string response schema for VERTEX_AI when no output_schema
356+
assert declaration.response is not None
357+
assert declaration.response.type == types.Type.STRING

0 commit comments

Comments
 (0)