openclaw-channel-xiaozhu 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +421 -65
- package/demo/app.js +350 -0
- package/demo/index.html +36 -0
- package/demo/style.css +249 -0
- package/demo/think.css +590 -0
- package/demo/think.html +92 -0
- package/demo/think.js +532 -0
- package/dist/channel.d.ts +22 -1
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +144 -74
- package/dist/channel.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/relay/cli.d.ts +10 -0
- package/dist/relay/cli.d.ts.map +1 -0
- package/dist/relay/cli.js +28 -0
- package/dist/relay/cli.js.map +1 -0
- package/dist/relay/client.d.ts +23 -0
- package/dist/relay/client.d.ts.map +1 -0
- package/dist/relay/client.js +242 -0
- package/dist/relay/client.js.map +1 -0
- package/dist/relay/protocol.d.ts +31 -0
- package/dist/relay/protocol.d.ts.map +1 -0
- package/dist/relay/protocol.js +5 -0
- package/dist/relay/protocol.js.map +1 -0
- package/dist/relay/server.d.ts +16 -0
- package/dist/relay/server.d.ts.map +1 -0
- package/dist/relay/server.js +322 -0
- package/dist/relay/server.js.map +1 -0
- package/dist/sdk/index.d.ts +259 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +415 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/sse.d.ts +18 -0
- package/dist/sdk/sse.d.ts.map +1 -0
- package/dist/sdk/sse.js +67 -0
- package/dist/sdk/sse.js.map +1 -0
- package/dist/sdk/types.d.ts +231 -0
- package/dist/sdk/types.d.ts.map +1 -0
- package/dist/sdk/types.js +5 -0
- package/dist/sdk/types.js.map +1 -0
- package/dist/server.d.ts +5 -3
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +616 -263
- package/dist/server.js.map +1 -0
- package/dist/shared/errors.d.ts +47 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +52 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/http-utils.d.ts +20 -0
- package/dist/shared/http-utils.d.ts.map +1 -0
- package/dist/shared/http-utils.js +109 -0
- package/dist/shared/http-utils.js.map +1 -0
- package/dist/shared/inbound.d.ts +45 -0
- package/dist/shared/inbound.d.ts.map +1 -0
- package/dist/shared/inbound.js +76 -0
- package/dist/shared/inbound.js.map +1 -0
- package/dist/shared/security.d.ts +19 -0
- package/dist/shared/security.d.ts.map +1 -0
- package/dist/shared/security.js +63 -0
- package/dist/shared/security.js.map +1 -0
- package/dist/standalone/app.d.ts +16 -0
- package/dist/standalone/app.d.ts.map +1 -0
- package/dist/standalone/app.js +194 -0
- package/dist/standalone/app.js.map +1 -0
- package/dist/standalone/auth.d.ts +19 -0
- package/dist/standalone/auth.d.ts.map +1 -0
- package/dist/standalone/auth.js +45 -0
- package/dist/standalone/auth.js.map +1 -0
- package/dist/standalone/cli.d.ts +10 -0
- package/dist/standalone/cli.d.ts.map +1 -0
- package/dist/standalone/cli.js +107 -0
- package/dist/standalone/cli.js.map +1 -0
- package/dist/standalone/media-store.d.ts +30 -0
- package/dist/standalone/media-store.d.ts.map +1 -0
- package/dist/standalone/media-store.js +150 -0
- package/dist/standalone/media-store.js.map +1 -0
- package/dist/standalone/migrate-to-sqlite.d.ts +10 -0
- package/dist/standalone/migrate-to-sqlite.d.ts.map +1 -0
- package/dist/standalone/migrate-to-sqlite.js +194 -0
- package/dist/standalone/migrate-to-sqlite.js.map +1 -0
- package/dist/standalone/router.d.ts +34 -0
- package/dist/standalone/router.d.ts.map +1 -0
- package/dist/standalone/router.js +94 -0
- package/dist/standalone/router.js.map +1 -0
- package/dist/standalone/routes.d.ts +12 -0
- package/dist/standalone/routes.d.ts.map +1 -0
- package/dist/standalone/routes.js +508 -0
- package/dist/standalone/routes.js.map +1 -0
- package/dist/standalone/server-context.d.ts +73 -0
- package/dist/standalone/server-context.d.ts.map +1 -0
- package/dist/standalone/server-context.js +38 -0
- package/dist/standalone/server-context.js.map +1 -0
- package/dist/standalone/store.d.ts +36 -0
- package/dist/standalone/store.d.ts.map +1 -0
- package/dist/standalone/store.js +163 -0
- package/dist/standalone/store.js.map +1 -0
- package/dist/standalone/thought-db.d.ts +92 -0
- package/dist/standalone/thought-db.d.ts.map +1 -0
- package/dist/standalone/thought-db.js +677 -0
- package/dist/standalone/thought-db.js.map +1 -0
- package/dist/standalone/thought-processor.d.ts +36 -0
- package/dist/standalone/thought-processor.d.ts.map +1 -0
- package/dist/standalone/thought-processor.js +352 -0
- package/dist/standalone/thought-processor.js.map +1 -0
- package/dist/standalone/thought-routes.d.ts +13 -0
- package/dist/standalone/thought-routes.d.ts.map +1 -0
- package/dist/standalone/thought-routes.js +326 -0
- package/dist/standalone/thought-routes.js.map +1 -0
- package/dist/standalone/thought-store-factory.d.ts +12 -0
- package/dist/standalone/thought-store-factory.d.ts.map +1 -0
- package/dist/standalone/thought-store-factory.js +20 -0
- package/dist/standalone/thought-store-factory.js.map +1 -0
- package/dist/standalone/thought-store.d.ts +103 -0
- package/dist/standalone/thought-store.d.ts.map +1 -0
- package/dist/standalone/thought-store.js +502 -0
- package/dist/standalone/thought-store.js.map +1 -0
- package/dist/standalone/thought-types.d.ts +169 -0
- package/dist/standalone/thought-types.d.ts.map +1 -0
- package/dist/standalone/thought-types.js +5 -0
- package/dist/standalone/thought-types.js.map +1 -0
- package/dist/standalone/types.d.ts +105 -0
- package/dist/standalone/types.d.ts.map +1 -0
- package/dist/standalone/types.js +5 -0
- package/dist/standalone/types.js.map +1 -0
- package/dist/standalone/ws-handler.d.ts +16 -0
- package/dist/standalone/ws-handler.d.ts.map +1 -0
- package/dist/standalone/ws-handler.js +183 -0
- package/dist/standalone/ws-handler.js.map +1 -0
- package/dist/types.d.ts +62 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/coalescer.d.ts +6 -0
- package/dist/utils/coalescer.d.ts.map +1 -0
- package/dist/utils/coalescer.js +26 -2
- package/dist/utils/coalescer.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +13 -2
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +50 -10
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/session-store.d.ts +32 -0
- package/dist/utils/session-store.d.ts.map +1 -0
- package/dist/utils/session-store.js +83 -0
- package/dist/utils/session-store.js.map +1 -0
- package/dist/utils/text-chunker.d.ts +14 -0
- package/dist/utils/text-chunker.d.ts.map +1 -0
- package/dist/utils/text-chunker.js +70 -0
- package/dist/utils/text-chunker.js.map +1 -0
- package/dist/utils/ttl-set.d.ts +1 -0
- package/dist/utils/ttl-set.d.ts.map +1 -0
- package/dist/utils/ttl-set.js +2 -1
- package/dist/utils/ttl-set.js.map +1 -0
- package/dist/utils/webhook-sender.d.ts +27 -0
- package/dist/utils/webhook-sender.d.ts.map +1 -0
- package/dist/utils/webhook-sender.js +59 -0
- package/dist/utils/webhook-sender.js.map +1 -0
- package/docs/API.md +1514 -141
- package/docs/DEVELOPMENT.md +299 -0
- package/docs/MILESTONES.md +135 -0
- package/docs/RISKS.md +179 -0
- package/docs/ROADMAP.md +144 -0
- package/openclaw.plugin.json +3 -0
- package/package.json +39 -3
- package/skills/openclaw-browser-quality/SKILL.md +32 -0
- package/skills/openclaw-browser-quality/references/browser-usage.md +134 -0
- package/skills/openclaw-browser-quality/references/quality-guidelines.md +19 -0
- package/skills/xiaozhu-cron-job/SKILL.md +169 -0
- package/skills/xiaozhu-send-media/SKILL.md +95 -0
package/README.md
CHANGED
|
@@ -1,106 +1,432 @@
|
|
|
1
1
|
# openclaw-channel-xiaozhu
|
|
2
2
|
|
|
3
|
-
小助 — OpenClaw 通用渠道插件,通过标准 HTTP/SSE 接口将任意客户端接入 OpenClaw 对话引擎。与钉钉(`
|
|
3
|
+
小助 — OpenClaw 通用渠道插件,通过标准 HTTP/SSE 接口将任意客户端接入 OpenClaw 对话引擎。与钉钉(`clawdbot-dingtalk`)、飞书等渠道并列,是面向自定义客户端的通用接入渠道。
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- 同步聊天 (`POST /api/chat`) 与 SSE 流式聊天 (`POST /api/chat/stream`)
|
|
8
|
-
-
|
|
7
|
+
- 同步聊天 (`POST /api/chat`) 与 SSE 流式聊天 (`POST /api/chat/stream`)
|
|
8
|
+
- SSE 心跳保活(防代理/LB 超时断连)
|
|
9
|
+
- SSE typing 状态指示(thinking → generating)
|
|
10
|
+
- 可配置文本合并缓冲(sizeThreshold / idleTimeoutMs)
|
|
11
|
+
- 滑动窗口限流 + 突发控制 + Per-IP 独立限流
|
|
9
12
|
- 消息去重(TTL 集合)
|
|
10
13
|
- 发送者白名单 (`allowFrom`)
|
|
11
14
|
- 群聊支持 (`chatType: "group"`)
|
|
12
15
|
- 多媒体消息:图片、音频、文件(base64 / URL)
|
|
16
|
+
- 文件上传端点 (`POST /api/upload`,支持 multipart 和 raw binary)
|
|
13
17
|
- 媒体文件托管 (`GET /api/media/:id`)
|
|
14
18
|
- 语音转文字 (`POST /api/stt`,基于 Whisper)
|
|
15
19
|
- 文字转语音 (`POST /api/tts`,基于 edge-tts)
|
|
16
|
-
- Webhook 外发消息
|
|
20
|
+
- Webhook 外发消息 + HMAC-SHA256 签名 + 指数退避重试
|
|
21
|
+
- 会话管理 API (`GET /api/sessions`, `DELETE /api/sessions/:id`)
|
|
22
|
+
- 聊天命令 (`/new`, `/help`, `/sessions`)
|
|
23
|
+
- 多账号支持(单配置向后兼容)
|
|
24
|
+
- 超长回复围栏感知分块(不在代码块内断开)
|
|
25
|
+
- Request ID 追踪 + Access Log
|
|
26
|
+
- 优雅关闭(排空活跃 SSE 连接)
|
|
17
27
|
- 可配置 CORS 来源
|
|
18
28
|
- 常量时间 Token 比较(防时序攻击)
|
|
29
|
+
- SSRF 防护(Webhook/STT URL 校验,拦截内网地址含 IPv6)
|
|
30
|
+
- Slowloris 防护(请求体读取 30s 超时)
|
|
31
|
+
- 请求体大小预检(Content-Length 提前拒绝)
|
|
32
|
+
- 云端中继模式(无公网 IP 时通过 WebSocket 反向连接)
|
|
33
|
+
- **独立服务端**(脱离 OpenClaw 运行,多 Bot 路由 + Admin API)
|
|
34
|
+
- **思维引擎**(Experimental)— AI 驱动的个人知识管理(想法捕获 → 结构化 → 关联发现 → 洞察 → 作品组装)
|
|
35
|
+
- **客户端 SDK**(TypeScript,浏览器 + Node.js 兼容)
|
|
36
|
+
- **Web Demo**(聊天界面 + 思维引擎界面)
|
|
37
|
+
- 聊天记录导出/导入(纯客户端,服务器不存储)
|
|
19
38
|
|
|
20
|
-
##
|
|
39
|
+
## 安装部署
|
|
21
40
|
|
|
22
|
-
###
|
|
41
|
+
### 前置条件
|
|
23
42
|
|
|
24
43
|
- Node.js >= 20
|
|
25
|
-
- OpenClaw >= 2026.1
|
|
44
|
+
- OpenClaw >= 2026.1(已安装并运行)
|
|
45
|
+
- C++ 编译工具链(可选,独立服务端的思维引擎需要 `better-sqlite3`,这是一个 native addon。不安装则思维引擎功能不可用,其他功能正常)
|
|
26
46
|
|
|
27
|
-
###
|
|
47
|
+
### 第一步:安装插件
|
|
28
48
|
|
|
29
49
|
```bash
|
|
30
|
-
npm install openclaw-channel-xiaozhu
|
|
50
|
+
npm install -g openclaw-channel-xiaozhu
|
|
31
51
|
```
|
|
32
52
|
|
|
33
|
-
|
|
53
|
+
> 如果你的 npm 默认源是淘宝镜像,新包同步可能有延迟,可指定官方源:
|
|
54
|
+
> ```bash
|
|
55
|
+
> npm install -g openclaw-channel-xiaozhu --registry=https://registry.npmjs.org/
|
|
56
|
+
> ```
|
|
34
57
|
|
|
35
|
-
|
|
36
|
-
npm run build
|
|
37
|
-
```
|
|
58
|
+
### 第二步:配置渠道
|
|
38
59
|
|
|
39
|
-
|
|
60
|
+
编辑 `~/.openclaw/openclaw.json`,在 `channels` 中添加小助渠道配置:
|
|
40
61
|
|
|
41
|
-
|
|
62
|
+
**单账号模式(推荐):**
|
|
42
63
|
|
|
43
|
-
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"channels": {
|
|
67
|
+
"channel-xiaozhu": {
|
|
68
|
+
"enabled": true,
|
|
69
|
+
"port": 18800,
|
|
70
|
+
"token": "your-secret-token",
|
|
71
|
+
"allowFrom": ["*"],
|
|
72
|
+
"allowOrigins": ["*"]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
44
77
|
|
|
45
|
-
|
|
78
|
+
**多账号模式:**
|
|
46
79
|
|
|
47
80
|
```json
|
|
48
81
|
{
|
|
49
|
-
"channels":
|
|
50
|
-
{
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
"port":
|
|
54
|
-
"token": "your-secret-token",
|
|
55
|
-
"rateLimitWindowMs": 60000,
|
|
56
|
-
"rateLimitMax": 60,
|
|
57
|
-
"rateLimitBurst": 10,
|
|
58
|
-
"dedupTtlMs": 5000,
|
|
59
|
-
"allowFrom": ["*"],
|
|
60
|
-
"webhookUrl": "",
|
|
61
|
-
"allowOrigins": ["*"]
|
|
82
|
+
"channels": {
|
|
83
|
+
"channel-xiaozhu": {
|
|
84
|
+
"accounts": {
|
|
85
|
+
"bot-a": { "port": 18800, "token": "token-a" },
|
|
86
|
+
"bot-b": { "port": 18801, "token": "token-b" }
|
|
62
87
|
}
|
|
63
88
|
}
|
|
64
|
-
|
|
89
|
+
}
|
|
65
90
|
}
|
|
66
91
|
```
|
|
67
92
|
|
|
93
|
+
**无公网 IP(云端中继模式):**
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"channels": {
|
|
98
|
+
"channel-xiaozhu": {
|
|
99
|
+
"port": 18800,
|
|
100
|
+
"token": "your-secret-token",
|
|
101
|
+
"networkMode": "cloud"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> 默认连接 `wss://relay.xiaozhu.ai/ws/bot`。也可以自建中继服务器:
|
|
108
|
+
> ```json
|
|
109
|
+
> {
|
|
110
|
+
> "networkMode": "cloud",
|
|
111
|
+
> "relayUrl": "wss://my-vps.com:8080/ws/bot",
|
|
112
|
+
> "relayToken": "my-relay-secret"
|
|
113
|
+
> }
|
|
114
|
+
> ```
|
|
115
|
+
>
|
|
116
|
+
> 自建中继:`npx xiaozhu-relay --port 8080 --token my-relay-secret`
|
|
117
|
+
|
|
118
|
+
> 注意:与已有配置合并,不要覆盖其他渠道(如钉钉)的配置。
|
|
119
|
+
|
|
120
|
+
### 第三步:重启 OpenClaw
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
systemctl --user restart openclaw-gateway.service
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 第四步:验证
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# 健康检查(不需要鉴权)
|
|
130
|
+
curl http://localhost:18800/api/health
|
|
131
|
+
|
|
132
|
+
# 测试对话
|
|
133
|
+
curl -X POST http://localhost:18800/api/chat \
|
|
134
|
+
-H "Authorization: Bearer your-secret-token" \
|
|
135
|
+
-H "Content-Type: application/json" \
|
|
136
|
+
-d '{"message": "你好", "session": "test-001"}'
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 第五步:防火墙放行(如需外部访问)
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
sudo firewall-cmd --permanent --add-port=18800/tcp
|
|
143
|
+
sudo firewall-cmd --reload
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 配置项
|
|
147
|
+
|
|
68
148
|
| 字段 | 类型 | 默认值 | 说明 |
|
|
69
149
|
|------|------|--------|------|
|
|
70
|
-
| `port` | number | `
|
|
150
|
+
| `port` | number | `18800` | HTTP 监听端口 |
|
|
71
151
|
| `token` | string | — | 鉴权 Token(必填) |
|
|
72
152
|
| `rateLimitWindowMs` | number | `60000` | 限流滑动窗口(毫秒) |
|
|
73
|
-
| `rateLimitMax` | number | `
|
|
74
|
-
| `rateLimitBurst` | number | `
|
|
75
|
-
| `dedupTtlMs` | number | `
|
|
153
|
+
| `rateLimitMax` | number | `20` | 窗口内最大请求数 |
|
|
154
|
+
| `rateLimitBurst` | number | `5` | 突发请求上限 |
|
|
155
|
+
| `dedupTtlMs` | number | `300000` | 消息去重 TTL(毫秒) |
|
|
76
156
|
| `allowFrom` | string[] | `["*"]` | 允许的发送者 ID,`*` 表示全部 |
|
|
77
|
-
| `webhookUrl` | string | `""` | Webhook
|
|
157
|
+
| `webhookUrl` | string | `""` | Webhook 回调地址 |
|
|
158
|
+
| `webhookSecret` | string | `""` | Webhook HMAC-SHA256 签名密钥 |
|
|
159
|
+
| `webhookRetry` | object | — | `{ maxAttempts: 3, baseDelayMs: 1000 }` |
|
|
78
160
|
| `allowOrigins` | string[] | `["*"]` | CORS 允许的来源 |
|
|
161
|
+
| `heartbeatIntervalMs` | number | `15000` | SSE 心跳间隔,0 禁用 |
|
|
162
|
+
| `textChunkLimit` | number | `4000` | 同步响应分块上限 |
|
|
163
|
+
| `commandsEnabled` | boolean | `true` | 是否启用聊天命令 |
|
|
164
|
+
| `coalesce` | object | — | `{ sizeThreshold: 200, idleTimeoutMs: 500 }` |
|
|
165
|
+
| `perIpRateLimit` | object | — | `{ windowMs: 60000, max: 10 }` |
|
|
166
|
+
| `networkMode` | string | — | 网络模式:`"webhook"`(有公网 IP)或 `"cloud"`(无公网 IP,走云端中继) |
|
|
167
|
+
| `relayUrl` | string | `wss://relay.xiaozhu.ai/ws/bot` | 自定义中继服务器地址(cloud 模式) |
|
|
168
|
+
| `relayToken` | string | — | 中继鉴权 token(不配则复用 token) |
|
|
79
169
|
|
|
80
|
-
## API
|
|
170
|
+
## API
|
|
81
171
|
|
|
82
172
|
| Method | Path | Auth | Description |
|
|
83
173
|
|--------|------|------|-------------|
|
|
84
|
-
| `POST` | `/api/chat` | Yes |
|
|
85
|
-
| `POST` | `/api/chat/stream` | Yes | SSE
|
|
86
|
-
| `
|
|
174
|
+
| `POST` | `/api/chat` | Yes | 同步聊天,返回完整回复 |
|
|
175
|
+
| `POST` | `/api/chat/stream` | Yes | SSE 流式聊天(含 typing + heartbeat) |
|
|
176
|
+
| `POST` | `/api/upload` | Yes | 文件上传(multipart 或 raw binary) |
|
|
177
|
+
| `GET` | `/api/media/:id` | No | 获取媒体文件 |
|
|
178
|
+
| `GET` | `/api/sessions` | Yes | 列出活跃会话 |
|
|
179
|
+
| `DELETE` | `/api/sessions/:id` | Yes | 删除会话 |
|
|
87
180
|
| `POST` | `/api/stt` | Yes | 语音转文字 |
|
|
88
181
|
| `POST` | `/api/tts` | Yes | 文字转语音 |
|
|
89
182
|
| `POST` | `/api/webhook/register` | Yes | 注册 Webhook |
|
|
183
|
+
| `DELETE` | `/api/webhook` | Yes | 注销 Webhook |
|
|
90
184
|
| `GET` | `/api/health` | No | 健康检查 |
|
|
91
185
|
|
|
92
186
|
完整 API 文档见 [docs/API.md](docs/API.md)。
|
|
93
187
|
|
|
94
|
-
##
|
|
188
|
+
## 独立服务端
|
|
189
|
+
|
|
190
|
+
独立服务端可脱离 OpenClaw 运行,作为多 Bot 接入平台。客户端通过 HTTP/SSE 对话,Bot 通过 WebSocket 连接。服务器不存储任何聊天记录。
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# 启动
|
|
194
|
+
npx xiaozhu-server --port 9000 --admin-key my-secret
|
|
195
|
+
|
|
196
|
+
# 或使用配置文件
|
|
197
|
+
npx xiaozhu-server --config ~/.xiaozhu-server/config.json
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**快速开始:**
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# 1. 注册 Bot
|
|
204
|
+
curl -X POST http://localhost:9000/admin/bots \
|
|
205
|
+
-H "Authorization: Bearer my-secret" \
|
|
206
|
+
-H "Content-Type: application/json" \
|
|
207
|
+
-d '{"name":"my-bot"}'
|
|
208
|
+
|
|
209
|
+
# 2. 创建 API Key
|
|
210
|
+
curl -X POST http://localhost:9000/admin/keys \
|
|
211
|
+
-H "Authorization: Bearer my-secret" \
|
|
212
|
+
-H "Content-Type: application/json" \
|
|
213
|
+
-d '{"label":"demo"}'
|
|
214
|
+
|
|
215
|
+
# 3. Bot 通过 WebSocket 连接
|
|
216
|
+
# ws://localhost:9000/ws/bot?token=<bot-token>
|
|
217
|
+
|
|
218
|
+
# 4. 客户端对话
|
|
219
|
+
curl -X POST http://localhost:9000/api/chat \
|
|
220
|
+
-H "Authorization: Bearer <api-key>" \
|
|
221
|
+
-H "Content-Type: application/json" \
|
|
222
|
+
-d '{"message":"你好"}'
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**独立服务端 API:**
|
|
226
|
+
|
|
227
|
+
| Method | Path | Auth | Description |
|
|
228
|
+
|--------|------|------|-------------|
|
|
229
|
+
| `GET` | `/api/health` | No | 健康检查(含在线 Bot 列表) |
|
|
230
|
+
| `POST` | `/api/chat` | API Key | 同步对话(支持 `botId` 指定目标 Bot) |
|
|
231
|
+
| `POST` | `/api/chat/stream` | API Key | SSE 流式对话 |
|
|
232
|
+
| `POST` | `/api/upload` | API Key | 文件上传 |
|
|
233
|
+
| `GET` | `/api/media/:id` | No | 媒体访问 |
|
|
234
|
+
| `GET` | `/api/bots` | API Key | 列出可用 Bot |
|
|
235
|
+
| `POST` | `/api/stt` | API Key | 语音转文字(转发到 Bot) |
|
|
236
|
+
| `POST` | `/api/tts` | API Key | 文字转语音(转发到 Bot) |
|
|
237
|
+
| `POST` | `/admin/bots` | Admin | 注册 Bot |
|
|
238
|
+
| `PUT` | `/admin/bots/:id` | Admin | 更新 Bot 配置 |
|
|
239
|
+
| `DELETE` | `/admin/bots/:id` | Admin | 删除 Bot |
|
|
240
|
+
| `GET` | `/admin/bots` | Admin | 列出 Bot(含在线状态) |
|
|
241
|
+
| `POST` | `/admin/keys` | Admin | 创建 API Key |
|
|
242
|
+
| `PUT` | `/admin/keys/:id` | Admin | 更新 API Key 配置 |
|
|
243
|
+
| `DELETE` | `/admin/keys/:id` | Admin | 删除 API Key |
|
|
244
|
+
| `GET` | `/admin/keys` | Admin | 列出 API Key |
|
|
245
|
+
|
|
246
|
+
**配置文件格式:**
|
|
247
|
+
|
|
248
|
+
```json
|
|
249
|
+
{
|
|
250
|
+
"port": 9000,
|
|
251
|
+
"adminKey": "my-secret",
|
|
252
|
+
"dataDir": "~/.xiaozhu-server",
|
|
253
|
+
"corsOrigin": "*",
|
|
254
|
+
"nodeId": "node-1",
|
|
255
|
+
"peers": ["http://127.0.0.1:9001"]
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
| 字段 | 必填 | 默认值 | 说明 |
|
|
260
|
+
|------|------|--------|------|
|
|
261
|
+
| `port` | 否 | `9000` | HTTP 监听端口 |
|
|
262
|
+
| `adminKey` | 是 | — | Admin Key(同时可作为 API Key) |
|
|
263
|
+
| `dataDir` | 否 | `~/.xiaozhu-server` | 数据存储目录 |
|
|
264
|
+
| `corsOrigin` | 否 | `*` | CORS 允许的来源 |
|
|
265
|
+
| `nodeId` | 否 | 随机生成 | 节点唯一标识(多节点部署时用于队列锁) |
|
|
266
|
+
| `peers` | 否 | `[]` | 对等节点地址列表(多节点部署) |
|
|
267
|
+
|
|
268
|
+
## 客户端 SDK
|
|
269
|
+
|
|
270
|
+
TypeScript SDK,浏览器和 Node.js 兼容。聊天记录保存在客户端内存,支持导出/导入,服务器不存储。
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
import { XiaozhuClient } from "openclaw-channel-xiaozhu/sdk";
|
|
274
|
+
|
|
275
|
+
const client = new XiaozhuClient({
|
|
276
|
+
baseUrl: "http://localhost:9000",
|
|
277
|
+
apiKey: "xz_your-api-key",
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// 同步对话
|
|
281
|
+
const result = await client.chat({ message: "你好", session: "s1" });
|
|
282
|
+
console.log(result.reply);
|
|
283
|
+
|
|
284
|
+
// 流式对话
|
|
285
|
+
const stream = client.chatStream({ message: "你好", session: "s1" }, {
|
|
286
|
+
onChunk: (text) => process.stdout.write(text),
|
|
287
|
+
onDone: (fullText) => console.log("\n完成"),
|
|
288
|
+
});
|
|
289
|
+
await stream.done;
|
|
290
|
+
|
|
291
|
+
// 列出在线 Bot
|
|
292
|
+
const bots = await client.listBots();
|
|
293
|
+
|
|
294
|
+
// 文件上传
|
|
295
|
+
const media = await client.upload(file);
|
|
296
|
+
|
|
297
|
+
// 语音转文字 / 文字转语音
|
|
298
|
+
const stt = await client.stt("data:audio/mp3;base64,...");
|
|
299
|
+
const tts = await client.tts("你好");
|
|
300
|
+
|
|
301
|
+
// 聊天记录导出(纯客户端,服务器不存储)
|
|
302
|
+
const json = client.exportHistory("s1");
|
|
303
|
+
|
|
304
|
+
// 聊天记录导入
|
|
305
|
+
client.importHistory(json);
|
|
306
|
+
|
|
307
|
+
// 获取会话记录
|
|
308
|
+
const messages = client.getHistory("s1");
|
|
309
|
+
|
|
310
|
+
// 清空记录
|
|
311
|
+
client.clearHistory("s1");
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## 思维引擎(Experimental)
|
|
315
|
+
|
|
316
|
+
> ⚠️ 实验性功能,API 可能在后续版本中变更。
|
|
317
|
+
|
|
318
|
+
独立服务端内置 AI 驱动的个人知识管理系统。用户随时记录想法碎片,系统自动完成结构化、关联发现、洞察生成和作品组装。数据使用 SQLite 存储(`better-sqlite3`),每用户独立数据库文件。
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { XiaozhuClient } from "openclaw-channel-xiaozhu/sdk";
|
|
322
|
+
|
|
323
|
+
const client = new XiaozhuClient({
|
|
324
|
+
baseUrl: "http://localhost:9000",
|
|
325
|
+
apiKey: "xz_your-api-key",
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// "随便说"— 系统自动识别意图(捕获想法/搜索/创建项目/查看洞察)
|
|
329
|
+
const result = await client.think({ input: "推荐系统可以用协同过滤", session: "s1" });
|
|
330
|
+
console.log(result.message); // "已捕获想法,正在分析..."
|
|
331
|
+
|
|
332
|
+
// 直接捕获想法
|
|
333
|
+
await client.captureThought("用户画像需要考虑冷启动问题");
|
|
334
|
+
|
|
335
|
+
// 列出想法(支持标签/概念/状态/搜索/分页/时间范围过滤)
|
|
336
|
+
const { thoughts, total } = await client.listThoughts({ tag: "推荐系统", limit: 20 });
|
|
337
|
+
|
|
338
|
+
// 查看想法关联
|
|
339
|
+
const related = await client.getRelatedThoughts("thought-id");
|
|
340
|
+
|
|
341
|
+
// 手动关联两个想法
|
|
342
|
+
await client.connectThoughts("id-a", "id-b", { type: "continuation", reason: "后者是前者的延续" });
|
|
343
|
+
|
|
344
|
+
// 创建项目(从想法碎片组装成作品)
|
|
345
|
+
const { project } = await client.createProject("推荐系统方案", "plan", ["thought-1", "thought-2"]);
|
|
346
|
+
|
|
347
|
+
// 触发 AI 组装(生成大纲 + 草稿)
|
|
348
|
+
await client.generateProject(project.id);
|
|
349
|
+
|
|
350
|
+
// 获取洞察(系统自动发现的模式和机会)
|
|
351
|
+
const { insights } = await client.getInsights();
|
|
352
|
+
|
|
353
|
+
// 时间线(想法 + 连接的时间视图)
|
|
354
|
+
const timeline = await client.getTimeline({ limit: 50 });
|
|
355
|
+
|
|
356
|
+
// 用户画像(统计 + 热门标签)
|
|
357
|
+
const { profile } = await client.getProfile();
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**思维引擎 API:**
|
|
361
|
+
|
|
362
|
+
| Method | Path | Auth | Description |
|
|
363
|
+
|--------|------|------|-------------|
|
|
364
|
+
| `POST` | `/api/think` | API Key | "随便说"核心入口 |
|
|
365
|
+
| `POST` | `/api/thoughts` | API Key | 捕获想法 |
|
|
366
|
+
| `GET` | `/api/thoughts` | API Key | 列出想法 |
|
|
367
|
+
| `GET` | `/api/thoughts/:id` | API Key | 想法详情 |
|
|
368
|
+
| `DELETE` | `/api/thoughts/:id` | API Key | 删除想法 |
|
|
369
|
+
| `GET` | `/api/thoughts/:id/related` | API Key | 关联想法 |
|
|
370
|
+
| `POST` | `/api/thoughts/:id/connect` | API Key | 手动关联 |
|
|
371
|
+
| `POST` | `/api/projects` | API Key | 创建项目 |
|
|
372
|
+
| `GET` | `/api/projects` | API Key | 列出项目 |
|
|
373
|
+
| `GET` | `/api/projects/:id` | API Key | 项目详情 |
|
|
374
|
+
| `PUT` | `/api/projects/:id` | API Key | 更新项目 |
|
|
375
|
+
| `DELETE` | `/api/projects/:id` | API Key | 删除项目 |
|
|
376
|
+
| `POST` | `/api/projects/:id/generate` | API Key | AI 组装 |
|
|
377
|
+
| `GET` | `/api/insights` | API Key | 获取洞察 |
|
|
378
|
+
| `POST` | `/api/insights/:id/dismiss` | API Key | 标记已读 |
|
|
379
|
+
| `GET` | `/api/timeline` | API Key | 时间线 |
|
|
380
|
+
| `GET` | `/api/profile` | API Key | 用户画像 |
|
|
381
|
+
|
|
382
|
+
完整 API 文档见 [docs/API.md](docs/API.md)。
|
|
383
|
+
|
|
384
|
+
## Web Demo
|
|
385
|
+
|
|
386
|
+
`demo/` 目录包含两个纯 HTML/CSS/JS 界面,无需构建,浏览器直接打开。
|
|
387
|
+
|
|
388
|
+
**聊天界面** (`demo/index.html`):
|
|
389
|
+
- 聊天气泡 UI + 流式打字效果
|
|
390
|
+
- typing 状态指示
|
|
391
|
+
- 图片上传预览
|
|
392
|
+
- 会话管理(新建会话)
|
|
393
|
+
- 聊天记录导出/导入(JSON 文件,纯客户端)
|
|
394
|
+
|
|
395
|
+
**思维引擎界面** (`demo/think.html`):
|
|
396
|
+
- 三栏布局:时间线 / 对话 / 上下文(关联 + 洞察 + 画像)
|
|
397
|
+
- 想法搜索(关键词模糊匹配)
|
|
398
|
+
- 项目管理(创建 / 查看 / AI 生成草稿 / 删除)
|
|
399
|
+
- 洞察面板(查看 / 忽略)
|
|
400
|
+
- 用户画像统计
|
|
401
|
+
- 移动端适配(底部 Tab 切换)
|
|
402
|
+
|
|
403
|
+
## 聊天命令
|
|
404
|
+
|
|
405
|
+
| 命令 | 说明 |
|
|
406
|
+
|------|------|
|
|
407
|
+
| `/new` | 重置当前会话 |
|
|
408
|
+
| `/help` | 显示可用命令 |
|
|
409
|
+
| `/sessions` | 列出活跃会话 |
|
|
410
|
+
|
|
411
|
+
## 环境变量(可选)
|
|
95
412
|
|
|
96
413
|
| 变量 | 说明 |
|
|
97
414
|
|------|------|
|
|
98
|
-
| `WHISPER_BIN` | Whisper
|
|
99
|
-
| `EDGE_TTS_BIN` | edge-tts
|
|
415
|
+
| `WHISPER_BIN` | Whisper 可执行文件路径 |
|
|
416
|
+
| `EDGE_TTS_BIN` | edge-tts 可执行文件路径 |
|
|
100
417
|
|
|
101
|
-
|
|
418
|
+
## 架构
|
|
102
419
|
|
|
103
|
-
|
|
420
|
+
本插件实现 OpenClaw 渠道接口的四个适配器:
|
|
421
|
+
|
|
422
|
+
1. **Config** — 读取并校验渠道配置,支持单账号和多账号模式
|
|
423
|
+
2. **Gateway** — 启动 HTTP 服务,处理入站消息,转发至 OpenClaw 对话引擎
|
|
424
|
+
3. **Outbound** — 将引擎回复通过 Webhook 推送到外部系统(带重试和签名)
|
|
425
|
+
4. **Status** — 暴露 `/api/health`,报告运行时间、请求统计、会话数、连接数
|
|
426
|
+
|
|
427
|
+
消息流:`客户端 → Gateway → OpenClaw Engine → Outbound → Webhook`
|
|
428
|
+
|
|
429
|
+
## 开发
|
|
104
430
|
|
|
105
431
|
```bash
|
|
106
432
|
git clone https://github.com/openclaw/openclaw-channel-xiaozhu.git
|
|
@@ -109,35 +435,65 @@ npm install
|
|
|
109
435
|
npm run build
|
|
110
436
|
```
|
|
111
437
|
|
|
112
|
-
###
|
|
438
|
+
### 项目结构
|
|
113
439
|
|
|
114
440
|
```
|
|
115
441
|
openclaw-channel-xiaozhu/
|
|
116
442
|
├── src/
|
|
117
|
-
│ ├── index.ts
|
|
118
|
-
│ ├── channel.ts
|
|
119
|
-
│ ├── server.ts
|
|
120
|
-
│ ├── types.ts
|
|
443
|
+
│ ├── index.ts # 插件入口
|
|
444
|
+
│ ├── channel.ts # Channel 插件对象(四个适配器)
|
|
445
|
+
│ ├── server.ts # HTTP 服务器(全功能)
|
|
446
|
+
│ ├── types.ts # 类型定义
|
|
447
|
+
│ ├── standalone/
|
|
448
|
+
│ │ ├── cli.ts # 独立服务端 CLI 入口
|
|
449
|
+
│ │ ├── app.ts # HTTP + WebSocket 服务器
|
|
450
|
+
│ │ ├── router.ts # 智能路由引擎
|
|
451
|
+
│ │ ├── auth.ts # API Key 鉴权(timing-safe)
|
|
452
|
+
│ │ ├── store.ts # JSON 文件持久化
|
|
453
|
+
│ │ ├── types.ts # 独立服务端类型
|
|
454
|
+
│ │ ├── thought-types.ts # 思维引擎类型定义
|
|
455
|
+
│ │ ├── thought-store.ts # 思维引擎 JSON 存储
|
|
456
|
+
│ │ ├── thought-db.ts # 思维引擎 SQLite 存储
|
|
457
|
+
│ │ ├── thought-processor.ts # 后台 AI 处理管线
|
|
458
|
+
│ │ └── migrate-to-sqlite.ts # JSON → SQLite 迁移
|
|
459
|
+
│ ├── sdk/
|
|
460
|
+
│ │ ├── index.ts # XiaozhuClient 类
|
|
461
|
+
│ │ ├── types.ts # SDK 公开类型
|
|
462
|
+
│ │ └── sse.ts # SSE 解析器
|
|
463
|
+
│ ├── relay/
|
|
464
|
+
│ │ ├── client.ts # 云端中继客户端(连接中继服务器)
|
|
465
|
+
│ │ ├── server.ts # 中继服务器(部署在公网 VPS)
|
|
466
|
+
│ │ ├── protocol.ts # 中继协议类型定义
|
|
467
|
+
│ │ └── cli.ts # 中继服务器 CLI 入口
|
|
468
|
+
│ ├── shared/
|
|
469
|
+
│ │ ├── security.ts # timing-safe 比较 + SSRF 防护
|
|
470
|
+
│ │ ├── http-utils.ts # 请求体读取(统一实现)
|
|
471
|
+
│ │ └── inbound.ts # 入站 ctx 构建 + 媒体文本拼接
|
|
121
472
|
│ └── utils/
|
|
122
|
-
│ ├── rate-limiter.ts
|
|
123
|
-
│ ├── ttl-set.ts
|
|
124
|
-
│
|
|
125
|
-
├──
|
|
473
|
+
│ ├── rate-limiter.ts # 滑动窗口速率限制器
|
|
474
|
+
│ ├── ttl-set.ts # TTL 集合(消息去重)
|
|
475
|
+
│ ├── coalescer.ts # SSE 文本合并缓冲
|
|
476
|
+
│ ├── session-store.ts # 会话追踪
|
|
477
|
+
│ ├── text-chunker.ts # 围栏感知文本分块
|
|
478
|
+
│ └── webhook-sender.ts # Webhook 重试 + HMAC 签名
|
|
479
|
+
├── demo/
|
|
480
|
+
│ ├── index.html # Web Demo 聊天界面
|
|
481
|
+
│ ├── style.css # 聊天界面样式
|
|
482
|
+
│ ├── app.js # 聊天界面逻辑
|
|
483
|
+
│ ├── think.html # 思维引擎 Demo
|
|
484
|
+
│ ├── think.css # 思维引擎样式
|
|
485
|
+
│ └── think.js # 思维引擎逻辑
|
|
486
|
+
├── skills/
|
|
487
|
+
│ ├── xiaozhu-send-media/ # 媒体发送 skill
|
|
488
|
+
│ ├── xiaozhu-cron-job/ # 定时提醒 skill
|
|
489
|
+
│ └── openclaw-browser-quality/ # 浏览器质量 skill
|
|
490
|
+
├── docs/
|
|
491
|
+
│ └── API.md # 完整 API 文档
|
|
492
|
+
├── openclaw.plugin.json # 插件声明
|
|
126
493
|
├── tsconfig.json
|
|
127
494
|
└── package.json
|
|
128
495
|
```
|
|
129
496
|
|
|
130
|
-
## Architecture
|
|
131
|
-
|
|
132
|
-
本插件实现 OpenClaw 渠道接口的四个适配器:
|
|
133
|
-
|
|
134
|
-
1. **Config** — 读取并校验渠道配置,合并默认值
|
|
135
|
-
2. **Gateway** — 启动 HTTP 服务,处理入站消息,转发至 OpenClaw 对话引擎
|
|
136
|
-
3. **Outbound** — 将引擎回复通过 Webhook 推送到外部系统
|
|
137
|
-
4. **Status** — 暴露 `/api/health`,报告运行时间、请求统计、限流状态
|
|
138
|
-
|
|
139
|
-
消息流:`客户端 → Gateway → OpenClaw Engine → Outbound → Webhook`
|
|
140
|
-
|
|
141
497
|
## License
|
|
142
498
|
|
|
143
499
|
[MIT](LICENSE)
|