@red-hat-developer-hub/backstage-plugin-intelligent-assistant-backend 3.2.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@ var getIdentity = require('../middleware/getIdentity.cjs.js');
9
9
  var permission = require('../permission.cjs.js');
10
10
  var documentHelpers = require('./documents/documentHelpers.cjs.js');
11
11
  var documentService = require('./documents/documentService.cjs.js');
12
+ var markitdownClient = require('./documents/markitdownClient.cjs.js');
12
13
  var sessionService = require('./sessions/sessionService.cjs.js');
13
14
  var notebooksTypes = require('./types/notebooksTypes.cjs.js');
14
15
  var utils = require('./utils.cjs.js');
@@ -53,13 +54,10 @@ async function createNotebooksRouter(options) {
53
54
  "general",
54
55
  logger
55
56
  );
56
- const requireNotebooksPermission = async (req, res, next) => {
57
+ const requirePermission = (permission) => async (req, res, next) => {
57
58
  try {
58
59
  const { credentials } = getIdentity.getIdentity(req);
59
- await authorizer.authorizeUser(
60
- backstagePluginIntelligentAssistantCommon.lightspeedNotebooksUsePermission,
61
- credentials
62
- );
60
+ await authorizer.authorizeUser(permission, credentials);
63
61
  next();
64
62
  } catch (error) {
65
63
  utils.handleError(logger, res, error, "Permission denied");
@@ -182,7 +180,7 @@ async function createNotebooksRouter(options) {
182
180
  notebooksRouter.post(
183
181
  "/v1/sessions",
184
182
  generalRateLimiter,
185
- requireNotebooksPermission,
183
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
186
184
  withAuth(async (req, res, userId) => {
187
185
  const { name, description, metadata } = req.body;
188
186
  if (!name) {
@@ -201,7 +199,7 @@ async function createNotebooksRouter(options) {
201
199
  notebooksRouter.get(
202
200
  "/v1/sessions",
203
201
  generalRateLimiter,
204
- requireNotebooksPermission,
202
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
205
203
  withAuth(async (_req, res, userId) => {
206
204
  const sessions = await sessionService$1.listSessions(userId);
207
205
  res.json(notebooksTypes.createSessionListResponse(sessions));
@@ -210,7 +208,7 @@ async function createNotebooksRouter(options) {
210
208
  notebooksRouter.get(
211
209
  "/v1/sessions/:sessionId",
212
210
  generalRateLimiter,
213
- requireNotebooksPermission,
211
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
214
212
  withAuth(async (req, res, userId) => {
215
213
  const { sessionId } = req.params;
216
214
  const session = await sessionService$1.readSession(sessionId, userId);
@@ -222,7 +220,7 @@ async function createNotebooksRouter(options) {
222
220
  notebooksRouter.put(
223
221
  "/v1/sessions/:sessionId",
224
222
  generalRateLimiter,
225
- requireNotebooksPermission,
223
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksManagePermission),
226
224
  withAuth(async (req, res, userId) => {
227
225
  const { sessionId } = req.params;
228
226
  const { name, description, metadata } = req.body;
@@ -239,7 +237,7 @@ async function createNotebooksRouter(options) {
239
237
  notebooksRouter.delete(
240
238
  "/v1/sessions/:sessionId",
241
239
  generalRateLimiter,
242
- requireNotebooksPermission,
240
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksManagePermission),
243
241
  withAuth(async (req, res, userId) => {
244
242
  const { sessionId } = req.params;
245
243
  await sessionService$1.deleteSession(sessionId, userId);
@@ -254,7 +252,7 @@ async function createNotebooksRouter(options) {
254
252
  notebooksRouter.get(
255
253
  "/v1/sessions/:sessionId/documents",
256
254
  generalRateLimiter,
257
- requireNotebooksPermission,
255
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
258
256
  requireSessionOwnership(),
259
257
  withAuth(async (req, res) => {
260
258
  const { sessionId } = req.params;
@@ -269,7 +267,7 @@ async function createNotebooksRouter(options) {
269
267
  notebooksRouter.put(
270
268
  "/v1/sessions/:sessionId/documents",
271
269
  expensiveRateLimiter,
272
- requireNotebooksPermission,
270
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
273
271
  constant.upload.single("file"),
274
272
  withAuth(async (req, res, userId) => {
275
273
  const { sessionId } = req.params;
@@ -291,19 +289,24 @@ async function createNotebooksRouter(options) {
291
289
  utils.handleError(logger, res, "Session not found");
292
290
  return;
293
291
  }
294
- const parsedDocument = await documentHelpers.parseFileContent(logger, fileType, req.file);
295
- const fileId = await documentService$1.uploadFile(
296
- parsedDocument.content,
297
- title
292
+ if (!req.file) {
293
+ utils.handleError(logger, res, "No file uploaded");
294
+ return;
295
+ }
296
+ const markdown = await markitdownClient.convertToMarkdown(
297
+ req.file.buffer,
298
+ req.file.originalname,
299
+ fileType
298
300
  );
301
+ const fileId = await documentService$1.uploadFile(markdown, title);
299
302
  res.status(constant.HTTP_STATUS_ACCEPTED).json({
300
303
  status: "processing",
301
304
  document_id: newTitle || title,
302
305
  session_id: sessionId,
303
- message: "Document upload started"
306
+ message: "Resource upload started"
304
307
  });
305
308
  const docName = newTitle || title;
306
- documentService$1.upsertDocument(sessionId, title, fileType, fileId, newTitle).then(() => logger.info(`Background upload succeeded: ${docName}`)).catch(
309
+ documentService$1.upsertDocument(sessionId, title, { fileType, fileId, newTitle }).then(() => logger.info(`Background upload succeeded: ${docName}`)).catch(
307
310
  (err) => logger.error(`Background upload failed: ${docName}`, err)
308
311
  );
309
312
  })
@@ -311,7 +314,7 @@ async function createNotebooksRouter(options) {
311
314
  notebooksRouter.get(
312
315
  "/v1/sessions/:sessionId/documents/:documentId/status",
313
316
  generalRateLimiter,
314
- requireNotebooksPermission,
317
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
315
318
  requireSessionOwnership(),
316
319
  withAuth(async (req, res) => {
317
320
  const { sessionId, documentId } = req.params;
@@ -327,10 +330,43 @@ async function createNotebooksRouter(options) {
327
330
  });
328
331
  })
329
332
  );
333
+ notebooksRouter.patch(
334
+ "/v1/sessions/:sessionId/documents/:documentId",
335
+ generalRateLimiter,
336
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksManagePermission),
337
+ requireSessionOwnership(),
338
+ withAuth(async (req, res) => {
339
+ const { sessionId, documentId } = req.params;
340
+ const { title } = req.body;
341
+ if (!title || typeof title !== "string" || !title.trim()) {
342
+ utils.handleError(logger, res, "title is required");
343
+ return;
344
+ }
345
+ const MAX_TITLE_LENGTH = 255;
346
+ if (title.trim().length > MAX_TITLE_LENGTH) {
347
+ utils.handleError(
348
+ logger,
349
+ res,
350
+ `title must be ${MAX_TITLE_LENGTH} characters or less`
351
+ );
352
+ return;
353
+ }
354
+ await documentService$1.upsertDocument(sessionId, documentId, {
355
+ newTitle: title.trim()
356
+ });
357
+ res.json(
358
+ notebooksTypes.createDocumentResponse(
359
+ title.trim(),
360
+ sessionId,
361
+ "Document renamed successfully"
362
+ )
363
+ );
364
+ })
365
+ );
330
366
  notebooksRouter.delete(
331
367
  "/v1/sessions/:sessionId/documents/:documentId",
332
368
  generalRateLimiter,
333
- requireNotebooksPermission,
369
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksManagePermission),
334
370
  requireSessionOwnership(),
335
371
  withAuth(async (req, res) => {
336
372
  const { sessionId, documentId } = req.params;
@@ -339,7 +375,7 @@ async function createNotebooksRouter(options) {
339
375
  notebooksTypes.createDocumentResponse(
340
376
  documentId,
341
377
  sessionId,
342
- "Document deleted successfully"
378
+ "Resource deleted successfully"
343
379
  )
344
380
  );
345
381
  })
@@ -354,7 +390,7 @@ async function createNotebooksRouter(options) {
354
390
  notebooksRouter.post(
355
391
  "/v1/sessions/:sessionId/query",
356
392
  expensiveRateLimiter,
357
- requireNotebooksPermission,
393
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
358
394
  express__default.default.json({ limit: constant.EXPRESS_JSON_BODY_LIMIT }),
359
395
  withAuth(async (req, res, userId) => {
360
396
  const { sessionId } = req.params;
@@ -1 +1 @@
1
- {"version":3,"file":"notebooksRouters.cjs.js","sources":["../../../src/service/notebooks/notebooksRouters.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n HttpAuthService,\n LoggerService,\n PermissionsService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\n\nimport express, { Router } from 'express';\n\nimport { lightspeedNotebooksUsePermission } from '@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common';\n\nimport { Readable, Transform } from 'stream';\n\nimport {\n DEFAULT_LIGHTSPEED_SERVICE_HOST,\n DEFAULT_LIGHTSPEED_SERVICE_PORT,\n EXPRESS_JSON_BODY_LIMIT,\n HTTP_STATUS_ACCEPTED,\n HTTP_STATUS_INTERNAL_ERROR,\n MAX_QUERY_LENGTH,\n MAX_QUERY_RETRIES,\n NOTEBOOKS_SYSTEM_PROMPT,\n upload,\n} from '../constant';\nimport { createRateLimitMiddleware } from '../middleware/createRateLimitMiddleware';\nimport {\n createIdentityMiddleware,\n getIdentity,\n} from '../middleware/getIdentity';\nimport { userPermissionAuthorization } from '../permission';\nimport { isValidFileType, parseFileContent } from './documents/documentHelpers';\nimport { DocumentService } from './documents/documentService';\nimport { SessionService } from './sessions/sessionService';\nimport {\n createDocumentListResponse,\n createDocumentResponse,\n createSessionListResponse,\n createSessionResponse,\n} from './types/notebooksTypes';\nimport { handleError } from './utils';\nimport { VectorStoresOperator } from './VectorStoresOperator';\n\nexport interface NotebooksRouterOptions {\n logger: LoggerService;\n config: Config;\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n permissions: PermissionsService;\n}\n\nexport async function createNotebooksRouter(\n options: NotebooksRouterOptions,\n): Promise<Router> {\n const { logger, config, httpAuth, userInfo, permissions } = options;\n const notebooksRouter = Router();\n notebooksRouter.use(express.json());\n\n const lightSpeedPort =\n config.getOptionalNumber('intelligent-assistant.servicePort') ??\n DEFAULT_LIGHTSPEED_SERVICE_PORT;\n const lcsBaseUrl = `http://${DEFAULT_LIGHTSPEED_SERVICE_HOST}:${lightSpeedPort}`;\n const queryModel = config.getString(\n 'intelligent-assistant.notebooks.queryDefaults.model',\n );\n const queryProvider = config.getString(\n 'intelligent-assistant.notebooks.queryDefaults.provider_id',\n );\n const systemPrompt = NOTEBOOKS_SYSTEM_PROMPT;\n\n logger.info(`AI Notebooks connecting to Lightspeed-Core at ${lcsBaseUrl}`);\n\n const vectorStoresOperator = VectorStoresOperator.getInstance(\n lcsBaseUrl,\n logger,\n );\n const sessionService = new SessionService(vectorStoresOperator, logger);\n const documentService = new DocumentService(\n vectorStoresOperator,\n logger,\n config,\n );\n\n const authorizer = userPermissionAuthorization(permissions);\n\n const expensiveRateLimiter = createRateLimitMiddleware(\n config,\n 'expensive',\n logger,\n );\n const generalRateLimiter = createRateLimitMiddleware(\n config,\n 'general',\n logger,\n );\n\n const requireNotebooksPermission = async (\n req: any,\n res: any,\n next: any,\n ): Promise<void> => {\n try {\n const { credentials } = getIdentity(req);\n await authorizer.authorizeUser(\n lightspeedNotebooksUsePermission,\n credentials,\n );\n next();\n } catch (error) {\n handleError(logger, res, error, 'Permission denied');\n }\n };\n\n const requireSessionOwnership =\n () => async (req: any, res: any, next: any) => {\n try {\n const { userEntityRef } = getIdentity(req);\n const { sessionId } = req.params;\n await sessionService.readSession(sessionId, userEntityRef);\n next();\n } catch (error) {\n handleError(\n logger,\n res,\n error,\n 'Session ownership verification failed',\n );\n }\n };\n\n const withAuth =\n (handler: (req: any, res: any, userId: string) => Promise<void>) =>\n async (req: any, res: any, next: any) => {\n try {\n const { userEntityRef } = getIdentity(req);\n await handler(req, res, userEntityRef);\n } catch (error) {\n next(error);\n }\n };\n\n /**\n * Transforms Responses API SSE (event:/data: lines) into the legacy\n * streaming format that the frontend useConversationMessages hook expects:\n * data: {\"event\": \"<type>\", \"data\": {...}}\\n\\n\n *\n * Also captures the conversation_id from the first response.created event\n * and persists it on the session when it is new.\n */\n const createResponsesApiTransform = (\n session: any,\n sessionId: string,\n userId: string,\n ) => {\n let buffer = '';\n let conversationCaptured = !!session.metadata?.conversation_id;\n\n return new Transform({\n transform(chunk: any, _encoding: any, callback: any) {\n buffer += chunk.toString();\n\n const blocks = buffer.split('\\n\\n');\n buffer = blocks.pop()!;\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const lines = block.split('\\n');\n let eventType = '';\n let dataLine = '';\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n eventType = line.slice(7).trim();\n } else if (line.startsWith('data: ')) {\n dataLine = line.slice(6).trim();\n }\n }\n\n if (dataLine === '[DONE]') {\n this.push('data: [DONE]\\n\\n');\n continue;\n }\n\n if (!dataLine) continue;\n\n let parsed: any;\n try {\n parsed = JSON.parse(dataLine);\n } catch {\n continue;\n }\n\n if (eventType === 'response.created') {\n const convId = parsed?.response?.conversation;\n const requestId = parsed?.response?.id;\n\n if (convId && !conversationCaptured) {\n conversationCaptured = true;\n logger.info(`Captured conversation ID: ${convId}`);\n sessionService\n .updateSession(sessionId, userId, undefined, undefined, {\n ...session.metadata,\n conversation_id: convId,\n })\n .catch((err: any) =>\n logger.error(`Failed to update session: ${err}`),\n );\n }\n\n const legacy = {\n event: 'start',\n data: { conversation_id: convId, request_id: requestId },\n };\n this.push(`data: ${JSON.stringify(legacy)}\\n\\n`);\n } else if (eventType === 'response.output_text.delta') {\n const legacy = {\n event: 'token',\n data: { token: parsed?.delta ?? '' },\n };\n this.push(`data: ${JSON.stringify(legacy)}\\n\\n`);\n } else if (eventType === 'response.completed') {\n // Log the full response to see what we're getting\n logger.info(\n `Full response.completed event: ${JSON.stringify(parsed?.response, null, 2)}`,\n );\n\n // Extract citations/sources from tool calls (file_search results)\n\n // this.push(`data: ${JSON.stringify(legacy)}\\n\\n`);\n } else {\n // Log unhandled event types to help identify what we're missing\n logger.debug(`Unhandled SSE event type: ${eventType}`, parsed);\n }\n }\n\n callback();\n },\n\n flush(callback: any) {\n if (buffer.trim()) {\n const lines = buffer.split('\\n');\n let dataLine = '';\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n dataLine = line.slice(6).trim();\n }\n }\n if (dataLine === '[DONE]') {\n this.push('data: [DONE]\\n\\n');\n }\n }\n callback();\n },\n });\n };\n\n notebooksRouter.get('/health', (_req, res) => res.json({ status: 'ok' }));\n notebooksRouter.use(\n '/v1',\n createIdentityMiddleware(httpAuth, userInfo, logger),\n );\n\n notebooksRouter.post(\n '/v1/sessions',\n generalRateLimiter,\n requireNotebooksPermission,\n withAuth(async (req, res, userId) => {\n const { name, description, metadata } = req.body;\n if (!name) {\n handleError(logger, res, 'name is required');\n return;\n }\n const session = await sessionService.createSession(\n userId,\n name,\n description,\n { ...metadata, conversation_id: null },\n );\n res.json(createSessionResponse(session, 'Session created successfully'));\n }),\n );\n\n notebooksRouter.get(\n '/v1/sessions',\n generalRateLimiter,\n requireNotebooksPermission,\n withAuth(async (_req, res, userId) => {\n const sessions = await sessionService.listSessions(userId);\n res.json(createSessionListResponse(sessions));\n }),\n );\n\n notebooksRouter.get(\n '/v1/sessions/:sessionId',\n generalRateLimiter,\n requireNotebooksPermission,\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n const session = await sessionService.readSession(sessionId, userId);\n res.json(\n createSessionResponse(session, 'Session retrieved successfully'),\n );\n }),\n );\n\n notebooksRouter.put(\n '/v1/sessions/:sessionId',\n generalRateLimiter,\n requireNotebooksPermission,\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n const { name, description, metadata } = req.body;\n const session = await sessionService.updateSession(\n sessionId,\n userId,\n name,\n description,\n metadata,\n );\n res.json(createSessionResponse(session, 'Session updated successfully'));\n }),\n );\n\n notebooksRouter.delete(\n '/v1/sessions/:sessionId',\n generalRateLimiter,\n requireNotebooksPermission,\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n await sessionService.deleteSession(sessionId, userId);\n res.json(\n createSessionResponse(\n { session_id: sessionId } as any,\n 'Session deleted successfully',\n ),\n );\n }),\n );\n\n notebooksRouter.get(\n '/v1/sessions/:sessionId/documents',\n generalRateLimiter,\n requireNotebooksPermission,\n requireSessionOwnership(),\n withAuth(async (req, res) => {\n const { sessionId } = req.params;\n const fileType = req.query.fileType as string | undefined;\n const documents = await documentService.listDocuments(\n sessionId,\n fileType,\n );\n res.json(createDocumentListResponse(sessionId, documents));\n }),\n );\n\n notebooksRouter.put(\n '/v1/sessions/:sessionId/documents',\n expensiveRateLimiter,\n requireNotebooksPermission,\n upload.single('file') as any,\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n const { fileType, title, newTitle } = req.body;\n\n if (!title) {\n handleError(logger, res, 'title is required');\n return;\n }\n\n if (!fileType || !isValidFileType(fileType)) {\n handleError(\n logger,\n res,\n `Unsupported file type: ${fileType}. Supported types: md, txt, pdf, json, yaml, yml, log`,\n );\n return;\n }\n\n const session = await sessionService.readSession(sessionId, userId);\n if (!session) {\n handleError(logger, res, 'Session not found');\n return;\n }\n const parsedDocument = await parseFileContent(logger, fileType, req.file);\n const fileId = await documentService.uploadFile(\n parsedDocument.content,\n title,\n );\n\n res.status(HTTP_STATUS_ACCEPTED).json({\n status: 'processing',\n document_id: newTitle || title,\n session_id: sessionId,\n message: 'Document upload started',\n });\n\n // Upload document to vector store in background\n const docName = newTitle || title;\n documentService\n .upsertDocument(sessionId, title, fileType, fileId, newTitle)\n .then(() => logger.info(`Background upload succeeded: ${docName}`))\n .catch((err: any) =>\n logger.error(`Background upload failed: ${docName}`, err),\n );\n }),\n );\n\n notebooksRouter.get(\n '/v1/sessions/:sessionId/documents/:documentId/status',\n generalRateLimiter,\n requireNotebooksPermission,\n requireSessionOwnership(),\n withAuth(async (req, res) => {\n const { sessionId, documentId } = req.params;\n const fileStatus = await documentService.getFileStatus(\n sessionId,\n documentId,\n );\n res.json({\n status: fileStatus.status,\n document_id: documentId,\n session_id: sessionId,\n ...(fileStatus.error && { error: fileStatus.error }),\n });\n }),\n );\n\n notebooksRouter.delete(\n '/v1/sessions/:sessionId/documents/:documentId',\n generalRateLimiter,\n requireNotebooksPermission,\n requireSessionOwnership(),\n withAuth(async (req, res) => {\n const { sessionId, documentId } = req.params;\n await documentService.deleteDocument(sessionId, documentId);\n res.json(\n createDocumentResponse(\n documentId,\n sessionId,\n 'Document deleted successfully',\n ),\n );\n }),\n );\n\n const validateNotebooksQuery = (query: unknown): string | null => {\n if (!query) return 'query is required';\n if (typeof query === 'string' && query.length > MAX_QUERY_LENGTH) {\n return `query exceeds maximum length of ${MAX_QUERY_LENGTH} characters`;\n }\n return null;\n };\n\n notebooksRouter.post(\n '/v1/sessions/:sessionId/query',\n expensiveRateLimiter,\n requireNotebooksPermission,\n express.json({ limit: EXPRESS_JSON_BODY_LIMIT }),\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n const { query } = req.body;\n\n const queryError = validateNotebooksQuery(query);\n if (queryError) {\n handleError(logger, res, queryError);\n return;\n }\n\n const session = await sessionService.readSession(sessionId, userId);\n let conversationId = session.metadata?.conversation_id;\n\n const lcsRequest: any = {\n input: query,\n instructions: systemPrompt,\n tools: [{ type: 'file_search', vector_store_ids: [sessionId] }],\n tool_choice: 'required',\n model: `${queryProvider}/${queryModel}`,\n stream: true,\n temperature: 0.35,\n shield_ids: [],\n max_tool_calls: 15,\n ...(conversationId && { conversation: conversationId }),\n };\n\n for (let retries = 0; retries <= MAX_QUERY_RETRIES; retries++) {\n const abortController = new AbortController();\n\n const response = await fetch(\n `${lcsBaseUrl}/v1/responses?user_id=${encodeURIComponent(userId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(lcsRequest),\n signal: abortController.signal,\n },\n );\n\n // Retry once if conversation not found (orphaned from interrupted query)\n if (\n !response.ok &&\n conversationId &&\n response.status === 404 &&\n retries === 0\n ) {\n logger.warn(`Conversation ${conversationId} not found - retrying`);\n await sessionService.updateSession(\n sessionId,\n userId,\n undefined,\n undefined,\n {\n ...session.metadata,\n conversation_id: null,\n },\n );\n delete lcsRequest.conversation;\n conversationId = null;\n continue;\n }\n\n if (!response.ok) {\n const errorBody = (await response.json()) as any;\n const errorMsg =\n errorBody?.detail?.[0]?.msg ||\n errorBody?.detail?.cause ||\n 'Unknown error';\n const statusCode =\n response.status >= 400 && response.status < 500\n ? response.status\n : HTTP_STATUS_INTERNAL_ERROR;\n res.status(statusCode).json({\n status: 'error',\n error: `Error from Lightspeed Core: ${errorMsg}`,\n });\n return;\n }\n\n if (response.body) {\n const body = Readable.fromWeb(response.body as any);\n const transformStream = createResponsesApiTransform(\n session,\n sessionId,\n userId,\n );\n\n body.on('error', (error: Error) => {\n logger.error(\n `Upstream stream error while processing notebook query: ${error}`,\n );\n if (res.headersSent) {\n res.destroy();\n } else {\n res\n .status(500)\n .json({ status: 'error', error: 'Stream error occurred' });\n }\n abortController.abort();\n transformStream.destroy();\n });\n\n transformStream.on('error', (error: Error) => {\n logger.error(\n `Transform stream error while processing notebook query: ${error}`,\n );\n if (res.headersSent) {\n res.destroy();\n } else {\n res.status(500).json({\n status: 'error',\n error: 'Processing error occurred',\n });\n }\n body.destroy();\n abortController.abort();\n });\n\n res.on('close', () => {\n if (!res.writableFinished) {\n logger.warn(\n 'Client disconnected while processing notebook query',\n );\n abortController.abort();\n body.destroy();\n transformStream.destroy();\n }\n });\n\n body.pipe(transformStream).pipe(res);\n }\n break;\n }\n }),\n );\n\n notebooksRouter.use((err: Error, req: any, res: any, _next: any) =>\n handleError(logger, res, err, req.path),\n );\n\n const router = Router();\n router.use('/notebooks', notebooksRouter);\n return router;\n}\n"],"names":["Router","express","DEFAULT_LIGHTSPEED_SERVICE_PORT","DEFAULT_LIGHTSPEED_SERVICE_HOST","NOTEBOOKS_SYSTEM_PROMPT","VectorStoresOperator","sessionService","SessionService","documentService","DocumentService","userPermissionAuthorization","createRateLimitMiddleware","getIdentity","lightspeedNotebooksUsePermission","handleError","Transform","createIdentityMiddleware","createSessionResponse","createSessionListResponse","createDocumentListResponse","upload","isValidFileType","parseFileContent","HTTP_STATUS_ACCEPTED","createDocumentResponse","MAX_QUERY_LENGTH","EXPRESS_JSON_BODY_LIMIT","MAX_QUERY_RETRIES","HTTP_STATUS_INTERNAL_ERROR","Readable"],"mappings":"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"}
1
+ {"version":3,"file":"notebooksRouters.cjs.js","sources":["../../../src/service/notebooks/notebooksRouters.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n HttpAuthService,\n LoggerService,\n PermissionsService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport type { BasicPermission } from '@backstage/plugin-permission-common';\n\nimport express, { Router } from 'express';\n\nimport {\n iaNotebooksManagePermission,\n iaNotebooksUsePermission,\n} from '@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common';\n\nimport { Readable, Transform } from 'stream';\n\nimport {\n DEFAULT_LIGHTSPEED_SERVICE_HOST,\n DEFAULT_LIGHTSPEED_SERVICE_PORT,\n EXPRESS_JSON_BODY_LIMIT,\n HTTP_STATUS_ACCEPTED,\n HTTP_STATUS_INTERNAL_ERROR,\n MAX_QUERY_LENGTH,\n MAX_QUERY_RETRIES,\n NOTEBOOKS_SYSTEM_PROMPT,\n upload,\n} from '../constant';\nimport { createRateLimitMiddleware } from '../middleware/createRateLimitMiddleware';\nimport {\n createIdentityMiddleware,\n getIdentity,\n} from '../middleware/getIdentity';\nimport { userPermissionAuthorization } from '../permission';\nimport { isValidFileType } from './documents/documentHelpers';\nimport { DocumentService } from './documents/documentService';\nimport { convertToMarkdown } from './documents/markitdownClient';\nimport { SessionService } from './sessions/sessionService';\nimport {\n createDocumentListResponse,\n createDocumentResponse,\n createSessionListResponse,\n createSessionResponse,\n} from './types/notebooksTypes';\nimport { handleError } from './utils';\nimport { VectorStoresOperator } from './VectorStoresOperator';\n\nexport interface NotebooksRouterOptions {\n logger: LoggerService;\n config: Config;\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n permissions: PermissionsService;\n}\n\nexport async function createNotebooksRouter(\n options: NotebooksRouterOptions,\n): Promise<Router> {\n const { logger, config, httpAuth, userInfo, permissions } = options;\n const notebooksRouter = Router();\n notebooksRouter.use(express.json());\n\n const lightSpeedPort =\n config.getOptionalNumber('intelligent-assistant.servicePort') ??\n DEFAULT_LIGHTSPEED_SERVICE_PORT;\n const lcsBaseUrl = `http://${DEFAULT_LIGHTSPEED_SERVICE_HOST}:${lightSpeedPort}`;\n const queryModel = config.getString(\n 'intelligent-assistant.notebooks.queryDefaults.model',\n );\n const queryProvider = config.getString(\n 'intelligent-assistant.notebooks.queryDefaults.provider_id',\n );\n const systemPrompt = NOTEBOOKS_SYSTEM_PROMPT;\n\n logger.info(`AI Notebooks connecting to Lightspeed-Core at ${lcsBaseUrl}`);\n\n const vectorStoresOperator = VectorStoresOperator.getInstance(\n lcsBaseUrl,\n logger,\n );\n const sessionService = new SessionService(vectorStoresOperator, logger);\n const documentService = new DocumentService(\n vectorStoresOperator,\n logger,\n config,\n );\n\n const authorizer = userPermissionAuthorization(permissions);\n\n const expensiveRateLimiter = createRateLimitMiddleware(\n config,\n 'expensive',\n logger,\n );\n const generalRateLimiter = createRateLimitMiddleware(\n config,\n 'general',\n logger,\n );\n\n const requirePermission =\n (permission: BasicPermission) =>\n async (req: any, res: any, next: any): Promise<void> => {\n try {\n const { credentials } = getIdentity(req);\n await authorizer.authorizeUser(permission, credentials);\n next();\n } catch (error) {\n handleError(logger, res, error, 'Permission denied');\n }\n };\n\n const requireSessionOwnership =\n () => async (req: any, res: any, next: any) => {\n try {\n const { userEntityRef } = getIdentity(req);\n const { sessionId } = req.params;\n await sessionService.readSession(sessionId, userEntityRef);\n next();\n } catch (error) {\n handleError(\n logger,\n res,\n error,\n 'Session ownership verification failed',\n );\n }\n };\n\n const withAuth =\n (handler: (req: any, res: any, userId: string) => Promise<void>) =>\n async (req: any, res: any, next: any) => {\n try {\n const { userEntityRef } = getIdentity(req);\n await handler(req, res, userEntityRef);\n } catch (error) {\n next(error);\n }\n };\n\n /**\n * Transforms Responses API SSE (event:/data: lines) into the legacy\n * streaming format that the frontend useConversationMessages hook expects:\n * data: {\"event\": \"<type>\", \"data\": {...}}\\n\\n\n *\n * Also captures the conversation_id from the first response.created event\n * and persists it on the session when it is new.\n */\n const createResponsesApiTransform = (\n session: any,\n sessionId: string,\n userId: string,\n ) => {\n let buffer = '';\n let conversationCaptured = !!session.metadata?.conversation_id;\n\n return new Transform({\n transform(chunk: any, _encoding: any, callback: any) {\n buffer += chunk.toString();\n\n const blocks = buffer.split('\\n\\n');\n buffer = blocks.pop()!;\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const lines = block.split('\\n');\n let eventType = '';\n let dataLine = '';\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n eventType = line.slice(7).trim();\n } else if (line.startsWith('data: ')) {\n dataLine = line.slice(6).trim();\n }\n }\n\n if (dataLine === '[DONE]') {\n this.push('data: [DONE]\\n\\n');\n continue;\n }\n\n if (!dataLine) continue;\n\n let parsed: any;\n try {\n parsed = JSON.parse(dataLine);\n } catch {\n continue;\n }\n\n if (eventType === 'response.created') {\n const convId = parsed?.response?.conversation;\n const requestId = parsed?.response?.id;\n\n if (convId && !conversationCaptured) {\n conversationCaptured = true;\n logger.info(`Captured conversation ID: ${convId}`);\n sessionService\n .updateSession(sessionId, userId, undefined, undefined, {\n ...session.metadata,\n conversation_id: convId,\n })\n .catch((err: any) =>\n logger.error(`Failed to update session: ${err}`),\n );\n }\n\n const legacy = {\n event: 'start',\n data: { conversation_id: convId, request_id: requestId },\n };\n this.push(`data: ${JSON.stringify(legacy)}\\n\\n`);\n } else if (eventType === 'response.output_text.delta') {\n const legacy = {\n event: 'token',\n data: { token: parsed?.delta ?? '' },\n };\n this.push(`data: ${JSON.stringify(legacy)}\\n\\n`);\n } else if (eventType === 'response.completed') {\n // Log the full response to see what we're getting\n logger.info(\n `Full response.completed event: ${JSON.stringify(parsed?.response, null, 2)}`,\n );\n\n // Extract citations/sources from tool calls (file_search results)\n\n // this.push(`data: ${JSON.stringify(legacy)}\\n\\n`);\n } else {\n // Log unhandled event types to help identify what we're missing\n logger.debug(`Unhandled SSE event type: ${eventType}`, parsed);\n }\n }\n\n callback();\n },\n\n flush(callback: any) {\n if (buffer.trim()) {\n const lines = buffer.split('\\n');\n let dataLine = '';\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n dataLine = line.slice(6).trim();\n }\n }\n if (dataLine === '[DONE]') {\n this.push('data: [DONE]\\n\\n');\n }\n }\n callback();\n },\n });\n };\n\n notebooksRouter.get('/health', (_req, res) => res.json({ status: 'ok' }));\n notebooksRouter.use(\n '/v1',\n createIdentityMiddleware(httpAuth, userInfo, logger),\n );\n\n notebooksRouter.post(\n '/v1/sessions',\n generalRateLimiter,\n requirePermission(iaNotebooksUsePermission),\n withAuth(async (req, res, userId) => {\n const { name, description, metadata } = req.body;\n if (!name) {\n handleError(logger, res, 'name is required');\n return;\n }\n const session = await sessionService.createSession(\n userId,\n name,\n description,\n { ...metadata, conversation_id: null },\n );\n res.json(createSessionResponse(session, 'Session created successfully'));\n }),\n );\n\n notebooksRouter.get(\n '/v1/sessions',\n generalRateLimiter,\n requirePermission(iaNotebooksUsePermission),\n withAuth(async (_req, res, userId) => {\n const sessions = await sessionService.listSessions(userId);\n res.json(createSessionListResponse(sessions));\n }),\n );\n\n notebooksRouter.get(\n '/v1/sessions/:sessionId',\n generalRateLimiter,\n requirePermission(iaNotebooksUsePermission),\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n const session = await sessionService.readSession(sessionId, userId);\n res.json(\n createSessionResponse(session, 'Session retrieved successfully'),\n );\n }),\n );\n\n notebooksRouter.put(\n '/v1/sessions/:sessionId',\n generalRateLimiter,\n requirePermission(iaNotebooksManagePermission),\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n const { name, description, metadata } = req.body;\n const session = await sessionService.updateSession(\n sessionId,\n userId,\n name,\n description,\n metadata,\n );\n res.json(createSessionResponse(session, 'Session updated successfully'));\n }),\n );\n\n notebooksRouter.delete(\n '/v1/sessions/:sessionId',\n generalRateLimiter,\n requirePermission(iaNotebooksManagePermission),\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n await sessionService.deleteSession(sessionId, userId);\n res.json(\n createSessionResponse(\n { session_id: sessionId } as any,\n 'Session deleted successfully',\n ),\n );\n }),\n );\n\n notebooksRouter.get(\n '/v1/sessions/:sessionId/documents',\n generalRateLimiter,\n requirePermission(iaNotebooksUsePermission),\n requireSessionOwnership(),\n withAuth(async (req, res) => {\n const { sessionId } = req.params;\n const fileType = req.query.fileType as string | undefined;\n const documents = await documentService.listDocuments(\n sessionId,\n fileType,\n );\n res.json(createDocumentListResponse(sessionId, documents));\n }),\n );\n\n notebooksRouter.put(\n '/v1/sessions/:sessionId/documents',\n expensiveRateLimiter,\n requirePermission(iaNotebooksUsePermission),\n upload.single('file') as any,\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n const { fileType, title, newTitle } = req.body;\n\n if (!title) {\n handleError(logger, res, 'title is required');\n return;\n }\n\n if (!fileType || !isValidFileType(fileType)) {\n handleError(\n logger,\n res,\n `Unsupported file type: ${fileType}. Supported types: md, txt, pdf, json, yaml, yml, log`,\n );\n return;\n }\n\n const session = await sessionService.readSession(sessionId, userId);\n if (!session) {\n handleError(logger, res, 'Session not found');\n return;\n }\n\n if (!req.file) {\n handleError(logger, res, 'No file uploaded');\n return;\n }\n\n const markdown = await convertToMarkdown(\n req.file.buffer,\n req.file.originalname,\n fileType,\n );\n const fileId = await documentService.uploadFile(markdown, title);\n\n res.status(HTTP_STATUS_ACCEPTED).json({\n status: 'processing',\n document_id: newTitle || title,\n session_id: sessionId,\n message: 'Resource upload started',\n });\n\n // Attach file to vector store in background\n const docName = newTitle || title;\n documentService\n .upsertDocument(sessionId, title, { fileType, fileId, newTitle })\n .then(() => logger.info(`Background upload succeeded: ${docName}`))\n .catch((err: any) =>\n logger.error(`Background upload failed: ${docName}`, err),\n );\n }),\n );\n\n notebooksRouter.get(\n '/v1/sessions/:sessionId/documents/:documentId/status',\n generalRateLimiter,\n requirePermission(iaNotebooksUsePermission),\n requireSessionOwnership(),\n withAuth(async (req, res) => {\n const { sessionId, documentId } = req.params;\n const fileStatus = await documentService.getFileStatus(\n sessionId,\n documentId,\n );\n res.json({\n status: fileStatus.status,\n document_id: documentId,\n session_id: sessionId,\n ...(fileStatus.error && { error: fileStatus.error }),\n });\n }),\n );\n\n notebooksRouter.patch(\n '/v1/sessions/:sessionId/documents/:documentId',\n generalRateLimiter,\n requirePermission(iaNotebooksManagePermission),\n requireSessionOwnership(),\n withAuth(async (req, res) => {\n const { sessionId, documentId } = req.params;\n const { title } = req.body;\n\n if (!title || typeof title !== 'string' || !title.trim()) {\n handleError(logger, res, 'title is required');\n return;\n }\n\n const MAX_TITLE_LENGTH = 255;\n if (title.trim().length > MAX_TITLE_LENGTH) {\n handleError(\n logger,\n res,\n `title must be ${MAX_TITLE_LENGTH} characters or less`,\n );\n return;\n }\n\n await documentService.upsertDocument(sessionId, documentId, {\n newTitle: title.trim(),\n });\n res.json(\n createDocumentResponse(\n title.trim(),\n sessionId,\n 'Document renamed successfully',\n ),\n );\n }),\n );\n\n notebooksRouter.delete(\n '/v1/sessions/:sessionId/documents/:documentId',\n generalRateLimiter,\n requirePermission(iaNotebooksManagePermission),\n requireSessionOwnership(),\n withAuth(async (req, res) => {\n const { sessionId, documentId } = req.params;\n await documentService.deleteDocument(sessionId, documentId);\n res.json(\n createDocumentResponse(\n documentId,\n sessionId,\n 'Resource deleted successfully',\n ),\n );\n }),\n );\n\n const validateNotebooksQuery = (query: unknown): string | null => {\n if (!query) return 'query is required';\n if (typeof query === 'string' && query.length > MAX_QUERY_LENGTH) {\n return `query exceeds maximum length of ${MAX_QUERY_LENGTH} characters`;\n }\n return null;\n };\n\n notebooksRouter.post(\n '/v1/sessions/:sessionId/query',\n expensiveRateLimiter,\n requirePermission(iaNotebooksUsePermission),\n express.json({ limit: EXPRESS_JSON_BODY_LIMIT }),\n withAuth(async (req, res, userId) => {\n const { sessionId } = req.params;\n const { query } = req.body;\n\n const queryError = validateNotebooksQuery(query);\n if (queryError) {\n handleError(logger, res, queryError);\n return;\n }\n\n const session = await sessionService.readSession(sessionId, userId);\n let conversationId = session.metadata?.conversation_id;\n\n const lcsRequest: any = {\n input: query,\n instructions: systemPrompt,\n tools: [{ type: 'file_search', vector_store_ids: [sessionId] }],\n tool_choice: 'required',\n model: `${queryProvider}/${queryModel}`,\n stream: true,\n temperature: 0.35,\n shield_ids: [],\n max_tool_calls: 15,\n ...(conversationId && { conversation: conversationId }),\n };\n\n for (let retries = 0; retries <= MAX_QUERY_RETRIES; retries++) {\n const abortController = new AbortController();\n\n const response = await fetch(\n `${lcsBaseUrl}/v1/responses?user_id=${encodeURIComponent(userId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(lcsRequest),\n signal: abortController.signal,\n },\n );\n\n // Retry once if conversation not found (orphaned from interrupted query)\n if (\n !response.ok &&\n conversationId &&\n response.status === 404 &&\n retries === 0\n ) {\n logger.warn(`Conversation ${conversationId} not found - retrying`);\n await sessionService.updateSession(\n sessionId,\n userId,\n undefined,\n undefined,\n {\n ...session.metadata,\n conversation_id: null,\n },\n );\n delete lcsRequest.conversation;\n conversationId = null;\n continue;\n }\n\n if (!response.ok) {\n const errorBody = (await response.json()) as any;\n const errorMsg =\n errorBody?.detail?.[0]?.msg ||\n errorBody?.detail?.cause ||\n 'Unknown error';\n const statusCode =\n response.status >= 400 && response.status < 500\n ? response.status\n : HTTP_STATUS_INTERNAL_ERROR;\n res.status(statusCode).json({\n status: 'error',\n error: `Error from Lightspeed Core: ${errorMsg}`,\n });\n return;\n }\n\n if (response.body) {\n const body = Readable.fromWeb(response.body as any);\n const transformStream = createResponsesApiTransform(\n session,\n sessionId,\n userId,\n );\n\n body.on('error', (error: Error) => {\n logger.error(\n `Upstream stream error while processing notebook query: ${error}`,\n );\n if (res.headersSent) {\n res.destroy();\n } else {\n res\n .status(500)\n .json({ status: 'error', error: 'Stream error occurred' });\n }\n abortController.abort();\n transformStream.destroy();\n });\n\n transformStream.on('error', (error: Error) => {\n logger.error(\n `Transform stream error while processing notebook query: ${error}`,\n );\n if (res.headersSent) {\n res.destroy();\n } else {\n res.status(500).json({\n status: 'error',\n error: 'Processing error occurred',\n });\n }\n body.destroy();\n abortController.abort();\n });\n\n res.on('close', () => {\n if (!res.writableFinished) {\n logger.warn(\n 'Client disconnected while processing notebook query',\n );\n abortController.abort();\n body.destroy();\n transformStream.destroy();\n }\n });\n\n body.pipe(transformStream).pipe(res);\n }\n break;\n }\n }),\n );\n\n notebooksRouter.use((err: Error, req: any, res: any, _next: any) =>\n handleError(logger, res, err, req.path),\n );\n\n const router = Router();\n router.use('/notebooks', notebooksRouter);\n return router;\n}\n"],"names":["Router","express","DEFAULT_LIGHTSPEED_SERVICE_PORT","DEFAULT_LIGHTSPEED_SERVICE_HOST","NOTEBOOKS_SYSTEM_PROMPT","VectorStoresOperator","sessionService","SessionService","documentService","DocumentService","userPermissionAuthorization","createRateLimitMiddleware","getIdentity","handleError","Transform","createIdentityMiddleware","iaNotebooksUsePermission","createSessionResponse","createSessionListResponse","iaNotebooksManagePermission","createDocumentListResponse","upload","isValidFileType","convertToMarkdown","HTTP_STATUS_ACCEPTED","createDocumentResponse","MAX_QUERY_LENGTH","EXPRESS_JSON_BODY_LIMIT","MAX_QUERY_RETRIES","HTTP_STATUS_INTERNAL_ERROR","Readable"],"mappings":"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"}
@@ -138,7 +138,7 @@ async function createRouter(options) {
138
138
  response.json({ status: "ok" });
139
139
  });
140
140
  const permissionIntegrationRouter = pluginPermissionNode.createPermissionIntegrationRouter({
141
- permissions: backstagePluginIntelligentAssistantCommon.lightspeedPermissions
141
+ permissions: backstagePluginIntelligentAssistantCommon.iaPermissions
142
142
  });
143
143
  router.use(permissionIntegrationRouter);
144
144
  const identityMiddleware = getIdentity.createIdentityMiddleware(
@@ -169,7 +169,7 @@ async function createRouter(options) {
169
169
  router.get(
170
170
  "/mcp-servers",
171
171
  generalRateLimiter,
172
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedMcpReadPermission),
172
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaMcpUsePermission),
173
173
  async (req, res) => {
174
174
  try {
175
175
  const { userEntityRef } = getIdentity.getIdentity(req);
@@ -204,7 +204,7 @@ async function createRouter(options) {
204
204
  router.post(
205
205
  "/mcp-servers/validate",
206
206
  generalRateLimiter,
207
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedMcpReadPermission),
207
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaMcpUsePermission),
208
208
  async (req, res) => {
209
209
  try {
210
210
  const { url, token } = req.body;
@@ -234,7 +234,7 @@ async function createRouter(options) {
234
234
  router.post(
235
235
  "/mcp-servers/:name/validate",
236
236
  generalRateLimiter,
237
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedMcpManagePermission),
237
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaMcpManagePermission),
238
238
  async (req, res) => {
239
239
  try {
240
240
  const { userEntityRef, credentials } = getIdentity.getIdentity(req);
@@ -306,7 +306,7 @@ async function createRouter(options) {
306
306
  router.patch(
307
307
  "/mcp-servers/:name",
308
308
  generalRateLimiter,
309
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedMcpManagePermission),
309
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaMcpManagePermission),
310
310
  async (req, res) => {
311
311
  try {
312
312
  const { userEntityRef } = getIdentity.getIdentity(req);
@@ -380,6 +380,7 @@ async function createRouter(options) {
380
380
  router.get(
381
381
  "/notebook-conversation-ids",
382
382
  generalRateLimiter,
383
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
383
384
  async (req, res) => {
384
385
  try {
385
386
  const { userEntityRef } = getIdentity.getIdentity(req);
@@ -410,62 +411,68 @@ async function createRouter(options) {
410
411
  router.get(
411
412
  "/v1/models",
412
413
  generalRateLimiter,
413
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatReadPermission),
414
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatAccessPermission),
414
415
  apiProxy
415
416
  );
416
417
  router.get(
417
418
  "/v1/shields",
418
419
  generalRateLimiter,
419
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatReadPermission),
420
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatAccessPermission),
420
421
  apiProxy
421
422
  );
422
423
  router.get(
423
424
  "/v2/conversations",
424
425
  generalRateLimiter,
425
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatReadPermission),
426
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatAccessPermission),
426
427
  apiProxy
427
428
  );
428
429
  router.get(
429
430
  "/v2/conversations/:conversation_id",
430
431
  generalRateLimiter,
431
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatReadPermission),
432
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatAccessPermission),
432
433
  apiProxy
433
434
  );
434
435
  router.delete(
435
436
  "/v2/conversations/:conversation_id",
436
437
  generalRateLimiter,
437
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatDeletePermission),
438
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatManagePermission),
438
439
  apiProxy
439
440
  );
440
441
  router.get(
441
442
  "/v1/feedback/status",
442
443
  generalRateLimiter,
443
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatReadPermission),
444
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatAccessPermission),
444
445
  apiProxy
445
446
  );
446
447
  router.get(
447
448
  "/v1/saved-prompts/config",
448
449
  generalRateLimiter,
449
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedSavedPromptsManagePermission),
450
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatUsePermission),
450
451
  apiProxy
451
452
  // SKIP_USER_ID_ENDPOINTS prevents user_id injection for this endpoint
452
453
  );
453
454
  router.get(
454
455
  "/v1/saved-prompts",
455
456
  generalRateLimiter,
456
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedSavedPromptsManagePermission),
457
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatUsePermission),
457
458
  apiProxy
458
459
  );
459
460
  router.delete(
460
461
  "/v1/saved-prompts/:prompt_id",
461
462
  generalRateLimiter,
462
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedSavedPromptsManagePermission),
463
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatUsePermission),
464
+ apiProxy
465
+ );
466
+ router.get(
467
+ "/v1/skills",
468
+ generalRateLimiter,
469
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaSkillsAccessPermission),
463
470
  apiProxy
464
471
  );
465
472
  router.post(
466
473
  "/v1/feedback",
467
474
  generalRateLimiter,
468
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatCreatePermission),
475
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatUsePermission),
469
476
  async (request, response) => {
470
477
  try {
471
478
  const { userEntityRef } = getIdentity.getIdentity(request);
@@ -503,7 +510,7 @@ async function createRouter(options) {
503
510
  router.post(
504
511
  "/v1/saved-prompts",
505
512
  generalRateLimiter,
506
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedSavedPromptsManagePermission),
513
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatUsePermission),
507
514
  async (request, response) => {
508
515
  try {
509
516
  const { userEntityRef } = getIdentity.getIdentity(request);
@@ -543,7 +550,7 @@ async function createRouter(options) {
543
550
  router.post(
544
551
  "/v1/query/interrupt",
545
552
  generalRateLimiter,
546
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatCreatePermission),
553
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatUsePermission),
547
554
  async (request, response) => {
548
555
  try {
549
556
  const { userEntityRef } = getIdentity.getIdentity(request);
@@ -582,7 +589,7 @@ async function createRouter(options) {
582
589
  expensiveRateLimiter,
583
590
  validation.validateCompletionsRequest,
584
591
  validation.validateAttachmentsForModel,
585
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatCreatePermission),
592
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatUsePermission),
586
593
  async (request, response) => {
587
594
  const { provider } = request.body;
588
595
  try {
@@ -659,7 +666,7 @@ async function createRouter(options) {
659
666
  router.put(
660
667
  "/v2/conversations/:conversation_id",
661
668
  generalRateLimiter,
662
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatUpdatePermission),
669
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatManagePermission),
663
670
  async (request, response) => {
664
671
  try {
665
672
  const { userEntityRef } = getIdentity.getIdentity(request);
@@ -697,7 +704,7 @@ async function createRouter(options) {
697
704
  router.post(
698
705
  "/v1/validate-model-vision",
699
706
  generalRateLimiter,
700
- requirePermission(backstagePluginIntelligentAssistantCommon.lightspeedChatReadPermission),
707
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaChatUsePermission),
701
708
  async (request, response) => {
702
709
  const { model, provider } = request.body;
703
710
  if (typeof model !== "string" || !model.trim() || typeof provider !== "string" || !provider.trim()) {
@@ -745,18 +752,6 @@ async function createRouter(options) {
745
752
  if (testResponse.ok) {
746
753
  attachmentValidation.ModelCapabilitiesCache.set(cacheKey, true);
747
754
  response.json({ model, provider, supportsVision: true });
748
- } else if (testResponse.status >= 500) {
749
- logger.warn(
750
- `Vision test for ${cacheKey}: ${testResponse.status} ${testResponse.statusText}, not caching`
751
- );
752
- response.status(502).json({
753
- error: `Unable to verify vision support for model \u2014 upstream returned ${testResponse.status}`,
754
- model,
755
- provider
756
- });
757
- } else {
758
- attachmentValidation.ModelCapabilitiesCache.set(cacheKey, false);
759
- response.json({ model, provider, supportsVision: false });
760
755
  }
761
756
  } catch (error) {
762
757
  logger.error(`Vision test error for ${cacheKey}:`, error);