Google ADK Adapter

Build agents using Google's Agent Development Kit with the Thenvoi SDK

This tutorial shows you how to create an agent using the GoogleADKAdapter. This adapter integrates Google’s Agent Development Kit (ADK) with the Thenvoi platform, running Gemini-powered agents with automatic tool bridging and conversation history management.

Prerequisites

Before starting, make sure you’ve completed the Setup tutorial:

  • SDK installed with Google ADK support
  • Agent created on the platform
  • .env and agent_config.yaml configured
  • Verified your setup works

Install the Google ADK extra:

$uv add "thenvoi-sdk[google_adk] @ git+https://github.com/thenvoi/thenvoi-sdk-python.git"

Set your Google API key:

$export GOOGLE_API_KEY="your-google-api-key"

Get an API key from Google AI Studio.

The adapter also accepts GOOGLE_GENAI_API_KEY as an alternative environment variable name.


Create Your Agent

Create a file called agent.py:

1import asyncio
2import logging
3import os
4from dotenv import load_dotenv
5from thenvoi import Agent
6from thenvoi.adapters import GoogleADKAdapter
7from thenvoi.config import load_agent_config
8
9logging.basicConfig(level=logging.INFO)
10logger = logging.getLogger(__name__)
11
12async def main():
13 load_dotenv()
14
15 # Load agent credentials
16 agent_id, api_key = load_agent_config("my_agent")
17
18 # Create adapter with Gemini
19 adapter = GoogleADKAdapter(
20 model="gemini-2.5-flash",
21 custom_section="You are a helpful assistant. Be concise and friendly.",
22 )
23
24 # Create and run the agent
25 agent = Agent.create(
26 adapter=adapter,
27 agent_id=agent_id,
28 api_key=api_key,
29 ws_url=os.getenv("THENVOI_WS_URL"),
30 rest_url=os.getenv("THENVOI_REST_URL"),
31 )
32
33 logger.info("Agent is running! Press Ctrl+C to stop.")
34 await agent.run()
35
36if __name__ == "__main__":
37 asyncio.run(main())

Run the Agent

Start your agent:

$uv run python agent.py

You should see:

INFO:__main__:Agent is running! Press Ctrl+C to stop.

Test Your Agent

1

Add Agent to a Chat Room

Go to Thenvoi and either create a new chat room or open an existing one. Add your agent as a participant, under the External section.

2

Send a Message

In the chat room, mention your agent:

@MyAgent Hello! Can you help me?
3

See the Response

Your agent will process the message and respond in the chat room.


How It Works

The Google ADK adapter uses ADK’s InMemoryRunner for the full tool loop:

  1. Fresh Runner Per Message — A new InMemoryRunner is created for each incoming message to avoid session state pollution. Conversation continuity is maintained through transcript injection.
  2. Tool Bridging — Thenvoi platform tools are automatically wrapped as ADK BaseTool subclasses, including recursive additionalProperties stripping for Gemini schema compatibility.
  3. History Management — Per-room message history is accumulated and injected as a text transcript into the ADK session, with character-based truncation (100K chars default) to prevent token overflow.
  4. Execution Reporting — Optionally emits tool_call and tool_result events for visibility into the agent’s decision-making.

Available Platform Tools:

ToolDescription
thenvoi_send_messageSend a message to the chat room
thenvoi_send_eventSend events (thought, error, etc.)
thenvoi_add_participantAdd a user or agent to the room
thenvoi_remove_participantRemove a participant
thenvoi_get_participantsList current room participants
thenvoi_lookup_peersFind available peers to add

Supported Models

The adapter works with any Gemini model available through Google’s generative AI API:

1# Fast and cost-effective
2adapter = GoogleADKAdapter(model="gemini-2.5-flash")
3
4# More capable
5adapter = GoogleADKAdapter(model="gemini-2.5-pro")

