@cxyhhhhh/openclaw-qqbot 2.0.0-dev.202607091957 → 2.0.0-dev.202607101321
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/dist/index.cjs +217 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +5 -5
- package/src/adapter/contract.ts +1 -1
- package/src/config.ts +23 -0
- package/src/dispatch/dispatch.ts +8 -6
- package/src/gateway/middleware-setup.ts +7 -1
- package/src/outbound/cron-scheduler.ts +4 -3
- package/src/types.ts +16 -0
- package/src/utils/ssrf-guard.ts +32 -2
- package/skills/qqbot-group/SKILL.md +0 -75
- package/skills/qqbot-group/references/api_reference.md +0 -94
package/dist/index.d.cts
CHANGED
|
@@ -30,6 +30,11 @@ interface ResolvedQQBotAccount {
|
|
|
30
30
|
markdownSupport: boolean;
|
|
31
31
|
/** User-Agent 尾部追加内容 */
|
|
32
32
|
userAgentSuffix: string;
|
|
33
|
+
/**
|
|
34
|
+
* 单条消息最大处理时间(ms)。超时后 concurrencyGuard 会 abort 处理链,
|
|
35
|
+
* 释放锁并排空缓冲消息。0 表示不限制。默认 0(不限制)。
|
|
36
|
+
*/
|
|
37
|
+
processingTimeoutMs: number;
|
|
33
38
|
config: QQBotAccountConfig;
|
|
34
39
|
}
|
|
35
40
|
/** 群消息策略:open=全响应 | allowlist=白名单 | disabled=不响应 */
|
|
@@ -145,6 +150,17 @@ interface QQBotAccountConfig {
|
|
|
145
150
|
* 配置后,收到语音消息时会自动调用 STT 服务转录为文字
|
|
146
151
|
*/
|
|
147
152
|
stt?: STTChannelConfig;
|
|
153
|
+
/**
|
|
154
|
+
* 单条消息最大处理时间(毫秒)。
|
|
155
|
+
* 超时后 concurrencyGuard 会 abort 处理链(取消 LLM 调用、工具执行等),
|
|
156
|
+
* 释放并发锁并排空缓冲消息。
|
|
157
|
+
*
|
|
158
|
+
* 设为 0 表示不限制超时。默认 0(不限制)。
|
|
159
|
+
*
|
|
160
|
+
* 可通过环境变量 OPENCLAW_PROCESSING_TIMEOUT_MS 覆盖全局默认值,
|
|
161
|
+
* 账户级配置优先级高于环境变量。
|
|
162
|
+
*/
|
|
163
|
+
processingTimeoutMs?: number;
|
|
148
164
|
/**
|
|
149
165
|
* User-Agent 尾部追加内容(用于私有化部署标识等场景)
|
|
150
166
|
* 追加在 `QQBotPlugin/{version} (Node/{nodeVersion}; {os}; OpenClaw/{version})` 之后
|
|
@@ -822,6 +838,12 @@ declare function resolveDefaultQQBotAccountId(cfg: OpenClawConfig): string;
|
|
|
822
838
|
* 用于私有化部署标识等场景,追加在 UA 末尾
|
|
823
839
|
*/
|
|
824
840
|
declare function resolveUserAgentSuffix(cfg: OpenClawConfig): string;
|
|
841
|
+
/**
|
|
842
|
+
* 解析单条消息处理超时时间(ms)。
|
|
843
|
+
* 优先级:账户配置 > 环境变量 OPENCLAW_PROCESSING_TIMEOUT_MS > 默认
|
|
844
|
+
* 返回 0 表示不限制超时。
|
|
845
|
+
*/
|
|
846
|
+
declare function resolveProcessingTimeoutMs(accountConfig?: QQBotAccountConfig): number;
|
|
825
847
|
/**
|
|
826
848
|
* 解析 QQBot 账户配置
|
|
827
849
|
*/
|
|
@@ -854,4 +876,4 @@ declare const plugin: {
|
|
|
854
876
|
register(api: OpenClawPluginApi): void;
|
|
855
877
|
};
|
|
856
878
|
|
|
857
|
-
export { type AudioFormatPolicy, type C2CMessageEvent, type CustomKeyboard, DEFAULT_ACCOUNT_ID, type DeliverDebounceConfig, type GroupConfig, type GroupMessageEvent, type GroupPolicy, type GuildMessageEvent, type InlineKeyboard, type InteractionEvent, type KeyboardAction, type KeyboardActionType, type KeyboardButton, type KeyboardModal, type KeyboardPermission, type KeyboardRenderData, type KeyboardRow, MSG_TYPE_QUOTE, MSG_TYPE_TEXT, type MessageAttachment, type MessageKeyboard, type MsgElement, PersistedRefIndexStore, type QQBotAccountConfig, type QQBotConfig, QQBotGateway, type ResolvedGroupConfig, type ResolvedQQBotAccount, type STTChannelConfig, StreamContentType, StreamInputMode, StreamInputState, type StreamMessageRequest, StreamingController, type ToolPolicy, type WSPayload, applyQQBotAccountConfig, buildUserAgent, plugin as default, dispatchToOpenClaw, flushAllRefIndexStores, getBotForAccount, getPersistedRefIndexStore, getQQBotRuntime, isGroupAllowed, listQQBotAccountIds, parseTarget, qqbotOnboardingAdapter, qqbotPlugin, resolveDefaultQQBotAccountId, resolveGroupAllowFrom, resolveGroupConfig, resolveGroupConfigFromAccount, resolveGroupName, resolveGroupPolicy, resolveGroupPrompt, resolveHistoryLimit, resolveIgnoreOtherMentions, resolveMentionPatterns, resolveQQBotAccount, resolveRequireMention, resolveToolPolicy, resolveUserAgentSuffix, sendMedia, sendText, setQQBotRuntime, shouldUseStreaming, tryGetBotForAccount };
|
|
879
|
+
export { type AudioFormatPolicy, type C2CMessageEvent, type CustomKeyboard, DEFAULT_ACCOUNT_ID, type DeliverDebounceConfig, type GroupConfig, type GroupMessageEvent, type GroupPolicy, type GuildMessageEvent, type InlineKeyboard, type InteractionEvent, type KeyboardAction, type KeyboardActionType, type KeyboardButton, type KeyboardModal, type KeyboardPermission, type KeyboardRenderData, type KeyboardRow, MSG_TYPE_QUOTE, MSG_TYPE_TEXT, type MessageAttachment, type MessageKeyboard, type MsgElement, PersistedRefIndexStore, type QQBotAccountConfig, type QQBotConfig, QQBotGateway, type ResolvedGroupConfig, type ResolvedQQBotAccount, type STTChannelConfig, StreamContentType, StreamInputMode, StreamInputState, type StreamMessageRequest, StreamingController, type ToolPolicy, type WSPayload, applyQQBotAccountConfig, buildUserAgent, plugin as default, dispatchToOpenClaw, flushAllRefIndexStores, getBotForAccount, getPersistedRefIndexStore, getQQBotRuntime, isGroupAllowed, listQQBotAccountIds, parseTarget, qqbotOnboardingAdapter, qqbotPlugin, resolveDefaultQQBotAccountId, resolveGroupAllowFrom, resolveGroupConfig, resolveGroupConfigFromAccount, resolveGroupName, resolveGroupPolicy, resolveGroupPrompt, resolveHistoryLimit, resolveIgnoreOtherMentions, resolveMentionPatterns, resolveProcessingTimeoutMs, resolveQQBotAccount, resolveRequireMention, resolveToolPolicy, resolveUserAgentSuffix, sendMedia, sendText, setQQBotRuntime, shouldUseStreaming, tryGetBotForAccount };
|
package/openclaw.plugin.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "QQ Bot channel plugin with message support, cron jobs, and proactive messaging",
|
|
5
5
|
"channels": ["qqbot"],
|
|
6
6
|
"extensions": ["./preload.cjs"],
|
|
7
|
-
"skills": ["skills/qqbot-channel", "skills/qqbot-
|
|
7
|
+
"skills": ["skills/qqbot-channel", "skills/qqbot-remind", "skills/qqbot-upgrade"],
|
|
8
8
|
"contracts": {
|
|
9
9
|
"tools": ["qqbot_platform_api", "qqbot_remind"]
|
|
10
10
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cxyhhhhh/openclaw-qqbot",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.202607101321",
|
|
4
4
|
"description": "QQ Bot channel plugin for OpenClaw",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
"lint:runtime": "npx tsx src/runtime-adapter/lint-runtime-access.ts"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@tencent-connect/qqbot-
|
|
45
|
-
"@tencent-connect/qqbot-
|
|
44
|
+
"@tencent-connect/qqbot-connector": "1.2.0",
|
|
45
|
+
"@tencent-connect/qqbot-nodejs": "npm:@cxyhhhhh/qqbot-nodejs@1.0.2-dev.202607101142"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@types/node": "^20.
|
|
49
|
-
"tsup": "^8.
|
|
48
|
+
"@types/node": "^20.19.43",
|
|
49
|
+
"tsup": "^8.5.1",
|
|
50
50
|
"typescript": "^5.9.3"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
package/src/adapter/contract.ts
CHANGED
|
@@ -62,7 +62,7 @@ export function verifyRuntimeContract(rt: PluginRuntime): ContractResult {
|
|
|
62
62
|
log.error(`BROKEN — missing: ${missing.join(', ')}`);
|
|
63
63
|
}
|
|
64
64
|
if (degraded.length) {
|
|
65
|
-
log.
|
|
65
|
+
log.debug(`degraded: ${degraded.join(', ')}`);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
return { ok: missing.length === 0, version, missing, degraded };
|
package/src/config.ts
CHANGED
|
@@ -79,6 +79,9 @@ const DEFAULT_GROUP_POLICY: GroupPolicy = "open";
|
|
|
79
79
|
/** 群历史缓存条数默认值 */
|
|
80
80
|
const DEFAULT_GROUP_HISTORY_LIMIT = 20;
|
|
81
81
|
|
|
82
|
+
/** 单条消息默认处理超时(0 = 不限制) */
|
|
83
|
+
const DEFAULT_PROCESSING_TIMEOUT_MS = 0;
|
|
84
|
+
|
|
82
85
|
const DEFAULT_GROUP_CONFIG: Omit<Required<GroupConfig>, "prompt"> = {
|
|
83
86
|
requireMention: true,
|
|
84
87
|
ignoreOtherMentions: false,
|
|
@@ -229,6 +232,25 @@ export function resolveUserAgentSuffix(cfg: OpenClawConfig): string {
|
|
|
229
232
|
return qqbot?.userAgentSuffix ? String(qqbot.userAgentSuffix).trim() : '';
|
|
230
233
|
}
|
|
231
234
|
|
|
235
|
+
/**
|
|
236
|
+
* 解析单条消息处理超时时间(ms)。
|
|
237
|
+
* 优先级:账户配置 > 环境变量 OPENCLAW_PROCESSING_TIMEOUT_MS > 默认
|
|
238
|
+
* 返回 0 表示不限制超时。
|
|
239
|
+
*/
|
|
240
|
+
export function resolveProcessingTimeoutMs(
|
|
241
|
+
accountConfig?: QQBotAccountConfig,
|
|
242
|
+
): number {
|
|
243
|
+
if (accountConfig?.processingTimeoutMs !== undefined) {
|
|
244
|
+
return accountConfig.processingTimeoutMs;
|
|
245
|
+
}
|
|
246
|
+
const env = process.env.OPENCLAW_PROCESSING_TIMEOUT_MS;
|
|
247
|
+
if (env) {
|
|
248
|
+
const v = Number(env);
|
|
249
|
+
if (!Number.isNaN(v) && v >= 0) return v;
|
|
250
|
+
}
|
|
251
|
+
return DEFAULT_PROCESSING_TIMEOUT_MS;
|
|
252
|
+
}
|
|
253
|
+
|
|
232
254
|
/**
|
|
233
255
|
* 解析 QQBot 账户配置
|
|
234
256
|
*/
|
|
@@ -287,6 +309,7 @@ export function resolveQQBotAccount(
|
|
|
287
309
|
systemPrompt: accountConfig.systemPrompt,
|
|
288
310
|
markdownSupport: accountConfig.markdownSupport !== false,
|
|
289
311
|
userAgentSuffix: resolveUserAgentSuffix(cfg),
|
|
312
|
+
processingTimeoutMs: resolveProcessingTimeoutMs(accountConfig),
|
|
290
313
|
config: accountConfig,
|
|
291
314
|
};
|
|
292
315
|
}
|
package/src/dispatch/dispatch.ts
CHANGED
|
@@ -137,15 +137,16 @@ export async function dispatchToOpenClaw(
|
|
|
137
137
|
await deliverReply(payload, info, deliverCtx);
|
|
138
138
|
},
|
|
139
139
|
},
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
replyOptions: {
|
|
141
|
+
abortSignal: ctx.signal,
|
|
142
|
+
...(streamingController
|
|
143
|
+
? {
|
|
143
144
|
onPartialReply: async (p: { text?: string }) => {
|
|
144
145
|
if (p.text) await streamingController.onPartialReply(p.text);
|
|
145
146
|
},
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
147
|
+
}
|
|
148
|
+
: {}),
|
|
149
|
+
},
|
|
149
150
|
});
|
|
150
151
|
if (streamingController && !streamingController.isTerminal) {
|
|
151
152
|
await streamingController.finalize();
|
|
@@ -272,6 +273,7 @@ export async function dispatchToOpenClaw(
|
|
|
272
273
|
},
|
|
273
274
|
},
|
|
274
275
|
replyOptions: {
|
|
276
|
+
abortSignal: ctx.signal,
|
|
275
277
|
runId: envelope.messageId,
|
|
276
278
|
...(streamingController
|
|
277
279
|
? {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 中间件负责过滤和上下文富化;concurrencyGuard 负责串行+合并,
|
|
6
6
|
* 合并后的消息继续走完剩余中间件链,最终统一由 bot.on("message") 处理转发。
|
|
7
7
|
*/
|
|
8
|
-
import type { QQBot } from '@tencent-connect/qqbot-nodejs';
|
|
8
|
+
import type { QQBot, MiddlewareContext } from '@tencent-connect/qqbot-nodejs';
|
|
9
9
|
import {
|
|
10
10
|
messageFilter,
|
|
11
11
|
contentSanitizer,
|
|
@@ -78,9 +78,15 @@ export function setupMiddlewares(bot: QQBot, account: ResolvedQQBotAccount, opts
|
|
|
78
78
|
// - 处理中消息暂存 buffer;完成后合并为一条,继续走完剩余中间件链
|
|
79
79
|
// (typingIndicator/quoteRef/attachmentProcessor/... 直到 bot.on("message"))
|
|
80
80
|
// - 合并时清除 assembledBody 让 dispatch.ts 用合并后 content 重建
|
|
81
|
+
// - 超时后 abort 处理链(取消 LLM 调用),释放锁并排空缓冲
|
|
81
82
|
bot.use(concurrencyGuard({
|
|
82
83
|
strategy: 'merge',
|
|
83
84
|
maxQueue: 50,
|
|
85
|
+
maxProcessingMs: account.processingTimeoutMs,
|
|
86
|
+
/** 紧急指令(/stop)跳过排队,立即处理 */
|
|
87
|
+
urgentPredicate: (ctx: MiddlewareContext) => {
|
|
88
|
+
return (ctx.message.content as string ?? '').trim() === '/stop';
|
|
89
|
+
},
|
|
84
90
|
onMerge: (buffered) => {
|
|
85
91
|
const last = buffered[buffered.length - 1];
|
|
86
92
|
if (buffered.length === 1) return last;
|
|
@@ -46,10 +46,11 @@ export class CronScheduler {
|
|
|
46
46
|
const target = payload.target ?? defaultTarget;
|
|
47
47
|
const triggerAt = resolveTriggerTime(payload.at);
|
|
48
48
|
const delayMs = Math.max(0, triggerAt - Date.now());
|
|
49
|
+
const text = payload.text?.trim() ?? '定时提醒';
|
|
49
50
|
|
|
50
51
|
const reminder: ScheduledReminder = {
|
|
51
52
|
id,
|
|
52
|
-
text
|
|
53
|
+
text,
|
|
53
54
|
target,
|
|
54
55
|
triggerAt,
|
|
55
56
|
};
|
|
@@ -60,7 +61,7 @@ export class CronScheduler {
|
|
|
60
61
|
reminder.timer = setTimeout(async () => {
|
|
61
62
|
this.reminders.delete(id);
|
|
62
63
|
try {
|
|
63
|
-
await this.send(target, `⏰ ${
|
|
64
|
+
await this.send(target, `⏰ ${text}`);
|
|
64
65
|
} catch { /* swallow */ }
|
|
65
66
|
}, delayMs);
|
|
66
67
|
}
|
|
@@ -68,7 +69,7 @@ export class CronScheduler {
|
|
|
68
69
|
this.reminders.set(id, reminder);
|
|
69
70
|
|
|
70
71
|
const when = new Date(triggerAt);
|
|
71
|
-
const confirmText = `✅ Reminder scheduled for ${when.toLocaleString()}: "${
|
|
72
|
+
const confirmText = `✅ Reminder scheduled for ${when.toLocaleString()}: "${text}"`;
|
|
72
73
|
return { id, triggerAt, confirmText };
|
|
73
74
|
}
|
|
74
75
|
|
package/src/types.ts
CHANGED
|
@@ -29,6 +29,11 @@ export interface ResolvedQQBotAccount {
|
|
|
29
29
|
markdownSupport: boolean;
|
|
30
30
|
/** User-Agent 尾部追加内容 */
|
|
31
31
|
userAgentSuffix: string;
|
|
32
|
+
/**
|
|
33
|
+
* 单条消息最大处理时间(ms)。超时后 concurrencyGuard 会 abort 处理链,
|
|
34
|
+
* 释放锁并排空缓冲消息。0 表示不限制。默认 0(不限制)。
|
|
35
|
+
*/
|
|
36
|
+
processingTimeoutMs: number;
|
|
32
37
|
config: QQBotAccountConfig;
|
|
33
38
|
}
|
|
34
39
|
|
|
@@ -148,6 +153,17 @@ export interface QQBotAccountConfig {
|
|
|
148
153
|
* 配置后,收到语音消息时会自动调用 STT 服务转录为文字
|
|
149
154
|
*/
|
|
150
155
|
stt?: STTChannelConfig;
|
|
156
|
+
/**
|
|
157
|
+
* 单条消息最大处理时间(毫秒)。
|
|
158
|
+
* 超时后 concurrencyGuard 会 abort 处理链(取消 LLM 调用、工具执行等),
|
|
159
|
+
* 释放并发锁并排空缓冲消息。
|
|
160
|
+
*
|
|
161
|
+
* 设为 0 表示不限制超时。默认 0(不限制)。
|
|
162
|
+
*
|
|
163
|
+
* 可通过环境变量 OPENCLAW_PROCESSING_TIMEOUT_MS 覆盖全局默认值,
|
|
164
|
+
* 账户级配置优先级高于环境变量。
|
|
165
|
+
*/
|
|
166
|
+
processingTimeoutMs?: number;
|
|
151
167
|
/**
|
|
152
168
|
* User-Agent 尾部追加内容(用于私有化部署标识等场景)
|
|
153
169
|
* 追加在 `QQBotPlugin/{version} (Node/{nodeVersion}; {os}; OpenClaw/{version})` 之后
|
package/src/utils/ssrf-guard.ts
CHANGED
|
@@ -48,13 +48,40 @@ export function isReservedAddr(ip: string): boolean {
|
|
|
48
48
|
|
|
49
49
|
const ALLOWED_SCHEMES = new Set(["http:", "https:"]);
|
|
50
50
|
|
|
51
|
+
/** QQ 官方媒体/API 域名白名单,匹配时跳过 DNS 解析检查 */
|
|
52
|
+
const QQ_TRUSTED_DOMAINS = new Set([
|
|
53
|
+
// QQ Bot API
|
|
54
|
+
"api.sgroup.qq.com",
|
|
55
|
+
"sandbox.api.sgroup.qq.com",
|
|
56
|
+
// QQ Bot Token
|
|
57
|
+
"bots.qq.com",
|
|
58
|
+
// QQ 多媒体上传/下载
|
|
59
|
+
"multimedia.nt.qq.com.cn",
|
|
60
|
+
"multimedia.nt.qq.com",
|
|
61
|
+
// QQ 群文件
|
|
62
|
+
"grouppro.grouppro.qq.com",
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
/** 检查 hostname 是否匹配 QQ 白名单(支持子域名通配 *.example.com) */
|
|
66
|
+
function isQQTrustedDomain(hostname: string): boolean {
|
|
67
|
+
if (QQ_TRUSTED_DOMAINS.has(hostname)) return true;
|
|
68
|
+
// 检查一级子域名:*.multimedia.nt.qq.com.cn
|
|
69
|
+
const dot = hostname.indexOf('.');
|
|
70
|
+
if (dot > 0) {
|
|
71
|
+
const parent = hostname.slice(dot + 1);
|
|
72
|
+
return QQ_TRUSTED_DOMAINS.has(parent);
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
51
77
|
/**
|
|
52
78
|
* 校验远程 URL 是否可安全请求。
|
|
53
79
|
*
|
|
54
80
|
* 规则:
|
|
55
81
|
* 1. 仅放行 http / https 协议
|
|
56
|
-
* 2.
|
|
57
|
-
* 3.
|
|
82
|
+
* 2. QQ 白名单域名直接放行(免 DNS 解析)
|
|
83
|
+
* 3. 若 URL 直接携带 IP 则即时判定
|
|
84
|
+
* 4. 若为域名则先做 DNS 解析,逐条检查解析结果
|
|
58
85
|
*
|
|
59
86
|
* @throws {Error} 当 URL 指向受限地址时
|
|
60
87
|
*/
|
|
@@ -70,6 +97,9 @@ export async function validateRemoteUrl(raw: string): Promise<void> {
|
|
|
70
97
|
// 去掉 IPv6 方括号
|
|
71
98
|
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
72
99
|
|
|
100
|
+
// QQ 官方域名 → 免 DNS 检查直接放行
|
|
101
|
+
if (isQQTrustedDomain(host)) return;
|
|
102
|
+
|
|
73
103
|
if (net.isIP(host)) {
|
|
74
104
|
assertPublicAddr(host, raw);
|
|
75
105
|
return;
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: qqbot-group
|
|
3
|
-
description: QQ 群管理技能。查询群基础信息、群成员信息、机器人群内状态。使用 qqbot_platform_api 工具调用接口,自动鉴权。当用户需要查询群信息、查看群成员、检查机器人群内状态时使用此技能。
|
|
4
|
-
metadata: {"openclaw":{"emoji":"👥","requires":{"config":["channels.qqbot"]}}}
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# QQ 群 API 请求指导
|
|
8
|
-
|
|
9
|
-
通过 `qqbot_platform_api` 工具调用群相关接口,鉴权由工具自动处理。
|
|
10
|
-
|
|
11
|
-
详细字段说明见 `references/api_reference.md`。
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## ⭐ 接口速查
|
|
16
|
-
|
|
17
|
-
| 操作 | 方法 | 路径 |
|
|
18
|
-
|------|------|------|
|
|
19
|
-
| 获取机器人群内状态 | `GET` | `/v2/groups/{group_id}/bot_state` |
|
|
20
|
-
| 获取群成员信息 | `GET` | `/v2/groups/{group_id}/members/{member_id}` |
|
|
21
|
-
| 获取群基础信息 | `GET` | `/v2/groups/{group_id}/info` |
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## 💡 调用示例
|
|
26
|
-
|
|
27
|
-
### 获取机器人群内状态
|
|
28
|
-
|
|
29
|
-
```json
|
|
30
|
-
{
|
|
31
|
-
"method": "GET",
|
|
32
|
-
"path": "/v2/groups/G_123456789/bot_state"
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
返回字段:`joined_at`(入群时间)、`allow_proactive_msg`(是否允许主动推送)、`recv_msg_setting`(`all`/`only_mention`/`mention_and_context`)、`member_role`(`member`/`owner`/`admin`)。
|
|
37
|
-
|
|
38
|
-
### 获取群成员信息
|
|
39
|
-
|
|
40
|
-
```json
|
|
41
|
-
{
|
|
42
|
-
"method": "GET",
|
|
43
|
-
"path": "/v2/groups/G_123456789/members/o_xxxxxxxx"
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
返回字段:`username`(昵称)、`member_role`、`joined_at`、`bot` 等。昵称仅在单个查询时返回。
|
|
48
|
-
|
|
49
|
-
### 获取群基础信息
|
|
50
|
-
|
|
51
|
-
```json
|
|
52
|
-
{
|
|
53
|
-
"method": "GET",
|
|
54
|
-
"path": "/v2/groups/G_123456789/info"
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
返回字段:`group_name`、`group_finger_memo`(简介)、`group_class_text`(分类)、`group_tags`(标签)、`group_member_num`(成员数)。
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## 💬 @群成员
|
|
63
|
-
|
|
64
|
-
发送消息时使用 `<@member_id>` 语法 @指定群成员:
|
|
65
|
-
|
|
66
|
-
- 格式:`<@member_id>`,例如 `<@o_xxxxxxxx>`
|
|
67
|
-
- 文本消息中直接拼接即可:`你好 <@o_xxxxxxxx>,欢迎入群!`
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## ⚠️ 注意事项
|
|
72
|
-
|
|
73
|
-
1. 路径占位符 `{group_id}`、`{member_id}` 需替换为实际值
|
|
74
|
-
2. 返回时间格式为 RFC3339(如 `2026-06-23T22:03:09+08:00`)
|
|
75
|
-
3. 群 openid 与频道 guild_id 是不同的概念,不要混淆
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# QQ 开放平台群接口参考
|
|
2
|
-
|
|
3
|
-
> 鉴权和请求头由 `qqbot_platform_api` 工具自动处理,无需手动管理。
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 接口列表
|
|
8
|
-
|
|
9
|
-
### 1. 获取机器人群内状态
|
|
10
|
-
|
|
11
|
-
- 方法:`GET`
|
|
12
|
-
- 路径:`/v2/groups/{group_id}/bot_state`
|
|
13
|
-
|
|
14
|
-
响应参数:
|
|
15
|
-
|
|
16
|
-
| 字段 | 类型 | 说明 |
|
|
17
|
-
|------|------|------|
|
|
18
|
-
| joined_at | string | 入群时间(RFC3339 格式) |
|
|
19
|
-
| allow_proactive_msg | bool | 是否允许主动消息推送 |
|
|
20
|
-
| recv_msg_setting | string | 接收消息设置:`all`、`only_mention`、`mention_and_context` |
|
|
21
|
-
| member_role | string | 群成员角色:`member`、`owner`、`admin` |
|
|
22
|
-
|
|
23
|
-
响应示例:
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{
|
|
27
|
-
"join_timestamp": "2026-06-23T22:03:09+08:00",
|
|
28
|
-
"allow_proactive_msg": true,
|
|
29
|
-
"recv_msg_setting": "all",
|
|
30
|
-
"member_role": "admin"
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
### 2. 获取群成员信息
|
|
37
|
-
|
|
38
|
-
- 方法:`GET`
|
|
39
|
-
- 路径:`/v2/groups/{group_id}/members/{member_id}`
|
|
40
|
-
|
|
41
|
-
响应参数:
|
|
42
|
-
|
|
43
|
-
| 字段 | 类型 | 说明 |
|
|
44
|
-
|------|------|------|
|
|
45
|
-
| union_openid | string | 用户在应用/开放平台下的统一标识 |
|
|
46
|
-
| user_openid | string | 用户 openid |
|
|
47
|
-
| username | string | 用户昵称(仅单个查询时返回) |
|
|
48
|
-
| member_role | string | 群成员角色:`member`、`owner`、`admin` |
|
|
49
|
-
| joined_at | string | 入群时间(RFC3339 格式) |
|
|
50
|
-
| bot | bool | 是否为机器人账号 |
|
|
51
|
-
|
|
52
|
-
响应示例:
|
|
53
|
-
|
|
54
|
-
```json
|
|
55
|
-
{
|
|
56
|
-
"union_openid": "u_xxxxxxxx",
|
|
57
|
-
"user_openid": "o_xxxxxxxx",
|
|
58
|
-
"username": "张三",
|
|
59
|
-
"member_role": "member",
|
|
60
|
-
"joined_at": "2026-06-23T22:03:09+08:00",
|
|
61
|
-
"bot": false
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
### 3. 获取群基础信息
|
|
68
|
-
|
|
69
|
-
- 方法:`GET`
|
|
70
|
-
- 路径:`/v2/groups/{group_id}/info`
|
|
71
|
-
|
|
72
|
-
响应参数:
|
|
73
|
-
|
|
74
|
-
| 字段 | 类型 | 说明 |
|
|
75
|
-
|------|------|------|
|
|
76
|
-
| group_openid | string | 群 openid |
|
|
77
|
-
| group_name | string | 群名称 |
|
|
78
|
-
| group_finger_memo | string | 群简介/群公告 |
|
|
79
|
-
| group_class_text | string | 群分类文案 |
|
|
80
|
-
| group_tags | array[] | 群标签列表 |
|
|
81
|
-
| group_member_num | int | 群成员数量 |
|
|
82
|
-
|
|
83
|
-
响应示例:
|
|
84
|
-
|
|
85
|
-
```json
|
|
86
|
-
{
|
|
87
|
-
"group_openid": "G_123456789",
|
|
88
|
-
"group_name": "技术交流群",
|
|
89
|
-
"group_finger_memo": "专注于后端技术开发交流",
|
|
90
|
-
"group_class_text": "技术-后端开发",
|
|
91
|
-
"group_tags": ["技术交流", "后端开发", "QQ机器人"],
|
|
92
|
-
"group_member_num": 1250
|
|
93
|
-
}
|
|
94
|
-
```
|