Membangun Aplikasi AI Agentik yang Dapat Digunakan Pelanggan Anda untuk Berinteraksi melalui Telegram

1. Pengantar

Buat pengalaman AI Agentic interaktif yang lancar dan dapat digunakan pelanggan Anda langsung dari aplikasi pesan yang telah mereka gunakan. Temukan cara mengembangkan dan men-deploy aplikasi cerdas yang berjalan lancar di seluruh antarmuka web dan saluran pesan modern.

Yang akan Anda build

Integrasi antara "Restaurant Concierge" yang lengkap, aplikasi berbasis ADK yang didukung oleh Gemini yang membantu pelanggan menelusuri menu restoran dan memesan tempat, serta aplikasi chat Telegram. Anda dapat berinteraksi dengan bot Telegram dan meminta deskripsi bahasa alami seperti "Saya ingin sesuatu yang pedas dan vegetarian". Bot kemudian akan terhubung ke agen ADK yang membaca dan menulis ke database Cloud SQL PostgreSQL sepenuhnya melalui MCP Toolbox for Databases, yang menangani semua akses database — termasuk pembuatan embedding otomatis untuk penelusuran vektor. Sementara itu, pengguna akan dapat melihat bahwa bot mengakui pesan dan mengetik ... typing untuk respons saat menunggu respons dari agen ADK.

c1d28343ed68358a.png

Yang akan Anda pelajari

  • Men-deploy "Restaurant Concierge" yang berfungsi, aplikasi berbasis ADK yang didukung oleh Gemini
  • Menyiapkan bot chat Telegram menggunakan BotFather
  • Menulis aplikasi Python untuk memproses webhook bot
  • Mengirim tindakan chat untuk memberikan ... typing notifikasi di Telegram pada pesan pengguna, dan melakukan polling untuk mengirim ... typing secara berkala saat menunggu respons sebenarnya
  • Memanggil endpoint Cloud Run Restaurant Concierge untuk memproses permintaan pengguna
  • Menangani respons dari agen ADK, dan mengirim pesan ke Telegram serta menutup buffer
  • Men-deploy aplikasi Python ke Cloud Run
  • Berinteraksi dengan bot Telegram Anda

Prasyarat

2. Penyiapan Lingkungan - Melanjutkan dari codelab sebelumnya

Narasi yang kami berikan dalam codelab ini sebenarnya merupakan kelanjutan dari codelab prasyarat ini: RAG Agentic dengan ADK, MCP Toolbox, dan Cloud SQL atau Agen dalam Skala Besar: Arsitektur Multi-Agen dengan Protokol A2A di Agent Runtime dan Integrasi ADK. Anda dapat melanjutkan pekerjaan dari codelab sebelumnya

Kita dapat mulai membangun di direktori kerja codelab sebelumnya ( direktori kerja harus berupa build-agent-adk-toolbox-cloudsql atau adk-a2a-agent-runtime-starter). Untuk menghindari kebingungan, mari kita ganti nama direktori dengan nama direktori yang sama yang kita gunakan saat memulai dari awal

Jika Anda melanjutkan dari lab RAG Agentic dengan ADK, MCP Toolbox, dan Cloud SQL :

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

Atau jika Anda melanjutkan dari lab Agen dalam Skala Besar: Arsitektur Multi-Agen dengan Protokol A2A di Agent Runtime dan Integrasi ADK

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

Kemudian, ubah direktori kerja kita ke direktori tersebut

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

Setelah itu, pastikan restaurant-agent Anda telah di-deploy dan memiliki URL publik yang dapat diakses

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

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

Jika dapat mengakses URL, Anda dapat melanjutkan ke bagian berikutnya: Create Telegram Bot

3. Penyiapan Lingkungan - Memulai dari awal dengan repo awal

Langkah ini menyiapkan lingkungan Cloud Shell Anda, mengonfigurasi project Google Cloud Anda, dan meng-clone repositori awal.

Membuka Cloud Shell

Buka Cloud Shell di browser Anda. Cloud Shell menyediakan lingkungan yang telah dikonfigurasi sebelumnya dengan semua alat yang Anda perlukan untuk codelab ini. Klik Authorize saat diminta

Kemudian, klik "View" -> "Terminal" untuk membuka terminal.Antarmuka Anda akan terlihat mirip dengan ini

