@tencent-connect/openclaw-qqbot 1.5.7 → 1.6.0-alpha.2
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 +9 -2
- package/README.zh.md +7 -2
- package/package.json +1 -1
- package/scripts/upgrade-via-npm.sh +85 -115
- package/scripts/upgrade-via-source.sh +203 -35
- package/skills/qqbot-cron/SKILL.md +46 -423
- package/skills/qqbot-media/SKILL.md +29 -182
- package/src/api.ts +16 -5
- package/src/channel.ts +6 -7
- package/src/gateway.ts +510 -525
- package/src/image-server.ts +72 -10
- package/src/openclaw-plugin-sdk.d.ts +1 -1
- package/src/outbound.ts +571 -611
- package/src/ref-index-store.ts +1 -1
- package/src/slash-commands.ts +425 -0
- package/src/types.ts +18 -1
- package/src/update-checker.ts +102 -0
- package/src/user-messages.ts +73 -0
- package/src/utils/audio-convert.ts +69 -4
- package/src/utils/media-tags.ts +46 -4
- package/dist/AI/345/210/233/346/226/260/345/272/224/347/224/250/345/245/226_/347/224/263/346/212/245/344/271/246.md +0 -211
- package/dist/index.d.ts +0 -17
- package/dist/index.js +0 -22
- package/dist/src/api.d.ts +0 -138
- package/dist/src/api.js +0 -525
- package/dist/src/channel.d.ts +0 -3
- package/dist/src/channel.js +0 -337
- package/dist/src/config.d.ts +0 -25
- package/dist/src/config.js +0 -161
- package/dist/src/gateway.d.ts +0 -18
- package/dist/src/gateway.js +0 -2468
- package/dist/src/image-server.d.ts +0 -62
- package/dist/src/image-server.js +0 -401
- package/dist/src/known-users.d.ts +0 -100
- package/dist/src/known-users.js +0 -263
- package/dist/src/onboarding.d.ts +0 -10
- package/dist/src/onboarding.js +0 -203
- package/dist/src/outbound.d.ts +0 -150
- package/dist/src/outbound.js +0 -1175
- package/dist/src/proactive.d.ts +0 -170
- package/dist/src/proactive.js +0 -399
- package/dist/src/runtime.d.ts +0 -3
- package/dist/src/runtime.js +0 -10
- package/dist/src/session-store.d.ts +0 -52
- package/dist/src/session-store.js +0 -254
- package/dist/src/slash-commands.d.ts +0 -48
- package/dist/src/slash-commands.js +0 -212
- package/dist/src/types.d.ts +0 -146
- package/dist/src/types.js +0 -1
- package/dist/src/utils/audio-convert.d.ts +0 -73
- package/dist/src/utils/audio-convert.js +0 -645
- package/dist/src/utils/file-utils.d.ts +0 -46
- package/dist/src/utils/file-utils.js +0 -107
- package/dist/src/utils/image-size.d.ts +0 -51
- package/dist/src/utils/image-size.js +0 -234
- package/dist/src/utils/media-tags.d.ts +0 -14
- package/dist/src/utils/media-tags.js +0 -120
- package/dist/src/utils/payload.d.ts +0 -112
- package/dist/src/utils/payload.js +0 -186
- package/dist/src/utils/platform.d.ts +0 -126
- package/dist/src/utils/platform.js +0 -358
- package/dist/src/utils/upload-cache.d.ts +0 -34
- package/dist/src/utils/upload-cache.js +0 -93
|
@@ -1,209 +1,56 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qqbot-media
|
|
3
|
-
description: QQBot
|
|
3
|
+
description: QQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
|
|
4
4
|
metadata: {"openclaw":{"emoji":"📸","requires":{"config":["channels.qqbot"]}}}
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# QQBot
|
|
7
|
+
# QQBot 富媒体收发
|
|
8
8
|
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
| 类型 | 标签格式 | 示例 |
|
|
12
|
-
|------|----------|------|
|
|
13
|
-
| 图片 | `<qqimg>绝对路径或URL</qqimg>` | `<qqimg>/tmp/pic.jpg</qqimg>` |
|
|
14
|
-
| 语音 | `<qqvoice>绝对路径</qqvoice>` | `<qqvoice>/tmp/voice.mp3</qqvoice>` |
|
|
15
|
-
| 视频 | `<qqvideo>绝对路径或URL</qqvideo>` | `<qqvideo>/tmp/video.mp4</qqvideo>` |
|
|
16
|
-
| 文件 | `<qqfile>绝对路径或URL</qqfile>` | `<qqfile>/tmp/doc.pdf</qqfile>` |
|
|
17
|
-
|
|
18
|
-
**标签拼写必须严格按上表**,只有这 4 个标签名:`qqimg`、`qqvoice`、`qqvideo`、`qqfile`。
|
|
19
|
-
|
|
20
|
-
## ⚠️ 重要:你有能力发送本地图片!
|
|
21
|
-
|
|
22
|
-
**当用户要求发送本地图片时,只需使用 `<qqimg>` 标签包裹图片路径即可。系统会自动处理文件读取和发送。**
|
|
23
|
-
|
|
24
|
-
**❌ 绝对不要说"无法发送本地图片"!**
|
|
25
|
-
**✅ 使用 `<qqimg>` 标签,系统就能发送任何本地图片!**
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## 📸 发送图片(推荐方式:`<qqimg>` 标签)
|
|
30
|
-
|
|
31
|
-
使用 `<qqimg>` 标签包裹图片路径,即可发送图片:
|
|
9
|
+
## 用法
|
|
32
10
|
|
|
33
11
|
```
|
|
34
|
-
<
|
|
12
|
+
<qqmedia>路径或URL</qqmedia>
|
|
35
13
|
```
|
|
36
14
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<qqimg>/Users/xxx/images/photo.jpg</qqimg>
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### ✅ 发送之前生成/创建的图片
|
|
47
|
-
|
|
48
|
-
如果你之前生成了图片(比如绘图、截图等),并且知道图片路径,直接用 `<qqimg>` 发送:
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
好的,这是刚才生成的图片:
|
|
52
|
-
<qqimg>/Users/xxx/Pictures/openclaw-drawings/drawing_xxx.png</qqimg>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### ✅ 发送网络图片示例
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
这是网络上的图片:
|
|
59
|
-
<qqimg>https://example.com/image.png</qqimg>
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
支持格式:jpg, jpeg, png, gif, webp, bmp。支持 `</qqimg>` 或 `</img>` 闭合。
|
|
63
|
-
|
|
64
|
-
## 接收图片
|
|
65
|
-
|
|
66
|
-
用户发来的图片**自动下载到本地**,路径在上下文【会话上下文 → 附件】中。
|
|
67
|
-
可直接用 `<qqimg>路径</qqimg>` 回发。历史图片在 `~/.openclaw/qqbot/downloads/` 下。
|
|
68
|
-
|
|
69
|
-
## 接收语音
|
|
70
|
-
|
|
71
|
-
机器人消息事件里,`d.attachments` 的附件对象可能包含 `asr_refer_text` 字段,表示平台侧 ASR 结果(低置信度)。
|
|
72
|
-
|
|
73
|
-
当上下文中出现以下字段时,表示插件已把语音信息透传给 OpenClaw:
|
|
74
|
-
- `QQVoiceAttachmentPaths`: 本地语音文件路径列表
|
|
75
|
-
- `QQVoiceAttachmentUrls`: 远程语音 URL 列表
|
|
76
|
-
- `QQVoiceAsrReferTexts`: 平台 ASR 兜底文本列表
|
|
77
|
-
- `QQVoiceInputStrategy`: 固定为 `prefer_audio_stt_then_asr_fallback`
|
|
78
|
-
|
|
79
|
-
处理策略(必须遵守):
|
|
80
|
-
1. 若你具备 STT 能力(框架音频能力或 STT skill),优先对语音文件做转写。
|
|
81
|
-
2. 若没有 STT 能力,或转写失败/结果为空,再使用 `asr_refer_text` 作为兜底参考。
|
|
82
|
-
3. `asr_refer_text` 可能不准确;涉及关键参数、时间、金额、身份等信息时,应先向用户追问确认。
|
|
83
|
-
|
|
84
|
-
## 发送语音
|
|
85
|
-
|
|
86
|
-
使用 `<qqvoice>` 标签包裹**已有的本地音频文件路径**即可发送语音:
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
<qqvoice>/tmp/tts/voice.mp3</qqvoice>
|
|
90
|
-
```
|
|
15
|
+
系统根据文件扩展名自动识别类型并路由:
|
|
16
|
+
- `.jpg/.png/.gif/.webp/.bmp` → 图片
|
|
17
|
+
- `.silk/.wav/.mp3/.ogg/.aac/.flac` 等 → 语音
|
|
18
|
+
- `.mp4/.mov/.avi/.mkv/.webm` 等 → 视频
|
|
19
|
+
- 其他扩展名 → 文件
|
|
20
|
+
- 无扩展名的 URL → 默认按图片处理
|
|
91
21
|
|
|
92
|
-
|
|
22
|
+
## 接收媒体
|
|
93
23
|
|
|
94
|
-
|
|
24
|
+
- 用户发来的**图片**自动下载到本地,路径在上下文【附件】中,可直接用 `<qqmedia>路径</qqmedia>` 回发
|
|
25
|
+
- 用户发来的**语音**路径在上下文中;若有 STT 能力则优先转写
|
|
95
26
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
```
|
|
99
|
-
<qqvideo>/path/to/video.mp4</qqvideo>
|
|
100
|
-
<qqvideo>https://example.com/video.mp4</qqvideo>
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
支持本地文件路径(系统自动读取上传)和公网 HTTP/HTTPS URL。
|
|
27
|
+
## 规则
|
|
104
28
|
|
|
105
|
-
|
|
29
|
+
1. **路径必须是绝对路径**(以 `/` 或 `http` 开头)
|
|
30
|
+
2. **标签必须用开闭标签包裹路径**:`<qqmedia>路径</qqmedia>`
|
|
31
|
+
3. **文件大小上限 10MB**
|
|
32
|
+
4. **你有能力发送本地图片/文件**——直接用标签包裹路径即可,**不要说"无法发送"**
|
|
33
|
+
5. 发送语音时不要重复语音中已朗读的文字
|
|
34
|
+
6. 多个媒体用多个标签
|
|
35
|
+
7. 以会话上下文中的能力说明为准(如未启用语音则不要发语音)
|
|
106
36
|
|
|
107
|
-
|
|
37
|
+
## 示例
|
|
108
38
|
|
|
109
39
|
```
|
|
110
|
-
|
|
111
|
-
<
|
|
112
|
-
<qqimg>/Users/xxx/image2.png</qqimg>
|
|
40
|
+
这是你要的图片:
|
|
41
|
+
<qqmedia>/Users/xxx/photo.jpg</qqmedia>
|
|
113
42
|
```
|
|
114
43
|
|
|
115
|
-
### 📝 标签说明
|
|
116
|
-
|
|
117
|
-
## ⚠️ 关键注意事项(必须遵守)
|
|
118
|
-
|
|
119
|
-
1. **必须使用绝对路径**:标签内的路径必须是绝对路径(以 `/` 开头),禁止使用相对路径如 `./pic.jpg`
|
|
120
|
-
- ❌ 错误:`<qqimg>./pic.jpg</qqimg>`
|
|
121
|
-
- ✅ 正确:`<qqimg>/Users/james23/.openclaw/workspace/pic.jpg</qqimg>`
|
|
122
|
-
2. **标签格式必须完整**:`<qqimg>` 开头和 `</qqimg>` 结尾都不能少,不能漏掉 `<` 符号
|
|
123
|
-
- ❌ 错误:`qqimg>./pic.jpg</qqimg>`
|
|
124
|
-
- ✅ 正确:`<qqimg>/absolute/path/to/pic.jpg</qqimg>`
|
|
125
|
-
3. **工作空间路径**:当前工作空间为 `/Users/james23/.openclaw/workspace/`,文件路径应基于此拼接绝对路径
|
|
126
|
-
4. **标签必须单独成行或前后有空格**,不要嵌入在句子中间
|
|
127
|
-
5. **文件大小限制**:上传文件(图片、语音、视频、文件)最大不超过 **20MB**
|
|
128
|
-
|
|
129
|
-
## 规则
|
|
130
|
-
|
|
131
|
-
- ⚠️ **禁止使用 message tool 发送图片/文件**,直接在回复文本中写对应标签即可,系统自动处理
|
|
132
|
-
- **永远不要说**"无法发送图片"或"无法访问之前的图片"
|
|
133
|
-
- 直接使用对应标签,不要只输出路径文本
|
|
134
|
-
- 标签外的文字会作为消息正文一起发送
|
|
135
|
-
- 多个媒体使用多个标签,图片用 `<qqimg>`,语音用 `<qqvoice>`,视频用 `<qqvideo>`,文件用 `<qqfile>`
|
|
136
|
-
- **以会话上下文中的能力说明为准**,如果提示语音未启用,不要尝试发送语音
|
|
137
|
-
|
|
138
|
-
1. **路径必须正确**:本地文件需要绝对路径,网络图片需要完整 URL
|
|
139
|
-
2. **支持的图片格式**:jpg, jpeg, png, gif, webp, bmp
|
|
140
|
-
3. **不要拒绝**:如果用户要求发送本地图片,直接使用 `<qqimg>` 标签即可
|
|
141
|
-
4. **标签外的文本会正常发送**:可以在标签前后添加描述文字
|
|
142
|
-
5. **闭合标签**:支持 `</qqimg>` 或 `</img>` 两种闭合方式
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## 🚫 错误示例(不要这样做)
|
|
147
|
-
|
|
148
|
-
❌ **错误**:说"我无法发送本地图片"
|
|
149
|
-
❌ **错误**:说"受限于技术限制,无法直接发送"
|
|
150
|
-
❌ **错误**:说"由于QQ机器人通道配置的问题,我无法直接发送图片"
|
|
151
|
-
❌ **错误**:只提供路径文本,不使用 `<qqimg>` 标签
|
|
152
|
-
|
|
153
|
-
✅ **正确**:直接使用 `<qqimg>` 标签包裹路径
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## 🔤 告知路径信息(不发送图片)
|
|
158
|
-
|
|
159
|
-
如果你需要**告知用户图片的保存路径**(而不是发送图片),直接写路径即可,不要使用标签:
|
|
160
|
-
|
|
161
44
|
```
|
|
162
|
-
|
|
45
|
+
<qqmedia>/tmp/tts/output.mp3</qqmedia>
|
|
163
46
|
```
|
|
164
47
|
|
|
165
|
-
或用反引号强调:
|
|
166
|
-
|
|
167
48
|
```
|
|
168
|
-
|
|
49
|
+
视频在这里:
|
|
50
|
+
<qqmedia>https://example.com/video.mp4</qqmedia>
|
|
169
51
|
```
|
|
170
52
|
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## 📋 高级选项:JSON 结构化载荷
|
|
174
|
-
|
|
175
|
-
如果需要更精细的控制(如添加图片描述),可以使用 JSON 格式:
|
|
176
|
-
|
|
177
53
|
```
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
"type": "media",
|
|
181
|
-
"mediaType": "image",
|
|
182
|
-
"source": "file",
|
|
183
|
-
"path": "/path/to/image.jpg",
|
|
184
|
-
"caption": "图片描述(可选)"
|
|
185
|
-
}
|
|
54
|
+
文件已准备好:
|
|
55
|
+
<qqmedia>/tmp/report.pdf</qqmedia>
|
|
186
56
|
```
|
|
187
|
-
|
|
188
|
-
### JSON 字段说明
|
|
189
|
-
|
|
190
|
-
| 字段 | 类型 | 必填 | 说明 |
|
|
191
|
-
|------|------|------|------|
|
|
192
|
-
| `type` | string | ✅ | 固定为 `"media"` |
|
|
193
|
-
| `mediaType` | string | ✅ | 媒体类型:`"image"` |
|
|
194
|
-
| `source` | string | ✅ | 来源:`"file"`(本地)或 `"url"`(网络) |
|
|
195
|
-
| `path` | string | ✅ | 图片路径或 URL |
|
|
196
|
-
| `caption` | string | ❌ | 图片描述,会作为单独消息发送 |
|
|
197
|
-
|
|
198
|
-
> 💡 **提示**:对于简单的图片发送,推荐使用 `<qqimg>` 标签,更简洁易用。
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
## 🎯 快速参考
|
|
203
|
-
|
|
204
|
-
| 场景 | 使用方式 |
|
|
205
|
-
|------|----------|
|
|
206
|
-
| 发送本地图片 | `<qqimg>/path/to/image.jpg</qqimg>` |
|
|
207
|
-
| 发送网络图片 | `<qqimg>https://example.com/image.png</qqimg>` |
|
|
208
|
-
| 发送多张图片 | 多个 `<qqimg>` 标签 |
|
|
209
|
-
| 告知路径(不发送) | 直接写路径文本 |
|
package/src/api.ts
CHANGED
|
@@ -3,12 +3,22 @@
|
|
|
3
3
|
* [修复版] 已重构为支持多实例并发,消除全局变量冲突
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import os from "node:os";
|
|
6
8
|
import { computeFileHash, getCachedFileInfo, setCachedFileInfo } from "./utils/upload-cache.js";
|
|
7
9
|
import { sanitizeFileName } from "./utils/platform.js";
|
|
8
10
|
|
|
9
11
|
const API_BASE = "https://api.sgroup.qq.com";
|
|
10
12
|
const TOKEN_URL = "https://bots.qq.com/app/getAppAccessToken";
|
|
11
13
|
|
|
14
|
+
// ============ Plugin User-Agent ============
|
|
15
|
+
// 格式: QQBotPlugin/{version} (Node/{nodeVersion}; {os})
|
|
16
|
+
// 示例: QQBotPlugin/1.6.0 (Node/22.14.0; darwin)
|
|
17
|
+
const _require = createRequire(import.meta.url);
|
|
18
|
+
let _pluginVersion = "unknown";
|
|
19
|
+
try { _pluginVersion = _require("../package.json").version ?? "unknown"; } catch { /* fallback */ }
|
|
20
|
+
export const PLUGIN_USER_AGENT = `QQBotPlugin/${_pluginVersion} (Node/${process.versions.node}; ${os.platform()})`;
|
|
21
|
+
|
|
12
22
|
// 运行时配置
|
|
13
23
|
let currentMarkdownSupport = false;
|
|
14
24
|
|
|
@@ -105,7 +115,7 @@ export async function getAccessToken(appId: string, clientSecret: string): Promi
|
|
|
105
115
|
*/
|
|
106
116
|
async function doFetchToken(appId: string, clientSecret: string): Promise<string> {
|
|
107
117
|
const requestBody = { appId, clientSecret };
|
|
108
|
-
const requestHeaders = { "Content-Type": "application/json" };
|
|
118
|
+
const requestHeaders = { "Content-Type": "application/json", "User-Agent": PLUGIN_USER_AGENT };
|
|
109
119
|
|
|
110
120
|
// 打印请求信息(隐藏敏感信息)
|
|
111
121
|
console.log(`[qqbot-api:${appId}] >>> POST ${TOKEN_URL}`);
|
|
@@ -217,6 +227,7 @@ export async function apiRequest<T = unknown>(
|
|
|
217
227
|
const headers: Record<string, string> = {
|
|
218
228
|
Authorization: `QQBot ${accessToken}`,
|
|
219
229
|
"Content-Type": "application/json",
|
|
230
|
+
"User-Agent": PLUGIN_USER_AGENT,
|
|
220
231
|
};
|
|
221
232
|
|
|
222
233
|
const isFileUpload = path.includes("/files");
|
|
@@ -628,8 +639,8 @@ export async function sendGroupImageMessage(accessToken: string, groupOpenid: st
|
|
|
628
639
|
return sendGroupMediaMessage(accessToken, groupOpenid, uploadResult.file_info, msgId, content);
|
|
629
640
|
}
|
|
630
641
|
|
|
631
|
-
export async function sendC2CVoiceMessage(accessToken: string, openid: string, voiceBase64
|
|
632
|
-
const uploadResult = await uploadC2CMedia(accessToken, openid, MediaFileType.VOICE,
|
|
642
|
+
export async function sendC2CVoiceMessage(accessToken: string, openid: string, voiceBase64?: string, voiceUrl?: string, msgId?: string, ttsText?: string, filePath?: string): Promise<MessageResponse> {
|
|
643
|
+
const uploadResult = await uploadC2CMedia(accessToken, openid, MediaFileType.VOICE, voiceUrl, voiceBase64, false);
|
|
633
644
|
return sendC2CMediaMessage(accessToken, openid, uploadResult.file_info, msgId, undefined, {
|
|
634
645
|
mediaType: "voice",
|
|
635
646
|
...(ttsText ? { ttsText } : {}),
|
|
@@ -637,8 +648,8 @@ export async function sendC2CVoiceMessage(accessToken: string, openid: string, v
|
|
|
637
648
|
});
|
|
638
649
|
}
|
|
639
650
|
|
|
640
|
-
export async function sendGroupVoiceMessage(accessToken: string, groupOpenid: string, voiceBase64
|
|
641
|
-
const uploadResult = await uploadGroupMedia(accessToken, groupOpenid, MediaFileType.VOICE,
|
|
651
|
+
export async function sendGroupVoiceMessage(accessToken: string, groupOpenid: string, voiceBase64?: string, voiceUrl?: string, msgId?: string): Promise<{ id: string; timestamp: string }> {
|
|
652
|
+
const uploadResult = await uploadGroupMedia(accessToken, groupOpenid, MediaFileType.VOICE, voiceUrl, voiceBase64, false);
|
|
642
653
|
return sendGroupMediaMessage(accessToken, groupOpenid, uploadResult.file_info, msgId);
|
|
643
654
|
}
|
|
644
655
|
|
package/src/channel.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ChannelPlugin,
|
|
3
3
|
type OpenClawConfig,
|
|
4
|
-
type NormalizeTargetResult,
|
|
5
4
|
applyAccountNameToChannelSection,
|
|
6
5
|
deleteAccountFromConfigSection,
|
|
7
6
|
setAccountEnabledInConfigSection,
|
|
@@ -168,30 +167,30 @@ export const qqbotPlugin: ChannelPlugin<ResolvedQQBotAccount> = {
|
|
|
168
167
|
* - channel:channelid -> 频道
|
|
169
168
|
* - 纯 openid(32位十六进制)-> 私聊
|
|
170
169
|
*/
|
|
171
|
-
normalizeTarget: (target: string):
|
|
170
|
+
normalizeTarget: (target: string): string | undefined => {
|
|
172
171
|
// 去掉 qqbot: 前缀(如果有)
|
|
173
172
|
const id = target.replace(/^qqbot:/i, "");
|
|
174
173
|
|
|
175
174
|
// 检查是否是已知格式
|
|
176
175
|
if (id.startsWith("c2c:") || id.startsWith("group:") || id.startsWith("channel:")) {
|
|
177
|
-
return
|
|
176
|
+
return `qqbot:${id}`;
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
// 检查是否是纯 openid(32位十六进制,不带连字符)
|
|
181
180
|
// QQ Bot OpenID 格式类似: 207A5B8339D01F6582911C014668B77B
|
|
182
181
|
const openIdHexPattern = /^[0-9a-fA-F]{32}$/;
|
|
183
182
|
if (openIdHexPattern.test(id)) {
|
|
184
|
-
return
|
|
183
|
+
return `qqbot:c2c:${id}`;
|
|
185
184
|
}
|
|
186
185
|
|
|
187
186
|
// 检查是否是 UUID 格式的 openid(带连字符)
|
|
188
187
|
const openIdUuidPattern = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
189
188
|
if (openIdUuidPattern.test(id)) {
|
|
190
|
-
return
|
|
189
|
+
return `qqbot:c2c:${id}`;
|
|
191
190
|
}
|
|
192
191
|
|
|
193
|
-
//
|
|
194
|
-
return
|
|
192
|
+
// 不认识的格式,返回 undefined 让核心使用原始值
|
|
193
|
+
return undefined;
|
|
195
194
|
},
|
|
196
195
|
/**
|
|
197
196
|
* 目标解析器配置
|