For clean Markdown of any page, append .md to the page URL. For a complete documentation index, see https://docs.telcoflow.com/integrations/llms.txt. For full documentation content, see https://docs.telcoflow.com/integrations/llms-full.txt.

# Google ADK (Agent Development Kit)

This guide shows how to integrate the Telcoflow SDK with the [Google Agent Development Kit (ADK)](https://github.com/google-gemini/google-adk) for complex AI agent behavior, including multi-agent orchestration, long-term memory, and structured tools.

## Overview

The integration bridges Telcoflow's bidirectional audio stream with ADK's `Runner` and `LiveRequestQueue`:

- **Caller audio -> ADK**: Incoming phone audio is sent to the `LiveRequestQueue` as real-time input
- **ADK audio -> Caller**: ADK events containing model audio are forwarded to the caller via `send_audio()`

## Full Example

```python
import asyncio
import os
from google.adk.agents import Agent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.adk.agents.live_request_queue import LiveRequestQueue
from google.adk.agents.run_config import RunConfig, StreamingMode
from google.genai import types
from telcoflow_sdk import TelcoflowClient, TelcoflowClientConfig, ActiveCall
import telcoflow_sdk.events as events

agent = Agent(
    name="telcoflow_agent",
    model="gemini-2.5-flash-native-audio-preview-12-2025",
    instruction="You are a helpful AI assistant talking over a phone call.",
)
session_service = InMemorySessionService()
runner = Runner(
    app_name="telcoflow_app", agent=agent, session_service=session_service
)

async def start_adk_session(call: ActiveCall):
    await call.answer()

    live_request_queue = LiveRequestQueue()

    async def stream_to_adk():
        async for audio_chunk in call.audio_stream():
            audio_blob = types.Blob(
                data=audio_chunk, mime_type="audio/pcm;rate=24000"
            )
            live_request_queue.send_realtime(audio_blob)

    async def receive_from_adk():
        run_config = RunConfig(
            streaming_mode=StreamingMode.BIDI,
            response_modalities=["AUDIO"],
        )
        async for event in runner.run_live(
            user_id="default_user",
            session_id=call.call_id,
            live_request_queue=live_request_queue,
            run_config=run_config,
        ):
            if event.interrupted:
                await call.clear_send_audio_buffer()

            if event.content and event.content.parts[0].inline_data:
                await call.send_audio(
                    event.content.parts[0].inline_data.data
                )

    await asyncio.gather(stream_to_adk(), receive_from_adk())

async def main():
    config = TelcoflowClientConfig.sandbox(
        api_key=os.getenv("WSS_API_KEY"),
        connector_uuid=os.getenv("WSS_CONNECTOR_UUID"),
        sample_rate=24000,
    )

    async with TelcoflowClient(config) as client:
        @client.on(events.INCOMING_CALL)
        async def handle_call(call: ActiveCall):
            await start_adk_session(call)

        await client.run_forever()

if __name__ == "__main__":
    asyncio.run(main())
```

## How It Works

### ADK Components

- **Agent** - Defines the AI model and system instruction
- **Runner** - Orchestrates agent execution and session management
- **InMemorySessionService** - Stores session state (swap for a persistent store in production)
- **LiveRequestQueue** - Accepts real-time audio input and feeds it to the runner

### Stream to ADK

The `stream_to_adk()` coroutine reads audio chunks from `call.audio_stream()`, wraps them as `types.Blob` objects, and sends them to the `LiveRequestQueue` using `send_realtime()`.

### Receive from ADK

The `receive_from_adk()` coroutine runs `runner.run_live()` with `StreamingMode.BIDI` and `response_modalities=["AUDIO"]`. For each event:

- **Interruption**: When `event.interrupted` is `True`, `clear_send_audio_buffer()` is called to stop queued audio
- **Model audio**: When `event.content` contains `inline_data`, the raw audio is forwarded to the caller

### Session Management

Each call gets its own session, keyed by `call.call_id`. This allows ADK to maintain conversation context within a single call. For cross-call memory, use a persistent session service.

## When to Use ADK vs. GenAI SDK

| Capability | GenAI SDK | ADK |
|---|---|---|
| Simple voice AI | Yes | Yes |
| Multi-agent orchestration | No | Yes |
| Structured tool calling | Limited | Yes |
| Session/memory management | Manual | Built-in |
| Complex agent workflows | No | Yes |

Use the [GenAI SDK integration](/integrations/google-gen-ai-sdk-gemini-live) for straightforward voice AI. Use ADK when you need structured agents, tools, or multi-agent coordination.

## Environment Variables

| Variable | Description |
|---|---|
| `GOOGLE_API_KEY` | Google API key with Gemini API access |
| `WSS_API_KEY` | Telcoflow API key |
| `WSS_CONNECTOR_UUID` | Telcoflow connector UUID |

## Next Steps

- [Google GenAI Integration](/integrations/google-gen-ai-sdk-gemini-live) - Simpler integration for basic voice AI
- [Audio Streaming](/concepts/audio-streaming) - Buffer management and interruption handling
- [Use Cases](/use-cases/human-escalation) - Combine ADK with escalation patterns