Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
976 changes: 0 additions & 976 deletions docs/streaming/custom-streaming-ws.md

This file was deleted.

735 changes: 0 additions & 735 deletions docs/streaming/custom-streaming.md

This file was deleted.

55 changes: 23 additions & 32 deletions docs/streaming/dev-guide/part1.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions docs/streaming/dev-guide/part2.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Understanding `LiveRequestQueue` is essential for building responsive streaming

The `LiveRequestQueue` is your primary interface for sending messages to the Agent in streaming conversations. Rather than managing separate channels for text, audio, and control signals, ADK provides a unified `LiveRequest` container that handles all message types through a single, elegant API:

```python title='Source reference: <a href="https://github.com/google/adk-python/blob/0b1784e0/src/google/adk/agents/live_request_queue.py" target="_blank">live_request_queue.py</a>'
```python title='Source reference: <a href="https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/agents/live_request_queue.py" target="_blank">live_request_queue.py</a>'
class LiveRequest(BaseModel):
content: Optional[Content] = None # Text-based content and structured data
blob: Optional[Blob] = None # Audio/video data and binary streams
Expand Down Expand Up @@ -73,7 +73,7 @@ graph LR

The `send_content()` method sends text messages in turn-by-turn mode, where each message represents a discrete conversation turn. This signals a complete turn to the model, triggering immediate response generation.

```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/main.py#L157-L158" target="_blank">main.py:157-158</a>'
```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/main.py#L166-L171" target="_blank">main.py:166-171</a>'
content = types.Content(parts=[types.Part(text=json_message["text"])])
live_request_queue.send_content(content)
```
Expand Down Expand Up @@ -103,7 +103,7 @@ For Live API, multimodal inputs (audio/video) use different mechanisms (see `sen

The `send_realtime()` method sends binary data streams—primarily audio, image and video—flow through the `Blob` type, which handles transmission in realtime mode. Unlike text content that gets processed in turn-by-turn mode, blobs are designed for continuous streaming scenarios where data arrives in chunks. You provide raw bytes, and Pydantic automatically handles base64 encoding during JSON serialization for safe network transmission (configured in `LiveRequest.model_config`). The MIME type helps the model understand the content format.

