Skip to content

Commit da1d8f1

Browse files
haranrkharanrk
authored andcommitted
feat(interactions): update ADK to support Google GenAI SDK v2.0.0
Update ADK to support the new Interactions API. See: https://ai.google.dev/gemini-api/docs/interactions-breaking-changes-may-2026 Key changes include: * Updated `interactions_utils.py` to parse new v2 interaction events such as `InteractionCreatedEvent`, `InteractionCompletedEvent`, and explicit step types (`ModelOutputStep`, `FunctionCallStep`, etc.). * Transitioned from "turns" to "steps" terminology, including renaming `convert_contents_to_turns` to `convert_contents_to_steps`. * Updated `contributing/samples/interactions_api` Breaking Changes in interactions_utils.py: - Renamed "turn" functions to "step" equivalents: - `convert_content_to_turn` -> `_convert_content_to_step` - `convert_contents_to_turns` -> `_convert_contents_to_steps` - `convert_interaction_output_to_part` -> `_convert_interaction_step_to_parts` - Updated `build_interactions_request_log` to use required `input_steps` instead of `input_turns`. - Deprecated `convert_part_to_interaction_content` Change-Id: I962724321342ba0192251896ce51832b214d60d9
1 parent 5ad1942 commit da1d8f1

5 files changed

Lines changed: 982 additions & 658 deletions

File tree

‎contributing/samples/models/interactions_api/agent.py‎

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,6 @@
1313
# limitations under the License.
1414

1515
"""Agent definition for testing the Interactions API integration.
16-
17-
NOTE: The Interactions API does NOT support mixing custom function calling tools
18-
with built-in tools in the same agent. To work around this limitation, we use
19-
bypass_multi_tools_limit=True on GoogleSearchTool, which converts the built-in
20-
google_search to a function calling tool (via GoogleSearchAgentTool).
21-
22-
The bypass is only triggered when len(agent.tools) > 1, so we include multiple
23-
tools in the agent (GoogleSearchTool + get_current_weather).
24-
25-
With bypass_multi_tools_limit=True and multiple tools, all tools become function
26-
calling tools, which allows mixing google_search with custom function tools.
2716
"""
2817

2918
from google.adk.agents.llm_agent import Agent
@@ -74,16 +63,13 @@ def get_current_weather(city: str) -> dict:
7463
}
7564

7665

