@zhin.js/adapter-qq 1.1.17 → 1.1.19

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.
Files changed (122) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +75 -21
  3. package/adapters/qq/index.js +4 -33
  4. package/adapters/qq/index.ts +3 -41
  5. package/agents/qq/boundaries.md +2 -0
  6. package/agents/qq/conversation.js +92 -0
  7. package/agents/qq/conversation.ts +99 -0
  8. package/agents/qq/messages.js +60 -0
  9. package/agents/qq/messages.ts +60 -0
  10. package/agents/qq/skills/qq/SKILL.md +8 -2
  11. package/agents/qq/skills/qq/tools/add_role/index.js +2 -1
  12. package/agents/qq/skills/qq/tools/add_role/index.ts +2 -1
  13. package/agents/qq/skills/qq/tools/channel_info/index.js +1 -1
  14. package/agents/qq/skills/qq/tools/channel_info/index.ts +1 -1
  15. package/agents/qq/skills/qq/tools/create_role/index.js +1 -1
  16. package/agents/qq/skills/qq/tools/create_role/index.ts +1 -1
  17. package/agents/qq/skills/qq/tools/guild_kick_member/index.js +30 -0
  18. package/agents/qq/skills/qq/tools/guild_kick_member/index.ts +29 -0
  19. package/agents/qq/skills/qq/tools/guild_mute_member/index.js +31 -0
  20. package/agents/qq/skills/qq/tools/guild_mute_member/index.ts +30 -0
  21. package/agents/qq/skills/qq/tools/list_channels/index.js +1 -1
  22. package/agents/qq/skills/qq/tools/list_channels/index.ts +1 -1
  23. package/agents/qq/skills/qq/tools/list_roles/index.js +1 -1
  24. package/agents/qq/skills/qq/tools/list_roles/index.ts +1 -1
  25. package/agents/qq/skills/qq/tools/member_detail/index.js +1 -1
  26. package/agents/qq/skills/qq/tools/member_detail/index.ts +1 -1
  27. package/agents/qq/skills/qq/tools/remove_role/index.js +2 -1
  28. package/agents/qq/skills/qq/tools/remove_role/index.ts +2 -1
  29. package/agents/qq/skills/qq-conversation/SKILL.md +24 -0
  30. package/agents/qq/skills/qq-conversation/tools/conversation_info/index.js +78 -0
  31. package/agents/qq/skills/qq-conversation/tools/conversation_info/index.ts +76 -0
  32. package/agents/qq/skills/qq-directory/tools/list_guilds/index.js +1 -1
  33. package/agents/qq/skills/qq-directory/tools/list_guilds/index.ts +1 -1
  34. package/agents/qq/skills/qq-group-admin/SKILL.md +34 -0
  35. package/agents/qq/skills/qq-group-admin/tools/group_kick/index.js +39 -0
  36. package/agents/qq/skills/qq-group-admin/tools/group_kick/index.ts +38 -0
  37. package/agents/qq/skills/qq-group-admin/tools/handle_join_request/index.js +33 -0
  38. package/agents/qq/skills/qq-group-admin/tools/handle_join_request/index.ts +32 -0
  39. package/agents/qq/skills/qq-group-admin/tools/recall_member_message/index.js +25 -0
  40. package/agents/qq/skills/qq-group-admin/tools/recall_member_message/index.ts +25 -0
  41. package/agents/qq/skills/qq-group-admin/tools/set_mute/index.js +37 -0
  42. package/agents/qq/skills/qq-group-admin/tools/set_mute/index.ts +36 -0
  43. package/agents/qq/skills/qq-group-directory/SKILL.md +24 -0
  44. package/agents/qq/skills/qq-group-directory/tools/group_info/index.js +16 -0
  45. package/agents/qq/skills/qq-group-directory/tools/group_info/index.ts +16 -0
  46. package/agents/qq/skills/qq-group-directory/tools/group_member_info/index.js +19 -0
  47. package/agents/qq/skills/qq-group-directory/tools/group_member_info/index.ts +19 -0
  48. package/agents/qq/skills/qq-group-directory/tools/group_members/index.js +19 -0
  49. package/agents/qq/skills/qq-group-directory/tools/group_members/index.ts +19 -0
  50. package/agents/qq/skills/qq-group-state/SKILL.md +21 -0
  51. package/agents/qq/skills/qq-group-state/tools/group_blacklist/index.js +19 -0
  52. package/agents/qq/skills/qq-group-state/tools/group_blacklist/index.ts +19 -0
  53. package/agents/qq/skills/qq-group-state/tools/list_join_requests/index.js +19 -0
  54. package/agents/qq/skills/qq-group-state/tools/list_join_requests/index.ts +19 -0
  55. package/agents/qq/skills/qq-group-state/tools/list_muted/index.js +21 -0
  56. package/agents/qq/skills/qq-group-state/tools/list_muted/index.ts +21 -0
  57. package/agents/qq/skills/qq-messages/SKILL.md +27 -0
  58. package/agents/qq/skills/qq-messages/tools/quote_reply/index.js +21 -0
  59. package/agents/qq/skills/qq-messages/tools/quote_reply/index.ts +21 -0
  60. package/agents/qq/skills/qq-messages/tools/recall_own_message/index.js +18 -0
  61. package/agents/qq/skills/qq-messages/tools/recall_own_message/index.ts +17 -0
  62. package/commands/qq/endpoint/definition.js +73 -55
  63. package/commands/qq/endpoint/definition.ts +75 -86
  64. package/lib/adapter.d.ts +13 -0
  65. package/lib/adapter.js +27 -0
  66. package/lib/client.d.ts +7 -9
  67. package/lib/client.js +1 -2
  68. package/lib/console.d.ts +3 -0
  69. package/lib/console.js +93 -0
  70. package/lib/endpoint.d.ts +17 -27
  71. package/lib/endpoint.js +325 -146
  72. package/lib/group-admin.d.ts +41 -0
  73. package/lib/group-admin.js +114 -0
  74. package/lib/i18n.js +4 -4
  75. package/lib/image-size.d.ts +6 -1
  76. package/lib/image-size.js +2 -3
  77. package/lib/index.d.ts +5 -4
  78. package/lib/index.js +3 -3
  79. package/lib/interaction.js +1 -1
  80. package/lib/outbound.d.ts +4 -1
  81. package/lib/outbound.js +3 -2
  82. package/lib/protocol.d.ts +7 -0
  83. package/lib/protocol.js +4 -0
  84. package/lib/qq-console-spec.d.ts +17 -0
  85. package/lib/qq-console-spec.js +21 -0
  86. package/lib/qq-console.d.ts +10 -0
  87. package/lib/qq-console.js +126 -0
  88. package/lib/qq-endpoint-write.d.ts +18 -0
  89. package/lib/qq-endpoint-write.js +7 -0
  90. package/lib/qq-runtime-state.d.ts +29 -9
  91. package/lib/qq-runtime-state.js +5 -5
  92. package/lib/qq-send.d.ts +7 -14
  93. package/lib/qq-send.js +20 -6
  94. package/lib/webhook.d.ts +3 -6
  95. package/lib/webhook.js +6 -49
  96. package/lib/ws.d.ts +10 -33
  97. package/lib/ws.js +21 -70
  98. package/middlewares/bot-kind-reply/index.js +1 -2
  99. package/middlewares/bot-kind-reply/index.ts +0 -2
  100. package/package.json +26 -18
  101. package/pages/index/index.js +15 -0
  102. package/pages/index/index.ts +16 -0
  103. package/plugin.js +9 -6
  104. package/schema.json +174 -0
  105. package/src/adapter.ts +23 -0
  106. package/src/client.ts +4 -12
  107. package/src/console.ts +103 -0
  108. package/src/endpoint.ts +328 -141
  109. package/src/group-admin.ts +155 -0
  110. package/src/i18n.ts +4 -4
  111. package/src/image-size.ts +7 -3
  112. package/src/index.ts +5 -5
  113. package/src/interaction.ts +1 -1
  114. package/src/outbound.ts +3 -2
  115. package/src/protocol.ts +10 -0
  116. package/src/qq-console-spec.ts +29 -0
  117. package/src/qq-console.ts +130 -0
  118. package/src/qq-endpoint-write.ts +24 -0
  119. package/src/qq-runtime-state.ts +31 -15
  120. package/src/qq-send.ts +28 -12
  121. package/src/webhook.ts +7 -57
  122. package/src/ws.ts +27 -105