```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/main.py#L141-L145" target="_blank">main.py:141-145</a>'
```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/main.py#L153-L156" target="_blank">main.py:153-156</a>'
audio_blob = types.Blob(
mime_type="audio/pcm;rate=16000",
data=audio_data
Expand Down Expand Up @@ -159,11 +159,11 @@ The `close` signal provides graceful termination semantics for streaming session

**Manual closure in BIDI mode:** When using `StreamingMode.BIDI` (Bidi-streaming), your application should manually call `close()` when the session terminates or when errors occur. This practice minimizes session resource usage.

**Automatic closure in SSE mode:** When using the legacy `StreamingMode.SSE` (not Bidi-streaming), ADK automatically calls `close()` on the queue when it receives a `turn_complete=True` event from the model (see `base_llm_flow.py:754`).
**Automatic closure in SSE mode:** When using the legacy `StreamingMode.SSE` (not Bidi-streaming), ADK automatically calls `close()` on the queue when it receives a `turn_complete=True` event from the model (see [`base_llm_flow.py:781`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/flows/llm_flows/base_llm_flow.py#L781)).

See [Part 4: Understanding RunConfig](part4.md#streamingmode-bidi-or-sse) for detailed comparison and when to use each mode.

```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/main.py#L195-L213" target="_blank">main.py:195-213</a>'
```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/main.py#L210-L225" target="_blank">main.py:210-225</a>'
try:
logger.debug("Starting asyncio.gather for upstream and downstream tasks")
await asyncio.gather(
Expand Down Expand Up @@ -199,7 +199,7 @@ Understanding how `LiveRequestQueue` handles concurrency is essential for buildi

**Why synchronous send methods?** Convenience and simplicity. You can call them from anywhere in your async code without `await`:

```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/main.py#L129-L158" target="_blank">main.py:129-158</a>'
```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/main.py#L141-L171" target="_blank">main.py:141-171</a>'
async def upstream_task() -> None:
"""Receives messages from WebSocket and sends to LiveRequestQueue."""
while True:
Expand Down
38 changes: 20 additions & 18 deletions docs/streaming/dev-guide/part3.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The `run_live()` method is ADK's primary entry point for streaming conversations
You'll learn how to process different event types (text, audio, transcriptions, tool calls), manage conversation flow with interruption and turn completion signals, serialize events for network transport, and leverage ADK's automatic tool execution. Understanding event handling is essential for building responsive streaming applications that feel natural and real-time to users.

!!! note "Async Context Required"

All `run_live()` code requires async context. See [Part 1: FastAPI Application Example](part1.md#fastapi-application-example) for details and production examples.

## How run_live() Works
Expand All @@ -16,7 +16,7 @@ You'll learn how to process different event types (text, audio, transcriptions,

**Usage:**

```python title='Source reference: <a href="https://github.com/google/adk-python/blob/main/src/google/adk/runners.py" target="_blank">runners.py</a>'
```python title='Source reference: <a href="https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/runners.py" target="_blank">runners.py</a>'
# The method signature reveals the thoughtful design
async def run_live(
self,
Expand Down Expand Up @@ -56,7 +56,7 @@ end

The simplest way to consume events from `run_live()` is to iterate over the async generator with a for-loop:

```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/main.py#L182-L190" target="_blank">main.py:182-190</a>'
```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/main.py#L197-L205" target="_blank">main.py:197-205</a>'
async for event in runner.run_live(
user_id=user_id,
session_id=session_id,
Expand Down Expand Up @@ -98,7 +98,7 @@ The `run_live()` method yields a stream of `Event` objects in real-time as the a

!!! note "Source Reference"

See the complete event type handling implementation in [`runners.py:746-775`](https://github.com/google/adk-python/blob/main/src/google/adk/runners.py#L746-L775)
See the complete event type handling implementation in [`runners.py`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/runners.py)

#### When run_live() Exits

Expand Down Expand Up @@ -127,7 +127,7 @@ Not all events yielded by `run_live()` are persisted to the ADK `Session`. When

!!! note "Source Reference"

See session event persistence logic in [`runners.py:746-775`](https://github.com/google/adk-python/blob/main/src/google/adk/runners.py#L746-L775)
See session event persistence logic in [`runners.py`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/runners.py)

**Events Saved to the ADK `Session`:**

Expand Down Expand Up @@ -160,7 +160,7 @@ ADK's `Event` class is a Pydantic model that represents all communication in a s

!!! note "Source Reference"

See Event class implementation in [`event.py:30-129`](https://github.com/google/adk-python/blob/main/src/google/adk/events/event.py#L30-L129) and [`llm_response.py:28-185`](https://github.com/google/adk-python/blob/main/src/google/adk/models/llm_response.py#L28-L185)
See Event class implementation in [`event.py:30-128`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/events/event.py#L30-L128) and [`llm_response.py:28-193`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/models/llm_response.py#L28-L193)

#### Key Fields

Expand Down Expand Up @@ -241,7 +241,7 @@ This transformation ensures that transcribed user input is correctly attributed

!!! note "Source Reference"

See author attribution logic in [`base_llm_flow.py:281-294`](https://github.com/google/adk-python/blob/main/src/google/adk/flows/llm_flows/base_llm_flow.py#L281-L294)
See author attribution logic in [`base_llm_flow.py:292-326`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/flows/llm_flows/base_llm_flow.py#L292-L326)

### Event Types and Handling

Expand Down Expand Up @@ -338,7 +338,7 @@ When audio data is aggregated and saved as files in artifacts, ADK yields events

!!! note "Source Reference"

See audio file aggregation logic in [`runners.py:752-754`](https://github.com/google/adk-python/blob/main/src/google/adk/runners.py#L752-L754) and [`audio_cache_manager.py:192-194`](https://github.com/google/adk-python/blob/main/src/google/adk/flows/llm_flows/audio_cache_manager.py#L192-L194)
See audio file aggregation logic in [`audio_cache_manager.py:157-177`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/flows/llm_flows/audio_cache_manager.py#L157-L177)

**Receiving Audio File References:**

Expand Down Expand Up @@ -377,7 +377,7 @@ Usage metadata events contain token usage information for monitoring costs and q

!!! note "Source Reference"

See usage metadata structure in [`llm_response.py:105-106`](https://github.com/google/adk-python/blob/main/src/google/adk/models/llm_response.py#L105-L106)
See usage metadata structure in [`llm_response.py:105`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/models/llm_response.py#L105)

**Accessing Token Usage:**

Expand Down Expand Up @@ -644,7 +644,7 @@ For complete error code listings and descriptions, refer to the official documen

- **FinishReason** (when model stops generating tokens): [Google AI for Developers](https://ai.google.dev/api/python/google/ai/generativelanguage/Candidate/FinishReason) | [Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/gemini)
- **BlockedReason** (when prompts are blocked by content filters): [Google AI for Developers](https://ai.google.dev/api/python/google/ai/generativelanguage/GenerateContentResponse/PromptFeedback/BlockReason) | [Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/configure-safety-attributes)
- **ADK Implementation**: [`llm_response.py:160-184`](https://github.com/google/adk-python/blob/main/src/google/adk/models/llm_response.py#L160-L184)
- **ADK Implementation**: [`llm_response.py:156-193`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/models/llm_response.py#L156-L193)

**Best practices for error handling:**

Expand Down Expand Up @@ -831,7 +831,7 @@ This provides a simple one-liner to convert ADK events into JSON format that can

The `model_dump_json()` method serializes an `Event` object to a JSON string:

```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/main.py#L178-L191" target="_blank">main.py:178-191</a>'
```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/main.py#L191-L206" target="_blank">main.py:191-206</a>'
async def downstream_task() -> None:
"""Receives Events from run_live() and sends to WebSocket."""
async for event in runner.run_live(
Expand Down Expand Up @@ -905,7 +905,7 @@ This shows how to parse and handle serialized events on the client side, enablin

On the client side (JavaScript/TypeScript), parse the JSON back to objects:

```javascript title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/static/js/app.js#L297-L576" target="_blank">app.js:297-576</a>'
```javascript title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/static/js/app.js#L297-L576" target="_blank">app.js:297-576</a>'
// Handle incoming messages
websocket.onmessage = function (event) {
// Parse the incoming ADK Event
Expand Down Expand Up @@ -979,7 +979,9 @@ websocket.onmessage = function (event) {
};
```

> 📖 **Demo Implementation**: See the complete WebSocket message handler in [`app.js:297-576`](https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/static/js/app.js#L297-L576)
!!! note "Demo Implementation"

See the complete WebSocket message handler in [`app.js:297-576`](https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/static/js/app.js#L297-L576)

### Optimization for Audio Transmission

Expand Down Expand Up @@ -1019,7 +1021,7 @@ This approach reduces bandwidth by ~75% for audio-heavy streams while maintainin

!!! note "Source Reference"

See automatic tool execution implementation in [`functions.py`](https://github.com/google/adk-python/blob/main/src/google/adk/flows/llm_flows/functions.py)
See automatic tool execution implementation in [`functions.py`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/flows/llm_flows/functions.py)

One of the most powerful features of ADK's `run_live()` is **automatic tool execution**. Unlike the raw Gemini Live API, which requires you to manually handle tool calls and responses, ADK abstracts this complexity entirely.

Expand All @@ -1038,7 +1040,7 @@ This creates significant implementation overhead, especially in streaming contex

With ADK, tool execution becomes declarative. Simply define tools on your Agent:

```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/google_search_agent/agent.py#L11-L16" target="_blank">agent.py:11-16</a>'
```python title='Demo implementation: <a href="https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/google_search_agent/agent.py#L11-L16" target="_blank">agent.py:11-16</a>'
import os
from google.adk.agents import Agent
from google.adk.tools import google_search
Expand Down Expand Up @@ -1081,7 +1083,7 @@ You don't need to handle the execution yourself—ADK does it automatically. You

!!! note "Learn More"

The bidi-demo sends all events (including function calls and responses) directly to the WebSocket client without server-side filtering. This allows the client to observe tool execution in real-time through the event stream. See the downstream task in [`main.py:178-191`](https://github.com/google/adk-samples/blob/main/python/agents/bidi-demo/app/main.py#L178-L191)
The bidi-demo sends all events (including function calls and responses) directly to the WebSocket client without server-side filtering. This allows the client to observe tool execution in real-time through the event stream. See the downstream task in [`main.py:191-206`](https://github.com/google/adk-samples/blob/4274c70ae3f4c68595f543ee504474747ea9f0da/python/agents/bidi-demo/app/main.py#L191-L206)

### Long-Running and Streaming Tools

Expand Down Expand Up @@ -1135,7 +1137,7 @@ This automatic handling is one of the core value propositions of ADK—it transf

!!! note "Source Reference"

See InvocationContext implementation in [`invocation_context.py`](https://github.com/google/adk-python/blob/main/src/google/adk/agents/invocation_context.py)
See InvocationContext implementation in [`invocation_context.py`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/agents/invocation_context.py)

While `run_live()` returns an AsyncGenerator for consuming events, internally it creates and manages an `InvocationContext`—ADK's unified state carrier that encapsulates everything needed for a complete conversation invocation. **One InvocationContext corresponds to one `run_live()` loop**—it's created when you call `run_live()` and persists for the entire streaming session.

Expand Down Expand Up @@ -1247,7 +1249,7 @@ When building multi-agent systems with ADK, understanding how agents transition

!!! note "Source Reference"

See SequentialAgent implementation in [`sequential_agent.py:119-159`](https://github.com/google/adk-python/blob/main/src/google/adk/agents/sequential_agent.py#L119-L159)
See SequentialAgent implementation in [`sequential_agent.py:119-158`](https://github.com/google/adk-python/blob/960b206752918d13f127a9d6ed8d21d34bcbc7fa/src/google/adk/agents/sequential_agent.py#L119-L158)

**How it works:**

Expand Down
Loading
Loading