openclaw/extensions/feishu/spec/proposal.md

301 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PRD: Feishu (飞书) channel extension
## Why
Clawdbot already supports several chat surfaces (e.g. Slack, Google Chat, Telegram). Feishu (飞书) is a common “primary chat” surface for many teams. Adding a Feishu channel plugin lets a user run Clawdbot as a personal assistant inside Feishu with the same security posture (pairing/allowlists) and the same agent routing + reply pipeline.
## Goals
- Ship a Feishu **channel plugin** under `extensions/` (installable from npm) that can:
- Receive inbound messages (DM + group) via Feishu event subscription callback.
- Respond with text replies (agent replies + `clawdbot message send`).
- Respect Clawdbots DM security model (pairing/allowlist/open/disabled).
- Support group allowlists + mention gating behavior consistent with other channels.
- Show up in onboarding as an installable channel (like Matrix/MSTeams plugins).
- Keep V1 minimal and consistent with existing integration patterns:
- `extensions/googlechat` for “HTTP webhook → monitor → reply dispatcher”
- `extensions/msteams` for “extension owns provider + status + onboarding”
## Non-goals (V1)
- Full message-card interactivity (buttons / card callbacks).
- Full media pipeline parity (file upload/download for every Feishu message type).
- Full directory/lookup parity (live user/group directory browsing).
- Multi-tenant ISV (app store) flow in the first pass (internal/self-built app only).
## Primary user
Single human operator running Clawdbot for personal use, inside one Feishu tenant.
## User journeys (high-level)
1. User installs and enables the Feishu plugin.
2. User creates a Feishu app (self-built/internal) with Bot capability enabled.
3. User configures event subscription callback URL (served by Clawdbot Gateway).
4. User DMs the bot; unknown DMs get pairing code; after approval bot answers.
5. User adds bot to a group; bot responds only when allowed and mention-gated.
## Functional requirements (high-level)
- Inbound:
- HTTP handler for Feishu event subscription callback.
- Support `url_verification` challenge handshake.
- Validate inbound requests (signature and/or verification token).
- Handle `im.message.receive_v1` events.
- Outbound:
- Send text messages to `open_id` (DM) and `chat_id` (group).
- Reply-to behavior: best-effort thread/reply mapping if Feishu supports it.
- Security:
- DM policy: `pairing` default; allowlists; `open`; `disabled`.
- Group policy: `allowlist` default; optional `open` with mention gating; `disabled`.
- Control command gating: ignore unauthorized control commands in group chats.
- Ops:
- `channels status` shows configured/running/probe/last inbound/outbound.
- `channels status --probe` validates token acquisition.
## Success criteria
- A user can complete onboarding and successfully:
- Receive a DM and get a pairing code.
- Approve pairing and receive a reply.
- Receive a group message and respond only when allowlisted + mention-gated.
- Send a message via `clawdbot message send --to <target>`.
## Decisions (confirmed)
1. **Region**: Feishu only.
2. **Inbound transport**: HTTP callback (event subscription webhook).
3. **V1 scope**: text-only.
## Risks and mitigations
- Misconfigured public exposure: document “only expose `/feishu` path” guidance and recommend a reverse proxy/Tailscale.
- Secret leakage: never log app secrets; store secrets only in config.
- Rate limits: cache tokens; chunk outbound messages via existing chunker helpers.
\*\*\* Add File: extensions/feishu/spec/design.md
# Tech design: Feishu (飞书) channel plugin
## Summary
Implement `@clawdbot/feishu` as a channel extension that:
- Registers a channel plugin (`api.registerChannel`) and an HTTP webhook handler (`api.registerHttpHandler`).
- Starts a per-account “monitor” on gateway start (via `plugin.gateway.startAccount`) that registers webhook targets and manages runtime status.
- Uses the existing Clawdbot reply pipeline (`runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher`) to route inbound messages to an agent and send outbound replies back to Feishu.
This follows the proven “webhook channel” structure in `extensions/googlechat`.
## Architecture
### Components
- **Feishu plugin entrypoint**: `extensions/feishu/index.ts`
- Stores `PluginRuntime` (like `extensions/googlechat/src/runtime.ts`).
- Registers channel + HTTP handler.
- **Channel plugin**: `extensions/feishu/src/channel.ts`
- Config adapter (accounts, enabled/configured, allowFrom formatting).
- Outbound adapter (sendText).
- Security adapter (DM policy warnings, group policy warnings).
- Status adapter (probe + runtime snapshot).
- Gateway adapter (startAccount → register webhook target).
- **Monitor / webhook handler**: `extensions/feishu/src/monitor.ts`
- Parses raw body, validates signature/token, decrypts if needed.
- Handles `url_verification`.
- Handles `im.message.receive_v1` text messages.
- Applies DM + group policies and mention gating.
- Builds inbound context and calls reply dispatcher.
- Sends replies via Feishu REST API.
- **API client**: `extensions/feishu/src/api.ts`
- Token manager: `tenant_access_token/internal` (self-built apps).
- Send message / reply message endpoints.
- Bot info (`/open-apis/bot/v3/info`) to detect mentions.
## Webhook verification and decryption
### URL verification
- Feishu sends a payload (plain or encrypted) where `type === "url_verification"` and includes `challenge`.
- The handler responds `200` with JSON: `{"challenge":"<challenge>"}`.
### Decrypt algorithm
- If payload has `encrypt`:
- Compute AES key = `sha256(encryptKey)` bytes (32 bytes).
- Decode `encrypt` from base64.
- IV = first 16 bytes; ciphertext = remaining bytes.
- Decrypt via `aes-256-cbc` to UTF-8 JSON.
### Signature validation (encrypted mode)
- Headers: `x-lark-request-timestamp`, `x-lark-request-nonce`, `x-lark-signature`.
- Compute: `sha256(timestamp + nonce + encryptKey + rawBodyString)` (hex).
- Compare with `x-lark-signature`.
- Use the raw request body string exactly as received (do not re-stringify parsed JSON).
### Token validation (non-encrypted mode)
- When `encryptKey` is not configured, validate `verificationToken` against payload `token` (or `header.token`).
## Mention gating
- Fetch and cache bot identity via `GET /open-apis/bot/v3/info`.
- In group chats:
- `wasMentioned = mentions.some(m => m.id.open_id === botOpenId || m.id.user_id === botUserId)`
- Apply `resolveMentionGatingWithBypass` with `requireMention` from group config or channel default.
## Test strategy
Colocate tests in `extensions/feishu/src/` (Vitest).
- Signature verification (valid/invalid).
- Decrypt (known encryptKey + payload → expected JSON).
- Target normalization.
- URL verification and event parsing.
\*\*\* Add File: extensions/feishu/spec/spec.md
# Spec: Feishu channel extension
## Requirements
### Requirement: Channel plugin availability
The system SHALL provide a Feishu chat channel as a Clawdbot extension plugin that can be installed and enabled without modifying core channel code.
#### Scenario: Plugin appears in onboarding catalog
- **GIVEN** a user runs `clawdbot onboard` in a workspace that contains the Feishu plugin (local path) or can access it on npm
- **WHEN** the user reaches the channel selection step
- **THEN** Feishu is listed as an installable channel plugin with a docs link
### Requirement: Webhook endpoint and URL verification
The system SHALL accept Feishu event subscription callbacks over HTTP and complete the platform “request URL verification” handshake.
#### Scenario: URL verification succeeds
- **GIVEN** Feishu sends a `type="url_verification"` callback payload with a `challenge`
- **WHEN** Clawdbot receives the POST at the configured webhook path
- **THEN** the response status is `200` and the response body is `{"challenge":"<value>"}` (JSON)
### Requirement: Request validation
The system SHALL validate inbound callback requests before processing events.
#### Scenario: Invalid signature/token is rejected
- **GIVEN** a callback request with an invalid signature (encrypted mode) OR mismatched verification token (non-encrypted mode)
- **WHEN** the request is received
- **THEN** the request is rejected with `401` and no message processing occurs
### Requirement: Encrypted payload support
When configured with an encrypt key, the system SHALL decrypt payloads that use the `encrypt` envelope.
#### Scenario: Encrypted event is processed
- **GIVEN** a callback request containing an `encrypt` field
- **WHEN** the plugin is configured with the correct `encryptKey`
- **THEN** the decrypted JSON is used for URL verification and event handling
### Requirement: Inbound message handling (DM)
The system SHALL process `im.message.receive_v1` DMs and route them into the Clawdbot agent pipeline with DM security policies.
#### Scenario: Unknown DM triggers pairing flow
- **GIVEN** `channels.feishu.dm.policy="pairing"`
- **AND** a DM sender is not allowlisted and not previously paired
- **WHEN** the sender DMs the bot
- **THEN** the system records a pairing request and replies with a pairing code message
### Requirement: Inbound message handling (groups)
The system SHALL process `im.message.receive_v1` group messages with group allowlists and mention gating.
#### Scenario: Group message is mention-gated
- **GIVEN** `channels.feishu.groupPolicy="open"` (or allowlisted group)
- **AND** `requireMention=true`
- **WHEN** a group message arrives without mentioning the bot
- **THEN** the system ignores the message and does not invoke the agent
### Requirement: Outbound text delivery
The system SHALL be able to send text messages to Feishu users and group chats.
#### Scenario: CLI message send delivers text
- **GIVEN** the user runs `clawdbot message send --to <feishu-target> --message "hi"`
- **WHEN** the target is a valid Feishu user (`open_id`) or chat (`chat_id`)
- **THEN** the plugin sends a Feishu API request that results in a visible message in the correct conversation
### Requirement: Status and probe visibility
The system SHALL expose Feishu channel health via `clawdbot channels status`, including an active probe that validates credentials.
#### Scenario: Probe fails with actionable error
- **GIVEN** the plugin is enabled but credentials are invalid
- **WHEN** the user runs `clawdbot channels status --probe`
- **THEN** the Feishu channel shows `probe=error` with an actionable message (e.g. token fetch failed)
\*\*\* Add File: extensions/feishu/spec/tasks.md
# Tasks: Add Feishu (飞书) channel extension
## 1. Extension scaffold
- [x] Create `extensions/feishu/` workspace package (`package.json`, `clawdbot.plugin.json`, `index.ts`, `src/`).
- [x] Add plugin catalog metadata in `extensions/feishu/package.json` (`clawdbot.channel` + `clawdbot.install`) so onboarding can install it.
## 2. Config + normalization
- [x] Define Feishu config Zod schema (extension-local) and expose it as `configSchema` via `buildChannelConfigSchema`.
- [x] Implement target normalization (`user:<open_id>`, `chat:<chat_id>`) and allowlist formatting.
- [x] Implement account model (start with default account; keep `accounts` extensible).
## 3. Token manager + API client
- [x] Implement tenant access token fetch + cache (`/auth/v3/tenant_access_token/internal`).
- [x] Implement Feishu “bot info” fetch (`/bot/v3/info`) for mention gating.
- [x] Implement send message (`/im/v1/messages`) and reply message (`/im/v1/messages/:message_id/reply`).
## 4. Webhook handler
- [x] Implement `handleFeishuWebhookRequest(req,res)` and register via `api.registerHttpHandler`.
- [x] Support `url_verification` challenge response (plain + encrypted).
- [x] Implement secure validation:
- [x] Raw-body capture with size limit.
- [x] Signature verification when `encryptKey` is configured.
- [x] Verification token checks when `encryptKey` is not configured.
- [x] Implement decrypt for payloads with `encrypt`.
## 5. Event processing + routing
- [x] Handle `im.message.receive_v1` (text-only V1):
- [x] DM policy + pairing store integration (mirror GoogleChat monitor behavior).
- [x] Group policy allowlists + mention gating integration.
- [x] Control command gating for group chats.
- [x] Build inbound context via `runtime.channel.reply.finalizeInboundContext` and dispatch replies via buffered dispatcher.
## 6. Outbound adapters
- [x] Implement `outbound.sendText` for `clawdbot message send` and heartbeats.
## 7. Status + probe
- [x] Implement `status` adapter snapshot + summary.
- [x] Implement `probeAccount` to validate credentials (token + bot info).
## 8. Onboarding
- [x] Add onboarding adapter with prompts for app id/secret and webhook settings.
## 9. Tests
- [x] Add unit tests for: signature, decrypt, target normalization.
- [ ] Add unit tests for: url_verification, event parsing.