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.
Files changed (171) hide show
  1. package/README.md +421 -65
  2. package/demo/app.js +350 -0
  3. package/demo/index.html +36 -0
  4. package/demo/style.css +249 -0
  5. package/demo/think.css +590 -0
  6. package/demo/think.html +92 -0
  7. package/demo/think.js +532 -0
  8. package/dist/channel.d.ts +22 -1
  9. package/dist/channel.d.ts.map +1 -0
  10. package/dist/channel.js +144 -74
  11. package/dist/channel.js.map +1 -0
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/relay/cli.d.ts +10 -0
  17. package/dist/relay/cli.d.ts.map +1 -0
  18. package/dist/relay/cli.js +28 -0
  19. package/dist/relay/cli.js.map +1 -0
  20. package/dist/relay/client.d.ts +23 -0
  21. package/dist/relay/client.d.ts.map +1 -0
  22. package/dist/relay/client.js +242 -0
  23. package/dist/relay/client.js.map +1 -0
  24. package/dist/relay/protocol.d.ts +31 -0
  25. package/dist/relay/protocol.d.ts.map +1 -0
  26. package/dist/relay/protocol.js +5 -0
  27. package/dist/relay/protocol.js.map +1 -0
  28. package/dist/relay/server.d.ts +16 -0
  29. package/dist/relay/server.d.ts.map +1 -0
  30. package/dist/relay/server.js +322 -0
  31. package/dist/relay/server.js.map +1 -0
  32. package/dist/sdk/index.d.ts +259 -0
  33. package/dist/sdk/index.d.ts.map +1 -0
  34. package/dist/sdk/index.js +415 -0
  35. package/dist/sdk/index.js.map +1 -0
  36. package/dist/sdk/sse.d.ts +18 -0
  37. package/dist/sdk/sse.d.ts.map +1 -0
  38. package/dist/sdk/sse.js +67 -0
  39. package/dist/sdk/sse.js.map +1 -0
  40. package/dist/sdk/types.d.ts +231 -0
  41. package/dist/sdk/types.d.ts.map +1 -0
  42. package/dist/sdk/types.js +5 -0
  43. package/dist/sdk/types.js.map +1 -0
  44. package/dist/server.d.ts +5 -3
  45. package/dist/server.d.ts.map +1 -0
  46. package/dist/server.js +616 -263
  47. package/dist/server.js.map +1 -0
  48. package/dist/shared/errors.d.ts +47 -0
  49. package/dist/shared/errors.d.ts.map +1 -0
  50. package/dist/shared/errors.js +52 -0
  51. package/dist/shared/errors.js.map +1 -0
  52. package/dist/shared/http-utils.d.ts +20 -0
  53. package/dist/shared/http-utils.d.ts.map +1 -0
  54. package/dist/shared/http-utils.js +109 -0
  55. package/dist/shared/http-utils.js.map +1 -0
  56. package/dist/shared/inbound.d.ts +45 -0
  57. package/dist/shared/inbound.d.ts.map +1 -0
  58. package/dist/shared/inbound.js +76 -0
  59. package/dist/shared/inbound.js.map +1 -0
  60. package/dist/shared/security.d.ts +19 -0
  61. package/dist/shared/security.d.ts.map +1 -0
  62. package/dist/shared/security.js +63 -0
  63. package/dist/shared/security.js.map +1 -0
  64. package/dist/standalone/app.d.ts +16 -0
  65. package/dist/standalone/app.d.ts.map +1 -0
  66. package/dist/standalone/app.js +194 -0
  67. package/dist/standalone/app.js.map +1 -0
  68. package/dist/standalone/auth.d.ts +19 -0
  69. package/dist/standalone/auth.d.ts.map +1 -0
  70. package/dist/standalone/auth.js +45 -0
  71. package/dist/standalone/auth.js.map +1 -0
  72. package/dist/standalone/cli.d.ts +10 -0
  73. package/dist/standalone/cli.d.ts.map +1 -0
  74. package/dist/standalone/cli.js +107 -0
  75. package/dist/standalone/cli.js.map +1 -0
  76. package/dist/standalone/media-store.d.ts +30 -0
  77. package/dist/standalone/media-store.d.ts.map +1 -0
  78. package/dist/standalone/media-store.js +150 -0
  79. package/dist/standalone/media-store.js.map +1 -0
  80. package/dist/standalone/migrate-to-sqlite.d.ts +10 -0
  81. package/dist/standalone/migrate-to-sqlite.d.ts.map +1 -0
  82. package/dist/standalone/migrate-to-sqlite.js +194 -0
  83. package/dist/standalone/migrate-to-sqlite.js.map +1 -0
  84. package/dist/standalone/router.d.ts +34 -0
  85. package/dist/standalone/router.d.ts.map +1 -0
  86. package/dist/standalone/router.js +94 -0
  87. package/dist/standalone/router.js.map +1 -0
  88. package/dist/standalone/routes.d.ts +12 -0
  89. package/dist/standalone/routes.d.ts.map +1 -0
  90. package/dist/standalone/routes.js +508 -0
  91. package/dist/standalone/routes.js.map +1 -0
  92. package/dist/standalone/server-context.d.ts +73 -0
  93. package/dist/standalone/server-context.d.ts.map +1 -0
  94. package/dist/standalone/server-context.js +38 -0
  95. package/dist/standalone/server-context.js.map +1 -0
  96. package/dist/standalone/store.d.ts +36 -0
  97. package/dist/standalone/store.d.ts.map +1 -0
  98. package/dist/standalone/store.js +163 -0
  99. package/dist/standalone/store.js.map +1 -0
  100. package/dist/standalone/thought-db.d.ts +92 -0
  101. package/dist/standalone/thought-db.d.ts.map +1 -0
  102. package/dist/standalone/thought-db.js +677 -0
  103. package/dist/standalone/thought-db.js.map +1 -0
  104. package/dist/standalone/thought-processor.d.ts +36 -0
  105. package/dist/standalone/thought-processor.d.ts.map +1 -0
  106. package/dist/standalone/thought-processor.js +352 -0
  107. package/dist/standalone/thought-processor.js.map +1 -0
  108. package/dist/standalone/thought-routes.d.ts +13 -0
  109. package/dist/standalone/thought-routes.d.ts.map +1 -0
  110. package/dist/standalone/thought-routes.js +326 -0
  111. package/dist/standalone/thought-routes.js.map +1 -0
  112. package/dist/standalone/thought-store-factory.d.ts +12 -0
  113. package/dist/standalone/thought-store-factory.d.ts.map +1 -0
  114. package/dist/standalone/thought-store-factory.js +20 -0
  115. package/dist/standalone/thought-store-factory.js.map +1 -0
  116. package/dist/standalone/thought-store.d.ts +103 -0
  117. package/dist/standalone/thought-store.d.ts.map +1 -0
  118. package/dist/standalone/thought-store.js +502 -0
  119. package/dist/standalone/thought-store.js.map +1 -0
  120. package/dist/standalone/thought-types.d.ts +169 -0
  121. package/dist/standalone/thought-types.d.ts.map +1 -0
  122. package/dist/standalone/thought-types.js +5 -0
  123. package/dist/standalone/thought-types.js.map +1 -0
  124. package/dist/standalone/types.d.ts +105 -0
  125. package/dist/standalone/types.d.ts.map +1 -0
  126. package/dist/standalone/types.js +5 -0
  127. package/dist/standalone/types.js.map +1 -0
  128. package/dist/standalone/ws-handler.d.ts +16 -0
  129. package/dist/standalone/ws-handler.d.ts.map +1 -0
  130. package/dist/standalone/ws-handler.js +183 -0
  131. package/dist/standalone/ws-handler.js.map +1 -0
  132. package/dist/types.d.ts +62 -0
  133. package/dist/types.d.ts.map +1 -0
  134. package/dist/types.js +1 -0
  135. package/dist/types.js.map +1 -0
  136. package/dist/utils/coalescer.d.ts +6 -0
  137. package/dist/utils/coalescer.d.ts.map +1 -0
  138. package/dist/utils/coalescer.js +26 -2
  139. package/dist/utils/coalescer.js.map +1 -0
  140. package/dist/utils/rate-limiter.d.ts +13 -2
  141. package/dist/utils/rate-limiter.d.ts.map +1 -0
  142. package/dist/utils/rate-limiter.js +50 -10
  143. package/dist/utils/rate-limiter.js.map +1 -0
  144. package/dist/utils/session-store.d.ts +32 -0
  145. package/dist/utils/session-store.d.ts.map +1 -0
  146. package/dist/utils/session-store.js +83 -0
  147. package/dist/utils/session-store.js.map +1 -0
  148. package/dist/utils/text-chunker.d.ts +14 -0
  149. package/dist/utils/text-chunker.d.ts.map +1 -0
  150. package/dist/utils/text-chunker.js +70 -0
  151. package/dist/utils/text-chunker.js.map +1 -0
  152. package/dist/utils/ttl-set.d.ts +1 -0
  153. package/dist/utils/ttl-set.d.ts.map +1 -0
  154. package/dist/utils/ttl-set.js +2 -1
  155. package/dist/utils/ttl-set.js.map +1 -0
  156. package/dist/utils/webhook-sender.d.ts +27 -0
  157. package/dist/utils/webhook-sender.d.ts.map +1 -0
  158. package/dist/utils/webhook-sender.js +59 -0
  159. package/dist/utils/webhook-sender.js.map +1 -0
  160. package/docs/API.md +1514 -141
  161. package/docs/DEVELOPMENT.md +299 -0
  162. package/docs/MILESTONES.md +135 -0
  163. package/docs/RISKS.md +179 -0
  164. package/docs/ROADMAP.md +144 -0
  165. package/openclaw.plugin.json +3 -0
  166. package/package.json +39 -3
  167. package/skills/openclaw-browser-quality/SKILL.md +32 -0
  168. package/skills/openclaw-browser-quality/references/browser-usage.md +134 -0
  169. package/skills/openclaw-browser-quality/references/quality-guidelines.md +19 -0
  170. package/skills/xiaozhu-cron-job/SKILL.md +169 -0
  171. 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 对话引擎。与钉钉(`openclaw-channel-dingtalk`)、飞书(`openclaw-channel-feishu`)并列,是面向自定义客户端的通用接入渠道。
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 外发消息 (`POST /api/webhook/register`)
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
- ## Quick Start
39
+ ## 安装部署
21
40
 
