@zhin.js/adapter-icqq 9.0.0 → 9.0.1

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 (55) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +82 -3
  3. package/adapters/icqq.js +1 -3
  4. package/adapters/icqq.ts +2 -8
  5. package/agent/prompt-sections/platform.ts +17 -0
  6. package/lib/client.d.ts +19 -0
  7. package/lib/client.js +3 -0
  8. package/lib/endpoint.d.ts +9 -6
  9. package/lib/endpoint.js +232 -83
  10. package/lib/icqq-endpoint-commands.d.ts +1 -1
  11. package/lib/index.d.ts +1 -1
  12. package/lib/index.js +1 -1
  13. package/package.json +21 -14
  14. package/plugin.js +1 -24
  15. package/src/client.ts +29 -0
  16. package/src/endpoint.ts +236 -85
  17. package/src/index.ts +4 -6
  18. package/tools/announce.js +3 -6
  19. package/tools/announce.ts +4 -7
  20. package/tools/essence.js +5 -7
  21. package/tools/essence.ts +6 -8
  22. package/tools/friend_list.js +6 -9
  23. package/tools/friend_list.ts +7 -10
  24. package/tools/group_files.js +3 -6
  25. package/tools/group_files.ts +4 -7
  26. package/tools/group_invite.js +6 -8
  27. package/tools/group_invite.ts +7 -9
  28. package/tools/group_kick.js +6 -8
  29. package/tools/group_kick.ts +7 -9
  30. package/tools/group_list.js +7 -10
  31. package/tools/group_list.ts +8 -11
  32. package/tools/group_member_info.js +3 -6
  33. package/tools/group_member_info.ts +3 -7
  34. package/tools/group_sign.js +5 -7
  35. package/tools/group_sign.ts +6 -8
  36. package/tools/list_muted.js +3 -6
  37. package/tools/list_muted.ts +4 -7
  38. package/tools/poke.js +3 -6
  39. package/tools/poke.ts +4 -7
  40. package/tools/send_user_like.js +3 -6
  41. package/tools/send_user_like.ts +4 -7
  42. package/tools/set_anonymous.js +5 -7
  43. package/tools/set_anonymous.ts +6 -8
  44. package/tools/set_mute.js +6 -8
  45. package/tools/set_mute.ts +7 -9
  46. package/tools/set_title.js +6 -8
  47. package/tools/set_title.ts +7 -9
  48. package/tools/user_info.js +3 -6
  49. package/tools/user_info.ts +4 -7
  50. package/lib/agent-prompt.d.ts +0 -2
  51. package/lib/agent-prompt.js +0 -97
  52. package/lib/icqq-agent-deps.d.ts +0 -13
  53. package/lib/icqq-agent-deps.js +0 -27
  54. package/src/agent-prompt.ts +0 -110
  55. package/src/icqq-agent-deps.ts +0 -43
@@ -1,23 +1,21 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineAgentTool } from '@zhin.js/tool';
3
3
  import { z } from 'zod';
