Files
memind/scripts/mock-memory-v2-services.mjs
T
2026-07-03 09:46:03 +08:00

196 lines
5.4 KiB
JavaScript

#!/usr/bin/env node
import http from 'node:http';
import { URL } from 'node:url';
function readJson(req) {
return new Promise((resolve, reject) => {
let body = '';
req.setEncoding('utf8');
req.on('data', (chunk) => {
body += chunk;
});
req.on('end', () => {
if (!body.trim()) {
resolve({});
return;
}
try {
resolve(JSON.parse(body));
} catch (err) {
reject(err);
}
});
req.on('error', reject);
});
}
function sendJson(res, statusCode, payload) {
res.writeHead(statusCode, { 'content-type': 'application/json; charset=utf-8' });
res.end(JSON.stringify(payload));
}
export function createMockMemoryV2Service() {
const state = {
mem0: {
writes: [],
compacts: [],
},
letta: {
messages: [],
compacts: [],
},
langgraph: {
resolves: [],
},
};
function reset() {
state.mem0.writes.length = 0;
state.mem0.compacts.length = 0;
state.letta.messages.length = 0;
state.letta.compacts.length = 0;
state.langgraph.resolves.length = 0;
}
async function handle(req, res) {
const url = new URL(req.url, 'http://127.0.0.1');
const pathname = url.pathname;
if (req.method === 'GET' && pathname === '/health') {
sendJson(res, 200, { ok: true, service: 'mock-memory-v2-services' });
return;
}
if (req.method === 'POST' && pathname === '/__admin/reset') {
reset();
sendJson(res, 200, { ok: true });
return;
}
if (req.method === 'GET' && pathname === '/__admin/state') {
sendJson(res, 200, {
ok: true,
state,
});
return;
}
if (req.method === 'POST' && pathname === '/mem0/v1/memories') {
const body = await readJson(req);
state.mem0.writes.push(body);
sendJson(res, 200, {
saved: 1,
analyzed: 1,
memory_count: Array.isArray(body.messages) ? body.messages.length : 0,
});
return;
}
if (req.method === 'POST' && pathname === '/mem0/v1/memories/compact') {
const body = await readJson(req);
state.mem0.compacts.push(body);
sendJson(res, 200, {
analyzed: 1,
memory_count: state.mem0.writes.filter((item) => item.user_id === body.user_id).length,
});
return;
}
if (req.method === 'POST' && /^\/letta\/v1\/agents\/[^/]+\/messages$/.test(pathname)) {
const body = await readJson(req);
const agentId = pathname.split('/')[4];
state.letta.messages.push({ agentId, ...body });
sendJson(res, 200, {
saved: 1,
analyzed: 0,
memory_count: Array.isArray(body.messages) ? body.messages.length : 0,
});
return;
}
if (req.method === 'POST' && /^\/letta\/v1\/agents\/[^/]+\/memory\/compact$/.test(pathname)) {
const body = await readJson(req);
const agentId = pathname.split('/')[4];
state.letta.compacts.push({ agentId, ...body });
sendJson(res, 200, {
analyzed: 1,
memory_count: state.letta.messages.filter((item) => item.user_id === body.user_id).length,
});
return;
}
if (req.method === 'POST' && /^\/letta\/v1\/agents\/[^/]+\/memory$/.test(pathname)) {
const body = await readJson(req);
const agentId = pathname.split('/')[4];
const messages = state.letta.messages
.filter((item) => item.agentId === agentId && item.user_id === body.user_id)
.flatMap((item) => Array.isArray(item.messages) ? item.messages : [])
.map((item, index) => ({
id: `letta-${index + 1}`,
label: 'lifecycle',
text: String(item.text ?? item.content ?? '').trim() || `letta-memory-${index + 1}`,
}))
.filter((item) => item.text);
sendJson(res, 200, {
memories: messages.length ? messages : ['letta lifecycle memory'],
activeGoals: ['memory-v2'],
});
return;
}
if (req.method === 'POST' && pathname === '/langgraph/memory/resolve') {
const body = await readJson(req);
state.langgraph.resolves.push(body);
sendJson(res, 200, {
memories: [{
id: 'langgraph-1',
label: 'policy',
text: `langgraph route for ${body.user_id ?? 'unknown-user'}`,
}],
activeGoals: ['route-memory'],
behaviorSummary: null,
});
return;
}
sendJson(res, 404, { ok: false, message: 'not found' });
}
return {
state,
reset,
createServer() {
return http.createServer((req, res) => {
Promise.resolve(handle(req, res)).catch((err) => {
sendJson(res, 500, {
ok: false,
message: err instanceof Error ? err.message : String(err),
});
});
});
},
};
}
export async function startMockMemoryV2Service({
port = Number(process.env.MEMORY_V2_MOCK_PORT ?? 19400) || 19400,
host = process.env.MEMORY_V2_MOCK_HOST ?? '127.0.0.1',
stdout = process.stdout,
} = {}) {
const service = createMockMemoryV2Service();
const server = service.createServer();
await new Promise((resolve, reject) => {
server.once('error', reject);
server.listen(port, host, resolve);
});
stdout.write(`${JSON.stringify({ ok: true, host, port }, null, 2)}\n`);
return { service, server, host, port };
}
if (import.meta.url === `file://${process.argv[1]}`) {
startMockMemoryV2Service().catch((err) => {
console.error(err instanceof Error ? err.message : err);
process.exitCode = 1;
});
}