voiceroute.py 0.1.0.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. voiceroute_py-0.1.0.dev0/.editorconfig +13 -0
  2. voiceroute_py-0.1.0.dev0/.env.example +6 -0
  3. voiceroute_py-0.1.0.dev0/.github/workflows/ci.yml +39 -0
  4. voiceroute_py-0.1.0.dev0/.gitignore +16 -0
  5. voiceroute_py-0.1.0.dev0/CHANGELOG.md +26 -0
  6. voiceroute_py-0.1.0.dev0/CONTRIBUTING.md +45 -0
  7. voiceroute_py-0.1.0.dev0/LICENSE +22 -0
  8. voiceroute_py-0.1.0.dev0/PKG-INFO +170 -0
  9. voiceroute_py-0.1.0.dev0/README.md +130 -0
  10. voiceroute_py-0.1.0.dev0/SECURITY.md +11 -0
  11. voiceroute_py-0.1.0.dev0/docs/api-coverage.md +34 -0
  12. voiceroute_py-0.1.0.dev0/docs/architecture.md +80 -0
  13. voiceroute_py-0.1.0.dev0/docs/commands.md +158 -0
  14. voiceroute_py-0.1.0.dev0/docs/content-api.md +65 -0
  15. voiceroute_py-0.1.0.dev0/docs/events.md +64 -0
  16. voiceroute_py-0.1.0.dev0/docs/extensions.md +86 -0
  17. voiceroute_py-0.1.0.dev0/docs/network.md +38 -0
  18. voiceroute_py-0.1.0.dev0/docs/roadmap.md +42 -0
  19. voiceroute_py-0.1.0.dev0/docs/runtime.md +121 -0
  20. voiceroute_py-0.1.0.dev0/docs/voiceroute-bot-platform-api-spec.md +1916 -0
  21. voiceroute_py-0.1.0.dev0/examples/__init__.py +1 -0
  22. voiceroute_py-0.1.0.dev0/examples/community_assistant/README.md +74 -0
  23. voiceroute_py-0.1.0.dev0/examples/community_assistant/__init__.py +5 -0
  24. voiceroute_py-0.1.0.dev0/examples/community_assistant/bot.py +45 -0
  25. voiceroute_py-0.1.0.dev0/examples/community_assistant/config.py +57 -0
  26. voiceroute_py-0.1.0.dev0/examples/community_assistant/data/faq.json +17 -0
  27. voiceroute_py-0.1.0.dev0/examples/community_assistant/extensions/__init__.py +1 -0
  28. voiceroute_py-0.1.0.dev0/examples/community_assistant/extensions/diagnostics.py +103 -0
  29. voiceroute_py-0.1.0.dev0/examples/community_assistant/extensions/general.py +55 -0
  30. voiceroute_py-0.1.0.dev0/examples/community_assistant/extensions/knowledge.py +101 -0
  31. voiceroute_py-0.1.0.dev0/examples/community_assistant/extensions/messages.py +164 -0
  32. voiceroute_py-0.1.0.dev0/examples/identify_bot.py +24 -0
  33. voiceroute_py-0.1.0.dev0/examples/ping_bot.py +42 -0
  34. voiceroute_py-0.1.0.dev0/pyproject.toml +78 -0
  35. voiceroute_py-0.1.0.dev0/src/voiceroute/__init__.py +149 -0
  36. voiceroute_py-0.1.0.dev0/src/voiceroute/api/__init__.py +8 -0
  37. voiceroute_py-0.1.0.dev0/src/voiceroute/api/bots.py +40 -0
  38. voiceroute_py-0.1.0.dev0/src/voiceroute/api/communities.py +36 -0
  39. voiceroute_py-0.1.0.dev0/src/voiceroute/api/events.py +86 -0
  40. voiceroute_py-0.1.0.dev0/src/voiceroute/api/messages.py +215 -0
  41. voiceroute_py-0.1.0.dev0/src/voiceroute/bot.py +535 -0
  42. voiceroute_py-0.1.0.dev0/src/voiceroute/client.py +48 -0
  43. voiceroute_py-0.1.0.dev0/src/voiceroute/commands/__init__.py +41 -0
  44. voiceroute_py-0.1.0.dev0/src/voiceroute/commands/context.py +81 -0
  45. voiceroute_py-0.1.0.dev0/src/voiceroute/commands/core.py +263 -0
  46. voiceroute_py-0.1.0.dev0/src/voiceroute/commands/pipeline.py +257 -0
  47. voiceroute_py-0.1.0.dev0/src/voiceroute/commands/prefix.py +44 -0
  48. voiceroute_py-0.1.0.dev0/src/voiceroute/config.py +18 -0
  49. voiceroute_py-0.1.0.dev0/src/voiceroute/errors.py +191 -0
  50. voiceroute_py-0.1.0.dev0/src/voiceroute/events/__init__.py +38 -0
  51. voiceroute_py-0.1.0.dev0/src/voiceroute/events/cursors.py +245 -0
  52. voiceroute_py-0.1.0.dev0/src/voiceroute/events/models.py +24 -0
  53. voiceroute_py-0.1.0.dev0/src/voiceroute/events/sse.py +63 -0
  54. voiceroute_py-0.1.0.dev0/src/voiceroute/events/transport.py +172 -0
  55. voiceroute_py-0.1.0.dev0/src/voiceroute/extensions.py +79 -0
  56. voiceroute_py-0.1.0.dev0/src/voiceroute/models/__init__.py +8 -0
  57. voiceroute_py-0.1.0.dev0/src/voiceroute/models/bot.py +21 -0
  58. voiceroute_py-0.1.0.dev0/src/voiceroute/models/community.py +68 -0
  59. voiceroute_py-0.1.0.dev0/src/voiceroute/models/message.py +75 -0
  60. voiceroute_py-0.1.0.dev0/src/voiceroute/models/user.py +23 -0
  61. voiceroute_py-0.1.0.dev0/src/voiceroute/runtime.py +13 -0
  62. voiceroute_py-0.1.0.dev0/src/voiceroute/transport/__init__.py +6 -0
  63. voiceroute_py-0.1.0.dev0/src/voiceroute/transport/auth.py +18 -0
  64. voiceroute_py-0.1.0.dev0/src/voiceroute/transport/http.py +204 -0
  65. voiceroute_py-0.1.0.dev0/src/voiceroute/transport/rate_limit.py +45 -0
  66. voiceroute_py-0.1.0.dev0/tests/contract/README.md +5 -0
  67. voiceroute_py-0.1.0.dev0/tests/contract/test_communities_api.py +27 -0
  68. voiceroute_py-0.1.0.dev0/tests/contract/test_http_transport.py +135 -0
  69. voiceroute_py-0.1.0.dev0/tests/contract/test_messages_api.py +187 -0
  70. voiceroute_py-0.1.0.dev0/tests/examples/test_community_assistant.py +179 -0
  71. voiceroute_py-0.1.0.dev0/tests/integration/README.md +5 -0
  72. voiceroute_py-0.1.0.dev0/tests/unit/test_auth.py +15 -0
  73. voiceroute_py-0.1.0.dev0/tests/unit/test_bot.py +249 -0
  74. voiceroute_py-0.1.0.dev0/tests/unit/test_command_framework.py +193 -0
  75. voiceroute_py-0.1.0.dev0/tests/unit/test_command_pipeline.py +181 -0
  76. voiceroute_py-0.1.0.dev0/tests/unit/test_community_models.py +47 -0
  77. voiceroute_py-0.1.0.dev0/tests/unit/test_config.py +15 -0
  78. voiceroute_py-0.1.0.dev0/tests/unit/test_context.py +133 -0
  79. voiceroute_py-0.1.0.dev0/tests/unit/test_cursor_store.py +103 -0
  80. voiceroute_py-0.1.0.dev0/tests/unit/test_event_transport.py +69 -0
  81. voiceroute_py-0.1.0.dev0/tests/unit/test_events_api.py +60 -0
  82. voiceroute_py-0.1.0.dev0/tests/unit/test_extensions.py +188 -0
  83. voiceroute_py-0.1.0.dev0/tests/unit/test_message_models.py +21 -0
  84. voiceroute_py-0.1.0.dev0/tests/unit/test_models.py +18 -0
  85. voiceroute_py-0.1.0.dev0/tests/unit/test_rate_limit.py +32 -0
  86. voiceroute_py-0.1.0.dev0/tests/unit/test_runtime_lifecycle.py +170 -0
  87. voiceroute_py-0.1.0.dev0/tests/unit/test_sse.py +28 -0
