Added episodic layer with FTS5 triggers and search
This commit is contained in:
@@ -2,6 +2,7 @@ require ('dotenv').config();
|
||||
const express = require('express');
|
||||
const {getEnv} = require('@nexusai/shared');
|
||||
const { getDB } = require('./db');
|
||||
const episodic = require('./episodic');
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
@@ -16,7 +17,81 @@ app.get('/health', (req, res) => {
|
||||
res.json({ service: 'Memory Service', status: 'healthy' });
|
||||
});
|
||||
|
||||
// Start the server
|
||||
/************************************ */
|
||||
/********** Session Routes ********** */
|
||||
/************************************ */
|
||||
|
||||
// Creates a new session with an external ID and optional metadata
|
||||
app.post('/sessions', (req, res) => {
|
||||
const {externalId, metadata} = req.body;
|
||||
if (!externalId) {
|
||||
return res.status(400).json({ error: 'externalId is required' });
|
||||
}
|
||||
try {
|
||||
const session = episodic.createSession(externalId, metadata);
|
||||
res.status(201).json(session);
|
||||
} catch (err) {
|
||||
res.status(409).json({ error: 'Session already exists', detail: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieves a session by its internal ID
|
||||
app.get('/sessions/:id', (req, res) => {
|
||||
const session = episodic.getSession(req.params.id);
|
||||
if (!session) return res.status(404).json({ error: 'Session not found' });
|
||||
res.json(session);
|
||||
});
|
||||
|
||||
// Retrieves a session by its external ID
|
||||
app.get('/sessions/by-external/:externalId', (req, res) => {
|
||||
const session = episodic.getSessionByExternalId(req.params.externalId);
|
||||
if (!session) return res.status(404).json({ error: 'Session not found' });
|
||||
res.json(session);
|
||||
});
|
||||
|
||||
|
||||
// Updates the session's updated_at timestamp to now
|
||||
app.delete('/sessions/:id', (req, res) => {
|
||||
episodic.deleteSession(req.params.id);
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
|
||||
/************************************* */
|
||||
/********** Episodic Routes ********** */
|
||||
/************************************* */
|
||||
|
||||
app.post('/episodes', (req, res) => {
|
||||
const { sessionId, userMessage, aiResponse, tokenCount, metadata } = req.body;
|
||||
if (!sessionId || !userMessage || !aiResponse) {
|
||||
return res.status(400).json({ error: 'sessionId, userMessage and aiResponse are required' });
|
||||
}
|
||||
const episode = episodic.createEpisode(sessionId, userMessage, aiResponse, tokenCount, metadata);
|
||||
res.status(201).json(episode);
|
||||
});
|
||||
|
||||
// Search MUST come before /:id — otherwise 'search' gets captured as an id
|
||||
app.get('/episodes/search', (req, res) => {
|
||||
const { q, limit = 10 } = req.query;
|
||||
if (!q) return res.status(400).json({ error: 'q (query) parameter is required' });
|
||||
const results = episodic.searchEpisodes(q, Number(limit));
|
||||
res.json(results);
|
||||
});
|
||||
|
||||
app.get('/episodes/:id', (req, res) => {
|
||||
const episode = episodic.getEpisode(req.params.id);
|
||||
if (!episode) return res.status(404).json({ error: 'Episode not found' });
|
||||
res.json(episode);
|
||||
});
|
||||
|
||||
app.delete('/episodes/:id', (req, res) => {
|
||||
episodic.deleteEpisode(req.params.id);
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
/********************************** */
|
||||
/********** Start Server ********** */
|
||||
/********************************** */
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Memory Service is running on port ${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user