Building a Bot π€
A FrogTalk bot is any program that holds a bot_β¦ API key and calls the
External Token API. Bots run anywhere β your laptop, a VPS, a serverless
function β they only need outbound HTTP to your FrogTalk server. Every message a bot posts is
stamped is_bot: true on the wire, so clients render a BOT pill next
to the author name in chat. There is no way to disguise a bot as a human.
1. Create the bot
- Open Settings β Developer β Bots in the FrogTalk app.
- Click + Create Bot and pick a unique handle. This handle is the name
users will
@-mention.
- Copy the
bot_β¦ token shown in the dialog β it's only displayed once.
- Click Edit on the bot row to set its avatar, description, and whether
it appears in the public directory (botfather-style).
2. Authenticate
Send the bot token on every request:
X-API-Key: bot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or
Authorization: Bearer bot_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3. Poll for messages
Bots cannot open a WebSocket β they poll. Keep track of the highest
message id you've seen, and act on anything newer:
import requests, time
BOT_TOKEN = "bot_β¦"
CHANNEL = "general"
SERVER = "https://frogtalk.xyz"
last_seen = 0
while True:
r = requests.get(
f"{SERVER}/api/external/channels/{CHANNEL}/messages",
headers={"X-API-Key": BOT_TOKEN},
params={"limit": 50},
timeout=15,
)
for m in r.json()["messages"]:
if m["id"] <= last_seen:
continue
last_seen = max(last_seen, m["id"])
# β¦ your logic β¦
time.sleep(2)
4. Reply
requests.post(
f"{SERVER}/api/external/channels/{CHANNEL}/messages",
headers={"X-API-Key": BOT_TOKEN},
json={"content": "hello, world!", "reply_to": m["id"]},
timeout=15,
)
Setting reply_to threads the bot's reply under the trigger message so users see the quoted parent.
5. Profile (botfather-style)
PUT /api/developer/bots/{bot_id} updates the bot's profile. Uses your user
session (not the bot key), so typically you'll use the in-app Edit dialog.
| Field | Type | Notes |
name | string | unique handle (β€32 chars) |
avatar | string | URL or data: URL |
description | string | shown in the directory (β€500 chars) |
is_public | bool | list publicly |
Etiquette & limits
- Rate limit:
POST /channels/{name}/messages is capped at
30 req/min per bot key. Stay well under it.
- No mention spam: only reply when the bot is explicitly addressed
(an
@mention in the message text, or a reply_to pointing at one
of your own messages).
- Don't impersonate: the BOT pill cannot be hidden.
- Be transparent: set a useful description so users understand what
data your bot processes.
Examples & SDK
Complete, runnable reference bots live in the FrogTalk repo under
bot-examples/.
Clone the repo, drop in your bot_β¦ token, and run.
π€ runpod-ai-bot — AI chat bot (Python)
A mention-driven AI chat bot powered by a RunPod
serverless LLM endpoint. Polls public channels, replies when @-mentioned or
when a user replies to its own message. ~200 lines, no async framework required.
Sends the conversation to the worker as an OpenAI-style
messages=[β¦] list so the vLLM worker applies the model's own chat
template — swap in any modern instruct model (Qwen, Mistral-Small /
MythoMax, Llama-3, etc.) with no code changes. Default endpoint runs
Gryphe/MythoMax-L2-13b (uncensored Llama-2 roleplay finetune).
Auto-falls-back to a raw Alpaca-style prompt if the worker reports the
loaded model has no chat template registered.
Includes a refusal-detection retry that catches canned RLHF safety output
and re-rolls at higher temperature with a stronger jailbreak preface.
π Quick start (60 seconds)
git clone https://github.com/deadinternetfox/frogtalk.git
cd frogtalk/bot-examples/runpod-ai-bot
# 1. Install deps
pip install -r requirements.txt
# 2. Configure
cp .env.example .env
$EDITOR .env # paste your FROGTALK_BOT_TOKEN and RUNPOD_* values
# 3. Run
python bot.py
π§ͺ Minimal bot in 20 lines
Don't want the full example? Here's the smallest useful loop — reads new messages
from a channel and replies to mentions:
import os, time, requests
TOKEN = os.environ["FROGTALK_BOT_TOKEN"] # bot_xxx from /api/developer/bots
BASE = "https://frogtalk.xyz/api/external"
CHANNEL = "general"
HEADERS = {"X-API-Key": TOKEN}
seen = set()
while True:
r = requests.get(f"{BASE}/channels/{CHANNEL}/messages?limit=20", headers=HEADERS, timeout=10)
for m in r.json().get("messages", []):
if m["id"] in seen: continue
seen.add(m["id"])
if "@mybot" in (m.get("text") or "").lower():
requests.post(
f"{BASE}/channels/{CHANNEL}/messages",
headers=HEADERS,
json={"text": f"hi @{m['nickname']} π", "reply_to": m["id"]},
timeout=10,
)
time.sleep(5)
π¦ TypeScript / Node.js
const TOKEN = process.env.FROGTALK_BOT_TOKEN!;
const BASE = "https://frogtalk.xyz/api/external";
const CHANNEL = "general";
const headers = { "X-API-Key": TOKEN, "Content-Type": "application/json" };
const seen = new Set<number>();
async function tick() {
const r = await fetch(`${BASE}/channels/${CHANNEL}/messages?limit=20`, { headers });
const { messages = [] } = await r.json();
for (const m of messages) {
if (seen.has(m.id)) continue;
seen.add(m.id);
if ((m.text || "").toLowerCase().includes("@mybot")) {
await fetch(`${BASE}/channels/${CHANNEL}/messages`, {
method: "POST", headers,
body: JSON.stringify({ text: `hi @${m.nickname} π`, reply_to: m.id }),
});
}
}
}
setInterval(tick, 5000);
Want to contribute another reference bot
(TypeScript, Go, Rust, a Discord-style command bot, an RSS posterβ¦)? Open a PR against
bot-examples/.