@@ -20,5 +20,65 @@ export const messages = createMessages({
20
20
  "roleRemoved": {
21
21
  "zh-CN": "已移除成员的角色",
22
22
  "en": "Role removed from the member"
23
+ },
24
+ "conversationRequired": {
25
+ "zh-CN": "此操作需要当前 QQ 官方机器人会话",
26
+ "en": "This operation requires the current QQ official bot conversation"
27
+ },
28
+ "groupRequired": {
29
+ "zh-CN": "此操作仅支持当前 QQ 群",
30
+ "en": "This operation requires the current QQ group"
31
+ },
32
+ "channelRequired": {
33
+ "zh-CN": "此操作仅支持当前 QQ 频道子频道",
34
+ "en": "This operation requires the current QQ guild channel"
35
+ },
36
+ "messageOutsideConversation": {
37
+ "zh-CN": "该消息 ID 不属于当前会话,请勿猜测消息 ID",
38
+ "en": "The message ID does not belong to this conversation; do not guess message IDs"
39
+ },
40
+ "ownMessageRequired": {
41
+ "zh-CN": "该工具只能撤回机器人自己发送的消息(发送回执里的消息 ID)",
42
+ "en": "This tool can only recall messages the bot sent (the ID from its send receipt)"
43
+ },
44
+ "botNotManager": {
45
+ "zh-CN": "机器人当前不是本群群主或管理员,平台不允许此操作",
46
+ "en": "The bot is not an owner or admin of this group, so the platform does not allow this"
47
+ },
48
+ "targetNotMember": {
49
+ "zh-CN": "目标必须是本群的普通成员(官方不允许处置群主、管理员或机器人)",
50
+ "en": "The target must be an ordinary member of this group (owners, admins and bots cannot be targeted)"
51
+ },
52
+ "messageRecalled": {
53
+ "zh-CN": "平台已确认撤回消息",
54
+ "en": "The platform confirmed the message was recalled"
55
+ },
56
+ "recallUnconfirmed": {
57
+ "zh-CN": "平台未确认撤回成功(官方只允许撤回 2 分钟内的消息),请勿自动重试",
58
+ "en": "Recall was not confirmed (QQ only allows recalling messages younger than 2 minutes); do not retry automatically"
59
+ },
60
+ "memberKicked": {
61
+ "zh-CN": "已将成员 {p0} 移出本群",
62
+ "en": "Removed member {p0} from this group"
63
+ },
64
+ "blacklistFailed": {
65
+ "zh-CN": "成员已移出,但加入黑名单失败",
66
+ "en": "The member was removed, but adding them to the blacklist failed"
67
+ },
68
+ "muted": {
69
+ "zh-CN": "已禁言 {user} {seconds} 秒",
70
+ "en": "Muted {user} for {seconds} seconds"
71
+ },
72
+ "unmuted": {
73
+ "zh-CN": "已解除 {user} 的禁言",
74
+ "en": "Unmuted {user}"
75
+ },
76
+ "joinApproved": {
77
+ "zh-CN": "已通过 {user} 的入群申请",
78
+ "en": "Approved the join request from {user}"
79
+ },
80
+ "joinDeclined": {
81
+ "zh-CN": "已拒绝 {user} 的入群申请",
82
+ "en": "Declined the join request from {user}"
23
83
  }
24
84
  });
