Larksuite (Feishu)
Feishu (国内版) e Lark Suite (海外版) compartilham a mesma superfície OpenAPI. O provider Ongrid os trata como uma única integração; escolha a base URL que casa com seu tenant.
| Modo | O que faz |
|---|---|
| Notificação | Push de alerta para grupo Feishu/Lark via webhook de bot custom. |
| Ponte IM | Chat two-way com o agent usando long-connection WebSocket. |
Modo notificação (bot custom)
O sender Feishu posta um payload de bot custom Feishu / Lark à URL do webhook que seu admin de bot fornece. Formato do payload:
{
"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>"
}Assinatura — campo sign
Quando você liga 签名校验 (verificação de assinatura) no bot custom Feishu, o Feishu te dá um secret compartilhado. O sender computa o campo sign como:
stringToSign = timestamp + "\n" + secret
sign = base64(HMAC-SHA256(key=stringToSign, message=<empty>))Sim — o secret assume o papel tanto de material de chave para o HMAC quanto de parte do string-to-sign. Esse é o algoritmo que o Feishu documenta, e é o que signFeishu implementa.
Se você deixar o campo Secret em branco, o Ongrid posta sem um sign / timestamp — utilizável apenas quando seu bot tem a verificação de assinatura desligada (ou tem allowlist de IP no lugar).
Configuração
- No grupo Feishu → 设置 → 群机器人 → 添加机器人 → 自定义机器人. Dê nome e avatar.
- Marque 签名校验; copie o secret.
- Copie a URL do webhook — algo como
https://open.feishu.cn/open-apis/bot/v2/hook/<uuid>(ou…/open.larksuite.com/…para Lark Suite). - No Ongrid: Settings → Channels → New → Provider =
feishu→ Endpoint = a URL do webhook → Secret = o secret de assinatura.
Bot custom ≠ App
O modo notificação usa um bot custom (escopo de grupo, só webhook). O modo ponte IM usa um app Feishu (escopo de tenant, OAuth + events). São conceitos diferentes; as credenciais não se sobrepõem.
Modo ponte IM (stream long-connection)
A ponte two-way usa a long-connection Feishu entregue pelo client oficial github.com/larksuite/oapi-sdk-go/v3/ws. O manager disca para o endpoint de events do Feishu e o Feishu empurra events pelo WebSocket — nenhuma URL pública de webhook é necessária.
Por que stream e não webhook
O modo webhook (mode=webhook) é suportado no schema para back-compat, mas o stream long-connection é o caminho recomendado:
- Sem necessidade de ingress público no manager.
- Reaproveita o reconnect-with-backoff do supervisor (o SDK tem seu próprio reconnect; o supervisor adiciona um loop externo para falhas terminais).
- O SDK lida com verificação de assinatura + descriptografia AES internamente, então você não precisa preencher
encrypt_keypara a variante stream — é só de webhook.
Mapeamento de credenciais
Coluna im_apps | Significado Feishu |
|---|---|
provider | "feishu" |
mode | "stream" (recomendado) ou "webhook" |
app_id | app_id Feishu (cli_…). |
app_secret | app_secret Feishu. |
verify_token | Opcional. Usado pela verificação de assinatura em modo webhook. |
encrypt_key | Obrigatório em modo webhook, ignorado em modo stream. |
allow_from | Opcional. Feishu é tenant-gated então a allowlist é não-obrigatória. |
default_locale
Set para zh para um tenant Feishu cujos operadores escrevem em chinês, para en para um time Lark em inglês. Vazio (padrão) significa que o LLM espelha o usuário.
Configuração
- 开发者后台 → 创建企业自建应用. Pegue
app_id+app_secret. - 应用功能 → 机器人 → enable. Adicione o bot ao seu chat de teste.
- 权限管理 → conceda:
im:message— ler mensagens endereçadas ao bot.im:message.group_at_msg— events de menção em grupo.im:message.p2p_msg— events de DM.im:message:send_as_bot—SendText/EditText.
- 事件订阅 → 长连接模式 (long-connection) → enable.
- No Ongrid: Settings → IM bridge → New → Provider =
feishu→ Mode =stream→ coleapp_id+app_secret. Salve e Enable. @o bot no chat. O agent pega.
Cache de tenant_access_token
Chamadas outbound (SendText, EditText) autenticam com um tenant_access_token, refreshado proativamente quando dentro de 200s do vencimento. O token é cacheado por instância de Client, protegido por um sync.Mutex; rotacionar credenciais significa rebuildar o client. Veja tenantAccessToken.
msg_type é obrigatório em edits também
O PUT /open-apis/im/v1/messages/<id> do Feishu exige msg_type no body — omiti-lo retorna code: 99992402 (validação de campo falhou) mesmo que a página de docs para "edit message" não deixe isso óbvio. O provider sempre envia msg_type: text.
Modo webhook (legado, mantido por compatibilidade)
O modo webhook ainda é selecionável na UI; o supervisor verifica assinaturas e decrypta payloads ele mesmo.
Verificação de assinatura
O handler HTTP lê X-Lark-Signature e roda VerifyEventSignature:
sig = sha256(timestamp + nonce + encrypt_key + body), hex-encodedSim — SHA-256, não HMAC. O encrypt_key faz o papel de shared-secret dentro do input de hash. O verifier nunca panica em input ruim; mismatch retorna ErrBadSignature.
Descriptografia de payload
Quando encrypt_key está setado, o Feishu envelopa o JSON do event em AES-256-CBC. A descriptografia usa:
- Chave:
SHA-256(encrypt_key). - IV: os primeiros 16 bytes do ciphertext decodificado em base64.
- Padding: PKCS#7.
Veja DecryptEvent.
Prefira modo stream se puder
Modo webhook requer um endpoint HTTPS público e a fiação de encrypt_key acima. O stream long-connection evita ambos. Vá no modo webhook só quando você especificamente precisa (ex.: integrar events Feishu com um router de webhook público existente).
Pegadinhas
- O client stream Feishu não impõe
allow_fromhoje — a própria plataforma Feishu é tenant-gated, então só membros da empresa alcançam o bot. Se seu tenant tem guests / colaboradores externos, preenchaallow_fromcom seus valores deopen_idpara travar a conversa mais. - Stickers, files, cards, e mensagens ricas são descartadas (só
msg_type == "text"dispara o agent). Mesmo contrato S1 que Telegram / Slack. - O campo
RootIdé capturado comoImThread.ImThreadIDpara que respostas dentro de uma thread continuem a mesma sessão — sem necessidade de o usuário resetar contexto por pergunta.