openclaw-plugin-fast-task 1.0.0 → 1.0.1
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 +826 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# OpenClaw Plugin - Fast Task
|
|
2
2
|
|
|
3
|
-
OpenClaw 插件,支持通过 WebSocket
|
|
3
|
+
OpenClaw 插件,支持通过 WebSocket 进行节点注册、点对点聊天以及 workspace 文件操作。
|
|
4
4
|
|
|
5
5
|
## 功能特性
|
|
6
6
|
|
|
7
|
-
- ✅ **WebSocket 通信** - 与 WebSocket
|
|
8
|
-
- ✅ **
|
|
9
|
-
- ✅
|
|
10
|
-
- ✅
|
|
7
|
+
- ✅ **WebSocket 通信** - 与 WebSocket 服务器建立持久连接
|
|
8
|
+
- ✅ **节点注册 (whoIAm)** - 自动向服务器注册节点身份和配置
|
|
9
|
+
- ✅ **点对点聊天** - 支持与 Agent 进行实时对话
|
|
10
|
+
- ✅ **Workspace 文件操作** - 读写 OpenClaw workspace 文件
|
|
11
|
+
- ✅ **Agent 管理** - 列出、查询 Agent 信息和绑定关系
|
|
12
|
+
- ✅ **自动重连** - 连接断开时自动重连
|
|
11
13
|
|
|
12
14
|
## 安装
|
|
13
15
|
|
|
@@ -17,11 +19,14 @@ openclaw plugins install openclaw-plugin-fast-task
|
|
|
17
19
|
|
|
18
20
|
# 或从 npm 安装
|
|
19
21
|
npm install openclaw-plugin-fast-task
|
|
20
|
-
```
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
# 本地开发
|
|
24
|
+
npm run build
|
|
25
|
+
npm pack
|
|
26
|
+
openclaw plugins install ./openclaw-plugin-fast-task-1.0.0.tgz
|
|
27
|
+
```
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
## 配置
|
|
25
30
|
|
|
26
31
|
在 OpenClaw 配置文件中添加:
|
|
27
32
|
|
|
@@ -46,10 +51,365 @@ npm install openclaw-plugin-fast-task
|
|
|
46
51
|
}
|
|
47
52
|
```
|
|
48
53
|
|
|
49
|
-
|
|
54
|
+
**配置说明:**
|
|
55
|
+
- `wsHost`: WebSocket 服务器地址
|
|
56
|
+
- `enabled`: 是否启用该通道
|
|
57
|
+
- `dmPolicy`: 私聊策略(`open`/`allowlist`/`pairing`)
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 核心功能
|
|
62
|
+
|
|
63
|
+
### 动态 Client ID 设计
|
|
64
|
+
|
|
65
|
+
本插件采用**动态 Client ID** 架构,所有消息路由由 WebSocket 服务器统一管理。
|
|
66
|
+
|
|
67
|
+
**设计优势:**
|
|
68
|
+
- ✅ **解耦客户端和服务端**:客户端不需要预设自己的 ID 或目标 ID
|
|
69
|
+
- ✅ **灵活的路由**:服务器可以根据业务逻辑动态管理消息路由
|
|
70
|
+
- ✅ **易于扩展**:支持多租户、负载均衡、消息广播等高级功能
|
|
71
|
+
- ✅ **自动分配**:新连接自动获得唯一 ID,无需手动配置
|
|
72
|
+
|
|
73
|
+
**工作原理:**
|
|
74
|
+
|
|
75
|
+
1. **连接建立**:客户端连接到 WebSocket 服务器
|
|
76
|
+
2. **ID 分配**:服务器为每个连接分配唯一的 `client_id`(如 `ws_client_001`)
|
|
77
|
+
3. **消息转发**:
|
|
78
|
+
- 客户端发送消息时不包含 `from` 字段
|
|
79
|
+
- 服务器在转发时自动添加 `from: <client_id>`
|
|
80
|
+
4. **回复路由**:
|
|
81
|
+
- 插件回复时使用 `to: <message.from>`
|
|
82
|
+
- 服务器根据 `to` 字段将消息路由到对应的客户端
|
|
83
|
+
|
|
84
|
+
**客户端视角:**
|
|
85
|
+
```javascript
|
|
86
|
+
// 客户端只发送核心数据,不需要关心 from/to
|
|
87
|
+
ws.send(JSON.stringify({
|
|
88
|
+
type: 'direct',
|
|
89
|
+
data: {
|
|
90
|
+
chatType: 'toAgent',
|
|
91
|
+
content: '你好'
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
|
|
95
|
+
// 服务器会自动添加 from 字段转发给 Agent
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**服务器职责:**
|
|
99
|
+
```javascript
|
|
100
|
+
// 服务器维护 client_id 映射
|
|
101
|
+
const clients = new Map(); // ws -> client_id
|
|
102
|
+
ws.on('connection', (socket) => {
|
|
103
|
+
const clientId = `ws_client_${Date.now()}_${Math.random()}`;
|
|
104
|
+
clients.set(socket, clientId);
|
|
105
|
+
|
|
106
|
+
// 转发消息时添加 from
|
|
107
|
+
socket.on('message', (data) => {
|
|
108
|
+
const msg = JSON.parse(data);
|
|
109
|
+
msg.from = clientId; // 添加 from 字段
|
|
110
|
+
forwardToAgent(msg);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
### 1. 节点注册 (whoIAm)
|
|
118
|
+
|
|
119
|
+
当 WebSocket 连接建立后,服务器发送 `welcome` 消息,插件自动响应 `whoIAm` 消息进行节点注册。
|
|
120
|
+
|
|
121
|
+
#### 服务器发送 welcome 消息
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"type": "welcome",
|
|
125
|
+
"timestamp": "2026-03-27T12:00:00Z"
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### 插件响应 whoIAm 注册
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"type": "whoIAm",
|
|
133
|
+
"data": {
|
|
134
|
+
"chatType": "register",
|
|
135
|
+
"cli": "agent",
|
|
136
|
+
"config": {
|
|
137
|
+
"agents": {
|
|
138
|
+
"list": [
|
|
139
|
+
{
|
|
140
|
+
"id": "main",
|
|
141
|
+
"name": "主智能体",
|
|
142
|
+
"model": "claude-sonnet-4-6"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
"bindings": [...],
|
|
147
|
+
"channels": {...}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**whoIAm 注册信息包含:**
|
|
154
|
+
- `chatType`: 固定为 "register"
|
|
155
|
+
- `cli`: 客户端类型(agent)
|
|
156
|
+
- `config`: 完整的 OpenClaw 配置(包含所有 Agent、绑定、通道配置)
|
|
157
|
+
|
|
158
|
+
**注册后服务器可以:**
|
|
159
|
+
- 识别节点身份和可用的 Agent
|
|
160
|
+
- 查询 Agent 列表和详细信息
|
|
161
|
+
- 了解 Agent 的绑定关系
|
|
162
|
+
- 执行 workspace 文件操作
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### 2. 点对点聊天
|
|
167
|
+
|
|
168
|
+
#### 动态 Client ID 机制
|
|
169
|
+
|
|
170
|
+
WebSocket 服务器为每个连接的客户端动态分配 `client_id`,消息的 `from` 和 `to` 字段使用这些动态 ID 进行路由。
|
|
171
|
+
|
|
172
|
+
**工作流程:**
|
|
173
|
+
```
|
|
174
|
+
客户端 A 连接 ──────> 服务器分配: client_id = "ws_client_001"
|
|
175
|
+
客户端 B 连接 ──────> 服务器分配: client_id = "ws_client_002"
|
|
176
|
+
|
|
177
|
+
服务器转发消息时动态设置 from/to:
|
|
178
|
+
- 消息来自客户端 A ──> from: "ws_client_001"
|
|
179
|
+
- 回复给客户端 A ────> to: "ws_client_001"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### 发送消息给 Agent
|
|
183
|
+
|
|
184
|
+
**WebSocket 服务器向插件转发消息:**
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"type": "direct",
|
|
189
|
+
"from": "ws_client_001",
|
|
190
|
+
"timestamp": "2026-03-27T12:00:00Z",
|
|
191
|
+
"data": {
|
|
192
|
+
"chatType": "toAgent",
|
|
193
|
+
"content": "你好,请介绍一下自己",
|
|
194
|
+
"files": {
|
|
195
|
+
"url": "https://example.com/image.png",
|
|
196
|
+
"fileName": "image.png"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**字段说明:**
|
|
203
|
+
- `type`: 消息类型,固定为 "direct"
|
|
204
|
+
- `from`: 发送者的动态 client_id(由 WebSocket 服务器分配)
|
|
205
|
+
- `data.chatType`: 固定为 "toAgent"
|
|
206
|
+
- `data.content`: 消息文本内容
|
|
207
|
+
- `data.files`: 可选的媒体文件(图片、文档等)
|
|
208
|
+
|
|
209
|
+
**注意:** `from` 字段是 WebSocket 服务器在转发消息时动态添加的,表示消息来源的 client_id。
|
|
210
|
+
|
|
211
|
+
#### Agent 回复消息
|
|
212
|
+
|
|
213
|
+
Agent 处理完消息后,回复给原始发送者:
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"type": "direct",
|
|
218
|
+
"to": "ws_client_001",
|
|
219
|
+
"timestamp": "2026-03-27T12:00:01Z",
|
|
220
|
+
"data": {
|
|
221
|
+
"chatType": "agent_chat",
|
|
222
|
+
"payload": {
|
|
223
|
+
"text": "你好!我是 OpenClaw 智能体,可以帮助你..."
|
|
224
|
+
},
|
|
225
|
+
"info": "回复成功",
|
|
226
|
+
"content": ""
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**回复逻辑:**
|
|
232
|
+
- 插件收到消息时,`message.from` 是发送者的 client_id
|
|
233
|
+
- Agent 处理完后,设置 `to: message.from` 回复给原发送者
|
|
234
|
+
- 不需要手动指定接收者,由 WebSocket 服务器根据 `to` 字段的路由转发
|
|
235
|
+
|
|
236
|
+
**回复类型:**
|
|
237
|
+
1. **agent_chat**: 正常回复
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"chatType": "agent_chat",
|
|
241
|
+
"payload": { "text": "回复内容" }
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
2. **agent_error**: 错误信息
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"chatType": "agent_error",
|
|
249
|
+
"error": "错误描述",
|
|
250
|
+
"info": "额外信息"
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
3. **agent_idle**: Agent 空闲状态
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"chatType": "agent_idle",
|
|
258
|
+
"content": "agent is idle"
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### 3. 网关命令 (Gateway Commands)
|
|
265
|
+
|
|
266
|
+
通过 `chatType: "toCmd"` 执行各种系统命令。
|
|
267
|
+
|
|
268
|
+
#### 3.1 列出所有 Agent
|
|
269
|
+
|
|
270
|
+
**客户端发送请求(不需要 from 字段):**
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"type": "direct",
|
|
274
|
+
"data": {
|
|
275
|
+
"chatType": "toCmd",
|
|
276
|
+
"gateWay": {
|
|
277
|
+
"cmd": "agents.list"
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**服务器添加 from 字段后转发给插件:**
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"type": "direct",
|
|
287
|
+
"from": "ws_client_001", // 服务器添加
|
|
288
|
+
"data": {
|
|
289
|
+
"chatType": "toCmd",
|
|
290
|
+
"gateWay": {
|
|
291
|
+
"cmd": "agents.list"
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**插件响应(使用 to 字段路由回原客户端):**
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"type": "direct",
|
|
301
|
+
"to": "ws_client_001",
|
|
302
|
+
"data": {
|
|
303
|
+
"chatType": "agents.list",
|
|
304
|
+
"agentIds": ["main", "helper", "coder"]
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
#### 3.2 查询 Agent 信息
|
|
310
|
+
|
|
311
|
+
**客户端请求:**
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"type": "direct",
|
|
315
|
+
"data": {
|
|
316
|
+
"chatType": "toCmd",
|
|
317
|
+
"gateWay": {
|
|
318
|
+
"cmd": "agent.info",
|
|
319
|
+
"id": "main"
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**服务器转发(添加 from):**
|
|
326
|
+
```json
|
|
327
|
+
{
|
|
328
|
+
"type": "direct",
|
|
329
|
+
"from": "ws_client_001",
|
|
330
|
+
"data": {
|
|
331
|
+
"chatType": "toCmd",
|
|
332
|
+
"gateWay": {
|
|
333
|
+
"cmd": "agent.info",
|
|
334
|
+
"id": "main"
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**插件响应:**
|
|
341
|
+
```json
|
|
342
|
+
{
|
|
343
|
+
"type": "direct",
|
|
344
|
+
"to": "ws_client_001",
|
|
345
|
+
"data": {
|
|
346
|
+
"chatType": "agent.info",
|
|
347
|
+
"info": {
|
|
348
|
+
"id": "main",
|
|
349
|
+
"name": "主智能体",
|
|
350
|
+
"model": "claude-sonnet-4-6",
|
|
351
|
+
"description": "负责主要对话"
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
#### 3.3 查询 Agent 绑定关系
|
|
358
|
+
|
|
359
|
+
**客户端请求:**
|
|
360
|
+
```json
|
|
361
|
+
{
|
|
362
|
+
"type": "direct",
|
|
363
|
+
"data": {
|
|
364
|
+
"chatType": "toCmd",
|
|
365
|
+
"gateWay": {
|
|
366
|
+
"cmd": "agents.bindings"
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
**服务器转发(添加 from):**
|
|
373
|
+
```json
|
|
374
|
+
{
|
|
375
|
+
"type": "direct",
|
|
376
|
+
"from": "ws_client_001",
|
|
377
|
+
"data": {
|
|
378
|
+
"chatType": "toCmd",
|
|
379
|
+
"gateWay": {
|
|
380
|
+
"cmd": "agents.bindings"
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**插件响应:**
|
|
387
|
+
```json
|
|
388
|
+
{
|
|
389
|
+
"type": "direct",
|
|
390
|
+
"to": "ws_client_001",
|
|
391
|
+
"data": {
|
|
392
|
+
"chatType": "agents.bindings",
|
|
393
|
+
"info": [
|
|
394
|
+
{
|
|
395
|
+
"agentId": "main",
|
|
396
|
+
"match": {
|
|
397
|
+
"channel": "fast_task",
|
|
398
|
+
"accountId": "default"
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
### 4. Workspace 文件操作
|
|
50
409
|
|
|
51
|
-
#### 读取 Workspace 文件
|
|
410
|
+
#### 4.1 读取 Workspace 文件
|
|
52
411
|
|
|
412
|
+
**客户端请求:**
|
|
53
413
|
```json
|
|
54
414
|
{
|
|
55
415
|
"type": "direct",
|
|
@@ -63,8 +423,41 @@ npm install openclaw-plugin-fast-task
|
|
|
63
423
|
}
|
|
64
424
|
```
|
|
65
425
|
|
|
66
|
-
|
|
426
|
+
**服务器转发(添加 from):**
|
|
427
|
+
```json
|
|
428
|
+
{
|
|
429
|
+
"type": "direct",
|
|
430
|
+
"from": "ws_client_001",
|
|
431
|
+
"data": {
|
|
432
|
+
"chatType": "toCmd",
|
|
433
|
+
"gateWay": {
|
|
434
|
+
"cmd": "workspace.read",
|
|
435
|
+
"file": "AGENTS.md"
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**插件响应:**
|
|
442
|
+
```json
|
|
443
|
+
{
|
|
444
|
+
"type": "direct",
|
|
445
|
+
"to": "ws_client_001",
|
|
446
|
+
"data": {
|
|
447
|
+
"chatType": "workspace.read",
|
|
448
|
+
"file": "AGENTS.md",
|
|
449
|
+
"success": true,
|
|
450
|
+
"exists": true,
|
|
451
|
+
"content": "# Agent 指南\n...",
|
|
452
|
+
"path": "/path/to/workspace/AGENTS.md",
|
|
453
|
+
"message": "Successfully read AGENTS.md"
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
#### 4.2 写入 Workspace 文件
|
|
67
459
|
|
|
460
|
+
**客户端请求:**
|
|
68
461
|
```json
|
|
69
462
|
{
|
|
70
463
|
"type": "direct",
|
|
@@ -73,23 +466,436 @@ npm install openclaw-plugin-fast-task
|
|
|
73
466
|
"gateWay": {
|
|
74
467
|
"cmd": "workspace.write",
|
|
75
468
|
"file": "AGENTS.md",
|
|
76
|
-
"content": "#
|
|
469
|
+
"content": "# 新的 Agent 配置\n..."
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
**服务器转发(添加 from):**
|
|
476
|
+
```json
|
|
477
|
+
{
|
|
478
|
+
"type": "direct",
|
|
479
|
+
"from": "ws_client_001",
|
|
480
|
+
"data": {
|
|
481
|
+
"chatType": "toCmd",
|
|
482
|
+
"gateWay": {
|
|
483
|
+
"cmd": "workspace.write",
|
|
484
|
+
"file": "AGENTS.md",
|
|
485
|
+
"content": "# 新的 Agent 配置\n..."
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**插件响应:**
|
|
492
|
+
```json
|
|
493
|
+
{
|
|
494
|
+
"type": "direct",
|
|
495
|
+
"to": "ws_client_001",
|
|
496
|
+
"data": {
|
|
497
|
+
"chatType": "workspace.write",
|
|
498
|
+
"file": "AGENTS.md",
|
|
499
|
+
"success": true,
|
|
500
|
+
"path": "/path/to/workspace/AGENTS.md",
|
|
501
|
+
"message": "Successfully wrote to AGENTS.md"
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
#### 4.3 列出所有 Workspace 文件
|
|
507
|
+
|
|
508
|
+
**客户端请求:**
|
|
509
|
+
```json
|
|
510
|
+
{
|
|
511
|
+
"type": "direct",
|
|
512
|
+
"data": {
|
|
513
|
+
"chatType": "toCmd",
|
|
514
|
+
"gateWay": {
|
|
515
|
+
"cmd": "workspace.list"
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
**服务器转发(添加 from):**
|
|
522
|
+
```json
|
|
523
|
+
{
|
|
524
|
+
"type": "direct",
|
|
525
|
+
"from": "ws_client_001",
|
|
526
|
+
"data": {
|
|
527
|
+
"chatType": "toCmd",
|
|
528
|
+
"gateWay": {
|
|
529
|
+
"cmd": "workspace.list"
|
|
77
530
|
}
|
|
78
531
|
}
|
|
79
532
|
}
|
|
80
533
|
```
|
|
81
534
|
|
|
535
|
+
**插件响应:**
|
|
536
|
+
```json
|
|
537
|
+
{
|
|
538
|
+
"type": "direct",
|
|
539
|
+
"to": "ws_client_001",
|
|
540
|
+
"data": {
|
|
541
|
+
"chatType": "workspace.list",
|
|
542
|
+
"success": true,
|
|
543
|
+
"files": [
|
|
544
|
+
{
|
|
545
|
+
"name": "AGENTS.md",
|
|
546
|
+
"exists": true,
|
|
547
|
+
"path": "/workspace/AGENTS.md"
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
"name": "SOUL.md",
|
|
551
|
+
"exists": true,
|
|
552
|
+
"path": "/workspace/SOUL.md"
|
|
553
|
+
}
|
|
554
|
+
],
|
|
555
|
+
"summary": {
|
|
556
|
+
"total": 8,
|
|
557
|
+
"existing": 5,
|
|
558
|
+
"missing": 3
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
82
566
|
## 支持的 Workspace 文件
|
|
83
567
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
568
|
+
| 文件名 | 说明 |
|
|
569
|
+
|--------|------|
|
|
570
|
+
| `AGENTS.md` | 智能体操作指南 |
|
|
571
|
+
| `SOUL.md` | 人设、语气和边界 |
|
|
572
|
+
| `TOOLS.md` | 工具说明 |
|
|
573
|
+
| `IDENTITY.md` | 智能体名称和风格 |
|
|
574
|
+
| `USER.md` | 用户信息 |
|
|
575
|
+
| `HEARTBEAT.md` | 心跳检查清单 |
|
|
576
|
+
| `BOOT.md` | 启动检查清单 |
|
|
577
|
+
| `MEMORY.md` | 长期记忆 |
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## 消息流程图
|
|
582
|
+
|
|
583
|
+
```
|
|
584
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
585
|
+
│ WebSocket 服务器 │
|
|
586
|
+
│ - 为每个连接动态分配 client_id │
|
|
587
|
+
│ - 转发消息时添加 from/to 字段 │
|
|
588
|
+
└────────┬────────────────────────────────────────────────────┘
|
|
589
|
+
│
|
|
590
|
+
│ 1. 客户端连接
|
|
591
|
+
│ 服务器分配: client_id = "ws_client_001"
|
|
592
|
+
▼
|
|
593
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
594
|
+
│ 发送 welcome 消息 │
|
|
595
|
+
│ { type: "welcome" } │
|
|
596
|
+
└────────┬────────────────────────────────────────────────────┘
|
|
597
|
+
│
|
|
598
|
+
│ 2. 插件响应 whoIAm 注册
|
|
599
|
+
▼
|
|
600
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
601
|
+
│ { type: "whoIAm", data: { chatType: "register", ... } } │
|
|
602
|
+
│ - 服务器保存节点配置 │
|
|
603
|
+
│ - 服务器记录 client_id 与节点的映射 │
|
|
604
|
+
└────────┬────────────────────────────────────────────────────┘
|
|
605
|
+
│
|
|
606
|
+
│ 3. 其他客户端发送消息
|
|
607
|
+
▼
|
|
608
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
609
|
+
│ 客户端 A (ws_client_002) 发送: │
|
|
610
|
+
│ { type: "direct", data: { chatType: "toAgent", ... } } │
|
|
611
|
+
└────────┬────────────────────────────────────────────────────┘
|
|
612
|
+
│
|
|
613
|
+
│ 4. 服务器添加 from 字段并转发
|
|
614
|
+
▼
|
|
615
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
616
|
+
│ { │
|
|
617
|
+
│ type: "direct", │
|
|
618
|
+
│ from: "ws_client_002", ← 服务器添加的动态 client_id │
|
|
619
|
+
│ data: { chatType: "toAgent", ... } │
|
|
620
|
+
│ } │
|
|
621
|
+
└────────┬────────────────────────────────────────────────────┘
|
|
622
|
+
│
|
|
623
|
+
│ 5. 插件收到消息,处理 Agent 推理
|
|
624
|
+
▼
|
|
625
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
626
|
+
│ Agent 推理完成,准备回复 │
|
|
627
|
+
│ - 读取 message.from = "ws_client_002" │
|
|
628
|
+
│ - 设置回复的 to = "ws_client_002" │
|
|
629
|
+
└────────┬────────────────────────────────────────────────────┘
|
|
630
|
+
│
|
|
631
|
+
│ 6. 发送回复
|
|
632
|
+
▼
|
|
633
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
634
|
+
│ { │
|
|
635
|
+
│ type: "direct", │
|
|
636
|
+
│ to: "ws_client_002", ← 回复到原发送者的 client_id │
|
|
637
|
+
│ data: { chatType: "agent_chat", ... } │
|
|
638
|
+
│ } │
|
|
639
|
+
└────────┬────────────────────────────────────────────────────┘
|
|
640
|
+
│
|
|
641
|
+
│ 7. 服务器根据 to 字段路由回客户端 A
|
|
642
|
+
▼
|
|
643
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
644
|
+
│ 客户端 A 收到回复 │
|
|
645
|
+
└─────────────────────────────────────────────────────────────┘
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**关键点:**
|
|
649
|
+
- 服务器为每个连接分配唯一的 `client_id`
|
|
650
|
+
- `from` 和 `to` 字段由服务器动态管理,客户端不需要预设
|
|
651
|
+
- 插件回复时使用 `message.from` 作为 `to`,确保回复给正确的发送者
|
|
652
|
+
- 服务器根据 `to` 字段将消息路由到对应的客户端
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
## 完整使用示例
|
|
657
|
+
|
|
658
|
+
### 场景 1: 启动并注册节点
|
|
659
|
+
|
|
660
|
+
```javascript
|
|
661
|
+
// 服务器端代码示例
|
|
662
|
+
const WebSocket = require('ws');
|
|
663
|
+
const wss = new WebSocket.Server({ port: 8765 });
|
|
664
|
+
|
|
665
|
+
// 为每个连接动态分配 client_id
|
|
666
|
+
let clientIdCounter = 0;
|
|
667
|
+
const clientMap = new Map(); // ws -> client_id
|
|
668
|
+
|
|
669
|
+
wss.on('connection', (ws) => {
|
|
670
|
+
const clientId = `ws_client_${++clientIdCounter}`;
|
|
671
|
+
clientMap.set(ws, clientId);
|
|
672
|
+
|
|
673
|
+
console.log(`新节点连接: ${clientId}`);
|
|
674
|
+
|
|
675
|
+
// 发送欢迎消息,触发节点注册
|
|
676
|
+
ws.send(JSON.stringify({
|
|
677
|
+
type: 'welcome',
|
|
678
|
+
timestamp: new Date().toISOString()
|
|
679
|
+
}));
|
|
680
|
+
|
|
681
|
+
// 监听节点的 whoIAm 注册
|
|
682
|
+
ws.on('message', (data) => {
|
|
683
|
+
const msg = JSON.parse(data);
|
|
684
|
+
|
|
685
|
+
if (msg.type === 'whoIAm') {
|
|
686
|
+
console.log(`节点 ${clientId} 注册成功`);
|
|
687
|
+
// 保存节点信息
|
|
688
|
+
registeredNodes.set(clientId, msg.data.config);
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
// 清理断开的连接
|
|
693
|
+
ws.on('close', () => {
|
|
694
|
+
clientMap.delete(ws);
|
|
695
|
+
registeredNodes.delete(clientId);
|
|
696
|
+
console.log(`节点 ${clientId} 断开连接`);
|
|
697
|
+
});
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
// 获取连接的 client_id
|
|
701
|
+
function getClientId(ws) {
|
|
702
|
+
return clientMap.get(ws);
|
|
703
|
+
}
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
### 场景 2: 与 Agent 对话(使用动态 client_id)
|
|
707
|
+
|
|
708
|
+
```javascript
|
|
709
|
+
// WebSocket 服务器转发客户端消息
|
|
710
|
+
function forwardMessageToAgent(clientWs, userMessage) {
|
|
711
|
+
const fromClientId = getClientId(clientWs);
|
|
712
|
+
|
|
713
|
+
// 服务器添加 from 字段后转发给 Agent
|
|
714
|
+
const message = {
|
|
715
|
+
type: 'direct',
|
|
716
|
+
from: fromClientId, // 动态分配的 client_id
|
|
717
|
+
timestamp: new Date().toISOString(),
|
|
718
|
+
data: {
|
|
719
|
+
chatType: 'toAgent',
|
|
720
|
+
content: userMessage
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
// 发送给 Agent 插件
|
|
725
|
+
agentWs.send(JSON.stringify(message));
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Agent 回复时,使用 to 字段路由回原客户端
|
|
729
|
+
// (插件代码中:to: message.from)
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
### 场景 3: 查询并操作 Workspace
|
|
733
|
+
|
|
734
|
+
```javascript
|
|
735
|
+
// 客户端通过服务器查询 Workspace
|
|
736
|
+
const ws = new WebSocket('ws://localhost:8765');
|
|
737
|
+
|
|
738
|
+
ws.on('open', () => {
|
|
739
|
+
// 1. 列出所有文件(不需要 from,服务器自动添加)
|
|
740
|
+
ws.send(JSON.stringify({
|
|
741
|
+
type: 'direct',
|
|
742
|
+
data: {
|
|
743
|
+
chatType: 'toCmd',
|
|
744
|
+
gateWay: { cmd: 'workspace.list' }
|
|
745
|
+
}
|
|
746
|
+
}));
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
// 服务器在转发时添加 from 字段
|
|
750
|
+
// Agent 回复时使用 to 字段路由回正确的客户端
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
---
|
|
754
|
+
|
|
755
|
+
## 开发和调试
|
|
756
|
+
|
|
757
|
+
### 构建项目
|
|
758
|
+
|
|
759
|
+
```bash
|
|
760
|
+
# 安装依赖
|
|
761
|
+
npm install
|
|
762
|
+
|
|
763
|
+
# 开发模式(自动编译)
|
|
764
|
+
npm run dev
|
|
765
|
+
|
|
766
|
+
# 生产构建
|
|
767
|
+
npm run build
|
|
768
|
+
|
|
769
|
+
# 清理构建文件
|
|
770
|
+
npm run clean
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
### 查看日志
|
|
774
|
+
|
|
775
|
+
```bash
|
|
776
|
+
# 查看 Gateway 日志
|
|
777
|
+
openclaw logs --grep "fast_task"
|
|
778
|
+
|
|
779
|
+
# 查看 WebSocket 连接状态
|
|
780
|
+
openclaw logs --grep "WebSocket"
|
|
781
|
+
|
|
782
|
+
# 查看 Agent 交互
|
|
783
|
+
openclaw logs --grep "Agent"
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### 测试连接
|
|
787
|
+
|
|
788
|
+
```bash
|
|
789
|
+
# 使用 wscat 测试 WebSocket 连接
|
|
790
|
+
wscat -c ws://localhost:8765
|
|
791
|
+
|
|
792
|
+
# 连接后发送测试消息
|
|
793
|
+
> {"type":"direct","data":{"chatType":"toCmd","gateWay":{"cmd":"agents.list"}}}
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
---
|
|
797
|
+
|
|
798
|
+
## 架构说明
|
|
799
|
+
|
|
800
|
+
### 核心模块
|
|
801
|
+
|
|
802
|
+
- **ws_client.ts**: WebSocket 客户端实现
|
|
803
|
+
- 连接管理(自动重连)
|
|
804
|
+
- 消息收发
|
|
805
|
+
- whoIAm 注册逻辑
|
|
806
|
+
|
|
807
|
+
- **channel_gateway.ts**: Gateway 适配器
|
|
808
|
+
- 启动/停止账户
|
|
809
|
+
- 管理 WebSocket 生命周期
|
|
810
|
+
|
|
811
|
+
- **workspace.ts**: Workspace 文件操作
|
|
812
|
+
- 读写配置文件
|
|
813
|
+
- 文件验证
|
|
814
|
+
|
|
815
|
+
### 消息类型 (MessageType)
|
|
816
|
+
|
|
817
|
+
| Type | 说明 |
|
|
818
|
+
|------|------|
|
|
819
|
+
| `welcome` | 服务器欢迎消息,触发注册 |
|
|
820
|
+
| `whoIAm` | 节点身份注册 |
|
|
821
|
+
| `direct` | 点对点消息(聊天或命令) |
|
|
822
|
+
|
|
823
|
+
### ChatType 分类
|
|
824
|
+
|
|
825
|
+
| ChatType | 分类 | 说明 |
|
|
826
|
+
|----------|------|------|
|
|
827
|
+
| `register` | 注册 | whoIAm 注册 |
|
|
828
|
+
| `toAgent` | 聊天 | 发送到 Agent 处理 |
|
|
829
|
+
| `toCmd` | 命令 | 执行网关命令 |
|
|
830
|
+
| `agent_chat` | 回复 | Agent 正常回复 |
|
|
831
|
+
| `agent_error` | 回复 | Agent 错误信息 |
|
|
832
|
+
| `agent_idle` | 回复 | Agent 空闲状态 |
|
|
833
|
+
|
|
834
|
+
---
|
|
835
|
+
|
|
836
|
+
## 常见问题
|
|
837
|
+
|
|
838
|
+
### Q: 如何确认节点已成功注册?
|
|
839
|
+
|
|
840
|
+
A: 检查日志中是否有 "✓ WebSocket 已连接" 和 whoIAm 消息已发送的日志。
|
|
841
|
+
|
|
842
|
+
### Q: Agent 不回复消息怎么办?
|
|
843
|
+
|
|
844
|
+
A: 检查:
|
|
845
|
+
1. 消息格式是否正确(chatType: "toAgent")
|
|
846
|
+
2. 服务器是否正确添加了 `from` 字段
|
|
847
|
+
3. Agent 是否已正确绑定
|
|
848
|
+
4. 插件是否正确读取了 `message.from` 并设置回复的 `to`
|
|
849
|
+
|
|
850
|
+
### Q: 如何重启 WebSocket 连接?
|
|
851
|
+
|
|
852
|
+
A: 使用 OpenClaw 命令:
|
|
853
|
+
```bash
|
|
854
|
+
openclaw gateway restart
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
### Q: 支持多节点吗?
|
|
858
|
+
|
|
859
|
+
A: 是的,每个节点在连接时都会发送自己的 whoIAm 信息,服务器可以为每个连接分配独立的 client_id 并管理多个节点。
|
|
860
|
+
|
|
861
|
+
### Q: from 和 to 字段是由谁管理的?
|
|
862
|
+
|
|
863
|
+
A: 由 **WebSocket 服务器** 统一管理:
|
|
864
|
+
- 服务器在转发客户端消息时添加 `from` 字段
|
|
865
|
+
- 插件回复时使用 `to` 字段指定接收者
|
|
866
|
+
- 服务器根据 `to` 字段将消息路由到正确的客户端
|
|
867
|
+
|
|
868
|
+
### Q: 客户端需要知道自己的 client_id 吗?
|
|
869
|
+
|
|
870
|
+
A: 不需要。客户端只需要发送消息内容,服务器会自动处理路由。但在调试时,可以通过服务器的响应消息中的 `to` 字段了解自己的 client_id。
|
|
871
|
+
|
|
872
|
+
### Q: 如何实现消息广播?
|
|
873
|
+
|
|
874
|
+
A: 服务器可以在转发消息时将 `to` 设置为特殊值(如 `"broadcast"` 或 `null`),插件收到后可以识别并广播到所有连接的客户端。
|
|
875
|
+
|
|
876
|
+
### Q: 连接断开后 client_id 会保留吗?
|
|
877
|
+
|
|
878
|
+
A: 这取决于服务器实现。建议:
|
|
879
|
+
- 短期断开:服务器保留 client_id 映射,重连后恢复
|
|
880
|
+
- 长期断开:清除映射,重新连接时分配新的 client_id
|
|
881
|
+
- 可以使用心跳机制检测连接状态
|
|
882
|
+
|
|
883
|
+
---
|
|
884
|
+
|
|
885
|
+
## 相关文档
|
|
886
|
+
|
|
887
|
+
- [WebSocket 客户端详解](docs/websocket_client_消息调度详解.md)
|
|
888
|
+
- [自建 WS 服务 IM 调度](docs/自建ws服务im调度.md)
|
|
889
|
+
- [IM Agent 设计方案](docs/im_agent设计方案.md)
|
|
890
|
+
|
|
891
|
+
---
|
|
92
892
|
|
|
93
893
|
## 许可证
|
|
94
894
|
|
|
95
895
|
MIT
|
|
896
|
+
|
|
897
|
+
---
|
|
898
|
+
|
|
899
|
+
## 作者
|
|
900
|
+
|
|
901
|
+
XPDD <1239694214@qq.com>
|
package/package.json
CHANGED