@@ -2,13 +2,15 @@
2
2
  name: qq
3
3
  platforms:
4
4
  - qq
5
- description: QQ 官方机器人频道、角色和成员详情管理。
5
+ description: QQ 官方机器人频道、角色、成员详情与成员禁言/移出管理。
6
6
  keywords:
7
7
  - qq
8
8
  - guild
9
9
  - channel
10
10
  - role
11
11
  - member
12
+ - 频道禁言
13
+ - 频道踢人
12
14
  tags:
13
15
  - adapter
14
16
  - community
@@ -20,9 +22,13 @@ tools:
20
22
  - remove_role
21
23
  - channel_info
22
24
  - member_detail
25
+ - guild_mute_member
26
+ - guild_kick_member
23
27
  scopes:
24
28
  - channel
25
29
  ---
26
30
  # QQ 频道
27
31
 
28
- 确认频道和成员 ID 后查询详情或维护角色;权限与审批由各 Tool 执行。可访问频道列表使用 qq-directory。
32
+ 确认频道和成员 ID 后查询详情、维护角色或处置成员;权限与审批由各 Tool 执行。可访问频道列表使用 qq-directory。
33
+
34
+ `guild_mute_member` 作用于当前频道(0 秒 = 解除),`guild_kick_member` 每次人工审批,可选拉黑和撤回近 N 天消息;机器人需具备频道管理权限,平台拒绝时不要自动重试。
@@ -17,7 +17,8 @@ export default defineAgentTool({
17
17
  permissions: [platformPermission('qq', 'manage_roles')],
18
18
  async execute({ guild_id, channel_id, user_id, role_id }, context) {
19
19
  const client = context.$client;
20
- const success = await client.addMemberRole(guild_id, channel_id, user_id, role_id);
20
+ await client.memberService.addMemberRole(guild_id, channel_id, user_id, role_id);
21
+ const success = true;
21
22
  return { success, message: success ? t(context.locale, 'roleAdded') : t(context.locale, 'operationFailed') };
22
23
  },
23
24
  });
