@zhin.js/adapter-qq 1.1.16 → 1.1.18
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 +62 -0
- package/README.md +56 -5
- package/adapters/qq/index.js +7 -2
- package/adapters/qq/index.ts +7 -2
- package/agents/qq/boundaries.md +2 -0
- package/agents/qq/conversation.js +92 -0
- package/agents/qq/conversation.ts +99 -0
- package/agents/qq/messages.js +60 -0
- package/agents/qq/messages.ts +60 -0
- package/agents/qq/skills/qq/SKILL.md +8 -2
- package/agents/qq/skills/qq/tools/guild_kick_member/index.js +30 -0
- package/agents/qq/skills/qq/tools/guild_kick_member/index.ts +29 -0
- package/agents/qq/skills/qq/tools/guild_mute_member/index.js +31 -0
- package/agents/qq/skills/qq/tools/guild_mute_member/index.ts +30 -0
- package/agents/qq/skills/qq-conversation/SKILL.md +24 -0
- package/agents/qq/skills/qq-conversation/tools/conversation_info/index.js +78 -0
- package/agents/qq/skills/qq-conversation/tools/conversation_info/index.ts +76 -0
- package/agents/qq/skills/qq-group-admin/SKILL.md +34 -0
- package/agents/qq/skills/qq-group-admin/tools/group_kick/index.js +39 -0
- package/agents/qq/skills/qq-group-admin/tools/group_kick/index.ts +38 -0
- package/agents/qq/skills/qq-group-admin/tools/handle_join_request/index.js +33 -0
- package/agents/qq/skills/qq-group-admin/tools/handle_join_request/index.ts +32 -0
- package/agents/qq/skills/qq-group-admin/tools/recall_member_message/index.js +25 -0
- package/agents/qq/skills/qq-group-admin/tools/recall_member_message/index.ts +25 -0
- package/agents/qq/skills/qq-group-admin/tools/set_mute/index.js +37 -0
- package/agents/qq/skills/qq-group-admin/tools/set_mute/index.ts +36 -0
- package/agents/qq/skills/qq-group-directory/SKILL.md +24 -0
- package/agents/qq/skills/qq-group-directory/tools/group_info/index.js +16 -0
- package/agents/qq/skills/qq-group-directory/tools/group_info/index.ts +16 -0
- package/agents/qq/skills/qq-group-directory/tools/group_member_info/index.js +19 -0
- package/agents/qq/skills/qq-group-directory/tools/group_member_info/index.ts +19 -0
- package/agents/qq/skills/qq-group-directory/tools/group_members/index.js +19 -0
- package/agents/qq/skills/qq-group-directory/tools/group_members/index.ts +19 -0
- package/agents/qq/skills/qq-group-state/SKILL.md +21 -0
- package/agents/qq/skills/qq-group-state/tools/group_blacklist/index.js +19 -0
- package/agents/qq/skills/qq-group-state/tools/group_blacklist/index.ts +19 -0
- package/agents/qq/skills/qq-group-state/tools/list_join_requests/index.js +19 -0
- package/agents/qq/skills/qq-group-state/tools/list_join_requests/index.ts +19 -0
- package/agents/qq/skills/qq-group-state/tools/list_muted/index.js +21 -0
- package/agents/qq/skills/qq-group-state/tools/list_muted/index.ts +21 -0
- package/agents/qq/skills/qq-messages/SKILL.md +27 -0
- package/agents/qq/skills/qq-messages/tools/quote_reply/index.js +21 -0
- package/agents/qq/skills/qq-messages/tools/quote_reply/index.ts +21 -0
- package/agents/qq/skills/qq-messages/tools/recall_own_message/index.js +18 -0
- package/agents/qq/skills/qq-messages/tools/recall_own_message/index.ts +17 -0
- package/commands/qq/endpoint/definition.js +35 -22
- package/commands/qq/endpoint/definition.ts +37 -22
- package/lib/console.d.ts +8 -0
- package/lib/console.js +84 -0
- package/lib/endpoint.d.ts +10 -1
- package/lib/endpoint.js +134 -8
- package/lib/group-admin.d.ts +36 -0
- package/lib/group-admin.js +113 -0
- package/lib/protocol.d.ts +5 -0
- package/lib/protocol.js +4 -0
- package/lib/qq-console-spec.d.ts +17 -0
- package/lib/qq-console-spec.js +10 -0
- package/lib/qq-console.d.ts +11 -0
- package/lib/qq-console.js +116 -0
- package/lib/qq-endpoint-write.d.ts +22 -0
- package/lib/qq-endpoint-write.js +34 -0
- package/lib/qq-runtime-state.d.ts +19 -0
- package/lib/qq-runtime-state.js +1 -0
- package/package.json +19 -11
- package/pages/index/index.js +15 -0
- package/pages/index/index.ts +16 -0
- package/plugin.js +5 -2
- package/schema.json +174 -0
- package/src/console.ts +96 -0
- package/src/endpoint.ts +137 -8
- package/src/group-admin.ts +153 -0
- package/src/protocol.ts +8 -0
- package/src/qq-console-spec.ts +18 -0
- package/src/qq-console.ts +124 -0
- package/src/qq-endpoint-write.ts +52 -0
- package/src/qq-runtime-state.ts +21 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { platformPermission } from '@zhin.js/permission';
|
|
5
|
+
import { currentGuildChannel } from '../../../../conversation.js';
|
|
6
|
+
import { messages as t } from '../../../../messages.js';
|
|
7
|
+
export default defineAgentTool({
|
|
8
|
+
description: '禁言 / 解除禁言当前 QQ 频道中的成员;需机器人具备频道管理权限',
|
|
9
|
+
adapter: 'qq',
|
|
10
|
+
scopes: ['channel'],
|
|
11
|
+
tags: ['qq'],
|
|
12
|
+
permissions: [platformPermission('qq', 'guild_admin')],
|
|
13
|
+
requiresApproval: 'always',
|
|
14
|
+
risk: 'dangerous',
|
|
15
|
+
riskCategory: 'member',
|
|
16
|
+
inputSchema: z.object({
|
|
17
|
+
user_id: z.string().min(1).describe('目标成员用户 ID'),
|
|
18
|
+
duration: z.number().int().min(0).default(0).describe('禁言秒数,0 = 解除禁言'),
|
|
19
|
+
}),
|
|
20
|
+
async execute({ user_id, duration }, context) {
|
|
21
|
+
const { guildId } = currentGuildChannel(context);
|
|
22
|
+
const members = context.$client.api.memberService;
|
|
23
|
+
const seconds = duration ?? 0;
|
|
24
|
+
const ok = seconds === 0
|
|
25
|
+
? await members.unmuteGuildMember(guildId, user_id)
|
|
26
|
+
: await members.muteGuildMember(guildId, user_id, seconds);
|
|
27
|
+
if (ok === false)
|
|
28
|
+
return { success: false, message: t(context.locale, 'operationFailed') };
|
|
29
|
+
return { success: true, message: seconds === 0 ? t(context.locale, 'unmuted', { user: user_id }) : t(context.locale, 'muted', { user: user_id, seconds }) };
|
|
30
|
+
},
|
|
31
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { platformPermission } from '@zhin.js/permission';
|
|
4
|
+
import { currentGuildChannel } from '../../../../conversation.js';
|
|
5
|
+
import { messages as t } from '../../../../messages.js';
|
|
6
|
+
|
|
7
|
+
export default defineAgentTool({
|
|
8
|
+
description: '禁言 / 解除禁言当前 QQ 频道中的成员;需机器人具备频道管理权限',
|
|
9
|
+
adapter: 'qq',
|
|
10
|
+
scopes: ['channel'],
|
|
11
|
+
tags: ['qq'],
|
|
12
|
+
permissions: [platformPermission('qq', 'guild_admin')],
|
|
13
|
+
requiresApproval: 'always',
|
|
14
|
+
risk: 'dangerous',
|
|
15
|
+
riskCategory: 'member',
|
|
16
|
+
inputSchema: z.object({
|
|
17
|
+
user_id: z.string().min(1).describe('目标成员用户 ID'),
|
|
18
|
+
duration: z.number().int().min(0).default(0).describe('禁言秒数,0 = 解除禁言'),
|
|
19
|
+
}),
|
|
20
|
+
async execute({ user_id, duration }, context) {
|
|
21
|
+
const { guildId } = currentGuildChannel(context);
|
|
22
|
+
const members = context.$client.api.memberService;
|
|
23
|
+
const seconds = duration ?? 0;
|
|
24
|
+
const ok = seconds === 0
|
|
25
|
+
? await members.unmuteGuildMember(guildId, user_id)
|
|
26
|
+
: await members.muteGuildMember(guildId, user_id, seconds);
|
|
27
|
+
if (ok === false) return { success: false, message: t(context.locale, 'operationFailed') };
|
|
28
|
+
return { success: true, message: seconds === 0 ? t(context.locale, 'unmuted', { user: user_id }) : t(context.locale, 'muted', { user: user_id, seconds }) };
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qq-conversation
|
|
3
|
+
platforms:
|
|
4
|
+
- qq
|
|
5
|
+
description: 查询当前 QQ 群或频道信息、机器人自身身份(群主/管理员/成员)以及当前会话支持的操作和官方限制。
|
|
6
|
+
keywords:
|
|
7
|
+
- 当前群
|
|
8
|
+
- 当前频道
|
|
9
|
+
- 你是管理员吗
|
|
10
|
+
- 群主
|
|
11
|
+
- 机器人权限
|
|
12
|
+
- 身份
|
|
13
|
+
tools:
|
|
14
|
+
- conversation_info
|
|
15
|
+
---
|
|
16
|
+
# qq-conversation
|
|
17
|
+
|
|
18
|
+
Use `conversation_info` before claiming the bot's role or available platform permissions. Group roles come live from the official `bot_state` API for the current endpoint, not from the sender's role. A failed lookup is not evidence that the bot is an ordinary member.
|
|
19
|
+
|
|
20
|
+
Caller roles authorize a request; bot platform roles determine whether QQ can execute it. They are independent, and a successful inspection does not replace the live check each management tool performs.
|
|
21
|
+
|
|
22
|
+
In guilds the bot role is read from its guild member record (4 owner, 2 admin, 5 child-channel admin). A `channel_admin` record does not say which child channels it governs, so it cannot authorize an operation in the current channel.
|
|
23
|
+
|
|
24
|
+
The official QQ Bot API has no merged forward, poke, profile like, leave group, group announcement, essence, special title, anonymous, group files or group sign-in. Do not promise or simulate them.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { currentConversation } from '../../../../conversation.js';
|
|
5
|
+
/** Guild built-in role ids: 4 = owner, 2 = super admin, 5 = child-channel admin. */
|
|
6
|
+
function guildRole(roles) {
|
|
7
|
+
const ids = (roles ?? []).map(String);
|
|
8
|
+
if (ids.includes('4'))
|
|
9
|
+
return 'owner';
|
|
10
|
+
if (ids.includes('2'))
|
|
11
|
+
return 'admin';
|
|
12
|
+
if (ids.includes('5'))
|
|
13
|
+
return 'channel_admin';
|
|
14
|
+
return ids.length ? 'member' : 'unknown';
|
|
15
|
+
}
|
|
16
|
+
export default defineAgentTool({
|
|
17
|
+
description: '读取当前 QQ 官方机器人会话及机器人自己的群/频道身份;区分调用者权限、机器人平台权限和官方不支持的操作',
|
|
18
|
+
adapter: 'qq',
|
|
19
|
+
requiresApproval: 'never',
|
|
20
|
+
readOnly: true,
|
|
21
|
+
inputSchema: z.object({}),
|
|
22
|
+
async execute(_input, context) {
|
|
23
|
+
const conversation = currentConversation(context);
|
|
24
|
+
const roles = context.principal.roles;
|
|
25
|
+
const common = {
|
|
26
|
+
conversation,
|
|
27
|
+
requester: {
|
|
28
|
+
roles,
|
|
29
|
+
canRequestGroupModeration: roles.some(role => ['master', 'admin', 'trusted', 'owner'].includes(role)),
|
|
30
|
+
},
|
|
31
|
+
operations: {
|
|
32
|
+
quoteReply: true,
|
|
33
|
+
recallOwnMessage: true,
|
|
34
|
+
recallMemberMessage: conversation.kind === 'group' || conversation.kind === 'channel',
|
|
35
|
+
reaction: conversation.kind === 'channel',
|
|
36
|
+
// 官方 API 不提供:合并转发、戳一戳、点赞、退群、群公告、精华、头衔、匿名、群文件、群签到。
|
|
37
|
+
forwardMessages: false,
|
|
38
|
+
leaveGroup: false,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
const api = context.$client.api;
|
|
42
|
+
if (conversation.kind === 'group') {
|
|
43
|
+
const [state, info] = await Promise.all([
|
|
44
|
+
api.groupService.getBotState(conversation.id),
|
|
45
|
+
api.groupService.getInfo(conversation.id).catch(() => undefined),
|
|
46
|
+
]);
|
|
47
|
+
context.signal.throwIfAborted();
|
|
48
|
+
const role = state.member_role;
|
|
49
|
+
return {
|
|
50
|
+
...common,
|
|
51
|
+
group: { id: conversation.id, name: info?.group_name, memberCount: info?.group_member_num },
|
|
52
|
+
bot: {
|
|
53
|
+
id: state.member_openid,
|
|
54
|
+
role,
|
|
55
|
+
canModerateMembers: role === 'owner' || role === 'admin',
|
|
56
|
+
allowProactiveMessage: state.allow_proactive_msg,
|
|
57
|
+
receiveSetting: state.recv_msg_setting,
|
|
58
|
+
joinedAt: state.joined_at,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (conversation.kind === 'channel' && conversation.parent?.kind === 'channel') {
|
|
63
|
+
const guildId = conversation.parent.id;
|
|
64
|
+
const self = await api.botService.getSelfInfo();
|
|
65
|
+
const member = self?.id
|
|
66
|
+
? await api.memberService.getGuildMemberInfo(guildId, String(self.id)).catch(() => undefined)
|
|
67
|
+
: undefined;
|
|
68
|
+
context.signal.throwIfAborted();
|
|
69
|
+
return {
|
|
70
|
+
...common,
|
|
71
|
+
guild: { id: guildId },
|
|
72
|
+
channel: { id: conversation.id },
|
|
73
|
+
bot: { id: self?.id, role: guildRole(member?.roles), channelAdminScope: 'unknown' },
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return { ...common, bot: { role: 'not_applicable' } };
|
|
77
|
+
},
|
|
78
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { currentConversation } from '../../../../conversation.js';
|
|
4
|
+
|
|
5
|
+
/** Guild built-in role ids: 4 = owner, 2 = super admin, 5 = child-channel admin. */
|
|
6
|
+
function guildRole(roles: readonly unknown[] | undefined): string {
|
|
7
|
+
const ids = (roles ?? []).map(String);
|
|
8
|
+
if (ids.includes('4')) return 'owner';
|
|
9
|
+
if (ids.includes('2')) return 'admin';
|
|
10
|
+
if (ids.includes('5')) return 'channel_admin';
|
|
11
|
+
return ids.length ? 'member' : 'unknown';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default defineAgentTool({
|
|
15
|
+
description: '读取当前 QQ 官方机器人会话及机器人自己的群/频道身份;区分调用者权限、机器人平台权限和官方不支持的操作',
|
|
16
|
+
adapter: 'qq',
|
|
17
|
+
requiresApproval: 'never',
|
|
18
|
+
readOnly: true,
|
|
19
|
+
inputSchema: z.object({}),
|
|
20
|
+
async execute(_input, context) {
|
|
21
|
+
const conversation = currentConversation(context);
|
|
22
|
+
const roles = context.principal.roles;
|
|
23
|
+
const common = {
|
|
24
|
+
conversation,
|
|
25
|
+
requester: {
|
|
26
|
+
roles,
|
|
27
|
+
canRequestGroupModeration: roles.some(role => ['master', 'admin', 'trusted', 'owner'].includes(role)),
|
|
28
|
+
},
|
|
29
|
+
operations: {
|
|
30
|
+
quoteReply: true,
|
|
31
|
+
recallOwnMessage: true,
|
|
32
|
+
recallMemberMessage: conversation.kind === 'group' || conversation.kind === 'channel',
|
|
33
|
+
reaction: conversation.kind === 'channel',
|
|
34
|
+
// 官方 API 不提供:合并转发、戳一戳、点赞、退群、群公告、精华、头衔、匿名、群文件、群签到。
|
|
35
|
+
forwardMessages: false,
|
|
36
|
+
leaveGroup: false,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
const api = context.$client.api;
|
|
40
|
+
if (conversation.kind === 'group') {
|
|
41
|
+
const [state, info] = await Promise.all([
|
|
42
|
+
api.groupService.getBotState(conversation.id),
|
|
43
|
+
api.groupService.getInfo(conversation.id).catch(() => undefined),
|
|
44
|
+
]);
|
|
45
|
+
context.signal.throwIfAborted();
|
|
46
|
+
const role = state.member_role;
|
|
47
|
+
return {
|
|
48
|
+
...common,
|
|
49
|
+
group: { id: conversation.id, name: info?.group_name, memberCount: info?.group_member_num },
|
|
50
|
+
bot: {
|
|
51
|
+
id: state.member_openid,
|
|
52
|
+
role,
|
|
53
|
+
canModerateMembers: role === 'owner' || role === 'admin',
|
|
54
|
+
allowProactiveMessage: state.allow_proactive_msg,
|
|
55
|
+
receiveSetting: state.recv_msg_setting,
|
|
56
|
+
joinedAt: state.joined_at,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (conversation.kind === 'channel' && conversation.parent?.kind === 'channel') {
|
|
61
|
+
const guildId = conversation.parent.id;
|
|
62
|
+
const self = await api.botService.getSelfInfo();
|
|
63
|
+
const member = self?.id
|
|
64
|
+
? await api.memberService.getGuildMemberInfo(guildId, String(self.id)).catch(() => undefined)
|
|
65
|
+
: undefined;
|
|
66
|
+
context.signal.throwIfAborted();
|
|
67
|
+
return {
|
|
68
|
+
...common,
|
|
69
|
+
guild: { id: guildId },
|
|
70
|
+
channel: { id: conversation.id },
|
|
71
|
+
bot: { id: self?.id, role: guildRole(member?.roles), channelAdminScope: 'unknown' },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { ...common, bot: { role: 'not_applicable' } };
|
|
75
|
+
},
|
|
76
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qq-group-admin
|
|
3
|
+
platforms:
|
|
4
|
+
- qq
|
|
5
|
+
description: QQ 官方机器人群管理:移出成员、禁言、撤回他人消息、处理入群申请;工具分别声明权限与审批要求。
|
|
6
|
+
keywords:
|
|
7
|
+
- 群管理
|
|
8
|
+
- 禁言
|
|
9
|
+
- 踢人
|
|
10
|
+
- 移出
|
|
11
|
+
- 入群申请
|
|
12
|
+
- 撤回他人消息
|
|
13
|
+
tools:
|
|
14
|
+
- group_kick
|
|
15
|
+
- set_mute
|
|
16
|
+
- recall_member_message
|
|
17
|
+
- handle_join_request
|
|
18
|
+
scopes:
|
|
19
|
+
- group
|
|
20
|
+
- channel
|
|
21
|
+
---
|
|
22
|
+
# qq-group-admin
|
|
23
|
+
|
|
24
|
+
Load only when the current group and target member are explicit. Every tool targets the current conversation; the model cannot choose another group. Each tool re-checks the bot's live role (`bot_state`) before acting.
|
|
25
|
+
|
|
26
|
+
Official limits (enforced by QQ, not by this skill): the bot must be group owner/admin; only ordinary members (not owner, admins or bots) can be removed or muted; mute is at most 30 days; recall works only within 2 minutes; member removal and join-request APIs are invite-only (11253 = no access).
|
|
27
|
+
|
|
28
|
+
`group_kick` and `handle_join_request` need a fresh human approval each time; show the target member and the reason. A previous approval never authorizes the next action. `set_mute` always needs approval.
|
|
29
|
+
|
|
30
|
+
Automatic moderation needs a confirmed rule and target group; never invent trigger conditions from permissions alone.
|
|
31
|
+
|
|
32
|
+
`recall_member_message` keeps the master/admin/trusted/owner requester permission without per-call approval and also works in guild channels (platform-enforced admin rights). To recall the bot's own message, use `qq-messages`.
|
|
33
|
+
|
|
34
|
+
Not available on official bots: invite to group, leave group, special title, anonymous, announcement, essence, poke and group sign-in.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { currentGroup, kickQqGroupMember, requireGroupManager } from '../../../../conversation.js';
|
|
5
|
+
import { messages as t } from '../../../../messages.js';
|
|
6
|
+
export default defineAgentTool({
|
|
7
|
+
description: '把当前 QQ 群中的普通成员移出群,可选同时拉黑;每次人工审批,官方白名单能力',
|
|
8
|
+
adapter: 'qq',
|
|
9
|
+
scopes: ['group'],
|
|
10
|
+
permissions: ['role(master,admin,trusted,owner)'],
|
|
11
|
+
requiresApproval: 'human',
|
|
12
|
+
risk: 'dangerous',
|
|
13
|
+
riskCategory: 'member',
|
|
14
|
+
inputSchema: z.object({
|
|
15
|
+
user_id: z.string().min(1).describe('要移出的成员 member_openid'),
|
|
16
|
+
reason: z.string().min(1).describe('本次移出的具体原因,随目标成员一起供人工确认'),
|
|
17
|
+
blacklist: z.boolean().default(false).describe('是否同时加入群黑名单'),
|
|
18
|
+
}),
|
|
19
|
+
async execute({ user_id, blacklist }, context) {
|
|
20
|
+
const group = currentGroup(context);
|
|
21
|
+
const client = context.$client;
|
|
22
|
+
const [self, member] = await Promise.all([
|
|
23
|
+
requireGroupManager(context, group),
|
|
24
|
+
client.api.groupService.getMemberInfo(group, user_id),
|
|
25
|
+
]);
|
|
26
|
+
if (!self)
|
|
27
|
+
return { success: false, message: t(context.locale, 'botNotManager') };
|
|
28
|
+
if (member.member_openid !== user_id || member.member_role !== 'member' || member.bot || user_id === self.member_openid) {
|
|
29
|
+
return { success: false, message: t(context.locale, 'targetNotMember') };
|
|
30
|
+
}
|
|
31
|
+
context.signal.throwIfAborted();
|
|
32
|
+
const { blacklistFailed } = await kickQqGroupMember(client.api, group, user_id, blacklist === true);
|
|
33
|
+
return {
|
|
34
|
+
success: true,
|
|
35
|
+
message: t(context.locale, 'memberKicked', { p0: member.username || user_id }),
|
|
36
|
+
...(blacklistFailed ? { warning: t(context.locale, 'blacklistFailed') } : {}),
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { currentGroup, kickQqGroupMember, requireGroupManager } from '../../../../conversation.js';
|
|
4
|
+
import { messages as t } from '../../../../messages.js';
|
|
5
|
+
|
|
6
|
+
export default defineAgentTool({
|
|
7
|
+
description: '把当前 QQ 群中的普通成员移出群,可选同时拉黑;每次人工审批,官方白名单能力',
|
|
8
|
+
adapter: 'qq',
|
|
9
|
+
scopes: ['group'],
|
|
10
|
+
permissions: ['role(master,admin,trusted,owner)'],
|
|
11
|
+
requiresApproval: 'human',
|
|
12
|
+
risk: 'dangerous',
|
|
13
|
+
riskCategory: 'member',
|
|
14
|
+
inputSchema: z.object({
|
|
15
|
+
user_id: z.string().min(1).describe('要移出的成员 member_openid'),
|
|
16
|
+
reason: z.string().min(1).describe('本次移出的具体原因,随目标成员一起供人工确认'),
|
|
17
|
+
blacklist: z.boolean().default(false).describe('是否同时加入群黑名单'),
|
|
18
|
+
}),
|
|
19
|
+
async execute({ user_id, blacklist }, context) {
|
|
20
|
+
const group = currentGroup(context);
|
|
21
|
+
const client = context.$client;
|
|
22
|
+
const [self, member] = await Promise.all([
|
|
23
|
+
requireGroupManager(context, group),
|
|
24
|
+
client.api.groupService.getMemberInfo(group, user_id),
|
|
25
|
+
]);
|
|
26
|
+
if (!self) return { success: false, message: t(context.locale, 'botNotManager') };
|
|
27
|
+
if (member.member_openid !== user_id || member.member_role !== 'member' || member.bot || user_id === self.member_openid) {
|
|
28
|
+
return { success: false, message: t(context.locale, 'targetNotMember') };
|
|
29
|
+
}
|
|
30
|
+
context.signal.throwIfAborted();
|
|
31
|
+
const { blacklistFailed } = await kickQqGroupMember(client.api, group, user_id, blacklist === true);
|
|
32
|
+
return {
|
|
33
|
+
success: true,
|
|
34
|
+
message: t(context.locale, 'memberKicked', { p0: member.username || user_id }),
|
|
35
|
+
...(blacklistFailed ? { warning: t(context.locale, 'blacklistFailed') } : {}),
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { currentGroup, requireGroupManager } from '../../../../conversation.js';
|
|
5
|
+
import { messages as t } from '../../../../messages.js';
|
|
6
|
+
export default defineAgentTool({
|
|
7
|
+
description: '通过或拒绝当前 QQ 群的一条入群申请;每次人工审批,需机器人为群管理员,官方白名单能力',
|
|
8
|
+
adapter: 'qq',
|
|
9
|
+
scopes: ['group'],
|
|
10
|
+
permissions: ['role(master,admin,trusted,owner)'],
|
|
11
|
+
requiresApproval: 'human',
|
|
12
|
+
risk: 'dangerous',
|
|
13
|
+
riskCategory: 'member',
|
|
14
|
+
inputSchema: z.object({
|
|
15
|
+
user_id: z.string().min(1).describe('申请人 member_openid(来自 list_join_requests 或入群申请事件)'),
|
|
16
|
+
join_request_id: z.string().min(1).optional().describe('申请 ID(list_join_requests 返回的 join_request_id)'),
|
|
17
|
+
approve: z.boolean().describe('true 通过,false 拒绝'),
|
|
18
|
+
reason: z.string().optional().describe('拒绝理由(仅拒绝时发送)'),
|
|
19
|
+
blacklist: z.boolean().default(false).describe('拒绝时是否同时拉黑'),
|
|
20
|
+
}),
|
|
21
|
+
async execute({ user_id, join_request_id, approve, reason, blacklist }, context) {
|
|
22
|
+
const group = currentGroup(context);
|
|
23
|
+
if (!await requireGroupManager(context, group))
|
|
24
|
+
return { success: false, message: t(context.locale, 'botNotManager') };
|
|
25
|
+
await context.$client.api.groupService.approveJoinRequest(group, user_id, {
|
|
26
|
+
op: approve ? 'approve' : 'decline',
|
|
27
|
+
...(join_request_id ? { join_request_id } : {}),
|
|
28
|
+
...(!approve && reason ? { reject_reason: reason } : {}),
|
|
29
|
+
...(!approve && blacklist ? { add_to_member_blacklist: true } : {}),
|
|
30
|
+
});
|
|
31
|
+
return { success: true, message: t(context.locale, approve ? 'joinApproved' : 'joinDeclined', { user: user_id }) };
|
|
32
|
+
},
|
|
33
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { currentGroup, requireGroupManager } from '../../../../conversation.js';
|
|
4
|
+
import { messages as t } from '../../../../messages.js';
|
|
5
|
+
|
|
6
|
+
export default defineAgentTool({
|
|
7
|
+
description: '通过或拒绝当前 QQ 群的一条入群申请;每次人工审批,需机器人为群管理员,官方白名单能力',
|
|
8
|
+
adapter: 'qq',
|
|
9
|
+
scopes: ['group'],
|
|
10
|
+
permissions: ['role(master,admin,trusted,owner)'],
|
|
11
|
+
requiresApproval: 'human',
|
|
12
|
+
risk: 'dangerous',
|
|
13
|
+
riskCategory: 'member',
|
|
14
|
+
inputSchema: z.object({
|
|
15
|
+
user_id: z.string().min(1).describe('申请人 member_openid(来自 list_join_requests 或入群申请事件)'),
|
|
16
|
+
join_request_id: z.string().min(1).optional().describe('申请 ID(list_join_requests 返回的 join_request_id)'),
|
|
17
|
+
approve: z.boolean().describe('true 通过,false 拒绝'),
|
|
18
|
+
reason: z.string().optional().describe('拒绝理由(仅拒绝时发送)'),
|
|
19
|
+
blacklist: z.boolean().default(false).describe('拒绝时是否同时拉黑'),
|
|
20
|
+
}),
|
|
21
|
+
async execute({ user_id, join_request_id, approve, reason, blacklist }, context) {
|
|
22
|
+
const group = currentGroup(context);
|
|
23
|
+
if (!await requireGroupManager(context, group)) return { success: false, message: t(context.locale, 'botNotManager') };
|
|
24
|
+
await context.$client.api.groupService.approveJoinRequest(group, user_id, {
|
|
25
|
+
op: approve ? 'approve' : 'decline',
|
|
26
|
+
...(join_request_id ? { join_request_id } : {}),
|
|
27
|
+
...(!approve && reason ? { reject_reason: reason } : {}),
|
|
28
|
+
...(!approve && blacklist ? { add_to_member_blacklist: true } : {}),
|
|
29
|
+
});
|
|
30
|
+
return { success: true, message: t(context.locale, approve ? 'joinApproved' : 'joinDeclined', { user: user_id }) };
|
|
31
|
+
},
|
|
32
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { currentConversation, recallTarget, requireGroupManager, resolveMessageTarget } from '../../../../conversation.js';
|
|
5
|
+
import { messages as t } from '../../../../messages.js';
|
|
6
|
+
export default defineAgentTool({
|
|
7
|
+
description: '撤回当前 QQ 群或频道子频道内他人的真实消息;需调用方具备群管发起权限,机器人须为管理员,官方只允许 2 分钟内',
|
|
8
|
+
adapter: 'qq',
|
|
9
|
+
scopes: ['group', 'channel'],
|
|
10
|
+
permissions: ['role(master,admin,trusted,owner)'],
|
|
11
|
+
requiresApproval: 'never',
|
|
12
|
+
inputSchema: z.object({
|
|
13
|
+
message_id: z.string().min(1).describe('当前会话中要撤回的真实消息 ID,或消息头里的 m<n> 别名'),
|
|
14
|
+
reason: z.string().min(1).describe('撤回的具体原因,自动处理必须依据已确认的群规'),
|
|
15
|
+
}),
|
|
16
|
+
async execute({ message_id }, context) {
|
|
17
|
+
const conversation = currentConversation(context);
|
|
18
|
+
const target = resolveMessageTarget(context, message_id);
|
|
19
|
+
// 自己的消息不依赖管理员身份。群里再实时核验机器人角色;目标角色(只能撤回普通成员)由平台执行。
|
|
20
|
+
if (!target.ownOutbound && conversation.kind === 'group' && !await requireGroupManager(context, conversation.id)) {
|
|
21
|
+
return { success: false, message: t(context.locale, 'botNotManager') };
|
|
22
|
+
}
|
|
23
|
+
return recallTarget(context, target);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { currentConversation, recallTarget, requireGroupManager, resolveMessageTarget } from '../../../../conversation.js';
|
|
4
|
+
import { messages as t } from '../../../../messages.js';
|
|
5
|
+
|
|
6
|
+
export default defineAgentTool({
|
|
7
|
+
description: '撤回当前 QQ 群或频道子频道内他人的真实消息;需调用方具备群管发起权限,机器人须为管理员,官方只允许 2 分钟内',
|
|
8
|
+
adapter: 'qq',
|
|
9
|
+
scopes: ['group', 'channel'],
|
|
10
|
+
permissions: ['role(master,admin,trusted,owner)'],
|
|
11
|
+
requiresApproval: 'never',
|
|
12
|
+
inputSchema: z.object({
|
|
13
|
+
message_id: z.string().min(1).describe('当前会话中要撤回的真实消息 ID,或消息头里的 m<n> 别名'),
|
|
14
|
+
reason: z.string().min(1).describe('撤回的具体原因,自动处理必须依据已确认的群规'),
|
|
15
|
+
}),
|
|
16
|
+
async execute({ message_id }, context) {
|
|
17
|
+
const conversation = currentConversation(context);
|
|
18
|
+
const target = resolveMessageTarget(context, message_id);
|
|
19
|
+
// 自己的消息不依赖管理员身份。群里再实时核验机器人角色;目标角色(只能撤回普通成员)由平台执行。
|
|
20
|
+
if (!target.ownOutbound && conversation.kind === 'group' && !await requireGroupManager(context, conversation.id)) {
|
|
21
|
+
return { success: false, message: t(context.locale, 'botNotManager') };
|
|
22
|
+
}
|
|
23
|
+
return recallTarget(context, target);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { currentGroup, muteQqGroupMember, QQ_GROUP_MUTE_MAX_SECONDS, requireGroupManager } from '../../../../conversation.js';
|
|
5
|
+
import { messages as t } from '../../../../messages.js';
|
|
6
|
+
export default defineAgentTool({
|
|
7
|
+
description: '禁言 / 解除禁言当前 QQ 群中的普通成员(最长 30 天);需机器人为群管理员',
|
|
8
|
+
adapter: 'qq',
|
|
9
|
+
scopes: ['group'],
|
|
10
|
+
permissions: ['role(master,admin,trusted,owner)'],
|
|
11
|
+
requiresApproval: 'always',
|
|
12
|
+
risk: 'dangerous',
|
|
13
|
+
riskCategory: 'member',
|
|
14
|
+
inputSchema: z.object({
|
|
15
|
+
user_id: z.string().min(1).describe('目标成员 member_openid'),
|
|
16
|
+
duration: z.number().int().min(0).max(QQ_GROUP_MUTE_MAX_SECONDS).default(0).describe('禁言秒数,0 = 解除禁言,最长 2592000(30 天)'),
|
|
17
|
+
}),
|
|
18
|
+
async execute({ user_id, duration }, context) {
|
|
19
|
+
const group = currentGroup(context);
|
|
20
|
+
const client = context.$client;
|
|
21
|
+
const seconds = duration ?? 0;
|
|
22
|
+
const [self, member] = await Promise.all([
|
|
23
|
+
requireGroupManager(context, group),
|
|
24
|
+
client.api.groupService.getMemberInfo(group, user_id),
|
|
25
|
+
]);
|
|
26
|
+
if (!self)
|
|
27
|
+
return { success: false, message: t(context.locale, 'botNotManager') };
|
|
28
|
+
// 官方:新增 / 更新禁言只能作用于普通成员;解除不限制。
|
|
29
|
+
if (member.member_openid !== user_id || (seconds > 0 && (member.member_role !== 'member' || member.bot))) {
|
|
30
|
+
return { success: false, message: t(context.locale, 'targetNotMember') };
|
|
31
|
+
}
|
|
32
|
+
context.signal.throwIfAborted();
|
|
33
|
+
await muteQqGroupMember(client.api, group, user_id, seconds);
|
|
34
|
+
const user = member.username || user_id;
|
|
35
|
+
return { success: true, message: seconds === 0 ? t(context.locale, 'unmuted', { user }) : t(context.locale, 'muted', { user, seconds }) };
|
|
36
|
+
},
|
|
37
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { currentGroup, muteQqGroupMember, QQ_GROUP_MUTE_MAX_SECONDS, requireGroupManager } from '../../../../conversation.js';
|
|
4
|
+
import { messages as t } from '../../../../messages.js';
|
|
5
|
+
|
|
6
|
+
export default defineAgentTool({
|
|
7
|
+
description: '禁言 / 解除禁言当前 QQ 群中的普通成员(最长 30 天);需机器人为群管理员',
|
|
8
|
+
adapter: 'qq',
|
|
9
|
+
scopes: ['group'],
|
|
10
|
+
permissions: ['role(master,admin,trusted,owner)'],
|
|
11
|
+
requiresApproval: 'always',
|
|
12
|
+
risk: 'dangerous',
|
|
13
|
+
riskCategory: 'member',
|
|
14
|
+
inputSchema: z.object({
|
|
15
|
+
user_id: z.string().min(1).describe('目标成员 member_openid'),
|
|
16
|
+
duration: z.number().int().min(0).max(QQ_GROUP_MUTE_MAX_SECONDS).default(0).describe('禁言秒数,0 = 解除禁言,最长 2592000(30 天)'),
|
|
17
|
+
}),
|
|
18
|
+
async execute({ user_id, duration }, context) {
|
|
19
|
+
const group = currentGroup(context);
|
|
20
|
+
const client = context.$client;
|
|
21
|
+
const seconds = duration ?? 0;
|
|
22
|
+
const [self, member] = await Promise.all([
|
|
23
|
+
requireGroupManager(context, group),
|
|
24
|
+
client.api.groupService.getMemberInfo(group, user_id),
|
|
25
|
+
]);
|
|
26
|
+
if (!self) return { success: false, message: t(context.locale, 'botNotManager') };
|
|
27
|
+
// 官方:新增 / 更新禁言只能作用于普通成员;解除不限制。
|
|
28
|
+
if (member.member_openid !== user_id || (seconds > 0 && (member.member_role !== 'member' || member.bot))) {
|
|
29
|
+
return { success: false, message: t(context.locale, 'targetNotMember') };
|
|
30
|
+
}
|
|
31
|
+
context.signal.throwIfAborted();
|
|
32
|
+
await muteQqGroupMember(client.api, group, user_id, seconds);
|
|
33
|
+
const user = member.username || user_id;
|
|
34
|
+
return { success: true, message: seconds === 0 ? t(context.locale, 'unmuted', { user }) : t(context.locale, 'muted', { user, seconds }) };
|
|
35
|
+
},
|
|
36
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qq-group-directory
|
|
3
|
+
platforms:
|
|
4
|
+
- qq
|
|
5
|
+
description: 当前 QQ 群的群信息、成员列表与成员详情(官方白名单能力)。
|
|
6
|
+
keywords:
|
|
7
|
+
- 群信息
|
|
8
|
+
- 群成员
|
|
9
|
+
- 成员列表
|
|
10
|
+
- member_openid
|
|
11
|
+
tools:
|
|
12
|
+
- group_info
|
|
13
|
+
- group_members
|
|
14
|
+
- group_member_info
|
|
15
|
+
scopes:
|
|
16
|
+
- group
|
|
17
|
+
---
|
|
18
|
+
# qq-group-directory
|
|
19
|
+
|
|
20
|
+
All lookups target the current group only. Members are identified by `member_openid`, which is scoped to this bot and group; never derive it from a nickname or reuse it in another group.
|
|
21
|
+
|
|
22
|
+
Member list and member detail are invite-only official capabilities. Error 11253 means the bot has no access; report that instead of guessing. `group_members` is paged (≤30 per page, 60 QPM): request further pages only when needed.
|
|
23
|
+
|
|
24
|
+
There is no official API for the bot's group list, friend list or arbitrary user profiles, so `group_list`, `friend_list` and `user_info` do not exist on QQ official bots.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { currentGroup } from '../../../../conversation.js';
|
|
5
|
+
export default defineAgentTool({
|
|
6
|
+
description: '获取当前 QQ 群的基本信息(群名、简介、分类、标签、人数)',
|
|
7
|
+
adapter: 'qq',
|
|
8
|
+
scopes: ['group'],
|
|
9
|
+
requiresApproval: 'never',
|
|
10
|
+
readOnly: true,
|
|
11
|
+
inputSchema: z.object({}),
|
|
12
|
+
async execute(_input, context) {
|
|
13
|
+
const info = await context.$client.api.groupService.getInfo(currentGroup(context));
|
|
14
|
+
return { success: true, group: info };
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { currentGroup } from '../../../../conversation.js';
|
|
4
|
+
|
|
5
|
+
export default defineAgentTool({
|
|
6
|
+
description: '获取当前 QQ 群的基本信息(群名、简介、分类、标签、人数)',
|
|
7
|
+
adapter: 'qq',
|
|
8
|
+
scopes: ['group'],
|
|
9
|
+
requiresApproval: 'never',
|
|
10
|
+
readOnly: true,
|
|
11
|
+
inputSchema: z.object({}),
|
|
12
|
+
async execute(_input, context) {
|
|
13
|
+
const info = await context.$client.api.groupService.getInfo(currentGroup(context));
|
|
14
|
+
return { success: true, group: info };
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { currentGroup } from '../../../../conversation.js';
|
|
5
|
+
export default defineAgentTool({
|
|
6
|
+
description: '获取当前 QQ 群中指定成员的信息(昵称、角色、是否机器人、入群时间);官方白名单能力',
|
|
7
|
+
adapter: 'qq',
|
|
8
|
+
scopes: ['group'],
|
|
9
|
+
permissions: ['role(master,admin,trusted,owner)'],
|
|
10
|
+
requiresApproval: 'never',
|
|
11
|
+
readOnly: true,
|
|
12
|
+
inputSchema: z.object({
|
|
13
|
+
user_id: z.string().min(1).describe('目标成员的 member_openid(来自消息发送者或成员列表,不要猜测)'),
|
|
14
|
+
}),
|
|
15
|
+
async execute({ user_id }, context) {
|
|
16
|
+
const member = await context.$client.api.groupService.getMemberInfo(currentGroup(context), user_id);
|
|
17
|
+
return { success: true, member };
|
|
18
|
+
},
|
|
19
|
+
});
|