openclaw/extensions/feishu/spec/proposal.md

189 lines
8.1 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 (HTTP callback or long connection).
- 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 delivery (HTTP callback or long connection).
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 (`mode="http"`).
- Long connection listener for Feishu event subscription (`mode="ws"`).
- 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 and long connection.
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.
### 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.
#### 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)