@@ -17,7 +17,8 @@ export default defineAgentTool<{ guild_id: string; channel_id: string; user_id:
17
17
  permissions: [platformPermission('qq', 'manage_roles')],
18
18
  async execute({ guild_id, channel_id, user_id, role_id }: { guild_id: string; channel_id: string; user_id: string; role_id: string }, context) {
19
19
  const client = context.$client;
20
- const success = await client.addMemberRole(guild_id, channel_id, user_id, role_id);
20
+ await client.memberService.addMemberRole(guild_id, channel_id, user_id, role_id);
21
+ const success = true;
21
22
  return { success, message: success ? t(context.locale, 'roleAdded') : t(context.locale, 'operationFailed') };
22
23
  },
23
24
  });
@@ -13,6 +13,6 @@ export default defineAgentTool({
13
13
  permissions: [platformPermission('qq', 'guild_admin')],
14
14
  async execute({ channel_id }, context) {
15
15
  const client = context.$client;
16
- return client.getChannelInfo(channel_id);
16
+ return client.channelService.getInfo(channel_id);
17
17
  },
18
18
  });
@@ -13,6 +13,6 @@ export default defineAgentTool<{ channel_id: string }>({
13
13
  permissions: [platformPermission('qq', 'guild_admin')],
14
14
  async execute({ channel_id }: { channel_id: string }, context) {
15
15
  const client = context.$client;
16
- return client.getChannelInfo(channel_id);
16
+ return client.channelService.getInfo(channel_id);
17
17
  },
18
18
  });
@@ -16,7 +16,7 @@ export default defineAgentTool({
16
16
  permissions: [platformPermission('qq', 'guild_owner')],
17
17
  async execute({ guild_id, name, color }, context) {
18
18
  const client = context.$client;
19
- const role = await client.createGuildRole(guild_id, name, color);
19
+ const role = await client.guildService.createRole(guild_id, { name, color: color || 0, hoist: 0 });
20
20
  return { success: !!role, role, message: role ? t(context.locale, 'namedRoleCreated', { p0: name }) : t(context.locale, 'createFailed') };
21
21
  },
22
22
  });