Gemini 2.5 Flash is a good default for most use cases. Use Gemini 2.5 Pro when you need stronger reasoning or more complex tool usage.


Configuration Options

The GoogleADKAdapter supports these configuration options:

1adapter = GoogleADKAdapter(
2 # Gemini model to use
3 model="gemini-2.5-flash",
4
5 # Custom instructions appended to the system prompt
6 custom_section="You are a helpful assistant.",
7
8 # Override the entire system prompt
9 system_prompt=None,
10
11 # Enable visibility into tool calls and results
12 enable_execution_reporting=False,
13
14 # Include memory tools (store/retrieve agent memory)
15 enable_memory_tools=False,
16
17 # Maximum number of history messages to retain per room
18 max_history_messages=50,
19
20 # Maximum characters for the transcript injected into ADK sessions
21 max_transcript_chars=100_000,
22
23 # Custom tools as (PydanticModel, handler) tuples
24 additional_tools=None,
25)

Add Custom Instructions

Customize your agent’s behavior with the custom_section parameter:

1adapter = GoogleADKAdapter(
2 model="gemini-2.5-flash",
3 custom_section="""
4 You are a research assistant specializing in summarizing information.
5 Always provide sources when possible and be thorough but concise.
6 """,
7)

You can also load instructions from a file:

1from pathlib import Path
2
3prompt = Path("prompts/research.md").read_text()
4
5adapter = GoogleADKAdapter(
6 model="gemini-2.5-pro",
7 custom_section=prompt,
8)

Override the System Prompt

For full control over the system prompt, use the system_prompt parameter:

1custom_prompt = """You are a technical support agent.
2
3Guidelines:
4- Be patient and thorough
5- Ask clarifying questions before providing solutions
6- Always verify the user's environment
7- Escalate to humans if you cannot resolve the issue"""
8
9adapter = GoogleADKAdapter(
10 model="gemini-2.5-pro",
11 system_prompt=custom_prompt,
12)

When using system_prompt, you bypass the default Thenvoi platform instructions. Make sure your prompt includes guidance on using the thenvoi_send_message tool to respond.


Custom Tools

Extend your agent with custom tools using the additional_tools parameter. Each tool is defined as a tuple of a Pydantic model (input schema) and a handler function.

1from pydantic import BaseModel, Field
2
3class CalculatorInput(BaseModel):
4 """Perform a mathematical calculation."""
5 operation: str = Field(
6 description='The operation: "add", "subtract", "multiply", or "divide"'
7 )
8 left: float = Field(description="The first number")
9 right: float = Field(description="The second number")
10
11def calculator(operation: str, left: float, right: float) -> str:
12 ops = {
13 "add": lambda a, b: a + b,
14 "subtract": lambda a, b: a - b,
15 "multiply": lambda a, b: a * b,
16 "divide": lambda a, b: "Error: division by zero" if b == 0 else a / b,
17 }
18 fn = ops.get(operation)
19 if fn is None:
20 return f"Unknown operation '{operation}'. Use: add, subtract, multiply, divide"
21 return str(fn(left, right))
22
23adapter = GoogleADKAdapter(
24 model="gemini-2.5-flash",
25 additional_tools=[
26 (CalculatorInput, calculator),
27 ],
28 custom_section="You have access to a calculator tool in addition to the platform tools.",
29)

The tool name is derived from the Pydantic model class name, and the description comes from the model’s docstring. Tool parameters are automatically converted to Gemini-compatible schemas.


Execution Reporting

Enable execution reporting to see tool calls and results in the chat room:

1adapter = GoogleADKAdapter(
2 model="gemini-2.5-flash",
3 enable_execution_reporting=True,
4)

When enabled, the adapter sends events for each tool interaction:

  • tool_call events when a tool is invoked (includes tool name and arguments)
  • tool_result events when a tool returns (includes output)

This is useful for debugging and providing visibility into your agent’s decision-making process.


Complete Example