4
- import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
4
  export default defineAgentTool({
6
5
  description: '开启或关闭 QQ 群的匿名聊天功能',
7
6
  inputSchema: z.object({
8
- endpoint_id: z.string().describe('Endpoint QQ号'),
9
7
  group_id: z.number().describe('目标群号'),
10
8
  enable: z.boolean().optional().describe('true=开启,false=关闭,默认 true'),
11
9
  }),
12
- platforms: ['icqq'],
10
+ adapter: 'icqq',
13
11
  permissions: ['role(master,trusted,owner,admin)'],
14
- async execute({ endpoint_id, group_id, enable }) {
15
- const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
12
+ async execute({ group_id, enable }, context) {
13
+ const client = context.$client;
16
14
  const on = enable ?? true;
17
- const selfInfo = endpoint.pickMember(group_id, endpoint.uin);
15
+ const selfInfo = client.pickMember(group_id, client.uin);
18
16
  if (!selfInfo.is_admin && !selfInfo.is_owner)
19
17
  return { success: false, message: '我不是群主或管理员,无法开启或关闭匿名聊天' };
20
- await endpoint.setGroupAnonymous(group_id, on);
18
+ await client.setGroupAnonymous(group_id, on);
21
19
  return { success: true, message: on ? '已开启匿名聊天' : '已关闭匿名聊天' };
22
20
  },
23
21
  });
@@ -1,21 +1,19 @@
1
1
  import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
- export default defineAgentTool<{ endpoint_id: string; group_id: number; enable?: boolean }>({
3
+ export default defineAgentTool<{ group_id: number; enable?: boolean }>({
5
4
  description: '开启或关闭 QQ 群的匿名聊天功能',
6
5
  inputSchema: z.object({
7
- endpoint_id: z.string().describe('Endpoint QQ号'),
8
6
  group_id: z.number().describe('目标群号'),
9
7
  enable: z.boolean().optional().describe('true=开启,false=关闭,默认 true'),
10
8
  }),
11
- platforms: ['icqq'],
9
+ adapter: 'icqq',
12
10
  permissions: ['role(master,trusted,owner,admin)'],
13
- async execute({ endpoint_id, group_id, enable }: { endpoint_id: string; group_id: number; enable?: boolean }) {
14
- const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
11
+ async execute({ group_id, enable }, context) {
12
+ const client = context.$client;
15
13
  const on = enable ?? true;
16
- const selfInfo= endpoint.pickMember(group_id,endpoint.uin);
14
+ const selfInfo= client.pickMember(group_id,client.uin);
17
15
  if(!selfInfo.is_admin && !selfInfo.is_owner) return { success: false, message: '我不是群主或管理员,无法开启或关闭匿名聊天' };
18
- await endpoint.setGroupAnonymous(group_id, on);
16
+ await client.setGroupAnonymous(group_id, on);
19
17
  return { success: true, message: on ? '已开启匿名聊天' : '已关闭匿名聊天' };
20
18
  },
21
19
  });
package/tools/set_mute.js CHANGED
@@ -1,26 +1,24 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineAgentTool } from '@zhin.js/tool';
3
3
  import { z } from 'zod';
4
- import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
4
  export default defineAgentTool({
6
5
  description: '禁言/解除禁言指定成员',
7
6
  inputSchema: z.object({
8
- endpoint_id: z.string().describe('Endpoint QQ号'),
9
7
  group_id: z.number().describe('目标群号'),
10
8
  user_id: z.number().describe('目标成员 QQ号'),
11
9
  duration: z.number().describe('禁言时间(秒),0=解除禁言').default(0),
12
10
  }),
13
- platforms: ['icqq'],
11
+ adapter: 'icqq',
14
12
  approval: 'always',
15
- async execute({ endpoint_id, group_id, user_id, duration }) {
16
- const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
17
- const selfInfo = endpoint.pickMember(group_id, endpoint.uin);
13
+ async execute({ group_id, user_id, duration }, context) {
14
+ const client = context.$client;
15
+ const selfInfo = client.pickMember(group_id, client.uin);
18
16
  if (!selfInfo.is_admin && !selfInfo.is_owner)
19
17
  return { success: false, message: '我不是群主或管理员,无法禁言/解除禁言成员' };
20
- const memberInfo = endpoint.pickMember(group_id, user_id);
18
+ const memberInfo = client.pickMember(group_id, user_id);
21
19
  if (!memberInfo)
22
20
  return { success: false, message: '目标成员不存在' };
23
- await endpoint.setGroupBan(group_id, user_id, duration === 0 ? 0 : duration);
21
+ await client.setGroupBan(group_id, user_id, duration === 0 ? 0 : duration);
24
22
  return { success: true, message: `已${duration === 0 ? '解除' : ''}禁言 ${user_id} 成员${duration === 0 ? '' : `(${duration}秒)`}` };
25
23
  },
26
24
  });
package/tools/set_mute.ts CHANGED
@@ -1,23 +1,21 @@
1
1
  import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
- export default defineAgentTool<{ endpoint_id: string; group_id: number; user_id: number; duration?: number }>({
3
+ export default defineAgentTool<{ group_id: number; user_id: number; duration?: number }>({
5
4
  description: '禁言/解除禁言指定成员',
6
5
  inputSchema: z.object({
7
- endpoint_id: z.string().describe('Endpoint QQ号'),
8
6
  group_id: z.number().describe('目标群号'),
9
7
  user_id: z.number().describe('目标成员 QQ号'),
10
8
  duration: z.number().describe('禁言时间(秒),0=解除禁言').default(0),
11
9
  }),
12
- platforms: ['icqq'],
10
+ adapter: 'icqq',
13
11
  approval: 'always',
14
- async execute({ endpoint_id, group_id, user_id, duration }: { endpoint_id: string; group_id: number; user_id: number; duration?: number }) {
15
- const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
16
- const selfInfo= endpoint.pickMember(group_id,endpoint.uin);
12
+ async execute({ group_id, user_id, duration }, context) {
13
+ const client = context.$client;
14
+ const selfInfo= client.pickMember(group_id,client.uin);
17
15
  if(!selfInfo.is_admin && !selfInfo.is_owner) return { success: false, message: '我不是群主或管理员,无法禁言/解除禁言成员' };
18
- const memberInfo= endpoint.pickMember(group_id,user_id);
16
+ const memberInfo= client.pickMember(group_id,user_id);
19
17
  if(!memberInfo) return { success: false, message: '目标成员不存在' };
20
- await endpoint.setGroupBan(group_id, user_id, duration === 0 ? 0 : duration);
18
+ await client.setGroupBan(group_id, user_id, duration === 0 ? 0 : duration);
21
19
  return { success: true, message: `已${duration === 0 ? '解除' : ''}禁言 ${user_id} 成员${duration === 0 ? '' : `(${duration}秒)`}` };
22
20
  },
23
21
  });
@@ -1,27 +1,25 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineAgentTool } from '@zhin.js/tool';
3
3
  import { z } from 'zod';
4
- import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
4
  export default defineAgentTool({
6
5
  description: '设置 QQ 群成员的专属头衔',
7
6
  inputSchema: z.object({
8
- endpoint_id: z.string().describe('Endpoint QQ号'),
9
7
  group_id: z.number().describe('目标群号'),
10
8
  user_id: z.number().describe('目标成员 QQ号'),
11
9
  title: z.string().describe('头衔文字'),
12
10
  duration: z.number().optional().describe('持续时间(秒),-1永久').default(-1),
13
11
  }),
14
- platforms: ['icqq'],
12
+ adapter: 'icqq',
15
13
  approval: 'always',
16
- async execute({ endpoint_id, group_id, user_id, title, duration }) {
17
- const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
18
- const selfInfo = endpoint.pickMember(group_id, endpoint.uin);
14
+ async execute({ group_id, user_id, title, duration }, context) {
15
+ const client = context.$client;
16
+ const selfInfo = client.pickMember(group_id, client.uin);
19
17
  if (!selfInfo.is_admin && !selfInfo.is_owner)
20
18
  return { success: false, message: '我不是群主或管理员,无法设置头衔' };
21
- const memberInfo = endpoint.pickMember(group_id, user_id);
19
+ const memberInfo = client.pickMember(group_id, user_id);
22
20
  if (!memberInfo)
23
21
  return { success: false, message: '目标成员不存在' };
24
- await endpoint.setGroupSpecialTitle(group_id, user_id, title, duration ?? -1);
22
+ await client.setGroupSpecialTitle(group_id, user_id, title, duration ?? -1);
25
23
  return { success: true, message: `已将 ${user_id} 的头衔设为 "${title}"` };
26
24
  },
27
25
  });
@@ -1,24 +1,22 @@
1
1
  import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
- export default defineAgentTool<{ endpoint_id: string; group_id: number; user_id: number; title: string; duration?: number }>({
3
+ export default defineAgentTool<{ group_id: number; user_id: number; title: string; duration?: number }>({
5
4
  description: '设置 QQ 群成员的专属头衔',
6
5
  inputSchema: z.object({
7
- endpoint_id: z.string().describe('Endpoint QQ号'),
8
6
  group_id: z.number().describe('目标群号'),
9
7
  user_id: z.number().describe('目标成员 QQ号'),
10
8
  title: z.string().describe('头衔文字'),
11
9
  duration: z.number().optional().describe('持续时间(秒),-1永久').default(-1),
12
10
  }),
13
- platforms: ['icqq'],
11
+ adapter: 'icqq',
14
12
  approval: 'always',
15
- async execute({ endpoint_id, group_id, user_id, title, duration }: { endpoint_id: string; group_id: number; user_id: number; title: string; duration?: number }) {
16
- const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
17
- const selfInfo= endpoint.pickMember(group_id,endpoint.uin);
13
+ async execute({ group_id, user_id, title, duration }, context) {
14
+ const client = context.$client;
15
+ const selfInfo= client.pickMember(group_id,client.uin);
18
16
  if(!selfInfo.is_admin && !selfInfo.is_owner) return { success: false, message: '我不是群主或管理员,无法设置头衔' };
19
- const memberInfo= endpoint.pickMember(group_id,user_id);
17
+ const memberInfo= client.pickMember(group_id,user_id);
20
18
  if(!memberInfo) return { success: false, message: '目标成员不存在' };
21
- await endpoint.setGroupSpecialTitle(group_id, user_id, title, duration ?? -1);
19
+ await client.setGroupSpecialTitle(group_id, user_id, title, duration ?? -1);
22
20
  return { success: true, message: `已将 ${user_id} 的头衔设为 "${title}"` };
23
21
  },
24
22
  });
@@ -1,17 +1,14 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineAgentTool } from '@zhin.js/tool';
3
3
  import { z } from 'zod';
4
- import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
4
  export default defineAgentTool({
6
5
  description: '获取指定QQ号的用户信息/资料/详情',
7
6
  inputSchema: z.object({
8
- endpoint_id: z.string().describe('Endpoint QQ号'),
9
7
  user_id: z.number().describe('目标成员 QQ号'),
10
8
  }),
11
- platforms: ['icqq'],
12
- async execute({ endpoint_id, user_id }) {
13
- const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
14
- const profile = await endpoint.getProfile(user_id);
9
+ adapter: 'icqq',
10
+ async execute({ user_id }, context) {
11
+ const profile = await context.$client.getProfile(user_id);
15
12
  return { success: true, message: `已获取 ${user_id} 的用户信息:${JSON.stringify(profile, null, 2)}` };
16
13
  },
17
14
  });
@@ -1,16 +1,13 @@
1
1
  import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
- export default defineAgentTool<{ endpoint_id: string; user_id: number }>({
3
+ export default defineAgentTool<{ user_id: number }>({
5
4
  description: '获取指定QQ号的用户信息/资料/详情',
6
5
  inputSchema: z.object({
7
- endpoint_id: z.string().describe('Endpoint QQ号'),
8
6
  user_id: z.number().describe('目标成员 QQ号'),
9
7
  }),
10
- platforms: ['icqq'],
11
- async execute({ endpoint_id, user_id }: { endpoint_id: string; user_id: number }) {
12
- const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
13
- const profile = await endpoint.getProfile(user_id);
8
+ adapter: 'icqq',
9
+ async execute({ user_id }, context) {
10
+ const profile = await context.$client.getProfile(user_id);
14
11
  return { success: true, message: `已获取 ${user_id} 的用户信息:${JSON.stringify(profile,null,2)}` };
15
12
  },
16
13
  });
@@ -1,2 +0,0 @@
1
- import type { AgentPromptContributor } from 'zhin.js';
2
- export declare function createIcqqAgentPromptContributor(): AgentPromptContributor;
@@ -1,97 +0,0 @@
1
- import { filterTools } from 'zhin.js/ai';
2
- function isIcqqDelegatedTask(query, goal) {
3
- const text = `${query} ${goal}`;
4
- const lower = text.toLowerCase();
5
- if (/\bicqq\b|icqq__|send_private_msg|friend\s+send/i.test(text))
6
- return true;
7
- if (/\bfriend\s+like\b/.test(lower) && /qq|好友|\d{5,}/i.test(text))
8
- return true;
9
- if (/点赞/.test(text) && /qq|好友|\d{5,}/i.test(text))
10
- return true;
11
- if (/发消息|发送消息|私聊/.test(text) && /qq|\d{5,}/i.test(text))
12
- return true;
13
- return false;
14
- }
15
- function selectIcqqDeferredTools(query, goal, deferredCatalog, maxTools) {
16
- const pool = deferredCatalog.filter(t => !t.name.startsWith('mcp_filesystem')
17
- && !t.name.startsWith('mcp_memory_')
18
- && !t.name.startsWith('mcp_icqq_'));
19
- const icqqTools = pool.filter(t => t.name.startsWith('icqq__') || t.name.startsWith('icqq_'));
20
- const pinned = [];
21
- const preferOrder = [
22
- 'icqq__send_user_like',
23
- 'icqq__friend_list',
24
- 'icqq__poke',
25
- ];
26
- for (const name of preferOrder) {
27
- const t = icqqTools.find(x => x.name === name);
28
- if (t)
29
- pinned.push(t);
30
- }
31
- for (const t of icqqTools) {
32
- if (pinned.length >= maxTools)
33
- break;
34
- if (!pinned.some(p => p.name === t.name))
35
- pinned.push(t);
36
- }
37
- const extra = filterTools(query, pool, { maxTools, minScore: 0.08 })
38
- .map((t) => ({ name: t.name, description: t.description }))
39
- .filter(t => !pinned.some(p => p.name === t.name));
40
- const merged = [...pinned];
41
- for (const t of extra) {
42
- if (merged.length >= maxTools)
43
- break;
44
- merged.push(t);
45
- }
46
- return merged.slice(0, maxTools);
47
- }
48
- const ORCHESTRATOR_ICQQ = [
49
- 'On icqq/QQ: if icqq__send_user_like is in your tool list, call it now with { endpoint_id, user_id, times }.',
50
- 'endpoint_id is this bot QQ (Session endpoint). user_id is the sender to like. times is 1-20.',
51
- 'Do not tell the user the tool is missing until you have called it this turn (or load_tool("icqq__send_user_like") failed).',
52
- 'Ignore prior turns that said the like tool was unavailable. Other social tools: icqq__poke, icqq__friend_list.',
53
- ].join('\n');
54
- const WORKER_ICQQ = [
55
- 'Friend like: load_tool("icqq__send_user_like") then call with { endpoint_id, user_id, times }. endpoint_id is this bot QQ (origin.endpoint).',
56
- 'Poke: icqq__poke. Friend list: icqq__friend_list.',
57
- 'Do NOT use mcp_icqq_*, mcp_filesystem_*, or bash `icqq friend like`.',
58
- 'Do not stop at --help; execute the action the goal describes.',
59
- ].map(line => `- ${line}`).join('\n');
60
- export function createIcqqAgentPromptContributor() {
61
- return {
62
- platform: 'icqq',
63
- async buildSections(ctx) {
64
- if (ctx.slot === 'orchestrator') {
65
- return [{
66
- id: 'platform.icqq.orchestrator',
67
- title: '## icqq / QQ',
68
- body: ORCHESTRATOR_ICQQ,
69
- priority: 50,
70
- }];
71
- }
72
- if (ctx.slot === 'deferred_worker') {
73
- const query = ctx.deferred?.toolQuery ?? ctx.deferred?.goal ?? '';
74
- const goal = ctx.deferred?.goal ?? '';
75
- if (!isIcqqDelegatedTask(query, goal))
76
- return null;
77
- return [{
78
- id: 'platform.icqq.deferred_worker',
79
- title: '## icqq / QQ(本任务)',
80
- body: WORKER_ICQQ,
81
- priority: 50,
82
- }];
83
- }
84
- return null;
85
- },
86
- matchesDeferredTask(ctx) {
87
- const query = ctx.deferred?.toolQuery ?? ctx.deferred?.goal ?? ctx.userMessagePreview ?? '';
88
- const goal = ctx.deferred?.goal ?? ctx.userMessagePreview ?? '';
89
- return isIcqqDelegatedTask(query, goal);
90
- },
91
- selectDeferredTools(query, goal, catalog, maxTools) {
92
- if (!isIcqqDelegatedTask(query, goal))
93
- return null;
94
- return selectIcqqDeferredTools(query, goal, catalog, maxTools);
95
- },
96
- };
97
- }
@@ -1,13 +0,0 @@
1
- import type { Client } from '@icqqjs/icqq';
2
- export interface IcqqAgentEndpoint extends Client {
3
- readonly endpointName: string;
4
- }
5
- export interface IcqqAgentDeps {
6
- getEndpoint: (endpointKey: string) => IcqqAgentEndpoint;
7
- getAdapter?: () => {
8
- getEndpoint: (id: string) => IcqqAgentEndpoint;
9
- };
10
- }
11
- export declare function registerIcqqAgentEndpoint(endpointKey: string, endpoint: IcqqAgentEndpoint): () => void;
12
- export declare function setIcqqAgentDeps(deps: IcqqAgentDeps | null): void;
13
- export declare function getIcqqAgentDeps(): IcqqAgentDeps;
@@ -1,27 +0,0 @@
1
- const endpoints = new Map();
2
- let override = null;
3
- export function registerIcqqAgentEndpoint(endpointKey, endpoint) {
4
- endpoints.set(endpointKey, endpoint);
5
- return () => {
6
- if (endpoints.get(endpointKey) === endpoint) {
7
- endpoints.delete(endpointKey);
8
- }
9
- };
10
- }
11
- export function setIcqqAgentDeps(deps) {
12
- override = deps;
13
- }
14
- function lookup(endpointKey) {
15
- const registered = endpoints.get(endpointKey);
16
- if (!registered)
17
- throw new Error(`Endpoint ${endpointKey} 不存在`);
18
- return registered;
19
- }
20
- export function getIcqqAgentDeps() {
21
- if (override)
22
- return override;
23
- return {
24
- getEndpoint: lookup,
25
- getAdapter: () => ({ getEndpoint: lookup }),
26
- };
27
- }
@@ -1,110 +0,0 @@
1
- import type {
2
- AgentPromptBuildContext,
3
- AgentPromptContributor,
4
- AgentPromptSection,
5
- DeferredToolCatalogItem,
6
- } from 'zhin.js';
7
- import { filterTools, type AgentTool } from 'zhin.js/ai';
8
-
9
- function isIcqqDelegatedTask(query: string, goal: string): boolean {
10
- const text = `${query} ${goal}`;
11
- const lower = text.toLowerCase();
12
- if (/\bicqq\b|icqq__|send_private_msg|friend\s+send/i.test(text)) return true;
13
- if (/\bfriend\s+like\b/.test(lower) && /qq|好友|\d{5,}/i.test(text)) return true;
14
- if (/点赞/.test(text) && /qq|好友|\d{5,}/i.test(text)) return true;
15
- if (/发消息|发送消息|私聊/.test(text) && /qq|\d{5,}/i.test(text)) return true;
16
- return false;
17
- }
18
-
19
- function selectIcqqDeferredTools(
20
- query: string,
21
- goal: string,
22
- deferredCatalog: DeferredToolCatalogItem[],
23
- maxTools: number,
24
- ): DeferredToolCatalogItem[] {
25
- const pool = deferredCatalog.filter(
26
- t => !t.name.startsWith('mcp_filesystem')
27
- && !t.name.startsWith('mcp_memory_')
28
- && !t.name.startsWith('mcp_icqq_'),
29
- );
30
- const icqqTools = pool.filter(t => t.name.startsWith('icqq__') || t.name.startsWith('icqq_'));
31
- const pinned: DeferredToolCatalogItem[] = [];
32
- const preferOrder = [
33
- 'icqq__send_user_like',
34
- 'icqq__friend_list',
35
- 'icqq__poke',
36
- ];
37
- for (const name of preferOrder) {
38
- const t = icqqTools.find(x => x.name === name);
39
- if (t) pinned.push(t);
40
- }
41
- for (const t of icqqTools) {
42
- if (pinned.length >= maxTools) break;
43
- if (!pinned.some(p => p.name === t.name)) pinned.push(t);
44
- }
45
-
46
- const extra = filterTools(query, pool as AgentTool[], { maxTools, minScore: 0.08 })
47
- .map((t) => ({ name: t.name, description: t.description }))
48
- .filter(t => !pinned.some(p => p.name === t.name));
49
-
50
- const merged: DeferredToolCatalogItem[] = [...pinned];
51
- for (const t of extra) {
52
- if (merged.length >= maxTools) break;
53
- merged.push(t);
54
- }
55
- return merged.slice(0, maxTools);
56
- }
57
-
58
- const ORCHESTRATOR_ICQQ = [
59
- 'On icqq/QQ: if icqq__send_user_like is in your tool list, call it now with { endpoint_id, user_id, times }.',
60
- 'endpoint_id is this bot QQ (Session endpoint). user_id is the sender to like. times is 1-20.',
61
- 'Do not tell the user the tool is missing until you have called it this turn (or load_tool("icqq__send_user_like") failed).',
62
- 'Ignore prior turns that said the like tool was unavailable. Other social tools: icqq__poke, icqq__friend_list.',
63
- ].join('\n');
64
-
65
- const WORKER_ICQQ = [
66
- 'Friend like: load_tool("icqq__send_user_like") then call with { endpoint_id, user_id, times }. endpoint_id is this bot QQ (origin.endpoint).',
67
- 'Poke: icqq__poke. Friend list: icqq__friend_list.',
68
- 'Do NOT use mcp_icqq_*, mcp_filesystem_*, or bash `icqq friend like`.',
69
- 'Do not stop at --help; execute the action the goal describes.',
70
- ].map(line => `- ${line}`).join('\n');
71
-
72
- export function createIcqqAgentPromptContributor(): AgentPromptContributor {
73
- return {
74
- platform: 'icqq',
75
-
76
- async buildSections(ctx: AgentPromptBuildContext): Promise<AgentPromptSection[] | null> {
77
- if (ctx.slot === 'orchestrator') {
78
- return [{
79
- id: 'platform.icqq.orchestrator',
80
- title: '## icqq / QQ',
81
- body: ORCHESTRATOR_ICQQ,
82
- priority: 50,
83
- }];
84
- }
85
- if (ctx.slot === 'deferred_worker') {
86
- const query = ctx.deferred?.toolQuery ?? ctx.deferred?.goal ?? '';
87
- const goal = ctx.deferred?.goal ?? '';
88
- if (!isIcqqDelegatedTask(query, goal)) return null;
89
- return [{
90
- id: 'platform.icqq.deferred_worker',
91
- title: '## icqq / QQ(本任务)',
92
- body: WORKER_ICQQ,
93
- priority: 50,
94
- }];
95
- }
96
- return null;
97
- },
98
-
99
- matchesDeferredTask(ctx: AgentPromptBuildContext): boolean {
100
- const query = ctx.deferred?.toolQuery ?? ctx.deferred?.goal ?? ctx.userMessagePreview ?? '';
101
- const goal = ctx.deferred?.goal ?? ctx.userMessagePreview ?? '';
102
- return isIcqqDelegatedTask(query, goal);
103
- },
104
-
105
- selectDeferredTools(query, goal, catalog, maxTools) {
106
- if (!isIcqqDelegatedTask(query, goal)) return null;
107
- return selectIcqqDeferredTools(query, goal, catalog, maxTools);
108
- },
109
- };
110
- }
@@ -1,43 +0,0 @@
1
- import type { Client } from '@icqqjs/icqq';
2
-
3
- export interface IcqqAgentEndpoint extends Client {
4
- readonly endpointName: string;
5
- }
6
-
7
- export interface IcqqAgentDeps {
8
- getEndpoint: (endpointKey: string) => IcqqAgentEndpoint;
9
- getAdapter?: () => { getEndpoint: (id: string) => IcqqAgentEndpoint };
10
- }
11
-
12
- const endpoints = new Map<string, IcqqAgentEndpoint>();
13
- let override: IcqqAgentDeps | null = null;
14
-
15
- export function registerIcqqAgentEndpoint(
16
- endpointKey: string,
17
- endpoint: IcqqAgentEndpoint,
18
- ): () => void {
19
- endpoints.set(endpointKey, endpoint);
20
- return () => {
21
- if (endpoints.get(endpointKey) === endpoint) {
22
- endpoints.delete(endpointKey);
23
- }
24
- };
25
- }
26
-
27
- export function setIcqqAgentDeps(deps: IcqqAgentDeps | null): void {
28
- override = deps;
29
- }
30
-
31
- function lookup(endpointKey: string): IcqqAgentEndpoint {
32
- const registered = endpoints.get(endpointKey);
33
- if (!registered) throw new Error(`Endpoint ${endpointKey} 不存在`);
34
- return registered;
35
- }
36
-
37
- export function getIcqqAgentDeps(): IcqqAgentDeps {
38
- if (override) return override;
39
- return {
40
- getEndpoint: lookup,
41
- getAdapter: () => ({ getEndpoint: lookup }),
42
- };
43
- }