@@ -16,7 +16,7 @@ export default defineAgentTool<{ guild_id: string; name: string; color?: number
16
16
  permissions: [platformPermission('qq', 'guild_owner')],
17
17
  async execute({ guild_id, name, color }: { guild_id: string; name: string; color?: number }, context) {
18
18
  const client = context.$client;
19
- const role = await client.createGuildRole(guild_id, name, color);
19
+ const role = await client.guildService.createRole(guild_id, { name, color: color || 0, hoist: 0 });
20
20
  return { success: !!role, role, message: role ? t(context.locale, 'namedRoleCreated', { p0: name }) : t(context.locale, 'createFailed') };
21
21
  },
22
22
  });
@@ -0,0 +1,30 @@
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: 'human',
14
+ risk: 'dangerous',
15
+ riskCategory: 'member',
16
+ inputSchema: z.object({
17
+ user_id: z.string().min(1).describe('要移出的成员用户 ID'),
18
+ reason: z.string().min(1).describe('本次移出的具体原因,供人工确认'),
19
+ blacklist: z.boolean().default(false).describe('是否同时拉黑'),
20
+ delete_history_days: z.union([z.literal(-1), z.literal(0), z.literal(3), z.literal(7), z.literal(15), z.literal(30)])
21
+ .default(0).describe('撤回该成员近 N 天消息:0 不撤回,-1 全部'),
22
+ }),
23
+ async execute({ user_id, blacklist, delete_history_days }, context) {
24
+ const { guildId } = currentGuildChannel(context);
25
+ const ok = await context.$client.memberService.kickMember(guildId, user_id, delete_history_days ?? 0, blacklist === true);
26
+ if (ok === false)
27
+ return { success: false, message: t(context.locale, 'operationFailed') };
28
+ return { success: true, message: t(context.locale, 'memberKicked', { p0: user_id }) };
29
+ },
30
+ });
@@ -0,0 +1,29 @@
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: 'human',
14
+ risk: 'dangerous',
15
+ riskCategory: 'member',
16
+ inputSchema: z.object({
17
+ user_id: z.string().min(1).describe('要移出的成员用户 ID'),
18
+ reason: z.string().min(1).describe('本次移出的具体原因,供人工确认'),
19
+ blacklist: z.boolean().default(false).describe('是否同时拉黑'),
20
+ delete_history_days: z.union([z.literal(-1), z.literal(0), z.literal(3), z.literal(7), z.literal(15), z.literal(30)])
21
+ .default(0).describe('撤回该成员近 N 天消息:0 不撤回,-1 全部'),
22
+ }),
23
+ async execute({ user_id, blacklist, delete_history_days }, context) {
24
+ const { guildId } = currentGuildChannel(context);
25
+ const ok = await context.$client.memberService.kickMember(guildId, user_id, delete_history_days ?? 0, blacklist === true);
26
+ if (ok === false) return { success: false, message: t(context.locale, 'operationFailed') };
27
+ return { success: true, message: t(context.locale, 'memberKicked', { p0: user_id }) };
28
+ },
29
+ });
@@ -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.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.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
+ });
@@ -13,7 +13,7 @@ export default defineAgentTool({
13
13
  permissions: [platformPermission('qq', 'manage_channels')],
14
14
  async execute({ guild_id }, context) {
15
15
  const client = context.$client;
16
- const channels = await client.getChannels(guild_id);
16
+ const channels = await client.channelService.getList(guild_id);
17
17
  return { channels, count: channels.length };
18
18
  },
19
19
  });
@@ -13,7 +13,7 @@ export default defineAgentTool<{ guild_id: string }>({
13
13
  permissions: [platformPermission('qq', 'manage_channels')],
14
14
  async execute({ guild_id }: { guild_id: string }, context) {
15
15
  const client = context.$client;
16
- const channels = await client.getChannels(guild_id);
16
+ const channels = await client.channelService.getList(guild_id);
17
17
  return { channels, count: channels.length };
18
18
  },
19
19
  });
