From fa20f735a5e28e1de70d7be000f74c378865d9fb Mon Sep 17 00:00:00 2001 From: john Date: Mon, 31 Aug 2026 10:16:03 +0800 Subject: [PATCH] Skip Cursor Chat Bridge for WeChat MP and page.generate sessions. WeChat Goose turns always include tools, which the bridge PoC rejects with HTTP 501; keep Kimi/DeepSeek on the session while Cursor handles page execution separately. Co-authored-by: Cursor --- tkmind-proxy.mjs | 4 ++- wechat-cursor-executor-policy.mjs | 9 ++++++ wechat-cursor-executor-policy.test.mjs | 44 ++++++++++++++++++++++++++ wechat-mp.mjs | 14 +++++--- 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/tkmind-proxy.mjs b/tkmind-proxy.mjs index 8716bf4..43e4e70 100644 --- a/tkmind-proxy.mjs +++ b/tkmind-proxy.mjs @@ -1602,7 +1602,7 @@ export function createTkmindProxy({ } } - async function applySessionLlmProvider(sessionId, { userId = null } = {}) { + async function applySessionLlmProvider(sessionId, { userId = null, channel = 'h5', intentKind = '' } = {}) { if (!llmProviderService || !sessionId) return null; try { const target = await resolveTarget(sessionId); @@ -1617,6 +1617,8 @@ export function createTkmindProxy({ if ( resolveCursorChatBridgeEligible({ user: { userId }, + channel, + intentKind, policy: cursorPolicy, }) && typeof llmProviderService.applyCursorChatBridgeForSession === 'function' diff --git a/wechat-cursor-executor-policy.mjs b/wechat-cursor-executor-policy.mjs index 65bd2d4..f25df71 100644 --- a/wechat-cursor-executor-policy.mjs +++ b/wechat-cursor-executor-policy.mjs @@ -30,6 +30,8 @@ export function resolveCursorChannelEligible({ export function resolveCursorChatBridgeEligible({ user = null, userId = null, + channel = '', + intentKind = '', policy = null, env = process.env, } = {}) { @@ -37,6 +39,13 @@ export function resolveCursorChatBridgeEligible({ const subject = user ?? { userId }; if (!isUserAllowedByWechatCursorPolicy(subject, policy)) return false; if (!isCursorFeatureEnabled(policy, CURSOR_CHANNEL_FEATURES.CHAT_BRIDGE)) return false; + const normalizedChannel = String(channel ?? '').trim().toLowerCase(); + // WeChat Goose sessions always carry tools; the bridge PoC rejects tool calls. + if (normalizedChannel === CURSOR_EXECUTOR_CHANNEL.WECHAT_MP) return false; + if (String(intentKind ?? '').trim() === 'page.generate') return false; + if (!isChannelAllowedByCursorPolicy(normalizedChannel || CURSOR_EXECUTOR_CHANNEL.H5, policy)) { + return false; + } const bridgeEnvEnabled = String(env?.MEMIND_CURSOR_CHAT_BRIDGE_ENABLED ?? '').trim(); if (!['1', 'true', 'yes', 'on'].includes(bridgeEnvEnabled.toLowerCase())) return false; return true; diff --git a/wechat-cursor-executor-policy.test.mjs b/wechat-cursor-executor-policy.test.mjs index 891f512..04b98c0 100644 --- a/wechat-cursor-executor-policy.test.mjs +++ b/wechat-cursor-executor-policy.test.mjs @@ -9,6 +9,7 @@ import { import { CURSOR_EXECUTOR_CHANNEL, resolveCursorChannelEligible, + resolveCursorChatBridgeEligible, resolveCursorScheduledTaskEligible, resolveWechatCursorExecutorEligible, } from './wechat-cursor-executor-policy.mjs'; @@ -178,6 +179,49 @@ test('H5 channel respects channelAllowlist', async () => { ); }); +test('resolveCursorChatBridgeEligible is disabled for WeChat MP and page.generate', async () => { + const pool = createMemoryPool(); + const service = createWechatCursorExecutorAdminConfigService(pool); + await service.updateAdminConfig({ + enabled: true, + userAllowlist: ['john-uuid'], + features: { + pageGenerate: { enabled: true }, + chatBridge: { enabled: true }, + }, + }, { updatedBy: 'admin-1' }); + const policy = await service.getEffectivePolicy('john-uuid', { userId: 'john-uuid' }); + assert.equal( + resolveCursorChatBridgeEligible({ + user: { userId: 'john-uuid' }, + channel: CURSOR_EXECUTOR_CHANNEL.WECHAT_MP, + policy, + env: { MEMIND_CURSOR_CHAT_BRIDGE_ENABLED: '1' }, + }), + false, + ); + assert.equal( + resolveCursorChatBridgeEligible({ + user: { userId: 'john-uuid' }, + channel: CURSOR_EXECUTOR_CHANNEL.H5, + intentKind: 'page.generate', + policy, + env: { MEMIND_CURSOR_CHAT_BRIDGE_ENABLED: '1' }, + }), + false, + ); + assert.equal( + resolveCursorChatBridgeEligible({ + user: { userId: 'john-uuid' }, + channel: CURSOR_EXECUTOR_CHANNEL.H5, + intentKind: 'chat.general', + policy, + env: { MEMIND_CURSOR_CHAT_BRIDGE_ENABLED: '1' }, + }), + true, + ); +}); + test('isChannelAllowedByCursorPolicy defaults to both channels', () => { const policy = { channelAllowlist: ['h5', 'wechat_mp'] }; assert.equal(isChannelAllowedByCursorPolicy('h5', policy), true); diff --git a/wechat-mp.mjs b/wechat-mp.mjs index 150763c..a3d9c61 100644 --- a/wechat-mp.mjs +++ b/wechat-mp.mjs @@ -2179,9 +2179,13 @@ export function createWechatMpService({ throw notifyFailure ? markWechatUserNotified(error) : error; }; - const ensureSessionProvider = async (sessionId, userId = null) => { + const ensureSessionProvider = async (sessionId, userId = null, { intentKind = '' } = {}) => { if (!applySessionLlmProvider || !sessionId) return; - const applied = await applySessionLlmProvider(sessionId, { userId }); + const applied = await applySessionLlmProvider(sessionId, { + userId, + channel: 'wechat_mp', + intentKind, + }); if (applied && applied.ok === false) { throw new Error(applied.message || '专属 Agent Provider 未配置'); } @@ -2823,7 +2827,7 @@ export function createWechatMpService({ }); let sessionId = route.sessionId; let carriedSessionContent = String(route.carriedSessionContent ?? '').trim(); - await ensureSessionProvider(sessionId, user.userId); + await ensureSessionProvider(sessionId, user.userId, { intentKind: wechatIntent.kind }); if (wechatIntent.kind === 'session.reset') { await sendCustomerServiceText( inbound.fromUserName, @@ -2850,7 +2854,7 @@ export function createWechatMpService({ if (pollutionRotation.carriedSessionContent) { carriedSessionContent = pollutionRotation.carriedSessionContent; } - await ensureSessionProvider(sessionId, user.userId); + await ensureSessionProvider(sessionId, user.userId, { intentKind: wechatIntent.kind }); await rememberWechatUserContext(sessionId, user, { forceBootstrap: true }); } if ( @@ -3392,7 +3396,7 @@ export function createWechatMpService({ userContext: user, }); sessionId = route.sessionId; - await ensureSessionProvider(sessionId, user.userId); + await ensureSessionProvider(sessionId, user.userId, { intentKind: wechatIntent.kind }); await rememberWechatUserContext(sessionId, user, { forceBootstrap: route.isNewSession }); if (historicalImageError) { prepareWechatIntentForHistoricalImageRetry(intent, {