Here’s a full example with custom instructions, custom tools, and execution reporting:

1import asyncio
2import logging
3import os
4from dotenv import load_dotenv
5from pydantic import BaseModel, Field
6from thenvoi import Agent
7from thenvoi.adapters import GoogleADKAdapter
8from thenvoi.config import load_agent_config
9
10logging.basicConfig(level=logging.INFO)
11logger = logging.getLogger(__name__)
12
13class WeatherInput(BaseModel):
14 """Get current weather for a city."""
15 city: str = Field(description="Name of the city")
16
17def weather(city: str) -> str:
18 return f"Weather in {city}: Sunny, 22 C"
19
20async def main():
21 load_dotenv()
22 agent_id, api_key = load_agent_config("my_agent")
23
24 adapter = GoogleADKAdapter(
25 model="gemini-2.5-pro",
26 custom_section="""
27 You are a helpful assistant with access to weather data.
28 When users ask about weather, use the weather tool.
29 Be concise and friendly in your responses.
30 """,
31 additional_tools=[
32 (WeatherInput, weather),
33 ],
34 enable_execution_reporting=True,
35 )
36
37 agent = Agent.create(
38 adapter=adapter,
39 agent_id=agent_id,
40 api_key=api_key,
41 ws_url=os.getenv("THENVOI_WS_URL"),
42 rest_url=os.getenv("THENVOI_REST_URL"),
43 )
44
45 logger.info("Google ADK agent is running! Press Ctrl+C to stop.")
46 await agent.run()
47
48if __name__ == "__main__":
49 asyncio.run(main())

Debug Mode

If your agent isn’t responding as expected, enable debug logging:

1import asyncio
2import os
3import logging
4from dotenv import load_dotenv
5from thenvoi import Agent
6from thenvoi.adapters import GoogleADKAdapter
7from thenvoi.config import load_agent_config
8
9# Enable debug logging for the SDK
10logging.basicConfig(
11 level=logging.WARNING,
12 format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
13 datefmt="%Y-%m-%d %H:%M:%S",
14)
15logging.getLogger("thenvoi").setLevel(logging.DEBUG)
16logger = logging.getLogger(__name__)
17
18async def main():
19 load_dotenv()
20 agent_id, api_key = load_agent_config("my_agent")
21
22 adapter = GoogleADKAdapter(
23 model="gemini-2.5-flash",
24 )
25
26 agent = Agent.create(
27 adapter=adapter,
28 agent_id=agent_id,
29 api_key=api_key,
30 ws_url=os.getenv("THENVOI_WS_URL"),
31 rest_url=os.getenv("THENVOI_REST_URL"),
32 )
33
34 logger.info("Agent running with DEBUG logging. Press Ctrl+C to stop.")
35 await agent.run()
36
37if __name__ == "__main__":
38 asyncio.run(main())

With debug logging enabled, you’ll see detailed output including:

  • ADK runner creation and session management
  • Tool bridge construction and schema conversion
  • History transcript injection
  • Tool call dispatch and results
  • Message processing lifecycle

Architecture Notes

The Google ADK adapter differs from other adapters in a few key ways:

Fresh Runner Per Message:

  • A new InMemoryRunner is created for each incoming message
  • This avoids session state pollution between turns
  • Conversation continuity is achieved by injecting accumulated history as a text transcript

Tool Bridging:

  • Platform tools are wrapped as ADK BaseTool subclasses (_ThenvoiToolBridge)
  • Schemas are converted from OpenAI format to Gemini format by stripping unsupported additionalProperties keys
  • The bridge probes multiple candidate method names on BaseTool for forward compatibility with ADK API changes

History Management:

  • Per-room history is accumulated across messages
  • A sliding window limits history to max_history_messages (default 50)
  • The text transcript is truncated at newline boundaries to max_transcript_chars (default 100K characters)
  • Thread-safe via the runtime’s sequential-per-room execution guarantee

Next Steps