86307fac5da2f077.png

Ini akan menjadi antarmuka utama kita, IDE di atas, terminal di bawah

Menyiapkan direktori kerja Anda

Clone repositori awal, semua kode yang Anda tulis di codelab ini ada di sini:

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

Buat file .env dari template yang disediakan:

cp .env.example .env

Untuk menyederhanakan penyiapan project di terminal, download skrip penyiapan project ini ke direktori kerja Anda:

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

Jalankan skrip. Skrip ini akan memverifikasi akun penagihan uji coba Anda, membuat project baru (atau memvalidasi project yang ada), menyimpan project ID Anda ke file .env di direktori saat ini, dan menetapkan project aktif di gcloud.

bash setup_verify_trial_project.sh && source .env

Skrip ini akan:

  1. Memverifikasi bahwa Anda memiliki akun penagihan uji coba yang aktif
  2. Memeriksa project yang ada di .env (jika ada)
  3. Membuat project baru atau menggunakan kembali project yang ada
  4. Menautkan akun penagihan uji coba ke project Anda
  5. Menyimpan project ID ke .env
  6. Menetapkan project sebagai project gcloud aktif

Verifikasi bahwa project telah ditetapkan dengan benar dengan memeriksa teks berwarna kuning di samping direktori kerja Anda di perintah terminal Cloud Shell. Project ID Anda akan ditampilkan.

5c515e235ee1179f.png

Penyiapan Infrastruktur Awal

Pertama, kita perlu menginstal dependensi Python menggunakan uv. Ini adalah pengelola project dan paket Python cepat yang ditulis dalam Rust ( dokumentasi uv ). Codelab ini menggunakannya untuk kecepatan dan kesederhanaan dalam memelihara project Python

uv sync

Kemudian, jalankan skrip penyiapan lengkap, yang membuat instance Cloud SQL, mengisi data, dan men-deploy layanan Toolbox yang akan bertindak sebagai status awal agen restoran kita

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

Ini akan:

  • Membuat instance Cloud SQL dan mengisi database (Fase 1)
  • Membuat konfigurasi lingkungan agen dan memulai layanan Toolbox lokal (Fase 2)
  • Men-deploy layanan Toolbox dan Agen ke Cloud Run (Fase 3)

Setelah deployment ini selesai, Anda dapat mengakses UI Dev ADK di URL 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 ""

Buka UI dev ADK, pilih restaurant_agent, dan uji dengan kueri seperti contoh berikut:

What Italian dishes do you have?

Atau,

I want something spicy and creamy

Sekarang, tindakan berikutnya adalah bagaimana kita dapat beralih dari antarmuka pengembangan web saja ke saluran pesan Telegram

4. Membuat Bot Telegram

Telegram adalah platform pesan gratis yang terkenal dan banyak digunakan untuk engagement berbasis komunitas. Salah satu alasannya adalah, platform ini menawarkan banyak cara untuk berintegrasi dengan mudah, sehingga orang dapat dengan mudah membuat bot mereka sendiri dengan berbagai fungsi yang berbeda.

Dalam kasus ini, kita akan menggunakan BotFather untuk membuat bot kita sendiri untuk pertama kalinya. Perlu diingat bahwa meskipun kita menggunakan Telegram untuk sesi ini, metode yang sama dapat digunakan untuk WhatsApp atau platform pesan lainnya yang dipilih.

Menggunakan BotFather untuk Membuat Bot Anda Sendiri

Arahkan browser web Anda dan buka https://telegram.me/BotFather untuk mulai membuat bot Telegram Anda sendiri.

1b817e758c699a79.png

Mulai Berinteraksi dengan BotFather

ad3daa08e73502db.png

Mengirim Perintah /start

Untuk mulai menggunakan BotFather dan mulai membuat bot pertama Anda, Anda harus memanggil pesan /start ke BotFather. Kemudian, pesan tersebut akan membagikan semua perintah yang dimilikinya agar Anda dapat berinteraksi lebih lanjut.

/start

Memulai Pembuatan Bot dengan Perintah /newbot

Mari kita buat bot baru dengan mengirim perintah /newbot ke BotFather. BotFather akan meminta Anda untuk memberi nama bot Anda, lalu meminta Anda untuk memberikan username bot yang selalu mengharuskan nama tersebut diakhiri dengan bot . Misalnya, TetrisBot atau tetris_bot. Nama ini harus unik.

