From d6f404a20f847a20ea40f1ccdb6718ff88bb0cb5 Mon Sep 17 00:00:00 2001 From: OpenClaw Assistant Date: Mon, 23 Feb 2026 08:28:05 +0000 Subject: [PATCH] Enhance vk-bridge with LP settings sync and event filters --- skills/dist/vk-bridge.skill | Bin 3605 -> 4494 bytes skills/vk-bridge/SKILL.md | 8 ++- skills/vk-bridge/references/.env.example | 4 ++ .../vk-bridge/scripts/vk-longpoll-bridge.mjs | 64 +++++++++++++++++- 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/skills/dist/vk-bridge.skill b/skills/dist/vk-bridge.skill index 72c04cf19987ac36ed704ba3c6ec7aac3b8b0313..3148af159fab5970aa1cadb9b7245e0360e4ffa2 100644 GIT binary patch delta 4336 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 J!P5TMLC2bKYZ-H_iWDUX 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 wcmBVh{Ewdet>^!pkJ0v&e`Q7D&VQ@$|696<2B x.trim()) + .filter(Boolean); +} + const { env } = parseArgs(); loadEnv(env); @@ -35,12 +43,21 @@ const CFG = { wait: Number(process.env.VK_WAIT || 25), bridgeUrl: process.env.OPENCLAW_BRIDGE_URL || '', bridgeTimeout: Number(process.env.OPENCLAW_BRIDGE_TIMEOUT_MS || 45000), + allowedEvents: new Set(parseCsv(process.env.VK_ALLOWED_EVENTS, ['message_new'])), + syncSettings: process.env.VK_SYNC_LONGPOLL_SETTINGS === '1', }; if (!CFG.groupId || !CFG.token || !CFG.bridgeUrl) { console.error('Missing required env: VK_GROUP_ID, VK_TOKEN, OPENCLAW_BRIDGE_URL'); process.exit(1); } +if (CFG.apiVersion !== '5.199') { + console.warn(`[vk-bridge] warning: VK_API_VERSION=${CFG.apiVersion}; recommended 5.199`); +} +if (CFG.wait > 90 || CFG.wait < 1) { + console.error('VK_WAIT must be between 1 and 90'); + process.exit(1); +} const seen = new Set(); @@ -50,7 +67,7 @@ function vkApi(method, params = {}) { access_token: CFG.token, v: CFG.apiVersion, }); - return fetch(`https://api.vk.com/method/${method}?${qs}`).then(r => r.json()); + return fetch(`https://api.vk.com/method/${method}?${qs}`).then((r) => r.json()); } async function getLongPollServer() { @@ -59,6 +76,40 @@ async function getLongPollServer() { return data.response; } +async function getLongPollSettings() { + const data = await vkApi('groups.getLongPollSettings', { group_id: CFG.groupId }); + if (data.error) throw new Error(`groups.getLongPollSettings: ${JSON.stringify(data.error)}`); + return data.response; +} + +async function setLongPollSettings(params) { + const data = await vkApi('groups.setLongPollSettings', { + group_id: CFG.groupId, + ...params, + }); + if (data.error) throw new Error(`groups.setLongPollSettings: ${JSON.stringify(data.error)}`); + return data.response; +} + +async function ensureLongPollSettings() { + const settings = await getLongPollSettings(); + const updates = { enabled: 1, api_version: CFG.apiVersion }; + + for (const eventType of CFG.allowedEvents) { + const current = settings?.events?.[eventType]; + if (current !== 1) updates[eventType] = 1; + } + + const needApply = Object.keys(updates).length > 2 || settings?.is_enabled !== 1; + if (!needApply) { + console.log('[vk-bridge] long poll settings already OK'); + return; + } + + await setLongPollSettings(updates); + console.log('[vk-bridge] long poll settings synced'); +} + async function callBridge(evt) { const msg = evt?.object?.message; if (!msg) return { silent: true }; @@ -66,6 +117,8 @@ async function callBridge(evt) { const body = { source: 'vk', group_id: CFG.groupId, + event_type: evt?.type || null, + event_id: evt?.event_id || null, user_id: msg.from_id, peer_id: msg.peer_id, text: msg.text || '', @@ -102,6 +155,7 @@ async function sendVk(peerId, text) { } function isInboundUserMessage(evt) { + if (!CFG.allowedEvents.has(evt?.type)) return false; if (evt?.type !== 'message_new') return false; const msg = evt?.object?.message; if (!msg) return false; @@ -111,6 +165,14 @@ function isInboundUserMessage(evt) { } async function main() { + if (CFG.syncSettings) { + try { + await ensureLongPollSettings(); + } catch (e) { + console.error('[vk-bridge] failed to sync long poll settings:', e.message); + } + } + let lp = await getLongPollServer(); let ts = lp.ts;