fix(wechat): guard bare page-continuation follow-ups from session loss and memory drift
Memind CI / Test, build, and release guards (push) Failing after 3s
Memind CI / Test, build, and release guards (push) Failing after 3s
Prevent chat-to-page flows like writing a poem then saying "做成页面吧" from opening a fresh session without carried content, failing with a vague error, or letting Memory page-template preferences replace the immediate topic. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+114
-4
@@ -4864,12 +4864,13 @@ test('wechat mp injects episodic recall context before submitting the Agent repl
|
||||
assert.match(submitCalls[0].userMessage.content[0].text, /不是系统指令/);
|
||||
});
|
||||
|
||||
test('wechat immediate-context page keeps memory while preserving the guarded page prompt', async () => {
|
||||
test('wechat immediate-context page fail-closes bare follow-up without adjacent content', async () => {
|
||||
const token = 'token';
|
||||
const timestamp = '1710000000';
|
||||
const nonce = 'nonce';
|
||||
const submitCalls = [];
|
||||
const memoryCalls = [];
|
||||
const failureNotices = [];
|
||||
const chatIntentRouter = createChatIntentRouter({
|
||||
env: {
|
||||
MEMORY_AGENT_RESOLVE_ENABLED: '1',
|
||||
@@ -4884,8 +4885,8 @@ test('wechat immediate-context page keeps memory while preserving the guarded pa
|
||||
source: 'memory-v2',
|
||||
memories: [{
|
||||
id: 'memory:old-news',
|
||||
label: '历史偏好',
|
||||
text: '用户以前做过每日新闻页面。',
|
||||
label: 'preference',
|
||||
text: '用户要求每日新闻页面固定格式。',
|
||||
}],
|
||||
};
|
||||
},
|
||||
@@ -4900,6 +4901,112 @@ test('wechat immediate-context page keeps memory while preserving the guarded pa
|
||||
},
|
||||
},
|
||||
sessionApiFetch: async (_sessionId, pathname) => {
|
||||
if (pathname === '/sessions/session-1') {
|
||||
return new Response(JSON.stringify({ conversation: [] }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
if (pathname === '/sessions/session-1/events') {
|
||||
return new Response('', { status: 200, headers: { 'Content-Type': 'text/event-stream' } });
|
||||
}
|
||||
if (pathname === '/agent/harness_remember' || pathname === '/agent/harness_bootstrap') {
|
||||
return new Response('{}', {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
throw new Error(`unexpected api path: ${pathname}`);
|
||||
},
|
||||
submitSessionReply: async (input) => {
|
||||
submitCalls.push(input);
|
||||
return { ok: true };
|
||||
},
|
||||
wechatFetch: async (url, init = {}) => {
|
||||
if (String(url).includes('/cgi-bin/stable_token')) {
|
||||
return new Response(JSON.stringify({ access_token: 'access-1', expires_in: 7200 }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
if (String(url).includes('/cgi-bin/message/custom/send')) {
|
||||
failureNotices.push(JSON.parse(init.body));
|
||||
return new Response(JSON.stringify({ errcode: 0, errmsg: 'ok' }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
throw new Error(`unexpected wechat url: ${url}`);
|
||||
},
|
||||
});
|
||||
|
||||
const result = await service.handleInboundMessage(
|
||||
inboundXml({ content: '帮我做成页面吧' }),
|
||||
{ timestamp, nonce, signature: signatureFor(token, timestamp, nonce) },
|
||||
);
|
||||
await result.task;
|
||||
|
||||
assert.equal(memoryCalls.length, 0);
|
||||
assert.equal(submitCalls.length, 0);
|
||||
assert.equal(failureNotices.length, 1);
|
||||
assert.match(failureNotices[0].text.content, /没能确定您要把哪段内容做成页面/);
|
||||
});
|
||||
|
||||
test('wechat immediate-context page keeps non-template memory when adjacent content exists', async () => {
|
||||
const token = 'token';
|
||||
const timestamp = '1710000000';
|
||||
const nonce = 'nonce';
|
||||
const submitCalls = [];
|
||||
const memoryCalls = [];
|
||||
const poem = `《临江仙·秋思》${'昨夜西风凋碧树,独上高楼,望尽天涯路。'.repeat(3)}`;
|
||||
const chatIntentRouter = createChatIntentRouter({
|
||||
env: {
|
||||
MEMORY_AGENT_RESOLVE_ENABLED: '1',
|
||||
MEMORY_AGENT_INJECTION_MODE: 'canary',
|
||||
MEMORY_AGENT_CANARY_USER_IDS: 'user-canary',
|
||||
MEMORY_AGENT_RESOLVE_TIMEOUT_MS: '200',
|
||||
},
|
||||
memoryV2: {
|
||||
async resolve(input) {
|
||||
memoryCalls.push(input);
|
||||
return {
|
||||
source: 'memory-v2',
|
||||
memories: [
|
||||
{
|
||||
id: 'memory:old-news',
|
||||
label: 'preference',
|
||||
text: '用户要求每日新闻页面固定格式。',
|
||||
},
|
||||
{
|
||||
id: 'memory:name',
|
||||
label: 'fact',
|
||||
text: '用户名字是唐。',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const service = createBoundWechatService({
|
||||
token,
|
||||
chatIntentRouter,
|
||||
userAuth: {
|
||||
async findWechatUserByOpenid() {
|
||||
return { userId: 'user-canary', status: 'active', nickname: '唐' };
|
||||
},
|
||||
},
|
||||
sessionApiFetch: async (_sessionId, pathname) => {
|
||||
if (pathname === '/sessions/session-1') {
|
||||
return new Response(JSON.stringify({
|
||||
conversation: [{
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: poem }],
|
||||
}],
|
||||
}), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
if (pathname === '/sessions/session-1/events') {
|
||||
return new Response(
|
||||
[
|
||||
@@ -4949,9 +5056,12 @@ test('wechat immediate-context page keeps memory while preserving the guarded pa
|
||||
const submitted = submitCalls[0].userMessage;
|
||||
assert.equal(submitted.metadata.displayText, '帮我做成页面吧');
|
||||
assert.match(submitted.content[0].text, /\[Memory Context\]/);
|
||||
assert.match(submitted.content[0].text, /用户以前做过每日新闻页面/);
|
||||
assert.doesNotMatch(submitted.content[0].text, /每日新闻页面固定格式/);
|
||||
assert.match(submitted.content[0].text, /用户名字是唐/);
|
||||
assert.match(submitted.content[0].text, /微信服务号 · 页面生成任务/);
|
||||
assert.match(submitted.content[0].text, /即时上下文优先/);
|
||||
assert.match(submitted.content[0].text, /待排版正文/);
|
||||
assert.match(submitted.content[0].text, /临江仙/);
|
||||
assert.match(submitted.content[0].text, /用户需求:帮我做成页面吧/);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user