feat(memory): add gated agent recall and lifecycle controls
This commit is contained in:
@@ -1078,6 +1078,83 @@ test('createChatIntentRouter timeout fallback prefers agent even when policy req
|
||||
assert.equal(result.source, 'fallback');
|
||||
});
|
||||
|
||||
test('agent memory shadow resolve is independently gated and never marked for injection', async () => {
|
||||
const calls = [];
|
||||
const router = createChatIntentRouter({
|
||||
env: {
|
||||
MEMORY_AGENT_RESOLVE_ENABLED: '1',
|
||||
MEMORY_AGENT_INJECTION_MODE: 'shadow',
|
||||
MEMORY_AGENT_RESOLVE_LIMIT: '3',
|
||||
MEMORY_AGENT_RESOLVE_TIMEOUT_MS: '100',
|
||||
},
|
||||
memoryV2: {
|
||||
async resolve(input) {
|
||||
calls.push(input);
|
||||
return { source: 'legacy-conversation-memory', memories: [{ label: 'preference', text: '喜欢完整方案' }] };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const result = await router.resolveAgentMemoryContext({
|
||||
userId: 'u1',
|
||||
sessionId: 's1',
|
||||
text: '帮我设计一个商城',
|
||||
});
|
||||
|
||||
assert.equal(result.mode, 'shadow');
|
||||
assert.equal(result.injectionEnabled, false);
|
||||
assert.equal(result.skipped, false);
|
||||
assert.equal(result.memories.length, 1);
|
||||
assert.deepEqual(calls[0], { userId: 'u1', sessionId: 's1', query: '帮我设计一个商城', limit: 3 });
|
||||
});
|
||||
|
||||
test('agent memory canary injects only for configured user ids', async () => {
|
||||
const router = createChatIntentRouter({
|
||||
env: {
|
||||
MEMORY_AGENT_RESOLVE_ENABLED: '1',
|
||||
MEMORY_AGENT_INJECTION_MODE: 'canary',
|
||||
MEMORY_AGENT_CANARY_USER_IDS: 'user-canary, user-other',
|
||||
},
|
||||
memoryV2: {
|
||||
async resolve() {
|
||||
return { memories: [{ label: 'goal', text: '当前项目是 TKMind' }] };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const canary = await router.resolveAgentMemoryContext({ userId: 'user-canary', text: '继续项目' });
|
||||
const control = await router.resolveAgentMemoryContext({ userId: 'user-control', text: '继续项目' });
|
||||
assert.equal(canary.injectionEnabled, true);
|
||||
assert.equal(control.injectionEnabled, false);
|
||||
assert.equal(canary.memories.length, 1);
|
||||
assert.equal(control.memories.length, 1);
|
||||
});
|
||||
|
||||
test('active agent memory context is hidden from displayText but available to orchestration envelope', () => {
|
||||
const enriched = applyAgentOrchestrationToUserMessage(
|
||||
{
|
||||
role: 'user',
|
||||
content: [{ type: 'text', text: '帮我设计一个商城' }],
|
||||
},
|
||||
{
|
||||
route: CHAT_INTENT_ROUTE.AGENT,
|
||||
reason: '任务执行',
|
||||
agentBrief: '',
|
||||
suggestedSkill: null,
|
||||
},
|
||||
{
|
||||
memoryContext: {
|
||||
injectionEnabled: true,
|
||||
memories: [{ label: 'preference', text: '用户喜欢完整方案' }],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(enriched.metadata.displayText, '帮我设计一个商城');
|
||||
assert.match(enriched.content[0].text, /Memory Context/);
|
||||
assert.match(enriched.content[0].text, /用户喜欢完整方案/);
|
||||
});
|
||||
|
||||
test('logRouterDecisionShadow emits payload only in shadow mode', () => {
|
||||
const previous = process.env.MEMIND_ROUTER_NORMALIZED_DECISION;
|
||||
const lines = [];
|
||||
|
||||
Reference in New Issue
Block a user