@@ -13,7 +13,7 @@ export default defineAgentTool({
13
13
  permissions: [platformPermission('qq', 'manage_roles')],
14
14
  async execute({ guild_id }, context) {
15
15
  const client = context.$client;
16
- const roles = await client.getGuildRoles(guild_id);
16
+ const roles = await client.guildService.getRoles(guild_id);
17
17
  return { roles, count: roles.length };
18
18
  },
19
19
  });
@@ -13,7 +13,7 @@ export default defineAgentTool<{ guild_id: string }>({
13
13
  permissions: [platformPermission('qq', 'manage_roles')],
14
14
  async execute({ guild_id }: { guild_id: string }, context) {
15
15
  const client = context.$client;
16
- const roles = await client.getGuildRoles(guild_id);
16
+ const roles = await client.guildService.getRoles(guild_id);
17
17
  return { roles, count: roles.length };
18
18
  },
19
19
  });
@@ -14,6 +14,6 @@ export default defineAgentTool({
14
14
  permissions: [platformPermission('qq', 'guild_admin')],
15
15
  async execute({ guild_id, user_id }, context) {
16
16
  const client = context.$client;
17
- return client.getGuildMember(guild_id, user_id);
17
+ return client.memberService.getGuildMemberInfo(guild_id, user_id);
18
18
  },
19
19
  });
@@ -14,6 +14,6 @@ export default defineAgentTool<{ guild_id: string; user_id: string }>({
14
14
  permissions: [platformPermission('qq', 'guild_admin')],
15
15
  async execute({ guild_id, user_id }: { guild_id: string; user_id: string }, context) {
16
16
  const client = context.$client;
17
- return client.getGuildMember(guild_id, user_id);
17
+ return client.memberService.getGuildMemberInfo(guild_id, user_id);
18
18
  },
19
19
  });
@@ -17,7 +17,8 @@ export default defineAgentTool({
17
17
  permissions: [platformPermission('qq', 'manage_roles')],
18
18
  async execute({ guild_id, channel_id, user_id, role_id }, context) {
19
19
  const client = context.$client;
20
- const success = await client.removeMemberRole(guild_id, channel_id, user_id, role_id);
20
+ await client.memberService.removeMemberRole(guild_id, channel_id, user_id, role_id);
21
+ const success = true;
21
22
  return { success, message: success ? t(context.locale, 'roleRemoved') : t(context.locale, 'operationFailed') };
22
23
  },
23
24
  });
@@ -17,7 +17,8 @@ export default defineAgentTool<{ guild_id: string; channel_id: string; user_id:
17
17
  permissions: [platformPermission('qq', 'manage_roles')],
18
18
  async execute({ guild_id, channel_id, user_id, role_id }: { guild_id: string; channel_id: string; user_id: string; role_id: string }, context) {
19
19
  const client = context.$client;
20
- const success = await client.removeMemberRole(guild_id, channel_id, user_id, role_id);
20
+ await client.memberService.removeMemberRole(guild_id, channel_id, user_id, role_id);
21
+ const success = true;
21
22
  return { success, message: success ? t(context.locale, 'roleRemoved') : t(context.locale, 'operationFailed') };
22
23
  },
23
24
  });
@@ -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;
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;
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
+ });
@@ -8,7 +8,7 @@ export default defineAgentTool({
8
8
  tags: ['qq'],
9
9
  async execute(_input, context) {
10
10
  const client = context.$client;
11
- const guilds = await client.getGuilds();
11
+ const guilds = await client.guildService.getList();
12
12
  return { guilds, count: guilds.length };
13
13
  },
14
14
  });
@@ -8,7 +8,7 @@ export default defineAgentTool<Record<string, never>>({
8
8
  tags: ['qq'],
9
9
  async execute(_input, context) {
10
10
  const client = context.$client;
11
- const guilds = await client.getGuilds();
11
+ const guilds = await client.guildService.getList();
12
12
  return { guilds, count: guilds.length };
13
13
  },
14
14
  });
@@ -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.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, { groupId: group, userId: user_id, addToBlacklist: 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
+ });