@zhin.js/adapter-icqq 1.1.14 → 1.1.16

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 (79) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/PERMITS.md +14 -18
  3. package/README.md +12 -0
  4. package/adapters/icqq/index.js +15 -0
  5. package/adapters/icqq/index.ts +15 -0
  6. package/agents/icqq/conversation.js +72 -0
  7. package/agents/icqq/conversation.ts +67 -0
  8. package/agents/icqq/messages.js +144 -0
  9. package/agents/icqq/messages.ts +144 -0
  10. package/agents/icqq/skills/icqq-conversation/SKILL.md +24 -0
  11. package/agents/icqq/skills/icqq-conversation/tools/conversation_info/index.js +61 -0
  12. package/agents/icqq/skills/icqq-conversation/tools/conversation_info/index.ts +61 -0
  13. package/agents/icqq/skills/icqq-directory/SKILL.md +9 -11
  14. package/agents/icqq/skills/icqq-directory/tools/user_info/index.js +2 -1
  15. package/agents/icqq/skills/icqq-directory/tools/user_info/index.ts +2 -1
  16. package/agents/icqq/skills/icqq-group-admin/SKILL.md +32 -15
  17. package/agents/icqq/skills/icqq-group-admin/tools/announce/index.js +2 -1
  18. package/agents/icqq/skills/icqq-group-admin/tools/announce/index.ts +2 -1
  19. package/agents/icqq/skills/icqq-group-admin/tools/essence/index.js +2 -1
  20. package/agents/icqq/skills/icqq-group-admin/tools/essence/index.ts +2 -1
  21. package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.js +5 -3
  22. package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.ts +5 -3
  23. package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.js +14 -11
  24. package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.ts +13 -9
  25. package/agents/icqq/skills/icqq-group-admin/tools/group_leave/index.js +33 -0
  26. package/agents/icqq/skills/icqq-group-admin/tools/group_leave/index.ts +32 -0
  27. package/agents/icqq/skills/icqq-group-admin/tools/recall_member_message/index.js +33 -0
  28. package/agents/icqq/skills/icqq-group-admin/tools/recall_member_message/index.ts +32 -0
  29. package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.js +3 -2
  30. package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.ts +3 -2
  31. package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.js +4 -3
  32. package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.ts +4 -3
  33. package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.js +4 -3
  34. package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.ts +4 -3
  35. package/agents/icqq/skills/icqq-group-directory/SKILL.md +16 -0
  36. package/agents/icqq/skills/{icqq-directory → icqq-group-directory}/tools/group_member_info/index.js +3 -2
  37. package/agents/icqq/skills/{icqq-directory → icqq-group-directory}/tools/group_member_info/index.ts +3 -2
  38. package/agents/icqq/skills/icqq-group-interaction/SKILL.md +18 -0
  39. package/agents/icqq/skills/{icqq-interaction → icqq-group-interaction}/tools/group_sign/index.js +3 -2
  40. package/agents/icqq/skills/{icqq-interaction → icqq-group-interaction}/tools/group_sign/index.ts +3 -2
  41. package/agents/icqq/skills/{icqq-interaction → icqq-group-interaction}/tools/poke/index.js +2 -1
  42. package/agents/icqq/skills/{icqq-interaction → icqq-group-interaction}/tools/poke/index.ts +2 -1
  43. package/agents/icqq/skills/icqq-group-state/SKILL.md +7 -6
  44. package/agents/icqq/skills/icqq-group-state/tools/group_files/index.js +2 -1
  45. package/agents/icqq/skills/icqq-group-state/tools/group_files/index.ts +2 -1
  46. package/agents/icqq/skills/icqq-interaction/SKILL.md +5 -10
  47. package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.js +3 -2
  48. package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.ts +3 -2
  49. package/agents/icqq/skills/icqq-messages/SKILL.md +28 -0
  50. package/agents/icqq/skills/icqq-messages/tools/forward_messages/index.js +42 -0
  51. package/agents/icqq/skills/icqq-messages/tools/forward_messages/index.ts +40 -0
  52. package/agents/icqq/skills/icqq-messages/tools/quote_reply/index.js +24 -0
  53. package/agents/icqq/skills/icqq-messages/tools/quote_reply/index.ts +24 -0
  54. package/agents/icqq/skills/icqq-messages/tools/recall_own_message/index.js +18 -0
  55. package/agents/icqq/skills/icqq-messages/tools/recall_own_message/index.ts +17 -0
  56. package/agents/icqq/system.md +4 -0
  57. package/commands/icqq/endpoint/definition.js +9 -7
  58. package/commands/icqq/endpoint/definition.ts +9 -9
  59. package/lib/endpoint.d.ts +1 -0
  60. package/lib/endpoint.js +12 -1
  61. package/lib/group-moderation.d.ts +5 -0
  62. package/lib/group-moderation.js +46 -0
  63. package/lib/i18n.d.ts +1 -0
  64. package/lib/i18n.js +47 -0
  65. package/lib/icqq-inbound.js +15 -0
  66. package/lib/icqq-login-assist.d.ts +2 -0
  67. package/lib/icqq-login-assist.js +8 -7
  68. package/lib/protocol.d.ts +1 -0
  69. package/lib/protocol.js +14 -1
  70. package/package.json +16 -16
  71. package/prompt-sections/platform/index.js +1 -2
  72. package/prompt-sections/platform/index.ts +1 -2
  73. package/schema.json +250 -42
  74. package/src/endpoint.ts +14 -1
  75. package/src/group-moderation.ts +52 -0
  76. package/src/i18n.ts +48 -0
  77. package/src/icqq-inbound.ts +14 -0
  78. package/src/icqq-login-assist.ts +10 -7
  79. package/src/protocol.ts +13 -1
