The gemini-robotics-er-2-streaming-preview model endpoint exposes a dedicated
streaming endpoint that integrates with the Live
API, enabling real-time,
bidirectional interaction between your application and the robot. This makes it
suited for agents that need fast feedback loops and reactive responses to the
environment.
Use cases
- Multi-robot coordination: Multiple robots that communicate task state and delegate subtasks through a shared session.
- Continuous monitoring: Robots that observe a scene and trigger actions when specific events occur, such as a container reaching a fill level.
- Warehouse and logistics: Pick-and-pack agents that verify items visually, track packing progress, and recover from errors.
Technical specifications
The following table outlines the technical specifications for the Live API:
| Category | Details |
|---|---|
| Input modalities | Audio (raw 16-bit PCM audio, 16kHz, little-endian), images (JPEG <= 1FPS), text |
| Output modalities | Text |
| Protocol | Stateful WebSocket connection (WSS) |
Build an agentic setup
Every robotics agent built on the Live API follows three steps:
- Declare robot capabilities as tools. Each action the robot can perform —
navigate, grasp, speak — becomes a function declaration with a name,
description, and parameter schema. Physical actions must use
"behavior": "BLOCKING"so the model waits for the robot to finish before choosing the next step. - Stream multimodal input into a persistent session. Open a
live.connectsession and keep it open for the life of the task. Send video frames, audio, or text as they arrive from your robot's sensors. - Handle tool calls in a receive loop. Each time the model selects an
action, it sends a
tool_callmessage. Your receive loop executes the function against your robot SDK and sends back atool_response. The session stays open, and the model picks the next action based on the result.
The following sections show how to apply these steps to three common patterns: a baseline agent loop, proactive scene monitoring with a heartbeat, and routing speech through TTS as a tool.
Orchestrate a robot through function calling
The following example shows all three steps wired together in a single Python script.
Step 1 — tool definitions — declares robot capabilities as function
declarations. The navigate function uses "behavior": "BLOCKING" so the
model waits for the robot to reach the waypoint before calling another tool.
Add more function declarations in the same list to expose additional robot
capabilities.
Step 2 — input helpers — shows three functions that stream different modality
inputs into the session: send_text for commands, send_image for camera
frames with an optional text prompt, and send_audio for raw PCM audio from a
microphone.
Step 3 — the receive loop — runs concurrently and handles two kinds of messages:
server_content messages (the model's text output) and tool_call messages
(the model requesting a robot action). When a tool call arrives, the loop calls
execute_tool — a stub you replace with your real robot SDK — then sends back a
tool_response so the model can select the next action.
import asyncio
from google import genai
from google.genai import types
MODEL = "gemini-robotics-er-2-streaming-preview"
# ── Tool definitions ─────────────────────────────────────────────────────────
tools = [
{
"function_declarations": [
{
"name": "navigate",
"description": "Navigate the robot to a named waypoint.",
"behavior": "BLOCKING",
"parameters": {
"type": "OBJECT",
"properties": {"name": {"type": "STRING"}},
"required": ["name"],
},
},
# Add more function definitions here
]
}
]
# ── Stub tool executor (replace with real robot SDK calls) ───────────────────
def execute_tool(name: str, args: dict) -> dict:
print(f" [Tool] {name}({args})")
return {"status": "success"}
# ── Input helpers ────────────────────────────────────────────────────────────
def send_text(session, text: str):
"""Send a text turn."""
return session.send_client_content(
turns=types.Content(role="user", parts=[types.Part(text=text)]),
turn_complete=True,
)
def send_image(session, image_bytes: bytes, prompt: str = ""):
"""Send a JPEG image with an optional text prompt."""
parts = [
types.Part(
inline_data=types.Blob(data=image_bytes, mime_type="image/jpeg")
)
]
if prompt:
parts.append(types.Part(text=prompt))
return session.send_client_content(
turns=types.Content(role="user", parts=parts),
turn_complete=True,
)
def send_audio(session, audio_chunk: bytes):
"""Stream a chunk of raw PCM audio (16-bit, 16 kHz, mono)."""
return session.send_realtime_input(
media=types.Blob(data=audio_chunk, mime_type="audio/pcm;rate=16000")
)
# ── Receive loop ─────────────────────────────────────────────────────────────
async def receive_loop(session):
"""Print model text and handle tool calls until the session ends."""
async for message in session.receive():
if message.server_content:
sc = message.server_content
if sc.model_turn and sc.model_turn.parts:
for part in sc.model_turn.parts:
if part.text:
print(f"Model: