|
1 | | -# Feishu |
| 1 | +# Feishu Channel |
2 | 2 |
|
3 | | -> Coming soon. |
| 3 | +[Feishu](https://www.feishu.cn/) (飞书) messaging integration for China users — supporting DMs, groups, streaming cards, and real-time updates via WebSocket or webhook. |
| 4 | + |
| 5 | +## Setup |
| 6 | + |
| 7 | +**Create Feishu App:** |
| 8 | + |
| 9 | +1. Go to https://open.feishu.cn |
| 10 | +2. Create custom app → fill Basic Information |
| 11 | +3. Under "Bots" → enable "Bot" capability |
| 12 | +4. Set bot name and avatar |
| 13 | +5. Copy `App ID` and `App Secret` |
| 14 | +6. Grant permissions: `im:message`, `im:message.p2p_msg:send`, `im:message.group_msg:send`, `contact:user.id:readonly` |
| 15 | + |
| 16 | +**Enable Feishu:** |
| 17 | + |
| 18 | +```json |
| 19 | +{ |
| 20 | + "channels": { |
| 21 | + "feishu": { |
| 22 | + "enabled": true, |
| 23 | + "app_id": "YOUR_APP_ID", |
| 24 | + "app_secret": "YOUR_APP_SECRET", |
| 25 | + "connection_mode": "websocket", |
| 26 | + "domain": "feishu", |
| 27 | + "dm_policy": "pairing", |
| 28 | + "group_policy": "open" |
| 29 | + } |
| 30 | + } |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +## Configuration |
| 35 | + |
| 36 | +All config keys are in `channels.feishu`: |
| 37 | + |
| 38 | +| Key | Type | Default | Description | |
| 39 | +|-----|------|---------|-------------| |
| 40 | +| `enabled` | bool | false | Enable/disable channel | |
| 41 | +| `app_id` | string | required | App ID from Feishu Developer Console | |
| 42 | +| `app_secret` | string | required | App Secret from Feishu Developer Console | |
| 43 | +| `encrypt_key` | string | -- | Optional message encryption key | |
| 44 | +| `verification_token` | string | -- | Optional webhook verification token | |
| 45 | +| `domain` | string | `"feishu"` | `"feishu"` for China, `"lark"` for Larksuite | |
| 46 | +| `connection_mode` | string | `"websocket"` | `"websocket"` or `"webhook"` | |
| 47 | +| `webhook_port` | int | 3000 | Port for webhook server (0=mount on gateway mux) | |
| 48 | +| `webhook_path` | string | `"/feishu/events"` | Webhook endpoint path | |
| 49 | +| `allow_from` | list | -- | User ID allowlist (DMs) | |
| 50 | +| `dm_policy` | string | `"pairing"` | `pairing`, `allowlist`, `open`, `disabled` | |
| 51 | +| `group_policy` | string | `"open"` | `open`, `allowlist`, `disabled` | |
| 52 | +| `group_allow_from` | list | -- | Group ID allowlist | |
| 53 | +| `require_mention` | bool | true | Require bot mention in groups | |
| 54 | +| `topic_session_mode` | string | `"disabled"` | `"disabled"` or `"enabled"` for thread isolation | |
| 55 | +| `text_chunk_limit` | int | 4000 | Max text characters per message | |
| 56 | +| `media_max_mb` | int | 30 | Max media file size (MB) | |
| 57 | +| `render_mode` | string | `"auto"` | `"auto"` (detect), `"card"`, `"raw"` | |
| 58 | +| `streaming` | bool | true | Enable streaming card updates | |
| 59 | +| `reaction_level` | string | `"off"` | `off`, `minimal` (⏳ only), `full` | |
| 60 | +| `history_limit` | int | -- | Max messages to load from history | |
| 61 | +| `block_reply` | bool | -- | Block reply-to-message context | |
| 62 | +| `stt_proxy_url` | string | -- | Speech-to-text proxy URL | |
| 63 | +| `stt_api_key` | string | -- | Speech-to-text API key | |
| 64 | +| `stt_tenant_id` | string | -- | Speech-to-text tenant ID | |
| 65 | +| `stt_timeout_seconds` | int | -- | Speech-to-text request timeout | |
| 66 | +| `voice_agent_id` | string | -- | Agent ID for voice message handling | |
| 67 | + |
| 68 | +## Transport Modes |
| 69 | + |
| 70 | +### WebSocket (Default) |
| 71 | + |
| 72 | +Persistent connection with auto-reconnect. Recommended for low latency. |
| 73 | + |
| 74 | +```json |
| 75 | +{ |
| 76 | + "connection_mode": "websocket" |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +### Webhook |
| 81 | + |
| 82 | +Feishu sends events via HTTP POST. Choose: |
| 83 | + |
| 84 | +1. **Mount on gateway mux** (`webhook_port: 0`): Handler shares main gateway port |
| 85 | +2. **Separate server** (`webhook_port: 3000`): Dedicated webhook listener |
| 86 | + |
| 87 | +```json |
| 88 | +{ |
| 89 | + "connection_mode": "webhook", |
| 90 | + "webhook_port": 0, |
| 91 | + "webhook_path": "/feishu/events" |
| 92 | +} |
| 93 | +``` |
| 94 | + |
| 95 | +Then configure the webhook URL in Feishu Developer Console: |
| 96 | +- Gateway mux: `https://your-gateway.com/feishu/events` |
| 97 | +- Separate server: `https://your-webhook-host:3000/feishu/events` |
| 98 | + |
| 99 | +## Features |
| 100 | + |
| 101 | +### Streaming Cards |
| 102 | + |
| 103 | +Real-time updates delivered as interactive card messages with animation: |
| 104 | + |
| 105 | +```mermaid |
| 106 | +flowchart TD |
| 107 | + START["Agent starts responding"] --> CREATE["Create streaming card"] |
| 108 | + CREATE --> SEND["Send card message<br/>(streaming_mode: true)"] |
| 109 | + SEND --> UPDATE["Update card text<br/>with accumulated chunks<br/>(throttled: 100ms min)"] |
| 110 | + UPDATE -->|"More chunks"| UPDATE |
| 111 | + UPDATE -->|"Done"| CLOSE["Close stream<br/>(streaming_mode: false)"] |
| 112 | + CLOSE --> FINAL["User sees full response"] |
| 113 | +``` |
| 114 | + |
| 115 | +Updates throttled to prevent rate limiting. Display uses 50ms animation frequency (2-character steps). |
| 116 | + |
| 117 | +### Media Handling |
| 118 | + |
| 119 | +**Inbound**: Images, files, audio, video, stickers auto-downloaded and saved: |
| 120 | + |
| 121 | +| Type | Extension | |
| 122 | +|------|-----------| |
| 123 | +| Image | `.png` | |
| 124 | +| File | Original extension | |
| 125 | +| Audio | `.opus` | |
| 126 | +| Video | `.mp4` | |
| 127 | +| Sticker | `.png` | |
| 128 | + |
| 129 | +Max 30 MB by default (`media_max_mb`). |
| 130 | + |
| 131 | +**Outbound**: Files auto-detected and uploaded with correct type (opus, mp4, pdf, doc, xls, ppt, or stream). |
| 132 | + |
| 133 | +### Mention Resolution |
| 134 | + |
| 135 | +Feishu sends placeholder tokens (e.g., `@_user_1`). Bot parses mention list and resolves to `@DisplayName`. |
| 136 | + |
| 137 | +### Thread Session Isolation |
| 138 | + |
| 139 | +When `topic_session_mode: "enabled"`, each thread gets isolated conversation: |
| 140 | + |
| 141 | +``` |
| 142 | +Session key: "{chatID}:topic:{rootMessageID}" |
| 143 | +``` |
| 144 | + |
| 145 | +Different threads in same group maintain separate histories. |
| 146 | + |
| 147 | +### Speech-to-Text |
| 148 | + |
| 149 | +Voice messages can be transcribed by configuring an STT service: |
| 150 | + |
| 151 | +```json |
| 152 | +{ |
| 153 | + "stt_proxy_url": "https://your-stt-service.com", |
| 154 | + "stt_api_key": "YOUR_STT_KEY", |
| 155 | + "stt_timeout_seconds": 30 |
| 156 | +} |
| 157 | +``` |
| 158 | + |
| 159 | +Set `voice_agent_id` to route transcribed voice messages to a specific agent. |
| 160 | + |
| 161 | +## Troubleshooting |
| 162 | + |
| 163 | +| Issue | Solution | |
| 164 | +|-------|----------| |
| 165 | +| "Invalid app credentials" | Check app_id and app_secret. Ensure app is published. | |
| 166 | +| Webhook not receiving events | Verify webhook URL is publicly accessible. Check Feishu Developer Console event subscriptions. | |
| 167 | +| WebSocket keeps disconnecting | Check network. Verify app has `im:message` permission. | |
| 168 | +| Streaming cards not updating | Ensure `streaming: true`. Check `render_mode` (auto/card). Messages shorter than limit render as plain text. | |
| 169 | +| Media upload fails | Verify file type matches. Check file size under `media_max_mb`. | |
| 170 | +| Mention not parsed | Ensure bot is mentioned. Check mention list in webhook payload. | |
| 171 | +| Wrong domain | China users must set `domain: "feishu"`. International users use `domain: "lark"`. | |
| 172 | + |
| 173 | +## What's Next |
| 174 | + |
| 175 | +- [Overview](#channels-overview) — Channel concepts and policies |
| 176 | +- [Larksuite](#channel-larksuite) — Larksuite (international) setup |
| 177 | +- [Telegram](#channel-telegram) — Telegram bot setup |
| 178 | +- [Browser Pairing](#channel-browser-pairing) — Pairing flow |
| 179 | + |
| 180 | +<!-- goclaw-source: 120fc2d | updated: 2026-03-18 --> |
0 commit comments