1. Introducción
Crea experiencias de IA basadas en agentes interactivas y fluidas con las que tus clientes puedan interactuar directamente desde la aplicación de mensajería que ya usaron. Descubre cómo desarrollar e implementar aplicaciones inteligentes que se ejecuten sin problemas en interfaces web y canales de mensajería modernos.
Qué compilarás
Integración entre un "conserje de restaurante" completo, una aplicación basada en ADK potenciada por Gemini que ayuda a los comensales a explorar el menú de un restaurante y reservar mesas, y la app de chat de Telegram. Puedes interactuar con el bot de Telegram y solicitar descripciones en lenguaje natural, como "Quiero algo picante y vegetariano". Luego, el bot se conectará al agente de ADK, que leerá y escribirá en una base de datos de Cloud SQL PostgreSQL por completo a través de MCP Toolbox para bases de datos, que controla todo el acceso a la base de datos, incluida la generación automática de embeddings para la búsqueda de vectores. Mientras tanto, el usuario podrá ver que el bot reconoce el mensaje y escribe ... typing para responder mientras espera la respuesta del agente de ADK.

Qué aprenderás
- Implementa un "conserje de restaurante" funcional, una aplicación basada en ADK potenciada por Gemini.
- Configura el bot de chat de Telegram con BotFather.
- Escribe aplicaciones de Python para escuchar el webhook del bot.
- Envía una acción de chat para proporcionar la notificación
... typingen Telegram en el mensaje del usuario y realiza un sondeo para enviar... typingde forma periódica mientras esperas la respuesta real. - Llama al extremo de Cloud Run de
Restaurant Conciergepara procesar la consulta del usuario. - Controla la respuesta del agente de ADK, envía un mensaje a Telegram y cierra el búfer.
- Implementa la aplicación de Python en Cloud Run.
- Interactúa con tu bot de Telegram.
Requisitos previos
- Una cuenta de Google Cloud con una cuenta de facturación de prueba
- Conocimientos básicos sobre Python
- Será útil tener experiencia previa con la implementación de ADK y Cloud Run.
- Cuenta de Telegram
- (Recomendado) Haber completado los siguientes codelabs :
- RAG agente con ADK, MCP Toolbox y Cloud SQL: Puedes seguir compilando tu agente desde este codelab. El código de partida proporcionado es idéntico.
- (O) Agentes a gran escala: Arquitectura multiagente con protocolo A2A en Agent Runtime y la integración de ADK: Si deseas enriquecer aún más el agente con la arquitectura multiagente
2. Configuración del entorno: Continuación del codelab anterior
Las narrativas que proporcionamos en este codelab son, en realidad, la continuación de este codelab de requisitos previos: RAG agente con ADK, MCP Toolbox y Cloud SQL o Agentes a gran escala: Arquitectura multiagente con protocolo A2A en Agent Runtime y la integración de ADK. Puedes continuar tu trabajo desde el codelab anterior.
Podemos comenzar a compilar en el directorio de trabajo del codelab anterior ( el directorio de trabajo debe ser build-agent-adk-toolbox-cloudsql o adk-a2a-agent-runtime-starter). Para evitar confusiones, cambiemos el nombre del directorio por el mismo nombre de directorio que usamos cuando comenzamos de cero.
Si continúas desde el lab RAG agente con ADK, MCP Toolbox y Cloud SQL :
mv ~/build-agent-adk-toolbox-cloudsql ~/build-agent-adk-telegram
De lo contrario, si continúas desde el lab Agentes a gran escala: Arquitectura multiagente con protocolo A2A en Agent Runtime y la integración de ADK
mv ~/adk-a2a-agent-runtime-starter ~/build-agent-adk-telegram
Luego, cambia nuestro directorio de trabajo a él.
cloudshell workspace ~/build-agent-adk-telegram && cd ~/build-agent-adk-telegram
source .env
Después de eso, verifica que tu restaurant-agent ya esté implementado y tenga una URL pública a la que se pueda acceder.
AGENT_URL=$(gcloud run services describe restaurant-agent \
--region="$REGION" \
--format='value(status.url)')
echo " ✓ Agent service deployed"
echo " Agent URL: $AGENT_URL"
echo ""
Si puedes acceder a la URL, puedes continuar con la siguiente sección: Create Telegram Bot.
3. Configuración del entorno: Comienza de cero con el repositorio de partida
En este paso, se prepara tu entorno de Cloud Shell, se configura tu proyecto de Google Cloud y se clona el repositorio de partida.
Abre Cloud Shell
Abre Cloud Shell en tu navegador. Cloud Shell proporciona un entorno preconfigurado con todas las herramientas que necesitas para este codelab. Haz clic en Autorizar cuando se te solicite.
Luego, haz clic en "Ver" -> "Terminal" para abrir la terminal. Tu interfaz debería verse similar a esta.

