254 lines
9.2 KiB
JavaScript
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,
|
|
} |