chatluna-plugin-onebot-toolbox 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +50 -2
- package/lib/config.d.ts +40 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +809 -0
- package/lib/index.js.map +1 -0
- package/lib/logger.d.ts +9 -0
- package/lib/logger.d.ts.map +1 -0
- package/lib/onebot.d.ts +35 -0
- package/lib/onebot.d.ts.map +1 -0
- package/lib/requests.d.ts +21 -0
- package/lib/requests.d.ts.map +1 -0
- package/lib/tools.d.ts +33 -0
- package/lib/tools.d.ts.map +1 -0
- package/lib/variables.d.ts +12 -0
- package/lib/variables.d.ts.map +1 -0
- package/package.json +78 -3
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/logger.ts","../src/config.ts","../src/requests.ts","../src/onebot.ts","../src/tools.ts","../src/variables.ts","../src/index.ts"],"sourcesContent":["import type { Context } from 'cordis'\n\n/** 插件内的日志:`debugLogging` 打开时调试信息以 info 级别输出,否则走 logger 自己的 debug 级别。 */\nexport interface Logger {\n debug(format: string, ...args: unknown[]): void\n info(format: string, ...args: unknown[]): void\n warn(format: string, ...args: unknown[]): void\n}\n\nexport function createLogger(ctx: Context, debugLogging: boolean): Logger {\n const logger = ctx.logger\n return {\n debug: (format, ...args) => (debugLogging ? logger.info(format, ...args) : logger.debug(format, ...args)),\n info: (format, ...args) => logger.info(format, ...args),\n warn: (format, ...args) => logger.warn(format, ...args),\n }\n}\n","import { Schema } from '@chatluna/schema'\n\nexport type OneBotProtocol = 'napcat' | 'llbot' | 'snowluma'\n\nexport type NativeToolKey =\n | 'setSelfProfile'\n | 'setQQAvatar'\n | 'setGroupCard'\n | 'searchGroupMember'\n | 'leaveGroup'\n | 'handleRequest'\n | 'setGroupKick'\n | 'setGroupSpecialTitle'\n | 'deleteMessage'\n\nexport interface NativeToolInfo {\n toolName: string\n description: string\n}\n\nexport type MemberInfoItem =\n | 'userId'\n | 'nickname'\n | 'role'\n | 'level'\n | 'title'\n | 'gender'\n | 'age'\n | 'area'\n | 'joinTime'\n | 'lastSentTime'\n\nexport type GroupInfoItem = 'groupName' | 'groupId' | 'memberCount' | 'createTime' | 'ownerList' | 'adminList'\n\nexport interface Config {\n oneBotProtocol: OneBotProtocol\n requestNotice: boolean\n userInfo: { variableName: string, items: MemberInfoItem[] }\n botInfo: { variableName: string, items: MemberInfoItem[] }\n groupInfo: { variableName: string, items: GroupInfoItem[] }\n groupShutList: { variableName: string }\n debugLogging: boolean\n}\n\n/** 原生工具的名称与描述固定,全部注册;启用范围交给 v2 的工具管理。 */\nexport const NATIVE_TOOLS: Record<NativeToolKey, NativeToolInfo> = {\n setSelfProfile: {\n toolName: 'set_self_profile',\n description: '修改自己的 QQ 资料,可设置昵称、签名和性别。',\n },\n setQQAvatar: {\n toolName: 'set_qq_avatar',\n description: '修改机器人 QQ 头像。imageUrl 填会话里图片的 ref(`<img ref=\"i…\"/>` 的 ref 属性)、HTTP/HTTPS 链接或 OneBot 端可读的本地路径;会话图片与 HTTP/HTTPS 图片会先由插件读取并转为 OneBot base64 文件,避免临时 URL 过期或 OneBot 端无法访问。',\n },\n setGroupCard: {\n toolName: 'set_group_card',\n description: '修改群成员的群昵称。',\n },\n searchGroupMember: {\n toolName: 'search_group_member',\n description: '根据 qqid 精确查询群成员的群昵称与 QQ 昵称,或根据群昵称/QQ 昵称搜索 qqid。默认查询当前群聊,可通过 groupId 查询指定群。',\n },\n leaveGroup: {\n toolName: 'set_group_leave',\n description: '让机器人退出当前群聊。',\n },\n handleRequest: {\n toolName: 'handle_request',\n description: '根据 OneBot 申请 flag 同意或拒绝好友申请、加群申请或群邀请。',\n },\n setGroupKick: {\n toolName: 'set_group_kick',\n description: '将指定成员踢出群聊。',\n },\n setGroupSpecialTitle: {\n toolName: 'set_group_special_title',\n description: '修改或清除群成员的 QQ 群专属头衔。',\n },\n deleteMessage: {\n toolName: 'delete_msg',\n description: '根据消息 ID 撤回指定消息。',\n },\n}\n\nexport const NATIVE_TOOL_KEYS = Object.keys(NATIVE_TOOLS) as NativeToolKey[]\n\nexport const DEFAULT_MEMBER_INFO_ITEMS: MemberInfoItem[] = [\n 'nickname', 'userId', 'role', 'level', 'title', 'gender', 'age', 'area', 'joinTime', 'lastSentTime',\n]\n\nexport const DEFAULT_GROUP_INFO_ITEMS: GroupInfoItem[] = ['groupName', 'groupId', 'memberCount', 'ownerList', 'adminList']\n\n/** 变量名须满足 v2 模板的变量命名规则(`@chatluna/prompt` 的 `variable`),留空表示不注册。 */\nconst VARIABLE_NAME = /^([a-z_][a-z0-9_]*)?$/i\n\nconst memberItems = (subject: string) => Schema.array(Schema.union([\n Schema.const('userId').description(`${subject} ID`),\n Schema.const('nickname').description('群昵称'),\n Schema.const('role').description('群内身份'),\n Schema.const('level').description('群等级'),\n Schema.const('title').description('群头衔'),\n Schema.const('gender').description('性别'),\n Schema.const('age').description('年龄'),\n Schema.const('area').description('地区'),\n Schema.const('joinTime').description('入群时间'),\n Schema.const('lastSentTime').description('最后发言时间'),\n])).role('checkbox').default([...DEFAULT_MEMBER_INFO_ITEMS])\n\nconst variableName = (name: string) => Schema.string().default(name).pattern(VARIABLE_NAME).extra('label', '变量名称')\n .description('在预设中以`{变量名称}`引用,留空时不注册')\n\nconst basicFields = {\n oneBotProtocol: Schema.union([\n Schema.const('napcat').description('NapCat'),\n Schema.const('llbot').description('LLBot'),\n Schema.const('snowluma').description('SnowLuma'),\n ]).default('napcat').role('radio').extra('label', 'OneBot 协议')\n .description('按所选实现调整请求参数:LLBot 不支持设置性别,群禁言列表的群号类型也不同;SnowLuma 同意好友申请后另行设置备注'),\n requestNotice: Schema.boolean().default(true).extra('label', '申请通知')\n .description('收到好友申请、加群申请或群邀请时唤醒对应会话,把申请 flag 告诉模型,供`handle_request`工具处理。好友申请与群邀请发往申请人的私聊,加群申请发往所申请的群;该工具在工具管理中禁用时不唤醒'),\n}\n\nconst variableFields = {\n userInfo: Schema.object({\n variableName: variableName('userInfo'),\n items: memberItems('用户').extra('label', '信息项').description('选择用户信息变量中显示的详细信息项'),\n }).description('用户信息变量').collapse(),\n botInfo: Schema.object({\n variableName: variableName('botInfo'),\n items: memberItems('机器人').extra('label', '信息项').description('选择机器人信息变量中显示的详细信息项'),\n }).description('机器人信息变量').collapse(),\n groupInfo: Schema.object({\n variableName: variableName('groupInfo'),\n items: Schema.array(Schema.union([\n Schema.const('groupName').description('群名称'),\n Schema.const('groupId').description('群号'),\n Schema.const('memberCount').description('成员数量'),\n Schema.const('createTime').description('创建时间(仅部分实现支持)'),\n Schema.const('ownerList').description('群主名单'),\n Schema.const('adminList').description('管理员名单'),\n ])).role('checkbox').default([...DEFAULT_GROUP_INFO_ITEMS]).extra('label', '信息项')\n .description('选择群信息变量中显示的群信息项'),\n }).description('群信息变量').collapse(),\n groupShutList: Schema.object({\n variableName: variableName('groupShutList'),\n }).description('群禁言列表变量').collapse(),\n}\n\nconst otherFields = {\n debugLogging: Schema.boolean().default(false).extra('label', '输出调试日志')\n .description('以 info 级别输出工具调用与变量解析的调试信息'),\n}\n\n/**\n * 插件配置,直接在 v2 的插件设置页编辑。顶层是分组的 intersect,SchemaForm 把每组的 description 渲染成小节标题;\n * 每个字段都写 `extra('label')`,缺 label 时 SchemaForm 会把配置键当标题显示。\n */\nexport const Config: Schema<Config> = Schema.intersect([\n Schema.object(basicFields).description('基础设置'),\n Schema.object(variableFields).description('变量'),\n Schema.object(otherFields).description('其他设置'),\n])\n","import type { Context } from 'cordis'\nimport type { Session } from '@satorijs/core'\nimport type { RouteIdentity } from '@chatluna/satori'\nimport type {} from '@chatluna/chat'\nimport type { Config } from './config'\nimport { NATIVE_TOOLS } from './config'\nimport type { Logger } from './logger'\n\ntype RequestKind = 'friend' | 'add' | 'invite'\n\n/**\n * 申请发往的会话:好友申请与群邀请发往申请人的私聊,加群申请发往所申请的群。\n * 用路由身份而不是事件 Session 唤醒:申请事件不是消息,申请人与机器人之间往往还没有会话,\n * `chat.wake` 会按身份新开一个。\n */\nexport function requestTarget(session: Session, kind: RequestKind): RouteIdentity | undefined {\n if (!session.userId) return undefined\n if (kind === 'add') {\n if (!session.guildId) return undefined\n return { platform: session.platform, selfId: session.selfId, isDirect: false, guildId: session.guildId, channelId: session.guildId, userId: session.userId }\n }\n return { platform: session.platform, selfId: session.selfId, isDirect: true, channelId: `private:${session.userId}`, userId: session.userId }\n}\n\n/** 唤醒原因即模型看到的通知,写明 flag 与调用方式,模型据此调用处理申请工具。 */\nexport function requestReason(session: Session, kind: RequestKind, toolName: string): string {\n const comment = session.content?.trim() ? `, message: ${JSON.stringify(session.content.trim())}` : ''\n const flag = `flag: ${JSON.stringify(session.messageId ?? '')}`\n if (kind === 'friend') {\n return `user ${session.userId} sent you a friend request (${flag}${comment}). Call ${toolName} with requestType \"friend\" and userId \"${session.userId}\" to approve or reject it`\n }\n if (kind === 'add') {\n return `user ${session.userId} requested to join group ${session.guildId} (${flag}${comment}). Call ${toolName} with requestType \"group\" and subType \"add\" to approve or reject it`\n }\n return `user ${session.userId} invited you to join group ${session.guildId} (${flag}${comment}). Call ${toolName} with requestType \"group\" and subType \"invite\" to approve or reject it`\n}\n\n/**\n * v2 不把 OneBot 的申请事件交给模型,`handle_request` 拿不到 flag 就无从调用,\n * 所以把申请转成一次唤醒;工具在 v2 工具管理里被禁用时跟着不唤醒。会话所在路由关闭或没选模型时 `wake` 会报错,只记调试日志。\n */\nexport function registerRequestNotices(ctx: Context, config: Config, log: Logger) {\n if (!config.requestNotice) return\n const toolName = NATIVE_TOOLS.handleRequest.toolName\n ctx.inject(['chat'], (inner) => {\n const notify = (session: Session, kind: RequestKind) => {\n if (session.platform !== 'onebot') return\n // 没有 flag 时模型无从处理申请,唤醒只会让它拿空值反复试错。\n if (!session.messageId) return log.debug('%s request without flag ignored', kind)\n // 工具在 v2 工具管理里被禁用时(全局过滤排除了它)不唤醒:模型调用不到,唤醒只会让它白跑一轮。\n if (!inner.tools.list().some((tool) => tool.name === toolName)) return log.debug('%s request ignored: %s is disabled', kind, toolName)\n const target = requestTarget(session, kind)\n if (!target) return\n inner.chat.wake(target, { reason: requestReason(session, kind, toolName), by: 'onebot-toolbox' })\n .then(() => log.debug('%s request %s delivered', kind, session.messageId))\n .catch((error: unknown) => log.debug('%s request %s not delivered: %s', kind, session.messageId, String(error)))\n }\n inner.on('friend-request', (session) => notify(session, 'friend'))\n inner.on('guild-member-request', (session) => notify(session, 'add'))\n inner.on('guild-request', (session) => notify(session, 'invite'))\n })\n}\n","import type { Context } from 'cordis'\nimport type { Bot } from '@satorijs/core'\n\n/** OneBot 适配器的原始请求返回完整响应包,业务失败也照常 resolve。 */\ninterface OneBotInternal {\n _request(action: string, params: Record<string, unknown>): Promise<unknown>\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/** 会话所在的 OneBot 机器人;不是 OneBot 会话或找不到机器人时为 undefined。 */\nexport function oneBotOf(ctx: Context, platform: string | undefined, selfId: string | undefined): Bot | undefined {\n if (platform !== 'onebot' || selfId === undefined) return undefined\n return ctx.satori.bots.find((bot) => bot.platform === 'onebot' && bot.selfId === selfId)\n}\n\n/** 调用 OneBot action 并返回 data,按响应包的 status 与 retcode 判定业务失败。 */\nexport async function callOneBot(bot: Bot, action: string, params: Record<string, unknown>): Promise<unknown> {\n const internal: OneBotInternal = bot.internal\n const result = await internal._request(action, params)\n if (!isRecord(result) || typeof result.status !== 'string' || typeof result.retcode !== 'number') {\n throw new Error('Invalid OneBot response envelope')\n }\n if (result.status === 'ok' && result.retcode === 0) return result.data\n const reason = result.wording || result.message || result.status || 'OneBot returned failed'\n throw new Error(`${String(reason)} (retcode: ${result.retcode})`)\n}\n\n/**\n * 整数形式的 ID 转成数字,其余原样保留;OneBot 实现普遍要求数字形式的群号、QQ 号与消息 ID。\n * SnowLuma 的 message_id 是 int32 哈希,常为负数,所以带负号的整数同样转换。\n */\nexport function numericId(value: string): string | number {\n return /^-?\\d+$/.test(value) ? Number(value) : value\n}\n\n/** 取第一个非空值(去掉首尾空白后不为空字符串),保留原始类型。 */\nexport function pickFirst(...values: unknown[]): string | number | undefined {\n for (const value of values) {\n if (value === null || value === undefined) continue\n if (!String(value).trim()) continue\n return typeof value === 'number' ? value : String(value)\n }\n return undefined\n}\n\nexport function pickText(...values: unknown[]): string {\n return String(pickFirst(...values) ?? '').trim()\n}\n\n/** OneBot 使用秒,Satori 使用毫秒,统一成毫秒;空值与 0 视为没有。 */\nexport function normalizeTimestamp(raw: unknown): number | undefined {\n if (raw === null || raw === undefined || raw === '') return undefined\n const numeric = Number(raw)\n if (!Number.isFinite(numeric) || numeric === 0) return undefined\n return numeric < 1e11 ? numeric * 1000 : numeric\n}\n\nconst pad = (value: number) => String(value).padStart(2, '0')\n\nexport function formatDate(value: number | undefined): string {\n if (value === undefined) return ''\n const date = new Date(value)\n if (Number.isNaN(date.valueOf())) return ''\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`\n}\n\nexport function formatDateTime(value: number | undefined): string {\n const day = formatDate(value)\n if (!day || value === undefined) return day\n const date = new Date(value)\n return `${day} ${pad(date.getHours())}:${pad(date.getMinutes())}`\n}\n\n/** OneBot 群成员信息;其他平台的 Satori 成员信息在查询入口显式转换。 */\nexport interface MemberInfo {\n user_id?: unknown\n role?: unknown\n card?: unknown\n nickname?: unknown\n level?: unknown\n title?: unknown\n sex?: unknown\n age?: unknown\n area?: unknown\n join_time?: unknown\n last_sent_time?: unknown\n}\n\nexport function asMembers(value: unknown): MemberInfo[] {\n return Array.isArray(value) ? value.filter(isRecord) : []\n}\n\nexport function asRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined\n}\n","import type { Context } from 'cordis'\nimport type { Bot } from '@satorijs/core'\nimport { Schema } from '@chatluna/schema'\nimport type { ToolCallContext, ToolDefinition } from '@chatluna/tool'\nimport type { Agent } from '@chatluna/agent'\nimport type { ChatFileBlock, ChatMessage } from '@chatluna/message'\nimport { fileRefTableOf } from '@chatluna/message'\nimport type {} from '@chatluna/storage-files'\nimport type { Config, NativeToolKey, OneBotProtocol } from './config'\nimport { NATIVE_TOOL_KEYS, NATIVE_TOOLS } from './config'\nimport type { Logger } from './logger'\nimport {\n asMembers,\n callOneBot,\n pickText,\n numericId,\n oneBotOf,\n type MemberInfo,\n} from './onebot'\n\n/** 工具执行时的上下文:会话所在的机器人与群。 */\nexport interface ToolScope {\n ctx: Context\n bot: Bot\n /** 会话所在群;私聊为 undefined。 */\n guildId?: string\n protocol: OneBotProtocol\n /** 发起调用的 agent(`call.agent`),用来在会话日志里解析图片 ref;脱离会话的调用没有。 */\n agent?: object\n}\n\ninterface NativeTool<A> {\n args: Schema<any, A>\n effect: 'read' | 'write'\n run(scope: ToolScope, args: A): Promise<string>\n}\n\nconst MISSING_GROUP = 'Missing groupId. Provide groupId explicitly or run inside a group session.'\nconst MAX_MEMBER_RESULTS = 10\n\nconst groupIdArg = () => Schema.string().required(false).description('Target group ID. Defaults to current session group.')\n\nfunction groupOf(scope: ToolScope, groupId: string | undefined): string {\n const resolved = groupId?.trim() || scope.guildId?.trim()\n if (!resolved) throw new Error(MISSING_GROUP)\n return resolved\n}\n\nfunction required(value: string, name: string): string {\n const trimmed = value.trim()\n if (!trimmed) throw new Error(`${name} is required.`)\n return trimmed\n}\n\nconst GENDERS = { unknown: '0', male: '1', female: '2' }\n\nconst STORAGE_PREFIX = 'storage://'\n/** v2 给模型的文件占位符 `<img ref=\"i…\"/>`:`i` 加内容哈希的最短唯一前缀(至少 6 位)。 */\nconst FILE_REF = /^i[0-9a-f]{6,}$/\n\nconst base64File = (buffer: Buffer) => `base64://${buffer.toString('base64')}`\n\n/** HTTP/HTTPS 图片先读成 base64:OneBot 端常访问不到临时 URL,或 URL 在提交前就已过期。 */\nasync function remoteFile(url: string): Promise<string> {\n try {\n const response = await fetch(url)\n if (!response.ok) throw new Error(`HTTP ${response.status}`)\n return base64File(Buffer.from(await response.arrayBuffer()))\n } catch (error) {\n throw new Error(`无法读取头像图片:${error instanceof Error ? error.message : String(error)}`)\n }\n}\n\n/** 入站图片由 v2 下载进 `chatluna_storage`,24 小时后过期;没装存储插件时会话里只有 url 或 data 块。 */\nasync function storageFile(ctx: Context, reference: string): Promise<string> {\n const storage = ctx.get('chatluna_storage')\n if (!storage) throw new Error(`Cannot read ${reference}: the chatluna_storage service is not loaded.`)\n const file = await storage.getTempFile(reference.slice(STORAGE_PREFIX.length))\n if (!file) throw new Error(`${reference} is not in storage (it may have expired).`)\n return base64File(await file.data)\n}\n\nfunction dataFile(data: string): string {\n if (!data.startsWith('data:')) return `base64://${data}`\n const comma = data.indexOf(',')\n const body = data.slice(comma + 1)\n return data.slice(0, comma).endsWith(';base64') ? `base64://${body}` : base64File(Buffer.from(decodeURIComponent(body)))\n}\n\nfunction messagesOf(agent: object | undefined): readonly ChatMessage[] | undefined {\n const session: unknown = agent && 'session' in agent ? agent.session : undefined\n if (session === null || typeof session !== 'object' || !('messages' in session) || typeof session.messages !== 'function') return undefined\n return session.messages() as readonly ChatMessage[]\n}\n\n/**\n * v2 不把聊天图片的地址交给模型,只给 `<img ref=\"i…\"/>`,ref 要在发起调用的 agent 的会话日志里按内容哈希解析\n * (与 v2 自带的 `look` 工具、出站 `<img ref>` 同一张表)。\n */\nasync function sessionImageFile(scope: ToolScope, ref: string): Promise<string> {\n const messages = messagesOf(scope.agent)\n if (!messages) throw new Error(`Image ref ${ref} can only be resolved inside a conversation.`)\n const block: ChatFileBlock | undefined = fileRefTableOf(messages).resolve(ref)\n if (!block) throw new Error(`Image ref ${ref} is not in this conversation.`)\n if (!block.mediaType.startsWith('image/')) throw new Error(`ref ${ref} is ${block.mediaType}, not an image.`)\n // 用原图 data,不用写入时压缩的 preview。\n const { data } = block\n if (data.type === 'data') return dataFile(data.data)\n if (data.type === 'url') return remoteFile(data.url)\n if (data.type === 'reference' && data.reference.startsWith(STORAGE_PREFIX)) return storageFile(scope.ctx, data.reference)\n throw new Error(`Image ref ${ref} cannot be read.`)\n}\n\n/** 头像来源:会话图片 ref、`storage://`、HTTP/HTTPS 图片都先读成 base64 再提交,其余(OneBot 端可读的本地路径)原样提交。 */\nasync function avatarFile(scope: ToolScope, image: string): Promise<string> {\n if (FILE_REF.test(image)) return sessionImageFile(scope, image)\n if (image.startsWith(STORAGE_PREFIX)) return storageFile(scope.ctx, image)\n if (/^https?:\\/\\//i.test(image)) return remoteFile(image)\n return image\n}\n\nfunction formatMember(index: number, member: MemberInfo): string {\n return `${index}. qqid:${pickText(member.user_id) || '未知'},群昵称:${pickText(member.card) || '无'},QQ昵称:${pickText(member.nickname) || '无'}`\n}\n\nexport const NATIVE_TOOL_IMPLEMENTATIONS: { [K in NativeToolKey]: NativeTool<any> } = {\n setSelfProfile: {\n args: Schema.args({\n nickname: Schema.string().min(1).description('The new nickname for the bot.'),\n signature: Schema.string().required(false).description('Optional: the new personal signature.'),\n gender: Schema.union(['unknown', 'male', 'female']).required(false).description('Optional: the new gender.'),\n }),\n effect: 'write',\n async run(scope, args: { nickname: string, signature?: string, gender?: keyof typeof GENDERS }) {\n await callOneBot(scope.bot, 'set_qq_profile', {\n nickname: args.nickname,\n ...(args.signature ? { personal_note: args.signature } : {}),\n // LLBot 的 set_qq_profile 不接受 sex。\n ...(args.gender && scope.protocol !== 'llbot' ? { sex: GENDERS[args.gender] } : {}),\n })\n return '机器人资料已更新。'\n },\n },\n setQQAvatar: {\n args: Schema.args({\n imageUrl: Schema.string().min(1).description('The image: the ref attribute of an `<img ref=\"i…\"/>` in this conversation, an HTTP/HTTPS URL, or a local file path readable by the OneBot side.'),\n }),\n effect: 'write',\n async run(scope, args: { imageUrl: string }) {\n const file = await avatarFile(scope, required(args.imageUrl, 'imageUrl'))\n await callOneBot(scope.bot, 'set_qq_avatar', { file })\n return 'QQ 头像已更新。'\n },\n },\n setGroupCard: {\n args: Schema.args({\n groupId: groupIdArg(),\n userId: Schema.string().min(1).description('Target member user ID.'),\n card: Schema.string().min(1).description('New group card for the member.'),\n }),\n effect: 'write',\n async run(scope, args: { groupId?: string, userId: string, card: string }) {\n const groupId = groupOf(scope, args.groupId)\n const userId = required(args.userId, 'userId')\n const card = required(args.card, 'card')\n await callOneBot(scope.bot, 'set_group_card', { group_id: groupId, user_id: userId, card })\n return `群昵称已更新:${userId} -> ${card}`\n },\n },\n searchGroupMember: {\n args: Schema.args({\n groupId: groupIdArg(),\n query: Schema.string().min(1).description('qqid, group card, or QQ nickname to search.'),\n mode: Schema.union(['auto', 'byName', 'byQQ']).required(false).description('Search mode. Defaults to auto.'),\n }),\n effect: 'read',\n async run(scope, args: { groupId?: string, query: string, mode?: 'auto' | 'byName' | 'byQQ' }) {\n const query = required(args.query, 'query')\n const mode = args.mode ?? 'auto'\n const groupId = groupOf(scope, args.groupId)\n const members = asMembers(await callOneBot(scope.bot, 'get_group_member_list', { group_id: numericId(groupId) }))\n const byQQ = mode === 'byQQ' || (mode === 'auto' && /^\\d+$/.test(query))\n const keyword = query.toLowerCase()\n const matches = members.filter((member) => byQQ\n ? pickText(member.user_id) === query\n : [pickText(member.card), pickText(member.nickname)].some((name) => name && name.toLowerCase().includes(keyword)))\n if (!matches.length) return '未找到匹配的群成员。'\n const header = matches.length > MAX_MEMBER_RESULTS\n ? `仅显示前 ${MAX_MEMBER_RESULTS} 条,共 ${matches.length} 条匹配:`\n : `找到 ${matches.length} 个匹配成员:`\n return [header, ...matches.slice(0, MAX_MEMBER_RESULTS).map((member, index) => formatMember(index + 1, member))].join('\\n')\n },\n },\n leaveGroup: {\n args: Schema.args({ groupId: groupIdArg() }),\n effect: 'write',\n async run(scope, args: { groupId?: string }) {\n const groupId = groupOf(scope, args.groupId)\n await callOneBot(scope.bot, 'set_group_leave', { group_id: groupId })\n return `已退出群 ${groupId}。`\n },\n },\n handleRequest: {\n args: Schema.args({\n requestType: Schema.union(['friend', 'group']).description('Request type: friend or group.'),\n flag: Schema.string().min(1).description('OneBot request flag from the event.'),\n approve: Schema.boolean().description('true to approve the request, false to reject it.'),\n subType: Schema.union(['add', 'invite']).required(false).description('Required for group requests: add or invite.'),\n remark: Schema.string().required(false).description('Optional friend remark when approving a friend request.'),\n userId: Schema.string().required(false).description('Requester user ID of a friend request; needed to apply the remark on SnowLuma.'),\n reason: Schema.string().required(false).description('Optional rejection reason for a group request.'),\n }),\n effect: 'write',\n async run(scope, args: { requestType: 'friend' | 'group', flag: string, approve: boolean, subType?: 'add' | 'invite', remark?: string, userId?: string, reason?: string }) {\n const flag = required(args.flag, 'request flag')\n const verb = args.approve ? '同意' : '拒绝'\n if (args.requestType === 'friend') {\n const remark = args.remark?.trim() ?? ''\n await callOneBot(scope.bot, 'set_friend_add_request', { flag, approve: args.approve, remark })\n const message = `已${verb}好友申请 ${flag}。`\n // SnowLuma 的 set_friend_add_request 不读 remark,同意后另用 set_friend_remark 设置。\n if (scope.protocol !== 'snowluma' || !args.approve || !remark) return message\n const userId = args.userId?.trim()\n if (!userId) return `${message}未提供申请人 userId,备注未设置。`\n await callOneBot(scope.bot, 'set_friend_remark', { user_id: numericId(userId), remark })\n return `${message}备注已设置为 ${remark}。`\n }\n if (!args.subType) throw new Error('subType is required for group requests; use add or invite.')\n await callOneBot(scope.bot, 'set_group_add_request', {\n flag,\n sub_type: args.subType,\n approve: args.approve,\n reason: args.reason?.trim() ?? '',\n })\n return `已${verb}${args.subType === 'invite' ? '群邀请' : '加群申请'} ${flag}。`\n },\n },\n setGroupKick: {\n args: Schema.args({\n groupId: groupIdArg(),\n userId: Schema.string().min(1).description('Target member user ID.'),\n }),\n effect: 'write',\n async run(scope, args: { groupId?: string, userId: string }) {\n const groupId = groupOf(scope, args.groupId)\n const userId = required(args.userId, 'userId')\n await callOneBot(scope.bot, 'set_group_kick', { group_id: groupId, user_id: userId })\n return `已将用户 ${userId} 移出群 ${groupId}。`\n },\n },\n setGroupSpecialTitle: {\n args: Schema.args({\n groupId: groupIdArg(),\n userId: Schema.string().min(1).description('Target member user ID.'),\n title: Schema.string().description('New special title. Use an empty string to clear it.'),\n }),\n effect: 'write',\n async run(scope, args: { groupId?: string, userId: string, title: string }) {\n const groupId = groupOf(scope, args.groupId)\n const userId = required(args.userId, 'userId')\n const title = args.title.trim()\n await callOneBot(scope.bot, 'set_group_special_title', { group_id: groupId, user_id: userId, special_title: title })\n return title ? `群专属头衔已更新:${userId} -> ${title}` : `群专属头衔已清除:${userId}`\n },\n },\n deleteMessage: {\n args: Schema.args({\n message_id: Schema.string().min(1).description('Specific message ID to delete.'),\n }),\n effect: 'write',\n async run(scope, args: { message_id: string }) {\n const messageId = required(args.message_id, 'message_id')\n await callOneBot(scope.bot, 'delete_msg', { message_id: numericId(messageId) })\n return `Message deleted by ID ${messageId}.`\n },\n },\n}\n\n/** 全部原生工具的定义,名称与描述统一取自 NATIVE_TOOLS。 */\nexport function nativeToolDefinitions(ctx: Context, config: Config, log: Logger): ToolDefinition[] {\n return NATIVE_TOOL_KEYS.map((key) => {\n const tool = NATIVE_TOOL_IMPLEMENTATIONS[key]\n const { toolName: name, description } = NATIVE_TOOLS[key]\n return {\n name,\n description,\n args: tool.args,\n traits: { effect: tool.effect },\n async run(args: unknown, call: ToolCallContext) {\n const location = call.location\n const bot = oneBotOf(ctx, location?.platform, location?.selfId)\n if (!bot) throw new Error('This tool only supports OneBot platform.')\n try {\n const result = await tool.run({ ctx, bot, guildId: location?.isDirect ? undefined : location?.guild, protocol: config.oneBotProtocol, agent: call.agent }, args)\n log.debug('%s: %s', name, result)\n return result\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n log.warn('%s failed: %s', name, message)\n throw new Error(`${name} failed: ${message}`)\n }\n },\n }\n })\n}\n\n/**\n * 注册原生工具。工具对所有会话全局可见(v2 的工具管理页因此能列出并开关它们),\n * 再给不在 OneBot 上的 agent 挂一层排除过滤。\n */\nexport function registerNativeTools(ctx: Context, config: Config, log: Logger) {\n const definitions = nativeToolDefinitions(ctx, config, log)\n for (const definition of definitions) ctx.tools.define(definition)\n const exclude = definitions.map((definition) => definition.name)\n log.info('native tools registered: %s', exclude.join(', '))\n ctx.inject(['agents'], (inner) => {\n const scope = (agent: Agent) => {\n if (agent.options.location?.platform !== 'onebot') inner.tools.filter({ exclude }, agent)\n }\n inner.on('chatluna/agent-open', ({ agent }) => scope(agent))\n for (const agent of inner.agents.list()) scope(agent)\n })\n}\n","import type { Context } from 'cordis'\nimport type { Bot } from '@satorijs/core'\nimport type { PromptEnvironment, VariableDeclaration, VariableProvider } from '@chatluna/prompt'\nimport type { Config, GroupInfoItem, MemberInfoItem, OneBotProtocol } from './config'\nimport { DEFAULT_GROUP_INFO_ITEMS } from './config'\nimport type { Logger } from './logger'\nimport {\n asRecord,\n asMembers,\n callOneBot,\n formatDate,\n formatDateTime,\n normalizeTimestamp,\n oneBotOf,\n pickFirst,\n pickText,\n type MemberInfo,\n} from './onebot'\n\nconst FALLBACK_MEMBER_ITEMS: MemberInfoItem[] = ['nickname', 'userId']\n\nconst SHUT_LIST_TIMEOUT_MS = 200\nconst SHUT_LIST_CACHE_TTL_MS = 15_000\n\nfunction translateGender(value: unknown): string {\n if (value === 'male') return '男'\n if (value === 'female') return '女'\n return ''\n}\n\nfunction normalizeRole(value: string): string {\n if (value === 'owner') return '群主'\n if (value === 'admin') return '管理员'\n return !value || value === 'member' ? '群员' : value\n}\n\n/** 会话所在的 Satori 机器人,任意平台;预览等没有真实机器人的环境里为 undefined。 */\nfunction botOf(ctx: Context, env: PromptEnvironment): Bot | undefined {\n return ctx.satori.bots.find((bot) => bot.platform === env.platform && bot.selfId === env.selfId)\n}\n\n/** 查询群成员信息;私聊、找不到机器人或查询失败时为 undefined,变量照常按已知信息渲染。 */\nasync function fetchMember(ctx: Context, env: PromptEnvironment, userId: string): Promise<MemberInfo | undefined> {\n const bot = botOf(ctx, env)\n if (!bot || !env.guildId) return undefined\n try {\n if (bot.platform === 'onebot') {\n return asRecord(await callOneBot(bot, 'get_group_member_info', {\n group_id: Number(env.guildId),\n user_id: Number(userId),\n no_cache: false,\n }))\n }\n const member = await bot.getGuildMember(env.guildId, userId)\n return {\n user_id: member.user?.id,\n card: pickText(member.nick, member.name),\n nickname: member.user?.name,\n role: member.roles?.[0]?.id,\n title: member.title,\n join_time: member.joinedAt,\n }\n } catch {\n return undefined\n }\n}\n\n/** 用户信息与机器人信息共用的渲染:按配置的信息项逐条输出,取不到的项省略。 */\nfunction renderMember(member: MemberInfo | undefined, items: MemberInfoItem[], id: string, fallbackName: unknown): string[] {\n const values: string[] = []\n for (const item of items) {\n switch (item) {\n case 'nickname': {\n const name = pickText(member?.card, member?.nickname, fallbackName, id)\n if (name) values.push(`name:${name}`)\n break\n }\n case 'userId':\n if (id) values.push(`id:${id}`)\n break\n case 'role':\n values.push(`群内身份:${normalizeRole(pickText(member?.role))}`)\n break\n case 'level': {\n const level = pickFirst(member?.level)\n if (level !== undefined) values.push(`群等级:${level}`)\n break\n }\n case 'title': {\n const title = pickFirst(member?.title)\n if (title !== undefined) values.push(`头衔:${title}`)\n break\n }\n case 'gender': {\n const gender = translateGender(member?.sex)\n if (gender) values.push(`性别:${gender}`)\n break\n }\n case 'age': {\n const age = Number(member?.age)\n if (Number.isFinite(age) && age > 0) values.push(`年龄:${age}`)\n break\n }\n case 'area': {\n const area = pickFirst(member?.area)\n if (area !== undefined) values.push(`地区:${area}`)\n break\n }\n case 'joinTime': {\n const joinTime = formatDate(normalizeTimestamp(member?.join_time))\n if (joinTime) values.push(`入群:${joinTime}`)\n break\n }\n case 'lastSentTime': {\n const lastSentTime = formatDateTime(normalizeTimestamp(member?.last_sent_time))\n if (lastSentTime) values.push(`活跃:${lastSentTime}`)\n break\n }\n }\n }\n return values\n}\n\nconst itemsOf = (items: MemberInfoItem[]) => items.length ? items : FALLBACK_MEMBER_ITEMS\n\nexport function userInfoProvider(ctx: Context, config: Config): VariableProvider {\n return async ({ env }) => {\n // 群聊里 userId 只来自本步最新的用户消息,工具调用后的后续步骤可能缺失,退回到消息发送者。\n const userId = (env.userId ?? env.message?.senderId)?.trim()\n if (!userId) return '未知用户'\n const member = await fetchMember(ctx, env, userId)\n const values = renderMember(member, itemsOf(config.userInfo.items), userId, env.userName ?? env.message?.senderName)\n return values.length ? values.join(', ') : `id:${userId}`\n }\n}\n\nexport function botInfoProvider(ctx: Context, config: Config): VariableProvider {\n return async ({ env }) => {\n const botId = env.selfId?.trim()\n if (!botId) return '未知机器人'\n const member = await fetchMember(ctx, env, botId)\n const values = renderMember(member, itemsOf(config.botInfo.items), botId, undefined)\n return values.length ? values.join(', ') : botId\n }\n}\n\ninterface GroupInfo {\n group_id?: unknown\n group_name?: unknown\n member_count?: unknown\n create_time?: unknown\n group_create_time?: unknown\n}\n\nasync function fetchRoles(bot: Bot, guildId: string, log: Logger): Promise<{ owners: string[], admins: string[] } | undefined> {\n try {\n const members = asMembers(await callOneBot(bot, 'get_group_member_list', { group_id: Number(guildId) }))\n if (!members.length) return undefined\n const owners: string[] = []\n const admins: string[] = []\n for (const member of members) {\n const role = member.role\n const userId = pickText(member.user_id)\n const name = pickText(member.card, member.nickname, userId)\n const label = userId ? `${name}(${userId})` : name\n if (role === 'owner') owners.push(label)\n else if (role === 'admin') admins.push(label)\n }\n return { owners, admins }\n } catch (error) {\n log.debug('group roles lookup failed: %s', String(error))\n return undefined\n }\n}\n\nfunction renderGroupInfo(group: GroupInfo, items: GroupInfoItem[], roles: { owners: string[], admins: string[] } | undefined): string {\n const id = pickText(group.group_id)\n const name = pickText(group.group_name)\n const memberCount = group.member_count\n const createTime = formatDate(normalizeTimestamp(group.create_time ?? group.group_create_time))\n const values: string[] = []\n for (const item of items) {\n switch (item) {\n case 'groupName':\n if (name) values.push(`群名:${name}`)\n break\n case 'groupId':\n if (id) values.push(`群号:${id}`)\n break\n case 'memberCount':\n if (memberCount !== undefined && memberCount !== null) values.push(`成员数量:${String(memberCount)}`)\n break\n case 'createTime':\n if (createTime) values.push(`创建时间:${createTime}`)\n break\n case 'ownerList':\n if (roles) values.push(`群主:${roles.owners.length ? roles.owners.join('、') : '无'}`)\n break\n case 'adminList':\n if (roles) values.push(`管理员:${roles.admins.length ? roles.admins.join('、') : '无'}`)\n break\n }\n }\n return values.length ? values.join('\\n') : id || name || '未能获取当前群信息。'\n}\n\nexport function groupInfoProvider(ctx: Context, config: Config, log: Logger): VariableProvider {\n return async ({ env }) => {\n if (!env.guildId) return ''\n if (env.platform !== 'onebot') return '当前平台暂不支持查询群信息。'\n const bot = oneBotOf(ctx, env.platform, env.selfId)\n if (!bot) return '暂无群信息。'\n const items = config.groupInfo.items.length ? config.groupInfo.items : DEFAULT_GROUP_INFO_ITEMS\n const group = await callOneBot(bot, 'get_group_info', { group_id: Number(env.guildId), no_cache: false })\n .then(asRecord, () => undefined)\n if (!group) return '未能获取当前群信息。'\n const roles = items.includes('ownerList') || items.includes('adminList') ? await fetchRoles(bot, env.guildId, log) : undefined\n return renderGroupInfo(group, items, roles)\n }\n}\n\nclass ShutListTimeout extends Error {}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new ShutListTimeout('group shut list request timed out')), ms)\n }),\n ]).finally(() => clearTimeout(timer))\n}\n\nasync function fetchShutList(bot: Bot, guildId: string, protocol: OneBotProtocol): Promise<unknown[]> {\n const groupId = protocol === 'llbot' ? guildId : Number(guildId)\n const data = await withTimeout(callOneBot(bot, 'get_group_shut_list', { group_id: groupId }), SHUT_LIST_TIMEOUT_MS)\n return Array.isArray(data) ? data : []\n}\n\nfunction renderShutItem(item: unknown): string | undefined {\n const record = asRecord(item)\n if (!record) return undefined\n const userId = pickText(record.uin, record.user_id)\n if (!userId) return undefined\n const name = pickText(record.cardName, record.remark, record.nick, record.nickname, userId)\n const until = formatDateTime(normalizeTimestamp(pickFirst(record.shutUpTime, record.shut_up_time))) || '未知'\n return `id:${userId},name:${name},禁言截至:${until}`\n}\n\nexport function groupShutListProvider(ctx: Context, config: Config, log: Logger): VariableProvider {\n // 变量每一步都会重新渲染,同一个群的结果缓存 15 秒,避免每一步都请求一次。\n const cache = new Map<string, { value: string, expiresAt: number }>()\n return async ({ env }) => {\n if (!env.guildId) return ''\n if (env.platform !== 'onebot') return '当前平台暂不支持查询群禁言列表。'\n const bot = oneBotOf(ctx, env.platform, env.selfId)\n if (!bot) return '暂无群禁言列表。'\n const key = `${env.selfId}:${env.guildId}`\n const cached = cache.get(key)\n if (cached && cached.expiresAt > Date.now()) return cached.value\n try {\n const lines = (await fetchShutList(bot, env.guildId, config.oneBotProtocol)).flatMap((item) => renderShutItem(item) ?? [])\n const value = lines.length ? lines.join('\\n') : '当前群暂无禁言成员。'\n cache.set(key, { value, expiresAt: Date.now() + SHUT_LIST_CACHE_TTL_MS })\n return value\n } catch (error) {\n log.debug('group shut list failed: %s', String(error))\n // 部分实现在群里没有禁言成员时迟迟不响应,超时按空列表处理。\n return error instanceof ShutListTimeout ? '当前群暂无禁言成员。' : '获取群禁言列表失败。'\n }\n }\n}\n\n/** 按配置得到要注册的变量;变量名留空的不注册。 */\nexport function variableDefinitions(ctx: Context, config: Config, log: Logger): Array<[VariableDeclaration, VariableProvider]> {\n const entries: Array<[string, string, VariableProvider]> = [\n [config.userInfo.variableName, 'Current user info in this group', userInfoProvider(ctx, config)],\n [config.botInfo.variableName, 'Bot info in this group', botInfoProvider(ctx, config)],\n [config.groupInfo.variableName, 'Current group info', groupInfoProvider(ctx, config, log)],\n [config.groupShutList.variableName, 'Muted members of this group', groupShutListProvider(ctx, config, log)],\n ]\n // 都随群聊状态变化,属于可变变量,不能写进 system 区。\n return entries\n .filter(([name]) => name.trim())\n .map(([name, description, provider]) => [{ name: name.trim(), description, mutable: true }, provider])\n}\n\nexport function registerVariables(ctx: Context, config: Config, log: Logger) {\n for (const [declaration, provider] of variableDefinitions(ctx, config, log)) {\n try {\n ctx.prompt.variable(declaration, provider)\n } catch (error) {\n // 同名变量已被其他插件注册时只跳过这一个,其余变量与工具照常可用。\n log.warn('variable %s not registered: %s', declaration.name, error instanceof Error ? error.message : String(error))\n }\n }\n}\n","import type { Context } from 'cordis'\nimport type { Config } from './config'\nimport { createLogger } from './logger'\nimport { registerRequestNotices } from './requests'\nimport { registerNativeTools } from './tools'\nimport { registerVariables } from './variables'\n\nexport * from './config'\n\nexport const name = 'chatluna-onebot-toolbox'\n\n/** 过滤工具用的 agents、唤醒用的 chat 与读取会话图片用的 chatluna_storage 是可选服务。 */\nexport const inject = ['satori', 'tools', 'prompt']\n\nexport function apply(ctx: Context, config: Config) {\n const log = createLogger(ctx, config.debugLogging)\n registerVariables(ctx, config, log)\n registerNativeTools(ctx, config, log)\n registerRequestNotices(ctx, config, log)\n}\n"],"mappings":"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"}
|
package/lib/logger.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Context } from 'cordis';
|
|
2
|
+
/** 插件内的日志:`debugLogging` 打开时调试信息以 info 级别输出,否则走 logger 自己的 debug 级别。 */
|
|
3
|
+
export interface Logger {
|
|
4
|
+
debug(format: string, ...args: unknown[]): void;
|
|
5
|
+
info(format: string, ...args: unknown[]): void;
|
|
6
|
+
warn(format: string, ...args: unknown[]): void;
|
|
7
|
+
}
|
|
8
|
+
export declare function createLogger(ctx: Context, debugLogging: boolean): Logger;
|
|
9
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAErC,wEAAwE;AACxE,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC/C,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC9C,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;CAC/C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAOxE"}
|
package/lib/onebot.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Context } from 'cordis';
|
|
2
|
+
import type { Bot } from '@satorijs/core';
|
|
3
|
+
/** 会话所在的 OneBot 机器人;不是 OneBot 会话或找不到机器人时为 undefined。 */
|
|
4
|
+
export declare function oneBotOf(ctx: Context, platform: string | undefined, selfId: string | undefined): Bot | undefined;
|
|
5
|
+
/** 调用 OneBot action 并返回 data,按响应包的 status 与 retcode 判定业务失败。 */
|
|
6
|
+
export declare function callOneBot(bot: Bot, action: string, params: Record<string, unknown>): Promise<unknown>;
|
|
7
|
+
/**
|
|
8
|
+
* 整数形式的 ID 转成数字,其余原样保留;OneBot 实现普遍要求数字形式的群号、QQ 号与消息 ID。
|
|
9
|
+
* SnowLuma 的 message_id 是 int32 哈希,常为负数,所以带负号的整数同样转换。
|
|
10
|
+
*/
|
|
11
|
+
export declare function numericId(value: string): string | number;
|
|
12
|
+
/** 取第一个非空值(去掉首尾空白后不为空字符串),保留原始类型。 */
|
|
13
|
+
export declare function pickFirst(...values: unknown[]): string | number | undefined;
|
|
14
|
+
export declare function pickText(...values: unknown[]): string;
|
|
15
|
+
/** OneBot 使用秒,Satori 使用毫秒,统一成毫秒;空值与 0 视为没有。 */
|
|
16
|
+
export declare function normalizeTimestamp(raw: unknown): number | undefined;
|
|
17
|
+
export declare function formatDate(value: number | undefined): string;
|
|
18
|
+
export declare function formatDateTime(value: number | undefined): string;
|
|
19
|
+
/** OneBot 群成员信息;其他平台的 Satori 成员信息在查询入口显式转换。 */
|
|
20
|
+
export interface MemberInfo {
|
|
21
|
+
user_id?: unknown;
|
|
22
|
+
role?: unknown;
|
|
23
|
+
card?: unknown;
|
|
24
|
+
nickname?: unknown;
|
|
25
|
+
level?: unknown;
|
|
26
|
+
title?: unknown;
|
|
27
|
+
sex?: unknown;
|
|
28
|
+
age?: unknown;
|
|
29
|
+
area?: unknown;
|
|
30
|
+
join_time?: unknown;
|
|
31
|
+
last_sent_time?: unknown;
|
|
32
|
+
}
|
|
33
|
+
export declare function asMembers(value: unknown): MemberInfo[];
|
|
34
|
+
export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
|
|
35
|
+
//# sourceMappingURL=onebot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onebot.d.ts","sourceRoot":"","sources":["../src/onebot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AAUzC,wDAAwD;AACxD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,GAAG,SAAS,CAGhH;AAED,+DAA+D;AAC/D,wBAAsB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAS5G;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAExD;AAED,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAO3E;AAED,wBAAgB,QAAQ,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAErD;AAED,+CAA+C;AAC/C,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKnE;AAID,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAK5D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKhE;AAED,+CAA+C;AAC/C,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,EAAE,CAEtD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAE5E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Context } from 'cordis';
|
|
2
|
+
import type { Session } from '@satorijs/core';
|
|
3
|
+
import type { RouteIdentity } from '@chatluna/satori';
|
|
4
|
+
import type { Config } from './config';
|
|
5
|
+
import type { Logger } from './logger';
|
|
6
|
+
type RequestKind = 'friend' | 'add' | 'invite';
|
|
7
|
+
/**
|
|
8
|
+
* 申请发往的会话:好友申请与群邀请发往申请人的私聊,加群申请发往所申请的群。
|
|
9
|
+
* 用路由身份而不是事件 Session 唤醒:申请事件不是消息,申请人与机器人之间往往还没有会话,
|
|
10
|
+
* `chat.wake` 会按身份新开一个。
|
|
11
|
+
*/
|
|
12
|
+
export declare function requestTarget(session: Session, kind: RequestKind): RouteIdentity | undefined;
|
|
13
|
+
/** 唤醒原因即模型看到的通知,写明 flag 与调用方式,模型据此调用处理申请工具。 */
|
|
14
|
+
export declare function requestReason(session: Session, kind: RequestKind, toolName: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* v2 不把 OneBot 的申请事件交给模型,`handle_request` 拿不到 flag 就无从调用,
|
|
17
|
+
* 所以把申请转成一次唤醒;工具在 v2 工具管理里被禁用时跟着不唤醒。会话所在路由关闭或没选模型时 `wake` 会报错,只记调试日志。
|
|
18
|
+
*/
|
|
19
|
+
export declare function registerRequestNotices(ctx: Context, config: Config, log: Logger): void;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=requests.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../src/requests.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEtC,KAAK,WAAW,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAA;AAE9C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,aAAa,GAAG,SAAS,CAO5F;AAED,+CAA+C;AAC/C,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAU3F;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAoB/E"}
|
package/lib/tools.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Context } from 'cordis';
|
|
2
|
+
import type { Bot } from '@satorijs/core';
|
|
3
|
+
import { Schema } from '@chatluna/schema';
|
|
4
|
+
import type { ToolDefinition } from '@chatluna/tool';
|
|
5
|
+
import type { Config, NativeToolKey, OneBotProtocol } from './config';
|
|
6
|
+
import type { Logger } from './logger';
|
|
7
|
+
/** 工具执行时的上下文:会话所在的机器人与群。 */
|
|
8
|
+
export interface ToolScope {
|
|
9
|
+
ctx: Context;
|
|
10
|
+
bot: Bot;
|
|
11
|
+
/** 会话所在群;私聊为 undefined。 */
|
|
12
|
+
guildId?: string;
|
|
13
|
+
protocol: OneBotProtocol;
|
|
14
|
+
/** 发起调用的 agent(`call.agent`),用来在会话日志里解析图片 ref;脱离会话的调用没有。 */
|
|
15
|
+
agent?: object;
|
|
16
|
+
}
|
|
17
|
+
interface NativeTool<A> {
|
|
18
|
+
args: Schema<any, A>;
|
|
19
|
+
effect: 'read' | 'write';
|
|
20
|
+
run(scope: ToolScope, args: A): Promise<string>;
|
|
21
|
+
}
|
|
22
|
+
export declare const NATIVE_TOOL_IMPLEMENTATIONS: {
|
|
23
|
+
[K in NativeToolKey]: NativeTool<any>;
|
|
24
|
+
};
|
|
25
|
+
/** 全部原生工具的定义,名称与描述统一取自 NATIVE_TOOLS。 */
|
|
26
|
+
export declare function nativeToolDefinitions(ctx: Context, config: Config, log: Logger): ToolDefinition[];
|
|
27
|
+
/**
|
|
28
|
+
* 注册原生工具。工具对所有会话全局可见(v2 的工具管理页因此能列出并开关它们),
|
|
29
|
+
* 再给不在 OneBot 上的 agent 挂一层排除过滤。
|
|
30
|
+
*/
|
|
31
|
+
export declare function registerNativeTools(ctx: Context, config: Config, log: Logger): void;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAKrE,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAErE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAUtC,4BAA4B;AAC5B,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,OAAO,CAAA;IACZ,GAAG,EAAE,GAAG,CAAA;IACR,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,cAAc,CAAA;IACxB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,UAAU,UAAU,CAAC,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;IACpB,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;IACxB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CAChD;AA0FD,eAAO,MAAM,2BAA2B,EAAE;KAAG,CAAC,IAAI,aAAa,GAAG,UAAU,CAAC,GAAG,CAAC;CAuJhF,CAAA;AAED,wCAAwC;AACxC,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,CAyBjG;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAY5E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Context } from 'cordis';
|
|
2
|
+
import type { VariableDeclaration, VariableProvider } from '@chatluna/prompt';
|
|
3
|
+
import type { Config } from './config';
|
|
4
|
+
import type { Logger } from './logger';
|
|
5
|
+
export declare function userInfoProvider(ctx: Context, config: Config): VariableProvider;
|
|
6
|
+
export declare function botInfoProvider(ctx: Context, config: Config): VariableProvider;
|
|
7
|
+
export declare function groupInfoProvider(ctx: Context, config: Config, log: Logger): VariableProvider;
|
|
8
|
+
export declare function groupShutListProvider(ctx: Context, config: Config, log: Logger): VariableProvider;
|
|
9
|
+
/** 按配置得到要注册的变量;变量名留空的不注册。 */
|
|
10
|
+
export declare function variableDefinitions(ctx: Context, config: Config, log: Logger): Array<[VariableDeclaration, VariableProvider]>;
|
|
11
|
+
export declare function registerVariables(ctx: Context, config: Config, log: Logger): void;
|
|
12
|
+
//# sourceMappingURL=variables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variables.d.ts","sourceRoot":"","sources":["../src/variables.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAErC,OAAO,KAAK,EAAqB,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAChG,OAAO,KAAK,EAAE,MAAM,EAAiD,MAAM,UAAU,CAAA;AAErF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAwHtC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAS/E;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAQ9E;AA8DD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAa7F;AA8BD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAsBjG;AAED,6BAA6B;AAC7B,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC,CAW7H;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAS1E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,81 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chatluna-plugin-onebot-toolbox",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "为 ChatLuna 提供 OneBot 原生工具与群聊信息变量:修改资料与头像、群名片与头衔、搜索群成员、退群、踢人、处理申请、撤回消息",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Sor85/chatluna-plugin-onebot-toolbox.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/Sor85/chatluna-plugin-onebot-toolbox#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/Sor85/chatluna-plugin-onebot-toolbox/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"chatluna-plugin",
|
|
17
|
+
"onebot",
|
|
18
|
+
"toolbox",
|
|
19
|
+
"tools",
|
|
20
|
+
"variables"
|
|
21
|
+
],
|
|
22
|
+
"main": "lib/index.js",
|
|
23
|
+
"types": "lib/index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./lib/index.d.ts",
|
|
27
|
+
"default": "./lib/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"lib",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=24.0.0"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"sync": "node scripts/sync-to-v2.mjs --once",
|
|
40
|
+
"sync:watch": "node scripts/sync-to-v2.mjs",
|
|
41
|
+
"build": "yakumo build",
|
|
42
|
+
"clean": "yakumo clean",
|
|
43
|
+
"test": "vitest run"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@chatluna/message": ">=2.0.0-alpha.0",
|
|
47
|
+
"@chatluna/schema": ">=2.0.0-alpha.0",
|
|
48
|
+
"cordis": "^4.0.0-rc.12"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@chatluna/agent": "2.0.0-alpha.0",
|
|
52
|
+
"@chatluna/chat": "2.0.0-alpha.0",
|
|
53
|
+
"@chatluna/message": "2.0.0-alpha.0",
|
|
54
|
+
"@chatluna/prompt": "2.0.0-alpha.0",
|
|
55
|
+
"@chatluna/satori": "2.0.0-alpha.0",
|
|
56
|
+
"@chatluna/schema": "2.0.0-alpha.0",
|
|
57
|
+
"@chatluna/storage-files": "2.0.0-alpha.0",
|
|
58
|
+
"@chatluna/tool": "2.0.0-alpha.0",
|
|
59
|
+
"@satorijs/core": "~4.6.1",
|
|
60
|
+
"cordis": "4.0.0-rc.12",
|
|
61
|
+
"vitest": "^3.2.4"
|
|
62
|
+
},
|
|
63
|
+
"cordis": {
|
|
64
|
+
"description": {
|
|
65
|
+
"en": "OneBot native tools and group-info prompt variables for ChatLuna",
|
|
66
|
+
"zh": "为 ChatLuna 提供 OneBot 原生工具与群聊信息变量"
|
|
67
|
+
},
|
|
68
|
+
"service": {
|
|
69
|
+
"required": [
|
|
70
|
+
"satori",
|
|
71
|
+
"tools",
|
|
72
|
+
"prompt"
|
|
73
|
+
],
|
|
74
|
+
"optional": [
|
|
75
|
+
"agents",
|
|
76
|
+
"chat",
|
|
77
|
+
"chatluna_storage"
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
6
81
|
}
|