@core-workspace/infoflow-openclaw-plugin 2026.3.9 → 2026.3.27-beta.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/CHANGELOG.md +91 -0
- package/CLAUDE.md +135 -0
- package/COLLABORATION_REPORT.md +209 -0
- package/PROJECT_GUIDE.md +355 -0
- package/README.md +158 -66
- package/docs/dev-guide.md +63 -50
- package/docs/qa-feature-list.md +452 -0
- package/docs/webhook-guide.md +178 -0
- package/index.ts +28 -2
- package/openclaw.plugin.json +131 -21
- package/package.json +16 -3
- package/scripts/deploy.sh +66 -7
- package/scripts/postinstall.cjs +80 -0
- package/skills/infoflow-dev/SKILL.md +2 -2
- package/skills/infoflow-dev/references/api.md +1 -1
- package/src/adapter/inbound/webhook-parser.ts +27 -5
- package/src/adapter/inbound/ws-receiver.ts +304 -43
- package/src/adapter/outbound/markdown-local-images.ts +80 -0
- package/src/adapter/outbound/reply-dispatcher.ts +146 -65
- package/src/adapter/outbound/target-resolver.ts +4 -3
- package/src/channel/accounts.ts +97 -22
- package/src/channel/channel.ts +456 -12
- package/src/channel/media.ts +20 -6
- package/src/channel/monitor.ts +8 -3
- package/src/channel/outbound.ts +358 -21
- package/src/channel/streaming.ts +740 -0
- package/src/commands/changelog.ts +80 -0
- package/src/commands/doctor.ts +545 -0
- package/src/commands/logs.ts +449 -0
- package/src/commands/version.ts +20 -0
- package/src/compat/openclaw-sdk.ts +218 -0
- package/src/handler/message-handler.ts +673 -166
- package/src/logging.ts +1 -1
- package/src/runtime.ts +1 -1
- package/src/security/dm-policy.ts +1 -4
- package/src/security/group-policy.ts +174 -51
- package/src/tools/actions/index.ts +15 -13
- package/src/tools/cron/relay.ts +1154 -0
- package/src/tools/hooks/index.ts +13 -1
- package/src/tools/index.ts +714 -32
- package/src/types.ts +144 -25
- package/src/utils/audio/g722/dct_tables.ts +381 -0
- package/src/utils/audio/g722/decoder.ts +919 -0
- package/src/utils/audio/g722/defs.ts +105 -0
- package/src/utils/audio/g722/hd-parser.ts +247 -0
- package/src/utils/audio/g722/huff_tables.ts +240 -0
- package/src/utils/audio/g722/index.ts +78 -0
- package/src/utils/audio/g722/output_decoded.pcm +0 -0
- package/src/utils/audio/g722/output_decoded.wav +0 -0
- package/src/utils/audio/g722/tables.ts +173 -0
- package/src/utils/audio/g722/test_api.ts +31 -0
- package/src/utils/audio/g722/test_voice.hd +0 -0
- package/src/utils/bos/im-bos-client.ts +219 -0
- package/src/utils/group-agent-cache.ts +142 -0
- package/src/utils/token-adapter.ts +120 -51
package/PROJECT_GUIDE.md
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# Infoflow OpenClaw Plugin — 项目导读
|
|
2
|
+
|
|
3
|
+
> 本文档面向初次接触此项目的开发者,帮助快速建立对项目结构、模块职责和核心逻辑的完整认知。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 一、项目定位
|
|
8
|
+
|
|
9
|
+
这是一个 **OpenClaw 渠道插件**,把百度如流(Infoflow)企业消息平台接入 OpenClaw AI Agent 框架。
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
如流用户 ←→ 如流服务器 ←→ OpenClaw (本插件) ←→ LLM
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
插件负责:接收消息 → 安全判断 → 分发给 LLM → 把回复发回如流。
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 二、目录结构全览
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
openclaw_infoflow/
|
|
23
|
+
├── index.ts # 插件入口:注册所有能力
|
|
24
|
+
├── src/
|
|
25
|
+
│ ├── types.ts # 所有 TypeScript 类型定义
|
|
26
|
+
│ ├── runtime.ts # OpenClaw runtime 单例
|
|
27
|
+
│ ├── logging.ts # 日志工具(多个命名 logger)
|
|
28
|
+
│ ├── events.ts # 内部事件总线(message:sent)
|
|
29
|
+
│ ├── compat/
|
|
30
|
+
│ │ └── openclaw-sdk.ts # SDK 兼容层(统一导出 openclaw/* 子路径)
|
|
31
|
+
│ │
|
|
32
|
+
│ ├── channel/ # 与如流 API 直接交互的 I/O 层
|
|
33
|
+
│ │ ├── channel.ts # ChannelPlugin 定义(OpenClaw 渠道注册)
|
|
34
|
+
│ │ ├── monitor.ts # Webhook/WebSocket 监听器生命周期
|
|
35
|
+
│ │ ├── outbound.ts # 发消息/撤回/ASR/群成员列表 API
|
|
36
|
+
│ │ ├── accounts.ts # 多账号配置解析
|
|
37
|
+
│ │ ├── media.ts # 图片 base64 准备与发送
|
|
38
|
+
│ │ └── streaming.ts # 流式卡片会话(streaming-card 格式)
|
|
39
|
+
│ │
|
|
40
|
+
│ ├── adapter/
|
|
41
|
+
│ │ ├── inbound/
|
|
42
|
+
│ │ │ ├── webhook-parser.ts # AES 解密、签名验证、去重、路由
|
|
43
|
+
│ │ │ └── ws-receiver.ts # WebSocket 接收器
|
|
44
|
+
│ │ └── outbound/
|
|
45
|
+
│ │ ├── reply-dispatcher.ts # LLM 回复 → Infoflow 消息的适配
|
|
46
|
+
│ │ ├── target-resolver.ts # infoflow: 前缀标准化
|
|
47
|
+
│ │ └── markdown-local-images.ts # Markdown 中本地图片替换
|
|
48
|
+
│ │
|
|
49
|
+
│ ├── handler/
|
|
50
|
+
│ │ └── message-handler.ts # 核心分发逻辑(最复杂的模块)
|
|
51
|
+
│ │
|
|
52
|
+
│ ├── security/
|
|
53
|
+
│ │ ├── dm-policy.ts # 私聊访问策略(open/pairing/allowlist)
|
|
54
|
+
│ │ └── group-policy.ts # 群聊策略(replyMode 判断、@mention 检测)
|
|
55
|
+
│ │
|
|
56
|
+
│ ├── tools/
|
|
57
|
+
│ │ ├── index.ts # LLM 工具注册(send/recall/cron/bos)
|
|
58
|
+
│ │ ├── hooks/index.ts # OpenClaw hooks 注册
|
|
59
|
+
│ │ ├── actions/index.ts # Channel action 定义
|
|
60
|
+
│ │ └── cron/relay.ts # 定时任务中继服务
|
|
61
|
+
│ │
|
|
62
|
+
│ ├── commands/
|
|
63
|
+
│ │ ├── doctor.ts # /infoflow-doctor 诊断命令
|
|
64
|
+
│ │ ├── logs.ts # /infoflow-logs 日志命令
|
|
65
|
+
│ │ ├── changelog.ts # /infoflow-changelog 更新日志命令
|
|
66
|
+
│ │ └── version.ts # 版本信息
|
|
67
|
+
│ │
|
|
68
|
+
│ └── utils/
|
|
69
|
+
│ ├── store/
|
|
70
|
+
│ │ └── message-store.ts # SQLite:已发消息记录(撤回依赖)
|
|
71
|
+
│ ├── audio/g722/ # 如流私有音频格式 .hd → WAV 解码
|
|
72
|
+
│ ├── bos/
|
|
73
|
+
│ │ └── im-bos-client.ts # 百度 BOS 文件上传/预签名 URL
|
|
74
|
+
│ ├── group-agent-cache.ts # 群成员 name→agentId 缓存
|
|
75
|
+
│ └── token-adapter.ts # App Access Token 管理(自动刷新)
|
|
76
|
+
│
|
|
77
|
+
├── tests/ # 测试(镜像 src/ 结构)
|
|
78
|
+
└── scripts/
|
|
79
|
+
├── deploy.sh # 部署脚本(sync + openclaw gateway restart)
|
|
80
|
+
└── build-tools/ # 构建辅助
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 三、模块职责速查
|
|
86
|
+
|
|
87
|
+
| 模块 | 职责一句话 |
|
|
88
|
+
|------|-----------|
|
|
89
|
+
| `index.ts` | 插件入口,注册所有能力(渠道/路由/工具/命令/服务) |
|
|
90
|
+
| `channel/channel.ts` | 向 OpenClaw 描述本渠道(配置 schema、启停逻辑) |
|
|
91
|
+
| `channel/monitor.ts` | 管理 Webhook 路径注册表;启/停 WS 接收器 |
|
|
92
|
+
| `adapter/inbound/webhook-parser.ts` | **入口解析**:AES 解密、签名验证、消息去重、路由私聊/群聊 |
|
|
93
|
+
| `handler/message-handler.ts` | **核心**:策略门控 → 构建上下文 → 媒体下载 → 分发 LLM |
|
|
94
|
+
| `security/dm-policy.ts` | 私聊白名单/配对策略(纯函数,无 I/O) |
|
|
95
|
+
| `security/group-policy.ts` | 群聊 replyMode 判断、@mention 检测(纯函数,无 I/O) |
|
|
96
|
+
| `channel/outbound.ts` | 发送/撤回/ASR/群成员 API 封装(所有 HTTP 出口) |
|
|
97
|
+
| `adapter/outbound/reply-dispatcher.ts` | 把 LLM 的 ReplyPayload 转为 Infoflow 消息并发送 |
|
|
98
|
+
| `tools/index.ts` | 注册 LLM 可调用工具:send/recall/cron/bos |
|
|
99
|
+
| `utils/store/message-store.ts` | SQLite 存储已发消息(撤回时查 messageid+msgseqid) |
|
|
100
|
+
| `utils/token-adapter.ts` | App Token 缓存,自动刷新,并发安全 |
|
|
101
|
+
| `utils/group-agent-cache.ts` | 群 robot name→agentId 映射缓存(@机器人名字→正确 AT) |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 四、消息入站全流程
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
如流服务器 POST /webhook/infoflow
|
|
109
|
+
│
|
|
110
|
+
▼
|
|
111
|
+
monitor.ts: handleInfoflowWebhookRequest
|
|
112
|
+
- 路径匹配 webhookTargets 注册表
|
|
113
|
+
- 只允许 POST,否则 405
|
|
114
|
+
- 读取原始 body(≤20MB)
|
|
115
|
+
│
|
|
116
|
+
▼
|
|
117
|
+
webhook-parser.ts: parseAndDispatchInfoflowRequest
|
|
118
|
+
按 Content-Type 分支:
|
|
119
|
+
┌── application/x-www-form-urlencoded
|
|
120
|
+
│ ├── echostr 字段 → 验签(MD5: rn+timestamp+checkToken)→ 200/403
|
|
121
|
+
│ └── messageJson 字段 → 私聊路径
|
|
122
|
+
└── text/plain → 群聊路径(body 本身就是密文)
|
|
123
|
+
|
|
124
|
+
tryDecryptAndDispatch(私聊/群聊共用):
|
|
125
|
+
1. AES-ECB 解密(尝试所有账号的 encodingAESKey)
|
|
126
|
+
2. patchPreciseIds:16+ 位整数转字符串(防 JSON.parse 精度丢失)
|
|
127
|
+
3. JSON.parse(私聊 fallback: XML 解析)
|
|
128
|
+
4. 去重检查(5分钟 TTL,1000条 LRU)
|
|
129
|
+
5. fire-and-forget 分发
|
|
130
|
+
│
|
|
131
|
+
▼
|
|
132
|
+
message-handler.ts: handlePrivateChatMessage
|
|
133
|
+
或 handleGroupChatMessage
|
|
134
|
+
┌── 私聊:提取字段 → dmPolicy 检查 → 语音处理 → handleInfoflowMessage
|
|
135
|
+
└── 群聊:提取字段 → groupPolicy 检查 → robotId 自发现 → 去自身消息
|
|
136
|
+
→ body 解析(TEXT/AT/IMAGE/replyData)→ handleInfoflowMessage
|
|
137
|
+
│
|
|
138
|
+
▼
|
|
139
|
+
message-handler.ts: handleInfoflowMessage(核心分发)
|
|
140
|
+
1. resolveAgentRoute → 确定 LLM agent 和 sessionKey
|
|
141
|
+
2. peerId 路由计算(group/user 模式)
|
|
142
|
+
3. 图片/语音媒体下载(SSRF 白名单保护)
|
|
143
|
+
4. 构建 ctxPayload(Body/From/To/MessageSid 等)
|
|
144
|
+
5. replyMode 门控(见第五节)
|
|
145
|
+
6. 启动 processing hint 定时器(默认 5s)
|
|
146
|
+
7. createInfoflowReplyDispatcher → 配置 deliver 回调
|
|
147
|
+
8. dispatchReplyWithBufferedBlockDispatcher → 送入 LLM
|
|
148
|
+
9. 清理历史、记录 followUp 时间戳
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 五、群聊 replyMode 门控(最核心的业务逻辑)
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
┌─────────────────────────────────┐
|
|
157
|
+
│ resolveGroupConfig │
|
|
158
|
+
│ groups.<id> > account > legacy │
|
|
159
|
+
└───────────────┬─────────────────┘
|
|
160
|
+
│ replyMode
|
|
161
|
+
┌─────────────────────┼──────────────────────┐
|
|
162
|
+
│ │ │
|
|
163
|
+
ignore record mention-only
|
|
164
|
+
│ │ │
|
|
165
|
+
丢弃 仅存历史 @机器人才触发
|
|
166
|
+
│
|
|
167
|
+
否─→ followUp 窗口内?─→ 是
|
|
168
|
+
│ │
|
|
169
|
+
存历史 LLM判断
|
|
170
|
+
丢弃
|
|
171
|
+
|
|
172
|
+
mention-and-watch proactive
|
|
173
|
+
───────────────── ─────────
|
|
174
|
+
@机器人 ─→ 触发 全量消息送 LLM
|
|
175
|
+
watchMentions 命中 ─→ 触发(watch提示) LLM 自决定 NO_REPLY
|
|
176
|
+
watchRegex 命中 ─→ 触发(regex提示)
|
|
177
|
+
否 ─→ followUp 窗口 ─→ 触发/存历史
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### followUp 窗口机制
|
|
181
|
+
- 机器人每次发出回复时,`recordGroupReply(groupId)` 记录时间戳
|
|
182
|
+
- 后续消息到达时,`isWithinFollowUpWindow(groupId, windowSeconds)` 判断是否在窗口内
|
|
183
|
+
- 窗口内的消息会注入 `GroupSystemPrompt`,让 LLM 判断是否是跟进问题,并允许输出 `NO_REPLY`
|
|
184
|
+
|
|
185
|
+
### GroupSystemPrompt 注入场景
|
|
186
|
+
|
|
187
|
+
| 触发原因 | 注入的提示 |
|
|
188
|
+
|---------|-----------|
|
|
189
|
+
| `followUp` | 告知 LLM 刚刚回复过,让它判断新消息是否跟进 |
|
|
190
|
+
| `watchMentions(id)` | 告知 LLM 某人被 @,作为其助手决定是否代回 |
|
|
191
|
+
| `watchRegex(pattern)` | 告知 LLM 内容命中配置的正则,决定是否回复 |
|
|
192
|
+
| `proactive` | 告知 LLM 在群里观察到消息,决定是否主动回复 |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 六、消息出站全流程
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
LLM 输出文本/工具调用
|
|
200
|
+
│
|
|
201
|
+
▼
|
|
202
|
+
reply-dispatcher.ts: createInfoflowReplyDispatcher
|
|
203
|
+
- 文本按 textChunkLimit(默认1800字符)切分
|
|
204
|
+
- 解析 @name 引用 → 通过 group-agent-cache 转换为 at-agent agentId
|
|
205
|
+
- 清理 bodyForAgent 注解(如 "(robotid:123)")
|
|
206
|
+
- Markdown 本地图片 → base64 嵌入
|
|
207
|
+
│
|
|
208
|
+
▼
|
|
209
|
+
outbound.ts: sendInfoflowMessage
|
|
210
|
+
解析 to 格式:
|
|
211
|
+
┌── "group:12345" → sendInfoflowGroupMessage
|
|
212
|
+
│ - TEXT/MD/AT 合并一条发
|
|
213
|
+
│ - LINK 逐条单独发
|
|
214
|
+
│ - IMAGE 逐条单独发
|
|
215
|
+
└── "username" → sendInfoflowPrivateMessage
|
|
216
|
+
+ 图片 → sendInfoflowPrivateImage(单独调用)
|
|
217
|
+
|
|
218
|
+
每条发送成功后:
|
|
219
|
+
- recordSentMessageId → 去重缓存(防止自己的发出消息被处理)
|
|
220
|
+
- coreEvents.emit("message:sent") → message-store.ts 写入 SQLite
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 鉴权
|
|
224
|
+
- Token 通过 `getAppAccessToken` 获取,由 `token-adapter.ts` 缓存并在到期前自动刷新
|
|
225
|
+
- 请求头格式:`Authorization: Bearer-<token>`(如流私有格式,非标准)
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 七、64 位整数精度问题(重要)
|
|
230
|
+
|
|
231
|
+
如流的 messageid 超过 `Number.MAX_SAFE_INTEGER (2^53-1)`,直接 `JSON.parse` 会丢失精度。
|
|
232
|
+
|
|
233
|
+
**入站**(`webhook-parser.ts`):
|
|
234
|
+
```
|
|
235
|
+
patchPreciseIds(rawText)
|
|
236
|
+
正则: /"(messageid|msgid|MsgId|msgkey)"\s*:\s*(\d{16,})/g
|
|
237
|
+
替换: "messageid": 12345678901234567 → "messageid": "12345678901234567"
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**出站**(`outbound.ts`):
|
|
241
|
+
```
|
|
242
|
+
extractIdFromRawJson(responseText, "messageid")
|
|
243
|
+
从原始响应字符串中用正则提取,不经过 JSON.parse
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**撤回**:手动拼 JSON 字符串,避免 stringify 精度丢失:
|
|
247
|
+
```ts
|
|
248
|
+
const bodyStr = `{"groupId":${groupId},"messageid":${messageid},"msgseqid":${msgseqid}}`;
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## 八、语音消息处理流程
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
收到 msgType=voice
|
|
257
|
+
│
|
|
258
|
+
├── voiceUrl 包含 .mp3
|
|
259
|
+
│ → 直接下载,传给 openclaw 处理
|
|
260
|
+
│
|
|
261
|
+
└── voiceUrl 其他格式(.hd 等)
|
|
262
|
+
→ 提取 MD5(从 fileid 参数)
|
|
263
|
+
→ 调用 ASR 接口(/api/v1/va/queryASRResult)
|
|
264
|
+
├── 成功 → mes = 识别文字
|
|
265
|
+
└── 失败 → 下载 .hd → decodeHdToWav(src/utils/audio/g722/)
|
|
266
|
+
├── 成功 → mes = "[语音消息]", localVoicePath = wav路径
|
|
267
|
+
└── 失败 → 丢弃消息
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## 九、LLM 工具(Tools)
|
|
273
|
+
|
|
274
|
+
注册在 `tools/index.ts`,LLM 在对话中可以主动调用:
|
|
275
|
+
|
|
276
|
+
| 工具名 | 功能 |
|
|
277
|
+
|--------|------|
|
|
278
|
+
| `infoflow_send` | 主动发私聊或群消息(文本/Markdown/图片/@ 成员) |
|
|
279
|
+
| `infoflow_recall` | 撤回最近 N 条或按 messageId 撤回 |
|
|
280
|
+
| `infoflow_cron` | 创建定时消息(绑定当前会话目标,LLM 无法伪造收件人) |
|
|
281
|
+
| `infoflow_bos_upload` | 上传文件到 BOS,返回预签名下载 URL |
|
|
282
|
+
| `infoflow_bos_get_url` | 刷新已上传文件的预签名 URL |
|
|
283
|
+
|
|
284
|
+
`infoflow_cron` 安全机制:收件人从可信的 session 上下文(groupId/FromUserId)自动绑定,
|
|
285
|
+
LLM 参数里没有 `to` 字段,防止模型被诱导给任意目标发定时消息。
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 十、配置优先级
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
groups.<groupId> > accounts.<id> > 顶层 defaults
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
关键配置字段速查:
|
|
296
|
+
|
|
297
|
+
| 字段 | 作用 |
|
|
298
|
+
|------|------|
|
|
299
|
+
| `replyMode` | 群聊触发策略(ignore/record/mention-only/mention-and-watch/proactive) |
|
|
300
|
+
| `groupSessionMode` | group=群共享会话,user=群内按人分会话 |
|
|
301
|
+
| `followUp` / `followUpWindow` | 跟进窗口开关与时长(默认 300s) |
|
|
302
|
+
| `watchMentions` | 监控 @某人触发 |
|
|
303
|
+
| `watchRegex` | 正则匹配触发 |
|
|
304
|
+
| `dmMessageFormat` | 私聊消息格式(text/markdown/streaming-card) |
|
|
305
|
+
| `groupMessageFormat` | 群聊消息格式 |
|
|
306
|
+
| `textChunkLimit` | 单条消息最大字符数(默认 1800) |
|
|
307
|
+
| `processingHint` / `processingHintDelay` | 慢响应提示(默认开启,5s 后发"👌收到啦") |
|
|
308
|
+
| `appAgentId` | 企业后台应用 ID(私聊撤回必填) |
|
|
309
|
+
| `robotId` | 机器人 ID(自动发现并写回配置) |
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 十一、连接模式
|
|
314
|
+
|
|
315
|
+
| 模式 | 说明 |
|
|
316
|
+
|------|------|
|
|
317
|
+
| `webhook`(默认) | 如流主动 POST 到 `/webhook/infoflow` |
|
|
318
|
+
| `websocket` | 插件主动连接如流 WS 网关,`ws-receiver.ts` 接收推送 |
|
|
319
|
+
|
|
320
|
+
WebSocket 模式需配置 `wsGateway`(Phase 1 端点分配)和可选的 `wsConnectDomain`(Phase 2 握手地址)。
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## 十二、关键约定
|
|
325
|
+
|
|
326
|
+
1. **所有 TS import 必须带 `.js` 后缀**(ESM 运行时要求)
|
|
327
|
+
2. **messageid 始终用字符串操作**,不经 Number 转换
|
|
328
|
+
3. **`openclaw` 是 peerDependency**,`deploy.sh` 部署时用 symlink 指向全局安装
|
|
329
|
+
4. **群消息 LINK 和 IMAGE 必须单独发送**(如流 API 限制,不能和文字混在同一条)
|
|
330
|
+
5. **撤回群消息需要 `messageid + msgseqid`**,私聊撤回需要 `msgkey + appAgentId`
|
|
331
|
+
6. **`robotId` 自动发现**:首次被 @时从 body AT 元素中读取并持久化到配置文件
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## 十三、本地调试
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
# 安装依赖
|
|
339
|
+
npm install
|
|
340
|
+
|
|
341
|
+
# 运行测试
|
|
342
|
+
npm test
|
|
343
|
+
|
|
344
|
+
# 部署(sync 到 ~/.openclaw/extensions/infoflow-openclaw-plugin/ 并重启网关)
|
|
345
|
+
./scripts/deploy.sh
|
|
346
|
+
|
|
347
|
+
# 查看实时日志
|
|
348
|
+
openclaw logs | grep infoflow
|
|
349
|
+
|
|
350
|
+
# 诊断配置
|
|
351
|
+
/infoflow-doctor
|
|
352
|
+
|
|
353
|
+
# 查看收发日志(最近 50 条)
|
|
354
|
+
/infoflow-logs 50
|
|
355
|
+
```
|