136 lines
6.4 KiB
Markdown
Executable File
136 lines
6.4 KiB
Markdown
Executable File
---
|
||
tags:
|
||
- hermes
|
||
- mattermost
|
||
- mention
|
||
- adapter
|
||
- whale
|
||
type: plan
|
||
namespace: personal
|
||
status: implemented — awaiting gateway restart
|
||
created: '2026-09-29'
|
||
updated: '2026-09-29'
|
||
---
|
||
# План: MM mention-gating — авто-ответ в треде с ботом
|
||
|
||
**Дата:** 2026-09-29
|
||
**Статус:** Реализовано, ждёт рестарта gateway (приёмка Alex в UI)
|
||
|
||
## Итог
|
||
|
||
| Что | Значение |
|
||
|---|---|
|
||
| Файл | `~/.hermes/hermes-agent/plugins/platforms/mattermost/adapter.py` |
|
||
| md5 до | `9f3def29d90d00287cdbca3db000c513` |
|
||
| md5 после | `ed8c4b7735e3371f697c20cfbd11e421` |
|
||
| Бэкап | `~/.hermes/hermes-whale/backups/20260929-mm-mention/adapter.py` |
|
||
| Скрипт | `/tmp/mm-thread-mention.py` (идемпотентный) |
|
||
| Тесты | `tests/gateway/test_mattermost.py` — 46 passed (было 43, +3) |
|
||
| Коммит hermes-agent | `9b46ba791a` feat(mattermost): allow thread replies without @mention |
|
||
| Push | `207a1de16c..9b46ba791a main -> main` → github.com:mallexxx/hermes-agent.git |
|
||
|
||
### Что именно изменено
|
||
|
||
`_handle_ws_event`, перед mention-гейтом:
|
||
|
||
```python
|
||
is_thread_reply = bool(post.get("root_id"))
|
||
...
|
||
if (
|
||
require_mention
|
||
and not is_free_channel
|
||
and not has_mention
|
||
and not is_thread_reply
|
||
):
|
||
return
|
||
```
|
||
|
||
Три новых теста:
|
||
- `test_thread_reply_without_mention_responds` — тред без меншна → ответ есть
|
||
- `test_channel_root_without_mention_still_skipped` — корень канала без меншна → тишина
|
||
- `test_thread_reply_with_mention_strips_mention` — меншн в треде всё ещё убирается из текста
|
||
|
||
Остаток: рестарт gateway. Без него патч не подхватится (адаптер импортируется при старте).
|
||
`gateway run --replace` из активной сессии её убьёт — рестарт делает Alex.
|
||
|
||
## Задача (Alex, дословно)
|
||
|
||
> «в канале — меншен обязателен, в треде где только с ботом переписка — авто, без меншена»
|
||
|
||
## Проблема (подтверждена фактами)
|
||
|
||
`plugins/platforms/mattermost/adapter.py:734` — гейт применяется к **любому** не-DM:
|
||
|
||
```python
|
||
if channel_type_raw != "D": # тред = channel_type "O" → гейт срабатывает
|
||
...
|
||
if require_mention and not is_free_channel and not has_mention:
|
||
return # молча дроп, inbound не создаётся
|
||
```
|
||
|
||
**Доказательство (2026-09-29, канал `hermes-maintenance` = `a6nyh77eyjbn5c1owh1i8eebee`):**
|
||
|
||
| Время | Пост | Меншн | inbound в gateway.log |
|
||
|---|---|---|---|
|
||
| 12:38:01 | `@whale` | ✅ | ✅ есть |
|
||
| 12:38:40 | `тут, отлично. как нам сделать бэкап...` | ❌ | ❌ **нет** (ответа не было) |
|
||
|
||
Пост 12:38:40 — в треде `pcoiddzrqty3ipqtozgcs9ttte`, начатом ботом. Меншн не нужен, но требуется.
|
||
|
||
## Решение
|
||
|
||
Пропускать mention-гейт, когда пост находится **в треде** (`root_id` задан).
|
||
В корне канала меншн остаётся обязательным.
|
||
|
||
### Критерий (выбран)
|
||
|
||
**Тред = `root_id` непустой.** Просто, детерминированно, не требует API-запросов.
|
||
|
||
Обоснование: чтобы ответить в треде, бот должен быть в канале. Треды канала — общие
|
||
рабочие ветки; вовлечение в тред человеком = приглашение. Дополнительный критерий
|
||
«бот уже отвечал в этом треде» требует запроса к API на каждое сообщение (латентность +
|
||
зависимость от прав) и не даёт выигрыша: в канале бот и так отвечает на `@whale`.
|
||
|
||
### Правка
|
||
|
||
В `_handle_ws_event` перед mention-гейтом вычислить `root_id` и добавить его в условие:
|
||
|
||
```python
|
||
is_thread_reply = bool(post.get("root_id"))
|
||
...
|
||
if require_mention and not is_free_channel and not has_mention and not is_thread_reply:
|
||
return
|
||
```
|
||
|
||
Плюс: стрип меншна выполнять как раньше (если меншн есть — убрать из текста).
|
||
|
||
### Что НЕ меняется
|
||
|
||
- Корень канала без `@whale` → по-прежнему молчит.
|
||
- `MATTERMOST_FREE_RESPONSE_CHANNELS` — не трогаем.
|
||
- DM — не затронуты.
|
||
- `MATTERMOST_REQUIRE_MENTION=true` — остаётся.
|
||
|
||
## Шаги
|
||
|
||
1. Коммит ДО (`hermes-agent`, ветка `main`, HEAD `207a1de16c`).
|
||
2. Правка adapter.py — скрипт `python3 /tmp/<name>.py`, не sed.
|
||
3. Тест: `pytest plugins/platforms/mattermost/ tests/ -k mattermost -o "addopts="` (если есть).
|
||
4. Коммит ПОСЛЕ.
|
||
5. Рестарт gateway — **делает Alex** (`gateway run --replace` из этой сессии её убьёт).
|
||
6. Приёмка Alex в UI: пост в треде без меншна → ответ есть; пост в корне канала без меншна → ответа нет.
|
||
|
||
## Питфоллы
|
||
|
||
- 🔴 `gateway run --replace` из этой сессии убивает саму сессию (инцидент 2026-09-29 11:31).
|
||
- 🔴 Логи читать из `~/.hermes/hermes-whale/logs/`, не из `~/.hermes/logs/`.
|
||
- Адаптер читает `config.extra.*` ИЛИ env — при правке поведение env перебивает config
|
||
(см. `_apply_yaml_config`, строки 1108-1114).
|
||
- Логи уровня DEBUG не пишутся — `skipping non-DM message without @mention` в `gateway.log`
|
||
не виден (`grep -c` вернул 0 при 1.6 МБ лога). Судить по наличию/отсутствию `inbound message`.
|
||
|
||
## Связанные заметки
|
||
|
||
- [[personal/tech/hermes-whale-mattermost-transport.md]] — транспорт, env-ключи, инцидент с рестартом, диагностика «бот молчит в канале»
|
||
- [[personal/tech/hermes-pairing-multi-profile.md]] — pairing
|