1f6a74f494d48986.png

Setelah pembuatan bot berhasil, Anda akan menerima pesan berikut dari 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

Catat YOUR_TELEGRAM_API_KEY. Kita akan menggunakannya di bagian berikutnya.

5. Mengembangkan Aplikasi Webhook Telegram

Mari kita siapkan direktori kerja untuk mulai mengembangkan aplikasi webhook Telegram Anda

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

Menambahkan Dependensi yang diperlukan

Buat skrip requirements.txt dengan konten berikut untuk menyediakan dependensi yang memadai untuk skrip pemroses webhook Telegram.

cloudshell edit ./telegram-integration/requirements.txt

Kemudian, tambahkan dependensi berikut

python-telegram-bot[webhooks]
httpx

Membuat skrip untuk Pemroses Webhook Telegram

Setelah kita menginstal dependensi. Sekarang kita dapat membuat skrip main.py Python untuk aplikasi integrasi

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

Kemudian, salin kode berikut ke dalamnya

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

Memahami kode Integrasi Bot Telegram

23b346f5ceb4712a.png

Saat pengguna mengirim pesan, pipeline berikut akan berjalan di bagian handle_message()

Langkah 1: Identitas &Turunan Sesi

Bot memetakan ID Pengguna Telegram ke ID ADK unik untuk menjaga sesi pengguna tetap berbeda:

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

Langkah 2: Status "Mengetik" Asinkron (Baris 53–58)

Untuk memastikan pengalaman pengguna yang sangat responsif saat agen ADK memproses perintah (yang dapat memerlukan waktu beberapa detik), bot akan memulai loop latar belakang asinkron:

  • asyncio.Event dibuat instance-nya sebagai stop_event.
  • asyncio.create_task membuat send_typing_loop(...) di latar belakang.
  • Loop mengirim tindakan ChatAction.TYPING ke Telegram setiap 4 detik hingga stop_event ditetapkan.

Langkah 3: Verifikasi &Pembuatan Sesi ADK (Baris 61–72)

Sebelum menjalankan agen, bot akan memeriksa apakah sesi sudah ada:

  1. Mengirim permintaan GET ke /apps/{appName}/users/{userId}/sessions/{sessionId}.
  2. Jika responsnya adalah 404 Not Found, sesi akan dibuat melalui permintaan POST ke URL yang sama dengan isi JSON kosong.
  3. Jika status selain 200 atau 404 ditampilkan, pengecualian akan muncul.

Langkah 4: Mengirim Permintaan ke Agen (Baris 74–85)

Payload pesan diteruskan ke endpoint ADK /run:

  • Endpoint: POST /run
  • Batas waktu permintaan ditetapkan ke 60.0 detik untuk memungkinkan penalaran yang kompleks atau latensi upstream.
  • Struktur Payload:
{
  "appName": "restaurant_agent",
  "userId": "tg_<user_id>",
  "sessionId": "tg_sess_<user_id>",
  "newMessage": {
    "role": "user",
    "parts": [{"text": "<user_message>"}]
  }
}

Langkah 5: Mengurai Respons (Baris 87–101)

Server ADK menampilkan daftar peristiwa pesan. Bot memeriksa array yang ditampilkan:

  • Bot mengambil peristiwa terakhir dalam daftar (events[-1]).
  • Bot membuka konten teks melalui event["content"]["parts"][0]["text"].
  • Jika tidak ada peristiwa yang ditampilkan atau struktur teks tidak ada, teks placeholder deskriptif akan ditetapkan.

Langkah 6: Penonaktifan &Pengiriman Respons (Baris 103–111)

  • Di blok finally, stop_event ditetapkan, sehingga menghentikan loop tindakan mengetik.
  • Bot menunggu penyelesaian typing_task untuk memastikan resource bersih.
  • Terakhir, bot membalas chat Telegram dengan teks respons yang diurai.

6. Men-deploy Aplikasi Webhook Telegram ke Cloud Run

Selanjutnya, kita akan men-deploy Pemroses Webhook Telegram ke Cloud Run, sehingga bot kita dapat berkomunikasi dengannya