@@ -1,3 +1,4 @@
1
+ import { messages as t } from "../../../../messages.js";
1
2
  import { defineAgentTool } from '@zhin.js/tool';
2
3
  import { z } from 'zod';
3
4
  export default defineAgentTool<{ group_id: number; user_id: number; duration?: number }>({
@@ -13,10 +14,10 @@ export default defineAgentTool<{ group_id: number; user_id: number; duration?: n
13
14
  async execute({ group_id, user_id, duration }, context) {
14
15
  const client = context.$client;
15
16
  const selfInfo= client.pickMember(group_id,client.uin);
16
- if(!selfInfo.is_admin && !selfInfo.is_owner) return { success: false, message: '机器人不是群主或管理员,无法禁言/解除禁言成员' };
17
+ if(!selfInfo.is_admin && !selfInfo.is_owner) return { success: false, message: t(context.locale, 'muteForbidden') };
17
18
  const memberInfo= client.pickMember(group_id,user_id);
18
- if(!memberInfo) return { success: false, message: '目标成员不存在' };
19
+ if(!memberInfo) return { success: false, message: t(context.locale, 'memberMissing') };
19
20
  await client.setGroupBan(group_id, user_id, duration === 0 ? 0 : duration);
20
- return { success: true, message: `已${duration === 0 ? '解除' : ''}禁言 ${user_id} 成员${duration === 0 ? '' : `(${duration}秒)`}` };
21
+ return { success: true, message: duration === 0 ? t(context.locale, 'unmuted', { user: user_id }) : t(context.locale, 'muted', { user: user_id, seconds: duration ?? 0 }) };
21
22
  },
22
23
  });
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { messages as t } from "../../../../messages.js";
2
3
  import { defineAgentTool } from '@zhin.js/tool';
3
4
  import { z } from 'zod';
4
5
  export default defineAgentTool({
@@ -16,11 +17,11 @@ export default defineAgentTool({
16
17
  const client = context.$client;
17
18
  const selfInfo = client.pickMember(group_id, client.uin);
18
19
  if (!selfInfo.is_admin && !selfInfo.is_owner)
19
- return { success: false, message: '机器人不是群主或管理员,无法设置头衔' };
20
+ return { success: false, message: t(context.locale, 'titleForbidden') };
20
21
  const memberInfo = client.pickMember(group_id, user_id);
21
22
  if (!memberInfo)
22
- return { success: false, message: '目标成员不存在' };
23
+ return { success: false, message: t(context.locale, 'memberMissing') };
23
24
  await client.setGroupSpecialTitle(group_id, user_id, title, duration ?? -1);
24
- return { success: true, message: `已将 ${user_id} 的头衔设为 "${title}"` };
25
+ return { success: true, message: t(context.locale, 'titleChanged', { p0: user_id, p1: title }) };
25
26
  },
26
27
  });
@@ -1,3 +1,4 @@
1
+ import { messages as t } from "../../../../messages.js";
1
2
  import { defineAgentTool } from '@zhin.js/tool';
2
3
  import { z } from 'zod';
3
4
  export default defineAgentTool<{ group_id: number; user_id: number; title: string; duration?: number }>({
@@ -14,10 +15,10 @@ export default defineAgentTool<{ group_id: number; user_id: number; title: strin
14
15
  async execute({ group_id, user_id, title, duration }, context) {
15
16
  const client = context.$client;
16
17
  const selfInfo= client.pickMember(group_id,client.uin);
17
- if(!selfInfo.is_admin && !selfInfo.is_owner) return { success: false, message: '机器人不是群主或管理员,无法设置头衔' };
18
+ if(!selfInfo.is_admin && !selfInfo.is_owner) return { success: false, message: t(context.locale, 'titleForbidden') };
18
19
  const memberInfo= client.pickMember(group_id,user_id);
19
- if(!memberInfo) return { success: false, message: '目标成员不存在' };
20
+ if(!memberInfo) return { success: false, message: t(context.locale, 'memberMissing') };
20
21
  await client.setGroupSpecialTitle(group_id, user_id, title, duration ?? -1);
21
- return { success: true, message: `已将 ${user_id} 的头衔设为 "${title}"` };
22
+ return { success: true, message: t(context.locale, 'titleChanged', { p0: user_id, p1: title }) };
22
23
  },
23
24
  });
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: icqq-group-directory
3
+ platforms:
4
+ - icqq
5
+ scopes:
6
+ - group
7
+ description: ICQQ 群成员信息查询。
8
+ keywords:
9
+ - icqq
10
+ - 成员信息
11
+ tools:
12
+ - group_member_info
13
+ ---
14
+ # icqq-group-directory
15
+
16
+ 目标群和成员必须明确;只把工具返回的信息当作已验证事实。
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { messages as t } from "../../../../messages.js";
2
3
  import { defineAgentTool } from '@zhin.js/tool';
3
4
  import { z } from 'zod';
4
5
  export default defineAgentTool({
@@ -14,10 +15,10 @@ export default defineAgentTool({
14
15
  async execute({ group_id, user_id }, context) {
15
16
  const group = context.$client.pickGroup(group_id);
16
17
  if (!group)
17
- return { success: false, message: '目标群不存在' };
18
+ return { success: false, message: t(context.locale, 'groupMissing') };
18
19
  const memberInfo = group.pickMember(user_id);
19
20
  if (!memberInfo)
20
- return { success: false, message: '目标成员不存在' };
21
+ return { success: false, message: t(context.locale, 'memberMissing') };
21
22
  return {
22
23
  success: true,
23
24
  member: memberInfo,
@@ -1,3 +1,4 @@
1
+ import { messages as t } from "../../../../messages.js";
1
2
  import { defineAgentTool } from '@zhin.js/tool';
2
3
  import { z } from 'zod';
3
4
  interface GroupMemberInfoInput {
@@ -17,9 +18,9 @@ export default defineAgentTool<GroupMemberInfoInput>({
17
18
  requiresApproval: 'never',
18
19
  async execute({ group_id, user_id }, context) {
19
20
  const group = context.$client.pickGroup(group_id);
20
- if (!group) return { success: false, message: '目标群不存在' };
21
+ if (!group) return { success: false, message: t(context.locale, 'groupMissing') };
21
22
  const memberInfo = group.pickMember(user_id);
22
- if (!memberInfo) return { success: false, message: '目标成员不存在' };
23
+ if (!memberInfo) return { success: false, message: t(context.locale, 'memberMissing') };
23
24
  return {
24
25
  success: true,
25
26
  member: memberInfo,
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: icqq-group-interaction
3
+ platforms:
4
+ - icqq
5
+ scopes:
6
+ - group
7
+ description: ICQQ 群成员戳一戳与群签到。
8
+ keywords:
9
+ - icqq
10
+ - 戳一戳
11
+ - 签到
12
+ tools:
13
+ - poke
14
+ - group_sign
15
+ ---
16
+ # icqq-group-interaction
17
+
18
+ 确认当前群和目标成员后调用;点赞使用 icqq-interaction。遵守各 Tool 审批策略。
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { messages as t } from "../../../../messages.js";
2
3
  import { defineAgentTool } from '@zhin.js/tool';
3
4
  import { z } from 'zod';
4
5
  export default defineAgentTool({
@@ -13,8 +14,8 @@ export default defineAgentTool({
13
14
  const client = context.$client;
14
15
  const groupInfo = client.pickGroup(group_id);
15
16
  if (!groupInfo)
16
- return { success: false, message: '目标群不存在' };
17
+ return { success: false, message: t(context.locale, 'groupMissing') };
17
18
  await client.sendGroupSign(group_id);
18
- return { success: true, message: '群签到成功' };
19
+ return { success: true, message: t(context.locale, 'checkedIn') };
19
20
  },
20
21
  });
@@ -1,3 +1,4 @@
1
+ import { messages as t } from "../../../../messages.js";
1
2
  import { defineAgentTool } from '@zhin.js/tool';
2
3
  import { z } from 'zod';
3
4
  export default defineAgentTool<{ group_id: number }>({
@@ -11,8 +12,8 @@ export default defineAgentTool<{ group_id: number }>({
11
12
  async execute({ group_id }, context) {
12
13
  const client = context.$client;
13
14
  const groupInfo= client.pickGroup(group_id);
14
- if(!groupInfo) return { success: false, message: '目标群不存在' };
15
+ if(!groupInfo) return { success: false, message: t(context.locale, 'groupMissing') };
15
16
  await client.sendGroupSign(group_id);
16
- return { success: true, message: '群签到成功' };
17
+ return { success: true, message: t(context.locale, 'checkedIn') };
17
18
  },
18
19
  });
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { messages as t } from "../../../../messages.js";
2
3
  import { defineAgentTool } from '@zhin.js/tool';
3
4
  import { z } from 'zod';
4
5
  export default defineAgentTool({
@@ -12,6 +13,6 @@ export default defineAgentTool({
12
13
  requiresApproval: 'never',
13
14
  async execute({ group_id, user_id }, context) {
14
15
  await context.$client.sendGroupPoke(group_id, user_id);
15
- return { success: true, message: `已戳了戳 ${user_id}` };
16
+ return { success: true, message: t(context.locale, 'poked', { p0: user_id }) };
16
17
  },
17
18
  });
@@ -1,3 +1,4 @@
1
+ import { messages as t } from "../../../../messages.js";
1
2
  import { defineAgentTool } from '@zhin.js/tool';
2
3
  import { z } from 'zod';
3
4
  export default defineAgentTool<{ group_id: number; user_id: number }>({
@@ -11,6 +12,6 @@ export default defineAgentTool<{ group_id: number; user_id: number }>({
11
12
  requiresApproval: 'never',
12
13
  async execute({ group_id, user_id }, context) {
13
14
  await context.$client.sendGroupPoke(group_id, user_id);
14
- return { success: true, message: `已戳了戳 ${user_id}` };
15
+ return { success: true, message: t(context.locale, 'poked', { p0: user_id }) };
15
16
  },
16
17
  });
@@ -4,14 +4,15 @@ platforms:
4
4
  - icqq
5
5
  description: ICQQ 群文件与禁言状态查询能力。
6
6
  keywords:
7
- - "icqq"
8
- - "群文件"
9
- - "禁言列表"
7
+ - icqq
8
+ - 群文件
9
+ - 禁言列表
10
10
  tools:
11
- - "group_files"
12
- - "list_muted"
11
+ - group_files
12
+ - list_muted
13
+ scopes:
14
+ - group
13
15
  ---
14
-
15
16
  # icqq-group-state
16
17
 
17
18
  用于读取群文件和禁言状态。确认群号后调用,不把列表之外的信息当作已验证事实。
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { messages as t } from "../../../../messages.js";
2
3
  import { defineAgentTool } from '@zhin.js/tool';
3
4
  import { z } from 'zod';
4
5
  export default defineAgentTool({
@@ -13,7 +14,7 @@ export default defineAgentTool({
13
14
  async execute({ group_id }, context) {
14
15
  const files = await context.$client.acquireGfs(group_id).ls('/');
15
16
  if (!files.length)
16
- return { files: [], message: '群文件为空' };
17
+ return { files: [], message: t(context.locale, 'filesEmpty') };
17
18
  return {
18
19
  files: files.slice(0, 30).map((f) => 'size' in f
19
20
  ? { name: f.name, is_dir: false, size: f.size, uploader: f.user_id, upload_time: f.create_time }
@@ -1,3 +1,4 @@
1
+ import { messages as t } from "../../../../messages.js";
1
2
  import { defineAgentTool } from '@zhin.js/tool';
2
3
  import { z } from 'zod';
3
4
  export default defineAgentTool<{ group_id: number }>({
@@ -11,7 +12,7 @@ export default defineAgentTool<{ group_id: number }>({
11
12
  permissions: ['role(master,admin,trusted,owner)'],
12
13
  async execute({ group_id }, context) {
13
14
  const files = await context.$client.acquireGfs(group_id).ls('/');
14
- if (!files.length) return { files: [], message: '群文件为空' };
15
+ if (!files.length) return { files: [], message: t(context.locale, 'filesEmpty') };
15
16
  return {
16
17
  files: files.slice(0, 30).map((f) => 'size' in f
17
18
  ? { name: f.name, is_dir: false, size: f.size, uploader: f.user_id, upload_time: f.create_time }
@@ -2,18 +2,13 @@
2
2
  name: icqq-interaction
3
3
  platforms:
4
4
  - icqq
5
- description: ICQQ 点赞、戳一戳和群签到互动能力。
5
+ description: ICQQ 用户点赞。
6
6
  keywords:
7
- - "icqq"
8
- - "点赞"
9
- - "戳一戳"
10
- - "签到"
7
+ - icqq
8
+ - 点赞
11
9
  tools:
12
- - "poke"
13
- - "send_user_like"
14
- - "group_sign"
10
+ - send_user_like
15
11
  ---
16
-
17
12
  # icqq-interaction
18
13
 
19
- 用于低风险社交互动。确认目标用户或群后再调用,并遵守各 Tool 的审批策略。
14
+ 用于给用户点赞;先确认真实 QQ 号,遵守 Tool 审批策略。
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { messages as t } from "../../../../messages.js";
2
3
  import { defineAgentTool } from '@zhin.js/tool';
3
4
  import { z } from 'zod';
4
5
  export default defineAgentTool({
@@ -20,7 +21,7 @@ export default defineAgentTool({
20
21
  }));
21
22
  const successTimes = successArray.reduce((a, b) => a + b, 0);
22
23
  if (!successTimes)
23
- return { success: false, message: '点赞失败' };
24
- return { success: true, message: `已给 ${user_id} 点赞 ${successTimes} 次` };
24
+ return { success: false, message: t(context.locale, 'likeFailed') };
25
+ return { success: true, message: t(context.locale, 'likesSent', { p0: user_id, p1: successTimes }) };
25
26
  },
26
27
  });
@@ -1,3 +1,4 @@
1
+ import { messages as t } from "../../../../messages.js";
1
2
  import { defineAgentTool } from '@zhin.js/tool';
2
3
  import { z } from 'zod';
3
4
  export default defineAgentTool<{ user_id: number }>({
@@ -16,7 +17,7 @@ export default defineAgentTool<{ user_id: number }>({
16
17
  } catch { /* ignore */ }
17
18
  }));
18
19
  const successTimes = successArray.reduce((a, b) => a + b, 0);
19
- if (!successTimes) return { success: false, message: '点赞失败' };
20
- return { success: true, message: `已给 ${user_id} 点赞 ${successTimes} 次` };
20
+ if (!successTimes) return { success: false, message: t(context.locale, 'likeFailed') };
21
+ return { success: true, message: t(context.locale, 'likesSent', { p0: user_id, p1: successTimes }) };
21
22
  },
22
23
  });
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: icqq-messages
3
+ platforms:
4
+ - icqq
5
+ description: ICQQ 当前会话的引用回复、真实消息合并转发,以及撤回机器人自己的发言。
6
+ keywords:
7
+ - 引用
8
+ - 回复原消息
9
+ - 转发
10
+ - 撤回
11
+ - 自己的消息
12
+ tools:
13
+ - quote_reply
14
+ - forward_messages
15
+ - recall_own_message
16
+ scopes:
17
+ - private
18
+ - group
19
+ ---
20
+ # icqq-messages
21
+
22
+ Only use real message IDs from the current conversation. Do not invent IDs, source authors or forwarded content. The tools resolve the originals and send through the unified outbound pipeline. Cross-conversation forwarding is not supported.
23
+
24
+ `quote_reply` sends a text reply quoting one original; `forward_messages` sends a merged forward of the supplied originals. Use `inspect_conversation_reference` to read an incoming quote/forward when available; it does not send messages.
25
+
26
+ `recall_own_message` needs no management role or per-call approval, including when the bot is an ordinary group member. It verifies the bot authored the message. The platform decides the recall time window; never promise success before receiving confirmation or retry an unconfirmed result automatically. To recall another member's message, load `icqq-group-admin` instead.
27
+
28
+ These tools currently support QQ private/group conversations, not guild channels. A failed or suppressed outbound receipt is not a delivered message.
@@ -0,0 +1,42 @@
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, resolveMessage, sendToConversation } from '../../../../conversation.js';
5
+ import { messages as t } from '../../../../messages.js';
6
+ export default defineAgentTool({
7
+ description: '将当前 QQ 群或私聊中的真实消息合并转发到本会话;保留真实作者和内容,不支持跨会话转发',
8
+ adapter: 'icqq',
9
+ scopes: ['private', 'group'],
10
+ requiresApproval: 'never',
11
+ inputSchema: z.object({ message_ids: z.array(z.string().min(1)).min(1).describe('当前会话的真实消息 ID,按转发顺序排列') }),
12
+ async execute({ message_ids }, context) {
13
+ const conversation = currentConversation(context);
14
+ if (conversation.kind === 'channel')
15
+ throw new Error(t(context.locale, 'channelOperationUnsupported'));
16
+ const originals = [];
17
+ for (const id of message_ids)
18
+ originals.push(await resolveMessage(context, id));
19
+ const client = context.$client;
20
+ const target = conversation.kind === 'group' ? client.pickGroup(Number(conversation.id))
21
+ : conversation.parent?.kind === 'group' ? client.pickMember(Number(conversation.parent.id), Number(conversation.id))
22
+ : client.pickFriend(Number(conversation.id));
23
+ // SDK preparation uploads a resource; only the gateway below delivers a message.
24
+ const card = await target.makeForwardMsg(originals.map(message => ({
25
+ user_id: message.sender.user_id,
26
+ nickname: message.sender.nickname,
27
+ time: message.time,
28
+ message: message.message,
29
+ })));
30
+ context.signal.throwIfAborted();
31
+ const data = typeof card.data === 'string' ? JSON.parse(card.data) : card.data;
32
+ const detail = data?.meta?.detail;
33
+ if (typeof detail?.resid !== 'string' || !detail.resid || typeof detail.uniseq !== 'string' || !detail.uniseq) {
34
+ throw new Error('ICQQ did not return a complete merged-forward resource');
35
+ }
36
+ return sendToConversation(context, {
37
+ type: 'forward',
38
+ data: { forward_id: detail.resid },
39
+ platform: { icqqForwardFilename: detail.uniseq },
40
+ });
41
+ },
42
+ });
@@ -0,0 +1,40 @@
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
+ import { z } from 'zod';
3
+ import { currentConversation, resolveMessage, sendToConversation } from '../../../../conversation.js';
4
+ import { messages as t } from '../../../../messages.js';
5
+
6
+ export default defineAgentTool({
7
+ description: '将当前 QQ 群或私聊中的真实消息合并转发到本会话;保留真实作者和内容,不支持跨会话转发',
8
+ adapter: 'icqq',
9
+ scopes: ['private', 'group'],
10
+ requiresApproval: 'never',
11
+ inputSchema: z.object({ message_ids: z.array(z.string().min(1)).min(1).describe('当前会话的真实消息 ID,按转发顺序排列') }),
12
+ async execute({ message_ids }, context) {
13
+ const conversation = currentConversation(context);
14
+ if (conversation.kind === 'channel') throw new Error(t(context.locale, 'channelOperationUnsupported'));
15
+ const originals = [];
16
+ for (const id of message_ids) originals.push(await resolveMessage(context, id));
17
+ const client = context.$client;
18
+ const target = conversation.kind === 'group' ? client.pickGroup(Number(conversation.id))
19
+ : conversation.parent?.kind === 'group' ? client.pickMember(Number(conversation.parent.id), Number(conversation.id))
20
+ : client.pickFriend(Number(conversation.id));
21
+ // SDK preparation uploads a resource; only the gateway below delivers a message.
22
+ const card = await target.makeForwardMsg(originals.map(message => ({
23
+ user_id: message.sender.user_id,
24
+ nickname: message.sender.nickname,
25
+ time: message.time,
26
+ message: message.message,
27
+ })));
28
+ context.signal.throwIfAborted();
29
+ const data = typeof card.data === 'string' ? JSON.parse(card.data) : card.data;
30
+ const detail = data?.meta?.detail;
31
+ if (typeof detail?.resid !== 'string' || !detail.resid || typeof detail.uniseq !== 'string' || !detail.uniseq) {
32
+ throw new Error('ICQQ did not return a complete merged-forward resource');
33
+ }
34
+ return sendToConversation(context, {
35
+ type: 'forward',
36
+ data: { forward_id: detail.resid },
37
+ platform: { icqqForwardFilename: detail.uniseq },
38
+ });
39
+ },
40
+ });
@@ -0,0 +1,24 @@
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 { resolveMessage, sendToConversation } from '../../../../conversation.js';
5
+ export default defineAgentTool({
6
+ description: '引用当前 QQ 群或私聊中的真实消息并回复文字;无需群管角色,发送走统一链路',
7
+ adapter: 'icqq',
8
+ scopes: ['private', 'group'],
9
+ requiresApproval: 'never',
10
+ inputSchema: z.object({
11
+ message_id: z.string().min(1).describe('当前会话中真实的原消息 ID'),
12
+ text: z.string().min(1).describe('本次回复的文字'),
13
+ }),
14
+ async execute({ message_id, text }, context) {
15
+ const original = await resolveMessage(context, message_id);
16
+ return sendToConversation(context, [
17
+ { type: 'reply', data: { message_id }, platform: { icqqQuote: {
18
+ user_id: original.sender.user_id, seq: original.seq, rand: original.rand,
19
+ time: original.time, message: original.raw_message,
20
+ } } },
21
+ { type: 'text', data: { text } },
22
+ ]);
23
+ },
24
+ });
@@ -0,0 +1,24 @@
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
+ import { z } from 'zod';
3
+ import { resolveMessage, sendToConversation } from '../../../../conversation.js';
4
+
5
+ export default defineAgentTool({
6
+ description: '引用当前 QQ 群或私聊中的真实消息并回复文字;无需群管角色,发送走统一链路',
7
+ adapter: 'icqq',
8
+ scopes: ['private', 'group'],
9
+ requiresApproval: 'never',
10
+ inputSchema: z.object({
11
+ message_id: z.string().min(1).describe('当前会话中真实的原消息 ID'),
12
+ text: z.string().min(1).describe('本次回复的文字'),
13
+ }),
14
+ async execute({ message_id, text }, context) {
15
+ const original = await resolveMessage(context, message_id);
16
+ return sendToConversation(context, [
17
+ { type: 'reply', data: { message_id }, platform: { icqqQuote: {
18
+ user_id: original.sender.user_id, seq: original.seq, rand: original.rand,
19
+ time: original.time, message: original.raw_message,
20
+ } } },
21
+ { type: 'text', data: { text } },
22
+ ]);
23
+ },
24
+ });
@@ -0,0 +1,18 @@
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 { recallMessage, resolveMessage } from '../../../../conversation.js';
5
+ import { messages as t } from '../../../../messages.js';
6
+ export default defineAgentTool({
7
+ description: '撤回机器人在当前 QQ 群或私聊中自己的发言;无需群管角色或逐次审批,时限由平台决定',
8
+ adapter: 'icqq',
9
+ scopes: ['private', 'group'],
10
+ requiresApproval: 'never',
11
+ inputSchema: z.object({ message_id: z.string().min(1).describe('机器人在当前会话中发送的真实消息 ID') }),
12
+ async execute({ message_id }, context) {
13
+ const message = await resolveMessage(context, message_id);
14
+ if (message.sender.user_id !== context.$client.uin)
15
+ return { success: false, message: t(context.locale, 'ownMessageRequired') };
16
+ return recallMessage(context, message_id);
17
+ },
18
+ });
@@ -0,0 +1,17 @@
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
+ import { z } from 'zod';
3
+ import { recallMessage, resolveMessage } from '../../../../conversation.js';
4
+ import { messages as t } from '../../../../messages.js';
5
+
6
+ export default defineAgentTool({
7
+ description: '撤回机器人在当前 QQ 群或私聊中自己的发言;无需群管角色或逐次审批,时限由平台决定',
8
+ adapter: 'icqq',
9
+ scopes: ['private', 'group'],
10
+ requiresApproval: 'never',
11
+ inputSchema: z.object({ message_id: z.string().min(1).describe('机器人在当前会话中发送的真实消息 ID') }),
12
+ async execute({ message_id }, context) {
13
+ const message = await resolveMessage(context, message_id);
14
+ if (message.sender.user_id !== context.$client.uin) return { success: false, message: t(context.locale, 'ownMessageRequired') };
15
+ return recallMessage(context, message_id);
16
+ },
17
+ });
@@ -1,3 +1,7 @@
1
1
  # ICQQ Platform Agent
2
2
 
3
3
  You are the icqq platform specialist. Interpret requests in the current icqq conversation and load only the narrowest private Skill needed for the task.
4
+
5
+ For your own group/guild role, current scene information or platform permissions, load `icqq-conversation` and query `conversation_info`. Sender roles describe the requester, not you. Do not infer your role from old session summaries or another endpoint account.
6
+
7
+ For quoting, forwarding or recalling your own speech, load `icqq-messages`. Your own-message recall needs no group management role or per-call approval. For recalling another member's message or leaving a group, load `icqq-group-admin` and follow the tool-specific rules; only leaving requires fresh approval. All these message tools are restricted to the current conversation. Guild-channel limitations are explicit in `conversation_info`.
@@ -1,4 +1,5 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { messages as t } from "../../../lib/i18n.js";
2
3
  import { createEndpointCommands, endpointConfigurationStoreToken } from 'zhin.js/adapter';
3
4
  import { defineCommand } from 'zhin.js/command';
4
5
  import { icqqRuntimeStateToken } from "../../../lib/icqq-runtime-state.js";
@@ -6,14 +7,16 @@ export const icqqEndpointCommands = createEndpointCommands({
6
7
  adapterKey: 'icqq',
7
8
  adapterDisplayName: 'ICQQ',
8
9
  running: (use) => use(icqqRuntimeStateToken).endpoints.values(),
9
- describeEntry: () => 'direct(直连 @icqqjs/icqq)',
10
+ describeEntry: (_entry, locale) => t(locale, 'direct'),
10
11
  addDescription: '登记 ICQQ endpoint(重启 zhin 生效)',
11
- bindFlow: async ({ id, use }) => {
12
+ addDescriptionI18n: { en: 'Register an ICQQ endpoint; restart zhin to apply' },
13
+ bindFlow: async ({ id, use, locale, formatCommand }) => {
12
14
  if (!id) {
13
- return '用法:icqq endpoint add <uin>(uin 为纯数字 QQ 号)';
15
+ const command = formatCommand?.('icqq endpoint add');
16
+ return command ? t(locale, 'addUsage', { command }) : t(locale, 'uinRequired');
14
17
  }
15
18
  if (!/^\d+$/.test(id)) {
16
- return 'icqq endpoint 名必须是纯数字 QQ 号(uin)';
19
+ return t(locale, 'uinInvalid');
17
20
  }
18
21
  try {
19
22
  const { filePath } = await use(endpointConfigurationStoreToken).add({
@@ -21,11 +24,10 @@ export const icqqEndpointCommands = createEndpointCommands({
21
24
  entry: { id },
22
25
  environment: {},
23
26
  });
24
- return (`✅ endpoint「${id}」已追加到 ${filePath} 的 plugins.icqq.endpoints。\n` +
25
- `重启 zhin 后生效。`);
27
+ return t(locale, 'endpointAdded', { id, file: filePath });
26
28
  }
27
29
  catch (error) {
28
- return `添加失败:${error instanceof Error ? error.message : String(error)}`;
30
+ return t(locale, 'endpointAddFailed', { error: error instanceof Error ? error.message : String(error) });
29
31
  }
30
32
  },
31
33
  }, defineCommand);
@@ -1,3 +1,4 @@
1
+ import { messages as t } from '../../../src/i18n.js';
1
2
  import { createEndpointCommands, endpointConfigurationStoreToken } from 'zhin.js/adapter';
2
3
  import { defineCommand } from 'zhin.js/command';
3
4
  import { icqqRuntimeStateToken } from '../../../src/icqq-runtime-state.js';
@@ -6,14 +7,16 @@ export const icqqEndpointCommands = createEndpointCommands({
6
7
  adapterKey: 'icqq',
7
8
  adapterDisplayName: 'ICQQ',
8
9
  running: (use) => use(icqqRuntimeStateToken).endpoints.values(),
9
- describeEntry: () => 'direct(直连 @icqqjs/icqq)',
10
+ describeEntry: (_entry, locale) => t(locale, 'direct'),
10
11
  addDescription: '登记 ICQQ endpoint(重启 zhin 生效)',
11
- bindFlow: async ({ id, use }) => {
12
+ addDescriptionI18n: { en: 'Register an ICQQ endpoint; restart zhin to apply' },
13
+ bindFlow: async ({ id, use, locale, formatCommand }) => {
12
14
  if (!id) {
13
- return '用法:icqq endpoint add <uin>(uin 为纯数字 QQ 号)';
15
+ const command = formatCommand?.('icqq endpoint add');
16
+ return command ? t(locale, 'addUsage', { command }) : t(locale, 'uinRequired');
14
17
  }
15
18
  if (!/^\d+$/.test(id)) {
16
- return 'icqq endpoint 名必须是纯数字 QQ 号(uin)';
19
+ return t(locale, 'uinInvalid');
17
20
  }
18
21
  try {
19
22
  const { filePath } = await use(endpointConfigurationStoreToken).add({
@@ -21,12 +24,9 @@ export const icqqEndpointCommands = createEndpointCommands({
21
24
  entry: { id },
22
25
  environment: {},
23
26
  });
24
- return (
25
- `✅ endpoint「${id}」已追加到 ${filePath} 的 plugins.icqq.endpoints。\n` +
26
- `重启 zhin 后生效。`
27
- );
27
+ return t(locale, 'endpointAdded', { id, file: filePath });
28
28
  } catch (error) {
29
- return `添加失败:${error instanceof Error ? error.message : String(error)}`;
29
+ return t(locale, 'endpointAddFailed', { error: error instanceof Error ? error.message : String(error) });
30
30
  }
31
31
  },
32
32
  }, defineCommand);
package/lib/endpoint.d.ts CHANGED
@@ -9,6 +9,7 @@ export interface IcqqEndpointOptions {
9
9
  readonly id: CapabilityId;
10
10
  readonly config: ResolvedIcqqConfig;
11
11
  readonly loginAssist: LoginAssist;
12
+ readonly locale?: import('zhin.js/i18n').Locale;
12
13
  }
13
14
  export declare class IcqqEndpoint extends Endpoint<Client> {
14
15
  #private;