22
- ### Prerequisites
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
- ### Install
47
+ ### 第一步:安装插件
28
48
 
29
49
  ```bash
30
- npm install openclaw-channel-xiaozhu
50
+ npm install -g openclaw-channel-xiaozhu
31
51
  ```
32
52
 
33
- ### Build
53
+ > 如果你的 npm 默认源是淘宝镜像,新包同步可能有延迟,可指定官方源:
54
+ > ```bash
55
+ > npm install -g openclaw-channel-xiaozhu --registry=https://registry.npmjs.org/
56
+ > ```
34
57
 
35
- ```bash
36
- npm run build
37
- ```
58
+ ### 第二步:配置渠道
38
59
 
39
- ### Deploy
60
+ 编辑 `~/.openclaw/openclaw.json`,在 `channels` 中添加小助渠道配置:
40
61
 
41
- 将构建产物部署到 OpenClaw 插件目录,或在 `openclaw.json` 中注册本渠道即可。
62
+ **单账号模式(推荐):**
42
63
 
43
- ## Configuration
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
- 在 `openclaw.json` 的 `channels` 中添加:
78
+ **多账号模式:**
46
79
 
47
80
  ```json
48
81
  {
49
- "channels": [
50
- {
51
- "type": "channel-xiaozhu",
52
- "config": {
53
- "port": 3000,
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 | `3000` | HTTP 监听端口 |
150
+ | `port` | number | `18800` | HTTP 监听端口 |
71
151
  | `token` | string | — | 鉴权 Token(必填) |
72
152
  | `rateLimitWindowMs` | number | `60000` | 限流滑动窗口(毫秒) |
73
- | `rateLimitMax` | number | `60` | 窗口内最大请求数 |
74
- | `rateLimitBurst` | number | `10` | 突发请求上限 |
75
- | `dedupTtlMs` | number | `5000` | 消息去重 TTL(毫秒) |
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 Overview
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
- | `GET` | `/api/media/:id` | Yes | 获取媒体文件 |
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
- ## Environment Variables
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 可执行文件路径,留空则从 PATH 查找 |
99
- | `EDGE_TTS_BIN` | edge-tts 可执行文件路径,留空则从 PATH 查找 |
415
+ | `WHISPER_BIN` | Whisper 可执行文件路径 |
416
+ | `EDGE_TTS_BIN` | edge-tts 可执行文件路径 |
100
417
 
101
- 可复制 `.env.example` 为 `.env` 进行配置。
418
+ ## 架构
102
419
 
103
- ## Development
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
- ### Project Structure
438
+ ### 项目结构
113
439
 
114
440
  ```
115
441
  openclaw-channel-xiaozhu/
116
442
  ├── src/
117
- │ ├── index.ts # 插件入口
118
- │ ├── channel.ts # Channel 插件对象(四个适配器)
119
- │ ├── server.ts # HTTP 服务器(全功能)
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 # TTL 集合(消息去重)
124
- └── coalescer.ts # SSE 文本合并缓冲
125
- ├── openclaw.plugin.json # 插件声明
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)