Skip to content
sonapersonal assistant
Channels

Telegram

Telegram is optional. sona init + sona chat work without a bot. Use this page when you want the same assistant on your phone.

The adapter long-polls the Bot API, so you don't need a public IP, a tunnel, or a webhook server — Sona pulls updates over an outbound HTTPS connection.

Get a bot token

  1. Open Telegram, search for @BotFather, start a chat.
  2. Send /newbot.
  3. Pick a display name — what users will see in the chat header. Anything goes.
  4. Pick a username — must be globally unique and end in _bot (e.g. myname_sona_bot).
  5. BotFather replies with the token. It looks like 123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11.

Keep the token secret — anyone with it can impersonate your bot.

Optional but useful, still in BotFather:

  • /setdescription — short blurb users see before the first message
  • /setabouttext — long description on the bot's profile page
  • /setuserpic — bot avatar
  • /setcommands — populate the slash-command menu (see slash commands below)
  • /setjoingroups and /setprivacy — group behaviour (default: groups disabled, "privacy mode" on so the bot only sees commands and mentions)

Wire it into Sona

Prefer the channel command (does not re-run the full wizard):

sona channel add telegram

Paste the token, or confirm the env var if TELEGRAM_BOT_TOKEN is already set. You can still edit the file directly:

# ~/.sona/sona.yml
channels:
  telegram:
    token: ${TELEGRAM_BOT_TOKEN}   # or paste the literal string

The ${VAR} form makes Sona read from the environment at boot — you keep the token out of the config file but still tie it to the channel config. If you'd rather paste the literal token, that works too.

Restart the daemon:

sona stop
sona

On a healthy start you should see:

INFO  c.t.c.t.TelegramAdapter [] - Telegram adapter started — listening for messages

If you see Unauthorized in the logs, the token is wrong or revoked — re-issue via BotFather /token and try again.

First message + pairing

Open t.me/<your_bot_username> and send hi.

A fresh install has no owner. The bot asks you to reply YES in that same chat — no second terminal, no pairing code.

You: hi
Bot: Hi! This Sona has no owner yet. Reply YES to claim it.
You: YES
Bot: You're the owner of this Sona.

After that, unknown senders get an 8-character pairing code. You approve them:

sona pair list              # pending + approved
sona pair approve AB3K7NPM  # 8 chars, A–Z 2–9 (no 0 O 1 I)

Do not pass telegram:<userId> to approve. That is not a pairing code.

Pairing is per-(channelId, senderId). Approving someone on Telegram does not approve the same person on Slack.

Slash commands

Telegram's slash-command menu helps users discover what a bot can do. Set the menu from BotFather:

/setcommands
@your_bot_username
help - What can this bot do?
new - Start a new conversation
stop - Stop the current task

Sona doesn't currently parse slash commands into special behaviours — they flow into the gateway like any other text. If you want a command to do something specific, register a skill whose match() looks for the /help prefix.

Threads, groups, and multi-user chats

By default Telegram bots only see DMs and messages that mention them. To use Sona in a group:

  1. In BotFather: /mybots → pick your bot → Bot SettingsGroup PrivacyTurn off. (This lets the bot see every message in the group, not just @mentions.)
  2. Add the bot to the group.
  3. Anyone in the group can now talk to it — but pairing applies per-user, so you'll need to approve each user that should be allowed to use the LLM budget.

For 1:1 DMs Sona's session boundary is the user's Telegram ID; conversations across days resume from where they left off (until the daemon is restarted with sona uninstall, or you explicitly purge ~/.sona/sessions/).

Media

The adapter accepts inbound photos, documents, and voice notes; they're attached to the UnifiedMessage as Attachment records. What happens next depends on whether your configured LLM is vision-capable:

AttachmentVision LLM (Claude Sonnet, GPT-4o, Gemini Vision)Text-only LLM
PhotoEncoded inline; passed to the LLM as image inputLogged, not sent to the LLM
Document (PDF, txt)If a tool's wired for it (tnsai-tools PDF / text), the agent can ask for content; otherwise loggedSame
Voice noteNot yet wired — tracked in tnsai-tools STT toolkit

For outbound media, the adapter renders UnifiedResponse.attachments as Telegram media — Sona doesn't ship outbound-media skills today, but the SPI supports it.

Privacy + audit

Sona logs every inbound message + the LLM reply to ~/.sona/sona.log (and the per-session JSON in ~/.sona/sessions/). The Telegram chat metadata (user ID, message ID, timestamps) is in the audit log; the LLM's API call to the provider follows the provider's own retention policy.

If you need a redaction filter on the way in — e.g. strip emails or credit-card numbers before they reach the LLM — see the framework's redaction guide. Wiring it through Sona is one extra config block; no code change.

Troubleshooting

SymptomCauseFix
Unauthorized in logsToken wrong / revokedRe-issue via BotFather /token, then sona channel add telegram
Conflict: terminated by other getUpdates requestAnother process is polling the same botStop the other process; only one consumer per token
Bot is added to a group but doesn't respondGroup privacy is onBotFather → bot settings → group privacy → turn off
Message reaches Sona logs but no replyLLM key is invalid, or budget is exhaustedCheck sona logs --grep ERROR -i for the provider's response
First hi does not ask for YESThis install already has an ownerExpected — later senders get an 8-char pairing code
sona pair approve says "no such code"Daemon restarted between code-issue and approveIssue a new one by sending a new message

Removing the bot

To stop using a bot but keep its token alive for future use:

# ~/.sona/sona.yml
channels: {}     # empty map = no adapters at boot

then sona stop && sona. The bot exists on Telegram's side until you /deletebot via BotFather.