Esta será nuestra interfaz principal, IDE en la parte superior y terminal en la parte inferior.
Configura el directorio de trabajo
Clona el repositorio de partida. Todo el código que escribas en este codelab se encuentra aquí:
rm -rf ~/build-agent-adk-telegram
git clone https://github.com/alphinside/adk-a2a-agent-runtime-starter.git build-agent-adk-telegram
cloudshell workspace ~/build-agent-adk-telegram && cd ~/build-agent-adk-telegram
Crea el archivo .env a partir de la plantilla proporcionada:
cp .env.example .env
Para simplificar la configuración del proyecto en tu terminal, descarga esta secuencia de comandos de configuración del proyecto en tu directorio de trabajo:
curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh
Ejecuta la secuencia de comandos. Verifica tu cuenta de facturación de prueba, crea un proyecto nuevo (o valida uno existente), guarda el ID del proyecto en un archivo .env en el directorio actual y establece el proyecto activo en gcloud.
bash setup_verify_trial_project.sh && source .env
La secuencia de comandos hará lo siguiente:
- Verifica que tengas una cuenta de facturación de prueba activa.
- Busca un proyecto existente en
.env(si existe). - Crea un proyecto nuevo o vuelve a usar el existente.
- Vincula la cuenta de facturación de prueba a tu proyecto.
- Guarda el ID del proyecto en
.env. - Establece el proyecto como el proyecto
gcloudactivo.
Para verificar que el proyecto esté configurado correctamente, revisa el texto amarillo junto a tu directorio de trabajo en el mensaje de la terminal de Cloud Shell. Debería mostrar el ID de tu proyecto.

Configuración de la infraestructura de partida
Primero, deberemos instalar las dependencias de Python con uv. Es un administrador de proyectos y paquetes de Python rápido escrito en Rust ( documentación de uv). Este codelab lo usa por su velocidad y simplicidad para mantener el proyecto de Python.
uv sync
Luego, ejecuta la secuencia de comandos de configuración completa, que crea la instancia de Cloud SQL, inicializa los datos y, luego, implementa el servicio de Toolbox que actuará como el estado inicial de nuestro agente de restaurante.
bash scripts/full_setup.sh > logs/full_setup.log 2>&1 &
Este comando realizará las siguientes acciones:
- Crea una instancia de Cloud SQL y propaga la base de datos (fase 1).
- Genera la configuración del entorno del agente y, luego, inicia el servicio de Toolbox local (fase 2).
- Implementa los servicios de Toolbox y Agent en Cloud Run (fase 3).
Una vez que finalice esta implementación, podrás acceder a la IU de desarrollo de ADK en la URL de Cloud Run.
source .env
AGENT_URL=$(gcloud run services describe restaurant-agent \
--region="$REGION" \
--format='value(status.url)')
echo " ✓ Agent service deployed"
echo " Agent URL: $AGENT_URL"
echo ""
Abre la IU de desarrollo de ADK, selecciona restaurant_agent y prueba con consultas como el siguiente ejemplo:
What Italian dishes do you have?
O
I want something spicy and creamy
Ahora, la siguiente acción es cómo podemos pasar de solo la interfaz de desarrollo web al canal de mensajería de Telegram.
4. Crea un bot de Telegram
Telegram es una plataforma de mensajería gratuita muy conocida que se usa ampliamente para la participación basada en la comunidad. Una de las razones es que ofrece muchas formas de integrarse con facilidad, por lo que las personas pueden crear fácilmente su propio bot con una gran variedad de funciones diferentes.
En nuestro caso, usaremos BotFather para crear nuestro propio bot por primera vez. Ten en cuenta que, aunque usamos Telegram para esta sesión, se puede usar el mismo método para WhatsApp o cualquier otra plataforma de mensajería que elijas.
Usa BotFather para crear tu propio bot
Abre tu navegador web y visita https://telegram.me/BotFather para comenzar a crear tu propio bot de Telegram.

