@aalis/plugin-tool-onebot 0.9.3 → 0.11.0
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/dist/index.d.ts +14 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +263 -247
- package/dist/index.js.map +1 -1
- package/package.json +17 -9
package/dist/index.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { media } from '@aalis/api-media';
|
|
2
|
+
import { getPlatformAdapters, getPlatformNames, platform as platformService, } from '@aalis/api-platform';
|
|
3
|
+
import { sessionHistory } from '@aalis/api-session-history';
|
|
4
|
+
import { createStorageGateway, storage } from '@aalis/api-storage';
|
|
5
|
+
import { tools, withToolGroups } from '@aalis/api-tools';
|
|
6
|
+
import { config, definePlugin, events, logger, optional } from '@aalis/core';
|
|
4
7
|
// ===== 插件元数据 =====
|
|
5
|
-
|
|
6
|
-
export const displayName = 'OneBot 工具';
|
|
7
|
-
export const subsystem = 'tools';
|
|
8
|
-
export const inject = {
|
|
9
|
-
optional: ['platform', 'session-history'],
|
|
10
|
-
};
|
|
11
|
-
export const configSchema = {
|
|
8
|
+
const configSchema = {
|
|
12
9
|
groupManagement: {
|
|
13
10
|
label: '群管理工具',
|
|
14
11
|
fields: {
|
|
@@ -43,9 +40,9 @@ export const configSchema = {
|
|
|
43
40
|
fields: {
|
|
44
41
|
enabled: {
|
|
45
42
|
type: 'boolean',
|
|
46
|
-
label: '启用 OneBot
|
|
43
|
+
label: '启用 OneBot 专属历史工具',
|
|
47
44
|
default: true,
|
|
48
|
-
description: '
|
|
45
|
+
description: '注册 onebot_resolve_session_id / onebot_get_session_history(按群号/QQ 号读取近期历史)。只管这两个工具:下面的访问规则始终生效,同样约束通用的 session_get_history。',
|
|
49
46
|
},
|
|
50
47
|
maxLimit: {
|
|
51
48
|
type: 'number',
|
|
@@ -86,6 +83,17 @@ export const configSchema = {
|
|
|
86
83
|
},
|
|
87
84
|
},
|
|
88
85
|
};
|
|
86
|
+
// ===== 能力声明 =====
|
|
87
|
+
const uses = {
|
|
88
|
+
tools: optional(tools),
|
|
89
|
+
platform: optional(platformService),
|
|
90
|
+
storage: optional(storage),
|
|
91
|
+
media: optional(media),
|
|
92
|
+
sessionHistory: optional(sessionHistory),
|
|
93
|
+
events,
|
|
94
|
+
logger,
|
|
95
|
+
config,
|
|
96
|
+
};
|
|
89
97
|
// ===== 辅助函数 =====
|
|
90
98
|
/** 从 sessionId 解析 OneBot 连接信息 */
|
|
91
99
|
function parseOneBotSession(sessionId) {
|
|
@@ -98,16 +106,16 @@ function parseOneBotSession(sessionId) {
|
|
|
98
106
|
targetId: parts.slice(3).join(':'),
|
|
99
107
|
};
|
|
100
108
|
}
|
|
101
|
-
/**
|
|
102
|
-
function findOneBotAdapter(
|
|
103
|
-
return getPlatformAdapters(
|
|
109
|
+
/** 在已注册的平台适配器里找出支持 callAction 的 OneBot 适配器 */
|
|
110
|
+
function findOneBotAdapter(platform) {
|
|
111
|
+
return getPlatformAdapters(platform).find(a => a.platform === 'onebot' && typeof a.callAction === 'function');
|
|
104
112
|
}
|
|
105
113
|
/** 从已连接的 OneBot 适配器中找出任意一个 selfId(优先 online) */
|
|
106
|
-
function getAnyOneBotSelfId(
|
|
107
|
-
for (const a of getPlatformAdapters(
|
|
114
|
+
function getAnyOneBotSelfId(platform) {
|
|
115
|
+
for (const a of getPlatformAdapters(platform)) {
|
|
108
116
|
if (a.platform !== 'onebot')
|
|
109
117
|
continue;
|
|
110
|
-
const conns = a.getConnections
|
|
118
|
+
const conns = a.getConnections();
|
|
111
119
|
const online = conns.find(c => c.status === 'online' && c.selfId);
|
|
112
120
|
if (online?.selfId)
|
|
113
121
|
return online.selfId;
|
|
@@ -122,14 +130,14 @@ function getAnyOneBotSelfId(ctx) {
|
|
|
122
130
|
* 优先级:args.self_id → 当前 callCtx 是 OneBot 会话时取它的 selfId → 任意可用 adapter 的第一个 selfId。
|
|
123
131
|
* 找不到则抛错(无可用 OneBot 连接)。
|
|
124
132
|
*/
|
|
125
|
-
function resolveSelfId(
|
|
133
|
+
function resolveSelfId(platform, callCtx, args) {
|
|
126
134
|
const fromArgs = args.self_id != null && String(args.self_id).trim() ? String(args.self_id).trim() : '';
|
|
127
135
|
if (fromArgs)
|
|
128
136
|
return fromArgs;
|
|
129
137
|
const parsed = parseOneBotSession(callCtx.sessionId);
|
|
130
138
|
if (parsed?.selfId)
|
|
131
139
|
return parsed.selfId;
|
|
132
|
-
const fallback = getAnyOneBotSelfId(
|
|
140
|
+
const fallback = getAnyOneBotSelfId(platform);
|
|
133
141
|
if (fallback)
|
|
134
142
|
return fallback;
|
|
135
143
|
throw new Error('未找到可用的 OneBot 连接');
|
|
@@ -138,9 +146,9 @@ function resolveSelfId(ctx, callCtx, args) {
|
|
|
138
146
|
* 解析"目标群":args.group_id 优先;否则当前会话必须在 OneBot 群里。
|
|
139
147
|
* 不再限制工具必须在群会话上下文中调用。
|
|
140
148
|
*/
|
|
141
|
-
function resolveGroupTarget(
|
|
149
|
+
function resolveGroupTarget(platform, callCtx, args) {
|
|
142
150
|
const argGroupId = args.group_id != null && String(args.group_id).trim() ? String(args.group_id).trim() : '';
|
|
143
|
-
const selfId = resolveSelfId(
|
|
151
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
144
152
|
if (argGroupId)
|
|
145
153
|
return { selfId, groupId: argGroupId };
|
|
146
154
|
const parsed = parseOneBotSession(callCtx.sessionId);
|
|
@@ -149,20 +157,6 @@ function resolveGroupTarget(ctx, callCtx, args) {
|
|
|
149
157
|
}
|
|
150
158
|
throw new Error('未提供 group_id,且当前不在 OneBot 群会话中。请在参数中显式传入 group_id。');
|
|
151
159
|
}
|
|
152
|
-
/**
|
|
153
|
-
* 解析"目标用户":args.user_id 优先;否则当前会话必须是 OneBot 私聊。
|
|
154
|
-
*/
|
|
155
|
-
function _resolveUserTarget(ctx, callCtx, args) {
|
|
156
|
-
const argUserId = args.user_id != null && String(args.user_id).trim() ? String(args.user_id).trim() : '';
|
|
157
|
-
const selfId = resolveSelfId(ctx, callCtx, args);
|
|
158
|
-
if (argUserId)
|
|
159
|
-
return { selfId, userId: argUserId };
|
|
160
|
-
const parsed = parseOneBotSession(callCtx.sessionId);
|
|
161
|
-
if (parsed?.detailType === 'private' && parsed.targetId) {
|
|
162
|
-
return { selfId: parsed.selfId, userId: parsed.targetId };
|
|
163
|
-
}
|
|
164
|
-
throw new Error('未提供 user_id,且当前不在 OneBot 私聊会话中。请在参数中显式传入 user_id。');
|
|
165
|
-
}
|
|
166
160
|
function buildOneBotSessionId(selfId, detailType, targetId) {
|
|
167
161
|
return `onebot:${selfId}:${detailType}:${targetId}`;
|
|
168
162
|
}
|
|
@@ -171,8 +165,8 @@ function buildOneBotSessionId(selfId, detailType, targetId) {
|
|
|
171
165
|
* adapter 内部只用 sessionId 解析 selfId 来定位 WebSocket 连接,
|
|
172
166
|
* 因此这里用合成 sessionId("onebot:<selfId>:internal:0")即可,与目标会话类型无关。
|
|
173
167
|
*/
|
|
174
|
-
async function callAction(
|
|
175
|
-
const adapter = findOneBotAdapter(
|
|
168
|
+
async function callAction(platform, selfId, action, params) {
|
|
169
|
+
const adapter = findOneBotAdapter(platform);
|
|
176
170
|
if (!adapter?.callAction)
|
|
177
171
|
throw new Error('OneBot 适配器不可用或不支持 callAction');
|
|
178
172
|
return adapter.callAction(buildOneBotSessionId(selfId, 'internal', '0'), action, params);
|
|
@@ -234,7 +228,7 @@ function extractCqImageRefs(content) {
|
|
|
234
228
|
}
|
|
235
229
|
const source = imageSourceFromSegment(params);
|
|
236
230
|
if (source)
|
|
237
|
-
refs.push({ source,
|
|
231
|
+
refs.push({ source, segment: params });
|
|
238
232
|
match = re.exec(content);
|
|
239
233
|
}
|
|
240
234
|
return refs;
|
|
@@ -254,7 +248,7 @@ function extractImageRefsFromContent(content) {
|
|
|
254
248
|
const data = segment.data ?? {};
|
|
255
249
|
const source = imageSourceFromSegment(data);
|
|
256
250
|
if (source)
|
|
257
|
-
refs.push({ source,
|
|
251
|
+
refs.push({ source, segment: data });
|
|
258
252
|
}
|
|
259
253
|
return refs;
|
|
260
254
|
}
|
|
@@ -287,11 +281,12 @@ function collectForwardImageRefs(data, limit) {
|
|
|
287
281
|
.slice(0, limit)
|
|
288
282
|
.flatMap(item => extractImageRefsFromContent(getForwardNodeContent(item)));
|
|
289
283
|
}
|
|
290
|
-
async function resolveForwardImageSource(
|
|
284
|
+
async function resolveForwardImageSource(caps, storage, selfId, ref) {
|
|
291
285
|
if (/^(https?:|data:)/i.test(ref.source))
|
|
292
286
|
return ref.source;
|
|
287
|
+
const { platform, logger } = caps;
|
|
293
288
|
try {
|
|
294
|
-
const imageData = (await callAction(
|
|
289
|
+
const imageData = (await callAction(platform, selfId, 'get_image', { file: ref.source }));
|
|
295
290
|
const resolvedSource = imageData.url ?? imageData.file ?? ref.source;
|
|
296
291
|
if (typeof resolvedSource === 'string') {
|
|
297
292
|
if (/^(https?:|data:)/i.test(resolvedSource))
|
|
@@ -303,19 +298,20 @@ async function resolveForwardImageSource(ctx, storage, selfId, ref) {
|
|
|
303
298
|
}
|
|
304
299
|
}
|
|
305
300
|
catch (err) {
|
|
306
|
-
|
|
301
|
+
logger.debug(`get_image 解析转发图片失败 (${ref.source}): ${err}`);
|
|
307
302
|
}
|
|
308
303
|
const dataUri = await localImageToDataUri(storage, ref.source);
|
|
309
304
|
return dataUri ?? ref.source;
|
|
310
305
|
}
|
|
311
|
-
async function recognizeForwardImages(
|
|
306
|
+
async function recognizeForwardImages(caps, storage, selfId, data, limit) {
|
|
312
307
|
const refs = collectForwardImageRefs(data, limit);
|
|
313
308
|
const imageDescriptions = new Map();
|
|
314
309
|
if (refs.length === 0)
|
|
315
310
|
return { imageDescriptions };
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
311
|
+
const { logger, media } = caps;
|
|
312
|
+
const mediaService = media.current;
|
|
313
|
+
if (!mediaService) {
|
|
314
|
+
logger.debug(`合并转发包含 ${refs.length} 张图片,但 media 服务不可用`);
|
|
319
315
|
return { imageDescriptions };
|
|
320
316
|
}
|
|
321
317
|
const seen = new Set();
|
|
@@ -325,20 +321,18 @@ async function recognizeForwardImages(ctx, storage, selfId, data, limit) {
|
|
|
325
321
|
continue;
|
|
326
322
|
seen.add(key);
|
|
327
323
|
try {
|
|
328
|
-
const imageSource = await resolveForwardImageSource(
|
|
329
|
-
const description = await
|
|
324
|
+
const imageSource = await resolveForwardImageSource(caps, storage, selfId, ref);
|
|
325
|
+
const description = await mediaService.describeImage(imageSource);
|
|
330
326
|
if (description)
|
|
331
327
|
imageDescriptions.set(key, description);
|
|
332
328
|
}
|
|
333
329
|
catch (err) {
|
|
334
|
-
|
|
330
|
+
logger.debug(`合并转发图片识别失败 (${ref.source}): ${err}`);
|
|
335
331
|
}
|
|
336
332
|
}
|
|
337
333
|
return { imageDescriptions };
|
|
338
334
|
}
|
|
339
335
|
function formatMessageContent(content, context) {
|
|
340
|
-
if (typeof content === 'string')
|
|
341
|
-
return content;
|
|
342
336
|
if (!Array.isArray(content))
|
|
343
337
|
return content == null ? '' : JSON.stringify(content);
|
|
344
338
|
return content
|
|
@@ -354,9 +348,7 @@ function formatMessageContent(content, context) {
|
|
|
354
348
|
return data.qq === 'all' ? '@全体成员' : `@${String(data.qq ?? '')}`;
|
|
355
349
|
case 'image': {
|
|
356
350
|
const source = imageSourceFromSegment(data);
|
|
357
|
-
const desc = source
|
|
358
|
-
? context?.imageDescriptions.get(imageRefKey({ source, label: '[图片]', segment: data }))
|
|
359
|
-
: undefined;
|
|
351
|
+
const desc = source ? context?.imageDescriptions.get(imageRefKey({ source, segment: data })) : undefined;
|
|
360
352
|
return desc ? `[图片: ${desc}]` : '[图片]';
|
|
361
353
|
}
|
|
362
354
|
case 'face':
|
|
@@ -423,9 +415,9 @@ function roleLevel(role) {
|
|
|
423
415
|
return ROLE_LEVEL[role] ?? 0;
|
|
424
416
|
}
|
|
425
417
|
/** 查询群成员信息(失败返回 null) */
|
|
426
|
-
async function getGroupMemberInfo(
|
|
418
|
+
async function getGroupMemberInfo(platform, selfId, groupId, userId) {
|
|
427
419
|
try {
|
|
428
|
-
return (await callAction(
|
|
420
|
+
return (await callAction(platform, selfId, 'get_group_member_info', {
|
|
429
421
|
group_id: Number(groupId),
|
|
430
422
|
user_id: Number(userId),
|
|
431
423
|
no_cache: true,
|
|
@@ -436,8 +428,8 @@ async function getGroupMemberInfo(ctx, selfId, groupId, userId) {
|
|
|
436
428
|
}
|
|
437
429
|
}
|
|
438
430
|
/** 检查管理操作权限,返回错误消息(null 表示通过或无法验证) */
|
|
439
|
-
async function checkAdminPermission(
|
|
440
|
-
const selfInfo = await getGroupMemberInfo(
|
|
431
|
+
async function checkAdminPermission(platform, selfId, groupId, targetUserId, requireOwner) {
|
|
432
|
+
const selfInfo = await getGroupMemberInfo(platform, selfId, groupId, selfId);
|
|
441
433
|
if (!selfInfo)
|
|
442
434
|
return null; // 无法获取自身信息,跳过权限检查
|
|
443
435
|
const selfRole = String(selfInfo.role ?? 'member');
|
|
@@ -448,7 +440,7 @@ async function checkAdminPermission(ctx, selfId, groupId, targetUserId, requireO
|
|
|
448
440
|
return `操作失败:机器人不是管理员(当前角色:${selfRole}),无法执行管理操作`;
|
|
449
441
|
}
|
|
450
442
|
if (targetUserId) {
|
|
451
|
-
const targetInfo = await getGroupMemberInfo(
|
|
443
|
+
const targetInfo = await getGroupMemberInfo(platform, selfId, groupId, targetUserId);
|
|
452
444
|
if (!targetInfo) {
|
|
453
445
|
return `操作失败:无法获取用户 ${targetUserId} 的信息,该用户可能不在群中`;
|
|
454
446
|
}
|
|
@@ -460,38 +452,20 @@ async function checkAdminPermission(ctx, selfId, groupId, targetUserId, requireO
|
|
|
460
452
|
}
|
|
461
453
|
return null;
|
|
462
454
|
}
|
|
463
|
-
export
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
ctx.logger.info('检测到 OneBot 平台,开始注册 OneBot 工具');
|
|
479
|
-
// 注册工具分组:按职责语义切分,彼此不重叠
|
|
480
|
-
tools.registerGroup({
|
|
481
|
-
name: 'onebot-daily',
|
|
482
|
-
label: 'OneBot 只读与日常',
|
|
483
|
-
description: '只读查询(群信息/成员/好友列表/历史/登录信息)+ 日常低风险互动(戳一戳、好友赞)',
|
|
484
|
-
});
|
|
485
|
-
tools.registerGroup({
|
|
486
|
-
name: 'onebot-group',
|
|
487
|
-
label: 'OneBot 群务',
|
|
488
|
-
description: '群务管理:禁言/全员禁言/踢人/撤回消息/设置群名片/改群名/设管理员/群打卡/审批加群申请 等',
|
|
489
|
-
});
|
|
490
|
-
tools.registerGroup({
|
|
491
|
-
name: 'onebot-personal',
|
|
492
|
-
label: 'OneBot 个人/私聊',
|
|
493
|
-
description: '影响 bot 账号本身的人际关系:退群、删好友、处理好友申请、接受/拒绝入群邀请',
|
|
494
|
-
});
|
|
455
|
+
export default definePlugin({
|
|
456
|
+
name: '@aalis/plugin-tool-onebot',
|
|
457
|
+
displayName: 'OneBot 工具',
|
|
458
|
+
subsystem: 'tools',
|
|
459
|
+
configSchema,
|
|
460
|
+
uses,
|
|
461
|
+
apply(caps) {
|
|
462
|
+
const { tools, events, logger, platform, config } = caps;
|
|
463
|
+
const storage = createStorageGateway(caps.storage);
|
|
464
|
+
const bundle = {
|
|
465
|
+
daily: withToolGroups(tools, ['onebot-daily']),
|
|
466
|
+
group: withToolGroups(tools, ['onebot-group']),
|
|
467
|
+
personal: withToolGroups(tools, ['onebot-personal']),
|
|
468
|
+
};
|
|
495
469
|
const cfg = {
|
|
496
470
|
groupManagement: { enabled: true, ...(config.groupManagement ?? {}) },
|
|
497
471
|
groupInfo: { enabled: true, ...(config.groupInfo ?? {}) },
|
|
@@ -508,33 +482,71 @@ export function apply(ctx, config) {
|
|
|
508
482
|
...(config.sessionHistory ?? {}),
|
|
509
483
|
},
|
|
510
484
|
};
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
485
|
+
const maxLimit = Math.max(1, Math.min(1000, Number(cfg.sessionHistory.maxLimit) || 100));
|
|
486
|
+
const defaultLimitRaw = Math.max(1, Math.floor(Number(cfg.sessionHistory.defaultLimit) || 20));
|
|
487
|
+
const historyCfg = {
|
|
488
|
+
maxLimit,
|
|
489
|
+
defaultLimit: Math.min(defaultLimitRaw, maxLimit),
|
|
490
|
+
allowGroupReadPrivate: cfg.sessionHistory.allowGroupReadPrivate === true,
|
|
491
|
+
allowCrossSelf: cfg.sessionHistory.allowCrossSelf === true,
|
|
492
|
+
allowCrossGroup: cfg.sessionHistory.allowCrossGroup !== false,
|
|
493
|
+
allowCrossPrivate: cfg.sessionHistory.allowCrossPrivate === true,
|
|
494
|
+
};
|
|
495
|
+
// 访问规则始终注册:它同样约束通用的 session_get_history,不随专属工具开关撤掉(关掉工具不能反倒放宽读取)。
|
|
496
|
+
// 规则只对 onebot 会话 id 表态,与 OneBot 平台在不在场无关:不进下面的平台闸。
|
|
497
|
+
registerOneBotHistoryAccessChecker(caps, historyCfg);
|
|
498
|
+
// 仅当 OneBot 平台可用时才注册工具。platform 是可选的多提供者服务,OneBot 适配器可能晚于
|
|
499
|
+
// app:ready 上线(WebUI 启用、市场热装、启动失败后修好),且作为非胜者上线时 follow 不触发:
|
|
500
|
+
// 故在 app:ready 与每次 platform 提供者注册时各判一次,出现 onebot 即注册,之后不再重复。
|
|
501
|
+
// 平台离场不反注册:工具调用时找不到 OneBot 连接本就会报错。
|
|
502
|
+
let toolsRegistered = false;
|
|
503
|
+
const registerToolsOnce = () => {
|
|
504
|
+
if (toolsRegistered || !getPlatformNames(platform).includes('onebot'))
|
|
505
|
+
return;
|
|
506
|
+
toolsRegistered = true;
|
|
507
|
+
logger.info('检测到 OneBot 平台,开始注册 OneBot 工具');
|
|
508
|
+
// 注册工具分组:按职责语义切分,彼此不重叠
|
|
509
|
+
tools.registerGroup({
|
|
510
|
+
name: 'onebot-daily',
|
|
511
|
+
label: 'OneBot 只读与日常',
|
|
512
|
+
description: '只读查询(群信息/成员/好友列表/历史/登录信息)+ 日常低风险互动(戳一戳、好友赞)',
|
|
513
|
+
});
|
|
514
|
+
tools.registerGroup({
|
|
515
|
+
name: 'onebot-group',
|
|
516
|
+
label: 'OneBot 群务',
|
|
517
|
+
description: '群务管理:禁言/全员禁言/踢人/撤回消息/设置群名片/改群名/设管理员/群打卡/审批加群申请 等',
|
|
518
|
+
});
|
|
519
|
+
tools.registerGroup({
|
|
520
|
+
name: 'onebot-personal',
|
|
521
|
+
label: 'OneBot 个人/私聊',
|
|
522
|
+
description: '影响 bot 账号本身的人际关系:退群、删好友、处理好友申请、接受/拒绝入群邀请',
|
|
523
|
+
});
|
|
524
|
+
if (cfg.groupManagement.enabled)
|
|
525
|
+
registerGroupManagementTools(caps, bundle);
|
|
526
|
+
if (cfg.groupInfo.enabled)
|
|
527
|
+
registerGroupInfoTools(caps, storage, bundle);
|
|
528
|
+
if (cfg.account.enabled)
|
|
529
|
+
registerAccountTools(caps, bundle);
|
|
530
|
+
if (cfg.interaction.enabled)
|
|
531
|
+
registerInteractionTools(caps, bundle);
|
|
532
|
+
if (cfg.sessionHistory.enabled)
|
|
533
|
+
registerSessionHistoryTools(caps, bundle, historyCfg);
|
|
534
|
+
registerRequestTools(caps, bundle);
|
|
535
|
+
};
|
|
536
|
+
events.on('app:ready', () => {
|
|
537
|
+
registerToolsOnce();
|
|
538
|
+
if (!toolsRegistered)
|
|
539
|
+
logger.info('未检测到 OneBot 平台,暂不注册 OneBot 工具(平台上线后自动补注册)');
|
|
540
|
+
});
|
|
541
|
+
events.on('service:registered', name => {
|
|
542
|
+
if (name === platformService.name)
|
|
543
|
+
registerToolsOnce();
|
|
544
|
+
});
|
|
545
|
+
},
|
|
546
|
+
});
|
|
536
547
|
// ===== 群管理工具 =====
|
|
537
|
-
function registerGroupManagementTools(
|
|
548
|
+
function registerGroupManagementTools(caps, bundle) {
|
|
549
|
+
const { platform, logger } = caps;
|
|
538
550
|
const { group, personal } = bundle;
|
|
539
551
|
// ---- 群禁言(单人)----
|
|
540
552
|
group.register({
|
|
@@ -555,18 +567,18 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
555
567
|
},
|
|
556
568
|
},
|
|
557
569
|
handler: async (args, callCtx) => {
|
|
558
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
570
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
559
571
|
const duration = typeof args.duration === 'number' ? args.duration : 60;
|
|
560
|
-
const permError = await checkAdminPermission(
|
|
572
|
+
const permError = await checkAdminPermission(platform, selfId, groupId, String(args.user_id));
|
|
561
573
|
if (permError)
|
|
562
574
|
return permError;
|
|
563
|
-
await callAction(
|
|
575
|
+
await callAction(platform, selfId, 'set_group_ban', {
|
|
564
576
|
group_id: Number(groupId),
|
|
565
577
|
user_id: Number(args.user_id),
|
|
566
578
|
duration,
|
|
567
579
|
});
|
|
568
580
|
// 验证禁言是否生效
|
|
569
|
-
const info = await getGroupMemberInfo(
|
|
581
|
+
const info = await getGroupMemberInfo(platform, selfId, groupId, String(args.user_id));
|
|
570
582
|
if (info && 'shut_up_timestamp' in info) {
|
|
571
583
|
const shutUp = Number(info.shut_up_timestamp);
|
|
572
584
|
const now = Math.floor(Date.now() / 1000);
|
|
@@ -602,11 +614,11 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
602
614
|
},
|
|
603
615
|
},
|
|
604
616
|
handler: async (args, callCtx) => {
|
|
605
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
606
|
-
const permError = await checkAdminPermission(
|
|
617
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
618
|
+
const permError = await checkAdminPermission(platform, selfId, groupId);
|
|
607
619
|
if (permError)
|
|
608
620
|
return permError;
|
|
609
|
-
await callAction(
|
|
621
|
+
await callAction(platform, selfId, 'set_group_whole_ban', {
|
|
610
622
|
group_id: Number(groupId),
|
|
611
623
|
enable: !!args.enable,
|
|
612
624
|
});
|
|
@@ -632,11 +644,11 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
632
644
|
},
|
|
633
645
|
},
|
|
634
646
|
handler: async (args, callCtx) => {
|
|
635
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
636
|
-
const permError = await checkAdminPermission(
|
|
647
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
648
|
+
const permError = await checkAdminPermission(platform, selfId, groupId, String(args.user_id));
|
|
637
649
|
if (permError)
|
|
638
650
|
return permError;
|
|
639
|
-
await callAction(
|
|
651
|
+
await callAction(platform, selfId, 'set_group_kick', {
|
|
640
652
|
group_id: Number(groupId),
|
|
641
653
|
user_id: Number(args.user_id),
|
|
642
654
|
reject_add_request: !!args.reject_add_request,
|
|
@@ -662,12 +674,12 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
662
674
|
},
|
|
663
675
|
handler: async (args, callCtx) => {
|
|
664
676
|
const argGroupId = args.group_id != null && String(args.group_id).trim() ? String(args.group_id).trim() : '';
|
|
665
|
-
const selfId = resolveSelfId(
|
|
677
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
666
678
|
const parsed = parseOneBotSession(callCtx.sessionId);
|
|
667
679
|
const groupId = argGroupId || (parsed?.detailType === 'group' ? parsed.targetId : '');
|
|
668
680
|
if (!groupId)
|
|
669
681
|
return '请提供 group_id,或在要退出的群聊中调用此工具';
|
|
670
|
-
await callAction(
|
|
682
|
+
await callAction(platform, selfId, 'set_group_leave', {
|
|
671
683
|
group_id: Number(groupId),
|
|
672
684
|
is_dismiss: false,
|
|
673
685
|
});
|
|
@@ -693,11 +705,11 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
693
705
|
},
|
|
694
706
|
},
|
|
695
707
|
handler: async (args, callCtx) => {
|
|
696
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
697
|
-
const permError = await checkAdminPermission(
|
|
708
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
709
|
+
const permError = await checkAdminPermission(platform, selfId, groupId);
|
|
698
710
|
if (permError)
|
|
699
711
|
return permError;
|
|
700
|
-
await callAction(
|
|
712
|
+
await callAction(platform, selfId, 'set_group_card', {
|
|
701
713
|
group_id: Number(groupId),
|
|
702
714
|
user_id: Number(args.user_id),
|
|
703
715
|
card: String(args.card ?? ''),
|
|
@@ -723,11 +735,11 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
723
735
|
},
|
|
724
736
|
},
|
|
725
737
|
handler: async (args, callCtx) => {
|
|
726
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
727
|
-
const permError = await checkAdminPermission(
|
|
738
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
739
|
+
const permError = await checkAdminPermission(platform, selfId, groupId);
|
|
728
740
|
if (permError)
|
|
729
741
|
return permError;
|
|
730
|
-
await callAction(
|
|
742
|
+
await callAction(platform, selfId, 'set_group_name', {
|
|
731
743
|
group_id: Number(groupId),
|
|
732
744
|
group_name: String(args.group_name),
|
|
733
745
|
});
|
|
@@ -753,11 +765,11 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
753
765
|
},
|
|
754
766
|
},
|
|
755
767
|
handler: async (args, callCtx) => {
|
|
756
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
757
|
-
const permError = await checkAdminPermission(
|
|
768
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
769
|
+
const permError = await checkAdminPermission(platform, selfId, groupId, undefined, true);
|
|
758
770
|
if (permError)
|
|
759
771
|
return permError;
|
|
760
|
-
await callAction(
|
|
772
|
+
await callAction(platform, selfId, 'set_group_special_title', {
|
|
761
773
|
group_id: Number(groupId),
|
|
762
774
|
user_id: Number(args.user_id),
|
|
763
775
|
special_title: String(args.special_title ?? ''),
|
|
@@ -785,11 +797,11 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
785
797
|
},
|
|
786
798
|
},
|
|
787
799
|
handler: async (args, callCtx) => {
|
|
788
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
789
|
-
const permError = await checkAdminPermission(
|
|
800
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
801
|
+
const permError = await checkAdminPermission(platform, selfId, groupId, undefined, true);
|
|
790
802
|
if (permError)
|
|
791
803
|
return permError;
|
|
792
|
-
await callAction(
|
|
804
|
+
await callAction(platform, selfId, 'set_group_admin', {
|
|
793
805
|
group_id: Number(groupId),
|
|
794
806
|
user_id: Number(args.user_id),
|
|
795
807
|
enable: !!args.enable,
|
|
@@ -815,8 +827,8 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
815
827
|
},
|
|
816
828
|
handler: async (args, callCtx) => {
|
|
817
829
|
// 不限制必须是群聊;只要能找到可用的 OneBot 账号即可
|
|
818
|
-
const selfId = resolveSelfId(
|
|
819
|
-
await callAction(
|
|
830
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
831
|
+
await callAction(platform, selfId, 'delete_msg', {
|
|
820
832
|
message_id: Number(args.message_id),
|
|
821
833
|
});
|
|
822
834
|
return `已撤回消息 ${args.message_id}`;
|
|
@@ -844,7 +856,7 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
844
856
|
},
|
|
845
857
|
},
|
|
846
858
|
handler: async (args, callCtx) => {
|
|
847
|
-
const selfId = resolveSelfId(
|
|
859
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
848
860
|
const argGroupId = args.group_id != null && String(args.group_id).trim() ? String(args.group_id).trim() : '';
|
|
849
861
|
const argUserId = args.user_id != null && String(args.user_id).trim() ? String(args.user_id).trim() : '';
|
|
850
862
|
let targetSessionId;
|
|
@@ -858,9 +870,9 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
858
870
|
return '当前不在 OneBot 会话中,请用 group_id 或 user_id 指定要撤回的目标会话。';
|
|
859
871
|
targetSessionId = callCtx.sessionId;
|
|
860
872
|
}
|
|
861
|
-
const adapter = findOneBotAdapter(
|
|
873
|
+
const adapter = findOneBotAdapter(platform);
|
|
862
874
|
if (!adapter?.getSentMessages) {
|
|
863
|
-
return '
|
|
875
|
+
return '未找到支持记录自身发出消息的 OneBot 适配器(getSentMessages 不在平台契约内,第三方适配器可不提供)。如已知 message_id 可改用 onebot_delete_msg。';
|
|
864
876
|
}
|
|
865
877
|
const count = Math.max(1, Math.min(10, Math.floor(Number(args.count) || 1)));
|
|
866
878
|
const recent = adapter.getSentMessages(targetSessionId, 10); // 新→旧
|
|
@@ -872,7 +884,7 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
872
884
|
const failed = [];
|
|
873
885
|
for (const t of targets) {
|
|
874
886
|
try {
|
|
875
|
-
await callAction(
|
|
887
|
+
await callAction(platform, selfId, 'delete_msg', { message_id: Number(t.messageId) || t.messageId });
|
|
876
888
|
adapter.forgetSentMessage?.(targetSessionId, t.messageId);
|
|
877
889
|
recalled.push(t.preview ? `「${t.preview}」` : `msg=${t.messageId}`);
|
|
878
890
|
}
|
|
@@ -889,10 +901,11 @@ function registerGroupManagementTools(ctx, bundle) {
|
|
|
889
901
|
return msg;
|
|
890
902
|
},
|
|
891
903
|
});
|
|
892
|
-
|
|
904
|
+
logger.info('OneBot 群管理工具已注册');
|
|
893
905
|
}
|
|
894
906
|
// ===== 群信息查询工具 =====
|
|
895
|
-
function registerGroupInfoTools(
|
|
907
|
+
function registerGroupInfoTools(caps, storage, bundle) {
|
|
908
|
+
const { platform, logger } = caps;
|
|
896
909
|
const { daily } = bundle;
|
|
897
910
|
// ---- 查看合并转发 ----
|
|
898
911
|
daily.register({
|
|
@@ -915,7 +928,7 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
915
928
|
},
|
|
916
929
|
},
|
|
917
930
|
handler: async (args, callCtx) => {
|
|
918
|
-
const selfId = resolveSelfId(
|
|
931
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
919
932
|
if (!args.id)
|
|
920
933
|
return '参数错误:缺少 id(合并转发 ID)。请使用 <forward id="..."> 中的 id 字符串,不要使用 message_id。';
|
|
921
934
|
const forwardId = String(args.id);
|
|
@@ -924,7 +937,7 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
924
937
|
// 并维护了一份接收时即抓取并展开(含摘要与图像识别)的缓存。
|
|
925
938
|
let data;
|
|
926
939
|
try {
|
|
927
|
-
data = await callAction(
|
|
940
|
+
data = await callAction(platform, selfId, 'get_forward_msg', { id: forwardId });
|
|
928
941
|
}
|
|
929
942
|
catch (err) {
|
|
930
943
|
return `合并转发读取失败:${err instanceof Error ? err.message : String(err)}。该转发可能已在协议端过期,或当前 OneBot 实现不支持跨会话读取。`;
|
|
@@ -937,7 +950,7 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
937
950
|
const summaryLine = entry.summary ? `\n摘要:${entry.summary}\n` : '\n';
|
|
938
951
|
return `${header}${summaryLine}\n原文:\n${entry.fullText}`;
|
|
939
952
|
}
|
|
940
|
-
const formatContext = await recognizeForwardImages(
|
|
953
|
+
const formatContext = await recognizeForwardImages(caps, storage, selfId, data, limit);
|
|
941
954
|
return formatForwardMessage(data, limit, formatContext);
|
|
942
955
|
},
|
|
943
956
|
});
|
|
@@ -958,8 +971,8 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
958
971
|
},
|
|
959
972
|
},
|
|
960
973
|
handler: async (args, callCtx) => {
|
|
961
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
962
|
-
const data = await callAction(
|
|
974
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
975
|
+
const data = await callAction(platform, selfId, 'get_group_info', {
|
|
963
976
|
group_id: Number(groupId),
|
|
964
977
|
});
|
|
965
978
|
return JSON.stringify(data);
|
|
@@ -983,9 +996,9 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
983
996
|
},
|
|
984
997
|
},
|
|
985
998
|
handler: async (args, callCtx) => {
|
|
986
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
999
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
987
1000
|
const userId = args.user_id ? String(args.user_id) : selfId;
|
|
988
|
-
const data = await callAction(
|
|
1001
|
+
const data = await callAction(platform, selfId, 'get_group_member_info', {
|
|
989
1002
|
group_id: Number(groupId),
|
|
990
1003
|
user_id: Number(userId),
|
|
991
1004
|
no_cache: true,
|
|
@@ -1014,8 +1027,8 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
1014
1027
|
},
|
|
1015
1028
|
},
|
|
1016
1029
|
handler: async (args, callCtx) => {
|
|
1017
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
1018
|
-
const data = await callAction(
|
|
1030
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
1031
|
+
const data = await callAction(platform, selfId, 'get_group_member_list', {
|
|
1019
1032
|
group_id: Number(groupId),
|
|
1020
1033
|
});
|
|
1021
1034
|
const list = Array.isArray(data) ? data : [];
|
|
@@ -1078,7 +1091,7 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
1078
1091
|
},
|
|
1079
1092
|
handler: async (args, callCtx) => {
|
|
1080
1093
|
const argGroupId = args.group_id != null && String(args.group_id).trim() ? String(args.group_id).trim() : '';
|
|
1081
|
-
const selfId = resolveSelfId(
|
|
1094
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
1082
1095
|
const parsed = parseOneBotSession(callCtx.sessionId);
|
|
1083
1096
|
let groupId = argGroupId;
|
|
1084
1097
|
if (!groupId) {
|
|
@@ -1087,12 +1100,12 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
1087
1100
|
}
|
|
1088
1101
|
groupId = parsed.targetId;
|
|
1089
1102
|
}
|
|
1090
|
-
const adapter = findOneBotAdapter(
|
|
1103
|
+
const adapter = findOneBotAdapter(platform);
|
|
1091
1104
|
if (!adapter?.callAction)
|
|
1092
1105
|
return JSON.stringify({ available: false, reason: 'OneBot 适配器不可用' });
|
|
1093
1106
|
let info = null;
|
|
1094
1107
|
try {
|
|
1095
|
-
info = (await callAction(
|
|
1108
|
+
info = (await callAction(platform, selfId, 'get_group_member_info', {
|
|
1096
1109
|
group_id: Number(groupId),
|
|
1097
1110
|
user_id: Number(selfId),
|
|
1098
1111
|
no_cache: true,
|
|
@@ -1141,9 +1154,12 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
1141
1154
|
},
|
|
1142
1155
|
},
|
|
1143
1156
|
handler: async (args) => {
|
|
1144
|
-
const adapter = findOneBotAdapter(
|
|
1157
|
+
const adapter = findOneBotAdapter(platform);
|
|
1145
1158
|
if (!adapter?.getSelfMutes) {
|
|
1146
|
-
return JSON.stringify({
|
|
1159
|
+
return JSON.stringify({
|
|
1160
|
+
supported: false,
|
|
1161
|
+
reason: '未找到支持记录自身禁言状态的 OneBot 适配器(getSelfMutes 不在平台契约内,第三方适配器可不提供)',
|
|
1162
|
+
});
|
|
1147
1163
|
}
|
|
1148
1164
|
const limit = Math.max(1, Math.min(200, Math.floor(Number(args.limit) || 30)));
|
|
1149
1165
|
const offset = Math.max(0, Math.floor(Number(args.offset) || 0));
|
|
@@ -1186,11 +1202,11 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
1186
1202
|
},
|
|
1187
1203
|
},
|
|
1188
1204
|
handler: async (args, callCtx) => {
|
|
1189
|
-
const selfId = resolveSelfId(
|
|
1205
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
1190
1206
|
if (!args.message_id)
|
|
1191
1207
|
return '参数错误:缺少 message_id';
|
|
1192
1208
|
try {
|
|
1193
|
-
const data = await callAction(
|
|
1209
|
+
const data = await callAction(platform, selfId, 'get_msg', {
|
|
1194
1210
|
message_id: Number(args.message_id),
|
|
1195
1211
|
});
|
|
1196
1212
|
return JSON.stringify(data);
|
|
@@ -1222,19 +1238,20 @@ function registerGroupInfoTools(ctx, storage, bundle) {
|
|
|
1222
1238
|
},
|
|
1223
1239
|
},
|
|
1224
1240
|
handler: async (args, callCtx) => {
|
|
1225
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
1241
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
1226
1242
|
const honorType = typeof args.type === 'string' ? args.type : 'all';
|
|
1227
|
-
const data = await callAction(
|
|
1243
|
+
const data = await callAction(platform, selfId, 'get_group_honor_info', {
|
|
1228
1244
|
group_id: Number(groupId),
|
|
1229
1245
|
type: honorType,
|
|
1230
1246
|
});
|
|
1231
1247
|
return JSON.stringify(data);
|
|
1232
1248
|
},
|
|
1233
1249
|
});
|
|
1234
|
-
|
|
1250
|
+
logger.info('OneBot 群信息查询工具已注册');
|
|
1235
1251
|
}
|
|
1236
1252
|
// ===== 账号 / 好友 / 群列表查询工具 =====
|
|
1237
|
-
function registerAccountTools(
|
|
1253
|
+
function registerAccountTools(caps, bundle) {
|
|
1254
|
+
const { platform, logger } = caps;
|
|
1238
1255
|
const { daily, personal } = bundle;
|
|
1239
1256
|
// ---- 群列表 ----
|
|
1240
1257
|
daily.register({
|
|
@@ -1258,8 +1275,8 @@ function registerAccountTools(ctx, bundle) {
|
|
|
1258
1275
|
},
|
|
1259
1276
|
},
|
|
1260
1277
|
handler: async (args, callCtx) => {
|
|
1261
|
-
const selfId = resolveSelfId(
|
|
1262
|
-
const data = await callAction(
|
|
1278
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
1279
|
+
const data = await callAction(platform, selfId, 'get_group_list', {});
|
|
1263
1280
|
const list = Array.isArray(data) ? data : [];
|
|
1264
1281
|
const keyword = typeof args.keyword === 'string' ? args.keyword.trim().toLowerCase() : '';
|
|
1265
1282
|
// 上限封顶,避免超大 limit 把整张列表灌进 LLM 上下文(token 浪费)。
|
|
@@ -1307,8 +1324,8 @@ function registerAccountTools(ctx, bundle) {
|
|
|
1307
1324
|
},
|
|
1308
1325
|
},
|
|
1309
1326
|
handler: async (args, callCtx) => {
|
|
1310
|
-
const selfId = resolveSelfId(
|
|
1311
|
-
const data = await callAction(
|
|
1327
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
1328
|
+
const data = await callAction(platform, selfId, 'get_friend_list', {});
|
|
1312
1329
|
const list = Array.isArray(data) ? data : [];
|
|
1313
1330
|
const keyword = typeof args.keyword === 'string' ? args.keyword.trim().toLowerCase() : '';
|
|
1314
1331
|
// 上限封顶,避免超大 limit 把整张列表灌进 LLM 上下文(token 浪费)。
|
|
@@ -1355,8 +1372,8 @@ function registerAccountTools(ctx, bundle) {
|
|
|
1355
1372
|
},
|
|
1356
1373
|
},
|
|
1357
1374
|
handler: async (args, callCtx) => {
|
|
1358
|
-
const selfId = resolveSelfId(
|
|
1359
|
-
const data = await callAction(
|
|
1375
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
1376
|
+
const data = await callAction(platform, selfId, 'get_stranger_info', {
|
|
1360
1377
|
user_id: Number(args.user_id),
|
|
1361
1378
|
no_cache: !!args.no_cache,
|
|
1362
1379
|
});
|
|
@@ -1374,8 +1391,8 @@ function registerAccountTools(ctx, bundle) {
|
|
|
1374
1391
|
},
|
|
1375
1392
|
},
|
|
1376
1393
|
handler: async (_args, callCtx) => {
|
|
1377
|
-
const selfId = resolveSelfId(
|
|
1378
|
-
const data = await callAction(
|
|
1394
|
+
const selfId = resolveSelfId(platform, callCtx, _args);
|
|
1395
|
+
const data = await callAction(platform, selfId, 'get_login_info', {});
|
|
1379
1396
|
return JSON.stringify(data);
|
|
1380
1397
|
},
|
|
1381
1398
|
});
|
|
@@ -1397,21 +1414,22 @@ function registerAccountTools(ctx, bundle) {
|
|
|
1397
1414
|
},
|
|
1398
1415
|
handler: async (args, callCtx) => {
|
|
1399
1416
|
const argUserId = args.user_id != null && String(args.user_id).trim() ? String(args.user_id).trim() : '';
|
|
1400
|
-
const selfId = resolveSelfId(
|
|
1417
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
1401
1418
|
const parsed = parseOneBotSession(callCtx.sessionId);
|
|
1402
1419
|
const userId = argUserId || (parsed?.detailType === 'private' ? parsed.targetId : '');
|
|
1403
1420
|
if (!userId)
|
|
1404
1421
|
return '请提供 user_id,或在要删除的好友私聊中调用此工具';
|
|
1405
|
-
await callAction(
|
|
1422
|
+
await callAction(platform, selfId, 'delete_friend', {
|
|
1406
1423
|
user_id: Number(userId),
|
|
1407
1424
|
});
|
|
1408
1425
|
return `已删除好友 ${userId}`;
|
|
1409
1426
|
},
|
|
1410
1427
|
});
|
|
1411
|
-
|
|
1428
|
+
logger.info('OneBot 账号 / 好友 / 群列表查询工具已注册');
|
|
1412
1429
|
}
|
|
1413
1430
|
// ===== 特殊交互工具 =====
|
|
1414
|
-
function registerInteractionTools(
|
|
1431
|
+
function registerInteractionTools(caps, bundle) {
|
|
1432
|
+
const { platform, logger } = caps;
|
|
1415
1433
|
const { daily, group } = bundle;
|
|
1416
1434
|
// ---- 戳一戳 ----
|
|
1417
1435
|
daily.register({
|
|
@@ -1436,7 +1454,7 @@ function registerInteractionTools(ctx, bundle) {
|
|
|
1436
1454
|
},
|
|
1437
1455
|
},
|
|
1438
1456
|
handler: async (args, callCtx) => {
|
|
1439
|
-
const selfId = resolveSelfId(
|
|
1457
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
1440
1458
|
const parsed = parseOneBotSession(callCtx.sessionId);
|
|
1441
1459
|
const argGroupId = args.group_id != null && String(args.group_id).trim() ? String(args.group_id).trim() : '';
|
|
1442
1460
|
const argUserId = args.user_id != null && String(args.user_id).trim() ? String(args.user_id).trim() : '';
|
|
@@ -1447,13 +1465,13 @@ function registerInteractionTools(ctx, bundle) {
|
|
|
1447
1465
|
throw new Error('群聊戳一戳必须显式提供 user_id(要戳的对象)。');
|
|
1448
1466
|
}
|
|
1449
1467
|
try {
|
|
1450
|
-
await callAction(
|
|
1468
|
+
await callAction(platform, selfId, 'group_poke', {
|
|
1451
1469
|
group_id: Number(groupId),
|
|
1452
1470
|
user_id: Number(argUserId),
|
|
1453
1471
|
});
|
|
1454
1472
|
}
|
|
1455
1473
|
catch {
|
|
1456
|
-
await callAction(
|
|
1474
|
+
await callAction(platform, selfId, 'send_group_poke', {
|
|
1457
1475
|
group_id: Number(groupId),
|
|
1458
1476
|
user_id: Number(argUserId),
|
|
1459
1477
|
});
|
|
@@ -1467,10 +1485,10 @@ function registerInteractionTools(ctx, bundle) {
|
|
|
1467
1485
|
}
|
|
1468
1486
|
// NapCat: friend_poke { user_id };其他实现可能用 send_poke
|
|
1469
1487
|
try {
|
|
1470
|
-
await callAction(
|
|
1488
|
+
await callAction(platform, selfId, 'friend_poke', { user_id: Number(userId) });
|
|
1471
1489
|
}
|
|
1472
1490
|
catch {
|
|
1473
|
-
await callAction(
|
|
1491
|
+
await callAction(platform, selfId, 'send_poke', { user_id: Number(userId) });
|
|
1474
1492
|
}
|
|
1475
1493
|
return `已戳了 ${userId} 一下`;
|
|
1476
1494
|
},
|
|
@@ -1493,9 +1511,9 @@ function registerInteractionTools(ctx, bundle) {
|
|
|
1493
1511
|
},
|
|
1494
1512
|
},
|
|
1495
1513
|
handler: async (args, callCtx) => {
|
|
1496
|
-
const selfId = resolveSelfId(
|
|
1514
|
+
const selfId = resolveSelfId(platform, callCtx, args);
|
|
1497
1515
|
const times = Math.min(10, Math.max(1, typeof args.times === 'number' ? Math.floor(args.times) : 1));
|
|
1498
|
-
await callAction(
|
|
1516
|
+
await callAction(platform, selfId, 'send_like', {
|
|
1499
1517
|
user_id: Number(args.user_id),
|
|
1500
1518
|
times,
|
|
1501
1519
|
});
|
|
@@ -1519,66 +1537,63 @@ function registerInteractionTools(ctx, bundle) {
|
|
|
1519
1537
|
},
|
|
1520
1538
|
},
|
|
1521
1539
|
handler: async (args, callCtx) => {
|
|
1522
|
-
const { selfId, groupId } = resolveGroupTarget(
|
|
1523
|
-
await callAction(
|
|
1540
|
+
const { selfId, groupId } = resolveGroupTarget(platform, callCtx, args);
|
|
1541
|
+
await callAction(platform, selfId, 'send_group_sign', {
|
|
1524
1542
|
group_id: Number(groupId),
|
|
1525
1543
|
});
|
|
1526
1544
|
return '打卡成功';
|
|
1527
1545
|
},
|
|
1528
1546
|
});
|
|
1529
|
-
|
|
1547
|
+
logger.info('OneBot 特殊交互工具已注册');
|
|
1530
1548
|
}
|
|
1531
1549
|
/**
|
|
1532
1550
|
* 把 OneBot 的细粒度访问规则注册到 session-history 服务。
|
|
1533
1551
|
* 通用工具 session_get_history 和平台专属工具 onebot_get_session_history
|
|
1534
1552
|
* 调用 service 时都会走这条规则链 —— 不存在绕过路径。
|
|
1535
1553
|
*/
|
|
1536
|
-
function registerOneBotHistoryAccessChecker(
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
if (!target)
|
|
1548
|
-
return undefined; // 不是合法 onebot 目标, 不表态
|
|
1549
|
-
const current = parseOneBotSession(currentSessionId);
|
|
1550
|
-
// 跨平台调用(current 不是 onebot)走默认放行: session-history scope 已粗筛
|
|
1551
|
-
if (!current)
|
|
1552
|
-
return undefined;
|
|
1553
|
-
if (current.selfId !== target.selfId && !cfg.allowCrossSelf) {
|
|
1554
|
-
return { decision: 'deny', reason: '当前 OneBot 配置不允许跨机器人账号读取会话历史' };
|
|
1555
|
-
}
|
|
1556
|
-
if (current.detailType === 'group' && target.detailType === 'private' && !cfg.allowGroupReadPrivate) {
|
|
1557
|
-
return { decision: 'deny', reason: '当前 OneBot 配置不允许从群聊读取私聊历史' };
|
|
1558
|
-
}
|
|
1559
|
-
if (current.detailType === 'group' &&
|
|
1560
|
-
target.detailType === 'group' &&
|
|
1561
|
-
current.targetId !== target.targetId &&
|
|
1562
|
-
!cfg.allowCrossGroup) {
|
|
1563
|
-
return { decision: 'deny', reason: '当前 OneBot 配置不允许跨群读取其他群历史' };
|
|
1564
|
-
}
|
|
1565
|
-
if (current.detailType === 'private' &&
|
|
1566
|
-
target.detailType === 'private' &&
|
|
1567
|
-
current.targetId !== target.targetId &&
|
|
1568
|
-
!cfg.allowCrossPrivate) {
|
|
1569
|
-
return { decision: 'deny', reason: '当前 OneBot 配置不允许跨私聊读取其他私聊历史' };
|
|
1570
|
-
}
|
|
1554
|
+
function registerOneBotHistoryAccessChecker(caps, cfg) {
|
|
1555
|
+
const { logger, sessionHistory } = caps;
|
|
1556
|
+
const checker = {
|
|
1557
|
+
platform: 'onebot',
|
|
1558
|
+
check({ currentSessionId, targetSessionId }) {
|
|
1559
|
+
const target = parseOneBotSession(targetSessionId);
|
|
1560
|
+
if (!target)
|
|
1561
|
+
return undefined; // 不是合法 onebot 目标, 不表态
|
|
1562
|
+
const current = parseOneBotSession(currentSessionId);
|
|
1563
|
+
// 跨平台调用(current 不是 onebot)走默认放行: session-history scope 已粗筛
|
|
1564
|
+
if (!current)
|
|
1571
1565
|
return undefined;
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1566
|
+
if (current.selfId !== target.selfId && !cfg.allowCrossSelf) {
|
|
1567
|
+
return { decision: 'deny', reason: '当前 OneBot 配置不允许跨机器人账号读取会话历史' };
|
|
1568
|
+
}
|
|
1569
|
+
if (current.detailType === 'group' && target.detailType === 'private' && !cfg.allowGroupReadPrivate) {
|
|
1570
|
+
return { decision: 'deny', reason: '当前 OneBot 配置不允许从群聊读取私聊历史' };
|
|
1571
|
+
}
|
|
1572
|
+
if (current.detailType === 'group' &&
|
|
1573
|
+
target.detailType === 'group' &&
|
|
1574
|
+
current.targetId !== target.targetId &&
|
|
1575
|
+
!cfg.allowCrossGroup) {
|
|
1576
|
+
return { decision: 'deny', reason: '当前 OneBot 配置不允许跨群读取其他群历史' };
|
|
1577
|
+
}
|
|
1578
|
+
if (current.detailType === 'private' &&
|
|
1579
|
+
target.detailType === 'private' &&
|
|
1580
|
+
current.targetId !== target.targetId &&
|
|
1581
|
+
!cfg.allowCrossPrivate) {
|
|
1582
|
+
return { decision: 'deny', reason: '当前 OneBot 配置不允许跨私聊读取其他私聊历史' };
|
|
1583
|
+
}
|
|
1584
|
+
return undefined;
|
|
1585
|
+
},
|
|
1586
|
+
};
|
|
1587
|
+
// 规则登记在 session-history 提供者实例的局部状态里:提供者重启或换人后,新实例身上没有这条规则,
|
|
1588
|
+
// 须跟随提供者重挂;返回的注销作为跟随清理,本插件 bounce / 卸载时一并撤回,不在下层泄漏。
|
|
1589
|
+
sessionHistory.follow(svc => {
|
|
1590
|
+
const dispose = svc.registerAccessChecker(checker);
|
|
1591
|
+
logger.info('OneBot 会话历史访问规则已注册到 session-history');
|
|
1592
|
+
return dispose;
|
|
1579
1593
|
});
|
|
1580
1594
|
}
|
|
1581
|
-
function registerSessionHistoryTools(
|
|
1595
|
+
function registerSessionHistoryTools(caps, bundle, cfg) {
|
|
1596
|
+
const { platform, logger, sessionHistory } = caps;
|
|
1582
1597
|
const { daily } = bundle;
|
|
1583
1598
|
daily.register({
|
|
1584
1599
|
definition: {
|
|
@@ -1612,7 +1627,7 @@ function registerSessionHistoryTools(ctx, bundle, cfg) {
|
|
|
1612
1627
|
if (!targetId)
|
|
1613
1628
|
return JSON.stringify({ error: 'target_id 不能为空' });
|
|
1614
1629
|
const argSelfId = args.self_id ? String(args.self_id).trim() : '';
|
|
1615
|
-
const selfId = argSelfId || current?.selfId || getAnyOneBotSelfId(
|
|
1630
|
+
const selfId = argSelfId || current?.selfId || getAnyOneBotSelfId(platform) || '';
|
|
1616
1631
|
if (!selfId)
|
|
1617
1632
|
return JSON.stringify({ error: '无法确定 self_id,且未找到可用的 OneBot 连接' });
|
|
1618
1633
|
// 跨账号限制:仅在当前也是 OneBot 会话时才作为参考点检查
|
|
@@ -1672,10 +1687,10 @@ function registerSessionHistoryTools(ctx, bundle, cfg) {
|
|
|
1672
1687
|
if (!targetId)
|
|
1673
1688
|
return JSON.stringify({ error: 'target_id 不能为空' });
|
|
1674
1689
|
const argSelfId = args.self_id ? String(args.self_id).trim() : '';
|
|
1675
|
-
const selfId = argSelfId || current?.selfId || getAnyOneBotSelfId(
|
|
1690
|
+
const selfId = argSelfId || current?.selfId || getAnyOneBotSelfId(platform) || '';
|
|
1676
1691
|
if (!selfId)
|
|
1677
1692
|
return JSON.stringify({ error: '无法确定 self_id,且未找到可用的 OneBot 连接' });
|
|
1678
|
-
const history =
|
|
1693
|
+
const history = sessionHistory.current;
|
|
1679
1694
|
if (!history)
|
|
1680
1695
|
return JSON.stringify({
|
|
1681
1696
|
error: 'session-history 服务不可用,请启用 @aalis/plugin-tool-session',
|
|
@@ -1698,19 +1713,20 @@ function registerSessionHistoryTools(ctx, bundle, cfg) {
|
|
|
1698
1713
|
}
|
|
1699
1714
|
catch (err) {
|
|
1700
1715
|
const message = err instanceof Error ? err.message : String(err);
|
|
1701
|
-
|
|
1716
|
+
logger.warn(`onebot_get_session_history 失败 (${sessionId}): ${message}`);
|
|
1702
1717
|
return JSON.stringify({ error: `读取 OneBot 会话历史失败: ${message}` });
|
|
1703
1718
|
}
|
|
1704
1719
|
},
|
|
1705
1720
|
});
|
|
1706
|
-
|
|
1721
|
+
logger.info('OneBot 会话历史工具已注册');
|
|
1707
1722
|
}
|
|
1708
1723
|
// ===== 请求处理工具(好友申请 / 群请求)=====
|
|
1709
|
-
function registerRequestTools(
|
|
1724
|
+
function registerRequestTools(caps, bundle) {
|
|
1725
|
+
const { platform, logger } = caps;
|
|
1710
1726
|
const { group, personal } = bundle;
|
|
1711
1727
|
/** 找到支持 handleFriendRequest 的 OneBot 适配器 */
|
|
1712
|
-
function findRequestAdapter(
|
|
1713
|
-
const adapter = getPlatformAdapters(
|
|
1728
|
+
function findRequestAdapter(platform) {
|
|
1729
|
+
const adapter = getPlatformAdapters(platform).find(a => a.platform === 'onebot' && typeof a.handleFriendRequest === 'function');
|
|
1714
1730
|
return adapter;
|
|
1715
1731
|
}
|
|
1716
1732
|
personal.register({
|
|
@@ -1731,7 +1747,7 @@ function registerRequestTools(ctx, bundle) {
|
|
|
1731
1747
|
},
|
|
1732
1748
|
},
|
|
1733
1749
|
handler: async (args) => {
|
|
1734
|
-
const adapter = findRequestAdapter(
|
|
1750
|
+
const adapter = findRequestAdapter(platform);
|
|
1735
1751
|
if (!adapter)
|
|
1736
1752
|
return '未找到支持请求处理的 OneBot 适配器';
|
|
1737
1753
|
return adapter.handleFriendRequest(String(args.user_id), !!args.approve, args.remark ? String(args.remark) : undefined);
|
|
@@ -1760,7 +1776,7 @@ function registerRequestTools(ctx, bundle) {
|
|
|
1760
1776
|
},
|
|
1761
1777
|
},
|
|
1762
1778
|
handler: async (args) => {
|
|
1763
|
-
const adapter = findRequestAdapter(
|
|
1779
|
+
const adapter = findRequestAdapter(platform);
|
|
1764
1780
|
if (!adapter)
|
|
1765
1781
|
return '未找到支持请求处理的 OneBot 适配器';
|
|
1766
1782
|
return adapter.handleGroupRequest(String(args.user_id), String(args.group_id), !!args.approve, args.reason ? String(args.reason) : undefined);
|
|
@@ -1785,12 +1801,12 @@ function registerRequestTools(ctx, bundle) {
|
|
|
1785
1801
|
},
|
|
1786
1802
|
},
|
|
1787
1803
|
handler: async (args) => {
|
|
1788
|
-
const adapter = findRequestAdapter(
|
|
1804
|
+
const adapter = findRequestAdapter(platform);
|
|
1789
1805
|
if (!adapter)
|
|
1790
1806
|
return '未找到支持请求处理的 OneBot 适配器';
|
|
1791
1807
|
return adapter.handleGroupRequest(String(args.user_id), String(args.group_id), !!args.approve, args.reason ? String(args.reason) : undefined);
|
|
1792
1808
|
},
|
|
1793
1809
|
});
|
|
1794
|
-
|
|
1810
|
+
logger.info('OneBot 请求处理工具已注册');
|
|
1795
1811
|
}
|
|
1796
1812
|
//# sourceMappingURL=index.js.map
|