157 lines
5.1 KiB
JavaScript
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');
|
|
});
|