Crie um app de IA agêntica para que seu cliente possa interagir via Telegram

1. Introdução

Crie experiências de IA agêntica interativas e integradas para que seus clientes possam interagir diretamente no aplicativo de mensagens que já usam. Saiba como desenvolver e implantar aplicativos inteligentes que funcionam sem problemas em interfaces da Web e canais de mensagens modernos.

O que você vai criar

Integração entre um "concierge de restaurante" completo, um aplicativo baseado no ADK com tecnologia do Gemini que ajuda os clientes a navegar pelo cardápio de um restaurante e fazer reservas, e o app de chat do Telegram. Você pode interagir com o bot do Telegram e pedir descrições em linguagem natural, como "Quero algo picante e vegetariano". Em seguida, o bot se conecta ao agente do ADK, que lê e grava em um banco de dados do Cloud SQL PostgreSQL totalmente pelo MCP Toolbox for Databases, que processa todo o acesso ao banco de dados, incluindo a geração automática de incorporação para pesquisa vetorial. Enquanto isso, o usuário poderá ver que o bot está reconhecendo a mensagem e digitando ... typing para resposta enquanto aguarda o retorno do agente do ADK.

c1d28343ed68358a.png

O que você aprenderá

  • Implantar um "concierge de restaurante" funcional, um aplicativo baseado no ADK com tecnologia do Gemini
  • Configurar o bot de chat do Telegram usando o BotFather
  • Criar aplicativos Python para detectar o webhook do bot
  • Enviar uma ação de chat para fornecer a notificação ... typing no Telegram na mensagem do usuário e fazer a pesquisa para enviar ... typing periodicamente enquanto aguarda a resposta real
  • Chamar o endpoint do Cloud Run do Restaurant Concierge para processar a consulta do usuário
  • Processar o retorno do agente do ADK e enviar uma mensagem ao Telegram e fechar o buffer
  • Implantar o aplicativo Python no Cloud Run
  • Interagir com o bot do Telegram

Pré-requisitos

2. Configuração do ambiente: continuando do codelab anterior

As narrativas fornecidas neste codelab são, na verdade, a continuação deste codelab de pré-requisito: RAG agêntico com ADK, MCP Toolbox e Cloud SQL ou Agentes em escala: arquitetura multiagente com protocolo A2A no Agent Runtime e integração do ADK. Você pode continuar seu trabalho do codelab anterior.

Podemos começar a criar no diretório de trabalho do codelab anterior ( o diretório de trabalho precisa ser build-agent-adk-toolbox-cloudsql ou adk-a2a-agent-runtime-starter). Para evitar confusão, vamos renomear o diretório com o mesmo nome de diretório que usamos quando começamos do zero.

Se você estiver continuando do laboratório RAG agêntico com ADK, MCP Toolbox e Cloud SQL :

mv ~/build-agent-adk-toolbox-cloudsql ~/build-agent-adk-telegram

Caso contrário, se você estiver continuando do laboratório Agentes em escala: arquitetura multiagente com protocolo A2A no Agent Runtime e integração do ADK

mv ~/adk-a2a-agent-runtime-starter ~/build-agent-adk-telegram

Em seguida, mude nosso diretório de trabalho para ele.

cloudshell workspace ~/build-agent-adk-telegram && cd ~/build-agent-adk-telegram
source .env

Depois disso, verifique se o restaurant-agent já foi implantado e tem um URL público para acesso.

AGENT_URL=$(gcloud run services describe restaurant-agent \
    --region="$REGION" \
    --format='value(status.url)')

echo "      ✓ Agent service deployed"
echo "      Agent URL: $AGENT_URL"
echo ""

Se você puder acessar o URL, poderá acessar a próxima seção: Create Telegram Bot.

3. Configuração do ambiente: começando do zero com o repositório inicial

Esta etapa prepara o ambiente shell do Cloud Shell, configura seu projeto na nuvem do Google Cloud e clona o repositório inicial.

Abra o Cloud Shell

Abra o Cloud Shell no navegador. O Cloud Shell oferece um ambiente pré-configurado com todas as ferramentas necessárias para este codelab. Clique em Autorizar quando solicitado.

Em seguida, clique em "Visualizar" -> "Terminal" para abrir o terminal.A interface precisa ser semelhante a esta:

86307fac5da2f077.png

Essa será nossa interface principal, o ambiente de desenvolvimento integrado na parte de cima e o terminal na parte de baixo.

Configure seu diretório de trabalho

Clone o repositório inicial. Todo o código que você escrever neste codelab fica aqui:

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

Crie o arquivo .env com base no modelo fornecido:

cp .env.example .env

Para simplificar a configuração do projeto no terminal, faça o download deste script de configuração do projeto no seu diretório de trabalho:

curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh

Execute o script. Ele verifica sua conta de faturamento de teste, cria um novo projeto (ou valida um existente), salva o ID do projeto em um arquivo .env no diretório atual e define o projeto ativo no gcloud.

bash setup_verify_trial_project.sh && source .env

O script faz o seguinte:

  1. Verifica se você tem uma conta de faturamento de teste ativa.
  2. Verifica se há um projeto no .env (se houver).
  3. Cria um novo projeto ou reutiliza o existente.
  4. Vincula a conta de faturamento de teste ao seu projeto.
  5. Salva o ID do projeto em .env.
  6. Define o projeto como o projeto gcloud ativo.

Verifique se o projeto está definido corretamente conferindo o texto amarelo ao lado do diretório de trabalho no prompt do terminal do Cloud Shell. Ele precisa mostrar o ID do projeto.

5c515e235ee1179f.png

Configuração da infraestrutura inicial

Primeiro, precisamos instalar as dependências do Python usando uv. Ele é um gerenciador de projetos e pacotes Python rápido escrito em Rust ( documentação do uv, link em inglês). Este codelab o usa para velocidade e simplicidade na manutenção do projeto Python.

uv sync

Em seguida, execute o script de configuração completo, que cria a instância do Cloud SQL, inicializa os dados e implanta o serviço do Toolbox, que vai atuar como o estado inicial do nosso agente de restaurante.

bash scripts/full_setup.sh > logs/full_setup.log 2>&1 &

Esta ação resultará no seguinte:

  • Cria uma instância do Cloud SQL e inicializa o banco de dados (fase 1).
  • Gera a configuração do ambiente do agente e inicia o serviço do Toolbox local (fase 2).
  • Implanta os serviços do Toolbox e do agente no Cloud Run (fase 3).

Depois que essa implantação for concluída, você poderá acessar a interface de desenvolvimento do ADK no URL do 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 ""

Abra a interface de desenvolvimento do ADK, selecione restaurant_agent e teste com consultas como o exemplo a seguir:

What Italian dishes do you have?

Ou,

I want something spicy and creamy

Agora, a próxima ação é como podemos passar da interface de desenvolvimento da Web para o canal de mensagens do Telegram.

4. Criar bot do Telegram

O Telegram é uma plataforma de mensagens sem custo financeiro conhecida que está sendo amplamente usada para o engajamento baseado na comunidade. Um dos motivos é que ela oferece muitas maneiras de integrar com facilidade. Assim, as pessoas podem criar facilmente o próprio bot com muitas funções diferentes.

No nosso caso, vamos usar o BotFather para criar nosso próprio bot pela primeira vez. Embora estejamos usando o Telegram para esta sessão, o mesmo método pode ser usado para o WhatsApp ou outras plataformas de mensagens de sua preferência.

Usar o BotFather para criar seu próprio bot

Acesse https://telegram.me/BotFather no navegador da Web para começar a criar seu próprio bot do Telegram.

1b817e758c699a79.png

Começar a interagir com o BotFather

ad3daa08e73502db.png

Enviar o comando /start

Para começar a usar o BotFather e criar seu primeiro bot, invoque a mensagem /start para o BotFather. Em seguida, ele vai compartilhar todos os comandos que tem para você interagir ainda mais.

/start

Iniciar a criação de bots com o comando /newbot

Vamos criar nosso novo bot enviando o comando /newbot para o BotFather. Ele vai pedir que você nomeie o bot e, em seguida, que forneça o username do bot, que sempre precisa terminar em bot . Por exemplo, TetrisBot ou tetris_bot. Ele precisa ser exclusivo.

1f6a74f494d48986.png

Após a criação bem-sucedida do bot, você vai receber a seguinte mensagem do 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

