Skip Cursor Chat Bridge for WeChat MP and page.generate sessions.
Memind CI / Test, build, and release guards (push) Failing after 5m45s

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 <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-31 10:16:03 +08:00
parent 3688d732c0
commit fa20f735a5
4 changed files with 65 additions and 6 deletions
+3 -1
View File
@@ -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; if (!llmProviderService || !sessionId) return null;
try { try {
const target = await resolveTarget(sessionId); const target = await resolveTarget(sessionId);
@@ -1617,6 +1617,8 @@ export function createTkmindProxy({
if ( if (
resolveCursorChatBridgeEligible({ resolveCursorChatBridgeEligible({
user: { userId }, user: { userId },
channel,
intentKind,
policy: cursorPolicy, policy: cursorPolicy,
}) })
&& typeof llmProviderService.applyCursorChatBridgeForSession === 'function' && typeof llmProviderService.applyCursorChatBridgeForSession === 'function'
+9
View File
@@ -30,6 +30,8 @@ export function resolveCursorChannelEligible({
export function resolveCursorChatBridgeEligible({ export function resolveCursorChatBridgeEligible({
user = null, user = null,
userId = null, userId = null,
channel = '',
intentKind = '',
policy = null, policy = null,
env = process.env, env = process.env,
} = {}) { } = {}) {
@@ -37,6 +39,13 @@ export function resolveCursorChatBridgeEligible({
const subject = user ?? { userId }; const subject = user ?? { userId };
if (!isUserAllowedByWechatCursorPolicy(subject, policy)) return false; if (!isUserAllowedByWechatCursorPolicy(subject, policy)) return false;
if (!isCursorFeatureEnabled(policy, CURSOR_CHANNEL_FEATURES.CHAT_BRIDGE)) 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(); const bridgeEnvEnabled = String(env?.MEMIND_CURSOR_CHAT_BRIDGE_ENABLED ?? '').trim();
if (!['1', 'true', 'yes', 'on'].includes(bridgeEnvEnabled.toLowerCase())) return false; if (!['1', 'true', 'yes', 'on'].includes(bridgeEnvEnabled.toLowerCase())) return false;
return true; return true;
+44
View File
@@ -9,6 +9,7 @@ import {
import { import {
CURSOR_EXECUTOR_CHANNEL, CURSOR_EXECUTOR_CHANNEL,
resolveCursorChannelEligible, resolveCursorChannelEligible,
resolveCursorChatBridgeEligible,
resolveCursorScheduledTaskEligible, resolveCursorScheduledTaskEligible,
resolveWechatCursorExecutorEligible, resolveWechatCursorExecutorEligible,
} from './wechat-cursor-executor-policy.mjs'; } 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', () => { test('isChannelAllowedByCursorPolicy defaults to both channels', () => {
const policy = { channelAllowlist: ['h5', 'wechat_mp'] }; const policy = { channelAllowlist: ['h5', 'wechat_mp'] };
assert.equal(isChannelAllowedByCursorPolicy('h5', policy), true); assert.equal(isChannelAllowedByCursorPolicy('h5', policy), true);
+9 -5
View File
@@ -2179,9 +2179,13 @@ export function createWechatMpService({
throw notifyFailure ? markWechatUserNotified(error) : error; throw notifyFailure ? markWechatUserNotified(error) : error;
}; };
const ensureSessionProvider = async (sessionId, userId = null) => { const ensureSessionProvider = async (sessionId, userId = null, { intentKind = '' } = {}) => {
if (!applySessionLlmProvider || !sessionId) return; 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) { if (applied && applied.ok === false) {
throw new Error(applied.message || '专属 Agent Provider 未配置'); throw new Error(applied.message || '专属 Agent Provider 未配置');
} }
@@ -2823,7 +2827,7 @@ export function createWechatMpService({
}); });
let sessionId = route.sessionId; let sessionId = route.sessionId;
let carriedSessionContent = String(route.carriedSessionContent ?? '').trim(); let carriedSessionContent = String(route.carriedSessionContent ?? '').trim();
await ensureSessionProvider(sessionId, user.userId); await ensureSessionProvider(sessionId, user.userId, { intentKind: wechatIntent.kind });
if (wechatIntent.kind === 'session.reset') { if (wechatIntent.kind === 'session.reset') {
await sendCustomerServiceText( await sendCustomerServiceText(
inbound.fromUserName, inbound.fromUserName,
@@ -2850,7 +2854,7 @@ export function createWechatMpService({
if (pollutionRotation.carriedSessionContent) { if (pollutionRotation.carriedSessionContent) {
carriedSessionContent = pollutionRotation.carriedSessionContent; carriedSessionContent = pollutionRotation.carriedSessionContent;
} }
await ensureSessionProvider(sessionId, user.userId); await ensureSessionProvider(sessionId, user.userId, { intentKind: wechatIntent.kind });
await rememberWechatUserContext(sessionId, user, { forceBootstrap: true }); await rememberWechatUserContext(sessionId, user, { forceBootstrap: true });
} }
if ( if (
@@ -3392,7 +3396,7 @@ export function createWechatMpService({
userContext: user, userContext: user,
}); });
sessionId = route.sessionId; sessionId = route.sessionId;
await ensureSessionProvider(sessionId, user.userId); await ensureSessionProvider(sessionId, user.userId, { intentKind: wechatIntent.kind });
await rememberWechatUserContext(sessionId, user, { forceBootstrap: route.isNewSession }); await rememberWechatUserContext(sessionId, user, { forceBootstrap: route.isNewSession });
if (historicalImageError) { if (historicalImageError) {
prepareWechatIntentForHistoricalImageRetry(intent, { prepareWechatIntentForHistoricalImageRetry(intent, {