An AI-powered Telegram bot playing "el gordo" — a blunt, politically incorrect Argentine character who answers everything in a single lowercase phrase using Argentine slang.
- AI chat: configurable personality with web search, powered by Qwen via OpenRouter
- Streaming responses: AI replies stream token-by-token to Telegram (when no tools are active)
- Chat memory with RediSearch: persistent conversation history, full-text search, automatic compaction
- Incremental summaries:
/resumenstreams conversation summaries using Minimax, with automatic context compaction - Agentic tools: AI can call tools (price lookup, calculator, web fetch, task scheduling) via function calling
- Market data:
/prices,/usd,/petroleo,/devo,/powerlaw,/rainbow,/rulo,/eleccion - BCRA economic data:
/bcra,/variables - Media: audio transcription (Whisper via Groq, with OpenRouter fallback) and image description (OpenRouter)
- Scheduled tasks:
/tareas,/tasks— create, list, and delete one-shot or recurring reminders via AI or inline buttons - AI credits billing: Telegram Stars (
/topup,/balance,/transfer) - Link enrichment: URLs get metadata injected into AI context; social links auto-replaced (fxTwitter, fixupx, etc.)
- Context injection: market data, weather, Hacker News top stories, and Buenos Aires time in every system prompt
- Response cleanup: deduplication, prefix stripping, identity leak prevention
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# Edit .env with your keys
python run_polling.py| Variable | Description |
|---|---|
BOT_SYSTEM_PROMPT |
Complete AI personality prompt |
BOT_TRIGGER_WORDS |
Comma-separated keywords that trigger responses in groups |
TELEGRAM_TOKEN |
Bot token from @BotFather |
TELEGRAM_USERNAME |
Bot username |
REDIS_HOST / REDIS_PORT / REDIS_PASSWORD |
Redis cache (requires RediSearch) |
SUPABASE_POSTGRES_URL |
Pooled Supabase Postgres URL (for AI credits) |
COINMARKETCAP_KEY |
CoinMarketCap API key |
GROQ_API_KEY |
Paid Groq API key for transcription |
GROQ_FREE_API_KEY |
Optional free-tier Groq key for transcription |
OPENROUTER_API_KEY |
OpenRouter API key for chat/vision |
CF_AIG_TOKEN |
Cloudflare AI Gateway token forwarded to OpenRouter requests |
GIPHY_API_KEY |
Giphy API key for /gm and /gn |
ADMIN_CHAT_ID |
Telegram chat ID for error reports |
FRIENDLY_INSTANCE_NAME |
Instance name for admin reports |
| Use | Provider | Model |
|---|---|---|
| Chat | OpenRouter | qwen/qwen3.6-plus |
| Vision | OpenRouter | google/gemini-3.1-flash-lite-preview |
| Transcription | Groq → OpenRouter fallback | whisper-large-v3 → google/gemini-3.1-flash-lite-preview |
| Summary | OpenRouter | minimax/minimax-m2.7 |
Streaming: token streaming only when no tools/web-search are active. Tool-enabled requests return complete responses.
| Command | Aliases | Description |
|---|---|---|
/ask |
/pregunta, /che, /gordo |
AI chat (streaming) |
/resumen |
/summary |
Stream conversation summary |
/transcribe |
/describe |
Transcribe audio / describe image |
/prices |
/price, /precios, /precio, /presio(s), /bresio(s), /brecio(s), /crypto, /criptos |
Crypto prices |
/dolar |
/dollar, /usd |
Dollar rates (CriptoYa) |
/petroleo |
/oil |
Oil prices |
/acciones |
/stocks |
Stock prices |
/eleccion |
- | Polymarket Argentina election odds |
/devo |
- | Arbitrage calculator (tarjeta vs crypto) |
/rulo |
- | Dollar arbitrage chains |
/powerlaw |
- | Bitcoin power law |
/rainbow |
- | Bitcoin rainbow chart |
/satoshi |
/sat, /sats |
Satoshi value |
/bcra |
/variables |
BCRA economic variables |
/random |
- | Random choice or number |
/convertbase |
- | Number base conversion |
/comando |
/command |
Text → Telegram command |
/time |
- | Unix timestamp |
/config |
- | Chat settings (admin only in groups) |
/topup |
- | Buy AI credits with Telegram Stars |
/balance |
- | Show credit balance |
/transfer |
- | Transfer credits to group |
/tareas |
/tasks |
Manage scheduled reminders |
/gm |
- | Good morning GIF |
/gn |
- | Good night GIF |
/help |
- | Command reference |
/instance |
- | Instance name |
ProviderChain— tries providers in order until one succeedsOpenRouterProvider— streaming + completion, primary chat model
TelegramMessageStreamer edits Telegram messages every 400ms or 15+ new chars. Token streaming from OpenRouterProvider.stream() when no tools active. Falls back to complete response for tool-enabled requests.
AIService orchestrates credit reservation → model call → billing settlement:
- Reserve: holds worst-case credits before AI call
- Settle: calculates actual cost, charges/refunds difference
- Refund: full return on failure, fallback, or empty response
COMPACTION_THRESHOLD = 20— compact when delta > 20 messagesCOMPACTION_KEEP = 15— retain last 15 messages- Incremental summaries from delta messages + prior summary
- RediSearch index (
idx:chat_messages) for full-text search and RAG retrieval
- User credits — personal balance
- Group credits — shared pool subsidizing creditless users
- Onboarding — 3 free credits for new users
- Hourly limit —
creditless_user_hourly_limitcaps free messages per user per hour - Credit packs (Telegram Stars): 50→2500 credits with 50% bonus tiers
Sequential cleanup:
- Remove "gordo:" prefix
- Strip echoed context strings
- Remove identity leak prefixes (
@user:) - Deduplicate consecutive lines/sentences
Every system prompt includes:
- Market: top 3 cryptos + dollar rates (oficial, blue, mep, tarjeta, usdt)
- Weather: Buenos Aires temp, rain probability, cloud cover
- Hacker News: top 5 stories (title, points, comments)
- Time: current Buenos Aires datetime
api/- application codeapi/providers/- AI provider abstraction (OpenRouter, ProviderChain)api/streaming.py- Telegram token streamingapi/ai_service.py- AI conversation orchestration and billingapi/ai_pipeline.py- response cleanup pipelineapi/ai_billing.py- credit reservation/settlement/refundapi/message_handler.py- message routing, command dispatch, billing integrationapi/message_state.py- Redis chat history, RediSearch indexing, compaction markersapi/command_registry.py- command definitions and aliasesapi/tools/- agentic tool registry (crypto, calculator, web fetch, tasks)api/index.py- core bot logic, commands, provider integration
quadlets/- Podman Quadlet container definitionssystemd/- systemd service and timer unitsrun_polling.py- bot entrypointrun_maintenance.py- maintenance entrypointtests/- test suiteContainerfile- container image definition
sudo apt install -y podman uidmap dbus-user-session slirp4netns fuse-overlayfs
sudo useradd -m -s /bin/bash respondedorbot
sudo loginctl enable-linger respondedorbotgit clone https://github.com/astrovm/respondedorbot
cd respondedorbot
mkdir -p ~/.config/containers/systemd
cp quadlets/* ~/.config/containers/systemd/
mkdir -p ~/respondedorbot
cp .env.example ~/respondedorbot/.env
# Edit ~/respondedorbot/.env — set REDIS_HOST=respondedorbot-redis
# Quadlet Redis uses redis-stack-server because the bot needs RediSearch (FT.CREATE / FT.SEARCH)
export XDG_RUNTIME_DIR=/run/user/$(id -u)
export DBUS_SESSION_BUS_ADDRESS=unix:path=${XDG_RUNTIME_DIR}/bus
systemctl --user daemon-reload
systemctl --user start respondedorbot-redis.service
systemctl --user start respondedorbot.serviceThe bundled Redis Quadlet uses redis/redis-stack-server, not plain redis, because chat memory search and compaction require RediSearch commands. The unit intentionally does not override the container command; it passes Redis tuning through REDIS_ARGS so the image can boot Redis Stack with its modules enabled.
systemctl --user enable fails on Quadlet-generated units on some distros — use symlinks instead:
mkdir -p ~/.config/systemd/user/default.target.wants
ln -sf ~/.config/containers/systemd/respondedorbot.container \
~/.config/systemd/user/default.target.wants/respondedorbot.container
ln -sf ~/.config/containers/systemd/respondedorbot-redis.container \
~/.config/systemd/user/default.target.wants/respondedorbot-redis.container
systemctl --user daemon-reloadcp systemd/respondedorbot-maintenance.* ~/.config/systemd/user/
cp systemd/respondedorbot-podman-prune.* ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now respondedorbot-maintenance.timer
systemctl --user enable --now respondedorbot-podman-prune.timerjournalctl --user -fu respondedorbot.service
systemctl --user status respondedorbot.service --no-pager
systemctl --user stop respondedorbot.service respondedorbot-redis.service
systemctl --user enable --now podman-auto-update.timer
podman exec systemd-respondedorbot python /app/run_maintenance.pypytest -q