Anote YOUR_TELEGRAM_API_KEY. Vamos usá-lo na seção a seguir.

5. Desenvolver o aplicativo de webhook do Telegram

Vamos preparar o diretório de trabalho para começar a desenvolver o aplicativo de webhook do Telegram.

mkdir ~/build-agent-adk-telegram/telegram-integration
cd ~/build-agent-adk-telegram

Adicionar dependências necessárias

Crie o script requirements.txt com o conteúdo a seguir para fornecer dependências adequadas para o script de listener de webhook do Telegram.

cloudshell edit ./telegram-integration/requirements.txt

Em seguida, adicione as seguintes dependências

python-telegram-bot[webhooks]
httpx

Criar script para o listener de webhook do Telegram

Depois que a dependência for instalada. Agora podemos criar um script Python main.py para o aplicativo de integração.

cloudshell edit ~/build-agent-adk-telegram/telegram-integration/main.py

Em seguida, copie o código a seguir para ele.

# ./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()

Entender o código de integração do bot do Telegram

23b346f5ceb4712a.png

Quando um usuário envia uma mensagem, o pipeline a seguir é executado em handle_message()

Etapa 1: derivação de identidade e sessão

O bot mapeia o ID do usuário do Telegram para identificadores exclusivos do ADK para manter as sessões do usuário distintas:

user_id = f"tg_{raw_user_id}"
session_id = f"tg_sess_{raw_user_id}"

Etapa 2: status "digitando" assíncrono (linhas 53 a 58)

Para garantir uma experiência do usuário altamente responsiva enquanto o agente do ADK processa o comando (o que pode levar vários segundos), o bot inicia um loop assíncrono em segundo plano:

  • asyncio.Event é instanciado como stop_event.
  • asyncio.create_task gera send_typing_loop(...) em segundo plano.
  • O loop envia uma ação ChatAction.TYPING para o Telegram a cada 4 segundos até que stop_event seja definido.

Etapa 3: verificação e criação da sessão do ADK (linhas 61 a 72)

Antes de executar o agente, o bot verifica se uma sessão já existe:

  1. Envia uma solicitação GET para /apps/{appName}/users/{userId}/sessions/{sessionId}.
  2. Se a resposta for 404 Not Found, ela cria a sessão por meio de uma solicitação POST para o mesmo URL com um corpo JSON vazio.
  3. Se um status diferente de 200 ou 404 for retornado, uma exceção será gerada.

Etapa 4: enviar solicitação ao agente (linhas 74 a 85)

O payload da mensagem é encaminhado para o endpoint /run do ADK:

  • Endpoint: POST /run
  • O tempo limite da solicitação é definido como 60.0 segundos para permitir raciocínio complexo ou latência upstream.
  • Estrutura do payload:
{
  "appName": "restaurant_agent",
  "userId": "tg_<user_id>",
  "sessionId": "tg_sess_<user_id>",
  "newMessage": {
    "role": "user",
    "parts": [{"text": "<user_message>"}]
  }
}

Etapa 5: analisar a resposta (linhas 87 a 101)

O servidor do ADK retorna uma lista de eventos de mensagem. O bot inspeciona a matriz retornada:

  • Ele recupera o evento final na lista (events[-1]).
  • Ele navega até o conteúdo de texto usando event["content"]["parts"][0]["text"].
  • Se nenhum evento for retornado ou a estrutura de texto estiver ausente, um texto de marcador descritivo será definido.

Etapa 6: desmontagem e envio de resposta (linhas 103 a 111)

  • No bloco finally, o stop_event é definido, interrompendo o loop de ação de digitação.
  • O bot aguarda a conclusão da typing_task para garantir recursos limpos.
  • Por fim, o bot responde ao chat do Telegram com o texto de resposta analisado.

6. Implantar o aplicativo de webhook do Telegram no Cloud Run

Em seguida, vamos implantar o listener de webhook do Telegram no Cloud Run para que nosso bot possa se comunicar com ele.

Criar o Dockerfile

Primeiro, precisamos criar o Dockerfile.

cloudshell edit ~/build-agent-adk-telegram/telegram-integration/Dockerfile

Em seguida, copie o código a seguir para ele.

# 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"]