Comienza a interactuar con BotFather
Envía el comando /start
Para comenzar a usar BotFather y crear tu primer bot, debes invocar el mensaje /start a BotFather. Luego, se compartirán todos los comandos que tiene para que interactúes con él.
/start
Inicia la creación del bot con el comando /newbot
Creemos nuestro nuevo bot enviando el comando /newbot a BotFather. Se te pedirá que le pongas un nombre al bot y, luego, que le asignes un username, que siempre debe terminar en bot . Por ejemplo, TetrisBot o tetris_bot. Debe ser único.

Una vez que se cree el bot correctamente, recibirás el siguiente mensaje de BotFather.
Done! Congratulations on your new bot. You will find it at t.me/AdkTelegramTest_bot. You can now add a description, about section and profile picture for your bot, see /help for a list of commands. By the way, when you've finished creating your cool bot, ping our Bot Support if you want a better username for it. Just make sure the bot is fully operational before you do this. Use this token to access the HTTP API:
<YOUR_TELEGRAM_API_KEY>
Keep your token secure and store it safely, it can be used by anyone to control your bot. For a description of the Bot API, see this page: https://core.telegram.org/bots/api
Toma nota de YOUR_TELEGRAM_API_KEY. La usaremos en la siguiente sección.
5. Desarrolla la aplicación de webhook de Telegram
Preparemos el directorio de trabajo para comenzar a desarrollar tu aplicación de webhook de Telegram.
mkdir ~/build-agent-adk-telegram/telegram-integration
cd ~/build-agent-adk-telegram
Agrega las dependencias necesarias
Crea la secuencia de comandos requirements.txt con el siguiente contenido para proporcionar dependencias adecuadas para la secuencia de comandos del objeto de escucha de webhook de Telegram.
cloudshell edit ./telegram-integration/requirements.txt
Luego, agrega las siguientes dependencias.
python-telegram-bot[webhooks]
httpx
Crea una secuencia de comandos para el objeto de escucha de webhook de Telegram
Una vez que se instale la dependencia, podremos crear una secuencia de comandos de Python main.py para la aplicación de integración.
cloudshell edit ~/build-agent-adk-telegram/telegram-integration/main.py
Luego, copia el siguiente código en él.
# ./telegram-integration/main.py
import asyncio
import os
import sys
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackContext
from telegram.constants import ChatAction
import httpx
# Read token from environment variable
TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN")
ADK_SERVER_URL = os.environ.get("ADK_SERVER_URL", "http://localhost:8000")
ADK_APP_NAME = os.environ.get("ADK_APP_NAME", "restaurant_agent")
# Parse base URL out of ADK_SERVER_URL
BASE_URL = ADK_SERVER_URL.rstrip('/')
if BASE_URL.endswith('/run'):
BASE_URL = BASE_URL[:-4]
elif BASE_URL.endswith('/query'):
BASE_URL = BASE_URL[:-6]
if not TOKEN:
print("Error: TELEGRAM_BOT_TOKEN environment variable not set.")
print("Please set it before running the application.")
sys.exit(1)
async def start(update: Update, context: CallbackContext) -> None:
"""Send a message when the command /start is issued."""
await update.message.reply_text('Hi! I am your ADK Integration Bot. Send me a message and I will forward it to the ADK server.')
async def send_typing_loop(chat_id: int, bot, stop_event: asyncio.Event):
"""Send typing action periodically until the stop event is set."""
while not stop_event.is_set():
try:
await bot.send_chat_action(chat_id=chat_id, action=ChatAction.TYPING)
# The research suggested repeating every 4 seconds
await asyncio.sleep(4)
except Exception as e:
print(f"Error sending chat action: {e}")
await asyncio.sleep(1) # Wait a bit before retrying if error
async def handle_message(update: Update, context: CallbackContext) -> None:
"""Handle incoming user messages."""
user_message = update.message.text
chat_id = update.message.chat_id
raw_user_id = str(update.message.from_user.id)
# Derive unique user_id and session_id for this user
user_id = f"tg_{raw_user_id}"
session_id = f"tg_sess_{raw_user_id}"
print(f"Received message from {user_id}: {user_message}")
# Create a stop event for the typing loop
stop_event = asyncio.Event()
# Start the typing loop as a background task
typing_task = asyncio.create_task(send_typing_loop(chat_id, context.bot, stop_event))
try:
async with httpx.AsyncClient() as client:
# 1. Check if the session exists
session_url = f"{BASE_URL}/apps/{ADK_APP_NAME}/users/{user_id}/sessions/{session_id}"
session_check = await client.get(session_url, timeout=10.0)
if session_check.status_code == 404:
# 2. If session doesn't exist, create it
print(f"Session {session_id} not found. Creating session...")
session_create = await client.post(session_url, json={}, timeout=10.0)
if session_create.status_code != 200:
raise Exception(f"Failed to create session: {session_create.status_code} {session_create.text}")
elif session_check.status_code != 200:
raise Exception(f"Error checking session: {session_check.status_code} {session_check.text}")
# 3. Run the ADK agent
run_url = f"{BASE_URL}/run"
payload = {
"appName": ADK_APP_NAME,
"userId": user_id,
"sessionId": session_id,
"newMessage": {
"role": "user",
"parts": [{"text": user_message}]
}
}
response = await client.post(run_url, json=payload, timeout=60.0)
if response.status_code == 200:
events = response.json()
if isinstance(events, list) and len(events) > 0:
# The last event contains the final text response
last_event = events[-1]
content = last_event.get("content", {})
parts = content.get("parts", [])
if parts and "text" in parts[0]:
reply_text = parts[0]["text"]
else:
reply_text = "ADK agent returned an empty or non-text response."
else:
reply_text = "No events returned from ADK agent."
else:
reply_text = f"Error communicating with ADK server (Status: {response.status_code})."
except Exception as e:
reply_text = f"Failed to connect to ADK server: {e}"
finally:
# Stop the typing loop
stop_event.set()
await typing_task
# Send the final response back to the user
await update.message.reply_text(reply_text)
def main() -> None:
"""Start the bot."""
# Create the Application and pass it your bot's token.
application = Application.builder().token(TOKEN).build()
# on different commands - answer in Telegram
application.add_handler(CommandHandler("start", start))
# on non command i.e message - echo the message on Telegram
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
# Check if running in webhook mode (e.g., on Cloud Run)
port = os.environ.get("PORT")
service_url = os.environ.get("SERVICE_URL")
if port and service_url:
if not service_url.startswith("http"):
service_url = f"https://{service_url}"
print(f"Starting bot in WEBHOOK mode on port {port} with url {service_url}")
application.run_webhook(
listen="0.0.0.0",
port=int(port),
url_path=TOKEN,
webhook_url=f"{service_url}/{TOKEN}",
allowed_updates=Update.ALL_TYPES
)
else:
print("Starting bot in POLLING mode")
# Run the bot until the user presses Ctrl-C
application.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()
Comprende el código de integración del bot de Telegram

