diff --git a/CHANGELOG.md b/CHANGELOG.md index 407acfda2f3..3a0971d43b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Docs: https://docs.openclaw.ai ## Unreleased +### Changes + +- Channels/Yuanbao: register the Tencent Yuanbao external channel plugin (`openclaw-plugin-yuanbao`) in the official channel catalog, contract suites, and community plugin docs, with a new `docs/channels/yuanbao.md` quick-start guide for WebSocket bot DMs and group chats. (#72756) Thanks @loongfay. + ## 2026.4.26 ### Changes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bffda1fcd71..433a2c5bb92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,7 +77,7 @@ Welcome to the lobster tank! ๐Ÿฆž - **Tengji (George) Zhang** - Chinese model APIs, cloud, pi - GitHub: [@odysseus0](https://github.com/odysseus0) ยท X: [@odysseus0z](https://x.com/odysseus0z) -- **Sliverp** - Chinese Channel: QQ, WeChat, Wecom, Dingtalk, Feishu +- **Sliverp** - Chinese Channel: QQ, WeChat, Wecom, Yuanbao, Dingtalk, Feishu - GitHub: [@sliverp](https://github.com/sliverp) ยท X: [@sliver01234](https://x.com/sliver01234) - **Mason Huang** - Stability, Security, Speed diff --git a/docs/channels/yuanbao.md b/docs/channels/yuanbao.md new file mode 100644 index 00000000000..1f97566ee82 --- /dev/null +++ b/docs/channels/yuanbao.md @@ -0,0 +1,416 @@ +--- +summary: "YuanBao bot overview, features, and configuration" +read_when: + - You want to connect a YuanBao bot + - You are configuring the YuanBao channel +title: YuanBao +--- + +# YuanBao + +YuanBao is Tencent's AI assistant platform that supports bot integration via instant messaging. Bots can interact with users through direct messages and group chats. + +**Status:** production-ready for bot DMs + group chats. WebSocket is the only supported connection mode. + +--- + +## Quick start + +> **Requires OpenClaw 2026.4.10 or above.** Run `openclaw --version` to check. Upgrade with `openclaw update`. + + + + ```bash + openclaw channels add --channel yuanbao --token "appKey:appSecret" + ``` + The `--token` value uses colon-separated `appKey:appSecret` format. You can obtain these from the YuanBao APP by creating a robot in your application settings. + + + + ```bash + openclaw gateway restart + ``` + + + +### Interactive setup (alternative) + +You can also use the interactive wizard: + +```bash +openclaw channels login --channel yuanbao +``` + +Follow the prompts to enter your App ID and App Secret. + +--- + +## Access control + +### Direct messages + +Configure `dmPolicy` to control who can DM the bot: + +- `"pairing"` โ€” unknown users receive a pairing code; approve via CLI +- `"allowlist"` โ€” only users listed in `allowFrom` can chat +- `"open"` โ€” allow all users (default) +- `"disabled"` โ€” disable all DMs + +**Approve a pairing request:** + +```bash +openclaw pairing list yuanbao +openclaw pairing approve yuanbao +``` + +### Group chats + +**Mention requirement** (`channels.yuanbao.requireMention`): + +- `true` โ€” require @mention (default) +- `false` โ€” respond without @mention + +Replying to the bot's message in a group chat is treated as an implicit mention. + +--- + +## Configuration examples + +### Basic setup with open DM policy + +```json5 +{ + channels: { + yuanbao: { + appKey: "your_app_key", + appSecret: "your_app_secret", + dm: { + policy: "open", + }, + }, + }, +} +``` + +### Restrict DMs to specific users + +```json5 +{ + channels: { + yuanbao: { + appKey: "your_app_key", + appSecret: "your_app_secret", + dm: { + policy: "allowlist", + allowFrom: ["user_id_1", "user_id_2"], + }, + }, + }, +} +``` + +### Disable @mention requirement in groups + +```json5 +{ + channels: { + yuanbao: { + requireMention: false, + }, + }, +} +``` + +### Optimize outbound message delivery + +```json5 +{ + channels: { + yuanbao: { + // Send each chunk immediately without buffering + outboundQueueStrategy: "immediate", + }, + }, +} +``` + +### Tune merge-text strategy + +```json5 +{ + channels: { + yuanbao: { + outboundQueueStrategy: "merge-text", + minChars: 2800, // buffer until this many chars + maxChars: 3000, // force split above this limit + idleMs: 5000, // auto-flush after idle timeout (ms) + }, + }, +} +``` + +--- + +## Common commands + +| Command | Description | +| ---------- | --------------------------- | +| `/help` | Show available commands | +| `/status` | Show bot status | +| `/new` | Start a new session | +| `/stop` | Stop the current run | +| `/restart` | Restart OpenClaw | +| `/compact` | Compact the session context | + +> YuanBao supports native slash-command menus. Commands are synced to the platform automatically when the gateway starts. + +--- + +## Troubleshooting + +### Bot does not respond in group chats + +1. Ensure the bot is added to the group +2. Ensure you @mention the bot (required by default) +3. Check logs: `openclaw logs --follow` + +### Bot does not receive messages + +1. Ensure the bot is created and approved in YuanBao APP +2. Ensure `appKey` and `appSecret` are correctly configured +3. Ensure the gateway is running: `openclaw gateway status` +4. Check logs: `openclaw logs --follow` + +### Bot sends empty or fallback replies + +1. Check if the AI model is returning valid content +2. The default fallback reply is: "ๆš‚ๆ—ถๆ— ๆณ•่งฃ็ญ”๏ผŒไฝ ๅฏไปฅๆขไธช้—ฎ้ข˜้—ฎ้—ฎๆˆ‘ๅ“ฆ" +3. Customize it via `channels.yuanbao.fallbackReply` + +### App Secret leaked + +1. Reset the App Secret in YuanBao APP +2. Update the value in your config +3. Restart the gateway: `openclaw gateway restart` + +--- + +## Advanced configuration + +### Multiple accounts + +```json5 +{ + channels: { + yuanbao: { + defaultAccount: "main", + accounts: { + main: { + appKey: "key_xxx", + appSecret: "secret_xxx", + name: "Primary bot", + }, + backup: { + appKey: "key_yyy", + appSecret: "secret_yyy", + name: "Backup bot", + enabled: false, + }, + }, + }, + }, +} +``` + +`defaultAccount` controls which account is used when outbound APIs do not specify an `accountId`. + +### Message limits + +- `maxChars` โ€” single message max character count (default: `3000` chars) +- `mediaMaxMb` โ€” media upload/download limit (default: `20` MB) +- `overflowPolicy` โ€” behavior when message exceeds limit: `"split"` (default) or `"stop"` + +### Streaming + +YuanBao supports block-level streaming output. When enabled, the bot sends text in chunks as it generates. + +```json5 +{ + channels: { + yuanbao: { + disableBlockStreaming: false, // block streaming enabled (default) + }, + }, +} +``` + +Set `disableBlockStreaming: true` to send the complete reply in one message. + +### Group chat history context + +Control how many historical messages are included in the AI context for group chats: + +```json5 +{ + channels: { + yuanbao: { + historyLimit: 100, // default: 100, set 0 to disable + }, + }, +} +``` + +### Reply-to mode + +Control how the bot quotes messages when replying in group chats: + +```json5 +{ + channels: { + yuanbao: { + replyToMode: "first", // "off" | "first" | "all" (default: "first") + }, + }, +} +``` + +| Value | Behavior | +| --------- | -------------------------------------------------------- | +| `"off"` | No quote reply | +| `"first"` | Quote only the first reply per inbound message (default) | +| `"all"` | Quote every reply | + +### Markdown hint injection + +By default, the bot injects instructions in the system prompt to prevent the AI model from wrapping the entire reply in markdown code blocks. + +```json5 +{ + channels: { + yuanbao: { + markdownHintEnabled: true, // default: true + }, + }, +} +``` + +### Debug mode + +Enable unsanitized log output for specific bot IDs: + +```json5 +{ + channels: { + yuanbao: { + debugBotIds: ["bot_user_id_1", "bot_user_id_2"], + }, + }, +} +``` + +### Multi-agent routing + +Use `bindings` to route YuanBao DMs or groups to different agents. + +```json5 +{ + agents: { + list: [ + { id: "main" }, + { id: "agent-a", workspace: "/home/user/agent-a" }, + { id: "agent-b", workspace: "/home/user/agent-b" }, + ], + }, + bindings: [ + { + agentId: "agent-a", + match: { + channel: "yuanbao", + peer: { kind: "direct", id: "user_xxx" }, + }, + }, + { + agentId: "agent-b", + match: { + channel: "yuanbao", + peer: { kind: "group", id: "group_zzz" }, + }, + }, + ], +} +``` + +Routing fields: + +- `match.channel`: `"yuanbao"` +- `match.peer.kind`: `"direct"` (DM) or `"group"` (group chat) +- `match.peer.id`: user ID or group code + +--- + +## Configuration reference + +Full configuration: [Gateway configuration](/gateway/configuration) + +| Setting | Description | Default | +| ------------------------------------------ | ------------------------------------------------- | -------------------------------------- | +| `channels.yuanbao.enabled` | Enable/disable the channel | `true` | +| `channels.yuanbao.defaultAccount` | Default account for outbound routing | `default` | +| `channels.yuanbao.accounts..appKey` | App Key (used for signing and ticket generation) | โ€” | +| `channels.yuanbao.accounts..appSecret` | App Secret (used for signing) | โ€” | +| `channels.yuanbao.accounts..token` | Pre-signed token (skips automatic ticket signing) | โ€” | +| `channels.yuanbao.accounts..name` | Account display name | โ€” | +| `channels.yuanbao.accounts..enabled` | Enable/disable a specific account | `true` | +| `channels.yuanbao.dm.policy` | DM policy | `open` | +| `channels.yuanbao.dm.allowFrom` | DM allowlist (user ID list) | โ€” | +| `channels.yuanbao.requireMention` | Require @mention in groups | `true` | +| `channels.yuanbao.overflowPolicy` | Long message handling (`split` or `stop`) | `split` | +| `channels.yuanbao.replyToMode` | Group reply-to strategy (`off`, `first`, `all`) | `first` | +| `channels.yuanbao.outboundQueueStrategy` | Outbound strategy (`merge-text` or `immediate`) | `merge-text` | +| `channels.yuanbao.minChars` | Merge-text: min chars to trigger send | `2800` | +| `channels.yuanbao.maxChars` | Merge-text: max chars per message | `3000` | +| `channels.yuanbao.idleMs` | Merge-text: idle timeout before auto-flush (ms) | `5000` | +| `channels.yuanbao.mediaMaxMb` | Media size limit (MB) | `20` | +| `channels.yuanbao.historyLimit` | Group chat history context entries | `100` | +| `channels.yuanbao.disableBlockStreaming` | Disable block-level streaming output | `false` | +| `channels.yuanbao.fallbackReply` | Fallback reply when AI returns no content | `ๆš‚ๆ—ถๆ— ๆณ•่งฃ็ญ”๏ผŒไฝ ๅฏไปฅๆขไธช้—ฎ้ข˜้—ฎ้—ฎๆˆ‘ๅ“ฆ` | +| `channels.yuanbao.markdownHintEnabled` | Inject markdown anti-wrapping instructions | `true` | +| `channels.yuanbao.debugBotIds` | Debug whitelist bot IDs (unsanitized logs) | `[]` | + +--- + +## Supported message types + +### Receive + +- โœ… Text +- โœ… Images +- โœ… Files +- โœ… Audio / Voice +- โœ… Video +- โœ… Stickers / Custom emoji +- โœ… Custom elements (link cards, etc.) + +### Send + +- โœ… Text (with markdown support) +- โœ… Images +- โœ… Files +- โœ… Audio +- โœ… Video +- โœ… Stickers + +### Threads and replies + +- โœ… Quote replies (configurable via `replyToMode`) +- โŒ Thread replies (not supported by platform) + +--- + +## Related + +- [Channels Overview](/channels) โ€” all supported channels +- [Pairing](/channels/pairing) โ€” DM authentication and pairing flow +- [Groups](/channels/groups) โ€” group chat behavior and mention gating +- [Channel Routing](/channels/channel-routing) โ€” session routing for messages +- [Security](/gateway/security) โ€” access model and hardening diff --git a/docs/plugins/community.md b/docs/plugins/community.md index 7377194f546..33bf3189df1 100644 --- a/docs/plugins/community.md +++ b/docs/plugins/community.md @@ -130,6 +130,20 @@ formatting, built-in access control, and document/meeting/messaging skills. openclaw plugins install @wecom/wecom-openclaw-plugin ``` +### Yuanbao + +Yuanbao channel plugin for OpenClaw by the Tencent Yuanbao team. Powered by +WebSocket persistent connections, it supports direct messages & group chats, +streaming replies, proactive messaging, image/file/audio/video processing, +Markdown formatting, built-in access control, and slash-command menus. + +- **npm:** `openclaw-plugin-yuanbao` +- **repo:** [github.com/yb-claw/openclaw-plugin-yuanbao](https://github.com/yb-claw/openclaw-plugin-yuanbao) + +```bash +openclaw plugins install openclaw-plugin-yuanbao +``` + ## Submit your plugin We welcome community plugins that are useful, documented, and safe to operate. diff --git a/scripts/lib/official-external-channel-catalog.json b/scripts/lib/official-external-channel-catalog.json index 97f1f5eef54..2c7f1d01e05 100644 --- a/scripts/lib/official-external-channel-catalog.json +++ b/scripts/lib/official-external-channel-catalog.json @@ -23,6 +23,29 @@ "expectedIntegrity": "sha512-bnzfdIEEu1/LFvcdyjaTkyxt27w6c7dqhkPezU62OWaqmcdFsUGR3T55USK/O9pIKsNcnL1Tnu1pqKYCWHFgWQ==" } } + }, + { + "name": "openclaw-plugin-yuanbao", + "description": "OpenClaw Yuanbao channel plugin by the Tencent Yuanbao team.", + "source": "external", + "kind": "channel", + "openclaw": { + "channel": { + "id": "openclaw-plugin-yuanbao", + "label": "Yuanbao", + "selectionLabel": "Yuanbao (ๅ…ƒๅฎ)", + "detailLabel": "Yuanbao", + "docsPath": "/plugins/community#yuanbao", + "docsLabel": "yuanbao", + "blurb": "Tencent Yuanbao AI assistant conversation channel.", + "aliases": ["yb", "tencent-yuanbao", "ๅ…ƒๅฎ"], + "order": 85 + }, + "install": { + "npmSpec": "openclaw-plugin-yuanbao", + "defaultChoice": "npm" + } + } } ] } diff --git a/src/channels/plugins/contracts/channel-catalog.contract.test.ts b/src/channels/plugins/contracts/channel-catalog.contract.test.ts index 6240bf4121e..a9bd782b763 100644 --- a/src/channels/plugins/contracts/channel-catalog.contract.test.ts +++ b/src/channels/plugins/contracts/channel-catalog.contract.test.ts @@ -42,3 +42,9 @@ describeChannelCatalogEntryContract({ npmSpec: "@wecom/wecom-openclaw-plugin@2026.4.23", alias: "wework", }); + +describeChannelCatalogEntryContract({ + channelId: "openclaw-plugin-yuanbao", + npmSpec: "openclaw-plugin-yuanbao", + alias: "yb", +}); diff --git a/test/helpers/channels/channel-plugin-catalog-contract-suites.ts b/test/helpers/channels/channel-plugin-catalog-contract-suites.ts index 73823833b3c..e31a31eb9f8 100644 --- a/test/helpers/channels/channel-plugin-catalog-contract-suites.ts +++ b/test/helpers/channels/channel-plugin-catalog-contract-suites.ts @@ -281,6 +281,71 @@ export function describeChannelPluginCatalogEntriesContract() { }; }, }, + { + name: "accepts rich external manifest entries for yuanbao with pinned npm metadata", + setup: () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-catalog-yuanbao-")); + const catalogPath = path.join(dir, "catalog.json"); + fs.writeFileSync( + catalogPath, + JSON.stringify({ + $schema: "./manifest.schema.json", + schemaVersion: 1, + description: + "Extension manifest. Declares plugin packages that OpenClaw can discover during onboarding and install on demand via `openclaw plugins install`.", + entries: [ + { + name: "openclaw-plugin-yuanbao", + description: + "OpenClaw Yuanbao (ๅ…ƒๅฎ) channel plugin โ€” community maintained, published on npm.", + source: "external", + kind: "channel", + openclaw: { + channel: { + id: "openclaw-plugin-yuanbao", + label: "Yuanbao", + selectionLabel: "Yuanbao (Tencent Yuanbao)", + detailLabel: "Yuanbao", + docsPath: "/channels/yuanbao", + docsLabel: "yuanbao", + blurb: "Tencent Yuanbao AI assistant conversation channel.", + aliases: ["yb", "tencent-yuanbao"], + order: 78, + }, + install: { + npmSpec: "openclaw-plugin-yuanbao@1.0.0", + defaultChoice: "npm", + minHostVersion: ">=2026.4.10", + expectedIntegrity: "sha512-yuanbao", + }, + }, + }, + ], + }), + ); + return { + channelId: "openclaw-plugin-yuanbao", + catalogPaths: [catalogPath], + expected: { + id: "openclaw-plugin-yuanbao", + meta: { + label: "Yuanbao", + selectionLabel: "Yuanbao (Tencent Yuanbao)", + detailLabel: "Yuanbao", + docsPath: "/channels/yuanbao", + docsLabel: "yuanbao", + blurb: "Tencent Yuanbao AI assistant conversation channel.", + }, + install: { + npmSpec: "openclaw-plugin-yuanbao@1.0.0", + defaultChoice: "npm", + minHostVersion: ">=2026.4.10", + expectedIntegrity: "sha512-yuanbao", + }, + }, + }; + }, + }, ] as const)("$name", ({ setup }) => { const setupResult = setup(); const { channelId, expected } = setupResult; diff --git a/test/official-channel-catalog.test.ts b/test/official-channel-catalog.test.ts index c9e186381f0..5b50a5505d8 100644 --- a/test/official-channel-catalog.test.ts +++ b/test/official-channel-catalog.test.ts @@ -86,6 +86,19 @@ describe("buildOfficialChannelCatalog", () => { }, }), }), + expect.objectContaining({ + name: "openclaw-plugin-yuanbao", + openclaw: expect.objectContaining({ + channel: expect.objectContaining({ + id: "openclaw-plugin-yuanbao", + label: "Yuanbao", + }), + install: { + npmSpec: "openclaw-plugin-yuanbao", + defaultChoice: "npm", + }, + }), + }), { name: "@openclaw/whatsapp", version: "2026.3.23", @@ -153,6 +166,9 @@ describe("buildOfficialChannelCatalog", () => { expect.objectContaining({ name: "@wecom/wecom-openclaw-plugin", }), + expect.objectContaining({ + name: "openclaw-plugin-yuanbao", + }), { name: "@openclaw/whatsapp", openclaw: {