@zhin.js/adapter-icqq 8.0.8 → 8.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +36 -28
- package/adapters/icqq.js +4 -9
- package/adapters/icqq.ts +5 -14
- package/agent/PERMITS.md +2 -0
- package/lib/agent-prompt.js +17 -22
- package/lib/cq-message.d.ts +2 -2
- package/lib/cq-message.js +7 -2
- package/lib/endpoint.d.ts +4 -74
- package/lib/endpoint.js +348 -507
- package/lib/forward-msg.d.ts +7 -8
- package/lib/forward-msg.js +11 -24
- package/lib/icqq-agent-deps.d.ts +3 -15
- package/lib/icqq-agent-deps.js +0 -5
- package/lib/icqq-endpoint-commands.js +4 -13
- package/lib/icqq-guild.d.ts +15 -11
- package/lib/icqq-guild.js +9 -17
- package/lib/icqq-inbound.d.ts +20 -20
- package/lib/icqq-inbound.js +9 -9
- package/lib/icqq-inbox.d.ts +2 -10
- package/lib/index.d.ts +2 -3
- package/lib/index.js +2 -3
- package/lib/outbound-media.d.ts +3 -8
- package/lib/outbound-media.js +3 -8
- package/lib/protocol.d.ts +38 -57
- package/lib/protocol.js +67 -21
- package/lib/types.d.ts +4 -40
- package/lib/types.js +0 -5
- package/package.json +26 -14
- package/plugin.js +6 -1
- package/schema.json +119 -61
- package/src/agent-prompt.ts +17 -22
- package/src/cq-message.ts +7 -2
- package/src/endpoint.ts +359 -600
- package/src/forward-msg.ts +12 -26
- package/src/icqq-agent-deps.ts +3 -17
- package/src/icqq-endpoint-commands.ts +4 -13
- package/src/icqq-guild.ts +16 -25
- package/src/icqq-inbound.ts +26 -26
- package/src/icqq-inbox.ts +2 -10
- package/src/icqqjs-icqq.d.ts +88 -0
- package/src/index.ts +2 -9
- package/src/outbound-media.ts +4 -9
- package/src/protocol.ts +108 -66
- package/src/types.ts +4 -41
- package/tools/announce.js +19 -0
- package/tools/announce.ts +18 -0
- package/tools/essence.js +24 -0
- package/{agent/tools → tools}/essence.ts +8 -8
- package/tools/friend_list.js +20 -0
- package/{agent/tools → tools}/friend_list.ts +7 -7
- package/tools/group_files.js +25 -0
- package/tools/group_files.ts +23 -0
- package/tools/group_invite.js +25 -0
- package/tools/group_invite.ts +22 -0
- package/tools/group_kick.js +28 -0
- package/tools/group_kick.ts +24 -0
- package/tools/group_list.js +21 -0
- package/{agent/tools → tools}/group_list.ts +7 -7
- package/tools/group_sign.js +21 -0
- package/tools/group_sign.ts +19 -0
- package/tools/list_muted.js +20 -0
- package/tools/list_muted.ts +19 -0
- package/tools/poke.js +19 -0
- package/tools/poke.ts +18 -0
- package/tools/send_user_like.js +28 -0
- package/tools/send_user_like.ts +25 -0
- package/tools/set_anonymous.js +23 -0
- package/tools/set_anonymous.ts +21 -0
- package/tools/set_mute.js +26 -0
- package/tools/set_mute.ts +23 -0
- package/tools/set_title.js +27 -0
- package/tools/set_title.ts +24 -0
- package/tools/user_info.js +17 -0
- package/tools/user_info.ts +16 -0
- package/agent/tools/announce.ts +0 -21
- package/agent/tools/group_files.ts +0 -27
- package/agent/tools/group_invite.ts +0 -20
- package/agent/tools/group_sign.ts +0 -19
- package/agent/tools/list_muted.ts +0 -22
- package/agent/tools/poke.ts +0 -20
- package/agent/tools/send_user_like.ts +0 -22
- package/agent/tools/set_anonymous.ts +0 -22
- package/agent/tools/set_title.ts +0 -25
- package/lib/ipc-client.d.ts +0 -73
- package/lib/ipc-client.js +0 -358
- package/src/ipc-client.ts +0 -417
package/schema.json
CHANGED
|
@@ -4,34 +4,75 @@
|
|
|
4
4
|
"additionalProperties": false,
|
|
5
5
|
"properties": {
|
|
6
6
|
"master": {
|
|
7
|
-
"type": [
|
|
8
|
-
"string",
|
|
9
|
-
"number"
|
|
10
|
-
],
|
|
7
|
+
"type": ["string", "number"],
|
|
11
8
|
"description": "框架 master QQ uin(/approve、AI/工具权限);endpoints[i].master 可逐项覆盖"
|
|
12
9
|
},
|
|
13
10
|
"trusted": {
|
|
14
11
|
"type": "array",
|
|
15
|
-
"items": {
|
|
16
|
-
"type": [
|
|
17
|
-
"string",
|
|
18
|
-
"number"
|
|
19
|
-
],
|
|
20
|
-
"description": "Trusted QQ uin"
|
|
21
|
-
},
|
|
12
|
+
"items": { "type": ["string", "number"] },
|
|
22
13
|
"description": "框架 trusted QQ uin 列表(弱于 master)"
|
|
23
14
|
},
|
|
15
|
+
"password": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "QQ 密码(可选,不填则扫码登录)"
|
|
18
|
+
},
|
|
19
|
+
"platform": {
|
|
20
|
+
"type": "number",
|
|
21
|
+
"enum": [1, 2, 3, 4, 5, 6, 7],
|
|
22
|
+
"default": 1,
|
|
23
|
+
"description": "登录设备平台:1=Android, 2=aPad, 3=Watch, 4=iMac, 5=iPad, 6=Tim, 7=Custom"
|
|
24
|
+
},
|
|
25
|
+
"ver": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "协议版本号,仅在对应 platform 有多个版本时有效,不填则使用最新版本"
|
|
28
|
+
},
|
|
29
|
+
"signApiAddr": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "签名服务器地址;未配置时若安装了 @icqqjs/qqsign 则自动使用本地签名"
|
|
32
|
+
},
|
|
33
|
+
"dataDir": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "数据存储文件夹路径,默认为主模块下的 data 文件夹"
|
|
36
|
+
},
|
|
24
37
|
"autoReconnect": {
|
|
25
38
|
"type": "boolean",
|
|
26
|
-
"default": true
|
|
39
|
+
"default": true,
|
|
40
|
+
"description": "断线后是否自动重连(默认 true)"
|
|
27
41
|
},
|
|
28
42
|
"outboundMedia": {
|
|
29
43
|
"type": "string",
|
|
30
|
-
"enum": [
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
"enum": ["file", "base64"],
|
|
45
|
+
"default": "file",
|
|
46
|
+
"description": "出站媒体模式:file=落盘本地路径(默认); base64=CQ base64:// 内联"
|
|
47
|
+
},
|
|
48
|
+
"ignoreSelf": {
|
|
49
|
+
"type": "boolean",
|
|
50
|
+
"default": true,
|
|
51
|
+
"description": "群聊和频道中是否过滤自己的消息(默认 true)"
|
|
52
|
+
},
|
|
53
|
+
"resend": {
|
|
54
|
+
"type": "boolean",
|
|
55
|
+
"default": false,
|
|
56
|
+
"description": "被风控时是否尝试用分片发送(默认 false)"
|
|
57
|
+
},
|
|
58
|
+
"cacheGroupMember": {
|
|
59
|
+
"type": "boolean",
|
|
60
|
+
"default": true,
|
|
61
|
+
"description": "是否缓存群员列表(默认 true);群多时(500+)会多占约 100MB+ 内存"
|
|
62
|
+
},
|
|
63
|
+
"autoServer": {
|
|
64
|
+
"type": "boolean",
|
|
65
|
+
"default": true,
|
|
66
|
+
"description": "是否自动选择最优服务器(默认 true)"
|
|
67
|
+
},
|
|
68
|
+
"qqnt": {
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"default": true,
|
|
71
|
+
"description": "是否使用 QQNT 协议(默认 true)"
|
|
72
|
+
},
|
|
73
|
+
"ntLogin": {
|
|
74
|
+
"type": "boolean",
|
|
75
|
+
"description": "是否使用 NT 登录方式"
|
|
35
76
|
},
|
|
36
77
|
"endpoints": {
|
|
37
78
|
"type": "array",
|
|
@@ -40,65 +81,82 @@
|
|
|
40
81
|
"type": "object",
|
|
41
82
|
"additionalProperties": true,
|
|
42
83
|
"properties": {
|
|
84
|
+
"id": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"description": "QQ uin"
|
|
87
|
+
},
|
|
43
88
|
"master": {
|
|
44
|
-
"type": [
|
|
45
|
-
|
|
46
|
-
"number"
|
|
47
|
-
],
|
|
48
|
-
"description": "本 endpoint 的框架 master QQ uin;覆盖顶层 master"
|
|
89
|
+
"type": ["string", "number"],
|
|
90
|
+
"description": "本 endpoint 的 master QQ uin;覆盖顶层 master"
|
|
49
91
|
},
|
|
50
92
|
"trusted": {
|
|
51
93
|
"type": "array",
|
|
52
|
-
"items": {
|
|
53
|
-
"type": [
|
|
54
|
-
"string",
|
|
55
|
-
"number"
|
|
56
|
-
],
|
|
57
|
-
"description": "Trusted QQ uin"
|
|
58
|
-
},
|
|
94
|
+
"items": { "type": ["string", "number"] },
|
|
59
95
|
"description": "本 endpoint 的 trusted 列表"
|
|
60
96
|
},
|
|
61
|
-
"
|
|
62
|
-
"type": "
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"port": {
|
|
70
|
-
"type": "number",
|
|
71
|
-
"description": "RPC port"
|
|
72
|
-
},
|
|
73
|
-
"token": {
|
|
74
|
-
"type": "string",
|
|
75
|
-
"description": "RPC token"
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
"required": [
|
|
79
|
-
"host",
|
|
80
|
-
"port",
|
|
81
|
-
"token"
|
|
82
|
-
]
|
|
97
|
+
"password": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "本 endpoint 的 QQ 密码"
|
|
100
|
+
},
|
|
101
|
+
"platform": {
|
|
102
|
+
"type": "number",
|
|
103
|
+
"enum": [1, 2, 3, 4, 5, 6, 7],
|
|
104
|
+
"description": "登录设备平台:1=Android, 2=aPad, 3=Watch, 4=iMac, 5=iPad, 6=Tim, 7=Custom"
|
|
83
105
|
},
|
|
84
|
-
"
|
|
106
|
+
"ver": {
|
|
107
|
+
"type": "string",
|
|
108
|
+
"description": "协议版本号"
|
|
109
|
+
},
|
|
110
|
+
"signApiAddr": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"description": "签名服务器地址"
|
|
113
|
+
},
|
|
114
|
+
"dataDir": {
|
|
85
115
|
"type": "string",
|
|
86
|
-
"description": "
|
|
116
|
+
"description": "数据存储文件夹路径"
|
|
117
|
+
},
|
|
118
|
+
"autoReconnect": {
|
|
119
|
+
"type": "boolean",
|
|
120
|
+
"description": "断线后是否自动重连"
|
|
121
|
+
},
|
|
122
|
+
"outboundMedia": {
|
|
123
|
+
"type": "string",
|
|
124
|
+
"enum": ["file", "base64"],
|
|
125
|
+
"description": "出站媒体模式"
|
|
126
|
+
},
|
|
127
|
+
"ignoreSelf": {
|
|
128
|
+
"type": "boolean",
|
|
129
|
+
"description": "是否过滤自己的消息"
|
|
130
|
+
},
|
|
131
|
+
"resend": {
|
|
132
|
+
"type": "boolean",
|
|
133
|
+
"description": "被风控时是否分片发送"
|
|
134
|
+
},
|
|
135
|
+
"cacheGroupMember": {
|
|
136
|
+
"type": "boolean",
|
|
137
|
+
"description": "是否缓存群员列表"
|
|
138
|
+
},
|
|
139
|
+
"autoServer": {
|
|
140
|
+
"type": "boolean",
|
|
141
|
+
"description": "是否自动选择最优服务器"
|
|
142
|
+
},
|
|
143
|
+
"qqnt": {
|
|
144
|
+
"type": "boolean",
|
|
145
|
+
"description": "是否使用 QQNT 协议"
|
|
146
|
+
},
|
|
147
|
+
"ntLogin": {
|
|
148
|
+
"type": "boolean",
|
|
149
|
+
"description": "是否使用 NT 登录方式"
|
|
87
150
|
}
|
|
88
151
|
},
|
|
89
|
-
"required": [
|
|
90
|
-
"id"
|
|
91
|
-
]
|
|
152
|
+
"required": ["id"]
|
|
92
153
|
}
|
|
93
154
|
},
|
|
94
155
|
"commandPrefix": {
|
|
95
156
|
"type": "string",
|
|
96
157
|
"default": "",
|
|
97
|
-
"description": "命令前缀(默认 ''
|
|
158
|
+
"description": "命令前缀(默认 '' 无前缀)。endpoints[i] 可逐项覆盖"
|
|
98
159
|
}
|
|
99
160
|
},
|
|
100
|
-
"required": [
|
|
101
|
-
"master",
|
|
102
|
-
"endpoints"
|
|
103
|
-
]
|
|
161
|
+
"required": ["master", "endpoints"]
|
|
104
162
|
}
|
package/src/agent-prompt.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { filterTools, type AgentTool } from 'zhin.js/ai';
|
|
|
9
9
|
function isIcqqDelegatedTask(query: string, goal: string): boolean {
|
|
10
10
|
const text = `${query} ${goal}`;
|
|
11
11
|
const lower = text.toLowerCase();
|
|
12
|
-
if (/\bicqq\b|
|
|
12
|
+
if (/\bicqq\b|icqq__|send_private_msg|friend\s+send/i.test(text)) return true;
|
|
13
13
|
if (/\bfriend\s+like\b/.test(lower) && /qq|好友|\d{5,}/i.test(text)) return true;
|
|
14
14
|
if (/点赞/.test(text) && /qq|好友|\d{5,}/i.test(text)) return true;
|
|
15
15
|
if (/发消息|发送消息|私聊/.test(text) && /qq|\d{5,}/i.test(text)) return true;
|
|
@@ -23,27 +23,22 @@ function selectIcqqDeferredTools(
|
|
|
23
23
|
maxTools: number,
|
|
24
24
|
): DeferredToolCatalogItem[] {
|
|
25
25
|
const pool = deferredCatalog.filter(
|
|
26
|
-
t => !t.name.startsWith('mcp_filesystem')
|
|
26
|
+
t => !t.name.startsWith('mcp_filesystem')
|
|
27
|
+
&& !t.name.startsWith('mcp_memory_')
|
|
28
|
+
&& !t.name.startsWith('mcp_icqq_'),
|
|
27
29
|
);
|
|
28
|
-
const
|
|
29
|
-
const icqqTools = pool.filter(t => t.name.startsWith('icqq_'));
|
|
30
|
+
const icqqTools = pool.filter(t => t.name.startsWith('icqq__') || t.name.startsWith('icqq_'));
|
|
30
31
|
const pinned: DeferredToolCatalogItem[] = [];
|
|
31
|
-
const bash = pool.find(t => t.name === 'bash');
|
|
32
|
-
if (bash) pinned.push(bash);
|
|
33
32
|
const preferOrder = [
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'icqq_friend_list',
|
|
38
|
-
'icqq_poke',
|
|
33
|
+
'icqq__send_user_like',
|
|
34
|
+
'icqq__friend_list',
|
|
35
|
+
'icqq__poke',
|
|
39
36
|
];
|
|
40
37
|
for (const name of preferOrder) {
|
|
41
|
-
const t =
|
|
42
|
-
icqqMcpTools.find(x => x.name === name) ??
|
|
43
|
-
icqqTools.find(x => x.name === name);
|
|
38
|
+
const t = icqqTools.find(x => x.name === name);
|
|
44
39
|
if (t) pinned.push(t);
|
|
45
40
|
}
|
|
46
|
-
for (const t of
|
|
41
|
+
for (const t of icqqTools) {
|
|
47
42
|
if (pinned.length >= maxTools) break;
|
|
48
43
|
if (!pinned.some(p => p.name === t.name)) pinned.push(t);
|
|
49
44
|
}
|
|
@@ -61,16 +56,16 @@ function selectIcqqDeferredTools(
|
|
|
61
56
|
}
|
|
62
57
|
|
|
63
58
|
const ORCHESTRATOR_ICQQ = [
|
|
64
|
-
'On icqq/QQ:
|
|
65
|
-
'
|
|
66
|
-
'
|
|
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.',
|
|
67
63
|
].join('\n');
|
|
68
64
|
|
|
69
65
|
const WORKER_ICQQ = [
|
|
70
|
-
'
|
|
71
|
-
'
|
|
72
|
-
'
|
|
73
|
-
'Do NOT use mcp_filesystem_* or explore node_modules / package.json to "discover" 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`.',
|
|
74
69
|
'Do not stop at --help; execute the action the goal describes.',
|
|
75
70
|
].map(line => `- ${line}`).join('\n');
|
|
76
71
|
|
package/src/cq-message.ts
CHANGED
|
@@ -83,6 +83,9 @@ function pushCqSegment(segments: MessageSegment[], type: string, arg: string): v
|
|
|
83
83
|
case "reply":
|
|
84
84
|
segments.push({ type: "reply", data: { message_id: arg } });
|
|
85
85
|
break;
|
|
86
|
+
case "json":
|
|
87
|
+
segments.push({ type: "json", data: { text: arg } });
|
|
88
|
+
break;
|
|
86
89
|
default:
|
|
87
90
|
segments.push({ type, data: { text: `[${type}:${arg}]` } });
|
|
88
91
|
break;
|
|
@@ -125,8 +128,8 @@ export function parseCqMessage(raw: string): MessageSegment[] {
|
|
|
125
128
|
return segments.length ? segments : [{ type: "text", data: { text: raw } }];
|
|
126
129
|
}
|
|
127
130
|
|
|
128
|
-
/** 构建 icqq
|
|
129
|
-
export function
|
|
131
|
+
/** 构建 icqq send_*_msg 的 message 字符串(非空) */
|
|
132
|
+
export function buildIcqqMessage(content: SendContent): string {
|
|
130
133
|
let message = toCqString(content).trim();
|
|
131
134
|
if (!message) message = "\u200b";
|
|
132
135
|
return message;
|
|
@@ -167,6 +170,8 @@ export function toCqString(content: SendContent): string {
|
|
|
167
170
|
}
|
|
168
171
|
case "reply":
|
|
169
172
|
return `[reply:${data.message_id ?? data.id}]`;
|
|
173
|
+
case "json":
|
|
174
|
+
return `[json:${data.text ?? ''}]`;
|
|
170
175
|
default:
|
|
171
176
|
return segment.toString(seg);
|
|
172
177
|
}
|