@qihoo/tuitui-openclaw-channel 1.0.45 → 1.0.47

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qihoo/tuitui-openclaw-channel",
3
- "version": "1.0.45",
3
+ "version": "1.0.47",
4
4
  "maintainers": [
5
5
  {
6
6
  "name": "huzunjie",
@@ -179,6 +179,7 @@ function createTuiTuiChannelPlugin(apiRuntime) {
179
179
  deliveryMode: 'direct',
180
180
  textChunkLimit: 10000, // API上限制为50k
181
181
  sendText: async ({ cfg, to, text, accountId, replyToId, threadId }) => {
182
+ console.log(`[${CHANNEL_ID}] sendText to=${to}, text=${text}, accountId=${accountId}`);
182
183
  const account = resolveAccount(cfg, accountId);
183
184
  const { chatId, chatType } = await guessChatTypeV2(account, to);
184
185
  console.log(`[${CHANNEL_ID}] AccountId ${accountId} outbound.sendText() ${chatType} to ${chatId} ${text}`);
@@ -196,8 +197,10 @@ function createTuiTuiChannelPlugin(apiRuntime) {
196
197
  return { channel: CHANNEL_ID, messageId: `tuitui-page-${Date.now()}`, chatId };
197
198
  },
198
199
  sendMedia: async ({ cfg, to, mediaUrl, accountId, account }) => {
200
+ console.log(`[${CHANNEL_ID}] sendMedia to=${to}, mediaUrl=${mediaUrl}, accountId=${accountId}`);
199
201
  account = account || resolveAccount(cfg, accountId);
200
202
  const { chatId, chatType } = await guessChatTypeV2(account, to);
203
+ console.log(`[${CHANNEL_ID}] sendMediaMsg guess chatId=${chatId}, chatType=${chatType}`);
201
204
  await sendMediaMsg(account, chatId, chatType, mediaUrl, 'tuitui.send.media');
202
205
  return { channel: CHANNEL_ID, messageId: `tuitui-media-${Date.now()}`, chatId };
203
206
  },
@@ -1 +1 @@
1
- {"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TuiTui Channel Plugin for OpenClaw.\n *\n * Implements the ChannelPlugin interface following the Synology Chat pattern.\n */\nimport { DEFAULT_ACCOUNT_ID } from 'openclaw/plugin-sdk/account-id';\nimport { setAccountEnabledInConfigSection, deleteAccountFromConfigSection, OpenClawPluginApi } from 'openclaw/plugin-sdk/core';\nimport { CHANNEL_ID, CHANNEL_NAME } from \"./const\";\nimport { version } from \"../package.json\"\nimport { handleInboundMessage } from './inbound';\nimport { guessChatTypeV2 } from \"./chat_record\"\nimport {\n sendTextMsg,\n sendPageMsg,\n sendMediaMsg,\n} from \"./outbound\";\nimport createWebSocket from './websocket';\nimport { channelConfigs } from '../openclaw.plugin.json';\nimport { isEnabled } from './utils';\nimport { dmPolicyDefault, resolveAccount, getAccountInfo } from \"./accounts\"\n\nconst isConfigured = (account: any)=> !!(account?.appId && account?.appSecret);\n\nlet _checkTuiTuiChannelLock = false;\nconst checkAndSetDefaultTuiTuiConfig = async (api: any) => {\n if (_checkTuiTuiChannelLock) return;\n _checkTuiTuiChannelLock = true;\n\n try {\n const cfg = await api.runtime.config.loadConfig();\n if (!cfg || !cfg.plugins || !cfg.models) return; // 基础配置结构不完整(插件无法运行的),后续流程也没必要继续,直接返回。\n const channels = cfg.channels || {};\n const currChannel = channels[CHANNEL_ID] || {};\n if (currChannel?.appId === undefined && !currChannel.accounts) {\n console.log(`[${CHANNEL_ID}] ⚠️ No configuration found, initializing with default TuiTui Account values.`);\n await api.runtime.config.writeConfigFile({\n ...cfg,\n channels: {\n ...channels,\n [CHANNEL_ID]: {\n ...getAccountInfo(),\n ...currChannel,\n }\n }\n });\n }\n } catch (err) {\n console.error(`[${CHANNEL_ID}] ❌ Failed to read/write default configuration:`, err);\n }\n};\n\nfunction createTuiTuiChannelPlugin(apiRuntime: any) {\n return {\n id: CHANNEL_ID,\n meta: {\n id: CHANNEL_ID,\n label: CHANNEL_NAME,\n selectionLabel: CHANNEL_NAME,\n detailLabel: CHANNEL_NAME + \" \" + version,\n docsPath: `/channels/${CHANNEL_ID}`,\n blurb: `Connect to ${CHANNEL_NAME} bot via WebSocket`,\n order: 100,\n },\n /*** 能力清单配置 ***/\n capabilities: {\n chatTypes: ['direct' as const, 'group' as const],\n media: true,\n threads: false,\n reactions: false,\n edit: false,\n unsend: false,\n reply: true,\n effects: false,\n blockStreaming: false,\n },\n configSchema: channelConfigs.tuitui,\n reload: { configPrefixes: [`channels.${CHANNEL_ID}`] },\n\n config: {\n listAccountIds: (cfg: any) => {\n const base = cfg?.channels?.[CHANNEL_ID];\n const ids = new Set<string>();\n ids.add(DEFAULT_ACCOUNT_ID);\n if (base?.accounts) for (const k in base.accounts) ids.add(k);\n return Array.from(ids);\n },\n\n resolveAccount,\n\n defaultAccountId: () => DEFAULT_ACCOUNT_ID,\n\n isEnabled,\n\n isConfigured,\n\n describeAccount: (account: any) => ({\n accountId: account?.accountId || DEFAULT_ACCOUNT_ID,\n enabled: isEnabled(account?.enabled),\n configured: isConfigured(account),\n }),\n\n setAccountEnabled: ({ cfg, accountId, enabled }: any) => {\n return accountId === DEFAULT_ACCOUNT_ID ? {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: { ...(cfg.channels?.[CHANNEL_ID] ?? {}), enabled },\n },\n } : setAccountEnabledInConfigSection({\n cfg,\n enabled,\n accountId,\n sectionKey: CHANNEL_ID,\n allowTopLevel: true,\n });\n },\n\n deleteAccount: ({ cfg, accountId }: any) => {\n return accountId === DEFAULT_ACCOUNT_ID ? {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: {\n ...(cfg.channels?.[CHANNEL_ID] ?? {}),\n ...getAccountInfo(), // 重置基础配置字段,恢复默认值\n enabled: false, // 默认账户不删除,改为禁用,并重置配置字段\n },\n },\n } : deleteAccountFromConfigSection({ cfg, accountId, sectionKey: CHANNEL_ID }); // 多账户状态下的配置信息,按 accountId 删除指定账户; 除非子账户影响根账户字段信息,否则不应该使用 clearBaseFields\n },\n },\n\n pairing: {\n idLabel: 'tuituiUserId',\n normalizeAllowEntry: (entry: string) => entry.toLowerCase().trim(),\n },\n\n status: {\n defaultRuntime: {\n accountId: DEFAULT_ACCOUNT_ID,\n running: false,\n lastStartAt: null,\n lastStopAt: null,\n lastError: null,\n },\n buildAccountSnapshot: (params: any) => {\n const account = params.account;\n return {\n ...params.runtime,\n accountId: params.accountId || account?.accountId || DEFAULT_ACCOUNT_ID,\n enabled: isEnabled(account?.enabled),\n configured: isConfigured(account),\n };\n },\n },\n\n security: {\n resolveDmPolicy: ({ cfg, accountId, account }: { cfg: any; accountId?: string | null; account?: any; }) => {\n account = account || resolveAccount(cfg, accountId);\n const accId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID;\n let allowFromPath =`channels.${CHANNEL_ID}.`;\n if (accId !== DEFAULT_ACCOUNT_ID) allowFromPath += `accounts.${accId}.`;\n\n const policy = account.dmPolicy ?? dmPolicyDefault;\n // dmPolicy semantics:\n // - open: always allow everyone ([\"*\"]), ignore allowFrom values.\n // - pairing: unknown senders get a pairing code; approvals add to allowFrom store.\n // - allowlist: only allow explicitly listed users in allowFrom.\n // - disabled: block all DMs.\n return {\n policy,\n allowFrom: policy === 'open' ? ['*'] : (account.allowFrom ?? []),\n policyPath: `${allowFromPath}dmPolicy`,\n allowFromPath,\n approveHint: `当前 ${CHANNEL_ID} openclaw(AccountId: ${accountId})需要配对校验, code: <code>`,\n normalizeEntry: (raw: string) => raw.toLowerCase().trim(),\n };\n },\n },\n\n messaging: {\n normalizeTarget: (target: string) => target.trim(),\n targetResolver: {\n looksLikeId: (id: string) => !!id && id.trim().length > 0,\n hint: \"<userId>\",\n },\n },\n\n directory: {\n self: async () => null,\n listPeers: async () => [],\n listGroups: async () => [],\n },\n\n outbound: {\n deliveryMode: 'direct' as const,\n textChunkLimit: 10000, // API上限制为50k\n\n sendText: async ({ cfg, to, text, accountId, replyToId, threadId }: any) => {\n const account = resolveAccount(cfg, accountId);\n \n const {chatId, chatType} = await guessChatTypeV2(account, to);\n \n console.log(`[${CHANNEL_ID}] AccountId ${accountId} outbound.sendText() ${chatType} to ${chatId} ${text}`);\n\n await sendTextMsg(account, chatId, chatType, text);\n\n return { channel: CHANNEL_ID, messageId: `tuitui-text-${Date.now()}`, chatId };\n },\n\n sendCustom: async ({ cfg, to, payload, accountId, account }: any) => {\n account = account || resolveAccount(cfg, accountId);\n // If it's a page message, we need to construct it\n if (payload?.msgtype !== 'page') {\n throw new Error(`[${CHANNEL_ID}] unsupported custom message type: ${payload?.msgtype}`);\n }\n\n const {chatId, chatType} = await guessChatTypeV2(account, to);\n await sendPageMsg(account, chatId, chatType, payload.page);\n\n return { channel: CHANNEL_ID, messageId: `tuitui-page-${Date.now()}`, chatId };\n },\n\n sendMedia: async ({ cfg, to, mediaUrl, accountId, account }: any) => {\n account = account || resolveAccount(cfg, accountId);\n\n const {chatId, chatType} = await guessChatTypeV2(account, to); \n await sendMediaMsg(account, chatId, chatType, mediaUrl, 'tuitui.send.media');\n\n return { channel: CHANNEL_ID, messageId: `tuitui-media-${Date.now()}`, chatId };\n },\n },\n\n gateway: {\n startAccount: async (ctx: any) => {\n const { cfg, accountId, log, abortSignal, setStatus, getStatus } = ctx;\n const _setStatus = (obj = {}) => {\n if (!setStatus || !getStatus) return;\n setStatus({ ...getStatus(), running: false, connected: false, ...obj });\n };\n const account = resolveAccount(cfg, accountId);\n\n if (!isEnabled(account.enabled)) {\n log?.info?.(`[${CHANNEL_ID}] AccountId ${accountId} is disabled, skipping`);\n return _setStatus();\n }\n\n if (!isConfigured(account)) {\n log?.warn?.(`[${CHANNEL_ID}] AccountId ${accountId} not fully configured (missing appId/appSecret)`);\n return _setStatus();\n }\n\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Starting TuiTui channel`);\n _setStatus({ running: true });\n\n // 创建 WebSocket 连接,并得到在需要时关闭该连接的方法。\n const _closeWs = createWebSocket({\n account,\n log,\n abortSignal,\n apiRuntime,\n onConnected: () => _setStatus({ running: true, connected: true }),\n onDisconnected: () => _setStatus({ running: false, connected: false }),\n onInbounMessage: (json: any) => {\n _setStatus({ running: true, connected: true, lastInboundAt: Date.now() });\n if (apiRuntime) {\n handleInboundMessage({ json, account, apiRuntime, log });\n } else {\n log?.error?.(`[${CHANNEL_ID}] AccountId: ${accountId}, WebSocket.onInbounMessage TuiTuiRuntime error`);\n }\n },\n });\n\n // 保持账户运行状态,直至触发“abortSignal”信号为止。\n await new Promise<void>((resolve) => {\n const _onAbort = () => {\n log?.info?.(`[${CHANNEL_ID}] AccountId ${accountId} stopping (abort signal)`);\n _closeWs();\n resolve();\n };\n if (abortSignal?.aborted) return _onAbort();\n abortSignal?.addEventListener(\"abort\", _onAbort, { once: true });\n });\n },\n\n stopAccount: async (ctx: any) => {\n ctx.log?.info?.(`[${CHANNEL_ID}] AccountId ${ctx.accountId} stopped`);\n ctx.setStatus?.({ ...ctx.getStatus?.(), running: false, connected: false });\n },\n },\n };\n}\n\nexport function registerTuiTuiChannel(api: OpenClawPluginApi) {\n checkAndSetDefaultTuiTuiConfig(api);\n api.registerChannel({ plugin: createTuiTuiChannelPlugin(api.runtime) });\n}\n"]}
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TuiTui Channel Plugin for OpenClaw.\n *\n * Implements the ChannelPlugin interface following the Synology Chat pattern.\n */\nimport { DEFAULT_ACCOUNT_ID } from 'openclaw/plugin-sdk/account-id';\nimport { setAccountEnabledInConfigSection, deleteAccountFromConfigSection, OpenClawPluginApi } from 'openclaw/plugin-sdk/core';\nimport { CHANNEL_ID, CHANNEL_NAME } from \"./const\";\nimport { version } from \"../package.json\"\nimport { handleInboundMessage } from './inbound';\nimport { guessChatTypeV2 } from \"./chat_record\"\nimport {\n sendTextMsg,\n sendPageMsg,\n sendMediaMsg,\n} from \"./outbound\";\nimport createWebSocket from './websocket';\nimport { channelConfigs } from '../openclaw.plugin.json';\nimport { isEnabled } from './utils';\nimport { dmPolicyDefault, resolveAccount, getAccountInfo } from \"./accounts\"\n\nconst isConfigured = (account: any)=> !!(account?.appId && account?.appSecret);\n\nlet _checkTuiTuiChannelLock = false;\nconst checkAndSetDefaultTuiTuiConfig = async (api: any) => {\n if (_checkTuiTuiChannelLock) return;\n _checkTuiTuiChannelLock = true;\n\n try {\n const cfg = await api.runtime.config.loadConfig();\n if (!cfg || !cfg.plugins || !cfg.models) return; // 基础配置结构不完整(插件无法运行的),后续流程也没必要继续,直接返回。\n const channels = cfg.channels || {};\n const currChannel = channels[CHANNEL_ID] || {};\n if (currChannel?.appId === undefined && !currChannel.accounts) {\n console.log(`[${CHANNEL_ID}] ⚠️ No configuration found, initializing with default TuiTui Account values.`);\n await api.runtime.config.writeConfigFile({\n ...cfg,\n channels: {\n ...channels,\n [CHANNEL_ID]: {\n ...getAccountInfo(),\n ...currChannel,\n }\n }\n });\n }\n } catch (err) {\n console.error(`[${CHANNEL_ID}] ❌ Failed to read/write default configuration:`, err);\n }\n};\n\nfunction createTuiTuiChannelPlugin(apiRuntime: any) {\n return {\n id: CHANNEL_ID,\n meta: {\n id: CHANNEL_ID,\n label: CHANNEL_NAME,\n selectionLabel: CHANNEL_NAME,\n detailLabel: CHANNEL_NAME + \" \" + version,\n docsPath: `/channels/${CHANNEL_ID}`,\n blurb: `Connect to ${CHANNEL_NAME} bot via WebSocket`,\n order: 100,\n },\n /*** 能力清单配置 ***/\n capabilities: {\n chatTypes: ['direct' as const, 'group' as const],\n media: true,\n threads: false,\n reactions: false,\n edit: false,\n unsend: false,\n reply: true,\n effects: false,\n blockStreaming: false,\n },\n configSchema: channelConfigs.tuitui,\n reload: { configPrefixes: [`channels.${CHANNEL_ID}`] },\n\n config: {\n listAccountIds: (cfg: any) => {\n const base = cfg?.channels?.[CHANNEL_ID];\n const ids = new Set<string>();\n ids.add(DEFAULT_ACCOUNT_ID);\n if (base?.accounts) for (const k in base.accounts) ids.add(k);\n return Array.from(ids);\n },\n\n resolveAccount,\n\n defaultAccountId: () => DEFAULT_ACCOUNT_ID,\n\n isEnabled,\n\n isConfigured,\n\n describeAccount: (account: any) => ({\n accountId: account?.accountId || DEFAULT_ACCOUNT_ID,\n enabled: isEnabled(account?.enabled),\n configured: isConfigured(account),\n }),\n\n setAccountEnabled: ({ cfg, accountId, enabled }: any) => {\n return accountId === DEFAULT_ACCOUNT_ID ? {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: { ...(cfg.channels?.[CHANNEL_ID] ?? {}), enabled },\n },\n } : setAccountEnabledInConfigSection({\n cfg,\n enabled,\n accountId,\n sectionKey: CHANNEL_ID,\n allowTopLevel: true,\n });\n },\n\n deleteAccount: ({ cfg, accountId }: any) => {\n return accountId === DEFAULT_ACCOUNT_ID ? {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: {\n ...(cfg.channels?.[CHANNEL_ID] ?? {}),\n ...getAccountInfo(), // 重置基础配置字段,恢复默认值\n enabled: false, // 默认账户不删除,改为禁用,并重置配置字段\n },\n },\n } : deleteAccountFromConfigSection({ cfg, accountId, sectionKey: CHANNEL_ID }); // 多账户状态下的配置信息,按 accountId 删除指定账户; 除非子账户影响根账户字段信息,否则不应该使用 clearBaseFields\n },\n },\n\n pairing: {\n idLabel: 'tuituiUserId',\n normalizeAllowEntry: (entry: string) => entry.toLowerCase().trim(),\n },\n\n status: {\n defaultRuntime: {\n accountId: DEFAULT_ACCOUNT_ID,\n running: false,\n lastStartAt: null,\n lastStopAt: null,\n lastError: null,\n },\n buildAccountSnapshot: (params: any) => {\n const account = params.account;\n return {\n ...params.runtime,\n accountId: params.accountId || account?.accountId || DEFAULT_ACCOUNT_ID,\n enabled: isEnabled(account?.enabled),\n configured: isConfigured(account),\n };\n },\n },\n\n security: {\n resolveDmPolicy: ({ cfg, accountId, account }: { cfg: any; accountId?: string | null; account?: any; }) => {\n account = account || resolveAccount(cfg, accountId);\n const accId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID;\n let allowFromPath =`channels.${CHANNEL_ID}.`;\n if (accId !== DEFAULT_ACCOUNT_ID) allowFromPath += `accounts.${accId}.`;\n\n const policy = account.dmPolicy ?? dmPolicyDefault;\n // dmPolicy semantics:\n // - open: always allow everyone ([\"*\"]), ignore allowFrom values.\n // - pairing: unknown senders get a pairing code; approvals add to allowFrom store.\n // - allowlist: only allow explicitly listed users in allowFrom.\n // - disabled: block all DMs.\n return {\n policy,\n allowFrom: policy === 'open' ? ['*'] : (account.allowFrom ?? []),\n policyPath: `${allowFromPath}dmPolicy`,\n allowFromPath,\n approveHint: `当前 ${CHANNEL_ID} openclaw(AccountId: ${accountId})需要配对校验, code: <code>`,\n normalizeEntry: (raw: string) => raw.toLowerCase().trim(),\n };\n },\n },\n\n messaging: {\n normalizeTarget: (target: string) => target.trim(),\n targetResolver: {\n looksLikeId: (id: string) => !!id && id.trim().length > 0,\n hint: \"<userId>\",\n },\n },\n\n directory: {\n self: async () => null,\n listPeers: async () => [],\n listGroups: async () => [],\n },\n\n outbound: {\n deliveryMode: 'direct' as const,\n textChunkLimit: 10000, // API上限制为50k\n\n sendText: async ({ cfg, to, text, accountId, replyToId, threadId }: any) => {\n console.log(`[${CHANNEL_ID}] sendText to=${to}, text=${text}, accountId=${accountId}`);\n const account = resolveAccount(cfg, accountId);\n \n const {chatId, chatType} = await guessChatTypeV2(account, to);\n \n console.log(`[${CHANNEL_ID}] AccountId ${accountId} outbound.sendText() ${chatType} to ${chatId} ${text}`);\n\n await sendTextMsg(account, chatId, chatType, text);\n\n return { channel: CHANNEL_ID, messageId: `tuitui-text-${Date.now()}`, chatId };\n },\n\n sendCustom: async ({ cfg, to, payload, accountId, account }: any) => {\n account = account || resolveAccount(cfg, accountId);\n // If it's a page message, we need to construct it\n if (payload?.msgtype !== 'page') {\n throw new Error(`[${CHANNEL_ID}] unsupported custom message type: ${payload?.msgtype}`);\n }\n\n const {chatId, chatType} = await guessChatTypeV2(account, to);\n await sendPageMsg(account, chatId, chatType, payload.page);\n\n return { channel: CHANNEL_ID, messageId: `tuitui-page-${Date.now()}`, chatId };\n },\n\n sendMedia: async ({ cfg, to, mediaUrl, accountId, account }: any) => {\n console.log(`[${CHANNEL_ID}] sendMedia to=${to}, mediaUrl=${mediaUrl}, accountId=${accountId}`);\n account = account || resolveAccount(cfg, accountId);\n\n const {chatId, chatType} = await guessChatTypeV2(account, to);\n console.log(`[${CHANNEL_ID}] sendMediaMsg guess chatId=${chatId}, chatType=${chatType}`);\n await sendMediaMsg(account, chatId, chatType, mediaUrl, 'tuitui.send.media');\n\n return { channel: CHANNEL_ID, messageId: `tuitui-media-${Date.now()}`, chatId };\n },\n },\n\n gateway: {\n startAccount: async (ctx: any) => {\n const { cfg, accountId, log, abortSignal, setStatus, getStatus } = ctx;\n const _setStatus = (obj = {}) => {\n if (!setStatus || !getStatus) return;\n setStatus({ ...getStatus(), running: false, connected: false, ...obj });\n };\n const account = resolveAccount(cfg, accountId);\n\n if (!isEnabled(account.enabled)) {\n log?.info?.(`[${CHANNEL_ID}] AccountId ${accountId} is disabled, skipping`);\n return _setStatus();\n }\n\n if (!isConfigured(account)) {\n log?.warn?.(`[${CHANNEL_ID}] AccountId ${accountId} not fully configured (missing appId/appSecret)`);\n return _setStatus();\n }\n\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Starting TuiTui channel`);\n _setStatus({ running: true });\n\n // 创建 WebSocket 连接,并得到在需要时关闭该连接的方法。\n const _closeWs = createWebSocket({\n account,\n log,\n abortSignal,\n apiRuntime,\n onConnected: () => _setStatus({ running: true, connected: true }),\n onDisconnected: () => _setStatus({ running: false, connected: false }),\n onInbounMessage: (json: any) => {\n _setStatus({ running: true, connected: true, lastInboundAt: Date.now() });\n if (apiRuntime) {\n handleInboundMessage({ json, account, apiRuntime, log });\n } else {\n log?.error?.(`[${CHANNEL_ID}] AccountId: ${accountId}, WebSocket.onInbounMessage TuiTuiRuntime error`);\n }\n },\n });\n\n // 保持账户运行状态,直至触发“abortSignal”信号为止。\n await new Promise<void>((resolve) => {\n const _onAbort = () => {\n log?.info?.(`[${CHANNEL_ID}] AccountId ${accountId} stopping (abort signal)`);\n _closeWs();\n resolve();\n };\n if (abortSignal?.aborted) return _onAbort();\n abortSignal?.addEventListener(\"abort\", _onAbort, { once: true });\n });\n },\n\n stopAccount: async (ctx: any) => {\n ctx.log?.info?.(`[${CHANNEL_ID}] AccountId ${ctx.accountId} stopped`);\n ctx.setStatus?.({ ...ctx.getStatus?.(), running: false, connected: false });\n },\n },\n };\n}\n\nexport function registerTuiTuiChannel(api: OpenClawPluginApi) {\n checkAndSetDefaultTuiTuiConfig(api);\n api.registerChannel({ plugin: createTuiTuiChannelPlugin(api.runtime) });\n}\n"]}
@@ -308,25 +308,6 @@ async function parse_teams_post(payload, msgData, account, apiRuntime, log) {
308
308
  await addUnmentionedHistory(apiRuntime, accountId, chatId, payload.tuituiUserName, tuituiAccount, payload.text, payload.timestamp);
309
309
  return false;
310
310
  }
311
- if (_session_ctx_injected.checkAndRecord(accountId + "_" + payload.chatId)) {
312
- // 注入上下文
313
- // 解决机器人不知道自己是谁的问题
314
- if (payload.botName) {
315
- payload.text += `\n\n*** 参考信息: 你在当前session中的名字叫: ${payload.botName} 如果有人@这个名字,就是在命令你 ***\n`;
316
- }
317
- // 公告
318
- const annnouncement = await teams_get_announcement(account, channel_id, false);
319
- if (annnouncement) {
320
- payload.text += "\n\n*** 参考信息: 当前公告内容如下 ***\n";
321
- payload.text += "```\n" + annnouncement + "\n```";
322
- }
323
- // 成员
324
- const members = await teams_get_members_text(account, team_id);
325
- if (members) {
326
- payload.text += "\n\n*** 参考信息: 当前团队成员清单如下,每行一个成员名。如果需要询问成员、或者发送给成员时,需要用 @名字 的语法;并且@时必须从如下清单中匹配到最接近的,禁止@不存在的成员 ***\n";
327
- payload.text += "```\n" + members + "\n```";
328
- }
329
- }
330
311
  // 私聊白名单对团队仍然生效,限制特定人@时,可以不配置groupAllowFrom,而是配置 allowFrom
331
312
  if (await isAllowAccount(tuituiAccount, apiRuntime, account)) {
332
313
  return true;
@@ -363,6 +344,32 @@ const parseAndVerifyPayload = {
363
344
  teams_post_create: parse_teams_post,
364
345
  //teams_post_modify: parse_teams_post,
365
346
  };
347
+ async function injectSessionContext(payload, msgData, account) {
348
+ const { accountId } = account;
349
+ if (!_session_ctx_injected.checkAndRecord(accountId + "_" + payload.chatId))
350
+ return;
351
+ // 注入上下文
352
+ if (payload.chatType === CHAT_TYPE_CHANNEL) {
353
+ // 解决机器人不知道自己是谁的问题 (仅团队有效)
354
+ if (payload.botName) {
355
+ payload.text += `\n\n*** 参考信息: 你在当前session中的名字叫: ${payload.botName} 如果有人@这个名字,就是在命令你 ***\n`;
356
+ }
357
+ const { team_id, channel_id } = msgData;
358
+ // 公告
359
+ const annnouncement = await teams_get_announcement(account, channel_id, false);
360
+ if (annnouncement) {
361
+ payload.text += "\n\n*** 参考信息: 当前公告内容如下 ***\n";
362
+ payload.text += "```\n" + annnouncement + "\n```";
363
+ }
364
+ // 成员
365
+ const members = await teams_get_members_text(account, team_id);
366
+ if (members) {
367
+ payload.text += "\n\n*** 参考信息: 当前团队成员清单如下,每行一个成员名。如果需要询问成员、或者发送给成员时,需要用 @名字 的语法;并且@时必须从如下清单中匹配到最接近的,禁止@不存在的成员 ***\n";
368
+ payload.text += "```\n" + members + "\n```";
369
+ }
370
+ }
371
+ payload.text += `\n\n【关键系统指令:产物交付】\n如果你的最终任务目标是生成文件(pdf/图片/Markdown/等),在文件生成落盘后你当前的任务并没有结束!你必须使用 \`message\` tool 将这些文件二进制作为 attachments 发回到当前 session 中`;
372
+ }
366
373
  /**
367
374
  * 处理长链接消息
368
375
  * account: 长连接初始化时,对应的Account配置信息
@@ -382,8 +389,8 @@ export async function handleInboundMessage({ json, account, apiRuntime, log }) {
382
389
  const payload = {
383
390
  chatType: CHAT_TYPE_DIRECT,
384
391
  chatId: undefined,
385
- botName: json.header['X-Tuitui-Robot-AppName'],
386
- text: undefined,
392
+ botName: json.header['X-Tuitui-Robot-AppName'] || '',
393
+ text: "",
387
394
  groupName: undefined,
388
395
  WasMentioned: undefined,
389
396
  channelName: undefined,
@@ -421,22 +428,24 @@ export async function handleInboundMessage({ json, account, apiRuntime, log }) {
421
428
  const cfg = await apiRuntime.config.loadConfig();
422
429
  const sessionKey = getSessionKey(cfg, payload, account, apiRuntime);
423
430
  log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, dispatching to agent session=${sessionKey}, chatType: ${payload.chatType}, chatId ${payload.chatId}, routeSenderFrom: ${routeSenderFrom}`);
424
- let finalBody = payload.text || ' ';
425
- if (payload.text && payload.botName) {
426
- const stripped = payload.text.replace(`@${payload.botName}`, '').trim();
427
- if (stripped.startsWith('/')) {
428
- finalBody = stripped;
431
+ payload.text = payload.text || '';
432
+ const stripedBody = payload.text.replace(`@${payload.botName}`, '').trim();
433
+ if (stripedBody.startsWith('/')) {
434
+ payload.text = stripedBody;
435
+ if (payload.text.startsWith('/new') || payload.text.startsWith('/reset')) {
436
+ // 清理agent上下文时,同时清空历史
437
+ popUnmentionedHistories(accountId, payload.chatId);
429
438
  }
430
439
  }
431
- if (finalBody.startsWith("/new") || finalBody.endsWith("/new")) {
432
- // 清理agent上下文时,同时清空历史
433
- popUnmentionedHistories(accountId, payload.chatId);
440
+ else {
441
+ // 指令以外的才注入
442
+ await injectSessionContext(payload, msgData, account);
434
443
  }
435
444
  // 字段意义 参考 openclaw 代码
436
445
  // src\auto-reply\reply\inbound-meta.ts
437
446
  // buildInboundUserContextPrefix()
438
447
  const ctx = {
439
- Body: finalBody,
448
+ Body: payload.text,
440
449
  From: String(routeSenderFrom),
441
450
  To: CHANNEL_ID,
442
451
  SessionId: sessionKey,
@@ -1 +1 @@
1
- {"version":3,"file":"inbound.js","sourceRoot":"","sources":["../../src/inbound.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TuiTui inbound message handler — pure business logic.\n *\n * channel.ts owns the WebSocket frame layer (JSON parse, ACK, keepalive\n * filtering) and calls handleInboundMessage with an already-parsed object.\n *\n * Usage:\n * ws.on('message', async (wsData) => {\n * // ... parse JSON, send ACK, filter keepalive ...\n * await handleInboundMessage(json, { account, accountId, apiRuntime, log });\n * });\n */\nimport type { TuiTuiInboundMessage, TuiTuiOutboundDeliverOptions } from './types';\nimport { CHANNEL_ID } from './const';\nimport {CHAT_TYPE_DIRECT,CHAT_TYPE_GROUP,CHAT_TYPE_CHANNEL,ChatType,teamsParseChatId,teamsBuildChatId} from \"./chat_base\"\nimport {tuituiEmojiReaction, sendTextMsg, sendPageMsg, sendMediaMsg } from \"./outbound\";\nimport { teams_get_members, teams_get_members_text, teams_get_announcement } from \"./teams_api\"\nimport { parseChatMessageBody } from './inbound_body_parse';\nimport { parseAllowFroms } from './utils';\nimport { addUnmentionedHistory, popUnmentionedHistories } from \"./histories\";\nimport { StringDeduplicator } from \"./deduplicator\"\nimport { getPostChainByChatId } from \"./chat_record\"\n\n// 会话上下文注入排重\nlet _session_ctx_injected = new StringDeduplicator(1000, 3600);\n\n/** 子函数共享的可变上下文,子函数直接修改字段,外层读取结果 */\ninterface ChatPayload {\n chatType: ChatType;\n chatId: string | undefined;\n botName: string;\n text: string | undefined;\n groupName: string | undefined;\n channelName: string | undefined;\n mediaUrls: string[] | undefined;\n replyToId: string | undefined; // 引用ID\n msgId?: string; // 消息ID\n tuituiAccount: string;\n tuituiUid: string | undefined;\n tuituiUserName: string | undefined;\n timestamp: Number | undefined;\n WasMentioned: boolean | undefined;\n}\n\nexport interface InboundAccount {\n accountId: string;\n appId: string;\n appSecret: string;\n dmPolicy: string;\n allowFrom: string[];\n groupPolicy: string;\n groupAllowFrom: string[];\n requireMention: boolean;\n emojiReaction: boolean;\n}\nexport interface InboundHandlerOptions {\n json: any\n account: InboundAccount;\n apiRuntime: any;\n log: any;\n}\n\nfunction getSessionKey(cfg: any, payload: ChatPayload, account: InboundAccount, apiRuntime: any): string {\n const { chatId, chatType } = payload;\n const { accountId } = account;\n // 你自己只需要拼接与定义 peer.id\n // 关于 sessionKey 格式的解释: https://docs.openclaw.ai/channels/channel-routing#sessionkey-%E5%8F%82%E8%80%83%E6%A0%BC%E5%BC%8F\n let id = chatId;\n if(chatType == CHAT_TYPE_CHANNEL) {\n const { channel_id, parent_id } = teamsParseChatId(chatId!);\n id = `${channel_id}`;\n if(parent_id) {\n id += `:thread:${parent_id}`;\n }\n }\n\n // sessionKey 不能自己拼字符串,需要用系统api识别,他会根据 bindings 路由规则处理\n const { sessionKey } = apiRuntime.channel.routing.resolveAgentRoute({\n cfg,\n accountId,\n channel: CHANNEL_ID,\n peer: { kind: chatType, id: id },\n });\n return String(sessionKey).replace(/\\//g, '_');\n}\n\nfunction getMediaUrls({ msg_type, images, voice, video, file }: any): string[] | undefined {\n if (msg_type === 'image' || msg_type === 'mixed') {\n if (images?.length) return images;\n } else if (msg_type === 'voice') {\n if (voice) return [voice];\n } else if (msg_type === 'video') {\n if (video) return [video];\n } else if (msg_type === 'file') {\n if (file?.url) return [file.url];\n }\n return undefined;\n}\n\nasync function dispatchReply(ctx: any, cfg: any, account: InboundAccount, payload: ChatPayload, apiRuntime: any, log: any) {\n const { accountId } = account;\n await apiRuntime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx,\n cfg,\n dispatcherOptions: {\n deliver: async (outbound: TuiTuiOutboundDeliverOptions) => {\n // Custom message (e.g. page)\n if (outbound.custom) {\n const { msgtype, page, tousers, togroups } = outbound.custom;\n if (msgtype === 'page' && page) {\n await sendPageMsg(account, payload.chatId, payload.chatType, page, 'tuitui.deliver.page', tousers, togroups);\n return;\n }\n log?.warn?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Unsupported custom message type: ${msgtype}`);\n return;\n }\n\n // Media message\n const mediaUrl = outbound.mediaUrl || outbound.mediaUrls?.[0];\n if (mediaUrl) {\n await sendMediaMsg(account, payload.chatId, payload.chatType, mediaUrl, 'tuitui.deliver.media', [payload.tuituiAccount]);\n return;\n }\n\n // Text message\n const replyText = outbound?.text || outbound?.body;\n if (replyText) {\n // 群消息回复时不再使用 reference_msgid 避免并发时引用错乱,依靠 @ 来提醒用户\n await sendTextMsg(account, payload.chatId, payload.chatType, replyText, 'tuitui.deliver.text', [payload.tuituiAccount]);\n return;\n }\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, no_reply_content`);\n },\n\n onReplyStart: () => {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Agent is typing to ${payload.tuituiAccount}`);\n },\n },\n });\n}\n\n/*** 配对节流映射 - 用于防止短时间内大量重复配对请求消息发出\n * key: `${accountId}-${chatId}`\n * val: timestamp */\nconst pairingThrottleMap = new Map<string, number>();\n// 暂时控制为 2 分钟内同一个用户只能触发一次配对请求\nconst needPairingThrottle = (accountId: string | undefined, chatId: string, throttleMs = 2 * 60 * 1000): boolean => {\n const key = `${accountId}-${chatId}`;\n const now = Date.now();\n const lastTime = pairingThrottleMap.get(key) || 0;\n if (now - lastTime < throttleMs) {\n return true;\n }\n pairingThrottleMap.set(key, now);\n return false;\n}\n\nasync function sendSingleChatPairingMsg(account: any, payload: any, log: any, apiRuntime: any) {\n const { accountId } = account;\n const { chatId, chatType } = payload;\n if (needPairingThrottle(accountId, chatId)) {\n return log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing throttled for sender=${chatId}`);\n }\n try {\n log?.debug?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing flow: checking if pairing request exists for sender=${chatId}`);\n const req = await apiRuntime.channel.pairing.upsertPairingRequest({ channel: CHANNEL_ID, accountId, id: chatId });\n log?.debug?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing flow: upsertPairingRequest result=${JSON.stringify(req)}`);\n // 只要没配对,会每次和机器人聊,都会返回配对信息。\n const replyText = apiRuntime.channel.pairing.buildPairingReply({ channel: CHANNEL_ID, code: req.code });\n await sendTextMsg(account, chatId, chatType, replyText, 'tuitui.pairing.reply');\n } catch (err) {\n log?.warn?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing failed for ${chatId}: ${String(err)}`);\n }\n}\n\n//tuituiAccounts列表中是否存在至少1个允许私聊的用户(私聊白名单、配对、或者open)\nasync function isAllowOneOfAccount(tuituiAccounts: string[], apiRuntime: any, account: InboundAccount) {\n if(!tuituiAccounts) return false;\n const { accountId, allowFrom, dmPolicy } = account;\n if (dmPolicy === 'open') return true;\n\n // 是否包含任意一个元素\n if (tuituiAccounts.some(item => allowFrom.includes(item))) return true;\n\n try {\n let storeAllowFrom = parseAllowFroms(\n await apiRuntime?.channel?.pairing?.readAllowFromStore?.({ channel: CHANNEL_ID, accountId })\n );\n if (tuituiAccounts.some(item => storeAllowFrom.includes(item))) return true;\n } catch {}\n return false; \n}\n\nasync function isAllowAccount(tuituiAccount: string, apiRuntime: any, account: InboundAccount) {\n return await isAllowOneOfAccount([tuituiAccount], apiRuntime, account);\n}\n\nasync function isChannelCoordAuthorized(tuituiAccount: string, apiRuntime: any, account: InboundAccount, team_id:string, chat_id:string) {\n // 协调员身份校验\n if (tuituiAccount != \"bot-FiwwCeDw\" && tuituiAccount != \"bot-sUwUeknd\") return false;\n\n // 当前 thread 中有白名单用户发帖,则协调员继承该权限\n const [members, posts] = await Promise.all([\n teams_get_members(account, team_id),\n getPostChainByChatId(account, chat_id),\n ]);\n if (!members?.length || !posts?.length) return false;\n\n const from_uids = posts.map((p: any) => p.from_uid).filter(Boolean);\n if (!from_uids.length) return false;\n\n //console.log(\"from_uids\", from_uids);\n\n // 将 uid 映射到 user_account\n const from_accounts: string[] = members\n .filter((m: any) => from_uids.includes(m.uid) && m.account)\n .map((m: any) => String(m.account));\n if (!from_accounts.length) return false;\n\n //console.log(\"from_accounts\", from_accounts);\n return await isAllowOneOfAccount(from_accounts, apiRuntime, account);\n}\n\n\n/**\n * 处理单聊(single_chat)、群聊、团队帖子分支,直接修改并校验 payload。\n * 返回 false 表示消息不合法,外层应提前 return;返回 true 表示校验通过,继续执行。\n */\nasync function parse_single_chat(payload: ChatPayload, msgData: any, account: InboundAccount, apiRuntime: any, log: any): Promise<boolean> {\n const { accountId, dmPolicy, allowFrom } = account;\n const chatId = payload.tuituiAccount ? String(payload.tuituiAccount || '').toLowerCase().trim() : '';\n if (dmPolicy === 'disabled') { //['pairing', 'allowlist', 'open', 'disabled'],\n log?.warn?.(`[${CHANNEL_ID}] AccountId: ${accountId}, DM disabled sender=${chatId}`);\n return false;\n }\n\n payload.chatType = CHAT_TYPE_DIRECT;\n payload.chatId = chatId;\n payload.text = parseChatMessageBody(msgData);\n payload.msgId = msgData.msgid;\n log?.debug?.(\n `[${CHANNEL_ID}] AccountId: ${accountId}, inbound single_chat:\n userAccount=${chatId},\n tuituiUid=${payload.tuituiUid},\n tuituiUserName=${payload.tuituiUserName},\n dmPolicy=${dmPolicy},\n allowFrom=${JSON.stringify(allowFrom)}`);\n\n if (!chatId && !payload.tuituiUid) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Missing user_account or uid in single_chat event`);\n return false;\n }\n\n if (dmPolicy === 'open') return true;\n\n if(await isAllowAccount(chatId, apiRuntime, account)){\n return true;\n }\n\n if (dmPolicy === 'pairing') {\n sendSingleChatPairingMsg(account, payload, log, apiRuntime);\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing required`);\n return false;\n }\n // allowlist\n log?.warn?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Blocked unauthorized sender (allowlist): sender=${chatId} allowFrom=${JSON.stringify(allowFrom)}`);\n return false;\n}\n\nasync function parse_group_chat(payload: ChatPayload, msgData: any, account: InboundAccount, apiRuntime: any, log: any): Promise<boolean> {\n const { accountId, groupPolicy, groupAllowFrom } = account;\n payload.chatType = CHAT_TYPE_GROUP;\n const chatId = msgData.group_id ? String(msgData.group_id).toLowerCase().trim() : '';\n payload.chatId = chatId;\n payload.groupName = msgData.group_name;\n payload.msgId = msgData.msgid;\n payload.text = parseChatMessageBody(msgData);\n payload.WasMentioned = msgData.at_me;\n const { tuituiAccount } = payload;\n log?.debug?.(\n `[${CHANNEL_ID}] AccountId: ${accountId}, inbound group_chat:\n tuituiAccount=${tuituiAccount},\n tuituiUid=${payload.tuituiUid},\n tuituiUserName=${payload.tuituiUserName},\n groupId=${chatId},\n groupPolicy=${groupPolicy},\n groupAllowFrom=${JSON.stringify(groupAllowFrom)},\n at_me=${JSON.stringify(msgData.at_me)},\n at=${JSON.stringify(msgData.at)}`);\n\n if (groupPolicy === 'disabled') {\n log?.info?.(`${CHANNEL_ID} AccountId: ${accountId}, groupPolicy disabled`);\n return false;\n }\n\n if (!tuituiAccount || !chatId) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Missing tuituiAccount or chatId in group_chat event`);\n return false;\n }\n\n if (!msgData.at_me && account.requireMention) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, ignore group message (not mentioned), add to history key: ${chatId}`);\n await addUnmentionedHistory(apiRuntime, accountId, chatId, payload.tuituiUserName, tuituiAccount, payload.text, payload.timestamp);\n return false;\n }\n\n // 私聊白名单对群聊仍然生效,当群里只想特定人@时,可以不配置groupAllowFrom,而是配置 allowFrom\n if(await isAllowAccount(tuituiAccount, apiRuntime, account)){\n return true;\n }\n\n if (!groupAllowFrom.includes(chatId)) {\n if (needPairingThrottle(accountId, chatId)) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, group pairing throttled for groupId=${chatId}`);\n return false;\n }\n\n const msgTxt=`当前 OpenClaw(AccountId: ${accountId})的群聊策略为白名单模式。\n需由龙虾主人在配置中添加白名单(两种方式二选一即可):\n\n- 允许群中所有人用,在群白名单(Group Allow From)添加当前群ID: ${chatId}\n\n- 不想群所有人用,只想特定人用,在私聊白名单(Allow From)添加当前用户 ${payload.tuituiAccount} ,私聊白名单对群仍然有效`\n\n await sendTextMsg(account, chatId, payload.chatType, msgTxt, 'tuitui.groupPolicy.reply');\n return false;\n }\n\n return true; \n}\n\n\nasync function parse_teams_post(payload: ChatPayload, msgData: any, account: InboundAccount, apiRuntime: any, log: any): Promise<boolean> {\n const { accountId, groupPolicy, groupAllowFrom } = account;\n payload.chatType = CHAT_TYPE_CHANNEL;\n const { team_id, channel_id, parent_id, post_id, content, team_name, channel_name } = msgData;\n const thread_id = (parent_id && parent_id != \"0\")?parent_id: post_id;\n const chatId = teamsBuildChatId(team_id, channel_id, thread_id);\n payload.chatId = chatId;\n payload.msgId = post_id;\n payload.text = content;\n payload.channelName = channel_name;\n payload.replyToId = \"\";\n payload.WasMentioned = msgData.at_me;\n const { tuituiAccount } = payload;\n log?.debug?.(\n `[${CHANNEL_ID}] AccountId: ${accountId}, inbound teams:\n tuituiAccount=${tuituiAccount},\n tuituiUid=${payload.tuituiUid},\n tuituiUserName=${payload.tuituiUserName},\n chatId=${chatId},\n groupPolicy=${groupPolicy},\n groupAllowFrom=${JSON.stringify(groupAllowFrom)},\n at_me=${JSON.stringify(msgData.at_me)},\n at=${JSON.stringify(msgData.at)}`,\n );\n\n if (groupPolicy === 'disabled') {\n log?.info?.(`${CHANNEL_ID} AccountId: ${accountId}, groupPolicy disabled`);\n return false;\n }\n\n if (!tuituiAccount) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Missing tuituiAccount or chatId in event`);\n return false;\n }\n\n \n {\n // 频道帖子文件、附件处理。必须放在正文里\n const {images, files} = msgData;\n if (images) {\n payload.text += \"\\n\\n附录上文提到的图片列表\\n\"\n for (const image of images) {\n payload.text += image + \"\\n\";\n }\n }\n if (files) {\n payload.text += \"\\n\\n附录上文提到的文件列表\\n\"\n for (const file of files) {\n payload.text += `[文件] ${file?.name} : ${file?.url} \\n`;\n }\n }\n }\n\n if (!msgData.at_me && account.requireMention) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, ignore teams post (not mentioned), add to history ${chatId} -> ${payload.text}`);\n await addUnmentionedHistory(apiRuntime, accountId, chatId, payload.tuituiUserName, tuituiAccount, payload.text, payload.timestamp);\n return false;\n }\n\n if(_session_ctx_injected.checkAndRecord(accountId + \"_\" + payload.chatId)) {\n // 注入上下文\n // 解决机器人不知道自己是谁的问题\n if(payload.botName) {\n payload.text += `\\n\\n*** 参考信息: 你在当前session中的名字叫: ${payload.botName} 如果有人@这个名字,就是在命令你 ***\\n`;\n }\n // 公告\n const annnouncement = await teams_get_announcement(account, channel_id, false);\n if(annnouncement) {\n payload.text += \"\\n\\n*** 参考信息: 当前公告内容如下 ***\\n\";\n payload.text += \"```\\n\" + annnouncement + \"\\n```\";\n }\n\n // 成员\n const members = await teams_get_members_text(account, team_id);\n if(members) {\n payload.text += \"\\n\\n*** 参考信息: 当前团队成员清单如下,每行一个成员名。如果需要询问成员、或者发送给成员时,需要用 @名字 的语法;并且@时必须从如下清单中匹配到最接近的,禁止@不存在的成员 ***\\n\";\n payload.text += \"```\\n\" + members + \"\\n```\";\n }\n }\n\n // 私聊白名单对团队仍然生效,限制特定人@时,可以不配置groupAllowFrom,而是配置 allowFrom\n if(await isAllowAccount(tuituiAccount, apiRuntime, account)){\n return true;\n }\n \n if (!groupAllowFrom.includes(String(team_id)) && !groupAllowFrom.includes(String(channel_id)) ) {\n if (!msgData.at_me) {\n // 解决这个case:requireMention=false时,团队里发任意帖子都会回复加白,搞得没法用\n // 要求必须@才触发回复加白\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, ignore teams post (not mentioned)`);\n return false;\n }\n\n // 频道中允许协调员@自己(且帖子里有白名单用户发帖)\n if (await isChannelCoordAuthorized(tuituiAccount, apiRuntime, account, team_id, chatId)) {\n return true;\n }\n\n if (needPairingThrottle(accountId, chatId)) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, teams pairing throttled for teamsChatId=${chatId}`);\n return false;\n }\n\n const msgTxt=`当前 OpenClaw(AccountId: ${accountId})的群聊/团队策略为白名单模式。\n需由龙虾主人在配置中添加白名单(3种方式选一种即可):\n\n- 允许团队中所有人用,在群白名单(Group Allow From)添加当前团队ID: ${team_id}\n- 仅允许当前频道使用,在群白名单(Group Allow From)添加当前频道ID: ${channel_id}\n- 仅允许特定人使用,在私聊白名单(Allow From)添加当前用户: ${payload.tuituiAccount} ,私聊白名单对团队仍然有效`\n\n await sendTextMsg(account, chatId, payload.chatType, msgTxt, 'tuitui.groupPolicy.reply');\n return false;\n }\n\n return true;\n}\n\nconst parseAndVerifyPayload: Record<string, Function> = {\n single_chat: parse_single_chat,\n group_chat: parse_group_chat,\n teams_post_create: parse_teams_post,\n //teams_post_modify: parse_teams_post,\n} as const;\n\n/**\n * 处理长链接消息\n * account: 长连接初始化时,对应的Account配置信息\n * accountId: 长连接启动初始化,对应的配置ID\n */\nexport async function handleInboundMessage({ json, account, apiRuntime, log }: InboundHandlerOptions) {\n // Signature / AppId validation\n const { accountId, appId, appSecret } = account;\n if (appSecret && appId && json.header['X-Tuitui-Robot-Appid'] !== appId) {\n log?.info?.(`[${CHANNEL_ID}] Invalid appId`);\n return;\n }\n\n // Decode message\n const msg = json.body as TuiTuiInboundMessage;\n const msgData = msg.data;\n const { ref } = msgData;\n const payload: ChatPayload = {\n chatType: CHAT_TYPE_DIRECT,\n chatId: undefined, \n botName: json.header['X-Tuitui-Robot-AppName'],\n text: undefined,\n groupName: undefined,\n WasMentioned: undefined,\n channelName: undefined,\n mediaUrls: getMediaUrls(msgData),\n replyToId: ref?.is_me && ref?.msgid ? ref.msgid : undefined,\n tuituiAccount: msg.user_account || \"\",\n tuituiUid: msg.uid || \"\",\n tuituiUserName: msg.user_name || \"\",\n timestamp: msg.timestamp ? parseInt(msg.timestamp, 10)*1000 : undefined\n };\n const wsEvent = json.body.event;\n // 按event类型,标准化并校验基础数据\n const parseAndVerifyPayloadFun = parseAndVerifyPayload[wsEvent] as Function | undefined;\n if (!parseAndVerifyPayloadFun) {\n log?.info?.(`[${CHANNEL_ID}] ignore unknown event ${wsEvent}`);\n return;\n }\n if (!(await parseAndVerifyPayloadFun(payload, msgData, account, apiRuntime, log))) return;\n\n if (!payload.chatId || !payload.msgId) {\n log?.info?.(`[${CHANNEL_ID}] ignore unknown mseeage, missing chatId or msgId`, payload);\n return;\n }\n\n if (account.emojiReaction) {\n // 因为回复较慢,先回复一个表情\n try{\n await tuituiEmojiReaction(account, payload.chatId, payload.chatType, payload.msgId, '收到');\n } catch (err) {\n // 出错不影响后续逻辑\n }\n }\n\n // 路由判断\n const routeSenderFrom = payload.tuituiAccount || payload.tuituiUid || 'unknown';\n\n const cfg = await apiRuntime.config.loadConfig();\n const sessionKey = getSessionKey(cfg, payload, account, apiRuntime);\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, dispatching to agent session=${sessionKey}, chatType: ${payload.chatType}, chatId ${payload.chatId}, routeSenderFrom: ${routeSenderFrom}`);\n\n let finalBody = payload.text || ' ';\n if (payload.text && payload.botName) {\n const stripped = payload.text.replace(`@${payload.botName}`, '').trim();\n if (stripped.startsWith('/')) {\n finalBody = stripped;\n }\n }\n\n if(finalBody.startsWith(\"/new\") || finalBody.endsWith(\"/new\")) {\n // 清理agent上下文时,同时清空历史\n popUnmentionedHistories(accountId, payload.chatId);\n }\n\n // 字段意义 参考 openclaw 代码\n // src\\auto-reply\\reply\\inbound-meta.ts\n // buildInboundUserContextPrefix()\n const ctx: any = {\n Body: finalBody,\n From: String(routeSenderFrom),\n To: CHANNEL_ID,\n SessionId: sessionKey,\n SessionKey: sessionKey,\n AccountId: accountId,\n OriginatingChannel: CHANNEL_ID,\n OriginatingTo: payload.chatId,\n ChatType: payload.chatType!,\n Surface: CHANNEL_ID,\n Provider: CHANNEL_ID,\n SenderName: payload.tuituiUserName,\n SenderId: payload.tuituiAccount,\n SenderUsername: payload.tuituiAccount, \n UserAccount: payload.tuituiAccount,\n Timestamp: payload.timestamp,\n CommandAuthorized: true, // 允许 /new 等内置命令\n };\n if (payload.chatType == CHAT_TYPE_GROUP && payload.chatId) {\n ctx.WasMentioned = payload.WasMentioned;\n ctx.GroupSubject = payload.groupName;\n ctx.GroupId = payload.chatId;\n ctx.InboundHistory = popUnmentionedHistories(accountId, payload.chatId);\n }\n if (payload.chatType == CHAT_TYPE_CHANNEL) {\n ctx.WasMentioned = payload.WasMentioned;\n ctx.IsForum = true;\n ctx.GroupSubject = payload.channelName;\n ctx.GroupChannel = payload.chatId;\n ctx.InboundHistory = popUnmentionedHistories(accountId, payload.chatId);\n }\n if (payload.mediaUrls?.length) ctx.MediaUrls = payload.mediaUrls;\n if (payload.replyToId) ctx.ReplyToId = payload.replyToId;\n\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, handleInboundMessage dispatchReply ctx: ${JSON.stringify(ctx, null, ' ')}`);\n try {\n await dispatchReply(ctx, cfg, account, payload, apiRuntime, log);\n } catch (err) {\n log?.error?.(`[${CHANNEL_ID}] AccountId: ${accountId}, dispatchReply failed:`, err);\n }\n}\n"]}
1
+ {"version":3,"file":"inbound.js","sourceRoot":"","sources":["../../src/inbound.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TuiTui inbound message handler — pure business logic.\n *\n * channel.ts owns the WebSocket frame layer (JSON parse, ACK, keepalive\n * filtering) and calls handleInboundMessage with an already-parsed object.\n *\n * Usage:\n * ws.on('message', async (wsData) => {\n * // ... parse JSON, send ACK, filter keepalive ...\n * await handleInboundMessage(json, { account, accountId, apiRuntime, log });\n * });\n */\nimport type { TuiTuiInboundMessage, TuiTuiOutboundDeliverOptions } from './types';\nimport { CHANNEL_ID } from './const';\nimport {CHAT_TYPE_DIRECT,CHAT_TYPE_GROUP,CHAT_TYPE_CHANNEL,ChatType,teamsParseChatId,teamsBuildChatId} from \"./chat_base\"\nimport {tuituiEmojiReaction, sendTextMsg, sendPageMsg, sendMediaMsg } from \"./outbound\";\nimport { teams_get_members, teams_get_members_text, teams_get_announcement } from \"./teams_api\"\nimport { parseChatMessageBody } from './inbound_body_parse';\nimport { parseAllowFroms } from './utils';\nimport { addUnmentionedHistory, popUnmentionedHistories } from \"./histories\";\nimport { StringDeduplicator } from \"./deduplicator\"\nimport { getPostChainByChatId } from \"./chat_record\"\n\n// 会话上下文注入排重\nlet _session_ctx_injected = new StringDeduplicator(1000, 3600);\n\n/** 子函数共享的可变上下文,子函数直接修改字段,外层读取结果 */\ninterface ChatPayload {\n chatType: ChatType;\n chatId: string | undefined;\n botName: string;\n text: string | undefined;\n groupName: string | undefined;\n channelName: string | undefined;\n mediaUrls: string[] | undefined;\n replyToId: string | undefined; // 引用ID\n msgId?: string; // 消息ID\n tuituiAccount: string;\n tuituiUid: string | undefined;\n tuituiUserName: string | undefined;\n timestamp: Number | undefined;\n WasMentioned: boolean | undefined;\n}\n\nexport interface InboundAccount {\n accountId: string;\n appId: string;\n appSecret: string;\n dmPolicy: string;\n allowFrom: string[];\n groupPolicy: string;\n groupAllowFrom: string[];\n requireMention: boolean;\n emojiReaction: boolean;\n}\nexport interface InboundHandlerOptions {\n json: any\n account: InboundAccount;\n apiRuntime: any;\n log: any;\n}\n\nfunction getSessionKey(cfg: any, payload: ChatPayload, account: InboundAccount, apiRuntime: any): string {\n const { chatId, chatType } = payload;\n const { accountId } = account;\n // 你自己只需要拼接与定义 peer.id\n // 关于 sessionKey 格式的解释: https://docs.openclaw.ai/channels/channel-routing#sessionkey-%E5%8F%82%E8%80%83%E6%A0%BC%E5%BC%8F\n let id = chatId;\n if(chatType == CHAT_TYPE_CHANNEL) {\n const { channel_id, parent_id } = teamsParseChatId(chatId!);\n id = `${channel_id}`;\n if(parent_id) {\n id += `:thread:${parent_id}`;\n }\n }\n\n // sessionKey 不能自己拼字符串,需要用系统api识别,他会根据 bindings 路由规则处理\n const { sessionKey } = apiRuntime.channel.routing.resolveAgentRoute({\n cfg,\n accountId,\n channel: CHANNEL_ID,\n peer: { kind: chatType, id: id },\n });\n return String(sessionKey).replace(/\\//g, '_');\n}\n\nfunction getMediaUrls({ msg_type, images, voice, video, file }: any): string[] | undefined {\n if (msg_type === 'image' || msg_type === 'mixed') {\n if (images?.length) return images;\n } else if (msg_type === 'voice') {\n if (voice) return [voice];\n } else if (msg_type === 'video') {\n if (video) return [video];\n } else if (msg_type === 'file') {\n if (file?.url) return [file.url];\n }\n return undefined;\n}\n\nasync function dispatchReply(ctx: any, cfg: any, account: InboundAccount, payload: ChatPayload, apiRuntime: any, log: any) {\n const { accountId } = account;\n await apiRuntime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx,\n cfg,\n dispatcherOptions: {\n deliver: async (outbound: TuiTuiOutboundDeliverOptions) => {\n // Custom message (e.g. page)\n if (outbound.custom) {\n const { msgtype, page, tousers, togroups } = outbound.custom;\n if (msgtype === 'page' && page) {\n await sendPageMsg(account, payload.chatId, payload.chatType, page, 'tuitui.deliver.page', tousers, togroups);\n return;\n }\n log?.warn?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Unsupported custom message type: ${msgtype}`);\n return;\n }\n\n // Media message\n const mediaUrl = outbound.mediaUrl || outbound.mediaUrls?.[0];\n if (mediaUrl) {\n await sendMediaMsg(account, payload.chatId, payload.chatType, mediaUrl, 'tuitui.deliver.media', [payload.tuituiAccount]);\n return;\n }\n\n // Text message\n const replyText = outbound?.text || outbound?.body;\n if (replyText) {\n // 群消息回复时不再使用 reference_msgid 避免并发时引用错乱,依靠 @ 来提醒用户\n await sendTextMsg(account, payload.chatId, payload.chatType, replyText, 'tuitui.deliver.text', [payload.tuituiAccount]);\n return;\n }\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, no_reply_content`);\n },\n\n onReplyStart: () => {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Agent is typing to ${payload.tuituiAccount}`);\n },\n },\n });\n}\n\n/*** 配对节流映射 - 用于防止短时间内大量重复配对请求消息发出\n * key: `${accountId}-${chatId}`\n * val: timestamp */\nconst pairingThrottleMap = new Map<string, number>();\n// 暂时控制为 2 分钟内同一个用户只能触发一次配对请求\nconst needPairingThrottle = (accountId: string | undefined, chatId: string, throttleMs = 2 * 60 * 1000): boolean => {\n const key = `${accountId}-${chatId}`;\n const now = Date.now();\n const lastTime = pairingThrottleMap.get(key) || 0;\n if (now - lastTime < throttleMs) {\n return true;\n }\n pairingThrottleMap.set(key, now);\n return false;\n}\n\nasync function sendSingleChatPairingMsg(account: any, payload: any, log: any, apiRuntime: any) {\n const { accountId } = account;\n const { chatId, chatType } = payload;\n if (needPairingThrottle(accountId, chatId)) {\n return log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing throttled for sender=${chatId}`);\n }\n try {\n log?.debug?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing flow: checking if pairing request exists for sender=${chatId}`);\n const req = await apiRuntime.channel.pairing.upsertPairingRequest({ channel: CHANNEL_ID, accountId, id: chatId });\n log?.debug?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing flow: upsertPairingRequest result=${JSON.stringify(req)}`);\n // 只要没配对,会每次和机器人聊,都会返回配对信息。\n const replyText = apiRuntime.channel.pairing.buildPairingReply({ channel: CHANNEL_ID, code: req.code });\n await sendTextMsg(account, chatId, chatType, replyText, 'tuitui.pairing.reply');\n } catch (err) {\n log?.warn?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing failed for ${chatId}: ${String(err)}`);\n }\n}\n\n//tuituiAccounts列表中是否存在至少1个允许私聊的用户(私聊白名单、配对、或者open)\nasync function isAllowOneOfAccount(tuituiAccounts: string[], apiRuntime: any, account: InboundAccount) {\n if(!tuituiAccounts) return false;\n const { accountId, allowFrom, dmPolicy } = account;\n if (dmPolicy === 'open') return true;\n\n // 是否包含任意一个元素\n if (tuituiAccounts.some(item => allowFrom.includes(item))) return true;\n\n try {\n let storeAllowFrom = parseAllowFroms(\n await apiRuntime?.channel?.pairing?.readAllowFromStore?.({ channel: CHANNEL_ID, accountId })\n );\n if (tuituiAccounts.some(item => storeAllowFrom.includes(item))) return true;\n } catch {}\n return false; \n}\n\nasync function isAllowAccount(tuituiAccount: string, apiRuntime: any, account: InboundAccount) {\n return await isAllowOneOfAccount([tuituiAccount], apiRuntime, account);\n}\n\nasync function isChannelCoordAuthorized(tuituiAccount: string, apiRuntime: any, account: InboundAccount, team_id:string, chat_id:string) {\n // 协调员身份校验\n if (tuituiAccount != \"bot-FiwwCeDw\" && tuituiAccount != \"bot-sUwUeknd\") return false;\n\n // 当前 thread 中有白名单用户发帖,则协调员继承该权限\n const [members, posts] = await Promise.all([\n teams_get_members(account, team_id),\n getPostChainByChatId(account, chat_id),\n ]);\n if (!members?.length || !posts?.length) return false;\n\n const from_uids = posts.map((p: any) => p.from_uid).filter(Boolean);\n if (!from_uids.length) return false;\n\n //console.log(\"from_uids\", from_uids);\n\n // 将 uid 映射到 user_account\n const from_accounts: string[] = members\n .filter((m: any) => from_uids.includes(m.uid) && m.account)\n .map((m: any) => String(m.account));\n if (!from_accounts.length) return false;\n\n //console.log(\"from_accounts\", from_accounts);\n return await isAllowOneOfAccount(from_accounts, apiRuntime, account);\n}\n\n\n/**\n * 处理单聊(single_chat)、群聊、团队帖子分支,直接修改并校验 payload。\n * 返回 false 表示消息不合法,外层应提前 return;返回 true 表示校验通过,继续执行。\n */\nasync function parse_single_chat(payload: ChatPayload, msgData: any, account: InboundAccount, apiRuntime: any, log: any): Promise<boolean> {\n const { accountId, dmPolicy, allowFrom } = account;\n const chatId = payload.tuituiAccount ? String(payload.tuituiAccount || '').toLowerCase().trim() : '';\n if (dmPolicy === 'disabled') { //['pairing', 'allowlist', 'open', 'disabled'],\n log?.warn?.(`[${CHANNEL_ID}] AccountId: ${accountId}, DM disabled sender=${chatId}`);\n return false;\n }\n\n payload.chatType = CHAT_TYPE_DIRECT;\n payload.chatId = chatId;\n payload.text = parseChatMessageBody(msgData);\n payload.msgId = msgData.msgid;\n log?.debug?.(\n `[${CHANNEL_ID}] AccountId: ${accountId}, inbound single_chat:\n userAccount=${chatId},\n tuituiUid=${payload.tuituiUid},\n tuituiUserName=${payload.tuituiUserName},\n dmPolicy=${dmPolicy},\n allowFrom=${JSON.stringify(allowFrom)}`);\n\n if (!chatId && !payload.tuituiUid) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Missing user_account or uid in single_chat event`);\n return false;\n }\n\n if (dmPolicy === 'open') return true;\n\n if(await isAllowAccount(chatId, apiRuntime, account)){\n return true;\n }\n\n if (dmPolicy === 'pairing') {\n sendSingleChatPairingMsg(account, payload, log, apiRuntime);\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, pairing required`);\n return false;\n }\n // allowlist\n log?.warn?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Blocked unauthorized sender (allowlist): sender=${chatId} allowFrom=${JSON.stringify(allowFrom)}`);\n return false;\n}\n\nasync function parse_group_chat(payload: ChatPayload, msgData: any, account: InboundAccount, apiRuntime: any, log: any): Promise<boolean> {\n const { accountId, groupPolicy, groupAllowFrom } = account;\n payload.chatType = CHAT_TYPE_GROUP;\n const chatId = msgData.group_id ? String(msgData.group_id).toLowerCase().trim() : '';\n payload.chatId = chatId;\n payload.groupName = msgData.group_name;\n payload.msgId = msgData.msgid;\n payload.text = parseChatMessageBody(msgData);\n payload.WasMentioned = msgData.at_me;\n const { tuituiAccount } = payload;\n log?.debug?.(\n `[${CHANNEL_ID}] AccountId: ${accountId}, inbound group_chat:\n tuituiAccount=${tuituiAccount},\n tuituiUid=${payload.tuituiUid},\n tuituiUserName=${payload.tuituiUserName},\n groupId=${chatId},\n groupPolicy=${groupPolicy},\n groupAllowFrom=${JSON.stringify(groupAllowFrom)},\n at_me=${JSON.stringify(msgData.at_me)},\n at=${JSON.stringify(msgData.at)}`);\n\n if (groupPolicy === 'disabled') {\n log?.info?.(`${CHANNEL_ID} AccountId: ${accountId}, groupPolicy disabled`);\n return false;\n }\n\n if (!tuituiAccount || !chatId) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Missing tuituiAccount or chatId in group_chat event`);\n return false;\n }\n\n if (!msgData.at_me && account.requireMention) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, ignore group message (not mentioned), add to history key: ${chatId}`);\n await addUnmentionedHistory(apiRuntime, accountId, chatId, payload.tuituiUserName, tuituiAccount, payload.text, payload.timestamp);\n return false;\n }\n\n // 私聊白名单对群聊仍然生效,当群里只想特定人@时,可以不配置groupAllowFrom,而是配置 allowFrom\n if(await isAllowAccount(tuituiAccount, apiRuntime, account)){\n return true;\n }\n\n if (!groupAllowFrom.includes(chatId)) {\n if (needPairingThrottle(accountId, chatId)) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, group pairing throttled for groupId=${chatId}`);\n return false;\n }\n\n const msgTxt=`当前 OpenClaw(AccountId: ${accountId})的群聊策略为白名单模式。\n需由龙虾主人在配置中添加白名单(两种方式二选一即可):\n\n- 允许群中所有人用,在群白名单(Group Allow From)添加当前群ID: ${chatId}\n\n- 不想群所有人用,只想特定人用,在私聊白名单(Allow From)添加当前用户 ${payload.tuituiAccount} ,私聊白名单对群仍然有效`\n\n await sendTextMsg(account, chatId, payload.chatType, msgTxt, 'tuitui.groupPolicy.reply');\n return false;\n }\n\n return true; \n}\n\n\nasync function parse_teams_post(payload: ChatPayload, msgData: any, account: InboundAccount, apiRuntime: any, log: any): Promise<boolean> {\n const { accountId, groupPolicy, groupAllowFrom } = account;\n payload.chatType = CHAT_TYPE_CHANNEL;\n const { team_id, channel_id, parent_id, post_id, content, team_name, channel_name } = msgData;\n const thread_id = (parent_id && parent_id != \"0\")?parent_id: post_id;\n const chatId = teamsBuildChatId(team_id, channel_id, thread_id);\n payload.chatId = chatId;\n payload.msgId = post_id;\n payload.text = content;\n payload.channelName = channel_name;\n payload.replyToId = \"\";\n payload.WasMentioned = msgData.at_me;\n const { tuituiAccount } = payload;\n log?.debug?.(\n `[${CHANNEL_ID}] AccountId: ${accountId}, inbound teams:\n tuituiAccount=${tuituiAccount},\n tuituiUid=${payload.tuituiUid},\n tuituiUserName=${payload.tuituiUserName},\n chatId=${chatId},\n groupPolicy=${groupPolicy},\n groupAllowFrom=${JSON.stringify(groupAllowFrom)},\n at_me=${JSON.stringify(msgData.at_me)},\n at=${JSON.stringify(msgData.at)}`,\n );\n\n if (groupPolicy === 'disabled') {\n log?.info?.(`${CHANNEL_ID} AccountId: ${accountId}, groupPolicy disabled`);\n return false;\n }\n\n if (!tuituiAccount) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, Missing tuituiAccount or chatId in event`);\n return false;\n }\n\n \n {\n // 频道帖子文件、附件处理。必须放在正文里\n const {images, files} = msgData;\n if (images) {\n payload.text += \"\\n\\n附录上文提到的图片列表\\n\"\n for (const image of images) {\n payload.text += image + \"\\n\";\n }\n }\n if (files) {\n payload.text += \"\\n\\n附录上文提到的文件列表\\n\"\n for (const file of files) {\n payload.text += `[文件] ${file?.name} : ${file?.url} \\n`;\n }\n }\n }\n\n if (!msgData.at_me && account.requireMention) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, ignore teams post (not mentioned), add to history ${chatId} -> ${payload.text}`);\n await addUnmentionedHistory(apiRuntime, accountId, chatId, payload.tuituiUserName, tuituiAccount, payload.text, payload.timestamp);\n return false;\n }\n\n // 私聊白名单对团队仍然生效,限制特定人@时,可以不配置groupAllowFrom,而是配置 allowFrom\n if(await isAllowAccount(tuituiAccount, apiRuntime, account)){\n return true;\n }\n \n if (!groupAllowFrom.includes(String(team_id)) && !groupAllowFrom.includes(String(channel_id)) ) {\n if (!msgData.at_me) {\n // 解决这个case:requireMention=false时,团队里发任意帖子都会回复加白,搞得没法用\n // 要求必须@才触发回复加白\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, ignore teams post (not mentioned)`);\n return false;\n }\n\n // 频道中允许协调员@自己(且帖子里有白名单用户发帖)\n if (await isChannelCoordAuthorized(tuituiAccount, apiRuntime, account, team_id, chatId)) {\n return true;\n }\n\n if (needPairingThrottle(accountId, chatId)) {\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, teams pairing throttled for teamsChatId=${chatId}`);\n return false;\n }\n\n const msgTxt=`当前 OpenClaw(AccountId: ${accountId})的群聊/团队策略为白名单模式。\n需由龙虾主人在配置中添加白名单(3种方式选一种即可):\n\n- 允许团队中所有人用,在群白名单(Group Allow From)添加当前团队ID: ${team_id}\n- 仅允许当前频道使用,在群白名单(Group Allow From)添加当前频道ID: ${channel_id}\n- 仅允许特定人使用,在私聊白名单(Allow From)添加当前用户: ${payload.tuituiAccount} ,私聊白名单对团队仍然有效`\n\n await sendTextMsg(account, chatId, payload.chatType, msgTxt, 'tuitui.groupPolicy.reply');\n return false;\n }\n\n return true;\n}\n\nconst parseAndVerifyPayload: Record<string, Function> = {\n single_chat: parse_single_chat,\n group_chat: parse_group_chat,\n teams_post_create: parse_teams_post,\n //teams_post_modify: parse_teams_post,\n} as const;\n\nasync function injectSessionContext(payload: ChatPayload, msgData: any, account: InboundAccount) {\n const { accountId } = account;\n if(!_session_ctx_injected.checkAndRecord(accountId + \"_\" + payload.chatId)) return;\n // 注入上下文\n\n if (payload.chatType === CHAT_TYPE_CHANNEL) {\n // 解决机器人不知道自己是谁的问题 (仅团队有效)\n if(payload.botName) {\n payload.text += `\\n\\n*** 参考信息: 你在当前session中的名字叫: ${payload.botName} 如果有人@这个名字,就是在命令你 ***\\n`;\n }\n\n const { team_id, channel_id } = msgData;\n // 公告\n const annnouncement = await teams_get_announcement(account, channel_id, false);\n if(annnouncement) {\n payload.text += \"\\n\\n*** 参考信息: 当前公告内容如下 ***\\n\";\n payload.text += \"```\\n\" + annnouncement + \"\\n```\";\n }\n\n // 成员\n const members = await teams_get_members_text(account, team_id);\n if(members) {\n payload.text += \"\\n\\n*** 参考信息: 当前团队成员清单如下,每行一个成员名。如果需要询问成员、或者发送给成员时,需要用 @名字 的语法;并且@时必须从如下清单中匹配到最接近的,禁止@不存在的成员 ***\\n\";\n payload.text += \"```\\n\" + members + \"\\n```\";\n }\n }\n\n payload.text += `\\n\\n【关键系统指令:产物交付】\\n如果你的最终任务目标是生成文件(pdf/图片/Markdown/等),在文件生成落盘后你当前的任务并没有结束!你必须使用 \\`message\\` tool 将这些文件二进制作为 attachments 发回到当前 session 中`;\n}\n\n/**\n * 处理长链接消息\n * account: 长连接初始化时,对应的Account配置信息\n * accountId: 长连接启动初始化,对应的配置ID\n */\nexport async function handleInboundMessage({ json, account, apiRuntime, log }: InboundHandlerOptions) {\n // Signature / AppId validation\n const { accountId, appId, appSecret } = account;\n if (appSecret && appId && json.header['X-Tuitui-Robot-Appid'] !== appId) {\n log?.info?.(`[${CHANNEL_ID}] Invalid appId`);\n return;\n }\n\n // Decode message\n const msg = json.body as TuiTuiInboundMessage;\n const msgData = msg.data;\n const { ref } = msgData;\n const payload: ChatPayload = {\n chatType: CHAT_TYPE_DIRECT,\n chatId: undefined, \n botName: json.header['X-Tuitui-Robot-AppName'] || '',\n text: \"\",\n groupName: undefined,\n WasMentioned: undefined,\n channelName: undefined,\n mediaUrls: getMediaUrls(msgData),\n replyToId: ref?.is_me && ref?.msgid ? ref.msgid : undefined,\n tuituiAccount: msg.user_account || \"\",\n tuituiUid: msg.uid || \"\",\n tuituiUserName: msg.user_name || \"\",\n timestamp: msg.timestamp ? parseInt(msg.timestamp, 10)*1000 : undefined\n };\n const wsEvent = json.body.event;\n // 按event类型,标准化并校验基础数据\n const parseAndVerifyPayloadFun = parseAndVerifyPayload[wsEvent] as Function | undefined;\n if (!parseAndVerifyPayloadFun) {\n log?.info?.(`[${CHANNEL_ID}] ignore unknown event ${wsEvent}`);\n return;\n }\n if (!(await parseAndVerifyPayloadFun(payload, msgData, account, apiRuntime, log))) return;\n\n if (!payload.chatId || !payload.msgId) {\n log?.info?.(`[${CHANNEL_ID}] ignore unknown mseeage, missing chatId or msgId`, payload);\n return;\n }\n\n if (account.emojiReaction) {\n // 因为回复较慢,先回复一个表情\n try{\n await tuituiEmojiReaction(account, payload.chatId, payload.chatType, payload.msgId, '收到');\n } catch (err) {\n // 出错不影响后续逻辑\n }\n }\n\n // 路由判断\n const routeSenderFrom = payload.tuituiAccount || payload.tuituiUid || 'unknown';\n\n const cfg = await apiRuntime.config.loadConfig();\n const sessionKey = getSessionKey(cfg, payload, account, apiRuntime);\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, dispatching to agent session=${sessionKey}, chatType: ${payload.chatType}, chatId ${payload.chatId}, routeSenderFrom: ${routeSenderFrom}`);\n\n payload.text = payload.text || '';\n const stripedBody = payload.text.replace(`@${payload.botName}`, '').trim();\n if (stripedBody.startsWith('/')) {\n payload.text = stripedBody;\n if (payload.text.startsWith('/new') || payload.text.startsWith('/reset')) {\n // 清理agent上下文时,同时清空历史\n popUnmentionedHistories(accountId, payload.chatId);\n }\n } else {\n // 指令以外的才注入\n await injectSessionContext(payload, msgData, account);\n }\n\n // 字段意义 参考 openclaw 代码\n // src\\auto-reply\\reply\\inbound-meta.ts\n // buildInboundUserContextPrefix()\n const ctx: any = {\n Body: payload.text,\n From: String(routeSenderFrom),\n To: CHANNEL_ID,\n SessionId: sessionKey,\n SessionKey: sessionKey,\n AccountId: accountId,\n OriginatingChannel: CHANNEL_ID,\n OriginatingTo: payload.chatId,\n ChatType: payload.chatType!,\n Surface: CHANNEL_ID,\n Provider: CHANNEL_ID,\n SenderName: payload.tuituiUserName,\n SenderId: payload.tuituiAccount,\n SenderUsername: payload.tuituiAccount, \n UserAccount: payload.tuituiAccount,\n Timestamp: payload.timestamp,\n CommandAuthorized: true, // 允许 /new 等内置命令\n };\n if (payload.chatType == CHAT_TYPE_GROUP && payload.chatId) {\n ctx.WasMentioned = payload.WasMentioned;\n ctx.GroupSubject = payload.groupName;\n ctx.GroupId = payload.chatId;\n ctx.InboundHistory = popUnmentionedHistories(accountId, payload.chatId);\n }\n if (payload.chatType == CHAT_TYPE_CHANNEL) {\n ctx.WasMentioned = payload.WasMentioned;\n ctx.IsForum = true;\n ctx.GroupSubject = payload.channelName;\n ctx.GroupChannel = payload.chatId;\n ctx.InboundHistory = popUnmentionedHistories(accountId, payload.chatId);\n }\n if (payload.mediaUrls?.length) ctx.MediaUrls = payload.mediaUrls;\n if (payload.replyToId) ctx.ReplyToId = payload.replyToId;\n\n log?.info?.(`[${CHANNEL_ID}] AccountId: ${accountId}, handleInboundMessage dispatchReply ctx: ${JSON.stringify(ctx, null, ' ')}`);\n try {\n await dispatchReply(ctx, cfg, account, payload, apiRuntime, log);\n } catch (err) {\n log?.error?.(`[${CHANNEL_ID}] AccountId: ${accountId}, dispatchReply failed:`, err);\n }\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  import { DEFAULT_ACCOUNT_ID } from 'openclaw/plugin-sdk/account-id';
2
2
  import { CHANNEL_ID } from './const';
3
3
  import { tuituiRobotApi } from './robot_api';
4
- import { parseChannelIdBySessionKey } from "./chat_base";
5
4
  import { monitorEnabledDefault } from './accounts';
6
5
  // 批量上报参数
7
6
  const BATCH_MAX_SIZE = 100; // 达到此条数立即 flush
@@ -212,10 +211,9 @@ function report(targets, eventType, ctx, data) {
212
211
  const agentId = extractAgentId(sessionKey);
213
212
  if (!agentId)
214
213
  return;
215
- // 仅频道支持;私聊群聊不启用
216
- const channelId = parseChannelIdBySessionKey(sessionKey);
217
- if (!channelId)
218
- return;
214
+ // 全部启用
215
+ // const channelId = parseChannelIdBySessionKey(sessionKey);
216
+ // if(!channelId) return;
219
217
  const reportedAccountIds = new Map();
220
218
  for (const target of targets) {
221
219
  if (target.agentId !== agentId)
@@ -1 +1 @@
1
- {"version":3,"file":"monitor.js","sourceRoot":"","sources":["../../src/monitor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TuiTui Monitor — 将 OpenClaw Hook 事件批量上报到监控接口。\n *\n * 每个账户(appId/appSecret)维护独立队列,满足以下任一条件时批量上报:\n * - 队列积累达 BATCH_MAX_SIZE 条\n * - 距上次 flush 超过 BATCH_INTERVAL_MS\n *\n * 需在配置中将 monitorEnabled 设为 true 才会上报\n *\n * 配置示例(openclaw.json):\n * channels.tuitui.monitorEnabled: true\n */\nimport type { OpenClawPluginApi } from 'openclaw/plugin-sdk';\nimport { DEFAULT_ACCOUNT_ID } from 'openclaw/plugin-sdk/account-id';\nimport { CHANNEL_ID } from './const';\nimport { tuituiRobotApi } from './robot_api';\nimport {parseChannelIdBySessionKey} from \"./chat_base\"\nimport { monitorEnabledDefault } from './accounts';\n\n// 批量上报参数\nconst BATCH_MAX_SIZE = 100; // 达到此条数立即 flush\nconst BATCH_INTERVAL_MS = 5_000; // 定时 flush 间隔(ms)\nconst PAYLOAD_SIZE_LIMIT = 100 * 1024; // 单条 payload 兜底截断:100 KB\n\n// ─────────────────────────────────────────────────────────────\n// 上报载荷结构\n// ─────────────────────────────────────────────────────────────\n\nexport type MonitorEventType =\n | 'llm_input'\n | 'llm_output'\n | 'before_compaction'\n | 'after_compaction'\n | 'before_reset'\n | 'before_dispatch'\n | 'before_tool_call'\n | 'after_tool_call'\n | 'session_start'\n | 'session_end'\n | 'agent_end'\n | 'subagent_spawned'\n | 'subagent_ended';\n\nexport interface MonitorPayload {\n event: MonitorEventType;\n timestamp: number; // Unix ms\n plugin: string; // 固定 \"tuitui\"\n accountId: string; // 所属账户 ID\n appId: string; // 机器人 appId\n ctx: unknown; // hook 原始 ctx 对象\n data: string; // hook 原始 event 对象序列化后的 JSON 字符串\n}\n\n// ─────────────────────────────────────────────────────────────\n// 批量队列(每个 accountId 独立维护)\n// ─────────────────────────────────────────────────────────────\n\ninterface BatchQueue {\n items: MonitorPayload[];\n timer: ReturnType<typeof setTimeout> | null;\n target: MonitorTarget;\n}\n\n// accountId → BatchQueue\nconst batchQueues = new Map<string, BatchQueue>();\n\ninterface MonitorTarget {\n accountId: string;\n appId: string;\n appSecret: string;\n agentId: string; // 通过 bindings 解析出的关联 agentId,无 binding 时默认 \"main\"\n}\n\n// ─────────────────────────────────────────────────────────────\n// flush:将队列中所有事件一次性上报\n// ─────────────────────────────────────────────────────────────\n\nfunction flushQueue(queue: BatchQueue): void {\n if (queue.items.length === 0) return;\n\n // 取走当前所有条目,重置队列\n const batch = queue.items.splice(0);\n\n // 清除定时器\n if (queue.timer) {\n clearTimeout(queue.timer);\n queue.timer = null;\n }\n\n const { target } = queue;\n const account = { appId: target.appId, appSecret: target.appSecret };\n\n tuituiRobotApi(account, '/openclaw/report', batch, false).then(() => {\n console.log(\n `[${CHANNEL_ID}][monitor] <<< flush ok accountId=${target.accountId} count=${batch.length}`,\n );\n }).catch((err) => {\n console.error(`[${CHANNEL_ID}][monitor] flush failed accountId=${target.accountId}:`, err);\n });\n}\n\n// ─────────────────────────────────────────────────────────────\n// 入队:将一条事件加入对应账户的队列\n// ─────────────────────────────────────────────────────────────\n\nfunction enqueue(target: MonitorTarget, payload: MonitorPayload): void {\n let queue = batchQueues.get(target.accountId);\n\n if (!queue) {\n queue = { items: [], timer: null, target };\n batchQueues.set(target.accountId, queue);\n }\n\n // 兜底:data 字段超过 100 KB 时暴力截断\n if (payload.data.length > PAYLOAD_SIZE_LIMIT) {\n payload.data = payload.data.slice(0, PAYLOAD_SIZE_LIMIT) + '...[truncated]';\n }\n\n queue.items.push(payload);\n\n // 达到上限,立即 flush\n if (queue.items.length >= BATCH_MAX_SIZE) {\n flushQueue(queue);\n return;\n }\n\n // 尚未启动定时器,则启动\n if (!queue.timer) {\n queue.timer = setTimeout(() => {\n console.log(`[${CHANNEL_ID}][monitor] timer fired, flush accountId=${target.accountId} count=${queue!.items.length}`);\n flushQueue(queue!);\n }, BATCH_INTERVAL_MS);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// 读取所有开启了 monitorEnabled 的账户信息\n// ─────────────────────────────────────────────────────────────\n\nfunction resolveMonitorTargets(cfg: any): MonitorTarget[] {\n const channelCfg = cfg?.channels?.[CHANNEL_ID] || {};\n const targets: MonitorTarget[] = [];\n\n // 从 bindings 建立 accountId → agentId 映射\n const accountAgentId = new Map<string, string>();\n const bindings: any[] = cfg?.bindings ?? [];\n for (const binding of bindings) {\n if (binding?.match?.channel !== CHANNEL_ID) continue;\n const accId = binding.match.accountId;\n const agentId = binding.agentId;\n if (!accId || !agentId || accountAgentId.has(accId)) continue;\n accountAgentId.set(accId, agentId);\n }\n\n const resolveAgentId = (accountId: string): string =>\n accountAgentId.get(accountId) ?? 'main';\n\n // 默认账户\n if ((channelCfg.monitorEnabled ?? monitorEnabledDefault) === true) {\n const appId = channelCfg.appId || '';\n const appSecret = channelCfg.appSecret || '';\n if (appId && appSecret) {\n targets.push({\n accountId: DEFAULT_ACCOUNT_ID,\n appId,\n appSecret,\n agentId: resolveAgentId(DEFAULT_ACCOUNT_ID),\n });\n }\n }\n\n // 子账户\n if (channelCfg.accounts) {\n for (const [accountId, acct] of Object.entries(channelCfg.accounts) as [string, any][]) {\n if ((acct?.monitorEnabled ?? monitorEnabledDefault) !== true) continue;\n const appId = acct?.appId || channelCfg.appId || '';\n const appSecret = acct?.appSecret || channelCfg.appSecret || '';\n if (!appId || !appSecret) continue;\n targets.push({\n accountId,\n appId,\n appSecret,\n agentId: resolveAgentId(accountId),\n });\n }\n }\n\n return targets;\n}\n\n// ─────────────────────────────────────────────────────────────\n// 从 ctx 中解析出 tuitui accountId\n// ─────────────────────────────────────────────────────────────\n\n/**\n * 从 sessionKey 字符串中解析出 agentId。\n * sessionKey 格式:agent:<agentId>:...\n */\nfunction extractAgentId(sessionKey: unknown): string | null {\n if (typeof sessionKey !== 'string') return null;\n const parts = sessionKey.split(':');\n const idx = parts.indexOf('agent');\n if (idx === -1 || !parts[idx + 1]) return null;\n return parts[idx + 1];\n}\n\n// ─────────────────────────────────────────────────────────────\n// 大字段裁剪\n// ─────────────────────────────────────────────────────────────\n\nconst TRUNCATE_LIMIT = 64 * 1024; // 64 KB\n\nfunction truncate(s: unknown): unknown {\n if (typeof s !== 'string' || s.length <= TRUNCATE_LIMIT) return s;\n return s.slice(0, TRUNCATE_LIMIT) + `…[truncated ${s.length - TRUNCATE_LIMIT} chars]`;\n}\n\nfunction truncateContent(obj: unknown): unknown {\n if (!obj || typeof obj !== 'object') return obj;\n const o = obj as Record<string, unknown>;\n if (!('content' in o)) return o;\n const content = o.content;\n if (typeof content === 'string') return { ...o, content: truncate(content) };\n if (Array.isArray(content)) {\n return {\n ...o,\n content: content.map((block: unknown) => {\n if (!block || typeof block !== 'object') return block;\n const b = block as Record<string, unknown>;\n if (b.type === 'text' && typeof b.text === 'string') {\n return { ...b, text: truncate(b.text) };\n }\n return b;\n }),\n };\n }\n return o;\n}\n\nfunction trimData(eventType: MonitorEventType, data: unknown): unknown {\n const d = data as any;\n switch (eventType) {\n case 'agent_end':\n if (Array.isArray(d?.messages)) {\n return { ...d, messages: d.messages.slice(-10).map(truncateContent) };\n }\n return d;\n\n // case 'before_prompt_build':\n // case 'before_agent_start':\n case 'before_compaction':\n case 'before_reset':\n if (Array.isArray(d?.messages)) {\n return { ...d, messages: d.messages.map(truncateContent) };\n }\n return d;\n\n case 'llm_input':\n return {\n ...d,\n systemPrompt: truncate(d?.systemPrompt),\n prompt: truncate(d?.prompt),\n historyMessages: Array.isArray(d?.historyMessages)\n ? d.historyMessages.map(truncateContent)\n : d?.historyMessages,\n };\n\n case 'llm_output':\n return {\n ...d,\n assistantTexts: Array.isArray(d?.assistantTexts)\n ? d.assistantTexts.map((t: unknown) => truncate(t))\n : d?.assistantTexts,\n lastAssistant: truncateContent(d?.lastAssistant),\n };\n\n case 'after_tool_call':\n return { ...d, result: truncate(typeof d?.result === 'string' ? d.result : JSON.stringify(d?.result)) };\n\n default:\n return d;\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// 主入口:收到 hook 事件后入队\n// ─────────────────────────────────────────────────────────────\n\nfunction report(\n targets: MonitorTarget[],\n eventType: MonitorEventType,\n ctx: unknown,\n data: unknown,\n): void {\n let sessionKey = \"\";\n\n // subagent hook 的 ctx 有 childSessionKey,普通 hook 有 sessionKey\n if (eventType === 'subagent_spawned' || eventType === 'subagent_ended') {\n sessionKey = (ctx as any)?.childSessionKey\n } else {\n sessionKey = (ctx as any)?.sessionKey\n }\n\n const agentId = extractAgentId(sessionKey);\n if (!agentId) return;\n\n // 仅频道支持;私聊群聊不启用\n const channelId = parseChannelIdBySessionKey(sessionKey);\n if(!channelId) return;\n\n const reportedAccountIds = new Map<string, boolean>();\n for (const target of targets) {\n if (target.agentId !== agentId) continue;\n if (reportedAccountIds.has(target.accountId)) continue;\n reportedAccountIds.set(target.accountId, true);\n\n const payload: MonitorPayload = {\n event: eventType,\n timestamp: Date.now(),\n plugin: CHANNEL_ID,\n accountId: target.accountId,\n appId: target.appId,\n ctx,\n data: JSON.stringify(trimData(eventType, data)),\n };\n\n enqueue(target, payload);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// 注册全量 Hook\n// ─────────────────────────────────────────────────────────────\n\nexport function registerMonitorHooks(api: OpenClawPluginApi) {\n const on = (eventType: MonitorEventType) =>\n api.on(eventType as any, (event: unknown, ctx: unknown) => {\n const targets = resolveMonitorTargets(api.runtime.config.loadConfig());\n if (targets.length > 0) {\n report(targets, eventType, ctx, event);\n }\n });\n\n // ── Agent run 阶段 ────────────────────────────────────────\n on('llm_input');\n on('llm_output');\n on('agent_end');\n\n // ── Compaction / Reset ────────────────────────────────────\n on('before_compaction');\n on('after_compaction');\n on('before_reset');\n\n // ── 消息阶段 ──────────────────────────────────────────────\n on('before_dispatch');\n\n // ── Tool 阶段 ─────────────────────────────────────────────\n on('before_tool_call');\n on('after_tool_call');\n\n // ── Session 阶段 ──────────────────────────────────────────\n on('session_start');\n on('session_end');\n\n // ── Subagent 阶段 ─────────────────────────────────────────\n on('subagent_spawned');\n on('subagent_ended');\n}\n"]}
1
+ {"version":3,"file":"monitor.js","sourceRoot":"","sources":["../../src/monitor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TuiTui Monitor — 将 OpenClaw Hook 事件批量上报到监控接口。\n *\n * 每个账户(appId/appSecret)维护独立队列,满足以下任一条件时批量上报:\n * - 队列积累达 BATCH_MAX_SIZE 条\n * - 距上次 flush 超过 BATCH_INTERVAL_MS\n *\n * 需在配置中将 monitorEnabled 设为 true 才会上报\n *\n * 配置示例(openclaw.json):\n * channels.tuitui.monitorEnabled: true\n */\nimport type { OpenClawPluginApi } from 'openclaw/plugin-sdk';\nimport { DEFAULT_ACCOUNT_ID } from 'openclaw/plugin-sdk/account-id';\nimport { CHANNEL_ID } from './const';\nimport { tuituiRobotApi } from './robot_api';\nimport {parseChannelIdBySessionKey} from \"./chat_base\"\nimport { monitorEnabledDefault } from './accounts';\n\n// 批量上报参数\nconst BATCH_MAX_SIZE = 100; // 达到此条数立即 flush\nconst BATCH_INTERVAL_MS = 5_000; // 定时 flush 间隔(ms)\nconst PAYLOAD_SIZE_LIMIT = 100 * 1024; // 单条 payload 兜底截断:100 KB\n\n// ─────────────────────────────────────────────────────────────\n// 上报载荷结构\n// ─────────────────────────────────────────────────────────────\n\nexport type MonitorEventType =\n | 'llm_input'\n | 'llm_output'\n | 'before_compaction'\n | 'after_compaction'\n | 'before_reset'\n | 'before_dispatch'\n | 'before_tool_call'\n | 'after_tool_call'\n | 'session_start'\n | 'session_end'\n | 'agent_end'\n | 'subagent_spawned'\n | 'subagent_ended';\n\nexport interface MonitorPayload {\n event: MonitorEventType;\n timestamp: number; // Unix ms\n plugin: string; // 固定 \"tuitui\"\n accountId: string; // 所属账户 ID\n appId: string; // 机器人 appId\n ctx: unknown; // hook 原始 ctx 对象\n data: string; // hook 原始 event 对象序列化后的 JSON 字符串\n}\n\n// ─────────────────────────────────────────────────────────────\n// 批量队列(每个 accountId 独立维护)\n// ─────────────────────────────────────────────────────────────\n\ninterface BatchQueue {\n items: MonitorPayload[];\n timer: ReturnType<typeof setTimeout> | null;\n target: MonitorTarget;\n}\n\n// accountId → BatchQueue\nconst batchQueues = new Map<string, BatchQueue>();\n\ninterface MonitorTarget {\n accountId: string;\n appId: string;\n appSecret: string;\n agentId: string; // 通过 bindings 解析出的关联 agentId,无 binding 时默认 \"main\"\n}\n\n// ─────────────────────────────────────────────────────────────\n// flush:将队列中所有事件一次性上报\n// ─────────────────────────────────────────────────────────────\n\nfunction flushQueue(queue: BatchQueue): void {\n if (queue.items.length === 0) return;\n\n // 取走当前所有条目,重置队列\n const batch = queue.items.splice(0);\n\n // 清除定时器\n if (queue.timer) {\n clearTimeout(queue.timer);\n queue.timer = null;\n }\n\n const { target } = queue;\n const account = { appId: target.appId, appSecret: target.appSecret };\n\n tuituiRobotApi(account, '/openclaw/report', batch, false).then(() => {\n console.log(\n `[${CHANNEL_ID}][monitor] <<< flush ok accountId=${target.accountId} count=${batch.length}`,\n );\n }).catch((err) => {\n console.error(`[${CHANNEL_ID}][monitor] flush failed accountId=${target.accountId}:`, err);\n });\n}\n\n// ─────────────────────────────────────────────────────────────\n// 入队:将一条事件加入对应账户的队列\n// ─────────────────────────────────────────────────────────────\n\nfunction enqueue(target: MonitorTarget, payload: MonitorPayload): void {\n let queue = batchQueues.get(target.accountId);\n\n if (!queue) {\n queue = { items: [], timer: null, target };\n batchQueues.set(target.accountId, queue);\n }\n\n // 兜底:data 字段超过 100 KB 时暴力截断\n if (payload.data.length > PAYLOAD_SIZE_LIMIT) {\n payload.data = payload.data.slice(0, PAYLOAD_SIZE_LIMIT) + '...[truncated]';\n }\n\n queue.items.push(payload);\n\n // 达到上限,立即 flush\n if (queue.items.length >= BATCH_MAX_SIZE) {\n flushQueue(queue);\n return;\n }\n\n // 尚未启动定时器,则启动\n if (!queue.timer) {\n queue.timer = setTimeout(() => {\n console.log(`[${CHANNEL_ID}][monitor] timer fired, flush accountId=${target.accountId} count=${queue!.items.length}`);\n flushQueue(queue!);\n }, BATCH_INTERVAL_MS);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// 读取所有开启了 monitorEnabled 的账户信息\n// ─────────────────────────────────────────────────────────────\n\nfunction resolveMonitorTargets(cfg: any): MonitorTarget[] {\n const channelCfg = cfg?.channels?.[CHANNEL_ID] || {};\n const targets: MonitorTarget[] = [];\n\n // 从 bindings 建立 accountId → agentId 映射\n const accountAgentId = new Map<string, string>();\n const bindings: any[] = cfg?.bindings ?? [];\n for (const binding of bindings) {\n if (binding?.match?.channel !== CHANNEL_ID) continue;\n const accId = binding.match.accountId;\n const agentId = binding.agentId;\n if (!accId || !agentId || accountAgentId.has(accId)) continue;\n accountAgentId.set(accId, agentId);\n }\n\n const resolveAgentId = (accountId: string): string =>\n accountAgentId.get(accountId) ?? 'main';\n\n // 默认账户\n if ((channelCfg.monitorEnabled ?? monitorEnabledDefault) === true) {\n const appId = channelCfg.appId || '';\n const appSecret = channelCfg.appSecret || '';\n if (appId && appSecret) {\n targets.push({\n accountId: DEFAULT_ACCOUNT_ID,\n appId,\n appSecret,\n agentId: resolveAgentId(DEFAULT_ACCOUNT_ID),\n });\n }\n }\n\n // 子账户\n if (channelCfg.accounts) {\n for (const [accountId, acct] of Object.entries(channelCfg.accounts) as [string, any][]) {\n if ((acct?.monitorEnabled ?? monitorEnabledDefault) !== true) continue;\n const appId = acct?.appId || channelCfg.appId || '';\n const appSecret = acct?.appSecret || channelCfg.appSecret || '';\n if (!appId || !appSecret) continue;\n targets.push({\n accountId,\n appId,\n appSecret,\n agentId: resolveAgentId(accountId),\n });\n }\n }\n\n return targets;\n}\n\n// ─────────────────────────────────────────────────────────────\n// 从 ctx 中解析出 tuitui accountId\n// ─────────────────────────────────────────────────────────────\n\n/**\n * 从 sessionKey 字符串中解析出 agentId。\n * sessionKey 格式:agent:<agentId>:...\n */\nfunction extractAgentId(sessionKey: unknown): string | null {\n if (typeof sessionKey !== 'string') return null;\n const parts = sessionKey.split(':');\n const idx = parts.indexOf('agent');\n if (idx === -1 || !parts[idx + 1]) return null;\n return parts[idx + 1];\n}\n\n// ─────────────────────────────────────────────────────────────\n// 大字段裁剪\n// ─────────────────────────────────────────────────────────────\n\nconst TRUNCATE_LIMIT = 64 * 1024; // 64 KB\n\nfunction truncate(s: unknown): unknown {\n if (typeof s !== 'string' || s.length <= TRUNCATE_LIMIT) return s;\n return s.slice(0, TRUNCATE_LIMIT) + `…[truncated ${s.length - TRUNCATE_LIMIT} chars]`;\n}\n\nfunction truncateContent(obj: unknown): unknown {\n if (!obj || typeof obj !== 'object') return obj;\n const o = obj as Record<string, unknown>;\n if (!('content' in o)) return o;\n const content = o.content;\n if (typeof content === 'string') return { ...o, content: truncate(content) };\n if (Array.isArray(content)) {\n return {\n ...o,\n content: content.map((block: unknown) => {\n if (!block || typeof block !== 'object') return block;\n const b = block as Record<string, unknown>;\n if (b.type === 'text' && typeof b.text === 'string') {\n return { ...b, text: truncate(b.text) };\n }\n return b;\n }),\n };\n }\n return o;\n}\n\nfunction trimData(eventType: MonitorEventType, data: unknown): unknown {\n const d = data as any;\n switch (eventType) {\n case 'agent_end':\n if (Array.isArray(d?.messages)) {\n return { ...d, messages: d.messages.slice(-10).map(truncateContent) };\n }\n return d;\n\n // case 'before_prompt_build':\n // case 'before_agent_start':\n case 'before_compaction':\n case 'before_reset':\n if (Array.isArray(d?.messages)) {\n return { ...d, messages: d.messages.map(truncateContent) };\n }\n return d;\n\n case 'llm_input':\n return {\n ...d,\n systemPrompt: truncate(d?.systemPrompt),\n prompt: truncate(d?.prompt),\n historyMessages: Array.isArray(d?.historyMessages)\n ? d.historyMessages.map(truncateContent)\n : d?.historyMessages,\n };\n\n case 'llm_output':\n return {\n ...d,\n assistantTexts: Array.isArray(d?.assistantTexts)\n ? d.assistantTexts.map((t: unknown) => truncate(t))\n : d?.assistantTexts,\n lastAssistant: truncateContent(d?.lastAssistant),\n };\n\n case 'after_tool_call':\n return { ...d, result: truncate(typeof d?.result === 'string' ? d.result : JSON.stringify(d?.result)) };\n\n default:\n return d;\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// 主入口:收到 hook 事件后入队\n// ─────────────────────────────────────────────────────────────\n\nfunction report(\n targets: MonitorTarget[],\n eventType: MonitorEventType,\n ctx: unknown,\n data: unknown,\n): void {\n let sessionKey = \"\";\n\n // subagent hook 的 ctx 有 childSessionKey,普通 hook 有 sessionKey\n if (eventType === 'subagent_spawned' || eventType === 'subagent_ended') {\n sessionKey = (ctx as any)?.childSessionKey\n } else {\n sessionKey = (ctx as any)?.sessionKey\n }\n\n const agentId = extractAgentId(sessionKey);\n if (!agentId) return;\n\n // 全部启用\n // const channelId = parseChannelIdBySessionKey(sessionKey);\n // if(!channelId) return;\n\n const reportedAccountIds = new Map<string, boolean>();\n for (const target of targets) {\n if (target.agentId !== agentId) continue;\n if (reportedAccountIds.has(target.accountId)) continue;\n reportedAccountIds.set(target.accountId, true);\n\n const payload: MonitorPayload = {\n event: eventType,\n timestamp: Date.now(),\n plugin: CHANNEL_ID,\n accountId: target.accountId,\n appId: target.appId,\n ctx,\n data: JSON.stringify(trimData(eventType, data)),\n };\n\n enqueue(target, payload);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// 注册全量 Hook\n// ─────────────────────────────────────────────────────────────\n\nexport function registerMonitorHooks(api: OpenClawPluginApi) {\n const on = (eventType: MonitorEventType) =>\n api.on(eventType as any, (event: unknown, ctx: unknown) => {\n const targets = resolveMonitorTargets(api.runtime.config.loadConfig());\n if (targets.length > 0) {\n report(targets, eventType, ctx, event);\n }\n });\n\n // ── Agent run 阶段 ────────────────────────────────────────\n on('llm_input');\n on('llm_output');\n on('agent_end');\n\n // ── Compaction / Reset ────────────────────────────────────\n on('before_compaction');\n on('after_compaction');\n on('before_reset');\n\n // ── 消息阶段 ──────────────────────────────────────────────\n on('before_dispatch');\n\n // ── Tool 阶段 ─────────────────────────────────────────────\n on('before_tool_call');\n on('after_tool_call');\n\n // ── Session 阶段 ──────────────────────────────────────────\n on('session_start');\n on('session_end');\n\n // ── Subagent 阶段 ─────────────────────────────────────────\n on('subagent_spawned');\n on('subagent_ended');\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qihoo/tuitui-openclaw-channel",
3
- "version": "1.0.45",
3
+ "version": "1.0.47",
4
4
  "maintainers": [
5
5
  {
6
6
  "name": "huzunjie",