Cuando un usuario envía un mensaje, se ejecuta la siguiente canalización en handle_message().
Paso 1: Derivación de identidad y sesión
El bot asigna el ID de usuario de Telegram a identificadores de ADK únicos para mantener las sesiones de usuario distintas:
user_id = f"tg_{raw_user_id}"
session_id = f"tg_sess_{raw_user_id}"
Paso 2: Estado "Escribiendo" asíncrono (líneas 53 a 58)
Para garantizar una experiencia del usuario altamente responsiva mientras el agente de ADK procesa el mensaje (lo que puede tardar varios segundos), el bot inicia un bucle asíncrono en segundo plano:
- Se crea una instancia de
asyncio.Eventcomostop_event. asyncio.create_taskgenerasend_typing_loop(...)en segundo plano.- El bucle envía una acción
ChatAction.TYPINGa Telegram cada 4 segundos hasta que se establecestop_event.
Paso 3: Verificación y creación de la sesión de ADK (líneas 61 a 72)
Antes de ejecutar el agente, el bot verifica si ya existe una sesión:
- Envía una solicitud
GETa/apps/{appName}/users/{userId}/sessions/{sessionId}. - Si la respuesta es
404 Not Found, crea la sesión a través de una solicitudPOSTa la misma URL con un cuerpo JSON vacío. - Si se muestra un estado que no sea
200o404, se genera una excepción.
Paso 4: Envío de la solicitud al agente (líneas 74 a 85)
La carga útil del mensaje se reenvía al extremo /run de ADK:
- Extremo:
POST /run - El tiempo de espera de la solicitud se establece en
60.0segundos para permitir un razonamiento complejo o una latencia ascendente. - Estructura de carga útil:
{
"appName": "restaurant_agent",
"userId": "tg_<user_id>",
"sessionId": "tg_sess_<user_id>",
"newMessage": {
"role": "user",
"parts": [{"text": "<user_message>"}]
}
}
Paso 5: Análisis de la respuesta (líneas 87 a 101)
El servidor de ADK muestra una lista de eventos de mensajes. El bot inspecciona el array que se muestra:
- Recupera el evento final de la lista (
events[-1]). - Navega al contenido de texto a través de
event["content"]["parts"][0]["text"]. - Si no se muestran eventos o falta la estructura de texto, se establece un texto de marcador de posición descriptivo.
Paso 6: Desglose y envío de la respuesta (líneas 103 a 111)
- En el bloque
finally, se establecestop_event, lo que detiene el bucle de acción de escritura. - El bot espera a que se complete
typing_taskpara garantizar recursos limpios. - Por último, el bot responde al chat de Telegram con el texto de respuesta analizado.
6. Implementa la aplicación de webhook de Telegram en Cloud Run
A continuación, implementaremos el objeto de escucha de webhook de Telegram en Cloud Run para que nuestro bot pueda comunicarse con él.
Crea el Dockerfile
Primero, debemos crear el Dockerfile.
cloudshell edit ~/build-agent-adk-telegram/telegram-integration/Dockerfile
Luego, copia el siguiente código en él.
# Use an official Python runtime as a parent image
FROM python:3.11-slim
# Prevent Python from writing pyc files to disc and buffering stdout/stderr
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Set the working directory in the container
WORKDIR /app
# Install system dependencies if needed
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Copy the dependencies file to the working directory
COPY requirements.txt .
# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application code
COPY main.py .
# Expose the port that Cloud Run will provide via environment variable
EXPOSE 8080
# Run main.py when the container launches
CMD ["python", "main.py"]
El servicio se contiene en contenedores con python:3.11-slim para mantener pequeña la huella de la imagen:
- Instala dependencias de
requirements.txt(python-telegram-bot[webhooks]yhttpx). - Expone el puerto estándar
8080. - Inicia
python main.py.
Prepara las variables de entorno
Después de eso, volvamos a verificar si nuestro agente se implementó correctamente.
AGENT_URL=$(gcloud run services describe restaurant-agent \
--region="$REGION" \
--format='value(status.url)')
echo " ✓ Agent service deployed"
echo " Agent URL: $AGENT_URL"
echo ""
A continuación, coloquemos el TELEGRAM_BOT_TOKEN que obtuvimos anteriormente en el .env.
echo "TELEGRAM_BOT_TOKEN=YOUR_TELEGRAM_API_KEY" >> .env
Luego, propaguemos los datos .env con otros valores que necesitamos.
echo "ADK_SERVER_URL=$AGENT_URL" >> .env
echo "ADK_APP_NAME=restaurant_agent" >> .env
echo "SERVICE_NAME=telegram-integration" >> .env
source .env
Crea una secuencia de comandos de implementación
Creemos una secuencia de comandos de implementación que proporcione verificaciones completas y, luego, implemente la app en Cloud Run.
cloudshell edit ~/build-agent-adk-telegram/telegram-integration/deploy.sh
Copia el siguiente código en el archivo.
#!/usr/bin/env bash
# ./telegram-integration/deploy.sh
# Exit immediately if a command exits with a non-zero status
set -euo pipefail
# Color codes for neat terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0;37m' # No Color
# Load environment variables from .env if it exists
if [ -f .env ]; then
echo -e "${GREEN}✔ Loading environment variables from .env...${NC}"
export $(grep -v '^#' .env | xargs)
fi
echo -e "${BLUE}====================================================${NC}"
echo -e "${BLUE} Google Cloud Run Deployment: Telegram Bot ${NC}"
echo -e "${BLUE}====================================================${NC}"
# 1. Check for gcloud CLI
if ! command -v gcloud &> /dev/null; then
echo -e "${RED}Error: 'gcloud' CLI is not installed.${NC}"
echo "Please install the Google Cloud SDK and try again."
echo "See: https://cloud.google.com/sdk/docs/install"
exit 1
fi
# 2. Check active gcloud account/auth
ACTIVE_ACCOUNT=$(gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>/dev/null || true)
if [ -z "$ACTIVE_ACCOUNT" ]; then
echo -e "${RED}Error: No active Google Cloud account found.${NC}"
echo "Please run: gcloud auth login"
exit 1
fi
# 3. Detect / Prompt for GCP Project
DEFAULT_PROJECT=${GCP_PROJECT_ID:-$(gcloud config get-value project 2>/dev/null || true)}
if [ -n "${DEFAULT_PROJECT}" ]; then
echo -e "${GREEN}✔ Using GCP Project: $DEFAULT_PROJECT${NC}"
GCP_PROJECT="$DEFAULT_PROJECT"
else
echo -n "Enter GCP Project ID: "
read -r GCP_PROJECT
fi
if [ -z "$GCP_PROJECT" ]; then
echo -e "${RED}Error: GCP Project ID is required.${NC}"
exit 1
fi
# Set active project
gcloud config set project "$GCP_PROJECT" &> /dev/null
# 4. Configure Service Parameters
DEFAULT_SERVICE=${SERVICE_NAME:-"telegram-integration"}
if [ -n "${SERVICE_NAME:-}" ]; then
echo -e "${GREEN}✔ Using Cloud Run Service Name: $SERVICE_NAME${NC}"
else
echo -n "Enter Cloud Run Service Name [Default: $DEFAULT_SERVICE]: "
read -r SERVICE_NAME
SERVICE_NAME=${SERVICE_NAME:-$DEFAULT_SERVICE}
fi
DEFAULT_REGION=${REGION:-"us-central1"}
if [ -n "${REGION:-}" ]; then
echo -e "${GREEN}✔ Using Cloud Run Region: $REGION${NC}"
else
echo -n "Enter Cloud Run Region [Default: $DEFAULT_REGION]: "
read -r REGION
REGION=${REGION:-$DEFAULT_REGION}
fi
DEFAULT_ADK_APP=${ADK_APP_NAME:-"restaurant_agent"}
if [ -n "${ADK_APP_NAME:-}" ]; then
echo -e "${GREEN}✔ Using ADK App Name: $ADK_APP_NAME${NC}"
ADK_APP="$ADK_APP_NAME"
else
echo -n "Enter ADK App Name [Default: $DEFAULT_ADK_APP]: "
read -r ADK_APP
ADK_APP=${ADK_APP:-$DEFAULT_ADK_APP}
fi
# 5. Retrieve/Prompt for Telegram Bot Token
if [ -n "${TELEGRAM_BOT_TOKEN:-}" ]; then
echo -e "${GREEN}✔ Found TELEGRAM_BOT_TOKEN in environment.${NC}"
BOT_TOKEN="$TELEGRAM_BOT_TOKEN"
else
echo -e "${YELLOW}TELEGRAM_BOT_TOKEN is not set in your environment.${NC}"
echo -n "Enter your Telegram Bot Token (input will be hidden): "
read -s -r BOT_TOKEN
echo ""
fi
if [ -z "$BOT_TOKEN" ]; then
echo -e "${RED}Error: Telegram Bot Token is required.${NC}"
exit 1
fi
# 6. Retrieve/Prompt for ADK Server URL
DEFAULT_ADK_URL="http://localhost:8000"
if [ -n "${ADK_SERVER_URL:-}" ]; then
echo -e "${GREEN}✔ Found ADK_SERVER_URL in environment: $ADK_SERVER_URL${NC}"
ADK_URL="$ADK_SERVER_URL"
else
echo -n "Enter your ADK Server URL [Default: $DEFAULT_ADK_URL]: "
read -r ADK_URL
ADK_URL=${ADK_URL:-$DEFAULT_ADK_URL}
fi
# Enable required GCP services
echo -e "\n${YELLOW}Checking and enabling required GCP services...${NC}"
gcloud services enable run.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com --project "$GCP_PROJECT"
# Determine source directory dynamically
SOURCE_DIR="."
if [ -d "telegram-integration" ]; then
SOURCE_DIR="telegram-integration"
echo -e "${GREEN}✔ Found source directory: telegram-integration${NC}"
elif [ -f "Dockerfile" ]; then
SOURCE_DIR="."
echo -e "${GREEN}✔ Dockerfile found in current directory. Using current directory as source.${NC}"
else
echo -e "${RED}Error: Could not find source directory 'telegram-integration' or Dockerfile in current directory.${NC}"
exit 1
fi
# 7. First-pass Deployment with placeholder SERVICE_URL
# This boots the container in Webhook mode (so health check binds to port)
# but uses a high-reliability placeholder URL (google.com) to pass DNS verification checks.
echo -e "\n${YELLOW}Deploying to Cloud Run (Step 1/2: Initial Deploy)...${NC}"
gcloud run deploy "$SERVICE_NAME" \
--source "$SOURCE_DIR" \
--region "$REGION" \
--allow-unauthenticated \
--set-env-vars "TELEGRAM_BOT_TOKEN=$BOT_TOKEN,ADK_SERVER_URL=$ADK_URL,ADK_APP_NAME=$ADK_APP,SERVICE_URL=https://google.com" \
--project "$GCP_PROJECT"
# 8. Retrieve the actual service URL
echo -e "\n${YELLOW}Retrieving service URL...${NC}"
SERVICE_URL=$(gcloud run services describe "$SERVICE_NAME" --region "$REGION" --project "$GCP_PROJECT" --format 'value(status.url)')
echo -e "${GREEN}✔ Service URL is: $SERVICE_URL${NC}"
# 9. Update service environment variables with the real SERVICE_URL
# This triggers a rolling update and registers the correct webhook with Telegram automatically!
echo -e "\n${YELLOW}Updating configuration with final Webhook URL (Step 2/2)...${NC}"
gcloud run services update "$SERVICE_NAME" \
--region "$REGION" \
--set-env-vars "TELEGRAM_BOT_TOKEN=$BOT_TOKEN,ADK_SERVER_URL=$ADK_URL,ADK_APP_NAME=$ADK_APP,SERVICE_URL=$SERVICE_URL" \
--project "$GCP_PROJECT"
echo -e "\n${GREEN}====================================================${NC}"
echo -e "${GREEN} Deployment Completed Successfully! 🎉 ${NC}"
echo -e "${GREEN}====================================================${NC}"
echo -e "Service Name: ${BLUE}$SERVICE_NAME${NC}"
echo -e "Region: ${BLUE}$REGION${NC}"
echo -e "Active URL: ${BLUE}$SERVICE_URL${NC}"
echo -e "Webhook Path: ${BLUE}$SERVICE_URL/<bot-token>${NC}"
echo -e "ADK Backend: ${BLUE}$ADK_URL${NC}"
echo -e "ADK App Name: ${BLUE}$ADK_APP${NC}"
echo -e "${GREEN}====================================================${NC}"
echo "Your Telegram Bot has been configured to use webhooks."
echo "Any message sent to your bot will now trigger this Cloud Run instance."
Secuencia de comandos de doble implementación (deploy.sh)
Cuando se implementa en Google Cloud Run, el bot debe especificar su propia URL (SERVICE_URL) en su entorno para poder registrarla como el destino del webhook con Telegram. Para resolver esta dependencia circular (la URL es desconocida hasta la implementación, pero el servicio requiere la URL para iniciarse sin fallas en la verificación de estado), deploy.sh realiza una implementación de dos etapas:
- Paso 1: Implementación inicial: Inicia el contenedor con un DNS de marcador de posición (
https://google.com) para que el servicio se inicie correctamente, se vincule al puerto local y pase las verificaciones de estado iniciales de Cloud Run. - Paso 2: Recupera la URL: Extrae de forma programática el extremo de Cloud Run recién creado con
gcloud run services describe. - Paso 3: Actualiza la configuración: Actualiza las variables de entorno con la URL real del servicio en vivo. Esto activa una actualización progresiva limpia en Cloud Run y registra de forma segura el destino correcto del webhook con la API de Telegram.
Implementa en Cloud Run
La secuencia de comandos de implementación imprime la URL del agente. Ábrela en tu navegador para acceder a la misma IU de desarrollo de ADK que se ejecuta en Cloud Run.
cd ~/build-agent-adk-telegram
bash ./telegram-integration/deploy.sh
Si todo sale bien, este es el momento en el que puedes comenzar a chatear con tu bot directamente desde la aplicación de chat de Telegram. Busca el bot que acabas de crear y comienza a interactuar con él:
What Italian dishes do you have?
O
I want something spicy and creamy
Mira el bot que envía el estado "...is typing" y, luego, pronto, mostrará el mensaje del ADK que creaste antes.

7. ¡Felicitaciones!
Compilaste, implementaste y completaste la integración de nuestro agente de IA inteligente basado en ADK del asistente de menú de restaurante con Telegram, a través de la comunicación del servidor cliente HTTP, y permitiste que las personas consulten su menú favorito y reserven el restaurante.
Qué aprendiste
- Implementa y configura el Conserje de restaurante, el agente basado en ADK y MCP Toolbox en Cloud Run.
- Cómo configurar el bot de Telegram con BotFather
- Cómo escribir secuencias de comandos de Python para escuchar el webhook de Telegram e interactuar con el agente de ADK para transmitir la consulta y la respuesta de los usuarios en consecuencia
- Cómo implementar
"... typing"en Telegram para indicar que los mensajes se están procesando como comentarios en tiempo real para los usuarios mientras esperan que responda el agente de ADK - Cómo implementar la secuencia de comandos de Python en Cloud Run y poder interactuar con ella
Realiza una limpieza
Para evitar que se apliquen cargos a tu cuenta de Google Cloud, borra los recursos que creaste en este codelab.
Opción 1: Borra el proyecto (recomendado)
gcloud projects delete $GOOGLE_CLOUD_PROJECT
Opción 2: Borra los recursos individuales
# If you follow from previous A2A Agent Runtime codelab
# Delete the Agent Runtime deployment (skip if not found)
uv run python -c "
import vertexai
from google.genai import types
vertexai.init(project='$GOOGLE_CLOUD_PROJECT', location='$REGION')
client = vertexai.Client(
project='$GOOGLE_CLOUD_PROJECT', location='$REGION',
http_options=types.HttpOptions(api_version='v1beta1'),
)
try:
agent = client.agent_engines.get(name='$RESERVATION_AGENT_RESOURCE_NAME')
agent.delete(force=True)
print('Agent Runtime deployment deleted.')
except Exception as e:
print(f'No agent deployment found or already deleted, skipping. ({e})')
"
# Delete GCS staging bucket (skip if STAGING_BUCKET is not set)
if [ -n "$STAGING_BUCKET" ]; then
gsutil rm -r gs://$STAGING_BUCKET
else
echo "STAGING_BUCKET not set, skipping bucket deletion."
fi
# Delete Cloud Run services
gcloud run services delete restaurant-agent --region=$REGION --quiet
gcloud run services delete toolbox-service --region=$REGION --quiet
gcloud run services delete telegram-integration --region=$REGION --quiet
# Delete Cloud SQL instance
gcloud sql instances delete $DB_INSTANCE --quiet
