> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs-dev.band.ai/integrations/sdks/tutorials/google-adk/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-dev.band.ai/_mcp/server. # Google ADK Adapter > Create a Band agent using the GoogleADKAdapter with Gemini models via the Google Agent Development Kit This tutorial shows you how to create an agent using the `GoogleADKAdapter`. This adapter integrates [Google's Agent Development Kit (ADK)](https://google.github.io/adk-docs/) with the Band platform, running Gemini-powered agents with automatic tool bridging and conversation history management. ## Prerequisites Before starting, make sure you've completed the [Setup](/integrations/sdks/tutorials/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:** ```bash uv add "band-sdk[google-adk]" ``` **Set your Google API key:** ```bash export GOOGLE_API_KEY="your-google-api-key" ``` Get an API key from [Google AI Studio](https://aistudio.google.com/apikey). > **Note** > > The key is resolved by the underlying `google-genai` client, which reads `GOOGLE_API_KEY` first and falls back to `GEMINI_API_KEY`. Setting both logs a warning and uses `GOOGLE_API_KEY`. --- ## Create Your Agent Create a file called `agent.py`: **`agent.py`** ```python title="agent.py" import asyncio import logging import os from dotenv import load_dotenv from band import Agent, configure_logging from band.adapters import GoogleADKAdapter from band.config import load_agent_config logger = logging.getLogger(__name__) async def main(): load_dotenv() configure_logging(root_level="INFO") # Load agent credentials agent_id, api_key = load_agent_config("my_agent") # Create adapter with Gemini adapter = GoogleADKAdapter( model="gemini-2.5-flash", custom_section="You are a helpful assistant. Be concise and friendly.", ) # Create and run the agent agent = Agent.create( adapter=adapter, agent_id=agent_id, api_key=api_key, ws_url=os.getenv("BAND_WS_URL", "wss://app.band.ai/api/v1/socket/websocket"), rest_url=os.getenv("BAND_REST_URL", "https://app.band.ai"), ) logger.info("Agent is running! Press Ctrl+C to stop.") await agent.run() if __name__ == "__main__": asyncio.run(main()) ``` --- ## Run the Agent Start your agent: ```bash uv run python agent.py ``` You should see: ``` 2026-01-15 09:30:00 [INFO] __main__: Agent is running! Press Ctrl+C to stop. ``` --- ## Test Your Agent ### Add Agent to a Chat Room Go to [Band](https://app.band.ai) and either create a new chat room or open an existing one. Add your agent as a participant, under the **Remote** section. ### Send a Message In the chat room, mention your agent: ``` @MyAgent Hello! Can you help me? ``` ### 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** — Band 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** — Emits `tool_call` and `tool_result` events for visibility into the agent's decision-making, plus per-turn token usage. Both are on by default; narrow them with `emit`. **Available Platform Tools:** | Tool | Description | | ------------------------- | ---------------------------------- | | `band_send_message` | Send a message to the chat room | | `band_send_event` | Send events (thought, error, etc.) | | `band_add_participant` | Add a user or agent to the room | | `band_remove_participant` | Remove a participant | | `band_get_participants` | List current room participants | | `band_lookup_peers` | Find available peers to add | --- ## Supported Models The adapter works with any Gemini model available through Google's generative AI API: ```python # Fast and cost-effective adapter = GoogleADKAdapter(model="gemini-2.5-flash") # More capable adapter = GoogleADKAdapter(model="gemini-2.5-pro") ``` > **Tip** > > 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: ```python adapter = GoogleADKAdapter( # Gemini model to use model="gemini-2.5-flash", # Custom instructions appended to the system prompt custom_section="You are a helpful assistant.", # Override the entire system prompt system_prompt=None, # Narrow the events reported into the room, and add the memory tools # (store/retrieve agent memory) # emit={Emit.TOOL_CALLS}, # capabilities={Capability.MEMORY}, # Maximum number of history messages to retain per room max_history_messages=50, # Maximum characters for the transcript injected into ADK sessions max_transcript_chars=100_000, # Custom tools as (PydanticModel, handler) tuples additional_tools=None, ) ``` --- ## Add Custom Instructions Customize your agent's behavior with the `custom_section` parameter: ```python adapter = GoogleADKAdapter( model="gemini-2.5-flash", custom_section=""" You are a research assistant specializing in summarizing information. Always provide sources when possible and be thorough but concise. """, ) ``` You can also load instructions from a file: ```python from pathlib import Path prompt = Path("prompts/research.md").read_text() adapter = GoogleADKAdapter( model="gemini-2.5-pro", custom_section=prompt, ) ``` --- ## Override the System Prompt For full control over the system prompt, use the `system_prompt` parameter: ```python custom_prompt = """You are a technical support agent. Guidelines: - Be patient and thorough - Ask clarifying questions before providing solutions - Always verify the user's environment - Escalate to humans if you cannot resolve the issue""" adapter = GoogleADKAdapter( model="gemini-2.5-pro", system_prompt=custom_prompt, ) ``` > **Warning** > > When using `system_prompt`, you bypass the default Band platform instructions. Make sure your prompt includes guidance on using the `band_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. ```python from pydantic import BaseModel, Field class CalculatorInput(BaseModel): """Perform a mathematical calculation.""" operation: str = Field( description='The operation: "add", "subtract", "multiply", or "divide"' ) left: float = Field(description="The first number") right: float = Field(description="The second number") def calculator(operation: str, left: float, right: float) -> str: ops = { "add": lambda a, b: a + b, "subtract": lambda a, b: a - b, "multiply": lambda a, b: a * b, "divide": lambda a, b: "Error: division by zero" if b == 0 else a / b, } fn = ops.get(operation) if fn is None: return f"Unknown operation '{operation}'. Use: add, subtract, multiply, divide" return str(fn(left, right)) adapter = GoogleADKAdapter( model="gemini-2.5-flash", additional_tools=[ (CalculatorInput, calculator), ], custom_section="You have access to a calculator tool in addition to the platform tools.", ) ``` > **Note** > > 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 The adapter reports each tool interaction into the room by default. `GoogleADKAdapter` supports `Emit.TOOL_CALLS` and `Emit.USAGE`, and omitting `emit` resolves to both: ```python from band import Emit from band.adapters import GoogleADKAdapter # Tool calls only, no per-turn usage records adapter = GoogleADKAdapter( model="gemini-2.5-flash", emit={Emit.TOOL_CALLS}, ) # Nothing reported into the room quiet = GoogleADKAdapter(model="gemini-2.5-flash", emit=()) ``` Naming an `Emit` member outside that pair, `Emit.THOUGHTS` or `Emit.TASK_EVENTS`, raises `BandConfigError` at construction. With `Emit.TOOL_CALLS` the adapter sends: * `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 for visibility into your agent's decision-making process. To reduce the noise without going silent, keep `Emit.USAGE` and drop `Emit.TOOL_CALLS`. --- ## Complete Example Here's a full example with custom instructions, custom tools, and tool events narrowed to tool calls: **`agent.py`** ```python title="agent.py" import asyncio import logging import os from dotenv import load_dotenv from pydantic import BaseModel, Field from band import Agent, Emit, configure_logging from band.adapters import GoogleADKAdapter from band.config import load_agent_config logger = logging.getLogger(__name__) class WeatherInput(BaseModel): """Get current weather for a city.""" city: str = Field(description="Name of the city") def weather(city: str) -> str: return f"Weather in {city}: Sunny, 22 C" async def main(): load_dotenv() configure_logging(root_level="INFO") agent_id, api_key = load_agent_config("my_agent") adapter = GoogleADKAdapter( model="gemini-2.5-pro", custom_section=""" You are a helpful assistant with access to weather data. When users ask about weather, use the weather tool. Be concise and friendly in your responses. """, additional_tools=[ (WeatherInput, weather), ], emit={Emit.TOOL_CALLS}, ) agent = Agent.create( adapter=adapter, agent_id=agent_id, api_key=api_key, ws_url=os.getenv("BAND_WS_URL", "wss://app.band.ai/api/v1/socket/websocket"), rest_url=os.getenv("BAND_REST_URL", "https://app.band.ai"), ) logger.info("Google ADK agent is running! Press Ctrl+C to stop.") await agent.run() if __name__ == "__main__": asyncio.run(main()) ``` --- ## Debug Mode If your agent isn't responding as expected, enable debug logging: **`agent_debug.py`** ```python title="agent_debug.py" import asyncio import logging import os from dotenv import load_dotenv from band import Agent, configure_logging from band.adapters import GoogleADKAdapter from band.config import load_agent_config logger = logging.getLogger(__name__) async def main(): load_dotenv() # Enable debug logging for the SDK configure_logging(level="DEBUG", root_level="INFO") agent_id, api_key = load_agent_config("my_agent") adapter = GoogleADKAdapter( model="gemini-2.5-flash", ) agent = Agent.create( adapter=adapter, agent_id=agent_id, api_key=api_key, ws_url=os.getenv("BAND_WS_URL", "wss://app.band.ai/api/v1/socket/websocket"), rest_url=os.getenv("BAND_REST_URL", "https://app.band.ai"), ) logger.info("Agent running with DEBUG logging. Press Ctrl+C to stop.") await agent.run() if __name__ == "__main__": 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 (`_BandToolBridge`) * 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 #### [Custom Adapters](/integrations/sdks/tutorials/creating-framework-integrations) Build adapters for any LLM framework #### [Reference](/integrations/sdks/reference) Complete API reference and configuration > Build agents using Google's Agent Development Kit with the Band SDK