77-
# Main agent with google_search (via bypass) and custom function tools
78-
# Using bypass_multi_tools_limit=True converts google_search to a function calling tool.
79-
# We need len(tools) > 1 to trigger the bypass, so we include get_current_weather directly.
80-
# This allows mixing google_search with custom function tools via the Interactions API.
66+
# Main agent with google_search built-in tool and custom function tools
8167
#
8268
# NOTE: code_executor is not compatible with function calling mode because the model
8369
# tries to call a function (e.g., run_code) instead of outputting code in markdown.
8470
root_agent = Agent(
8571
model=Gemini(
86-
model="gemini-3-flash-preview",
72+
model="gemini-3.1-flash-lite",
8773
use_interactions_api=True,
8874
),
8975
name="interactions_test_agent",
@@ -99,7 +85,7 @@ def get_current_weather(city: str) -> dict:
9985
Be concise and helpful in your responses. Always confirm what you did.
10086
""",
10187
tools=[
102-
GoogleSearchTool(bypass_multi_tools_limit=True),
88+
GoogleSearchTool(),
10389
get_current_weather,
10490
],
10591
)

‎contributing/samples/models/interactions_api/main.py‎

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,11 @@
1616
1717
This script tests the following features:
1818
1. Basic text generation
19-
2. Google Search tool (via bypass_multi_tools_limit)
19+
2. Google Search tool
2020
3. Multi-turn conversations with stateful interactions
2121
4. Google Search tool (additional coverage)
2222
5. Custom function tool (get_current_weather)
2323
24-
NOTE: The Interactions API does NOT support mixing custom function calling tools
25-
with built-in tools. To work around this, we use bypass_multi_tools_limit=True
26-
on GoogleSearchTool, which converts it to a function calling tool (via
27-
GoogleSearchAgentTool). The bypass only triggers when len(agent.tools) > 1,
28-
so we include both GoogleSearchTool and get_current_weather in the agent.
29-
3024
NOTE: Code execution via UnsafeLocalCodeExecutor is not compatible with function
3125
calling mode because the model tries to call a function instead of outputting
3226
code in markdown.
@@ -41,8 +35,8 @@
4135
import logging
4236
from pathlib import Path
4337
import time
44-
from typing import Optional
4538

39+
import httpx
4640
from dotenv import load_dotenv
4741
from google.adk.agents.run_config import RunConfig
4842
from google.adk.cli.utils import logs
@@ -67,7 +61,8 @@ async def call_agent_async(
6761
prompt: str,
6862
agent_name: str = "",
6963
show_interaction_id: bool = True,
70-
) -> tuple[str, Optional[str]]:
64+
additional_parts: list[types.Part] | None = None,
65+
) -> tuple[str, str | None]:
7166
"""Call the agent asynchronously with the user's prompt.
7267
7368
Args:
@@ -77,12 +72,17 @@ async def call_agent_async(
7772
prompt: The prompt to send
7873
agent_name: The expected agent name for filtering responses
7974
show_interaction_id: Whether to show interaction IDs in output
75+
additional_parts: Optional list of additional content parts (e.g. files)
8076
8177
Returns:
8278
A tuple of (response_text, interaction_id)
8379
"""
80+
parts = [types.Part.from_text(text=prompt)]
81+
if additional_parts:
82+
parts.extend(additional_parts)
83+
8484
content = types.Content(
85-
role="user", parts=[types.Part.from_text(text=prompt)]
85+
role="user", parts=parts
8686
)
8787

8888
final_response_text = ""
@@ -264,6 +264,35 @@ async def test_custom_function_tool(runner: Runner, session_id: str):
264264
return interaction_id
265265

266266

267+
async def test_pdf_summarization(runner: Runner, session_id: str) -> str | None:
268+
"""Test PDF summarization using the Interactions API."""
269+
print("\n" + "=" * 60)
270+
print("TEST 6: PDF Summarization")
271+
print("=" * 60)
272+
273+
url = "https://storage.googleapis.com/cloud-samples-data/generative-ai/pdf/2403.05530.pdf"
274+
print(f"Downloading {url}...")
275+
async with httpx.AsyncClient() as client:
276+
response = await client.get(url, headers={'User-Agent': 'Mozilla/5.0'}, follow_redirects=True)
277+
response.raise_for_status()
278+
pdf_bytes = response.content
279+
280+
pdf_part = types.Part.from_bytes(data=pdf_bytes, mime_type="application/pdf")
281+
response, interaction_id = await call_agent_async(
282+
runner,
283+
USER_ID,
284+
session_id,
285+
"Please summarize the attached PDF document.",
286+
additional_parts=[pdf_part],
287+
)
288+
289+
assert response, "Expected a non-empty response"
290+
assert len(response) > 0, f"Expected summary in response: {response}"
291+
assert "gemini" in response.lower() or "multimodal" in response.lower(), f"Expected summary of PDF in response: {response}"
292+
print("PASSED: PDF Summarization works")
293+
return interaction_id
294+
295+
267296
def check_interactions_api_available() -> bool:
268297
"""Check if the interactions API is available in the SDK."""
269298
try:
@@ -311,6 +340,7 @@ async def run_all_tests():
311340
await test_multi_turn_conversation(runner, session.id)
312341
await test_google_search_tool(runner, session.id)
313342
await test_custom_function_tool(runner, session.id)
343+
await test_pdf_summarization(runner, session.id)
314344

315345
print("\n" + "=" * 60)
316346
print("ALL TESTS PASSED (Interactions API)")

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ dependencies = [
3838
"click>=8.1.8,<9",
3939
"fastapi>=0.124.1,<1",
4040
"google-auth[pyopenssl]>=2.47",
41-
"google-genai>=1.72,<2",
41+
"google-genai>=2.4,<3",
4242
"graphviz>=0.20.2,<1",
4343
"httpx>=0.27,<1",
4444
"jsonschema>=4.23,<5",

0 commit comments

Comments
 (0)