@zhin.js/adapter-icqq 1.0.71 → 1.1.2
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 +1216 -52
- package/PERMITS.md +24 -0
- package/README.md +123 -429
- package/adapters/icqq/index.js +31 -0
- package/adapters/icqq/index.ts +42 -0
- package/agents/icqq/agent.json +20 -0
- package/agents/icqq/boundaries.md +3 -0
- package/agents/icqq/conventions.md +3 -0
- package/agents/icqq/skills/icqq-directory/SKILL.md +20 -0
- package/agents/icqq/skills/icqq-directory/tools/friend_list/index.js +19 -0
- package/agents/icqq/skills/icqq-directory/tools/friend_list/index.ts +19 -0
- package/agents/icqq/skills/icqq-directory/tools/group_list/index.js +20 -0
- package/agents/icqq/skills/icqq-directory/tools/group_list/index.ts +20 -0
- package/agents/icqq/skills/icqq-directory/tools/group_member_info/index.js +26 -0
- package/agents/icqq/skills/icqq-directory/tools/group_member_info/index.ts +28 -0
- package/agents/icqq/skills/icqq-directory/tools/user_info/index.js +15 -0
- package/agents/icqq/skills/icqq-directory/tools/user_info/index.ts +14 -0
- package/agents/icqq/skills/icqq-group-admin/SKILL.md +25 -0
- package/agents/icqq/skills/icqq-group-admin/tools/announce/index.js +18 -0
- package/agents/icqq/skills/icqq-group-admin/tools/announce/index.ts +17 -0
- package/agents/icqq/skills/icqq-group-admin/tools/essence/index.js +24 -0
- package/agents/icqq/skills/icqq-group-admin/tools/essence/index.ts +22 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.js +23 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.ts +20 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.js +27 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.ts +23 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.js +23 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.ts +21 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.js +25 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.ts +22 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.js +26 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.ts +23 -0
- package/agents/icqq/skills/icqq-group-state/SKILL.md +17 -0
- package/agents/icqq/skills/icqq-group-state/tools/group_files/index.js +24 -0
- package/agents/icqq/skills/icqq-group-state/tools/group_files/index.ts +22 -0
- package/agents/icqq/skills/icqq-group-state/tools/list_muted/index.js +18 -0
- package/agents/icqq/skills/icqq-group-state/tools/list_muted/index.ts +17 -0
- package/agents/icqq/skills/icqq-interaction/SKILL.md +19 -0
- package/agents/icqq/skills/icqq-interaction/tools/group_sign/index.js +20 -0
- package/agents/icqq/skills/icqq-interaction/tools/group_sign/index.ts +18 -0
- package/agents/icqq/skills/icqq-interaction/tools/poke/index.js +17 -0
- package/agents/icqq/skills/icqq-interaction/tools/poke/index.ts +16 -0
- package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.js +26 -0
- package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.ts +22 -0
- package/agents/icqq/system.md +3 -0
- package/commands/icqq/endpoint/add/[[id]]/index.js +3 -0
- package/commands/icqq/endpoint/add/[[id]]/index.ts +3 -0
- package/commands/icqq/endpoint/definition.js +31 -0
- package/commands/icqq/endpoint/definition.ts +32 -0
- package/commands/icqq/endpoint/list/index.js +3 -0
- package/commands/icqq/endpoint/list/index.ts +3 -0
- package/commands/icqq/endpoint/remove/[id]/index.js +3 -0
- package/commands/icqq/endpoint/remove/[id]/index.ts +3 -0
- package/lib/client.d.ts +19 -0
- package/lib/client.js +3 -0
- package/lib/content-resolver.d.ts +10 -0
- package/lib/content-resolver.js +98 -0
- package/lib/cq-message.d.ts +14 -0
- package/lib/cq-message.js +106 -0
- package/lib/endpoint.d.ts +30 -0
- package/lib/endpoint.js +1003 -0
- package/lib/forward-msg.d.ts +6 -0
- package/lib/forward-msg.js +107 -0
- package/lib/icqq-guild.d.ts +57 -0
- package/lib/icqq-guild.js +109 -0
- package/lib/icqq-inbound.d.ts +165 -0
- package/lib/icqq-inbound.js +651 -0
- package/lib/icqq-inbox.d.ts +25 -0
- package/lib/icqq-inbox.js +129 -0
- package/lib/icqq-login-assist.d.ts +27 -0
- package/lib/icqq-login-assist.js +109 -0
- package/lib/icqq-runtime-state.d.ts +1 -0
- package/lib/icqq-runtime-state.js +6 -0
- package/lib/index.d.ts +5 -18
- package/lib/index.js +5 -124
- package/lib/outbound-media.d.ts +14 -0
- package/lib/outbound-media.js +76 -0
- package/lib/protocol.d.ts +258 -0
- package/lib/protocol.js +422 -0
- package/lib/types.d.ts +33 -13
- package/lib/types.js +0 -1
- package/package.json +86 -32
- package/plugin.js +19 -0
- package/prompt-sections/platform/index.js +16 -0
- package/prompt-sections/platform/index.ts +16 -0
- package/schema.json +168 -0
- package/src/client.ts +29 -0
- package/src/content-resolver.ts +131 -0
- package/src/cq-message.ts +113 -0
- package/src/endpoint.ts +1084 -0
- package/src/forward-msg.ts +112 -0
- package/src/icqq-guild.ts +154 -0
- package/src/icqq-inbound.ts +814 -0
- package/src/icqq-inbox.ts +147 -0
- package/src/icqq-login-assist.ts +132 -0
- package/src/icqq-runtime-state.ts +7 -0
- package/src/index.ts +30 -149
- package/src/outbound-media.ts +103 -0
- package/src/protocol.ts +551 -0
- package/src/types.ts +35 -13
- package/LICENSE +0 -21
- package/client/ICQQManagement.tsx +0 -139
- package/client/LoginAssistPanel.tsx +0 -293
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -20
- package/dist/index.js +0 -1
- package/lib/adapter.d.ts +0 -34
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -396
- package/lib/adapter.js.map +0 -1
- package/lib/bot.d.ts +0 -46
- package/lib/bot.d.ts.map +0 -1
- package/lib/bot.js +0 -457
- package/lib/bot.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js.map +0 -1
- package/skills/icqq/SKILL.md +0 -22
- package/src/adapter.ts +0 -448
- package/src/bot.ts +0 -521
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type IcqqMessageElement } from "./icqq-inbound.js";
|
|
2
|
+
import type { ForwardEntry } from '@zhin.js/im-contract';
|
|
3
|
+
/** 从 QQ 合并转发 json 元素提取 resid */
|
|
4
|
+
export declare function extractForwardResidFromJsonElement(el: IcqqMessageElement): string | undefined;
|
|
5
|
+
/** Canonical merged-forward entries. Speakers are data actors, never LLM roles. */
|
|
6
|
+
export declare function normalizeForwardMsgResponse(data: unknown): readonly ForwardEntry[];
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { icqqElementsToSegments, } from "./icqq-inbound.js";
|
|
2
|
+
import { toCanonicalSegments } from '@zhin.js/core';
|
|
3
|
+
const RESID_IN_XML_RE = /(?:m_resid|resid|fileid|res_id)=["']?([A-Za-z0-9+/=_.-]{8,})/i;
|
|
4
|
+
function parseJsonPayload(raw) {
|
|
5
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
6
|
+
return raw;
|
|
7
|
+
}
|
|
8
|
+
if (typeof raw !== "string" || !raw.trim())
|
|
9
|
+
return null;
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(raw);
|
|
12
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
13
|
+
return parsed;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// ignore
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
/** 从 QQ 合并转发 json 元素提取 resid */
|
|
22
|
+
export function extractForwardResidFromJsonElement(el) {
|
|
23
|
+
const record = parseJsonPayload(el.data) ??
|
|
24
|
+
parseJsonPayload(el.text) ??
|
|
25
|
+
parseJsonPayload(el);
|
|
26
|
+
if (!record) {
|
|
27
|
+
const text = typeof el.text === "string" ? el.text : "";
|
|
28
|
+
const m = text.match(RESID_IN_XML_RE);
|
|
29
|
+
return m?.[1]?.trim();
|
|
30
|
+
}
|
|
31
|
+
const bytes = record.bytesData ?? record.bytes_data ?? record.bytes;
|
|
32
|
+
if (typeof bytes === "string" && bytes.trim()) {
|
|
33
|
+
const inner = parseJsonPayload(bytes);
|
|
34
|
+
if (inner) {
|
|
35
|
+
const nested = extractForwardResidFromJsonElement({
|
|
36
|
+
type: "json",
|
|
37
|
+
data: inner,
|
|
38
|
+
});
|
|
39
|
+
if (nested)
|
|
40
|
+
return nested;
|
|
41
|
+
}
|
|
42
|
+
const m = bytes.match(RESID_IN_XML_RE);
|
|
43
|
+
if (m?.[1])
|
|
44
|
+
return m[1].trim();
|
|
45
|
+
}
|
|
46
|
+
const app = String(record.app ?? record.App ?? "");
|
|
47
|
+
if (app.includes("multimsg") || app.includes("MultiMsg")) {
|
|
48
|
+
const meta = record.meta;
|
|
49
|
+
const detail = meta?.detail;
|
|
50
|
+
const resid = detail?.resid ?? detail?.ResID ?? detail?.resId;
|
|
51
|
+
if (resid != null && String(resid).trim())
|
|
52
|
+
return String(resid).trim();
|
|
53
|
+
}
|
|
54
|
+
const prompt = record.prompt;
|
|
55
|
+
if (prompt) {
|
|
56
|
+
const m = prompt.match(RESID_IN_XML_RE);
|
|
57
|
+
if (m?.[1])
|
|
58
|
+
return m[1].trim();
|
|
59
|
+
}
|
|
60
|
+
const direct = record.resid ?? record.m_resid ?? record.fileid;
|
|
61
|
+
if (direct != null && String(direct).trim())
|
|
62
|
+
return String(direct).trim();
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
/** Canonical merged-forward entries. Speakers are data actors, never LLM roles. */
|
|
66
|
+
export function normalizeForwardMsgResponse(data) {
|
|
67
|
+
const root = data && typeof data === 'object' && !Array.isArray(data)
|
|
68
|
+
? data
|
|
69
|
+
: undefined;
|
|
70
|
+
const list = Array.isArray(data)
|
|
71
|
+
? data
|
|
72
|
+
: Array.isArray(root?.messages) ? root.messages
|
|
73
|
+
: Array.isArray(root?.msgList) ? root.msgList
|
|
74
|
+
: Array.isArray(root?.msg_list) ? root.msg_list
|
|
75
|
+
: Array.isArray(root?.message) ? root.message
|
|
76
|
+
: [];
|
|
77
|
+
return Object.freeze(list.flatMap((item) => {
|
|
78
|
+
if (!item || typeof item !== 'object')
|
|
79
|
+
return [];
|
|
80
|
+
const row = item;
|
|
81
|
+
const sender = row.sender && typeof row.sender === 'object'
|
|
82
|
+
? row.sender
|
|
83
|
+
: row.user && typeof row.user === 'object'
|
|
84
|
+
? row.user
|
|
85
|
+
: undefined;
|
|
86
|
+
const id = sender?.user_id ?? sender?.uin ?? sender?.id;
|
|
87
|
+
const displayName = sender?.nickname ?? sender?.card ?? sender?.name;
|
|
88
|
+
const body = row.message ?? row.content ?? row.elements ?? row.raw_message;
|
|
89
|
+
let segments;
|
|
90
|
+
if (Array.isArray(body))
|
|
91
|
+
segments = toCanonicalSegments(icqqElementsToSegments(body) ?? body);
|
|
92
|
+
else if (typeof body === 'string' && body.trim())
|
|
93
|
+
segments = [{ type: 'text', data: { text: body.trim() } }];
|
|
94
|
+
else
|
|
95
|
+
segments = [];
|
|
96
|
+
if (segments.length === 0)
|
|
97
|
+
return [];
|
|
98
|
+
return [Object.freeze({
|
|
99
|
+
...(id != null ? { actor: Object.freeze({
|
|
100
|
+
id: String(id),
|
|
101
|
+
...(displayName != null && String(displayName).trim() ? { displayName: String(displayName) } : {}),
|
|
102
|
+
}) } : {}),
|
|
103
|
+
...(typeof row.time === 'number' ? { timestamp: row.time < 1e12 ? row.time * 1000 : row.time } : {}),
|
|
104
|
+
segments: Object.freeze(segments),
|
|
105
|
+
})];
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ICQQ guild (QQ 频道) catalog sync, inbound normalize, Console channel list.
|
|
3
|
+
*/
|
|
4
|
+
import { type MessageSegment } from "zhin.js";
|
|
5
|
+
import type { GuildMessageEventData } from "./protocol.js";
|
|
6
|
+
export interface IcqqGuildClient {
|
|
7
|
+
getGuildList(): Array<{
|
|
8
|
+
guild_id: string;
|
|
9
|
+
guild_name: string;
|
|
10
|
+
}>;
|
|
11
|
+
getChannelList(guildId: string): Array<{
|
|
12
|
+
guild_id: string;
|
|
13
|
+
channel_id: string;
|
|
14
|
+
channel_name: string;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
export interface IcqqGuildChannelEntry {
|
|
18
|
+
channel_id: string;
|
|
19
|
+
channel_name: string;
|
|
20
|
+
guild_id: string;
|
|
21
|
+
guild_name: string;
|
|
22
|
+
}
|
|
23
|
+
export interface NormalizedIcqqGuildInbound {
|
|
24
|
+
messageId: string;
|
|
25
|
+
channelId: string;
|
|
26
|
+
guildId: string;
|
|
27
|
+
guildName: string;
|
|
28
|
+
channelName: string;
|
|
29
|
+
userId: string;
|
|
30
|
+
nickname: string;
|
|
31
|
+
content: MessageSegment[];
|
|
32
|
+
rawMessage: string;
|
|
33
|
+
timestampMs: number;
|
|
34
|
+
raw: GuildMessageEventData;
|
|
35
|
+
}
|
|
36
|
+
export declare class IcqqGuildCatalog {
|
|
37
|
+
private readonly channels;
|
|
38
|
+
private readonly guilds;
|
|
39
|
+
clear(): void;
|
|
40
|
+
syncAll(client: IcqqGuildClient): Promise<void>;
|
|
41
|
+
upsertFromInbound(data: GuildMessageEventData): void;
|
|
42
|
+
getGuildChannelList(): Array<{
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
parent: {
|
|
46
|
+
type: "guild";
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
};
|
|
50
|
+
}>;
|
|
51
|
+
resolveConsoleChannelNames(channelId: string, guildId?: string): {
|
|
52
|
+
channelName?: string;
|
|
53
|
+
parentName?: string;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export declare function isIcqqGuildEvent(eventName: string | undefined): boolean;
|
|
57
|
+
export declare function normalizeIcqqGuildInboundMessage(data: GuildMessageEventData & Record<string, unknown>): NormalizedIcqqGuildInbound | null;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ICQQ guild (QQ 频道) catalog sync, inbound normalize, Console channel list.
|
|
3
|
+
*/
|
|
4
|
+
import { toCanonicalSegments } from "zhin.js";
|
|
5
|
+
import { parseCqMessage } from "./cq-message.js";
|
|
6
|
+
export class IcqqGuildCatalog {
|
|
7
|
+
channels = new Map();
|
|
8
|
+
guilds = new Map();
|
|
9
|
+
clear() {
|
|
10
|
+
this.channels.clear();
|
|
11
|
+
this.guilds.clear();
|
|
12
|
+
}
|
|
13
|
+
async syncAll(client) {
|
|
14
|
+
const guildRows = client.getGuildList();
|
|
15
|
+
for (const row of guildRows) {
|
|
16
|
+
const guild_id = String(row.guild_id ?? "");
|
|
17
|
+
if (!guild_id)
|
|
18
|
+
continue;
|
|
19
|
+
const guild_name = String(row.guild_name ?? guild_id);
|
|
20
|
+
this.guilds.set(guild_id, { guild_id, guild_name });
|
|
21
|
+
const channels = client.getChannelList(guild_id);
|
|
22
|
+
for (const ch of channels) {
|
|
23
|
+
const channel_id = String(ch.channel_id ?? "");
|
|
24
|
+
if (!channel_id)
|
|
25
|
+
continue;
|
|
26
|
+
const channel_name = String(ch.channel_name ?? channel_id);
|
|
27
|
+
this.channels.set(channel_id, {
|
|
28
|
+
channel_id,
|
|
29
|
+
channel_name,
|
|
30
|
+
guild_id,
|
|
31
|
+
guild_name,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
upsertFromInbound(data) {
|
|
37
|
+
const guild_id = String(data.guild_id ?? "");
|
|
38
|
+
const channel_id = String(data.channel_id ?? "");
|
|
39
|
+
if (!guild_id || !channel_id)
|
|
40
|
+
return;
|
|
41
|
+
const guild_name = String(data.guild_name ?? guild_id);
|
|
42
|
+
const channel_name = String(data.channel_name ?? channel_id);
|
|
43
|
+
this.guilds.set(guild_id, { guild_id, guild_name });
|
|
44
|
+
this.channels.set(channel_id, {
|
|
45
|
+
channel_id,
|
|
46
|
+
channel_name,
|
|
47
|
+
guild_id,
|
|
48
|
+
guild_name,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
getGuildChannelList() {
|
|
52
|
+
return Array.from(this.channels.values()).map((entry) => ({
|
|
53
|
+
id: entry.channel_id,
|
|
54
|
+
name: entry.channel_name,
|
|
55
|
+
parent: {
|
|
56
|
+
type: "guild",
|
|
57
|
+
id: entry.guild_id,
|
|
58
|
+
name: entry.guild_name,
|
|
59
|
+
},
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
resolveConsoleChannelNames(channelId, guildId) {
|
|
63
|
+
const entry = this.channels.get(channelId);
|
|
64
|
+
if (entry) {
|
|
65
|
+
return { channelName: entry.channel_name, parentName: entry.guild_name };
|
|
66
|
+
}
|
|
67
|
+
if (guildId) {
|
|
68
|
+
const guild = this.guilds.get(guildId);
|
|
69
|
+
return guild ? { parentName: guild.guild_name } : {};
|
|
70
|
+
}
|
|
71
|
+
return {};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function isIcqqGuildEvent(eventName) {
|
|
75
|
+
return typeof eventName === "string" && eventName.startsWith("message.guild");
|
|
76
|
+
}
|
|
77
|
+
export function normalizeIcqqGuildInboundMessage(data) {
|
|
78
|
+
if (data.type !== "guild")
|
|
79
|
+
return null;
|
|
80
|
+
const guildId = String(data.guild_id ?? "");
|
|
81
|
+
const channelId = String(data.channel_id ?? "");
|
|
82
|
+
if (!guildId || !channelId)
|
|
83
|
+
return null;
|
|
84
|
+
const userId = String(data.tiny_id ?? data.user_id ?? "");
|
|
85
|
+
const nickname = String(data.nickname ?? userId);
|
|
86
|
+
const rawMessage = String(data.raw_message ?? "");
|
|
87
|
+
const timestampMs = typeof data.time === "number" ? data.time * 1000 : Date.now();
|
|
88
|
+
const messageId = data.message_id != null && String(data.message_id) !== ""
|
|
89
|
+
? String(data.message_id)
|
|
90
|
+
: data.seq != null
|
|
91
|
+
? String(data.seq)
|
|
92
|
+
: `${data.time ?? 0}_${userId}_${channelId}`;
|
|
93
|
+
const parsed = parseCqMessage(rawMessage);
|
|
94
|
+
const canonical = toCanonicalSegments(parsed);
|
|
95
|
+
const content = canonical.length > 0 ? canonical : [{ type: "text", data: { text: rawMessage } }];
|
|
96
|
+
return {
|
|
97
|
+
messageId,
|
|
98
|
+
channelId,
|
|
99
|
+
guildId,
|
|
100
|
+
guildName: String(data.guild_name ?? guildId),
|
|
101
|
+
channelName: String(data.channel_name ?? channelId),
|
|
102
|
+
userId,
|
|
103
|
+
nickname,
|
|
104
|
+
content,
|
|
105
|
+
rawMessage,
|
|
106
|
+
timestampMs,
|
|
107
|
+
raw: data,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* icqq 入站事件归一化(post_type / message_type / message 段)
|
|
3
|
+
*/
|
|
4
|
+
import { type MessageSegment } from "zhin.js";
|
|
5
|
+
import type { GroupRole } from "./types.js";
|
|
6
|
+
/** 守护进程推送的通用事件壳 */
|
|
7
|
+
export interface IcqqEventBase {
|
|
8
|
+
post_type?: string;
|
|
9
|
+
self_id?: number;
|
|
10
|
+
}
|
|
11
|
+
/** post_type=message 时的消息体(字段随 icqqjs/cli 演进,未知字段保留) */
|
|
12
|
+
export interface IcqqMessageEvent extends IcqqEventBase {
|
|
13
|
+
post_type: "message";
|
|
14
|
+
message_id?: string;
|
|
15
|
+
msg_id?: string;
|
|
16
|
+
user_id: number;
|
|
17
|
+
user_uid?: string;
|
|
18
|
+
time: number;
|
|
19
|
+
seq?: number;
|
|
20
|
+
message_type: string;
|
|
21
|
+
sub_type?: string;
|
|
22
|
+
raw_message?: string;
|
|
23
|
+
message?: IcqqMessageElement[];
|
|
24
|
+
sender?: {
|
|
25
|
+
user_id?: number;
|
|
26
|
+
user_uid?: string;
|
|
27
|
+
nickname?: string;
|
|
28
|
+
card?: string;
|
|
29
|
+
/** 群临时会话来源群号 */
|
|
30
|
+
group_id?: number;
|
|
31
|
+
/** 群成员角色:owner | admin | member */
|
|
32
|
+
role?: GroupRole | string;
|
|
33
|
+
};
|
|
34
|
+
from_id?: number;
|
|
35
|
+
from_uid?: string;
|
|
36
|
+
group_id?: number;
|
|
37
|
+
to_id?: number;
|
|
38
|
+
nickname?: string;
|
|
39
|
+
/** 旧版仅有 type 无 message_type */
|
|
40
|
+
type?: "group" | "private";
|
|
41
|
+
/** oicq Message#source:被引用回复的源消息 */
|
|
42
|
+
source?: IcqqMessageSource;
|
|
43
|
+
}
|
|
44
|
+
/** oicq 引用源消息(与 MessageEvent.source 对齐) */
|
|
45
|
+
export interface IcqqMessageSource {
|
|
46
|
+
message_id?: string;
|
|
47
|
+
msg_id?: string;
|
|
48
|
+
seq?: number;
|
|
49
|
+
rand?: number;
|
|
50
|
+
time?: number;
|
|
51
|
+
user_id?: number;
|
|
52
|
+
group_id?: number;
|
|
53
|
+
raw_message?: string;
|
|
54
|
+
/** 元素数组,或 NT 推送的纯文本摘要 */
|
|
55
|
+
message?: IcqqMessageElement[] | string;
|
|
56
|
+
sender?: {
|
|
57
|
+
user_id?: number;
|
|
58
|
+
nickname?: string;
|
|
59
|
+
card?: string;
|
|
60
|
+
};
|
|
61
|
+
[key: string]: unknown;
|
|
62
|
+
}
|
|
63
|
+
interface IcqqMessageLookup {
|
|
64
|
+
readonly messageId: string;
|
|
65
|
+
readonly sender?: Readonly<{
|
|
66
|
+
id?: string;
|
|
67
|
+
name?: string;
|
|
68
|
+
}>;
|
|
69
|
+
readonly content: readonly MessageSegment[] | string;
|
|
70
|
+
readonly raw?: string;
|
|
71
|
+
readonly time?: number;
|
|
72
|
+
}
|
|
73
|
+
export type IcqqMessageElement = {
|
|
74
|
+
type: string;
|
|
75
|
+
text?: string;
|
|
76
|
+
qq?: string | number;
|
|
77
|
+
user_id?: string | number;
|
|
78
|
+
id?: string | number;
|
|
79
|
+
url?: string;
|
|
80
|
+
file?: string;
|
|
81
|
+
fid?: string;
|
|
82
|
+
name?: string;
|
|
83
|
+
size?: number;
|
|
84
|
+
seconds?: number;
|
|
85
|
+
[key: string]: unknown;
|
|
86
|
+
};
|
|
87
|
+
export interface IcqqInboundMediaResolver {
|
|
88
|
+
getPttUrl(element: IcqqMessageElement): Promise<string | null | undefined>;
|
|
89
|
+
getVideoUrl(element: IcqqMessageElement): Promise<string | null | undefined>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Resolve ICQQ's opaque protobuf media references while the endpoint-owned
|
|
93
|
+
* native client is still available. Resolution failure preserves the opaque
|
|
94
|
+
* reference, so canonical ingress stays truthful and can report unsupported
|
|
95
|
+
* media instead of inventing a URL.
|
|
96
|
+
*/
|
|
97
|
+
export declare function resolveIcqqInboundMedia(elements: IcqqMessageElement[] | undefined, resolver: IcqqInboundMediaResolver): Promise<void>;
|
|
98
|
+
/** 归一化后供适配器使用的入站消息 */
|
|
99
|
+
export interface NormalizedIcqqInbound {
|
|
100
|
+
messageId: string;
|
|
101
|
+
idSource: "message_id" | "msg_id" | "seq" | "synthetic";
|
|
102
|
+
channelType: "group" | "private";
|
|
103
|
+
channelId: string;
|
|
104
|
+
/** 群临时会话:来源群号 */
|
|
105
|
+
channelParentGroupId?: string;
|
|
106
|
+
userId: string;
|
|
107
|
+
nickname: string;
|
|
108
|
+
/** 群聊时来自 sender.role(私聊无) */
|
|
109
|
+
senderRole?: GroupRole;
|
|
110
|
+
content: MessageSegment[];
|
|
111
|
+
rawMessage: string;
|
|
112
|
+
timestampMs: number;
|
|
113
|
+
raw: IcqqMessageEvent;
|
|
114
|
+
}
|
|
115
|
+
/** 从 sender.role 解析群成员角色(供 Message.$sender → resolveSenderRoles) */
|
|
116
|
+
export declare function parseIcqqSenderGroupRole(sender: {
|
|
117
|
+
role?: unknown;
|
|
118
|
+
} | undefined): GroupRole | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* 判断入站消息是否 @ 了本机账号(uin = endpoint 配置 name,即 QQ 号)。
|
|
121
|
+
* 新 Plugin Runtime 的 Message.content 为纯文本,at 信息只能经 metadata 传递,
|
|
122
|
+
* endpoint 在 admit 时用本函数标注 `metadata.mentioned`(供 Agent Host 的 @ 触发)。
|
|
123
|
+
*/
|
|
124
|
+
export declare function isIcqqBotMentioned(input: {
|
|
125
|
+
readonly uin: string;
|
|
126
|
+
readonly content?: readonly MessageSegment[] | null;
|
|
127
|
+
readonly rawMessage?: string;
|
|
128
|
+
}): boolean;
|
|
129
|
+
/** 从事件壳中取出 OneBot/icqq 载荷(兼容 data 嵌套或字段在根级) */
|
|
130
|
+
export declare function unwrapIcqqEventPayload(event: {
|
|
131
|
+
data?: unknown;
|
|
132
|
+
[key: string]: unknown;
|
|
133
|
+
}): unknown;
|
|
134
|
+
export declare function resolveIcqqInboundUserId(data: Record<string, unknown>): number | undefined;
|
|
135
|
+
export declare function isIcqqMessagePostType(data: unknown): data is IcqqMessageEvent;
|
|
136
|
+
export declare function shouldSkipSelfInboundMessage(data: IcqqMessageEvent): boolean;
|
|
137
|
+
/** 群临时会话私聊:icqq message_type=private & sub_type=group */
|
|
138
|
+
export declare function isIcqqGroupTempPrivateMessage(data: IcqqMessageEvent): boolean;
|
|
139
|
+
export declare function resolveChannelFromIcqqMessage(data: IcqqMessageEvent): {
|
|
140
|
+
channelType: "group" | "private";
|
|
141
|
+
channelId: string;
|
|
142
|
+
channelParentGroupId?: string;
|
|
143
|
+
};
|
|
144
|
+
export declare function resolveIcqqInboundMessageId(data: IcqqMessageEvent, channelId: string): {
|
|
145
|
+
id: string;
|
|
146
|
+
source: "message_id" | "msg_id" | "seq" | "synthetic";
|
|
147
|
+
};
|
|
148
|
+
export declare function icqqElementsToSegments(elements: IcqqMessageElement[] | undefined): MessageSegment[] | null;
|
|
149
|
+
/** 载荷可能把 source 嵌在 data / event 等字段,深度查找 */
|
|
150
|
+
export declare function findIcqqNestedMessageSource(root: unknown, maxDepth?: number): IcqqMessageSource | undefined;
|
|
151
|
+
/** 从 oicq MessageEvent.source 解析被引用消息的 message_id */
|
|
152
|
+
export declare function resolveQuoteIdFromIcqqSource(source: unknown): string | undefined;
|
|
153
|
+
/** Convert an ICQQ source into the adapter-local lookup payload. */
|
|
154
|
+
export declare function messageLookupFromIcqqSource(source: unknown): IcqqMessageLookup | null;
|
|
155
|
+
/** 从事件顶层字段解析引用 message_id(与 message 段互补) */
|
|
156
|
+
export declare function resolveIcqqQuoteIdFromEvent(data: IcqqMessageEvent): string | undefined;
|
|
157
|
+
export declare function resolveInboundContent(data: IcqqMessageEvent): MessageSegment[];
|
|
158
|
+
export declare function normalizeIcqqInboundMessage(data: IcqqMessageEvent): NormalizedIcqqInbound | null;
|
|
159
|
+
/** 按 message_id 去重(多路 subscribe 会收到同一消息多次) */
|
|
160
|
+
export declare class InboundMessageDeduper {
|
|
161
|
+
private readonly seen;
|
|
162
|
+
shouldProcess(messageId: string): boolean;
|
|
163
|
+
clear(): void;
|
|
164
|
+
}
|
|
165
|
+
export {};
|