Membuat Dockerfile

Pertama, kita perlu membuat Dockerfile.

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

Kemudian, salin kode berikut ke dalamnya

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

Layanan ini dikontainerisasi menggunakan python:3.11-slim agar ukuran image tetap kecil:

  • Menginstal dependensi dari requirements.txt (python-telegram-bot[webhooks] dan httpx).
  • Mengekspos port standar 8080.
  • Meluncurkan python main.py.

Menyiapkan Variabel Lingkungan

Setelah itu, mari kita periksa kembali apakah agen kita berhasil di-deploy

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

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

Selanjutnya, mari kita masukkan TELEGRAM_BOT_TOKEN yang sebelumnya kita dapatkan ke .env

echo "TELEGRAM_BOT_TOKEN=YOUR_TELEGRAM_API_KEY" >> .env

Kemudian, mari kita isi data .env dengan nilai lain yang kita perlukan.

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

Membuat Skrip Deployment

Mari kita buat skrip deployment yang akan memberikan pemeriksaan lengkap dan men-deploy aplikasi ke Cloud Run

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

Lalu, salin kode berikut ke file

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

Skrip Deployment Ganda (deploy.sh)

Saat men-deploy ke Google Cloud Run, bot harus menentukan URL-nya sendiri (SERVICE_URL) di lingkungannya sehingga dapat mendaftarkannya sebagai target webhook dengan Telegram. Untuk mengatasi dependensi melingkar ini (URL tidak diketahui hingga deployment, tetapi layanan memerlukan URL untuk melakukan booting tanpa kegagalan health check), deploy.sh melakukan deployment dua tahap:

  1. Langkah 1: Deployment Awal: Melakukan booting container dengan DNS placeholder (https://google.com) sehingga layanan berhasil dimulai, terikat ke port lokal, dan lulus health check Cloud Run awal.
  2. Langkah 2: Mengambil URL: Mengekstrak endpoint Cloud Run yang baru dibuat secara terprogram menggunakan gcloud run services describe.
  3. Langkah 3: Memperbarui Konfigurasi: Memperbarui variabel lingkungan dengan URL layanan aktif yang sebenarnya. Tindakan ini memicu update berkelanjutan yang bersih di Cloud Run dan mendaftarkan target webhook yang benar dengan aman ke Telegram API.

Men-deploy ke Cloud Run

Skrip deployment mencetak URL Agen. Buka di browser Anda untuk mengakses UI dev ADK yang sama yang berjalan di Cloud Run.

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

Jika semuanya berjalan lancar, inilah saatnya Anda dapat mulai melakukan chat ke bot Anda langsung dari aplikasi chat Telegram. Temukan bot yang baru saja Anda buat dan mulai berinteraksi dengannya:

What Italian dishes do you have?

Atau,

I want something spicy and creamy

Perhatikan bot yang mengirim status "...is typing", lalu segera, bot akan menampilkan pesan dari ADK yang Anda buat sebelumnya.

c62fd4016ddd3c9b.png

7. Selamat!

Anda telah membangun, men-deploy, dan mengintegrasikan sepenuhnya asisten menu restoran pintar berbasis ADK, agen AI dengan Telegram, melalui komunikasi server klien HTTP, dan memungkinkan orang untuk membuat kueri menu favorit mereka dan memesan tempat di restoran.

Yang telah Anda pelajari

  • Men-deploy dan mengonfigurasi Restaurant Concierge, agen berbasis ADK, dan MCP Toolbox ke Cloud Run
  • Cara menyiapkan bot Telegram menggunakan BotFather
  • Cara menulis skrip Python untuk memproses webhook Telegram dan berinteraksi dengan agen ADK untuk meneruskan kueri dan respons pengguna dengan tepat
  • Cara menerapkan "... typing" di Telegram untuk memberi sinyal bahwa pesan sedang diproses sebagai masukan real-time kepada pengguna saat menunggu respons agen ADK.
  • Cara Men-deploy skrip Python ke Cloud Run dan dapat berinteraksi dengannya

Pembersihan

Untuk menghindari tagihan ke akun Google Cloud Anda, hapus resource yang dibuat di codelab ini.

gcloud projects delete $GOOGLE_CLOUD_PROJECT

Opsi 2: Menghapus setiap resource

# 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