Metadata-Version: 2.4
Name: kestrel-channel-telegram
Version: 0.1.1
Summary: Telegram channel for Kestrel agents — isolated-venv feature (Telegram Bot API).
License-Expression: MIT
Requires-Python: <3.15,>=3.11
Requires-Dist: kestrel-sovereign-sdk<1,>=0.29.0
Provides-Extra: service
Requires-Dist: httpx<1,>=0.27; extra == 'service'
Description-Content-Type: text/markdown

# kestrel-channel-telegram

Telegram channel for [Kestrel](https://github.com/KestrelSovereignAI/kestrel-sovereign)
agents — an **isolated-venv feature** where the agent talks over a Telegram
**bot** it owns (a Bot API token), not a device grafted onto a personal account.

Unlike the WhatsApp channel (a companion device linked to a personal number),
Telegram gives the agent its **own identity** with almost no friction:

- Create a bot with [@BotFather](https://t.me/BotFather) → you get a **token**.
  No phone number, no QR, no linked device.
- You DM the bot; the agent replies **as the bot**.
- Access is **default-deny**: with an empty `allowed_senders` the bot replies to
  no one. Send `/start` to the bot and it tells you your Telegram user id; add
  that id (or your `@username`) to `allowed_senders` to enable the conversation.

## Setup — the agent walks you through it

You don't need to remember these steps: enable the feature and **ask the agent to
set up Telegram**. It calls `telegram_status`, which returns a plain-language
`next_step`, and guides you through whichever step is next. The full flow:

1. **Create the bot** *(only you can do this — it's in your Telegram)*:
   - Open Telegram, search **@BotFather** (the blue-check official one), press
     **Start**.
   - Send **`/newbot`**, choose a **name** (e.g. `Emma`) and a **username** ending
     in `bot` (e.g. `emma_kestrel_bot`).
   - BotFather replies with a **token** like `12345678:AAExample…` (~46 chars).
     Copy it. *(It's the bot's password — keep it private; it's fine to give to
     the agent/operator to store in config.)*
2. **Configure the token**: save the token in this feature's config (`token`) via
   the features UI (or hand it to the operator). The agent tells you when it's
   set and connected (as your bot's `@username`).
3. **Get on the allowlist** *(this is how you get access — default-deny)*:
   - Ask the agent for the link, or run `telegram_link` → it returns
     `https://t.me/<your_bot>`.
   - Open it, press **Start**, send **`/start`** → the bot replies with **your
     numeric Telegram id**.
   - Add that id (or your `@username`) to **`allowed_senders`**.
4. **Chat**: DM the bot — the agent replies. Done.

> **What the agent does vs. what you do.** The agent can't create your bot or read
> your Telegram, so steps 1 and the `/start` in step 3 are yours. Everything else
> — telling you exactly what's missing (`telegram_status.next_step`), handing you
> the `t.me` link (`telegram_link`), and surfacing your id from `/start` — the
> agent drives. Setting the token/allowlist config today goes through the features
> UI/operator; an agent-side `feature_configure` tool would let the agent do that
> for you too (planned).

## How it works

The package has two roles (same shape as `kestrel-channel-whatsapp`):

- **Discovery marker** `TelegramFeature` (SDK-only) — installed into the host.
- **Transport service** `kestrel_channel_telegram.service` — its only dep is
  `httpx` (the `[service]` extra), installed by the host loader into a per-agent
  isolated venv and run as the `kestrel-telegram-service` console script over the
  SDK stdio JSON-RPC contract.

The service:

- registers `telegram_send`, `telegram_status`, `telegram_link` tools;
- long-polls the Bot API (`getUpdates`) for inbound and emits `channel.inbound`
  for **allowed** senders (routed into `ChannelFeature.handle_inbound`);
- sends via `sendMessage`.

## Config

| key | meaning |
|-----|---------|
| `enabled` | turn the channel on/off |
| `token` | Bot API token from @BotFather (the agent's identity) |
| `allowed_senders` | Telegram numeric user ids or `@usernames` allowed to DM the agent. **Empty = deny all.** |

## Development

```bash
uv run --no-project --with "kestrel-sovereign-sdk>=0.29.0" --with httpx \
  --with pytest --with pytest-asyncio python -m pytest -q
```

## Release

Bump `version` in `pyproject.toml` (+ `uv.lock`), tag `vX.Y.Z`; `publish.yml`
verifies the tag matches and publishes to PyPI via OIDC trusted publishing
(`environment: pypi`).

## License

MIT
