Merge Memory V2 runtime facade
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
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');
|
||||
});
|
||||
Reference in New Issue
Block a user