# Ajouter un nouveau bot Trois cas selon ce que tu veux faire. --- ## Cas 1 — Envoi seul (Cowork → Telegram, pas d'interaction) **Le gateway n'est pas nécessaire.** Une session Cowork qui envoie juste des notifications appelle directement la Bot API. Setup une fois (humain) : 1. @BotFather → `/newbot` → noter le token 2. Trouver ton chat_id via [@userinfobot](https://t.me/userinfobot) ou en messageant le bot et en regardant `getUpdates` Prompt à donner à la session Cowork : ``` Tu peux envoyer une notification Telegram via : curl -sS -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \ -H 'Content-Type: application/json' \ -d '{"chat_id":,"text":""}' Variables : BOT_TOKEN= # à fournir en env ou en clair CHAT_ID= Pas besoin du gateway pour de l'envoi pur. Préfère cette voie quand la session n'a rien à recevoir en retour. ``` --- ## Cas 2 — Bot echo simple via le gateway (Phase 1, gated par auth) Utile pour valider la chaîne, créer un canal de log conversationnel, etc. > **Auth (Phase 1.5, ADR [20260509](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/doc/adr/20260509-telegram-gateway-auth.md))** : par défaut, **`requireAuth: true`** s'applique → tout user qui DM ce bot doit d'abord ouvrir une session via `/auth ` chez `@arcodange_factory_bot`. Voir [`AUTH.md`](AUTH.md). Pour rendre un bot public, ajouter explicitement `requireAuth: false`. Steps (humain ou session Claude avec accès au cluster + au repo) : 1. **@BotFather crée le bot**, noter le TOKEN. ```bash TOKEN='1234:AAA...' SLUG='monbot' # kebab-case, [a-z0-9-]+ ENV_SLUG=$(echo "$SLUG" | tr 'a-z-' 'A-Z_') # ex: monbot → MONBOT SECRET=$(openssl rand -hex 32) ``` 2. **Patcher le Secret cluster** (ajoute les 2 clés sans toucher aux existantes) : ```bash kubectl -n telegram-gateway patch secret telegram-gateway-bots --type=json -p="[ {\"op\":\"add\",\"path\":\"/data/BOT_${ENV_SLUG}_TOKEN\",\"value\":\"$(echo -n "$TOKEN" | base64)\"}, {\"op\":\"add\",\"path\":\"/data/BOT_${ENV_SLUG}_SECRET\",\"value\":\"$(echo -n "$SECRET" | base64)\"} ]" ``` 3. **Déclarer le bot** dans `chart/values.yaml` sous `bots:` : ```yaml bots: monbot: handler: echo # requireAuth: true (implicite — défaut sécurisé) ``` Pour un bot public (notifications status, etc.), opt-out explicite : ```yaml bots: statusbot: handler: echo requireAuth: false ``` 4. **Push + rollout** : ```bash cd /Users/gabrielradureau/Work/Vibe/telegram-gateway git add chart/values.yaml git commit -m "bots: add $SLUG" git push kubectl -n telegram-gateway rollout restart deploy/telegram-gateway kubectl -n telegram-gateway rollout status deploy/telegram-gateway ``` 5. **Enregistrer le webhook côté Telegram** : ```bash export BOT_${ENV_SLUG}_TOKEN="$TOKEN" export BOT_${ENV_SLUG}_SECRET="$SECRET" make setwebhook SLUG="$SLUG" BASE_URL=https://tg.arcodange.fr ``` 6. **Test** : - Si `requireAuth` est laissé à true : envoie un message → réponse `🔒 /auth chez @arcodange_factory_bot` ; fais `/auth ` chez factory ; renvoie un message → echo en < 2 s. - Si `requireAuth: false` : echo direct en < 2 s. **Limite handler `echo`** : tous les bots `echo` répondent toujours pareil. Pour de la logique métier, voir Cas 2.5 (HTTP forward) ou Cas 3 (agent async). --- ## Cas 2.5 — Bot piloté par un service interne via HTTP forward (Phase 2a, livré) Cible : un service du cluster (par ex. `webapp`, ou un mini-service Go/Python dédié) reçoit l'`Update` Telegram complet en POST JSON, traite sa logique, renvoie `{"text": ""}`. Le gateway envoie `text` au user. Sync : le webhook ack attend la réponse (timeout par défaut 5 s, plafond 30 s — Telegram coupe vers 60 s). Pour des backends lents, voir Cas 3. Setup côté gateway (suit Cas 2 pour le bot Telegram + le Secret) puis : 1. **Déclarer le bot avec `handler: http`** dans `chart/values.yaml` : ```yaml bots: webappbot: handler: http http: url: http://webapp.webapp.svc.cluster.local:8080/telegram/update timeout: 5s # requireAuth: true (implicite — défaut sécurisé) ``` 2. **Côté service interne**, exposer un endpoint qui : - Accepte `POST ` avec un body = JSON Telegram `Update` (champs : `update_id`, `message.text`, `message.from.id`, `message.chat.id`, etc.) - Lit le header `X-Bot-Slug: ` pour distinguer plusieurs bots qui forwarderaient au même service - Renvoie `200 {"text": "réponse au user"}` (ou `200` body vide si pas de réponse à envoyer) - Respecte le timeout configuré (le gateway coupe à `timeout`) 3. **Push values.yaml + rollout** comme dans Cas 2. Exemple minimal de upstream service (Go) : ```go http.HandleFunc("/telegram/update", func(w http.ResponseWriter, r *http.Request) { var u struct { Message struct { Text string `json:"text"` From struct{ ID int64 `json:"id"` } `json:"from"` } `json:"message"` } json.NewDecoder(r.Body).Decode(&u) reply := fmt.Sprintf("hello user %d, you said: %s", u.Message.From.ID, u.Message.Text) json.NewEncoder(w).Encode(map[string]string{"text": reply}) }) ``` --- ## Cas 3 — Bot interactif piloté par un agent async (Phase 3, pas encore livré) Cible : utilisateur DM le bot → gateway enqueue le job → worker async exécute un wrapper shell (ex. `claude --print`, `mistral-vibe`, ou un script Python qui appelle Ollama) → la réponse est renvoyée via Telegram, **même si le backend (Macbook Ollama) dort au moment du DM** (retry exponentiel jusqu'à 1 h). Pour l'instant **non supporté**. Requiert : - Phase 2b (queue Postgres + worker — fondation async) - Phase 3 (handlers `shell` / `script` / `ollama` + WoL Macbook optionnel) Quand Phase 3 sera up, l'ajout d'un tel bot sera : steps Cas 2 + handler `shell`/`script`/`ollama` au lieu d'`echo`, plus la commande/script à exécuter. Plan complet : `~/.claude/plans/pour-les-notifications-on-inherited-seal.md`. --- ## Récap : quel cas choisir ? | Besoin | Cas | État | Gateway impliqué ? | |---|---|---|---| | Notifs sortantes one-way (Cowork → user) | Cas 1 | livré | non, Bot API directe | | Bot qui répond toujours pareil (echo, ack, ping) | Cas 2 | livré (Phase 1) | oui | | Bot piloté par un service interne du cluster (webapp, mini-service custom) | Cas 2.5 | **livré (Phase 2a)** | oui | | Bot conversationnel piloté par agent async (Claude / Mistral / Ollama / script, retry si backend dort) | Cas 3 | futur (Phase 3) | oui |