O serviço é contêinerizado usando python:3.11-slim para manter a imagem pequena:

  • Instala dependências de requirements.txt (python-telegram-bot[webhooks] e httpx).
  • Expõe a porta padrão 8080.
  • Inicia python main.py.

Preparar as variáveis de ambiente

Depois disso, vamos verificar novamente se o agente foi implantado corretamente.

AGENT_URL=$(gcloud run services describe restaurant-agent \
    --region="$REGION" \
    --format='value(status.url)')

echo "      ✓ Agent service deployed"
echo "      Agent URL: $AGENT_URL"
echo ""

Em seguida, vamos colocar o TELEGRAM_BOT_TOKEN que recebemos anteriormente no .env.

echo "TELEGRAM_BOT_TOKEN=YOUR_TELEGRAM_API_KEY" >> .env

Em seguida, vamos preencher os dados .env com outros valores de que precisamos.

echo "ADK_SERVER_URL=$AGENT_URL" >> .env
echo "ADK_APP_NAME=restaurant_agent" >> .env
echo "SERVICE_NAME=telegram-integration" >> .env
source .env

Criar script de implantação

Vamos criar um script de implantação que vai fornecer verificações completas e implantar o app no Cloud Run.

cloudshell edit ~/build-agent-adk-telegram/telegram-integration/deploy.sh

Copie o código a seguir para o arquivo.

#!/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."

Script de implantação dupla (deploy.sh)

Ao implantar no Google Cloud Run, o bot precisa especificar o próprio URL (SERVICE_URL) no ambiente para que possa registrá-lo como o destino do webhook no Telegram. Para resolver essa dependência circular (o URL é desconhecido até a implantação, mas o serviço exige o URL para inicializar sem falhas de verificação de integridade), deploy.sh realiza uma implantação em duas etapas:

  1. Etapa 1: implantação inicial: inicializa o contêiner com um DNS de marcador (https://google.com) para que o serviço seja iniciado corretamente, seja vinculado à porta local e passe nas verificações de integridade iniciais do Cloud Run.
  2. Etapa 2: buscar URL: extrai programaticamente o endpoint do Cloud Run recém-criado usando gcloud run services describe.
  3. Etapa 3: atualizar configuração: atualiza as variáveis de ambiente com o URL do serviço ativo real. Isso aciona uma atualização gradual limpa no Cloud Run e registra com segurança o destino correto do webhook com a API Telegram.

Implantar no Cloud Run

O script de implantação imprime o URL do agente. Abra-o no navegador para acessar a mesma interface de desenvolvimento do ADK em execução no Cloud Run.

cd ~/build-agent-adk-telegram
bash ./telegram-integration/deploy.sh

Se tudo correr bem, esse é o momento em que você pode começar a conversar com o bot diretamente no aplicativo de chat do Telegram. Encontre o bot que você acabou de criar e comece a interagir com ele:

What Italian dishes do you have?

Ou,

I want something spicy and creamy

Assista o bot enviando o status "...is typing" e, em breve, ele vai retornar a mensagem do ADK que você criou anteriormente.

c62fd4016ddd3c9b.png

7. Parabéns!

Você criou, implantou e integrou completamente nosso agente de IA inteligente baseado no ADK do assistente de cardápio de restaurante com o Telegram, por meio da comunicação do servidor do cliente HTTP, e permite que as pessoas consultem o cardápio favorito e reservem o restaurante.

O que você aprendeu

  • Implantar e configurar o Restaurant Concierge, o agente baseado no ADK e o MCP Toolbox no Cloud Run
  • Como configurar o bot do Telegram usando o BotFather
  • Como criar scripts Python para detectar o webhook do Telegram e interagir com o agente do ADK para transmitir a consulta e a resposta dos usuários de acordo
  • Como implementar "... typing" no Telegram para sinalizar que as mensagens estão sendo processadas como um feedback em tempo real para os usuários enquanto aguardam a resposta do agente do ADK.
  • Como implantar o script Python no Cloud Run e interagir com ele

Limpeza

Para evitar cobranças na sua conta do Google Cloud, exclua os recursos criados neste codelab.

gcloud projects delete $GOOGLE_CLOUD_PROJECT

Opção 2: excluir recursos individuais

# 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