Files
2026-07-24 22:36:04 +03:00

84 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Relay Bot
Relay Bot is a self-hosted Telegram assistant for a small software team. It keeps only messages received after it is connected, reads one Git repository in read-only mode, and answers short, source-grounded questions. It is intentionally not an architect, code-review system, task manager, or replacement for a senior engineer.
## MVP boundaries
The bot uses Telegram long polling and PostgreSQL. It does not retrieve old group history (Telegram Bot API does not expose it), create commits/PRs, index embeddings, download random group files, or turn chat/repository content into instructions. Webhooks, automatic archive extraction, and rich document workflows are deliberately outside this MVP.
## Setup
1. Create a bot with [@BotFather](https://t.me/BotFather), copy its token, and disable **Privacy Mode** (or make it a group administrator) so it receives ordinary group messages.
2. Add the bot to the project group. Obtain your numeric Telegram user ID and the group chat ID (they are not usernames). Set the owner as `OWNER_TELEGRAM_ID` and the group as `PROJECT_GROUP_ID`.
3. Create a DeepSeek API key and set `DEEPSEEK_API_KEY`. The API is used through its OpenAI-compatible endpoint.
4. Copy configuration and fill the required values:
```bash
cp .env.example .env
```
`REPOSITORY_URL` is optional: it provides an initial fallback repository. The recommended flow is to send the owner message `посмотри этот репозиторий: https://github.com/acme/project`. Relay Bot attaches that repository to the current chat/topic. For a private HTTPS repository, set the token separately; it is injected only for the Git operation, is never persisted in the database or logged, and is not sent to the model.
5. Start the service:
```bash
docker compose up --build
```
The container runs `alembic upgrade head` before polling. PostgreSQL uses a persistent Docker volume and the bot waits for its health check.
For local checks, use Python 3.12+:
```bash
python -m pip install -e '.[dev]'
pytest
ruff check .
ruff format --check .
```
## Configuration
Required secrets and endpoints are kept only in environment variables:
| Variable | Purpose |
| --- | --- |
| `TELEGRAM_BOT_TOKEN` | BotFather token |
| `DEEPSEEK_API_KEY`, `DEEPSEEK_BASE_URL`, `DEEPSEEK_MODEL` | DeepSeek client configuration |
| `DATABASE_URL` | async SQLAlchemy PostgreSQL URL |
| `REPOSITORY_URL`, `REPOSITORY_BRANCH` | optional initial read-only project repository |
| `REPOSITORY_ACCESS_TOKEN` | optional private HTTPS repository credential |
| `OWNER_TELEGRAM_ID`, `PROJECT_GROUP_ID` | numeric authorization allowlist |
| `BOT_TIMEZONE`, `LOG_LEVEL` | operation settings |
Additional limits in `.env.example` cap repository file size, attachment size, context, summary trigger, confidence, and proactive cooldown.
## Commands
Everyone in the configured project group or the owner’s private chat can use `/start`, `/help`, `/ask <question>`, `/context`, `/status`, `/forget_me`, and `/cancel`. The owner can attach a repository in natural language: `посмотри этот репозиторий: https://github.com/acme/project`, or explicitly with `/repo <URL>` (the `/syncrepo <URL>` alias is also supported). `/sync_repo` only updates an already attached repository.
Only the numeric owner ID can use `/set_prompt`, `/show_prompt`, `/prompt_history`, `/rollback_prompt`, `/summarize`, `/sync_repo`, `/repo_status`, `/proactive off|mentions|safe|active`, `/memory_status`, and `/settings`. `/set_prompt` opens a one-message private-chat flow. The owner’s prompt augments, never replaces, the immutable safety prompt.
## Memory and answers
Each incoming message is saved separately with chat, topic/thread, user, reply, edit, type, and attachment metadata. Group, owner-DM, participant-DM, and forum topics remain separate by chat/topic keys. Old originals are retained after a versioned summary is made. A summary is generated per chat/topic on `/summarize`; the service also exposes an automatic token threshold for scheduling during normal operation.
Answers receive: immutable safety rules, active owner metaprompt, the latest summary, recent messages, and limited repository evidence. A dynamically attached repository is stored per chat/topic and cloned with Git partial-clone filtering (`blob:none`): the bot receives the Git tree and history first, then fetches the content of only a file it explicitly reads. Repository research uses a bounded tool-selection pass: directory map, filename search, safe ranged read, commit log, diff/stat, and file information. It never sends whole repositories. Answers should name an exact path or commit; absence of evidence is reported as needing a human decision.
## Proactivity
Default `safe` mode uses a cheap classification step and may reply without a mention only when a project question is factual, non-rhetorical, high-confidence, not a new decision, and not suppressed by duplicate/cooldown protection. `mentions` requires an explicit mention, `off` suppresses proactive replies, and `active` is reserved for extra blocker/contradiction detection. The bot does not routinely interrupt unknown questions; questions requiring a new design or management choice are left to the owner.
## Files, privacy, and safety
Group documents are ignored unless the bot is explicitly mentioned in the caption, the user replies with an explicit read request, or a future explicit command invokes processing. Files sent in a private bot chat are eligible. Supported MVP formats are `.txt`, `.md`, `.json`, `.yaml/.yml`, `.csv`, text-extractable `.pdf`, and `.docx`; executables and archives are rejected. Size and extracted-text limits apply. File contents are untrusted data, never policy instructions.
Only the configured group and the owner private chat are accepted; unknown groups are ignored. Repository paths are contained under the clone, sensitive names/extensions and common generated/vendor directories are excluded, and subprocesses use argument lists rather than shell interpolation. Logs contain operational metadata, not tokens, keys, full private messages, or attachment content. `/forget_me` deletes a user’s individual message records where permitted; project summaries may retain an aggregate historical fact.
## Common problems
- **Bot sees only commands:** disable Privacy Mode or grant appropriate group administrator access, then re-add/restart the bot.
- **No group response:** check the numeric negative `PROJECT_GROUP_ID`, the selected proactive mode, confidence threshold, and cooldown.
- **Repository sync fails:** verify URL, branch, and private HTTPS token; do not put the token in the URL.
- **Model unavailable:** verify DeepSeek URL/key/model and retry; temporary API failures are retried with exponential backoff.
- **Database connection fails:** wait for the Compose health check and keep `DATABASE_URL` pointed at `postgres` from inside Docker.