Files
nexusAI/packages/orchestration-service/src/services/memory.js
T

254 lines
9.2 KiB
JavaScript

const { getEnv, SERVICES, EPISODIC } = require('@nexusai/shared');
const BASE_URL = getEnv('MEMORY_SERVICE_URL', SERVICES.MEMORY_URL);
//function to get session by external id, returns null if not found, throws error for other issues
async function getSessionByExternalId(externalId) {
const res = await fetch(`${BASE_URL}/sessions/by-external/${externalId}`);
if (res.status === 404) return null; // Not found or bad request
if (!res.ok) throw new Error(`Memory service error: ${res.status} ${res.statusText}`); // Other errors
return res.json();
}
// create a new session with an external ID, returns the created session
async function createSession(externalId) {
const res = await fetch(`${BASE_URL}/sessions`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ externalId })
});
if (!res.ok) throw new Error(`Failed to create sessions: ${res.status} ${res.statusText}`);
return res.json();
}
async function getRecentEpisodes(sessionId, limit = EPISODIC.DEFAULT_SESSIONS_LIMIT) {
const res = await fetch(`${BASE_URL}/sessions/${sessionId}/episodes?limit=${limit}`);
if (!res.ok) throw new Error(`Failed to fetch episodes: ${res.status} ${res.statusText}`);
return res.json();
}
async function createEpisode(sessionId, userMessage, aiResponse, tokenCount, projectId=null) {
const res = await fetch(`${BASE_URL}/episodes`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sessionId, userMessage, aiResponse, tokenCount, projectId })
});
if (!res.ok) throw new Error(`Failed to create episode: ${res.status} ${res.statusText}`);
return res.json();
}
async function getEpisodeById(episodeId) {
const res = await fetch(`${BASE_URL}/episodes/${episodeId}`);
if (res.status === 404) return null;
if (!res.ok) throw new Error(`Failed to fetch episode: ${res.status}`);
return res.json();
}
async function getSessionHistory(sessionId, limit = EPISODIC.DEFAULT_SESSIONS_LIMIT, offset = EPISODIC.DEFAULT_OFFSET) {
const res = await fetch(
`${BASE_URL}/sessions/${sessionId}/episodes?limit=${limit}&offset=${offset}`
);
if (res.status === 404 ) return null;
if (!res.ok) throw new Error(`Failed to fetch history: ${res.status}`);
return res.json();
}
async function getSessions(limit = EPISODIC.DEFAULT_SESSIONS_LIMIT, offset = EPISODIC.DEFAULT_OFFSET, projectId = null) {
const url = new URL(`${BASE_URL}/sessions`);
url.searchParams.set('limit', limit);
url.searchParams.set('offset', offset);
if (projectId) url.searchParams.set('projectId', projectId);
const res = await fetch(url.toString());
if (!res.ok) throw new Error(`Failed to fetch sessions: ${res.status}`);
return res.json();
}
async function updateSession(externalId, { name, projectId }) {
const res = await fetch(`${BASE_URL}/sessions/by-external/${externalId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, projectId }),
});
if (!res.ok) throw new Error(`Failed to update session: ${res.status}`);
return res.json();
}
async function deleteSession(externalId) {
const res = await fetch(`${BASE_URL}/sessions/by-external/${externalId}`, {
method: 'DELETE',
});
if (!res.ok) throw new Error(`Failed to delete session: ${res.status}`);
}
/******** PROJECTS ********* */
async function createProject({ name, description, colour, icon }) {
const res = await fetch(`${BASE_URL}/projects`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, description, colour, icon })
});
if (!res.ok) throw new Error(`Failed to create project: ${res.status}`);
return res.json();
}
async function getProjects() {
const res = await fetch(`${BASE_URL}/projects`);
if (!res.ok) throw new Error(`Failed to fetch projects: ${res.status}`);
return res.json();
}
async function updateProject(id, fields = {}) {
const res = await fetch(`${BASE_URL}/projects/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(fields)
});
if (!res.ok) throw new Error(`Failed to update project: ${res.status}`);
return res.json();
}
async function deleteProject(id) {
const res = await fetch(`${BASE_URL}/projects/${id}`, { method: 'DELETE' });
if (!res.ok) throw new Error(`Failed to delete project: ${res.status}`);
}
async function getProjectSessions(projectId) {
const url = new URL(`${BASE_URL}/sessions`);
url.searchParams.set('limit', 200); // generous upper bound
url.searchParams.set('offset', 0);
url.searchParams.set('projectId', projectId);
const res = await fetch(url.toString());
if (!res.ok) throw new Error(`Failed to fetch project sessions: ${res.status}`);
return res.json(); // returns array of session objects
}
async function getProject(id) {
const res = await fetch(`${BASE_URL}/projects/${id}`);
if (res.status === 404) return null;
if (!res.ok) throw new Error(`Failed to fetch project: ${res.status}`);
return res.json();
}
async function getEpisodes({ limit = 50, offset = 0, sessionId, q } = {}) {
const url = new URL(`${BASE_URL}/episodes`);
url.searchParams.set('limit', limit);
url.searchParams.set('offset', offset);
if (sessionId) url.searchParams.set('sessionId', sessionId);
if (q) url.searchParams.set('q', q);
const res = await fetch(url.toString());
if (!res.ok) throw new Error(`Failed to fetch episodes: ${res.status}`);
return res.json();
}
async function deleteEpisode(id) {
const res = await fetch(`${BASE_URL}/episodes/${id}`, { method: 'DELETE' });
if (!res.ok) throw new Error(`Failed to delete episode: ${res.status}`);
}
async function getSummariesBySession(sessionId) {
const res = await fetch(`${BASE_URL}/sessions/${sessionId}/summaries`);
if (!res.ok) throw new Error(`Failed to fetch summaries: ${res.status}`);
return res.json();
}
async function createSummary({ sessionId, projectId, content, tokenCount, episodeRange }) {
const res = await fetch(`${BASE_URL}/summaries`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sessionId, projectId, content, tokenCount, episodeRange }),
});
if (!res.ok) throw new Error(`Failed to create summary: ${res.status}`);
return res.json();
}
async function updateSummary(id, { content, tokenCount, episodeRange }) {
const res = await fetch(`${BASE_URL}/summaries/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content, tokenCount, episodeRange }),
});
if (!res.ok) throw new Error(`Failed to update summary: ${res.status}`);
return res.json();
}
async function getSummariesByProject(projectId) {
const res = await fetch(`${BASE_URL}/projects/${projectId}/summaries`);
if (!res.ok) throw new Error(`Failed to fetch summaries: ${res.status}`);
return res.json();
}
async function generateProjectSummary(projectId) {
const res = await fetch(`${BASE_URL}/projects/${projectId}/summarize`, {
method: 'POST',
});
if (!res.ok) throw new Error(`Failed to generate project summary: ${res.status}`);
return res.json();
}
async function getProjectOverviewSummary(projectId) {
const res = await fetch(`${BASE_URL}/projects/${projectId}/overview`);
if (!res.ok) throw new Error(`Failed to fetch project overview: ${res.status}`);
return res.json(); // null if none exists yet
}
async function searchEpisodes(query, { limit = 10, sessionIds = null } = {}) {
const url = new URL(`${BASE_URL}/episodes/search`);
url.searchParams.set('q', query);
url.searchParams.set('limit', limit);
if (sessionIds?.length) url.searchParams.set('sessionIds', sessionIds.join(','));
const res = await fetch(url.toString());
if (!res.ok) throw new Error(`FTS search error: ${res.status}`);
return res.json();
}
async function getEpisodesByEntities(entityIds) {
const res = await fetch(`${BASE_URL}/episodes/by-entities`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ entityIds }),
});
if (!res.ok) throw new Error(`Episodes-by-entities error: ${res.status}`);
return res.json(); // { episodeIds: [...] }
}
async function getEntityIdsBySession(sessionId){
const res = await fetch(`${BASE_URL}/sessions/${sessionId}/entity-ids`);
if (!res.ok) throw new Error(`Entity-ids-by-session error: ${res.status}`);
const {entityIds} = await res.jaon();
return entityIds;
}
module.exports = {
getSessionByExternalId,
createSession,
getRecentEpisodes,
createEpisode,
getEpisodeById,
getSessionHistory,
getSessions,
updateSession,
deleteSession,
createProject,
getProjects,
updateProject,
deleteProject,
getProjectSessions,
getProject,
getEpisodes,
deleteEpisode,
getSummariesBySession,
createSummary,
updateSummary,
getSummariesByProject,
generateProjectSummary,
getProjectOverviewSummary,
searchEpisodes,
getEpisodesByEntities,
getEntityIdsBySession,
}