Files
memind/memory-v2-letta.test.mjs
2026-07-03 09:46:03 +08:00

157 lines
5.1 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { inspectMemoryV2Backend } from './memory-v2-backend-contract.mjs';
import { createLettaHttpClient, createLettaMemoryBackend } from './memory-v2-letta.mjs';
test('letta backend is disabled by default and passes contract gate', async () => {
const backend = createLettaMemoryBackend();
const report = inspectMemoryV2Backend(backend);
assert.equal(backend.name, 'letta');
assert.equal(backend.category, 'lifecycle');
assert.equal(backend.role, 'long-short-term-memory-os');
assert.equal(backend.flag, 'MEMORY_LETTA_ENABLED');
assert.equal(backend.isAvailable(), false);
assert.equal(backend.getUnavailableReason(), 'not_configured');
assert.equal(report.ok, true);
assert.deepEqual(await backend.resolve({}), {
memories: [],
semanticMemories: [],
behaviorSummary: null,
activeGoals: [],
});
assert.deepEqual(await backend.write({}), { saved: 0, analyzed: 0, memories: 0 });
assert.deepEqual(await backend.compact({}), { analyzed: 0, memories: 0 });
});
test('letta backend reports api key and client configuration reasons', () => {
assert.equal(
createLettaMemoryBackend({ enabled: true }).getUnavailableReason(),
'api_key_not_configured',
);
assert.equal(
createLettaMemoryBackend({
enabled: true,
apiKey: 'secret',
projectId: 'memind_project',
agentId: 'agent_1',
}).getUnavailableReason(),
'client_not_configured',
);
});
test('letta backend validates project and agent ids', () => {
assert.throws(
() => createLettaMemoryBackend({ projectId: 'bad project id' }),
/Invalid MEMORY_LETTA_PROJECT_ID/,
);
assert.throws(
() => createLettaMemoryBackend({ agentId: 'bad agent id' }),
/Invalid MEMORY_LETTA_AGENT_ID/,
);
});
test('letta backend delegates only when explicitly wired with a full client', async () => {
const calls = [];
const backend = createLettaMemoryBackend({
enabled: true,
apiKey: 'secret',
projectId: 'memind_project',
agentId: 'agent_1',
client: {
async resolve(input) {
calls.push(['resolve', input]);
return {
memories: [{ id: 1, type: 'goal', content: 'keep long-term context tidy' }],
activeGoals: ['memory-v2'],
};
},
async write(input) {
calls.push(['write', input]);
return { saved: 2, analyzed: 1, memories: 1 };
},
async compact(input) {
calls.push(['compact', input]);
return { analyzed: 3, memories: 2 };
},
},
});
assert.equal(backend.isAvailable(), true);
assert.equal(backend.getUnavailableReason(), null);
assert.deepEqual(await backend.resolve({ userId: 'u1' }), {
memories: [{
id: '1',
label: 'goal',
text: 'keep long-term context tidy',
createdAt: null,
}],
semanticMemories: ['keep long-term context tidy'],
behaviorSummary: null,
activeGoals: ['memory-v2'],
profile: null,
});
assert.deepEqual(await backend.write({ userId: 'u1' }), {
saved: 2,
analyzed: 1,
memories: 1,
});
assert.deepEqual(await backend.compact({ userId: 'u1' }), {
analyzed: 3,
memories: 2,
});
assert.deepEqual(calls.map(([name, input]) => [name, input.projectId, input.agentId]), [
['resolve', 'memind_project', 'agent_1'],
['write', 'memind_project', 'agent_1'],
['compact', 'memind_project', 'agent_1'],
]);
});
test('letta HTTP client resolves, writes, and compacts with agent-scoped paths', async () => {
const calls = [];
const client = createLettaHttpClient({
apiKey: 'secret',
baseUrl: 'https://letta.local',
agentId: 'agent_1',
projectId: 'memind_project',
modelProviderKeyId: 'key_letta',
model: 'gpt-4.1',
modelApiType: 'chat',
async fetchImpl(url, options) {
calls.push({ url, headers: options.headers, body: options.body ? JSON.parse(options.body) : null });
return {
ok: true,
async json() {
if (url.endsWith('/memory')) return { memories: ['letta memory'] };
return { saved: 1, analyzed: 1, memories: 1 };
},
};
},
});
assert.deepEqual(await client.resolve({ userId: 'u1', query: 'hello' }), {
memories: ['letta memory'],
});
assert.deepEqual(await client.write({ userId: 'u1', sessionId: 's1', messages: [] }), {
saved: 1,
analyzed: 1,
memories: 1,
});
assert.deepEqual(await client.compact({ userId: 'u1' }), {
analyzed: 1,
memories: 1,
});
assert.deepEqual(calls.map((call) => call.url), [
'https://letta.local/v1/agents/agent_1/memory',
'https://letta.local/v1/agents/agent_1/messages',
'https://letta.local/v1/agents/agent_1/memory/compact',
]);
assert.equal(calls[0].headers.authorization, 'Bearer secret');
assert.equal(calls[0].body.project_id, 'memind_project');
assert.equal(calls[0].body.model_provider_key_id, 'key_letta');
assert.equal(calls[0].body.model, 'gpt-4.1');
assert.equal(calls[0].body.model_api_type, 'chat');
assert.equal(calls[1].body.model_provider_key_id, 'key_letta');
assert.equal(calls[2].body.model_api_type, 'chat');
});