← Back to Plugins
Channels

Channel Max

ikrajushkin By ikrajushkin 👁 55 views ▲ 0 votes

Plugin connector for OpenClaw to connect a bot in the MAX messenger

GitHub

Install

npm install
npm

Configuration Example

{
  "channels": {
    "max": {
      "tokenFile": "/путь/к/секретам/max.token",
      "dmPolicy": "allowlist",
      "allowFrom": ["<ваш user_id в MAX>"]
    }
  }
}

README

# openclaw-channel-max

Канал мессенджера [MAX](https://max.ru) для [OpenClaw](https://openclaw.ai).

> *A [MAX messenger](https://max.ru) channel plugin for OpenClaw. Lets an OpenClaw
> agent receive and answer messages in MAX. Docs below are in Russian —
> MAX is a Russian-market messenger.*

Готового канала для MAX в OpenClaw нет: в каталоге около трёх десятков
мессенджеров, MAX среди них отсутствует, в ClawHub тоже пусто. Этот плагин
закрывает пробел.

## Что умеет

- Приём текстовых сообщений через long polling (`GET /updates`).
- Ответы агента обратно в MAX (`POST /messages`), с разбиением по 4000 символов.
- Политики доступа `dmPolicy` (`pairing` / `allowlist` / `open` / `disabled`)
  и `allowFrom` — та же модель, что у штатных каналов OpenClaw.
- Несколько аккаунтов: `channels.max.accounts.<id>`; значения аккаунта
  перекрывают корневые.
- Токен из файла (`tokenFile`), чтобы не держать секрет в конфиге.
- Горячий перезапуск: правка `channels.max.*` поднимает только этот канал,
  не трогая остальные.

## Чего пока нет

- **Вебхук.** MAX рекомендует его для продакшена, а long polling помечает как
  средство разработки и ограничивает по скорости.
- **Вложения.** Приходят и разбираются, но пока не передаются агенту:
  на сообщение с вложением бот отвечает, что обрабатывать его не умеет.
  См. раздел «Вложения и голосовые» ниже.
- **Долговечная очередь входящих.** Курсор `marker` живёт в памяти процесса:
  после перезапуска канал стартует с текущего момента и не переигрывает историю.
- **Уведомление о сопряжении.** `pairing.notify` отправляет код через аккаунт
  по умолчанию; на практике проще подтверждать вручную через
  `openclaw pairing approve`.

## Требования

- OpenClaw 2026.8 или новее.
- Node.js 22.22+, 24.15+ или 25.9+.
- Бот в MAX и его токен.

## Установка

```bash
git clone https://github.com/<владелец>/openclaw-channel-max.git
cd openclaw-channel-max
npm install
npm run build
```

Установщик OpenClaw копирует каталог целиком, включая `node_modules`, поэтому
ставить нужно чистую выкладку. Это делает вспомогательный скрипт:

```bash
bash scripts/install-local.sh
```

Он собирает проект, раскладывает в отдельный каталог только то, что нужно
в рантайме, и вызывает `openclaw plugins install`. После установки перезапустите
шлюз, чтобы плагин загрузился:

```bash
openclaw plugins install <каталог-выкладки> --force --accept-capabilities
systemctl restart openclaw-gateway   # или как у вас запускается шлюз
```

Флаг `--accept-capabilities` обязателен: плагин объявляет канал, а это требует
явного согласия.

## Получение токена

Бот создаётся в самом мессенджере у `@MasterBot`: команда `/create`, имя от 11
до 60 символов с обязательным окончанием `_bot`. В ответ приходит токен.

## Настройка

```jsonc
{
  "channels": {
    "max": {
      "tokenFile": "/путь/к/секретам/max.token",
      "dmPolicy": "allowlist",
      "allowFrom": ["<ваш user_id в MAX>"]
    }
  }
}
```

Или через CLI:

```bash
openclaw config set channels.max.tokenFile /путь/к/секретам/max.token
openclaw config set channels.max.dmPolicy allowlist
openclaw config set channels.max.allowFrom '["<ваш user_id>"]'
```

### Как узнать свой user_id

Он **не совпадает** с номером аккаунта, под которым создавался бот (тот зашит
в имя бота вида `seNNNNNNNN_1_bot`). Bot API оперирует другим идентификатором.

Самый простой способ: оставить `dmPolicy: "allowlist"` с пустым списком,
написать боту и посмотреть журнал шлюза — отказ печатает id отправителя:

```
[max] отправитель 200000002 отклонён политикой allowlist
```

Этот номер и нужен в `allowFrom`.

### Маршрутизация на агента

Если у вас несколько агентов, канал нужно привязать явно, иначе ядро откажется
угадывать (`AgentSelectionRequiredError`). Привязки живут в верхнеуровневом
массиве `bindings`:

```jsonc
{
  "bindings": [
    {
      "type": "route",
      "agentId": "<имя агента>",
      "match": { "channel": "max", "accountId": "default" }
    }
  ]
}
```

Правка `bindings` требует полного перезапуска шлюза.

### Несколько ботов

```jsonc
{
  "channels": {
    "max": {
      "dmPolicy": "allowlist",
      "accounts": {
        "default": { "tokenFile": "/путь/к/секретам/max-1.token",
                     "allowFrom": ["111"] },
        "support":  { "tokenFile": "/путь/к/секретам/max-2.token",
                      "allowFrom": ["222"] }
      }
    }
  }
}
```

Значения аккаунта перекрывают корневые, корневые служат общими умолчаниями.

## Параметры

| Ключ | По умолчанию | Смысл |
|---|---|---|
| `token` | — | Токен бота прямо в конфиге. Предпочтительнее `tokenFile`. |
| `tokenFile` | — | Путь к файлу с токеном. |
| `apiBaseUrl` | `https://platform-api.max.ru` | База Bot API. |
| `dmPolicy` | `pairing` | Кто может писать боту в личку. |
| `allowFrom` | `[]` | Белый список отправителей. |
| `groupPolicy` | `allowlist` | Политика для групповых чатов. |
| `pollTimeoutSec` | `30` | Таймаут одного запроса long polling (0–90). |
| `pollLimit` | `100` | Сколько событий забирать за раз (1–1000). |
| `enabled` | `true` | Выключатель аккаунта. |

## Разработка

```bash
npm run typecheck    # tsc --noEmit
npm test             # vitest
npm run build        # tsc -> dist/
```

Типы стоит брать от **установленного** экземпляра OpenClaw, а не от свежего
с npm, иначе они разойдутся с тем, что реально работает на шлюзе:

```bash
rm -rf node_modules/openclaw
ln -s "$(npm root -g)/openclaw" node_modules/openclaw
```

## Вложения и голосовые

Формы входящих вложений в документации MAX нет — ниже то, что подтверждено
на живом боте.

**Картинки и файлы приходят полноценно, с прямой ссылкой:**

```jsonc
// изображение
{ "type": "image",
  "payload": { "photo_id": 41029804448, "token": "…", "url": "https://i.oneme.ru/i?r=…" } }

// файл
{ "type": "file", "filename": "ticket.pdf", "size": 367884,
  "payload": { "fileId": 4818474188, "token": "…",
               "url": "https://fd.oneme.ru/getfile?rq=…&expires=1791134734010" } }
```

`payload.url` скачивается напрямую; у файлов ссылка со сроком годности
(`expires`). Этого достаточно, чтобы забрать вложение и передать его агенту —
работа запланирована.

**Голосовые сообщения боту недоступны.** Событие приходит, но без поля
`message` вообще:

```json
{ "timestamp": 1788542381579, "user_locale": "ru", "update_type": "message_created" }
```

Ни отправителя, ни чата, ни вложения. Практические следствия:

- расшифровать нечего — файла нет;
- **ответить тоже некуда** — неизвестен чат, так что бот даже не может
  сообщить, что не расслышал;
- отличить это событие от прочих можно только по отсутствию `message`.

Обходной путь для голоса: отправить аудио **вложением-файлом**, а не записью
через микрофон. Такое вложение приходит обычным `file` со ссылкой.

Если вам известен способ получить содержимое голосовых — заводите issue,
это самое востребованное недостающее звено.

## Особенности MAX Bot API, на которые стоит заложиться

- **Отвечать нужно в `recipient.chat_id`.** В диалоге `recipient.user_id` — это
  сам бот, то есть получатель входящего. Отправка по нему возвращает
  `Invalid chatId: 0`, и ответ теряется. `chat_id` работает и для диалога,
  и для группы.
- **`GET /chats` для ботов не отдаёт JSON** — приходит zip-архив с `logcat.txt`.
  Список диалогов через него получить нельзя.
- **`marker` в `/updates`** при первом запросе без значения отдаёт только
  последнее событие, а не всю очередь.
- **`GET /messages` возвращает только сообщения самого бота.** Дозапросить
  входящее сообщение по нему нельзя.
- **Фильтр `types` в `/updates` отсекает молча.** При отладке лучше убрать его
  и логировать всё подряд, иначе неожиданные события исчезают бесследно.
- **Лимиты:** 30 запросов в секунду на REST, не больше двух сообщений в секунду
  в один диалог, 4000 символов на сообщение.

## Лицензия

MIT — см. [LICENSE](LICENSE).
channels

Comments

Sign in to leave a comment

Loading comments...