Skip to content

Larksuite (Feishu)

Feishu (国内版) и Lark Suite (海外版) разделяют ту же поверхность OpenAPI. Provider Ongrid трактует их как одну интеграцию; выберите базовый URL, который соответствует вашему тенанту.

РежимЧто он делает
NotificationПуш алертов в Feishu/Lark-группу через webhook кастомного бота.
IM bridgeДвусторонний чат с агентом через WebSocket long-connection.

Notification-режим (кастомный бот)

Sender Feishu постит payload Feishu / Lark кастомного бота на webhook URL, который предоставляет администратор вашего бота. Форма payload:

json
{
  "msg_type": "text",
  "content": {"text": "[CRITICAL] swap_high node-01\nswap_in_pages > 1000 for 5m\nsource: alert\ndedupe: alert:swap_high:device=7"},
  "timestamp": "1717012345",
  "sign": "<base64-hmac>"
}

Подпись — поле sign

Когда вы включаете 签名校验 (signature verification) на кастомном боте Feishu, Feishu выдаёт вам shared secret. Sender вычисляет поле sign как:

text
stringToSign = timestamp + "\n" + secret
sign         = base64(HMAC-SHA256(key=stringToSign, message=<empty>))

Да — secret выполняет роль и key material для HMAC, и части string-to-sign. Это алгоритм, который документирует Feishu, и это то, что реализует signFeishu.

Если вы оставляете поле Secret пустым, Ongrid постит без sign / timestamp — пригодно только когда у вашего бота signature verification выключена (или есть IP allowlist вместо).

Настройка

  1. В Feishu-группе → 设置 → 群机器人 → 添加机器人 → 自定义机器人. Дайте имя и аватар.
  2. Отметьте 签名校验; скопируйте secret.
  3. Скопируйте webhook URL — выглядит как https://open.feishu.cn/open-apis/bot/v2/hook/<uuid> (или …/open.larksuite.com/… для Lark Suite).
  4. В Ongrid: Settings → Channels → New → Provider = feishu → Endpoint = webhook URL → Secret = signing secret.

Кастомный бот ≠ App

Notification-режим использует кастомного бота (group-scoped, только webhook). IM bridge-режим использует Feishu app (tenant-scoped, OAuth

  • events). Это разные концепции; credentials не перекрываются.

IM bridge-режим (long-connection stream)

Двусторонний bridge использует Feishu long-connection, доставленный официальным github.com/larksuite/oapi-sdk-go/v3/ws клиентом. Manager дозванивается на event-эндпоинт Feishu, и Feishu пушит события через WebSocket — публичный webhook URL не требуется.

Почему stream, а не webhook

Webhook-режим (mode=webhook) поддерживается в схеме для back-compat, но long-connection stream — рекомендуемый путь:

  • Не нужен публичный ingress на manager.
  • Переиспользует reconnect-with-backoff supervisor (у SDK есть собственный reconnect; supervisor добавляет внешнюю петлю для терминальных отказов).
  • SDK обрабатывает signature verification + AES-расшифровку внутри, так что вам не нужно заполнять encrypt_key для stream-варианта — это только для webhook.

Маппинг credentials

Столбец im_appsЗначение в Feishu
provider"feishu"
mode"stream" (рекомендуется) или "webhook"
app_idFeishu app_id (cli_…).
app_secretFeishu app_secret.
verify_tokenОпционально. Используется signature verification в webhook-режиме.
encrypt_keyОбязательно в webhook-режиме, игнорируется в stream-режиме.
allow_fromОпционально. Feishu tenant-gated, так что allowlist не обязателен.

default_locale

Поставьте zh для Feishu-тенанта, чьи операторы пишут на китайском, en для англоязычной Lark-команды. Пустое (по умолчанию) означает, что LLM зеркалит пользователя.

Настройка

  1. 开发者后台 → 创建企业自建应用. Получите app_id + app_secret.
  2. 应用功能 → 机器人 → включить. Добавьте бота в ваш тестовый чат.
  3. 权限管理 → grant:
    • im:message — читать сообщения, адресованные боту.
    • im:message.group_at_msg — события group-mention.
    • im:message.p2p_msg — события DM.
    • im:message:send_as_botSendText / EditText.
  4. 事件订阅 → 长连接模式 (long-connection) → включить.
  5. В Ongrid: Settings → IM bridge → New → Provider = feishu → Mode = stream → вставить app_id + app_secret. Сохранить и Enable.
  6. @ бота в чате. Агент его подхватит.

Кэширование tenant_access_token

Исходящие вызовы (SendText, EditText) аутентифицируются через tenant_access_token, обновляемый проактивно, когда в пределах 200с до expiry. Токен кэшируется per-Client экземпляр, защищён sync.Mutex; ротация credentials означает пересборку клиента. См. tenantAccessToken.

msg_type обязательно и на edits

PUT /open-apis/im/v1/messages/<id> Feishu требует msg_type в теле — пропуск возвращает code: 99992402 (field validation failed), даже если страница документации для «edit message» этого не делает очевидным. Provider всегда отправляет msg_type: text.

Webhook-режим (legacy, оставлен для совместимости)

Webhook-режим всё ещё выбираем в UI; supervisor сам проверяет подписи и расшифровывает payload.

Signature verification

HTTP-handler читает X-Lark-Signature и запускает VerifyEventSignature:

text
sig = sha256(timestamp + nonce + encrypt_key + body), hex-encoded

Да — SHA-256, не HMAC. encrypt_key играет роль shared-secret внутри hash input. Verifier никогда не паникует на плохом вводе; mismatch возвращает ErrBadSignature.

Расшифровка payload

Когда encrypt_key установлен, Feishu оборачивает event JSON в AES-256-CBC. Расшифровка использует:

  • Key: SHA-256(encrypt_key).
  • IV: первые 16 байт base64-декодированного ciphertext.
  • Padding: PKCS#7.

См. DecryptEvent.

Выбирайте stream-режим, если можете

Webhook-режим требует публичного HTTPS-эндпоинта и encrypt_key- обвязки выше. Long-connection stream избегает обоих. Тянитесь к webhook- режиму, только когда вам это нужно (например, интегрировать события Feishu с существующим публичным webhook-роутером).

Особенности

  • Feishu stream client сегодня не форсит allow_from — сама платформа Feishu tenant-gated, так что только enterprise-члены достают до бота. Если у вашего тенанта есть гости / внешние коллабораторы, заполните allow_from их значениями open_id, чтобы заблокировать разговор сильнее.
  • Стикеры, файлы, карты и rich-сообщения отбрасываются (только msg_type == "text" триггерит агента). Тот же S1-контракт, что у Telegram / Slack.
  • Поле RootId захватывается как ImThread.ImThreadID, так что ответы внутри треда продолжают ту же сессию — нет необходимости пользователю ресетить контекст на каждый вопрос.