@@ -0,0 +1,13 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ indent_style = space
8
+ indent_size = 4
9
+ trim_trailing_whitespace = true
10
+
11
+ [*.{md,yml,yaml}]
12
+ indent_size = 2
13
+
@@ -0,0 +1,6 @@
1
+ VOICEROUTE_URL=https://dev.voiceroute.cc
2
+ VOICEROUTE_BOT_TOKEN=vrb_replace_me
3
+ # Необязательные ограничения для бота, слушающего только один канал:
4
+ # VOICEROUTE_COMMUNITY_ID=00000000-0000-4000-8000-000000000000
5
+ # VOICEROUTE_CHANNEL_ID=00000000-0000-4000-8000-000000000000
6
+
@@ -0,0 +1,39 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ quality:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.11"
19
+ cache: pip
20
+ - run: python -m pip install -e '.[dev]'
21
+ - run: ruff check .
22
+ - run: ruff format --check .
23
+ - run: mypy src
24
+
25
+ tests:
26
+ runs-on: ubuntu-latest
27
+ strategy:
28
+ fail-fast: false
29
+ matrix:
30
+ python-version: ["3.11", "3.12", "3.13"]
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+ - uses: actions/setup-python@v5
34
+ with:
35
+ python-version: ${{ matrix.python-version }}
36
+ cache: pip
37
+ - run: python -m pip install -e '.[dev]'
38
+ - run: pytest --cov=voiceroute --cov-report=term-missing
39
+
@@ -0,0 +1,16 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .coverage
5
+ .env
6
+ .idea/
7
+ .mypy_cache/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .venv/
11
+ .voiceroute/
12
+ .vscode/
13
+ build/
14
+ dist/
15
+ htmlcov/
16
+
@@ -0,0 +1,26 @@
1
+ # История изменений
2
+
3
+ Проект следует [Semantic Versioning](https://semver.org/) и рекомендациям
4
+ [Keep a Changelog](https://keepachangelog.com/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ### Added
9
+
10
+ - Начальная структура Python-пакета.
11
+ - Асинхронный HTTP transport и bot-аутентификация.
12
+ - Базовые модели и API профиля текущего бота.
13
+ - Восстанавливаемые SSE-потоки с checkpoint после успешной обработки.
14
+ - Атомарное файловое и process-local хранилища cursor.
15
+ - Общий sliding-window rate limiter и безопасные retry с учётом `Retry-After`.
16
+ - Постраничное восстановление backlog перед переходом к live SSE.
17
+ - Публичный `EventTransport` и `LegacySSETransport`, отделяющие runtime от сетевого
18
+ протокола событий.
19
+ - Независимые `Command`, `CommandRegistry`, `CommandInvocation` и
20
+ `PrefixCommandAdapter` с aliases, группами, типизированными аргументами и command
21
+ lifecycle events.
22
+ - Command pipeline с async middleware, checks, cooldowns и concurrency limits.
23
+ - Расширения с декларативными командами/listeners, атомарной регистрацией и module
24
+ load/unload/reload lifecycle.
25
+ - Явный runtime lifecycle, graceful shutdown и независимый supervision channel consumers.
26
+
@@ -0,0 +1,45 @@
1
+ # Участие в разработке
2
+
3
+ ## Ветки
4
+
5
+ Используйте общепринятые префиксы:
6
+
7
+ - `feature/` — новая функциональность;
8
+ - `fix/` — исправление ошибки;
9
+ - `docs/` — документация;
10
+ - `refactor/` — внутреннее изменение без нового поведения;
11
+ - `test/` — тесты;
12
+ - `chore/` — инфраструктура и обслуживание;
13
+ - `release/` — подготовка выпуска;
14
+ - `hotfix/` — срочное исправление стабильной версии.
15
+
16
+ Ветки с префиксом `codex/` запрещены.
17
+
18
+ ## Коммиты
19
+
20
+ Сообщения пишутся на английском языке в формате Conventional Commits со scope:
21
+
22
+ ```text
23
+ feat(events): add resumable channel stream
24
+ fix(http): preserve idempotency key across retries
25
+ docs(readme): document development setup
26
+ ```
27
+
28
+ ## Слияния
29
+
30
+ - изменения попадают в `main` через pull request;
31
+ - fast-forward merge запрещён;
32
+ - используйте merge commit (`git merge --no-ff`);
33
+ - перед слиянием должны пройти lint, format, type check и tests;
34
+ - публичное поведение сопровождается тестами и документацией;
35
+ - несовместимые изменения до `1.0.0` явно отмечаются в changelog.
36
+
37
+ ## Локальная проверка
38
+
39
+ ```bash
40
+ ruff check .
41
+ ruff format --check .
42
+ mypy src
43
+ pytest
44
+ ```
45
+
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dog-bobik
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.5
2
+ Name: voiceroute.py
3
+ Version: 0.1.0.dev0
4
+ Summary: Async Python SDK and bot framework for the VoiceRoute HTTP and SSE APIs.
5
+ Project-URL: Homepage, https://github.com/dog-bobik/voiceroute.py
6
+ Project-URL: Documentation, https://github.com/dog-bobik/voiceroute.py#readme
7
+ Project-URL: Issues, https://github.com/dog-bobik/voiceroute.py/issues
8
+ Project-URL: Repository, https://github.com/dog-bobik/voiceroute.py.git
9
+ Author: dog-bobik
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: asyncio,bot,sdk,sse,voiceroute
13
+ Classifier: Development Status :: 2 - Pre-Alpha
14
+ Classifier: Framework :: AsyncIO
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: httpx<1,>=0.27
24
+ Provides-Extra: dev
25
+ Requires-Dist: mypy>=1.13; extra == 'dev'
26
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
27
+ Requires-Dist: pytest-cov>=6; extra == 'dev'
28
+ Requires-Dist: pytest>=8.3; extra == 'dev'
29
+ Requires-Dist: python-dotenv<2,>=1.0; extra == 'dev'
30
+ Requires-Dist: respx>=0.22; extra == 'dev'
31
+ Requires-Dist: ruff>=0.8; extra == 'dev'
32
+ Provides-Extra: docs
33
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
34
+ Requires-Dist: mkdocstrings[python]>=0.27; extra == 'docs'
35
+ Provides-Extra: examples
36
+ Requires-Dist: python-dotenv<2,>=1.0; extra == 'examples'
37
+ Provides-Extra: redis
38
+ Requires-Dist: redis<8,>=5; extra == 'redis'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # voiceroute.py
42
+
43
+ Асинхронный Python SDK и фреймворк для разработки ботов в
44
+ [VoiceRoute](https://voiceroute.cc).
45
+
46
+ > [!WARNING]
47
+ > Проект находится на ранней стадии разработки. Публичный API может меняться до
48
+ > выпуска версии `1.0.0`.
49
+
50
+ ## Цели проекта
51
+
52
+ - типизированный асинхронный клиент HTTP API;
53
+ - надёжная обработка SSE с восстановлением курсора;
54
+ - идемпотентная отправка сообщений;
55
+ - удобная событийная модель и команды в стиле современных bot-фреймворков;
56
+ - расширяемая архитектура без смешивания bot token и пользовательской сессии;
57
+ - безопасная работа с лимитами запросов, повторными попытками и секретами.
58
+
59
+ ## Установка для разработки
60
+
61
+ Требуется Python 3.11 или новее.
62
+
63
+ ```bash
64
+ python -m venv .venv
65
+ source .venv/bin/activate
66
+ python -m pip install -e '.[dev]'
67
+ ```
68
+
69
+ Примеры автоматически читают локальный `.env` из корня репозитория. В нём
70
+ достаточно указать `VOICEROUTE_BOT_TOKEN`; production используется по умолчанию.
71
+
72
+ Полноценный демонстрационный пример: [Community Assistant Bot](examples/community_assistant/README.md).
73
+
74
+ ## Минимальный бот
75
+
76
+ ```python
77
+ import os
78
+
79
+ from voiceroute import Bot, Context, FileCursorStore
80
+
81
+ bot = Bot(
82
+ token=os.environ["VOICEROUTE_BOT_TOKEN"],
83
+ cursor_store=FileCursorStore(".voiceroute/cursors.json"),
84
+ )
85
+
86
+
87
+ @bot.command()
88
+ async def ping(context: Context) -> None:
89
+ await context.reply("Pong!")
90
+
91
+
92
+ bot.run()
93
+ ```
94
+
95
+ Ответ использует стабильный UUID, производный от исходного сообщения. Повторная
96
+ доставка SSE-события поэтому не создаст дубликат ответа.
97
+
98
+ По умолчанию команды принимают оба привычных префикса: `/ping` и `!ping`.
99
+ Собственный префикс задаётся через `Bot(..., command_prefix="?")`.
100
+
101
+ Команды поддерживают aliases, группы и типизированные позиционные аргументы. Метаданные и
102
+ вызов не зависят от prefix transport, поэтому будущие server-native interactions можно
103
+ будет подключить отдельным адаптером. Подробнее: [командный фреймворк](docs/commands.md).
104
+
105
+ Команды и listeners больших ботов можно объединять в расширения с атомарной загрузкой,
106
+ выгрузкой и reload. Подробнее: [расширения](docs/extensions.md).
107
+
108
+ Runtime поддерживает явные состояния, graceful shutdown и изоляцию channel consumers с
109
+ ограниченным backoff. Подробнее: [жизненный цикл runtime](docs/runtime.md).
110
+
111
+ Клиент умеет редактировать и удалять сообщения, управлять закреплением и реакцией,
112
+ читать pins и выполнять поиск. Подробнее: [контентный API](docs/content-api.md).
113
+
114
+ По умолчанию бот обнаруживает все доступные ему сообщества и текстовые каналы.
115
+ Для ограничения одним каналом можно явно передать `community_id` и `channel_id`.
116
+ При первом подключении он запрашивает историю после `seq=0`, чтобы не пропустить
117
+ команды, отправленные незадолго до запуска. Идемпотентные ответы защищают от
118
+ дубликатов при повторном получении тех же сообщений.
119
+
120
+ `FileCursorStore` атомарно сохраняет обработанную позицию с правами `0600`.
121
+ Cursor обновляется только после успешного завершения обработчика, поэтому после
122
+ сбоя событие будет доставлено повторно. Для нескольких процессов доступны SQLite и
123
+ Redis. Подробнее: [события и восстановление](docs/events.md).
124
+
125
+ Все HTTP-операции одного клиента используют общий лимитер 50 запросов в секунду.
126
+ Безопасные запросы и идемпотентная отправка сообщений повторяются после временных
127
+ сетевых ошибок; `429` соблюдает `Retry-After`. Подробнее: [сеть и повторы](docs/network.md).
128
+
129
+ ## Состояние реализации
130
+
131
+ | Возможность | Состояние |
132
+ | --- | --- |
133
+ | Bot-аутентификация | Основа готова |
134
+ | Профиль текущего бота | Основа готова |
135
+ | Сообщества и каналы | Базовое чтение готово |
136
+ | Сообщения | История, отправка и изменение готовы |
137
+ | Реакции, закрепления и поиск | Основа готова |
138
+ | SSE и восстановление курсора | Основа готова |
139
+ | Prefix-команды | Основа готова |
140
+ | Middleware | Основа готова |
141
+ | Треды и вложения | Запланировано |
142
+ | Роли и модерация | Запланировано |
143
+ | Голос для сторонних ботов | Не поддерживается API [VoiceRoute](https://voiceroute.cc) |
144
+
145
+ Подробная последовательность работ находится в [дорожной карте](docs/roadmap.md),
146
+ текущее покрытие — в [матрице API](docs/api-coverage.md), а принятые границы проекта —
147
+ в [описании архитектуры](docs/architecture.md).
148
+
149
+ ## Разработка
150
+
151
+ ```bash
152
+ ruff check .
153
+ ruff format --check .
154
+ mypy src
155
+ pytest --cov=voiceroute --cov-report=term-missing
156
+ ```
157
+
158
+ Правила веток, коммитов и слияний описаны в [CONTRIBUTING.md](CONTRIBUTING.md).
159
+
160
+ ## Безопасность
161
+
162
+ Не добавляйте bot token в исходный код, URL, query-параметры или логи. Используйте
163
+ переменные окружения и передавайте токен только через официальный заголовок
164
+ авторизации. Инструкции по сообщению об уязвимостях находятся в
165
+ [SECURITY.md](SECURITY.md).
166
+
167
+ ## Лицензия
168
+
169
+ [MIT](LICENSE)
170
+
@@ -0,0 +1,130 @@
1
+ # voiceroute.py
2
+
3
+ Асинхронный Python SDK и фреймворк для разработки ботов в
4
+ [VoiceRoute](https://voiceroute.cc).
5
+
6
+ > [!WARNING]
7
+ > Проект находится на ранней стадии разработки. Публичный API может меняться до
8
+ > выпуска версии `1.0.0`.
9
+
10
+ ## Цели проекта
11
+
12
+ - типизированный асинхронный клиент HTTP API;
13
+ - надёжная обработка SSE с восстановлением курсора;
14
+ - идемпотентная отправка сообщений;
15
+ - удобная событийная модель и команды в стиле современных bot-фреймворков;
16
+ - расширяемая архитектура без смешивания bot token и пользовательской сессии;
17
+ - безопасная работа с лимитами запросов, повторными попытками и секретами.
18
+
19
+ ## Установка для разработки
20
+
21
+ Требуется Python 3.11 или новее.
22
+
23
+ ```bash
24
+ python -m venv .venv
25
+ source .venv/bin/activate
26
+ python -m pip install -e '.[dev]'
27
+ ```
28
+
29
+ Примеры автоматически читают локальный `.env` из корня репозитория. В нём
30
+ достаточно указать `VOICEROUTE_BOT_TOKEN`; production используется по умолчанию.
31
+
32
+ Полноценный демонстрационный пример: [Community Assistant Bot](examples/community_assistant/README.md).
33
+
34
+ ## Минимальный бот
35
+
36
+ ```python
37
+ import os
38
+
39
+ from voiceroute import Bot, Context, FileCursorStore
40
+
41
+ bot = Bot(
42
+ token=os.environ["VOICEROUTE_BOT_TOKEN"],
43
+ cursor_store=FileCursorStore(".voiceroute/cursors.json"),
44
+ )
45
+
46
+
47
+ @bot.command()
48
+ async def ping(context: Context) -> None:
49
+ await context.reply("Pong!")
50
+
51
+
52
+ bot.run()
53
+ ```
54
+
55
+ Ответ использует стабильный UUID, производный от исходного сообщения. Повторная
56
+ доставка SSE-события поэтому не создаст дубликат ответа.
57
+
58
+ По умолчанию команды принимают оба привычных префикса: `/ping` и `!ping`.
59
+ Собственный префикс задаётся через `Bot(..., command_prefix="?")`.
60
+
61
+ Команды поддерживают aliases, группы и типизированные позиционные аргументы. Метаданные и
62
+ вызов не зависят от prefix transport, поэтому будущие server-native interactions можно
63
+ будет подключить отдельным адаптером. Подробнее: [командный фреймворк](docs/commands.md).
64
+
65
+ Команды и listeners больших ботов можно объединять в расширения с атомарной загрузкой,
66
+ выгрузкой и reload. Подробнее: [расширения](docs/extensions.md).
67
+
68
+ Runtime поддерживает явные состояния, graceful shutdown и изоляцию channel consumers с
69
+ ограниченным backoff. Подробнее: [жизненный цикл runtime](docs/runtime.md).
70
+
71
+ Клиент умеет редактировать и удалять сообщения, управлять закреплением и реакцией,
72
+ читать pins и выполнять поиск. Подробнее: [контентный API](docs/content-api.md).
73
+
74
+ По умолчанию бот обнаруживает все доступные ему сообщества и текстовые каналы.
75
+ Для ограничения одним каналом можно явно передать `community_id` и `channel_id`.
76
+ При первом подключении он запрашивает историю после `seq=0`, чтобы не пропустить
77
+ команды, отправленные незадолго до запуска. Идемпотентные ответы защищают от
78
+ дубликатов при повторном получении тех же сообщений.
79
+
80
+ `FileCursorStore` атомарно сохраняет обработанную позицию с правами `0600`.
81
+ Cursor обновляется только после успешного завершения обработчика, поэтому после
82
+ сбоя событие будет доставлено повторно. Для нескольких процессов доступны SQLite и
83
+ Redis. Подробнее: [события и восстановление](docs/events.md).
84
+
85
+ Все HTTP-операции одного клиента используют общий лимитер 50 запросов в секунду.
86
+ Безопасные запросы и идемпотентная отправка сообщений повторяются после временных
87
+ сетевых ошибок; `429` соблюдает `Retry-After`. Подробнее: [сеть и повторы](docs/network.md).
88
+
89
+ ## Состояние реализации
90
+
91
+ | Возможность | Состояние |
92
+ | --- | --- |
93
+ | Bot-аутентификация | Основа готова |
94
+ | Профиль текущего бота | Основа готова |
95
+ | Сообщества и каналы | Базовое чтение готово |
96
+ | Сообщения | История, отправка и изменение готовы |
97
+ | Реакции, закрепления и поиск | Основа готова |
98
+ | SSE и восстановление курсора | Основа готова |
99
+ | Prefix-команды | Основа готова |
100
+ | Middleware | Основа готова |
101
+ | Треды и вложения | Запланировано |
102
+ | Роли и модерация | Запланировано |
103
+ | Голос для сторонних ботов | Не поддерживается API [VoiceRoute](https://voiceroute.cc) |
104
+
105
+ Подробная последовательность работ находится в [дорожной карте](docs/roadmap.md),
106
+ текущее покрытие — в [матрице API](docs/api-coverage.md), а принятые границы проекта —
107
+ в [описании архитектуры](docs/architecture.md).
108
+
109
+ ## Разработка
110
+
111
+ ```bash
112
+ ruff check .
113
+ ruff format --check .
114
+ mypy src
115
+ pytest --cov=voiceroute --cov-report=term-missing
116
+ ```
117
+
118
+ Правила веток, коммитов и слияний описаны в [CONTRIBUTING.md](CONTRIBUTING.md).
119
+
120
+ ## Безопасность
121
+
122
+ Не добавляйте bot token в исходный код, URL, query-параметры или логи. Используйте
123
+ переменные окружения и передавайте токен только через официальный заголовок
124
+ авторизации. Инструкции по сообщению об уязвимостях находятся в
125
+ [SECURITY.md](SECURITY.md).
126
+
127
+ ## Лицензия
128
+
129
+ [MIT](LICENSE)
130
+
@@ -0,0 +1,11 @@
1
+ # Политика безопасности
2
+
3
+ Не публикуйте сведения об уязвимости в открытом issue до согласования исправления.
4
+ Свяжитесь с владельцем репозитория через приватный канал GitHub.
5
+
6
+ Никогда не прикладывайте к отчёту действующие bot token, cookie, пароль,
7
+ recovery code или полный секретный URL вебхука. Перед отправкой логов удалите из
8
+ них все секреты.
9
+
10
+ Поддерживаемые версии будут перечислены здесь после первого стабильного релиза.
11
+
@@ -0,0 +1,34 @@
1
+ # Покрытие API VoiceRoute
2
+
3
+ Покрытие кода тестами и покрытие API — разные метрики. Процент из `pytest-cov`
4
+ показывает, сколько веток Python-кода выполнили тесты. Эта матрица показывает, какие
5
+ bot-compatible ресурсы [VoiceRoute](https://voiceroute.cc) представлены публичным API
6
+ библиотеки.
7
+
8
+ В знаменатель не входят пользовательские сессии, пароль, MFA, друзья, личные и
9
+ групповые чаты, управление bot applications/installations и создание сообщества: по
10
+ предоставленному контракту bot token получает для них `403`. Голос также не считается
11
+ реализуемым ресурсом, пока сервер не выдаёт сторонним ботам WebRTC token.
12
+
13
+ | Домен | Реализовано | Контрактные тесты | Статус |
14
+ | --- | --- | --- | --- |
15
+ | Текущий бот | профиль и совместимый `/auth/me` | частично | базовый |
16
+ | Сообщества | список, одно сообщество | да | базовый |
17
+ | Каналы | список доступных каналов | да | базовый |
18
+ | События | channel SSE, catch-up, checkpoint | да | готово |
19
+ | Сообщения | история, отправка, edit, delete | да | готово |
20
+ | Контент сообщений | pins, reactions, search | да | готово |
21
+ | Вложения | — | — | следующий домен |
22
+ | Треды и форумы | — | — | следующий домен |
23
+ | Участники, роли, permissions | — | — | запланировано |
24
+ | Баны, timeout, AutoMod, audit | — | — | запланировано |
25
+ | Categories и управление channels | — | — | запланировано |
26
+ | Expressions, sounds, soundboard | — | — | запланировано |
27
+ | Webhooks | — | — | запланировано |
28
+ | Stage и music | — | — | требует отдельного контракта |
29
+
30
+ Матрица ведётся по доменам, а не одним вводящим в заблуждение процентом. Некоторые
31
+ маршруты в реестре являются alias одного обработчика, а отдельные маршруты формально
32
+ находятся под `/api/communities/:id/...`, но требуют внешнего сервиса или недоступного
33
+ ботам транспорта. Числовой процент появится после машиночитаемого OpenAPI со
34
+ стабильными operation ID и признаками bot compatibility.
@@ -0,0 +1,80 @@
1
+ # Архитектура
2
+
3
+ Библиотека строится слоями и не связывает пользовательский API с деталями сети.
4
+
5
+ ```text
6
+ Bot framework
7
+ -> Resource APIs
8
+ -> HTTP and SSE transports
9
+ -> VoiceRoute API
10
+ ```
11
+
12
+ ## Transport
13
+
14
+ Transport отвечает за авторизацию, URL, JSON, таймауты, rate limits, retries и
15
+ преобразование HTTP-ошибок. Он не содержит бизнес-объектов и команд.
16
+
17
+ Один `VoiceRouteClient` разделяет sliding-window limiter между resource API и
18
+ открытием SSE. Retry разрешён по умолчанию только безопасным HTTP-методам.
19
+ Изменяющая операция обязана явно подтвердить идемпотентность; отправка сообщения
20
+ делает это благодаря стабильному `clientMessageId`.
21
+
22
+ ## Resource API
23
+
24
+ Модули `api` группируют endpoint-ы по предметной области. Сырые ответы
25
+ преобразуются в типизированные DTO из `models`.
26
+
27
+ ## Events
28
+
29
+ Runtime получает события через протокол `EventTransport` и не зависит от сетевого
30
+ формата. Текущий `LegacySSETransport` объединяет постраничное восстановление истории и
31
+ канальный SSE в поток `EventDelivery`. Каждая доставка содержит нормализованное событие,
32
+ источник и checkpoint, который runtime сохраняет только после успешной обработки.
33
+
34
+ Пользовательский transport можно передать через `Bot(..., event_transport=...)`. Это
35
+ позволяет тестировать runtime без сети и позже добавить Gateway-адаптер без изменения
36
+ команд и обработчиков бота.
37
+
38
+ SSE-потоки используют отдельные курсоры. События сообщений применяются как
39
+ upsert, пока серверный контракт не позволяет достоверно различить создание и
40
+ изменение без локального состояния.
41
+
42
+ Runtime сохраняет составной checkpoint: `message_seq` закрывает начальную выдачу,
43
+ у которой ещё нет SSE ID, а `change_cursor` восстанавливает поток изменений.
44
+ Checkpoint фиксируется только после успешной обработки события. Хранилище
45
+ задаётся через протокол `CursorStore`; встроены process-local и атомарный файловый
46
+ адаптеры. Файловый адаптер предназначен для одного процесса.
47
+
48
+ ## Commands
49
+
50
+ Команды являются клиентской абстракцией поверх обычных сообщений. Библиотека не
51
+ имитирует отсутствующие на сервере interactions, intents или gateway.
52
+
53
+ `CommandRegistry` хранит метаданные, aliases и многоуровневые пути, а `Command` отвечает
54
+ за типизированное преобразование аргументов и вызов callback. `PrefixCommandAdapter`
55
+ только преобразует текст сообщения в независимый `CommandInvocation`. Будущий adapter
56
+ interactions сможет использовать тот же registry и pipeline.
57
+
58
+ `CommandPipeline` последовательно выполняет checks, cooldown, concurrency gate и
59
+ middleware. Состояние встроенных ограничителей локально процессу; распределённые
60
+ адаптеры хранения будут добавлены отдельно и не должны менять публичные декораторы.
61
+
62
+ ## Extensions
63
+
64
+ `Extension` группирует bound commands и event listeners. Подключение атомарно: конфликт
65
+ регистрации откатывает уже добавленные handlers и вызывает teardown. Модульная загрузка
66
+ требует `async setup(bot) -> Extension`; unload удаляет exact handlers экземпляра, а reload
67
+ восстанавливает предыдущий экземпляр при ошибке новой версии.
68
+
69
+ ## Границы безопасности
70
+
71
+ Runtime-клиент принимает только bot token. Управление приложениями через cookie,
72
+ пароль и MFA не входит в него и при необходимости будет реализовано отдельно.
73
+
74
+ ## Runtime lifecycle
75
+
76
+ `Bot` имеет явные состояния от `CREATED` до `CLOSED`. Channel consumers изолированы
77
+ supervisor-ами: необработанная ошибка одного канала запускает bounded backoff и чтение с
78
+ последнего подтверждённого checkpoint, не отменяя остальные каналы. `stop()` сериализует
79
+ конкурирующие остановки, отменяет consumers и освобождает extensions и HTTP transport.
80
+