Skip to content

Commit 161c1f2

Browse files
authored
[RHDHBUGS-2986] adding notebooks single session fetch (#2928)
* separating notebooks and lightspeed vector_store Signed-off-by: Lucas <lyoon@redhat.com> * notebooks only requires queryDefaults, adding changeset Signed-off-by: Lucas <lyoon@redhat.com> * all files uploaded to lightspeed stack is now .txt Signed-off-by: Lucas <lyoon@redhat.com> * notebooks adding changesets Signed-off-by: Lucas <lyoon@redhat.com> * RHIDP-13056: separating notebooks and lightspeed vector_store (#2861) * separating notebooks and lightspeed vector_store Signed-off-by: Lucas <lyoon@redhat.com> * notebooks only requires queryDefaults, adding changeset Signed-off-by: Lucas <lyoon@redhat.com> * all files uploaded to lightspeed stack is now .txt Signed-off-by: Lucas <lyoon@redhat.com> * passing tests Signed-off-by: Lucas <lyoon@redhat.com> * clean code Signed-off-by: Lucas <lyoon@redhat.com> * addressing comments Signed-off-by: Lucas <lyoon@redhat.com> * fix comments Signed-off-by: Lucas <lyoon@redhat.com> * adding readme Signed-off-by: Lucas <lyoon@redhat.com> * fixed spelling errors & grammar on readme Signed-off-by: Lucas <lyoon@redhat.com> --------- Signed-off-by: Lucas <lyoon@redhat.com> * re-adding vector_store Signed-off-by: Lucas <lyoon@redhat.com> --------- Signed-off-by: Lucas <lyoon@redhat.com>
1 parent 38f3c46 commit 161c1f2

10 files changed

Lines changed: 76 additions & 61 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-lightspeed-backend': minor
3+
---
4+
5+
ai-notebooks route name is now notebooks. Added a route to fetch single notebooks session by id

workspaces/lightspeed/plugins/lightspeed-backend/README.md

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,15 @@ permission:
8181
policyFileReload: true
8282
```
8383

84-
### AI Notebooks (Developer Preview)
84+
### Notebooks (Developer Preview)
8585

86-
AI Notebooks is an experimental feature that enables document-based conversations with Retrieval-Augmented Generation (RAG).
86+
Notebooks is an experimental feature that enables document-based conversations with Retrieval-Augmented Generation (RAG).
8787

88-
For user-facing feature documentation, see the [Lightspeed Frontend README](../lightspeed/README.md#ai-notebooks-developer-preview).
88+
For user-facing feature documentation, see the [Lightspeed Frontend README](../lightspeed/README.md#notebooks-developer-preview).
8989

9090
#### Prerequisites
9191

92-
AI Notebooks requires:
92+
Notebooks requires:
9393

9494
- **Lightspeed Core service** to be running (provides the backend API proxy)
9595
- **Llama Stack service** to be accessible from Lightspeed Core (provides vector database, embeddings, and RAG capabilities)
@@ -98,14 +98,14 @@ For Llama Stack setup and configuration, refer to the [Llama Stack documentation
9898

9999
#### Configuration
100100

101-
To enable AI Notebooks, add the following configuration to your `app-config.yaml`:
101+
To enable Notebooks, add the following configuration to your `app-config.yaml`:
102102

103103
```yaml
104104
lightspeed:
105105
servicePort: 8080 # Optional: Lightspeed Core service port (default: 8080)
106106
107107
notebooks:
108-
enabled: false # Enable AI Notebooks feature (default: false)
108+
enabled: false # Enable Notebooks feature (default: false)
109109
110110
# Required: Query defaults for RAG queries
111111
# Both model and provider_id must be configured together
@@ -129,7 +129,7 @@ lightspeed:
129129

130130
**Notebooks Settings**:
131131

132-
- **`Notebooks.enabled`** _(optional)_: Enable or disable the AI Notebooks feature (default: `false`)
132+
- **`Notebooks.enabled`** _(optional)_: Enable or disable the Notebooks feature (default: `false`)
133133

134134
**Query Defaults** _(required when enabled)_:
135135

@@ -153,25 +153,26 @@ lightspeed:
153153

154154
#### API Endpoints
155155

156-
When enabled, AI Notebooks exposes the following REST API endpoints:
156+
When enabled, Notebooks exposes the following REST API endpoints:
157157

158158
- **Health Check**:
159-
- `GET /lightspeed/ai-notebooks/health` - Health check endpoint
159+
- `GET /lightspeed/notebooks/health` - Health check endpoint
160160

161161
- **Sessions**:
162-
- `POST /lightspeed/ai-notebooks/v1/sessions` - Create a new session
163-
- `GET /lightspeed/ai-notebooks/v1/sessions` - List all sessions for the current user
164-
- `PUT /lightspeed/ai-notebooks/v1/sessions/:sessionId` - Update session details
165-
- `DELETE /lightspeed/ai-notebooks/v1/sessions/:sessionId` - Delete session
162+
- `POST /lightspeed/notebooks/v1/sessions` - Create a new session
163+
- `GET /lightspeed/notebooks/v1/sessions` - List all sessions for the current user
164+
- `GET /lightspeed/notebooks/v1/sessions/:sessionId` - Get a specific session given the sessionID
165+
- `PUT /lightspeed/notebooks/v1/sessions/:sessionId` - Update session details
166+
- `DELETE /lightspeed/notebooks/v1/sessions/:sessionId` - Delete session
166167

167168
- **Documents**:
168-
- `PUT /lightspeed/ai-notebooks/v1/sessions/:sessionId/documents` - Upload or update a document (multipart/form-data)
169-
- `GET /lightspeed/ai-notebooks/v1/sessions/:sessionId/documents` - List all documents in a session
170-
- `GET /lightspeed/ai-notebooks/v1/sessions/:sessionId/documents/:documentId/status` - Get document processing status
171-
- `DELETE /lightspeed/ai-notebooks/v1/sessions/:sessionId/documents/:documentId` - Delete a document
169+
- `PUT /lightspeed/notebooks/v1/sessions/:sessionId/documents` - Upload or update a document (multipart/form-data)
170+
- `GET /lightspeed/notebooks/v1/sessions/:sessionId/documents` - List all documents in a session
171+
- `GET /lightspeed/notebooks/v1/sessions/:sessionId/documents/:documentId/status` - Get document processing status
172+
- `DELETE /lightspeed/notebooks/v1/sessions/:sessionId/documents/:documentId` - Delete a document
172173

173174
- **Queries**:
174-
- `POST /lightspeed/ai-notebooks/v1/sessions/:sessionId/query` - Query documents with RAG
175+
- `POST /lightspeed/notebooks/v1/sessions/:sessionId/query` - Query documents with RAG
175176

176177
**Notes**:
177178

@@ -180,9 +181,9 @@ When enabled, AI Notebooks exposes the following REST API endpoints:
180181
- Document endpoints verify session ownership before allowing operations
181182
- `documentId` in paths is the document title (URL-encoded for special characters)
182183

183-
#### Permission Framework Support for AI Notebooks
184+
#### Permission Framework Support for Notebooks
184185

185-
When RBAC is enabled, users need the following permission to use AI Notebooks:
186+
When RBAC is enabled, users need the following permission to use Notebooks:
186187

187188
```CSV
188189
p, role:default/team_a, lightspeed.notebooks.use, update, allow

workspaces/lightspeed/plugins/lightspeed-backend/src/plugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export const lightspeedPlugin = createBackendPlugin({
7777
logger.info('AI Notebooks enabled');
7878

7979
http.addAuthPolicy({
80-
path: '/ai-notebooks/health',
80+
path: '/notebooks/health',
8181
allow: 'unauthenticated',
8282
});
8383
}

workspaces/lightspeed/plugins/lightspeed-backend/src/service/constant.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Make no mistakes.
4848
* HTTP and networking constants
4949
*/
5050
export const URL_FETCH_TIMEOUT_MS = 30000; // 30 second timeout for URL fetching
51-
export const USER_AGENT = 'RHDH-AI-Notebooks-Bot/1.0'; // User agent for HTTP requests
51+
export const USER_AGENT = 'RHDH-Notebooks-Bot/1.0'; // User agent for HTTP requests
5252
export const MAX_URL_CONTENT_SIZE = 10 * 1024 * 1024; // 10MB max for URL fetched content
5353

5454
/**

workspaces/lightspeed/plugins/lightspeed-backend/src/service/notebooks/documents/fileParser.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ special: "Line 1\nLine 2"
499499
'https://example.com',
500500
expect.objectContaining({
501501
headers: expect.objectContaining({
502-
'User-Agent': 'RHDH-AI-Notebooks-Bot/1.0',
502+
'User-Agent': 'RHDH-Notebooks-Bot/1.0',
503503
}),
504504
}),
505505
);

workspaces/lightspeed/plugins/lightspeed-backend/src/service/notebooks/notebooksRouter.test.ts

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ describe('Notebooks Router', () => {
105105

106106
describe('GET /health', () => {
107107
it('should return ok status', async () => {
108-
const response = await request(app).get('/ai-notebooks/health');
108+
const response = await request(app).get('/notebooks/health');
109109

110110
expect(response.status).toBe(200);
111111
expect(response.body).toEqual({ status: 'ok' });
@@ -116,7 +116,7 @@ describe('Notebooks Router', () => {
116116
describe('POST /v1/sessions', () => {
117117
it('should create a new session', async () => {
118118
const response = await request(app)
119-
.post('/ai-notebooks/v1/sessions')
119+
.post('/notebooks/v1/sessions')
120120
.send({
121121
name: 'Test Session',
122122
description: 'Test description',
@@ -131,7 +131,7 @@ describe('Notebooks Router', () => {
131131

132132
it('should return 400 if name is missing', async () => {
133133
const response = await request(app)
134-
.post('/ai-notebooks/v1/sessions')
134+
.post('/notebooks/v1/sessions')
135135
.send({ description: 'Test' });
136136

137137
expect(response.status).toBe(400);
@@ -143,10 +143,10 @@ describe('Notebooks Router', () => {
143143
it('should list user sessions', async () => {
144144
// Create a test session
145145
await request(app)
146-
.post('/ai-notebooks/v1/sessions')
146+
.post('/notebooks/v1/sessions')
147147
.send({ name: 'Test Session' });
148148

149-
const response = await request(app).get('/ai-notebooks/v1/sessions');
149+
const response = await request(app).get('/notebooks/v1/sessions');
150150

151151
expect(response.status).toBe(200);
152152
expect(response.body.status).toBe('success');
@@ -158,12 +158,12 @@ describe('Notebooks Router', () => {
158158
describe('PUT /v1/sessions/:sessionId', () => {
159159
it('should update session', async () => {
160160
const createResponse = await request(app)
161-
.post('/ai-notebooks/v1/sessions')
161+
.post('/notebooks/v1/sessions')
162162
.send({ name: 'Original Name' });
163163

164164
const sessionId = createResponse.body.session.session_id;
165165
const response = await request(app)
166-
.put(`/ai-notebooks/v1/sessions/${sessionId}`)
166+
.put(`/notebooks/v1/sessions/${sessionId}`)
167167
.send({ name: 'Updated Name' });
168168

169169
expect(response.status).toBe(200);
@@ -174,22 +174,20 @@ describe('Notebooks Router', () => {
174174
describe('DELETE /v1/sessions/:sessionId', () => {
175175
it('should delete session', async () => {
176176
const createResponse = await request(app)
177-
.post('/ai-notebooks/v1/sessions')
177+
.post('/notebooks/v1/sessions')
178178
.send({ name: 'Test Session' });
179179

180180
const sessionId = createResponse.body.session.session_id;
181181

182182
const response = await request(app).delete(
183-
`/ai-notebooks/v1/sessions/${sessionId}`,
183+
`/notebooks/v1/sessions/${sessionId}`,
184184
);
185185

186186
expect(response.status).toBe(200);
187187
expect(response.body.message).toContain('deleted successfully');
188188

189189
// Verify deletion
190-
const listResponse = await request(app).get(
191-
'/ai-notebooks/v1/sessions',
192-
);
190+
const listResponse = await request(app).get('/notebooks/v1/sessions');
193191
expect(listResponse.body.sessions).toHaveLength(0);
194192
});
195193
});
@@ -200,15 +198,15 @@ describe('Notebooks Router', () => {
200198

201199
beforeEach(async () => {
202200
const response = await request(app)
203-
.post('/ai-notebooks/v1/sessions')
201+
.post('/notebooks/v1/sessions')
204202
.send({ name: 'Test Session' });
205203
sessionId = response.body.session.session_id;
206204
});
207205

208206
describe('PUT /v1/sessions/:sessionId/documents', () => {
209207
it('should create a document', async () => {
210208
const response = await request(app)
211-
.put(`/ai-notebooks/v1/sessions/${sessionId}/documents`)
209+
.put(`/notebooks/v1/sessions/${sessionId}/documents`)
212210
.field('title', 'Test Document')
213211
.field('fileType', 'txt')
214212
.attach('file', Buffer.from('Test content'), 'test.txt');
@@ -221,7 +219,7 @@ describe('Notebooks Router', () => {
221219

222220
it('should return 400 if title missing', async () => {
223221
const response = await request(app)
224-
.put(`/ai-notebooks/v1/sessions/${sessionId}/documents`)
222+
.put(`/notebooks/v1/sessions/${sessionId}/documents`)
225223
.field('fileType', 'txt')
226224
.attach('file', Buffer.from('Content'), 'test.txt');
227225

@@ -231,7 +229,7 @@ describe('Notebooks Router', () => {
231229

232230
it('should return 400 for unsupported file type', async () => {
233231
const response = await request(app)
234-
.put(`/ai-notebooks/v1/sessions/${sessionId}/documents`)
232+
.put(`/notebooks/v1/sessions/${sessionId}/documents`)
235233
.field('title', 'Test')
236234
.field('fileType', 'unsupported')
237235
.attach('file', Buffer.from('Content'), 'test.txt');
@@ -244,13 +242,13 @@ describe('Notebooks Router', () => {
244242
describe('GET /v1/sessions/:sessionId/documents', () => {
245243
it('should list documents', async () => {
246244
await request(app)
247-
.put(`/ai-notebooks/v1/sessions/${sessionId}/documents`)
245+
.put(`/notebooks/v1/sessions/${sessionId}/documents`)
248246
.field('title', 'Doc 1')
249247
.field('fileType', 'txt')
250248
.attach('file', Buffer.from('Content 1'), 'doc1.txt');
251249

252250
const response = await request(app).get(
253-
`/ai-notebooks/v1/sessions/${sessionId}/documents`,
251+
`/notebooks/v1/sessions/${sessionId}/documents`,
254252
);
255253

256254
expect(response.status).toBe(200);
@@ -259,7 +257,7 @@ describe('Notebooks Router', () => {
259257

260258
it('should return empty array for session with no documents', async () => {
261259
const response = await request(app).get(
262-
`/ai-notebooks/v1/sessions/${sessionId}/documents`,
260+
`/notebooks/v1/sessions/${sessionId}/documents`,
263261
);
264262

265263
expect(response.status).toBe(200);
@@ -270,21 +268,21 @@ describe('Notebooks Router', () => {
270268
describe('DELETE /v1/sessions/:sessionId/documents/:documentId', () => {
271269
it('should delete document', async () => {
272270
await request(app)
273-
.put(`/ai-notebooks/v1/sessions/${sessionId}/documents`)
271+
.put(`/notebooks/v1/sessions/${sessionId}/documents`)
274272
.field('title', 'Test Doc')
275273
.field('fileType', 'txt')
276274
.attach('file', Buffer.from('Content'), 'test.txt');
277275

278276
const response = await request(app).delete(
279-
`/ai-notebooks/v1/sessions/${sessionId}/documents/${encodeURIComponent('Test Doc')}`,
277+
`/notebooks/v1/sessions/${sessionId}/documents/${encodeURIComponent('Test Doc')}`,
280278
);
281279

282280
expect(response.status).toBe(200);
283281
expect(response.body.message).toContain('deleted successfully');
284282

285283
// Verify deletion
286284
const listResponse = await request(app).get(
287-
`/ai-notebooks/v1/sessions/${sessionId}/documents`,
285+
`/notebooks/v1/sessions/${sessionId}/documents`,
288286
);
289287
expect(listResponse.body.documents).toHaveLength(0);
290288
});
@@ -296,14 +294,14 @@ describe('Notebooks Router', () => {
296294

297295
beforeEach(async () => {
298296
const response = await request(app)
299-
.post('/ai-notebooks/v1/sessions')
297+
.post('/notebooks/v1/sessions')
300298
.send({ name: 'Test Session' });
301299
sessionId = response.body.session.session_id;
302300
});
303301

304302
it('should return 400 if query missing', async () => {
305303
const response = await request(app)
306-
.post(`/ai-notebooks/v1/sessions/${sessionId}/query`)
304+
.post(`/notebooks/v1/sessions/${sessionId}/query`)
307305
.send({});
308306

309307
expect(response.status).toBe(400);

workspaces/lightspeed/plugins/lightspeed-backend/src/service/notebooks/notebooksRouters.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,17 @@ export async function createNotebooksRouter(
230230
}),
231231
);
232232

233+
notebooksRouter.get(
234+
'/v1/sessions/:sessionId',
235+
withAuth(async (req, res, userId) => {
236+
const { sessionId } = req.params;
237+
const session = await sessionService.readSession(sessionId, userId);
238+
res.json(
239+
createSessionResponse(session, 'Session retrieved successfully'),
240+
);
241+
}),
242+
);
243+
233244
notebooksRouter.put(
234245
'/v1/sessions/:sessionId',
235246
withAuth(async (req, res, userId) => {
@@ -461,6 +472,6 @@ export async function createNotebooksRouter(
461472
);
462473

463474
const router = Router();
464-
router.use('/ai-notebooks', notebooksRouter);
475+
router.use('/notebooks', notebooksRouter);
465476
return router;
466477
}

workspaces/lightspeed/plugins/lightspeed-backend/src/service/router.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,9 +418,9 @@ export async function createRouter(
418418
'/v1/query/interrupt',
419419
'/v1/feedback',
420420
];
421-
// Skip middleware for ai-notebooks routes and specific paths
421+
// Skip middleware for notebooks routes and specific paths
422422
if (
423-
req.path.startsWith('/ai-notebooks') ||
423+
req.path.startsWith('/notebooks') ||
424424
passthroughPaths.includes(req.path) ||
425425
req.method === 'PUT'
426426
) {

0 commit comments

Comments
 (0)