@red-hat-developer-hub/backstage-plugin-intelligent-assistant-backend 3.2.0 → 4.0.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,77 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-intelligent-assistant-backend
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - adb65c9: Breaking changes to MCP permissions using behavior-linked vocabulary rather than CRUD-linked vocabulary:
8
+
9
+ | Before (Lightspeed) | Before (Intelligent Assistant) | After |
10
+ | ----------------------- | ---------------------------------- | ------------------ |
11
+ | `lightspeed.mcp.read` | `intelligent-assistant.mcp.read` | `mcp.tools.use` |
12
+ | `lightspeed.mcp.manage` | `intelligent-assistant.mcp.manage` | `mcp.tools.manage` |
13
+
14
+ Removed permission CRUD action attributes; RBAC entries for these permission sets now use the generic `use` action.
15
+
16
+ Permission variable renamed from `iaMcpReadPermission` to `iaMcpUsePermission`; `iaMcpManagePermission` keeps its name.
17
+
18
+ Plugin documentation and example RBAC policy CSV updated to reflect the new MCP permission names.
19
+
20
+ - 0ed3adc: Breaking changes to the notebooks permissions model that uses behavior-linked vocabulary:
21
+
22
+ | Before (Lightspeed) | Before (Intelligent Assistant) | After |
23
+ | -------------------------- | ------------------------------------- | ---------------------------------------- |
24
+ | `lightspeed.notebooks.use` | `intelligent-assistant.notebooks.use` | `intelligent-assistant.notebooks.use` |
25
+ | | | `intelligent-assistant.notebooks.manage` |
26
+ - `notebooks.use` covers list/read/create session, upload document, and query endpoints
27
+ - `notebooks.manage` covers update/delete session and document endpoints
28
+
29
+ Removed permission CRUD action attributes; RBAC entries for notebooks permission sets now use the generic `use` action.
30
+
31
+ Hard-coded permission names were replaced by constants from the permission entities.
32
+
33
+ Plugin documentation and example RBAC policy CSV updated to reflect the notebooks permission model.
34
+
35
+ - f1dba9b: Breaking changes to the permissions model that uses behavior-linked vocabulary rather than CRUD-linked vocabulary:
36
+
37
+ | Before (Lightspeed) | Before (Intelligent Assistant) | After |
38
+ | ------------------------ | ----------------------------------- | ----------------------------------- |
39
+ | `lightspeed.chat.read` | `intelligent-assistant.chat.read` | `intelligent-assistant.chat.access` |
40
+ | `lightspeed.chat.create` | `intelligent-assistant.chat.create` | `intelligent-assistant.chat.use` |
41
+ | `lightspeed.chat.delete` | `intelligent-assistant.chat.delete` | `intelligent-assistant.chat.manage` |
42
+ | `lightspeed.chat.update` | `intelligent-assistant.chat.update` | `intelligent-assistant.chat.manage` |
43
+
44
+ Changes are applied to `lightspeed` (Frontend), `lightspeed-backend`, and `lightspeed-common` plugins.
45
+
46
+ Removed permission CRUD action attributes, rbac entries for permission sets now to generic 'use' action, allows `intelligent-assistant.chat.manage` to combine the update and delete actions.
47
+
48
+ Any hard-coded permission names have been replaced by constants, source references permission names from the permission entities.
49
+
50
+ `Trans.test.tsx` component test unit has permission names to reflect Intelligent Assistant for RHDH.
51
+
52
+ Additionally, hard-coded permission names have been replaced by local constants with the new names set.
53
+
54
+ Plugin documentation changes to revise information to permissions model changes to Intelligent Assistant for RHDH.
55
+
56
+ Changed permission variable 'lightspeed' prefix to 'ia' to use Intelligent Assistant rebranding.
57
+
58
+ Changes to example RBAC policy CSV file to reflect Intelligent Assistant for RHDH.
59
+
60
+ ### Minor Changes
61
+
62
+ - e996529: Add inline rename for notebook resources with click or kebab menu, optimistic updates with rollback, frontend conflict validation, and backend PATCH endpoint with rollback on failure
63
+ - 0f32982: Deep context inteeligent-assistant model vision verification for 500 is not cached anymore
64
+ - 3d1d7d7: introduced new endpoint to proxy to LCORE /v1/skills endpoint, to be able to list available skills. also the backend endpoint will be gated by the new rbac permission: intelligent-assistant.skills.access
65
+
66
+ ### Patch Changes
67
+
68
+ - 82742f0: Unify notebook terminology from "document" to "resource" across all UI strings, translations, and backend messages.
69
+ - Updated dependencies [3d1d7d7]
70
+ - Updated dependencies [adb65c9]
71
+ - Updated dependencies [0ed3adc]
72
+ - Updated dependencies [f1dba9b]
73
+ - @red-hat-developer-hub/backstage-plugin-intelligent-assistant-common@4.0.0
74
+
3
75
  ## 3.2.0
4
76
 
5
77
  ### Minor Changes
package/README.md CHANGED
@@ -81,15 +81,16 @@ All nested keys (`servicePort`, `systemPrompt`, `prompts`, `mcpServers`, `notebo
81
81
 
82
82
  Update permission names in your `rbac-policy.csv`:
83
83
 
84
- | Before | After |
85
- | -------------------------- | ------------------------------------- |
86
- | `lightspeed.chat.read` | `intelligent-assistant.chat.read` |
87
- | `lightspeed.chat.create` | `intelligent-assistant.chat.create` |
88
- | `lightspeed.chat.delete` | `intelligent-assistant.chat.delete` |
89
- | `lightspeed.chat.update` | `intelligent-assistant.chat.update` |
90
- | `lightspeed.notebooks.use` | `intelligent-assistant.notebooks.use` |
91
- | `lightspeed.mcp.read` | `intelligent-assistant.mcp.read` |
92
- | `lightspeed.mcp.manage` | `intelligent-assistant.mcp.manage` |
84
+ | Before | After |
85
+ | -------------------------- | ---------------------------------------- |
86
+ | `lightspeed.chat.read` | `intelligent-assistant.chat.access` |
87
+ | `lightspeed.chat.create` | `intelligent-assistant.chat.use` |
88
+ | `lightspeed.chat.delete` | `intelligent-assistant.chat.manage` |
89
+ | `lightspeed.chat.update` | `intelligent-assistant.chat.manage` |
90
+ | `lightspeed.notebooks.use` | `intelligent-assistant.notebooks.use` |
91
+ | | `intelligent-assistant.notebooks.manage` |
92
+ | `lightspeed.mcp.read` | `mcp.tools.use` |
93
+ | `lightspeed.mcp.manage` | `mcp.tools.manage` |
93
94
 
94
95
  #### 5. OFS dynamic plugin configuration
95
96
 
@@ -332,17 +333,17 @@ The Intelligent Assistant Backend plugin has support for the permission framewor
332
333
  - When [RBAC permission](https://github.com/backstage/community-plugins/tree/main/workspaces/rbac/plugins/rbac-backend#installation) framework is enabled, for non-admin users to access intelligent-assistant backend API, the role associated with your user should have the following permission policies associated with it. Add the following in your permission policies configuration file named `rbac-policy.csv`:
333
334
 
334
335
  ```CSV
335
- p, role:default/team_a, intelligent-assistant.chat.read, read, allow
336
- p, role:default/team_a, intelligent-assistant.chat.create, create, allow
337
- p, role:default/team_a, intelligent-assistant.chat.delete, delete, allow
338
- p, role:default/team_a, intelligent-assistant.chat.update, update, allow
336
+ p, role:default/team_a, intelligent-assistant.chat.access, use, allow
337
+ p, role:default/team_a, intelligent-assistant.chat.use, use, allow
338
+ p, role:default/team_a, intelligent-assistant.chat.manage, use, allow
339
339
 
340
340
  # Required for Notebooks feature (if enabled)
341
- p, role:default/team_a, intelligent-assistant.notebooks.use, update, allow
341
+ p, role:default/team_a, intelligent-assistant.notebooks.use, use, allow
342
+ p, role:default/team_a, intelligent-assistant.notebooks.manage, use, allow
342
343
 
343
344
  # Required for MCP server management (if configured)
344
- p, role:default/team_a, intelligent-assistant.mcp.read, read, allow
345
- p, role:default/team_a, intelligent-assistant.mcp.manage, update, allow
345
+ p, role:default/team_a, mcp.tools.use, use, allow
346
+ p, role:default/team_a, mcp.tools.manage, use, allow
346
347
 
347
348
  # Required for saved prompts
348
349
  p, role:default/team_a, intelligent-assistant.saved-prompts.manage, update, allow
@@ -449,6 +450,7 @@ When enabled, Notebooks exposes the following REST API endpoints:
449
450
  - `PUT /intelligent-assistant/notebooks/v1/sessions/:sessionId/documents` - Upload or update a document (multipart/form-data)
450
451
  - `GET /intelligent-assistant/notebooks/v1/sessions/:sessionId/documents` - List all documents in a session
451
452
  - `GET /intelligent-assistant/notebooks/v1/sessions/:sessionId/documents/:documentId/status` - Get document processing status
453
+ - `PATCH /intelligent-assistant/notebooks/v1/sessions/:sessionId/documents/:documentId` - Rename a document (JSON body: `{ "title": "new name" }`)
452
454
  - `DELETE /intelligent-assistant/notebooks/v1/sessions/:sessionId/documents/:documentId` - Delete a document
453
455
 
454
456
  - **Queries**:
@@ -457,16 +459,19 @@ When enabled, Notebooks exposes the following REST API endpoints:
457
459
  **Notes**:
458
460
 
459
461
  - All endpoints require authentication (user context is automatically provided by Backstage)
460
- - All `/v1/*` endpoints require the `intelligent-assistant.notebooks.use` permission
462
+ - All `/v1/*` endpoints require notebooks permissions:
463
+ - `intelligent-assistant.notebooks.use` for list/read/create session, upload document, and query endpoints
464
+ - `intelligent-assistant.notebooks.manage` for update/delete session and document endpoints
461
465
  - Document endpoints verify session ownership before allowing operations
462
466
  - `documentId` in paths is the document title (URL-encoded for special characters)
463
467
 
464
468
  #### Permission Framework Support for Notebooks
465
469
 
466
- When RBAC is enabled, users need the following permission to use Notebooks:
470
+ When RBAC is enabled, users need the following permissions to use Notebooks:
467
471
 
468
472
  ```CSV
469
- p, role:default/team_a, intelligent-assistant.notebooks.use, update, allow
473
+ p, role:default/team_a, intelligent-assistant.notebooks.use, use, allow
474
+ p, role:default/team_a, intelligent-assistant.notebooks.manage, use, allow
470
475
 
471
476
  g, user:default/<your-user-name>, role:default/team_a
472
477
  ```
@@ -71,51 +71,93 @@ class DocumentService {
71
71
  }
72
72
  }
73
73
  /**
74
- * Upsert a document - create if it doesn't exist, update if it does
74
+ * Upsert a document - create if it doesn't exist, update if it does.
75
+ * Also used for rename-only operations when fileType/fileId are omitted.
75
76
  * @param sessionId - Vector store ID
76
77
  * @param title - Original document title
77
- * @param fileType - Document source type (text, pdf, url, etc.)
78
- * @param fileId - File ID from Files API
79
- * @param newTitle - New title for rename operation (optional)
78
+ * @param opts - Optional parameters for upload or rename
79
+ * @param opts.fileType - Document source type (derived from existing file when omitted)
80
+ * @param opts.fileId - File ID from Files API (derived from existing file when omitted)
81
+ * @param opts.newTitle - New title for rename operation
80
82
  * @returns Upsert result with document ID and status
83
+ * @throws NotFoundError if fileId is omitted and document does not exist
81
84
  * @throws ConflictError if newTitle conflicts with existing document
82
85
  */
83
- async upsertDocument(sessionId, title, fileType, fileId, newTitle) {
86
+ async upsertDocument(sessionId, title, opts) {
87
+ const { fileType, fileId, newTitle } = opts || {};
84
88
  const existingFile = await this.findFileByTitle(sessionId, title);
89
+ let resolvedFileId;
90
+ let resolvedFileType;
91
+ if (fileId) {
92
+ resolvedFileId = fileId;
93
+ resolvedFileType = fileType || "unknown";
94
+ } else {
95
+ if (!existingFile) {
96
+ throw new errors.NotFoundError(`Document not found: ${title}`);
97
+ }
98
+ resolvedFileId = existingFile.id;
99
+ resolvedFileType = fileType || existingFile.attributes?.source_type || "unknown";
100
+ }
85
101
  const createdAt = existingFile?.attributes?.created_at || (/* @__PURE__ */ new Date()).toISOString();
86
102
  if (newTitle && title !== newTitle) {
87
103
  const conflictingFile = await this.findFileByTitle(sessionId, newTitle);
88
104
  if (conflictingFile) {
89
105
  throw new errors.ConflictError(
90
- `A document with the title "${newTitle || title}" already exists in this session`
106
+ `A resource with the title "${newTitle || title}" already exists in this session`
91
107
  );
92
108
  }
93
109
  }
94
110
  if (existingFile) {
95
111
  await this.deleteDocument(sessionId, title);
96
112
  }
97
- const vectorStoreFile = await this.client.vectorStores.files.create(
98
- sessionId,
99
- {
100
- file_id: fileId,
101
- chunking_strategy: this.chunkingStrategy,
102
- attributes: {
103
- title: newTitle || title,
104
- source_type: fileType,
105
- created_at: createdAt,
106
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
113
+ const baseAttrs = existingFile?.attributes || {};
114
+ const attributes = {
115
+ ...baseAttrs,
116
+ title: newTitle || title,
117
+ source_type: resolvedFileType,
118
+ created_at: createdAt,
119
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
120
+ };
121
+ try {
122
+ const vectorStoreFile = await this.client.vectorStores.files.create(
123
+ sessionId,
124
+ {
125
+ file_id: resolvedFileId,
126
+ chunking_strategy: this.chunkingStrategy,
127
+ attributes
128
+ }
129
+ );
130
+ this.logger.info(
131
+ `Document "${newTitle || title}" (ID: ${title}) upsert started with file ${resolvedFileId}`
132
+ );
133
+ return {
134
+ document_id: newTitle || title,
135
+ file_id: resolvedFileId,
136
+ replaced: !!existingFile,
137
+ status: vectorStoreFile.status
138
+ };
139
+ } catch (error) {
140
+ if (existingFile) {
141
+ this.logger.error(
142
+ `Failed to re-create vector store entry after delete for "${title}". Attempting rollback.`
143
+ );
144
+ try {
145
+ await this.client.vectorStores.files.create(sessionId, {
146
+ file_id: existingFile.id,
147
+ chunking_strategy: this.chunkingStrategy,
148
+ attributes: existingFile.attributes || {}
149
+ });
150
+ this.logger.info(
151
+ `Rollback succeeded: restored "${title}" in session ${sessionId}`
152
+ );
153
+ } catch (rollbackError) {
154
+ this.logger.error(
155
+ `Rollback failed: document "${title}" (file ${existingFile.id}) is orphaned in session ${sessionId}`
156
+ );
107
157
  }
108
158
  }
109
- );
110
- this.logger.info(
111
- `Document "${newTitle || title}" (ID: ${title}) upload started with file ${fileId}`
112
- );
113
- return {
114
- document_id: newTitle || title,
115
- file_id: fileId,
116
- replaced: false,
117
- status: vectorStoreFile.status
118
- };
159
+ throw error;
160
+ }
119
161
  }
120
162
  /**
121
163
  * Get file processing status
@@ -127,7 +169,7 @@ class DocumentService {
127
169
  async getFileStatus(sessionId, documentTitle) {
128
170
  const file = await this.findFileByTitle(sessionId, documentTitle);
129
171
  if (!file) {
130
- throw new errors.NotFoundError(`Document not found: ${documentTitle}`);
172
+ throw new errors.NotFoundError(`Resource not found: ${documentTitle}`);
131
173
  }
132
174
  return {
133
175
  status: file.status,
@@ -160,6 +202,10 @@ class DocumentService {
160
202
  created_at: attrs.created_at,
161
203
  updated_at: attrs.updated_at
162
204
  };
205
+ }).sort((a, b) => {
206
+ const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
207
+ const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
208
+ return timeA - timeB;
163
209
  });
164
210
  this.logger.info(
165
211
  `Found ${documents.length} documents in session ${sessionId}`
@@ -167,7 +213,9 @@ class DocumentService {
167
213
  return documents;
168
214
  }
169
215
  /**
170
- * Delete a document from the vector store and Files API
216
+ * Remove a document's vector store entry.
217
+ * Note: the underlying file in the Files API is intentionally preserved
218
+ * so it can be re-associated (e.g., during rename/upsert).
171
219
  * @param sessionId - Vector store ID
172
220
  * @param documentTitle - Document title to delete
173
221
  * @throws NotFoundError if document not found
@@ -176,7 +224,7 @@ class DocumentService {
176
224
  this.logger.info(`Deleting document ${documentTitle} from ${sessionId}`);
177
225
  const file = await this.findFileByTitle(sessionId, documentTitle);
178
226
  if (!file) {
179
- throw new errors.NotFoundError(`Document not found: ${documentTitle}`);
227
+ throw new errors.NotFoundError(`Resource not found: ${documentTitle}`);
180
228
  }
181
229
  await this.client.vectorStores.files.delete(sessionId, file.id);
182
230
  this.logger.info(
@@ -1 +1 @@
1
- {"version":3,"file":"documentService.cjs.js","sources":["../../../../src/service/notebooks/documents/documentService.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 { LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\n\nimport {\n DEFAULT_CHUNK_OVERLAP_TOKENS,\n DEFAULT_CHUNKING_STRATEGY_TYPE,\n DEFAULT_MAX_CHUNK_SIZE_TOKENS,\n} from '../../constant';\nimport { SessionDocument, UpsertResult } from '../types/notebooksTypes';\nimport { VectorStoresOperator } from '../VectorStoresOperator';\nimport { toFile } from './fileParser';\n\n/**\n * Service for managing documents within notebook sessions using File-Based API\n * Each session has its own dedicated vector store\n * Uses VectorStoresOperator to proxy through lightspeed-core\n */\nexport class DocumentService {\n private logger: LoggerService;\n private client: VectorStoresOperator;\n private chunkingStrategy: {\n type: string;\n static?: { max_chunk_size_tokens: number; chunk_overlap_tokens: number };\n };\n\n constructor(\n client: VectorStoresOperator,\n logger: LoggerService,\n config?: Config,\n ) {\n this.client = client;\n this.logger = logger;\n\n // Chunking strategy configuration\n const chunkingType =\n config?.getOptionalString(\n 'intelligent-assistant.notebooks.chunkingStrategy.type',\n ) || DEFAULT_CHUNKING_STRATEGY_TYPE;\n\n if (chunkingType === 'static') {\n this.chunkingStrategy = {\n type: 'static',\n static: {\n max_chunk_size_tokens:\n config?.getOptionalNumber(\n 'intelligent-assistant.notebooks.chunkingStrategy.maxChunkSizeTokens',\n ) || DEFAULT_MAX_CHUNK_SIZE_TOKENS,\n chunk_overlap_tokens:\n config?.getOptionalNumber(\n 'intelligent-assistant.notebooks.chunkingStrategy.chunkOverlapTokens',\n ) || DEFAULT_CHUNK_OVERLAP_TOKENS,\n },\n };\n } else {\n this.chunkingStrategy = { type: 'auto' };\n }\n }\n\n /**\n * Find a file by title in vector store\n * @param sessionId - Vector store ID\n * @param documentTitle - Document title to search for\n * @returns File object if found, null otherwise\n */\n async findFileByTitle(\n sessionId: string,\n documentTitle: string,\n ): Promise<any | null> {\n const filesResponse = await this.client.vectorStores.files.list(sessionId);\n return (\n filesResponse.data.find(\n (f: any) => f.attributes?.title === documentTitle,\n ) || null\n );\n }\n\n /**\n * Upload a file to the Files API\n * @param content - File content as string\n * @param title - File title/name\n * @returns File ID from the Files API\n * @throws Error if upload fails\n */\n async uploadFile(content: string, title: string): Promise<string> {\n try {\n // Determine MIME type from file type or default to text/plain\n const mimeType = 'text/plain';\n const txtFilename = `${title.replace(/\\.[^.]+$/, '')}.txt`;\n const file = await this.client.files.create({\n file: await toFile(Buffer.from(content, 'utf-8'), txtFilename, {\n type: mimeType,\n }),\n purpose: 'assistants',\n });\n\n this.logger.info(\n `File created - id: ${file.id}, filename: ${file.filename}`,\n );\n return file.id;\n } catch (error) {\n // Preserve the original error type and message\n if (error instanceof Error) {\n throw error;\n }\n // For non-Error objects, wrap with context\n throw new Error(`Failed to upload file: ${String(error)}`);\n }\n }\n\n /**\n * Upsert a document - create if it doesn't exist, update if it does\n * @param sessionId - Vector store ID\n * @param title - Original document title\n * @param fileType - Document source type (text, pdf, url, etc.)\n * @param fileId - File ID from Files API\n * @param newTitle - New title for rename operation (optional)\n * @returns Upsert result with document ID and status\n * @throws ConflictError if newTitle conflicts with existing document\n */\n async upsertDocument(\n sessionId: string,\n title: string,\n fileType: string,\n fileId: string,\n newTitle?: string,\n ): Promise<UpsertResult> {\n // Find existing file by document_id\n const existingFile = await this.findFileByTitle(sessionId, title);\n const createdAt =\n (existingFile?.attributes?.created_at as string) ||\n new Date().toISOString();\n\n if (newTitle && title !== newTitle) {\n // Check for title conflicts when renaming\n const conflictingFile = await this.findFileByTitle(sessionId, newTitle);\n\n if (conflictingFile) {\n throw new ConflictError(\n `A document with the title \"${newTitle || title}\" already exists in this session`,\n );\n }\n }\n if (existingFile) {\n await this.deleteDocument(sessionId, title);\n }\n\n const vectorStoreFile = await this.client.vectorStores.files.create(\n sessionId,\n {\n file_id: fileId,\n chunking_strategy: this.chunkingStrategy,\n attributes: {\n title: newTitle || title,\n source_type: fileType,\n created_at: createdAt,\n updated_at: new Date().toISOString(),\n },\n },\n );\n\n this.logger.info(\n `Document \"${newTitle || title}\" (ID: ${title}) upload started with file ${fileId}`,\n );\n\n return {\n document_id: newTitle || title,\n file_id: fileId,\n replaced: false,\n status: vectorStoreFile.status,\n };\n }\n\n /**\n * Get file processing status\n * @param sessionId - Vector store ID\n * @param documentTitle - Document title\n * @returns File status including processing state, chunk count, and error if any\n * @throws NotFoundError if document not found\n */\n async getFileStatus(\n sessionId: string,\n documentTitle: string,\n ): Promise<{\n status: 'in_progress' | 'completed' | 'failed' | 'cancelled';\n chunks_count: number;\n error?: string;\n }> {\n const file = await this.findFileByTitle(sessionId, documentTitle);\n\n if (!file) {\n throw new NotFoundError(`Document not found: ${documentTitle}`);\n }\n return {\n status: file.status,\n chunks_count: file.chunks_count,\n error: file.last_error?.message,\n };\n }\n\n /**\n * List all documents in a session\n * @param sessionId - Vector store ID\n * @param fileTypeFilter - Optional filter by source type (text, pdf, url, etc.)\n * @returns Array of session documents\n */\n async listDocuments(\n sessionId: string,\n fileTypeFilter?: string,\n ): Promise<SessionDocument[]> {\n this.logger.info(`Listing documents for session ${sessionId}`);\n\n // List all files in vector store\n const filesResponse = await this.client.vectorStores.files.list(sessionId);\n\n if (!filesResponse.data || filesResponse.data.length === 0) {\n return [];\n }\n\n // Map files to SessionDocument format\n const documents = filesResponse.data\n .filter((file: any) => {\n // Apply file type filter if provided\n if (fileTypeFilter && file.attributes?.source_type !== fileTypeFilter) {\n return false;\n }\n return true;\n })\n .map((file: any) => {\n const attrs = file.attributes || {};\n return {\n document_id: attrs.title,\n source_type:\n (attrs.source_type as SessionDocument['source_type']) || 'text',\n created_at: attrs.created_at,\n updated_at: attrs.updated_at,\n };\n });\n\n this.logger.info(\n `Found ${documents.length} documents in session ${sessionId}`,\n );\n return documents;\n }\n\n /**\n * Delete a document from the vector store and Files API\n * @param sessionId - Vector store ID\n * @param documentTitle - Document title to delete\n * @throws NotFoundError if document not found\n */\n async deleteDocument(\n sessionId: string,\n documentTitle: string,\n ): Promise<void> {\n this.logger.info(`Deleting document ${documentTitle} from ${sessionId}`);\n\n const file = await this.findFileByTitle(sessionId, documentTitle);\n\n if (!file) {\n throw new NotFoundError(`Document not found: ${documentTitle}`);\n }\n\n // Delete from vector store first\n await this.client.vectorStores.files.delete(sessionId, file.id);\n\n this.logger.info(\n `Deleted document ${documentTitle} (file ${file.id}) from session ${sessionId}`,\n );\n }\n}\n"],"names":["DEFAULT_CHUNKING_STRATEGY_TYPE","DEFAULT_MAX_CHUNK_SIZE_TOKENS","DEFAULT_CHUNK_OVERLAP_TOKENS","toFile","ConflictError","NotFoundError"],"mappings":"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"}
1
+ {"version":3,"file":"documentService.cjs.js","sources":["../../../../src/service/notebooks/documents/documentService.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 { LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\n\nimport {\n DEFAULT_CHUNK_OVERLAP_TOKENS,\n DEFAULT_CHUNKING_STRATEGY_TYPE,\n DEFAULT_MAX_CHUNK_SIZE_TOKENS,\n} from '../../constant';\nimport { SessionDocument, UpsertResult } from '../types/notebooksTypes';\nimport { VectorStoresOperator } from '../VectorStoresOperator';\nimport { toFile } from './fileParser';\n\n/**\n * Service for managing documents within notebook sessions using File-Based API\n * Each session has its own dedicated vector store\n * Uses VectorStoresOperator to proxy through lightspeed-core\n */\nexport class DocumentService {\n private logger: LoggerService;\n private client: VectorStoresOperator;\n private chunkingStrategy: {\n type: string;\n static?: { max_chunk_size_tokens: number; chunk_overlap_tokens: number };\n };\n\n constructor(\n client: VectorStoresOperator,\n logger: LoggerService,\n config?: Config,\n ) {\n this.client = client;\n this.logger = logger;\n\n // Chunking strategy configuration\n const chunkingType =\n config?.getOptionalString(\n 'intelligent-assistant.notebooks.chunkingStrategy.type',\n ) || DEFAULT_CHUNKING_STRATEGY_TYPE;\n\n if (chunkingType === 'static') {\n this.chunkingStrategy = {\n type: 'static',\n static: {\n max_chunk_size_tokens:\n config?.getOptionalNumber(\n 'intelligent-assistant.notebooks.chunkingStrategy.maxChunkSizeTokens',\n ) || DEFAULT_MAX_CHUNK_SIZE_TOKENS,\n chunk_overlap_tokens:\n config?.getOptionalNumber(\n 'intelligent-assistant.notebooks.chunkingStrategy.chunkOverlapTokens',\n ) || DEFAULT_CHUNK_OVERLAP_TOKENS,\n },\n };\n } else {\n this.chunkingStrategy = { type: 'auto' };\n }\n }\n\n /**\n * Find a file by title in vector store\n * @param sessionId - Vector store ID\n * @param documentTitle - Document title to search for\n * @returns File object if found, null otherwise\n */\n async findFileByTitle(\n sessionId: string,\n documentTitle: string,\n ): Promise<any | null> {\n const filesResponse = await this.client.vectorStores.files.list(sessionId);\n return (\n filesResponse.data.find(\n (f: any) => f.attributes?.title === documentTitle,\n ) || null\n );\n }\n\n /**\n * Upload a file to the Files API\n * @param content - File content as string\n * @param title - File title/name\n * @returns File ID from the Files API\n * @throws Error if upload fails\n */\n async uploadFile(content: string, title: string): Promise<string> {\n try {\n // Determine MIME type from file type or default to text/plain\n const mimeType = 'text/plain';\n const txtFilename = `${title.replace(/\\.[^.]+$/, '')}.txt`;\n const file = await this.client.files.create({\n file: await toFile(Buffer.from(content, 'utf-8'), txtFilename, {\n type: mimeType,\n }),\n purpose: 'assistants',\n });\n\n this.logger.info(\n `File created - id: ${file.id}, filename: ${file.filename}`,\n );\n return file.id;\n } catch (error) {\n // Preserve the original error type and message\n if (error instanceof Error) {\n throw error;\n }\n // For non-Error objects, wrap with context\n throw new Error(`Failed to upload file: ${String(error)}`);\n }\n }\n\n /**\n * Upsert a document - create if it doesn't exist, update if it does.\n * Also used for rename-only operations when fileType/fileId are omitted.\n * @param sessionId - Vector store ID\n * @param title - Original document title\n * @param opts - Optional parameters for upload or rename\n * @param opts.fileType - Document source type (derived from existing file when omitted)\n * @param opts.fileId - File ID from Files API (derived from existing file when omitted)\n * @param opts.newTitle - New title for rename operation\n * @returns Upsert result with document ID and status\n * @throws NotFoundError if fileId is omitted and document does not exist\n * @throws ConflictError if newTitle conflicts with existing document\n */\n async upsertDocument(\n sessionId: string,\n title: string,\n opts?: {\n fileType?: string;\n fileId?: string;\n newTitle?: string;\n },\n ): Promise<UpsertResult> {\n const { fileType, fileId, newTitle } = opts || {};\n const existingFile = await this.findFileByTitle(sessionId, title);\n\n // Rename-only mode: no fileId means we must have an existing file\n let resolvedFileId: string;\n let resolvedFileType: string;\n if (fileId) {\n resolvedFileId = fileId;\n resolvedFileType = fileType || 'unknown';\n } else {\n if (!existingFile) {\n throw new NotFoundError(`Document not found: ${title}`);\n }\n resolvedFileId = existingFile.id;\n resolvedFileType =\n fileType ||\n (existingFile.attributes?.source_type as string) ||\n 'unknown';\n }\n\n const createdAt =\n (existingFile?.attributes?.created_at as string) ||\n new Date().toISOString();\n\n if (newTitle && title !== newTitle) {\n const conflictingFile = await this.findFileByTitle(sessionId, newTitle);\n if (conflictingFile) {\n throw new ConflictError(\n `A resource with the title \"${newTitle || title}\" already exists in this session`,\n );\n }\n }\n\n if (existingFile) {\n await this.deleteDocument(sessionId, title);\n }\n\n // Preserve existing attributes, override with known fields\n const baseAttrs = existingFile?.attributes || {};\n const attributes = {\n ...baseAttrs,\n title: newTitle || title,\n source_type: resolvedFileType,\n created_at: createdAt,\n updated_at: new Date().toISOString(),\n };\n\n try {\n const vectorStoreFile = await this.client.vectorStores.files.create(\n sessionId,\n {\n file_id: resolvedFileId,\n chunking_strategy: this.chunkingStrategy,\n attributes,\n },\n );\n\n this.logger.info(\n `Document \"${newTitle || title}\" (ID: ${title}) upsert started with file ${resolvedFileId}`,\n );\n\n return {\n document_id: newTitle || title,\n file_id: resolvedFileId,\n replaced: !!existingFile,\n status: vectorStoreFile.status,\n };\n } catch (error) {\n // Rollback: restore original entry if delete succeeded but create failed\n if (existingFile) {\n this.logger.error(\n `Failed to re-create vector store entry after delete for \"${title}\". Attempting rollback.`,\n );\n try {\n await this.client.vectorStores.files.create(sessionId, {\n file_id: existingFile.id,\n chunking_strategy: this.chunkingStrategy,\n attributes: existingFile.attributes || {},\n });\n this.logger.info(\n `Rollback succeeded: restored \"${title}\" in session ${sessionId}`,\n );\n } catch (rollbackError) {\n this.logger.error(\n `Rollback failed: document \"${title}\" (file ${existingFile.id}) is orphaned in session ${sessionId}`,\n );\n }\n }\n throw error;\n }\n }\n\n /**\n * Get file processing status\n * @param sessionId - Vector store ID\n * @param documentTitle - Document title\n * @returns File status including processing state, chunk count, and error if any\n * @throws NotFoundError if document not found\n */\n async getFileStatus(\n sessionId: string,\n documentTitle: string,\n ): Promise<{\n status: 'in_progress' | 'completed' | 'failed' | 'cancelled';\n chunks_count: number;\n error?: string;\n }> {\n const file = await this.findFileByTitle(sessionId, documentTitle);\n\n if (!file) {\n throw new NotFoundError(`Resource not found: ${documentTitle}`);\n }\n return {\n status: file.status,\n chunks_count: file.chunks_count,\n error: file.last_error?.message,\n };\n }\n\n /**\n * List all documents in a session\n * @param sessionId - Vector store ID\n * @param fileTypeFilter - Optional filter by source type (text, pdf, url, etc.)\n * @returns Array of session documents\n */\n async listDocuments(\n sessionId: string,\n fileTypeFilter?: string,\n ): Promise<SessionDocument[]> {\n this.logger.info(`Listing documents for session ${sessionId}`);\n\n // List all files in vector store\n const filesResponse = await this.client.vectorStores.files.list(sessionId);\n\n if (!filesResponse.data || filesResponse.data.length === 0) {\n return [];\n }\n\n // Map files to SessionDocument format, sorted by original upload time\n const documents = filesResponse.data\n .filter((file: any) => {\n if (fileTypeFilter && file.attributes?.source_type !== fileTypeFilter) {\n return false;\n }\n return true;\n })\n .map((file: any) => {\n const attrs = file.attributes || {};\n return {\n document_id: attrs.title,\n source_type:\n (attrs.source_type as SessionDocument['source_type']) || 'text',\n created_at: attrs.created_at,\n updated_at: attrs.updated_at,\n };\n })\n .sort((a: SessionDocument, b: SessionDocument) => {\n const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;\n const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;\n return timeA - timeB;\n });\n\n this.logger.info(\n `Found ${documents.length} documents in session ${sessionId}`,\n );\n return documents;\n }\n\n /**\n * Remove a document's vector store entry.\n * Note: the underlying file in the Files API is intentionally preserved\n * so it can be re-associated (e.g., during rename/upsert).\n * @param sessionId - Vector store ID\n * @param documentTitle - Document title to delete\n * @throws NotFoundError if document not found\n */\n async deleteDocument(\n sessionId: string,\n documentTitle: string,\n ): Promise<void> {\n this.logger.info(`Deleting document ${documentTitle} from ${sessionId}`);\n\n const file = await this.findFileByTitle(sessionId, documentTitle);\n\n if (!file) {\n throw new NotFoundError(`Resource not found: ${documentTitle}`);\n }\n\n // Delete from vector store first\n await this.client.vectorStores.files.delete(sessionId, file.id);\n\n this.logger.info(\n `Deleted document ${documentTitle} (file ${file.id}) from session ${sessionId}`,\n );\n }\n}\n"],"names":["DEFAULT_CHUNKING_STRATEGY_TYPE","DEFAULT_MAX_CHUNK_SIZE_TOKENS","DEFAULT_CHUNK_OVERLAP_TOKENS","toFile","NotFoundError","ConflictError"],"mappings":"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"}
@@ -53,13 +53,10 @@ async function createNotebooksRouter(options) {
53
53
  "general",
54
54
  logger
55
55
  );
56
- const requireNotebooksPermission = async (req, res, next) => {
56
+ const requirePermission = (permission) => async (req, res, next) => {
57
57
  try {
58
58
  const { credentials } = getIdentity.getIdentity(req);
59
- await authorizer.authorizeUser(
60
- backstagePluginIntelligentAssistantCommon.lightspeedNotebooksUsePermission,
61
- credentials
62
- );
59
+ await authorizer.authorizeUser(permission, credentials);
63
60
  next();
64
61
  } catch (error) {
65
62
  utils.handleError(logger, res, error, "Permission denied");
@@ -182,7 +179,7 @@ async function createNotebooksRouter(options) {
182
179
  notebooksRouter.post(
183
180
  "/v1/sessions",
184
181
  generalRateLimiter,
185
- requireNotebooksPermission,
182
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
186
183
  withAuth(async (req, res, userId) => {
187
184
  const { name, description, metadata } = req.body;
188
185
  if (!name) {
@@ -201,7 +198,7 @@ async function createNotebooksRouter(options) {
201
198
  notebooksRouter.get(
202
199
  "/v1/sessions",
203
200
  generalRateLimiter,
204
- requireNotebooksPermission,
201
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
205
202
  withAuth(async (_req, res, userId) => {
206
203
  const sessions = await sessionService$1.listSessions(userId);
207
204
  res.json(notebooksTypes.createSessionListResponse(sessions));
@@ -210,7 +207,7 @@ async function createNotebooksRouter(options) {
210
207
  notebooksRouter.get(
211
208
  "/v1/sessions/:sessionId",
212
209
  generalRateLimiter,
213
- requireNotebooksPermission,
210
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
214
211
  withAuth(async (req, res, userId) => {
215
212
  const { sessionId } = req.params;
216
213
  const session = await sessionService$1.readSession(sessionId, userId);
@@ -222,7 +219,7 @@ async function createNotebooksRouter(options) {
222
219
  notebooksRouter.put(
223
220
  "/v1/sessions/:sessionId",
224
221
  generalRateLimiter,
225
- requireNotebooksPermission,
222
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksManagePermission),
226
223
  withAuth(async (req, res, userId) => {
227
224
  const { sessionId } = req.params;
228
225
  const { name, description, metadata } = req.body;
@@ -239,7 +236,7 @@ async function createNotebooksRouter(options) {
239
236
  notebooksRouter.delete(
240
237
  "/v1/sessions/:sessionId",
241
238
  generalRateLimiter,
242
- requireNotebooksPermission,
239
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksManagePermission),
243
240
  withAuth(async (req, res, userId) => {
244
241
  const { sessionId } = req.params;
245
242
  await sessionService$1.deleteSession(sessionId, userId);
@@ -254,7 +251,7 @@ async function createNotebooksRouter(options) {
254
251
  notebooksRouter.get(
255
252
  "/v1/sessions/:sessionId/documents",
256
253
  generalRateLimiter,
257
- requireNotebooksPermission,
254
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
258
255
  requireSessionOwnership(),
259
256
  withAuth(async (req, res) => {
260
257
  const { sessionId } = req.params;
@@ -269,7 +266,7 @@ async function createNotebooksRouter(options) {
269
266
  notebooksRouter.put(
270
267
  "/v1/sessions/:sessionId/documents",
271
268
  expensiveRateLimiter,
272
- requireNotebooksPermission,
269
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
273
270
  constant.upload.single("file"),
274
271
  withAuth(async (req, res, userId) => {
275
272
  const { sessionId } = req.params;
@@ -300,10 +297,10 @@ async function createNotebooksRouter(options) {
300
297
  status: "processing",
301
298
  document_id: newTitle || title,
302
299
  session_id: sessionId,
303
- message: "Document upload started"
300
+ message: "Resource upload started"
304
301
  });
305
302
  const docName = newTitle || title;
306
- documentService$1.upsertDocument(sessionId, title, fileType, fileId, newTitle).then(() => logger.info(`Background upload succeeded: ${docName}`)).catch(
303
+ documentService$1.upsertDocument(sessionId, title, { fileType, fileId, newTitle }).then(() => logger.info(`Background upload succeeded: ${docName}`)).catch(
307
304
  (err) => logger.error(`Background upload failed: ${docName}`, err)
308
305
  );
309
306
  })
@@ -311,7 +308,7 @@ async function createNotebooksRouter(options) {
311
308
  notebooksRouter.get(
312
309
  "/v1/sessions/:sessionId/documents/:documentId/status",
313
310
  generalRateLimiter,
314
- requireNotebooksPermission,
311
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
315
312
  requireSessionOwnership(),
316
313
  withAuth(async (req, res) => {
317
314
  const { sessionId, documentId } = req.params;
@@ -327,10 +324,43 @@ async function createNotebooksRouter(options) {
327
324
  });
328
325
  })
329
326
  );
327
+ notebooksRouter.patch(
328
+ "/v1/sessions/:sessionId/documents/:documentId",
329
+ generalRateLimiter,
330
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksManagePermission),
331
+ requireSessionOwnership(),
332
+ withAuth(async (req, res) => {
333
+ const { sessionId, documentId } = req.params;
334
+ const { title } = req.body;
335
+ if (!title || typeof title !== "string" || !title.trim()) {
336
+ utils.handleError(logger, res, "title is required");
337
+ return;
338
+ }
339
+ const MAX_TITLE_LENGTH = 255;
340
+ if (title.trim().length > MAX_TITLE_LENGTH) {
341
+ utils.handleError(
342
+ logger,
343
+ res,
344
+ `title must be ${MAX_TITLE_LENGTH} characters or less`
345
+ );
346
+ return;
347
+ }
348
+ await documentService$1.upsertDocument(sessionId, documentId, {
349
+ newTitle: title.trim()
350
+ });
351
+ res.json(
352
+ notebooksTypes.createDocumentResponse(
353
+ title.trim(),
354
+ sessionId,
355
+ "Document renamed successfully"
356
+ )
357
+ );
358
+ })
359
+ );
330
360
  notebooksRouter.delete(
331
361
  "/v1/sessions/:sessionId/documents/:documentId",
332
362
  generalRateLimiter,
333
- requireNotebooksPermission,
363
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksManagePermission),
334
364
  requireSessionOwnership(),
335
365
  withAuth(async (req, res) => {
336
366
  const { sessionId, documentId } = req.params;
@@ -339,7 +369,7 @@ async function createNotebooksRouter(options) {
339
369
  notebooksTypes.createDocumentResponse(
340
370
  documentId,
341
371
  sessionId,
342
- "Document deleted successfully"
372
+ "Resource deleted successfully"
343
373
  )
344
374
  );
345
375
  })
@@ -354,7 +384,7 @@ async function createNotebooksRouter(options) {
354
384
  notebooksRouter.post(
355
385
  "/v1/sessions/:sessionId/query",
356
386
  expensiveRateLimiter,
357
- requireNotebooksPermission,
387
+ requirePermission(backstagePluginIntelligentAssistantCommon.iaNotebooksUsePermission),
358
388
  express__default.default.json({ limit: constant.EXPRESS_JSON_BODY_LIMIT }),
359
389
  withAuth(async (req, res, userId) => {
360
390
  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, 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 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 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: 'Resource 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 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","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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"}
@@ -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.iaSavedPromptsManagePermission),
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.iaSavedPromptsManagePermission),
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.iaSavedPromptsManagePermission),
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.iaSavedPromptsManagePermission),
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);
@@ -1 +1 @@
1
- {"version":3,"file":"router.cjs.js","sources":["../../src/service/router.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 { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport type {\n AuthService,\n BackstageCredentials,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport type { BasicPermission } from '@backstage/plugin-permission-common';\nimport { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';\n\nimport express, { Router } from 'express';\nimport { createProxyMiddleware } from 'http-proxy-middleware';\n\nimport {\n lightspeedChatCreatePermission,\n lightspeedChatDeletePermission,\n lightspeedChatReadPermission,\n lightspeedChatUpdatePermission,\n lightspeedMcpManagePermission,\n lightspeedMcpReadPermission,\n lightspeedPermissions,\n lightspeedSavedPromptsManagePermission,\n} from '@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common';\n\nimport { Readable } from 'node:stream';\n\nimport { ModelCapabilitiesCache } from './attachment-validation';\nimport {\n DEFAULT_LIGHTSPEED_SERVICE_HOST,\n DEFAULT_LIGHTSPEED_SERVICE_PORT,\n EXPRESS_JSON_BODY_LIMIT,\n TEST_VISION_JPEG,\n} from './constant';\nimport { McpUserSettingsStore } from './mcp-server-store';\nimport {\n McpServerAuth,\n McpServerResponse,\n McpServerStatus,\n McpValidationResult,\n} from './mcp-server-types';\nimport { McpServerValidator } from './mcp-server-validator';\nimport { createPermissionMiddleware } from './middleware/createPermissionMiddleware';\nimport { createRateLimitMiddleware } from './middleware/createRateLimitMiddleware';\nimport {\n createIdentityMiddleware,\n getIdentity,\n} from './middleware/getIdentity';\nimport { VectorStoresOperator } from './notebooks/VectorStoresOperator';\nimport { userPermissionAuthorization } from './permission';\nimport { createTokenEncryptor } from './token-encryption';\nimport { QueryRequestBody, RouterOptions } from './types';\nimport { handleLCSFetchError, rewriteProxyPath } from './utils';\nimport {\n validateAttachmentsForModel,\n validateCompletionsRequest,\n} from './validation';\n\n/**\n * MCP Server authentication modes for lightspeed.mcpServers entries.\n *\n * - `'dcr'` — Dynamic Client Registration. The Lightspeed backend mints a\n * short-lived Backstage plugin-request token carrying the current user's\n * identity. This token is forwarded to the MCP server via LCORE's\n * MCP-HEADERS, and the MCP Actions backend validates it against the\n * Backstage Permission Framework (RBAC). Use this for Backstage-internal\n * MCP servers (e.g. `@backstage/plugin-mcp-actions-backend`).\n * A static `token` field is **ignored** when `auth: dcr` is set.\n *\n * - (absent / undefined) — Legacy static-token mode. The token is resolved\n * from the user's DB override first, then from the `token` field in\n * app-config. If neither exists, the server is omitted from MCP-HEADERS.\n * Users can also set their own tokens via the Lightspeed UI.\n */\ninterface StaticMcpServer {\n name: string;\n token?: string;\n auth?: McpServerAuth;\n}\n\n/**\n * Build MCP-HEADERS for LCS. Format matches the LCS \"client\"/\"oauth\" auth\n * model: `{ \"server-name\": { \"Authorization\": \"<token>\" } }`\n *\n * For each admin-configured server:\n *\n * 1. If `auth: 'dcr'`, a Backstage plugin-request token is minted on behalf\n * of the authenticated user. Any static token is ignored.\n *\n * 2. Otherwise, the user's personal token (DB) takes precedence over the\n * admin default from app-config. If neither exists, the server is\n * excluded from MCP-HEADERS (LCORE will skip it or return 401).\n *\n * Servers the user has disabled are always excluded.\n */\nasync function buildMcpHeaders(\n servers: StaticMcpServer[],\n store: McpUserSettingsStore,\n userEntityRef: string,\n options?: {\n dcrAuth?: { authService: AuthService; credentials: BackstageCredentials };\n logger?: LoggerService;\n },\n): Promise<string> {\n const headers: Record<string, { Authorization: string }> = {};\n const userSettings = await store.listByUser(userEntityRef);\n const settingsMap = new Map(userSettings.map(s => [s.server_name, s]));\n\n for (const server of servers) {\n const setting = settingsMap.get(server.name);\n const enabled = setting ? Boolean(setting.enabled) : true;\n if (!enabled) continue;\n\n if (server.auth === 'dcr') {\n if (options?.dcrAuth) {\n try {\n const { token } =\n await options.dcrAuth.authService.getPluginRequestToken({\n onBehalfOf: options.dcrAuth.credentials,\n targetPluginId: 'mcp-actions',\n });\n headers[server.name] = { Authorization: `${token}` };\n } catch (err) {\n options?.logger?.error(\n `Failed to mint DCR token for MCP server '${server.name}': ${err}`,\n );\n }\n } else {\n options?.logger?.warn(\n `MCP server '${server.name}' has auth: dcr but AuthService is not available; skipping`,\n );\n }\n } else {\n // Static token: user's personal token (DB) > admin default (app-config).\n // If neither exists, the server is excluded from MCP-HEADERS.\n const token = setting?.token || server.token;\n if (token) {\n headers[server.name] = { Authorization: `${token}` };\n }\n }\n }\n\n return Object.keys(headers).length > 0 ? JSON.stringify(headers) : '';\n}\n\n/**\n * @public\n * The lightspeed backend router\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, database, httpAuth, auth, userInfo, permissions } =\n options;\n\n const router = Router();\n router.use(express.json());\n\n const port =\n config.getOptionalNumber('intelligent-assistant.servicePort') ??\n DEFAULT_LIGHTSPEED_SERVICE_PORT;\n const system_prompt = config.getOptionalString(\n 'intelligent-assistant.systemPrompt',\n );\n const lcsBaseUrl = `http://${DEFAULT_LIGHTSPEED_SERVICE_HOST}:${port}`;\n\n const apiProxy = createProxyMiddleware({\n target: lcsBaseUrl,\n changeOrigin: true,\n pathRewrite: (path, req) => {\n const userEntityRef = (req as any).userEntityRef;\n const newPath = rewriteProxyPath(path, userEntityRef);\n\n if (newPath !== path) {\n logger.info(`Rewriting path from ${path} to ${newPath}`);\n }\n return newPath;\n },\n });\n\n const vectorStoresOperator = VectorStoresOperator.getInstance(\n lcsBaseUrl,\n logger,\n );\n // Parse admin-configured MCP servers from app-config.\n //\n // Each entry supports:\n // name (required) — unique identifier, must match the name in lightspeed-stack.yaml\n // auth (optional) — authentication mode:\n // 'dcr' = the backend mints a per-user Backstage token (for\n // Backstage-internal MCP servers with DCR/OAuth enabled)\n // absent = legacy static-token mode (see `token` below)\n // token (optional) — static fallback token from app-config. Ignored when auth: dcr.\n // Users can also set personal tokens via the Lightspeed UI.\n //\n // URLs come from LCS (GET /v1/mcp-servers), not from app-config.\n const mcpServersConfig = config.getOptionalConfigArray(\n 'intelligent-assistant.mcpServers',\n );\n const staticServers: StaticMcpServer[] = [];\n if (mcpServersConfig) {\n for (const mcpServer of mcpServersConfig) {\n const authValue = mcpServer.getOptionalString('auth')?.toLowerCase();\n if (authValue && authValue !== 'dcr') {\n logger.warn(\n `MCP server '${mcpServer.getString('name')}' has unsupported auth value '${authValue}'; ` +\n `only 'dcr' is supported — falling back to static-token mode`,\n );\n }\n staticServers.push({\n name: mcpServer.getString('name'),\n token: mcpServer.getOptionalString('token'),\n auth: authValue === 'dcr' ? 'dcr' : undefined,\n });\n }\n }\n\n // Initialize database-backed store for per-user preferences and validator\n const dbClient = await database.getClient();\n const encryptor = createTokenEncryptor(config, logger);\n const settingsStore = new McpUserSettingsStore(dbClient, encryptor, logger);\n const mcpValidator = new McpServerValidator(logger);\n\n // URL cache populated from LCS GET /v1/mcp-servers.\n // The canonical URL for each MCP server lives in LCS config, not app-config.\n const lcsUrlCache = new Map<string, string>();\n\n async function refreshLcsUrlCache(): Promise<void> {\n try {\n const response = await fetch(`${lcsBaseUrl}/v1/mcp-servers`, {\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) {\n logger.warn(\n `Failed to fetch MCP server URLs from LCS: HTTP ${response.status}`,\n );\n return;\n }\n const data = (await response.json()) as {\n servers: Array<{ name: string; url: string }>;\n };\n for (const s of data.servers) {\n lcsUrlCache.set(s.name, s.url);\n }\n logger.info(`Cached ${lcsUrlCache.size} MCP server URL(s) from LCS`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n logger.warn(`Failed to fetch MCP server URLs from LCS: ${msg}`);\n }\n }\n\n function resolveServerUrl(serverName: string): string | undefined {\n return lcsUrlCache.get(serverName);\n }\n\n // Best-effort URL cache on startup (non-blocking)\n refreshLcsUrlCache().catch(() => {});\n\n router.get('/health', (_, response) => {\n response.json({ status: 'ok' });\n });\n\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n permissions: lightspeedPermissions,\n });\n router.use(permissionIntegrationRouter);\n\n const identityMiddleware = createIdentityMiddleware(\n httpAuth,\n userInfo,\n logger,\n );\n router.use((req, res, next) => {\n // Middleware mounts to notebooks router independently\n // so we skip it here\n if (req.path.startsWith('/notebooks')) {\n return next();\n }\n return identityMiddleware(req, res, next);\n });\n\n const authorizer = userPermissionAuthorization(permissions);\n\n function requirePermission(permission: BasicPermission) {\n return createPermissionMiddleware(authorizer, permission, logger);\n }\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 // ─── MCP Server Management Endpoints ────────────────────────────────\n // All MCP servers are admin-configured (static). Users can view the\n // list, toggle servers on/off, and provide personal access tokens.\n\n router.get(\n '/mcp-servers',\n generalRateLimiter,\n requirePermission(lightspeedMcpReadPermission),\n async (req, res) => {\n try {\n const { userEntityRef } = getIdentity(req);\n\n const userSettings = await settingsStore.listByUser(userEntityRef);\n const settingsMap = new Map(userSettings.map(s => [s.server_name, s]));\n\n const hasAllUrls = staticServers.every(s => lcsUrlCache.has(s.name));\n if (!hasAllUrls) {\n await refreshLcsUrlCache();\n }\n\n const servers: McpServerResponse[] = staticServers.map(server => {\n const setting = settingsMap.get(server.name);\n return {\n name: server.name,\n url: resolveServerUrl(server.name),\n enabled: setting ? Boolean(setting.enabled) : true,\n status: setting?.status ?? 'unknown',\n toolCount: setting?.tool_count ?? 0,\n // DCR servers always have a token (minted per-request); static servers check DB + config.\n hasToken:\n server.auth === 'dcr' || !!(setting?.token || server.token),\n hasUserToken: !!setting?.token,\n hasOrgToken: server.auth !== 'dcr' && !!server.token,\n auth: server.auth,\n };\n });\n\n res.json({ servers });\n } catch (error) {\n logger.error(`Error listing MCP servers: ${error}`);\n res.status(500).json({ error: 'Failed to list MCP servers' });\n }\n },\n );\n\n router.post(\n '/mcp-servers/validate',\n generalRateLimiter,\n requirePermission(lightspeedMcpReadPermission),\n async (req, res) => {\n try {\n const { url, token } = req.body;\n if (!url || !token) {\n res.status(400).json({ error: 'url and token are required' });\n return;\n }\n\n // SSRF protection: only allow URLs registered in LCS\n let knownUrls = new Set(lcsUrlCache.values());\n if (!knownUrls.has(url)) {\n await refreshLcsUrlCache();\n knownUrls = new Set(lcsUrlCache.values());\n }\n if (!knownUrls.has(url)) {\n res.status(400).json({\n error:\n 'URL not recognized — only MCP server URLs registered in LCS are allowed',\n });\n return;\n }\n\n const result = await mcpValidator.validate(url, token);\n res.json(result);\n } catch (error) {\n logger.error(`Error validating MCP credentials: ${error}`);\n res.status(500).json({ error: 'Validation failed' });\n }\n },\n );\n\n router.post(\n '/mcp-servers/:name/validate',\n generalRateLimiter,\n requirePermission(lightspeedMcpManagePermission),\n async (req, res) => {\n try {\n const { userEntityRef, credentials } = getIdentity(req);\n\n const { name } = req.params;\n const server = staticServers.find(s => s.name === name);\n if (!server) {\n res.status(404).json({\n error: `MCP server '${name}' is not configured — it must be defined in the Lightspeed Stack config and listed under intelligent-assistant.mcpServers in app-config`,\n });\n return;\n }\n // Resolve URL: LCS cache → fresh LCS fetch\n let serverUrl = resolveServerUrl(server.name);\n if (!serverUrl) {\n await refreshLcsUrlCache();\n serverUrl = resolveServerUrl(server.name);\n }\n if (!serverUrl) {\n res\n .status(400)\n .json({ error: 'Server has no URL — not found in LCS or config' });\n return;\n }\n\n let effectiveToken: string | undefined;\n if (server.auth === 'dcr') {\n try {\n const { token: dcrToken } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'mcp-actions',\n });\n effectiveToken = dcrToken;\n } catch (err) {\n logger.error(\n `Failed to mint DCR token for server '${name}': ${err}`,\n );\n res.status(502).json({\n error: `Failed to mint authentication token for DCR server '${name}' — check Backstage auth configuration`,\n });\n return;\n }\n } else {\n const setting = await settingsStore.get(name, userEntityRef);\n effectiveToken = setting?.token || server.token;\n }\n if (!effectiveToken) {\n res\n .status(400)\n .json({ error: 'No token available — provide one first' });\n return;\n }\n\n const validation = await mcpValidator.validate(\n serverUrl,\n effectiveToken,\n );\n const status: McpServerStatus = validation.valid\n ? 'connected'\n : 'error';\n\n await settingsStore.updateStatus(\n name,\n userEntityRef,\n status,\n validation.toolCount,\n );\n\n res.json({\n name,\n status,\n toolCount: validation.toolCount,\n validation,\n });\n } catch (error) {\n logger.error(`Error validating MCP server: ${error}`);\n res.status(500).json({ error: 'Validation failed' });\n }\n },\n );\n\n router.patch(\n '/mcp-servers/:name',\n generalRateLimiter,\n requirePermission(lightspeedMcpManagePermission),\n async (req, res) => {\n try {\n const { userEntityRef } = getIdentity(req);\n\n const { name } = req.params;\n const server = staticServers.find(s => s.name === name);\n if (!server) {\n res.status(404).json({\n error: `MCP server '${name}' is not configured — it must be defined in the Lightspeed Stack config and listed under intelligent-assistant.mcpServers in app-config`,\n });\n return;\n }\n\n const body = (req.body ?? {}) as {\n enabled?: boolean;\n token?: string | null;\n };\n const hasEnabledField = Object.prototype.hasOwnProperty.call(\n body,\n 'enabled',\n );\n const hasTokenField = Object.prototype.hasOwnProperty.call(\n body,\n 'token',\n );\n const { enabled, token } = body;\n if (!hasEnabledField && !hasTokenField) {\n res.status(400).json({\n error: 'At least one of enabled or token must be provided',\n });\n return;\n }\n\n const setting = await settingsStore.upsert(name, userEntityRef, {\n enabled: hasEnabledField ? enabled : undefined,\n token: hasTokenField ? token : undefined,\n });\n\n let validation: McpValidationResult | undefined;\n let serverUrl = resolveServerUrl(server.name);\n if (token && !serverUrl) {\n await refreshLcsUrlCache();\n serverUrl = resolveServerUrl(server.name);\n }\n if (token && serverUrl) {\n validation = await mcpValidator.validate(serverUrl, token);\n const newStatus: McpServerStatus = validation.valid\n ? 'connected'\n : 'error';\n await settingsStore.updateStatus(\n name,\n userEntityRef,\n newStatus,\n validation.toolCount,\n );\n setting.status = newStatus;\n setting.tool_count = validation.toolCount;\n }\n\n const result: Record<string, unknown> = {\n server: {\n name: server.name,\n url: resolveServerUrl(server.name),\n enabled: Boolean(setting.enabled),\n status: setting.status,\n toolCount: setting.tool_count,\n hasToken:\n server.auth === 'dcr' || !!(setting.token || server.token),\n hasUserToken: !!setting.token,\n hasOrgToken: server.auth !== 'dcr' && !!server.token,\n auth: server.auth,\n },\n };\n if (validation) result.validation = validation;\n res.json(result);\n } catch (error) {\n logger.error(`Error updating MCP server settings: ${error}`);\n res.status(500).json({ error: 'Failed to update MCP server settings' });\n }\n },\n );\n\n // Returns conversation IDs associated with notebook sessions for filtering\n router.get(\n '/notebook-conversation-ids',\n generalRateLimiter,\n async (req, res) => {\n try {\n const { userEntityRef } = getIdentity(req);\n\n const vectorStoresPage = await vectorStoresOperator.vectorStores.list();\n const vectorStores = vectorStoresPage.data || [];\n\n const conversationIds: string[] = [];\n\n for (const store of vectorStores) {\n const sessionUserId = store.metadata?.user_id as string;\n const conversationId = store.metadata?.conversation_id as\n string | null;\n\n // Only include this user's sessions with a conversation_id\n if (sessionUserId === userEntityRef && conversationId) {\n conversationIds.push(conversationId);\n }\n }\n\n res.json({\n conversation_ids: conversationIds,\n });\n } catch (error) {\n const errormsg = `Error fetching notebook conversation IDs: ${error}`;\n logger.error(errormsg);\n\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: errormsg });\n }\n }\n },\n );\n\n // ─── Proxy Routes ───────────────────────────────────────────────────\n\n router.get(\n '/v1/models',\n generalRateLimiter,\n requirePermission(lightspeedChatReadPermission),\n apiProxy,\n );\n router.get(\n '/v1/shields',\n generalRateLimiter,\n requirePermission(lightspeedChatReadPermission),\n apiProxy,\n );\n router.get(\n '/v2/conversations',\n generalRateLimiter,\n requirePermission(lightspeedChatReadPermission),\n apiProxy,\n );\n router.get(\n '/v2/conversations/:conversation_id',\n generalRateLimiter,\n requirePermission(lightspeedChatReadPermission),\n apiProxy,\n );\n router.delete(\n '/v2/conversations/:conversation_id',\n generalRateLimiter,\n requirePermission(lightspeedChatDeletePermission),\n apiProxy,\n );\n router.get(\n '/v1/feedback/status',\n generalRateLimiter,\n requirePermission(lightspeedChatReadPermission),\n apiProxy,\n );\n\n router.get(\n '/v1/saved-prompts/config',\n generalRateLimiter,\n requirePermission(lightspeedSavedPromptsManagePermission),\n apiProxy, // SKIP_USER_ID_ENDPOINTS prevents user_id injection for this endpoint\n );\n router.get(\n '/v1/saved-prompts',\n generalRateLimiter,\n requirePermission(lightspeedSavedPromptsManagePermission),\n apiProxy,\n );\n router.delete(\n '/v1/saved-prompts/:prompt_id',\n generalRateLimiter,\n requirePermission(lightspeedSavedPromptsManagePermission),\n apiProxy,\n );\n\n router.post(\n '/v1/feedback',\n generalRateLimiter,\n requirePermission(lightspeedChatCreatePermission),\n async (request, response) => {\n try {\n const { userEntityRef } = getIdentity(request);\n\n logger.info(`/v1/feedback receives call from user: ${userEntityRef}`);\n\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n const requestBody = JSON.stringify(request.body);\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v1/feedback?${userQueryParam}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: requestBody,\n },\n );\n\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'sending feedback',\n response,\n );\n return;\n }\n\n const data = await fetchResponse.json();\n response.status(fetchResponse.status).json(data);\n } catch (error) {\n const errormsg = `Error while sending feedback: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.post(\n '/v1/saved-prompts',\n generalRateLimiter,\n requirePermission(lightspeedSavedPromptsManagePermission),\n async (request, response) => {\n try {\n const { userEntityRef } = getIdentity(request);\n\n logger.info(\n `/v1/saved-prompts receives call from user: ${userEntityRef}`,\n );\n\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n const requestBody = JSON.stringify(request.body);\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v1/saved-prompts?${userQueryParam}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: requestBody,\n },\n );\n\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'creating saved prompt',\n response,\n );\n return;\n }\n\n const data = await fetchResponse.json();\n response.status(fetchResponse.status).json(data);\n } catch (error) {\n const errormsg = `Error while creating saved prompt: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.post(\n '/v1/query/interrupt',\n generalRateLimiter,\n requirePermission(lightspeedChatCreatePermission),\n async (request, response) => {\n try {\n const { userEntityRef } = getIdentity(request);\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n const requestBody = JSON.stringify(request.body);\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v1/streaming_query/interrupt?${userQueryParam}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: requestBody,\n },\n );\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'interrupting query',\n response,\n );\n return;\n }\n response.status(fetchResponse.status).json(await fetchResponse.json());\n } catch (error) {\n const errormsg = `Error while interrupting query: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.post(\n '/v1/query',\n express.json({ limit: EXPRESS_JSON_BODY_LIMIT }),\n expensiveRateLimiter,\n validateCompletionsRequest,\n validateAttachmentsForModel,\n requirePermission(lightspeedChatCreatePermission),\n async (request, response) => {\n const { provider }: Pick<QueryRequestBody, 'provider'> = request.body;\n try {\n const { userEntityRef, credentials } = getIdentity(request);\n logger.info(`/v1/query receives call from user: ${userEntityRef}`);\n\n if (request.body.attachments?.length) {\n logger.info(\n `/v1/query includes ${request.body.attachments.length} attachment(s): ${request.body.attachments.map((a: { attachment_type: string }) => a.attachment_type).join(', ')}`,\n );\n }\n\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n request.body.media_type = 'application/json'; // set media_type to receive start and end event\n // if system_prompt is defined in lightspeed config\n // set system_prompt to override the default rhdh system prompt\n if (system_prompt && system_prompt.trim().length > 0) {\n request.body.system_prompt = system_prompt;\n }\n\n const requestBody = JSON.stringify(request.body);\n\n // Build MCP headers from config servers + this user's preferences.\n // For servers with auth: dcr, a per-user Backstage token is minted.\n const mcpHeadersValue = await buildMcpHeaders(\n staticServers,\n settingsStore,\n userEntityRef,\n { dcrAuth: { authService: auth, credentials }, logger },\n );\n\n const abortController = new AbortController();\n\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v1/streaming_query?${userQueryParam}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'MCP-HEADERS': mcpHeadersValue,\n },\n body: requestBody,\n signal: abortController.signal,\n },\n );\n\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'processing query',\n response,\n );\n return;\n }\n\n // Pipe the response back to the original response\n if (fetchResponse.body) {\n const nodeStream = Readable.fromWeb(fetchResponse.body as any);\n\n nodeStream.on('error', (error: Error) => {\n logger.error(\n `Upstream stream error while processing query: ${error}`,\n );\n if (response.headersSent) {\n response.destroy();\n } else {\n response.status(500).json({ error: 'Stream error occurred' });\n }\n abortController.abort();\n });\n\n response.on('close', () => {\n if (!response.writableFinished) {\n logger.warn('Client disconnected while processing query');\n nodeStream.destroy();\n abortController.abort();\n }\n });\n\n nodeStream.pipe(response);\n }\n } catch (error) {\n const errormsg = `Error fetching completions from ${provider}: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.put(\n '/v2/conversations/:conversation_id',\n generalRateLimiter,\n requirePermission(lightspeedChatUpdatePermission),\n async (request, response) => {\n try {\n const { userEntityRef } = getIdentity(request);\n const conversation_id = request.params.conversation_id;\n\n const requestBody = JSON.stringify(request.body);\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v2/conversations/${conversation_id}?${userQueryParam}`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: requestBody,\n },\n );\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'updating conversation',\n response,\n );\n return;\n }\n\n const data = await fetchResponse.json();\n response.status(fetchResponse.status).json(data);\n } catch (error) {\n const errormsg = `Error while updating topic summary: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.post(\n '/v1/validate-model-vision',\n generalRateLimiter,\n requirePermission(lightspeedChatReadPermission),\n async (request, response) => {\n const { model, provider } = request.body;\n\n if (\n typeof model !== 'string' ||\n !model.trim() ||\n typeof provider !== 'string' ||\n !provider.trim()\n ) {\n response.status(400).json({ error: 'model and provider are required' });\n return;\n }\n\n const cacheKey = `${provider}/${model}`;\n\n try {\n logger.info(`Vision validation requested for model: ${cacheKey}`);\n\n if (ModelCapabilitiesCache.has(cacheKey)) {\n const cached = ModelCapabilitiesCache.get(cacheKey)!;\n logger.info(`Cache hit for ${cacheKey}: ${cached}`);\n response.json({ model, provider, supportsVision: cached });\n return;\n }\n\n const testJpeg = `data:image/jpeg;base64,${TEST_VISION_JPEG}`;\n const testResponse = await fetch(`${lcsBaseUrl}/v1/responses`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: cacheKey,\n input: [\n {\n type: 'message',\n role: 'user',\n content: [\n {\n type: 'input_image',\n image_url: testJpeg,\n detail: 'low',\n },\n {\n type: 'input_text',\n text: 'hi, respond with hi.',\n },\n ],\n },\n ],\n tool_choice: 'none',\n temperature: 0,\n store: false,\n stream: false,\n }),\n });\n\n if (testResponse.ok) {\n ModelCapabilitiesCache.set(cacheKey, true);\n response.json({ model, provider, supportsVision: true });\n } else if (testResponse.status >= 500) {\n logger.warn(\n `Vision test for ${cacheKey}: ${testResponse.status} ${testResponse.statusText}, not caching`,\n );\n response.status(502).json({\n error: `Unable to verify vision support for model — upstream returned ${testResponse.status}`,\n model,\n provider,\n });\n } else {\n ModelCapabilitiesCache.set(cacheKey, false);\n response.json({ model, provider, supportsVision: false });\n }\n } catch (error) {\n logger.error(`Vision test error for ${cacheKey}:`, error);\n response.status(502).json({\n error:\n 'Unable to verify vision support for model — upstream unreachable',\n model,\n provider,\n });\n }\n },\n );\n\n router.use((_request, response) => {\n response.status(404).json({ error: 'Requested path is not available' });\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n\n router.use(middleware.error());\n return router;\n}\n"],"names":["Router","express","DEFAULT_LIGHTSPEED_SERVICE_PORT","DEFAULT_LIGHTSPEED_SERVICE_HOST","createProxyMiddleware","rewriteProxyPath","VectorStoresOperator","createTokenEncryptor","McpUserSettingsStore","McpServerValidator","createPermissionIntegrationRouter","lightspeedPermissions","createIdentityMiddleware","userPermissionAuthorization","createPermissionMiddleware","createRateLimitMiddleware","lightspeedMcpReadPermission","getIdentity","lightspeedMcpManagePermission","NotAllowedError","lightspeedChatReadPermission","lightspeedChatDeletePermission","lightspeedSavedPromptsManagePermission","lightspeedChatCreatePermission","handleLCSFetchError","EXPRESS_JSON_BODY_LIMIT","validateCompletionsRequest","validateAttachmentsForModel","Readable","lightspeedChatUpdatePermission","ModelCapabilitiesCache","TEST_VISION_JPEG","MiddlewareFactory"],"mappings":"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"}
1
+ {"version":3,"file":"router.cjs.js","sources":["../../src/service/router.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 { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport type {\n AuthService,\n BackstageCredentials,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport type { BasicPermission } from '@backstage/plugin-permission-common';\nimport { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';\n\nimport express, { Router } from 'express';\nimport { createProxyMiddleware } from 'http-proxy-middleware';\n\nimport {\n iaChatAccessPermission,\n iaChatManagePermission,\n iaChatUsePermission,\n iaMcpManagePermission,\n iaMcpUsePermission,\n iaNotebooksUsePermission,\n iaPermissions,\n iaSavedPromptsManagePermission,\n iaSkillsAccessPermission,\n} from '@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common';\n\nimport { Readable } from 'node:stream';\n\nimport { ModelCapabilitiesCache } from './attachment-validation';\nimport {\n DEFAULT_LIGHTSPEED_SERVICE_HOST,\n DEFAULT_LIGHTSPEED_SERVICE_PORT,\n EXPRESS_JSON_BODY_LIMIT,\n TEST_VISION_JPEG,\n} from './constant';\nimport { McpUserSettingsStore } from './mcp-server-store';\nimport {\n McpServerAuth,\n McpServerResponse,\n McpServerStatus,\n McpValidationResult,\n} from './mcp-server-types';\nimport { McpServerValidator } from './mcp-server-validator';\nimport { createPermissionMiddleware } from './middleware/createPermissionMiddleware';\nimport { createRateLimitMiddleware } from './middleware/createRateLimitMiddleware';\nimport {\n createIdentityMiddleware,\n getIdentity,\n} from './middleware/getIdentity';\nimport { VectorStoresOperator } from './notebooks/VectorStoresOperator';\nimport { userPermissionAuthorization } from './permission';\nimport { createTokenEncryptor } from './token-encryption';\nimport { QueryRequestBody, RouterOptions } from './types';\nimport { handleLCSFetchError, rewriteProxyPath } from './utils';\nimport {\n validateAttachmentsForModel,\n validateCompletionsRequest,\n} from './validation';\n\n/**\n * MCP Server authentication modes for lightspeed.mcpServers entries.\n *\n * - `'dcr'` — Dynamic Client Registration. The Lightspeed backend mints a\n * short-lived Backstage plugin-request token carrying the current user's\n * identity. This token is forwarded to the MCP server via LCORE's\n * MCP-HEADERS, and the MCP Actions backend validates it against the\n * Backstage Permission Framework (RBAC). Use this for Backstage-internal\n * MCP servers (e.g. `@backstage/plugin-mcp-actions-backend`).\n * A static `token` field is **ignored** when `auth: dcr` is set.\n *\n * - (absent / undefined) — Legacy static-token mode. The token is resolved\n * from the user's DB override first, then from the `token` field in\n * app-config. If neither exists, the server is omitted from MCP-HEADERS.\n * Users can also set their own tokens via the Lightspeed UI.\n */\ninterface StaticMcpServer {\n name: string;\n token?: string;\n auth?: McpServerAuth;\n}\n\n/**\n * Build MCP-HEADERS for LCS. Format matches the LCS \"client\"/\"oauth\" auth\n * model: `{ \"server-name\": { \"Authorization\": \"<token>\" } }`\n *\n * For each admin-configured server:\n *\n * 1. If `auth: 'dcr'`, a Backstage plugin-request token is minted on behalf\n * of the authenticated user. Any static token is ignored.\n *\n * 2. Otherwise, the user's personal token (DB) takes precedence over the\n * admin default from app-config. If neither exists, the server is\n * excluded from MCP-HEADERS (LCORE will skip it or return 401).\n *\n * Servers the user has disabled are always excluded.\n */\nasync function buildMcpHeaders(\n servers: StaticMcpServer[],\n store: McpUserSettingsStore,\n userEntityRef: string,\n options?: {\n dcrAuth?: { authService: AuthService; credentials: BackstageCredentials };\n logger?: LoggerService;\n },\n): Promise<string> {\n const headers: Record<string, { Authorization: string }> = {};\n const userSettings = await store.listByUser(userEntityRef);\n const settingsMap = new Map(userSettings.map(s => [s.server_name, s]));\n\n for (const server of servers) {\n const setting = settingsMap.get(server.name);\n const enabled = setting ? Boolean(setting.enabled) : true;\n if (!enabled) continue;\n\n if (server.auth === 'dcr') {\n if (options?.dcrAuth) {\n try {\n const { token } =\n await options.dcrAuth.authService.getPluginRequestToken({\n onBehalfOf: options.dcrAuth.credentials,\n targetPluginId: 'mcp-actions',\n });\n headers[server.name] = { Authorization: `${token}` };\n } catch (err) {\n options?.logger?.error(\n `Failed to mint DCR token for MCP server '${server.name}': ${err}`,\n );\n }\n } else {\n options?.logger?.warn(\n `MCP server '${server.name}' has auth: dcr but AuthService is not available; skipping`,\n );\n }\n } else {\n // Static token: user's personal token (DB) > admin default (app-config).\n // If neither exists, the server is excluded from MCP-HEADERS.\n const token = setting?.token || server.token;\n if (token) {\n headers[server.name] = { Authorization: `${token}` };\n }\n }\n }\n\n return Object.keys(headers).length > 0 ? JSON.stringify(headers) : '';\n}\n\n/**\n * @public\n * The lightspeed backend router\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, database, httpAuth, auth, userInfo, permissions } =\n options;\n\n const router = Router();\n router.use(express.json());\n\n const port =\n config.getOptionalNumber('intelligent-assistant.servicePort') ??\n DEFAULT_LIGHTSPEED_SERVICE_PORT;\n const system_prompt = config.getOptionalString(\n 'intelligent-assistant.systemPrompt',\n );\n const lcsBaseUrl = `http://${DEFAULT_LIGHTSPEED_SERVICE_HOST}:${port}`;\n\n const apiProxy = createProxyMiddleware({\n target: lcsBaseUrl,\n changeOrigin: true,\n pathRewrite: (path, req) => {\n const userEntityRef = (req as any).userEntityRef;\n const newPath = rewriteProxyPath(path, userEntityRef);\n\n if (newPath !== path) {\n logger.info(`Rewriting path from ${path} to ${newPath}`);\n }\n return newPath;\n },\n });\n\n const vectorStoresOperator = VectorStoresOperator.getInstance(\n lcsBaseUrl,\n logger,\n );\n // Parse admin-configured MCP servers from app-config.\n //\n // Each entry supports:\n // name (required) — unique identifier, must match the name in lightspeed-stack.yaml\n // auth (optional) — authentication mode:\n // 'dcr' = the backend mints a per-user Backstage token (for\n // Backstage-internal MCP servers with DCR/OAuth enabled)\n // absent = legacy static-token mode (see `token` below)\n // token (optional) — static fallback token from app-config. Ignored when auth: dcr.\n // Users can also set personal tokens via the Lightspeed UI.\n //\n // URLs come from LCS (GET /v1/mcp-servers), not from app-config.\n const mcpServersConfig = config.getOptionalConfigArray(\n 'intelligent-assistant.mcpServers',\n );\n const staticServers: StaticMcpServer[] = [];\n if (mcpServersConfig) {\n for (const mcpServer of mcpServersConfig) {\n const authValue = mcpServer.getOptionalString('auth')?.toLowerCase();\n if (authValue && authValue !== 'dcr') {\n logger.warn(\n `MCP server '${mcpServer.getString('name')}' has unsupported auth value '${authValue}'; ` +\n `only 'dcr' is supported — falling back to static-token mode`,\n );\n }\n staticServers.push({\n name: mcpServer.getString('name'),\n token: mcpServer.getOptionalString('token'),\n auth: authValue === 'dcr' ? 'dcr' : undefined,\n });\n }\n }\n\n // Initialize database-backed store for per-user preferences and validator\n const dbClient = await database.getClient();\n const encryptor = createTokenEncryptor(config, logger);\n const settingsStore = new McpUserSettingsStore(dbClient, encryptor, logger);\n const mcpValidator = new McpServerValidator(logger);\n\n // URL cache populated from LCS GET /v1/mcp-servers.\n // The canonical URL for each MCP server lives in LCS config, not app-config.\n const lcsUrlCache = new Map<string, string>();\n\n async function refreshLcsUrlCache(): Promise<void> {\n try {\n const response = await fetch(`${lcsBaseUrl}/v1/mcp-servers`, {\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) {\n logger.warn(\n `Failed to fetch MCP server URLs from LCS: HTTP ${response.status}`,\n );\n return;\n }\n const data = (await response.json()) as {\n servers: Array<{ name: string; url: string }>;\n };\n for (const s of data.servers) {\n lcsUrlCache.set(s.name, s.url);\n }\n logger.info(`Cached ${lcsUrlCache.size} MCP server URL(s) from LCS`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n logger.warn(`Failed to fetch MCP server URLs from LCS: ${msg}`);\n }\n }\n\n function resolveServerUrl(serverName: string): string | undefined {\n return lcsUrlCache.get(serverName);\n }\n\n // Best-effort URL cache on startup (non-blocking)\n refreshLcsUrlCache().catch(() => {});\n\n router.get('/health', (_, response) => {\n response.json({ status: 'ok' });\n });\n\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n permissions: iaPermissions,\n });\n router.use(permissionIntegrationRouter);\n\n const identityMiddleware = createIdentityMiddleware(\n httpAuth,\n userInfo,\n logger,\n );\n router.use((req, res, next) => {\n // Middleware mounts to notebooks router independently\n // so we skip it here\n if (req.path.startsWith('/notebooks')) {\n return next();\n }\n return identityMiddleware(req, res, next);\n });\n\n const authorizer = userPermissionAuthorization(permissions);\n\n function requirePermission(permission: BasicPermission) {\n return createPermissionMiddleware(authorizer, permission, logger);\n }\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 // ─── MCP Server Management Endpoints ────────────────────────────────\n // All MCP servers are admin-configured (static). Users can view the\n // list, toggle servers on/off, and provide personal access tokens.\n\n router.get(\n '/mcp-servers',\n generalRateLimiter,\n requirePermission(iaMcpUsePermission),\n async (req, res) => {\n try {\n const { userEntityRef } = getIdentity(req);\n\n const userSettings = await settingsStore.listByUser(userEntityRef);\n const settingsMap = new Map(userSettings.map(s => [s.server_name, s]));\n\n const hasAllUrls = staticServers.every(s => lcsUrlCache.has(s.name));\n if (!hasAllUrls) {\n await refreshLcsUrlCache();\n }\n\n const servers: McpServerResponse[] = staticServers.map(server => {\n const setting = settingsMap.get(server.name);\n return {\n name: server.name,\n url: resolveServerUrl(server.name),\n enabled: setting ? Boolean(setting.enabled) : true,\n status: setting?.status ?? 'unknown',\n toolCount: setting?.tool_count ?? 0,\n // DCR servers always have a token (minted per-request); static servers check DB + config.\n hasToken:\n server.auth === 'dcr' || !!(setting?.token || server.token),\n hasUserToken: !!setting?.token,\n hasOrgToken: server.auth !== 'dcr' && !!server.token,\n auth: server.auth,\n };\n });\n\n res.json({ servers });\n } catch (error) {\n logger.error(`Error listing MCP servers: ${error}`);\n res.status(500).json({ error: 'Failed to list MCP servers' });\n }\n },\n );\n\n router.post(\n '/mcp-servers/validate',\n generalRateLimiter,\n requirePermission(iaMcpUsePermission),\n async (req, res) => {\n try {\n const { url, token } = req.body;\n if (!url || !token) {\n res.status(400).json({ error: 'url and token are required' });\n return;\n }\n\n // SSRF protection: only allow URLs registered in LCS\n let knownUrls = new Set(lcsUrlCache.values());\n if (!knownUrls.has(url)) {\n await refreshLcsUrlCache();\n knownUrls = new Set(lcsUrlCache.values());\n }\n if (!knownUrls.has(url)) {\n res.status(400).json({\n error:\n 'URL not recognized — only MCP server URLs registered in LCS are allowed',\n });\n return;\n }\n\n const result = await mcpValidator.validate(url, token);\n res.json(result);\n } catch (error) {\n logger.error(`Error validating MCP credentials: ${error}`);\n res.status(500).json({ error: 'Validation failed' });\n }\n },\n );\n\n router.post(\n '/mcp-servers/:name/validate',\n generalRateLimiter,\n requirePermission(iaMcpManagePermission),\n async (req, res) => {\n try {\n const { userEntityRef, credentials } = getIdentity(req);\n\n const { name } = req.params;\n const server = staticServers.find(s => s.name === name);\n if (!server) {\n res.status(404).json({\n error: `MCP server '${name}' is not configured — it must be defined in the Lightspeed Stack config and listed under intelligent-assistant.mcpServers in app-config`,\n });\n return;\n }\n // Resolve URL: LCS cache → fresh LCS fetch\n let serverUrl = resolveServerUrl(server.name);\n if (!serverUrl) {\n await refreshLcsUrlCache();\n serverUrl = resolveServerUrl(server.name);\n }\n if (!serverUrl) {\n res\n .status(400)\n .json({ error: 'Server has no URL — not found in LCS or config' });\n return;\n }\n\n let effectiveToken: string | undefined;\n if (server.auth === 'dcr') {\n try {\n const { token: dcrToken } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'mcp-actions',\n });\n effectiveToken = dcrToken;\n } catch (err) {\n logger.error(\n `Failed to mint DCR token for server '${name}': ${err}`,\n );\n res.status(502).json({\n error: `Failed to mint authentication token for DCR server '${name}' — check Backstage auth configuration`,\n });\n return;\n }\n } else {\n const setting = await settingsStore.get(name, userEntityRef);\n effectiveToken = setting?.token || server.token;\n }\n if (!effectiveToken) {\n res\n .status(400)\n .json({ error: 'No token available — provide one first' });\n return;\n }\n\n const validation = await mcpValidator.validate(\n serverUrl,\n effectiveToken,\n );\n const status: McpServerStatus = validation.valid\n ? 'connected'\n : 'error';\n\n await settingsStore.updateStatus(\n name,\n userEntityRef,\n status,\n validation.toolCount,\n );\n\n res.json({\n name,\n status,\n toolCount: validation.toolCount,\n validation,\n });\n } catch (error) {\n logger.error(`Error validating MCP server: ${error}`);\n res.status(500).json({ error: 'Validation failed' });\n }\n },\n );\n\n router.patch(\n '/mcp-servers/:name',\n generalRateLimiter,\n requirePermission(iaMcpManagePermission),\n async (req, res) => {\n try {\n const { userEntityRef } = getIdentity(req);\n\n const { name } = req.params;\n const server = staticServers.find(s => s.name === name);\n if (!server) {\n res.status(404).json({\n error: `MCP server '${name}' is not configured — it must be defined in the Lightspeed Stack config and listed under intelligent-assistant.mcpServers in app-config`,\n });\n return;\n }\n\n const body = (req.body ?? {}) as {\n enabled?: boolean;\n token?: string | null;\n };\n const hasEnabledField = Object.prototype.hasOwnProperty.call(\n body,\n 'enabled',\n );\n const hasTokenField = Object.prototype.hasOwnProperty.call(\n body,\n 'token',\n );\n const { enabled, token } = body;\n if (!hasEnabledField && !hasTokenField) {\n res.status(400).json({\n error: 'At least one of enabled or token must be provided',\n });\n return;\n }\n\n const setting = await settingsStore.upsert(name, userEntityRef, {\n enabled: hasEnabledField ? enabled : undefined,\n token: hasTokenField ? token : undefined,\n });\n\n let validation: McpValidationResult | undefined;\n let serverUrl = resolveServerUrl(server.name);\n if (token && !serverUrl) {\n await refreshLcsUrlCache();\n serverUrl = resolveServerUrl(server.name);\n }\n if (token && serverUrl) {\n validation = await mcpValidator.validate(serverUrl, token);\n const newStatus: McpServerStatus = validation.valid\n ? 'connected'\n : 'error';\n await settingsStore.updateStatus(\n name,\n userEntityRef,\n newStatus,\n validation.toolCount,\n );\n setting.status = newStatus;\n setting.tool_count = validation.toolCount;\n }\n\n const result: Record<string, unknown> = {\n server: {\n name: server.name,\n url: resolveServerUrl(server.name),\n enabled: Boolean(setting.enabled),\n status: setting.status,\n toolCount: setting.tool_count,\n hasToken:\n server.auth === 'dcr' || !!(setting.token || server.token),\n hasUserToken: !!setting.token,\n hasOrgToken: server.auth !== 'dcr' && !!server.token,\n auth: server.auth,\n },\n };\n if (validation) result.validation = validation;\n res.json(result);\n } catch (error) {\n logger.error(`Error updating MCP server settings: ${error}`);\n res.status(500).json({ error: 'Failed to update MCP server settings' });\n }\n },\n );\n\n // Returns conversation IDs associated with notebook sessions for filtering\n router.get(\n '/notebook-conversation-ids',\n generalRateLimiter,\n requirePermission(iaNotebooksUsePermission),\n async (req, res) => {\n try {\n const { userEntityRef } = getIdentity(req);\n\n const vectorStoresPage = await vectorStoresOperator.vectorStores.list();\n const vectorStores = vectorStoresPage.data || [];\n\n const conversationIds: string[] = [];\n\n for (const store of vectorStores) {\n const sessionUserId = store.metadata?.user_id as string;\n const conversationId = store.metadata?.conversation_id as\n string | null;\n\n // Only include this user's sessions with a conversation_id\n if (sessionUserId === userEntityRef && conversationId) {\n conversationIds.push(conversationId);\n }\n }\n\n res.json({\n conversation_ids: conversationIds,\n });\n } catch (error) {\n const errormsg = `Error fetching notebook conversation IDs: ${error}`;\n logger.error(errormsg);\n\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: errormsg });\n }\n }\n },\n );\n\n // ─── Proxy Routes ───────────────────────────────────────────────────\n\n router.get(\n '/v1/models',\n generalRateLimiter,\n requirePermission(iaChatAccessPermission),\n apiProxy,\n );\n router.get(\n '/v1/shields',\n generalRateLimiter,\n requirePermission(iaChatAccessPermission),\n apiProxy,\n );\n router.get(\n '/v2/conversations',\n generalRateLimiter,\n requirePermission(iaChatAccessPermission),\n apiProxy,\n );\n router.get(\n '/v2/conversations/:conversation_id',\n generalRateLimiter,\n requirePermission(iaChatAccessPermission),\n apiProxy,\n );\n router.delete(\n '/v2/conversations/:conversation_id',\n generalRateLimiter,\n requirePermission(iaChatManagePermission),\n apiProxy,\n );\n router.get(\n '/v1/feedback/status',\n generalRateLimiter,\n requirePermission(iaChatAccessPermission),\n apiProxy,\n );\n\n router.get(\n '/v1/saved-prompts/config',\n generalRateLimiter,\n requirePermission(iaSavedPromptsManagePermission),\n apiProxy, // SKIP_USER_ID_ENDPOINTS prevents user_id injection for this endpoint\n );\n router.get(\n '/v1/saved-prompts',\n generalRateLimiter,\n requirePermission(iaSavedPromptsManagePermission),\n apiProxy,\n );\n router.delete(\n '/v1/saved-prompts/:prompt_id',\n generalRateLimiter,\n requirePermission(iaSavedPromptsManagePermission),\n apiProxy,\n );\n\n router.get(\n '/v1/skills',\n generalRateLimiter,\n requirePermission(iaSkillsAccessPermission),\n apiProxy,\n );\n\n router.post(\n '/v1/feedback',\n generalRateLimiter,\n requirePermission(iaChatUsePermission),\n async (request, response) => {\n try {\n const { userEntityRef } = getIdentity(request);\n\n logger.info(`/v1/feedback receives call from user: ${userEntityRef}`);\n\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n const requestBody = JSON.stringify(request.body);\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v1/feedback?${userQueryParam}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: requestBody,\n },\n );\n\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'sending feedback',\n response,\n );\n return;\n }\n\n const data = await fetchResponse.json();\n response.status(fetchResponse.status).json(data);\n } catch (error) {\n const errormsg = `Error while sending feedback: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.post(\n '/v1/saved-prompts',\n generalRateLimiter,\n requirePermission(iaSavedPromptsManagePermission),\n async (request, response) => {\n try {\n const { userEntityRef } = getIdentity(request);\n\n logger.info(\n `/v1/saved-prompts receives call from user: ${userEntityRef}`,\n );\n\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n const requestBody = JSON.stringify(request.body);\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v1/saved-prompts?${userQueryParam}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: requestBody,\n },\n );\n\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'creating saved prompt',\n response,\n );\n return;\n }\n\n const data = await fetchResponse.json();\n response.status(fetchResponse.status).json(data);\n } catch (error) {\n const errormsg = `Error while creating saved prompt: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.post(\n '/v1/query/interrupt',\n generalRateLimiter,\n requirePermission(iaChatUsePermission),\n async (request, response) => {\n try {\n const { userEntityRef } = getIdentity(request);\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n const requestBody = JSON.stringify(request.body);\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v1/streaming_query/interrupt?${userQueryParam}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: requestBody,\n },\n );\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'interrupting query',\n response,\n );\n return;\n }\n response.status(fetchResponse.status).json(await fetchResponse.json());\n } catch (error) {\n const errormsg = `Error while interrupting query: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.post(\n '/v1/query',\n express.json({ limit: EXPRESS_JSON_BODY_LIMIT }),\n expensiveRateLimiter,\n validateCompletionsRequest,\n validateAttachmentsForModel,\n requirePermission(iaChatUsePermission),\n async (request, response) => {\n const { provider }: Pick<QueryRequestBody, 'provider'> = request.body;\n try {\n const { userEntityRef, credentials } = getIdentity(request);\n logger.info(`/v1/query receives call from user: ${userEntityRef}`);\n if (request.body.attachments?.length) {\n logger.info(\n `/v1/query includes ${request.body.attachments.length} attachment(s): ${request.body.attachments.map((a: { attachment_type: string }) => a.attachment_type).join(', ')}`,\n );\n }\n\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n request.body.media_type = 'application/json'; // set media_type to receive start and end event\n // if system_prompt is defined in lightspeed config\n // set system_prompt to override the default rhdh system prompt\n if (system_prompt && system_prompt.trim().length > 0) {\n request.body.system_prompt = system_prompt;\n }\n\n const requestBody = JSON.stringify(request.body);\n\n // Build MCP headers from config servers + this user's preferences.\n // For servers with auth: dcr, a per-user Backstage token is minted.\n const mcpHeadersValue = await buildMcpHeaders(\n staticServers,\n settingsStore,\n userEntityRef,\n { dcrAuth: { authService: auth, credentials }, logger },\n );\n\n const abortController = new AbortController();\n\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v1/streaming_query?${userQueryParam}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'MCP-HEADERS': mcpHeadersValue,\n },\n body: requestBody,\n signal: abortController.signal,\n },\n );\n\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'processing query',\n response,\n );\n return;\n }\n\n // Pipe the response back to the original response\n if (fetchResponse.body) {\n const nodeStream = Readable.fromWeb(fetchResponse.body as any);\n\n nodeStream.on('error', (error: Error) => {\n logger.error(\n `Upstream stream error while processing query: ${error}`,\n );\n if (response.headersSent) {\n response.destroy();\n } else {\n response.status(500).json({ error: 'Stream error occurred' });\n }\n abortController.abort();\n });\n\n response.on('close', () => {\n if (!response.writableFinished) {\n logger.warn('Client disconnected while processing query');\n nodeStream.destroy();\n abortController.abort();\n }\n });\n\n nodeStream.pipe(response);\n }\n } catch (error) {\n const errormsg = `Error fetching completions from ${provider}: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.put(\n '/v2/conversations/:conversation_id',\n generalRateLimiter,\n requirePermission(iaChatManagePermission),\n async (request, response) => {\n try {\n const { userEntityRef } = getIdentity(request);\n const conversation_id = request.params.conversation_id;\n\n const requestBody = JSON.stringify(request.body);\n const userQueryParam = `user_id=${encodeURIComponent(userEntityRef)}`;\n const fetchResponse = await fetch(\n `${lcsBaseUrl}/v2/conversations/${conversation_id}?${userQueryParam}`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: requestBody,\n },\n );\n if (!fetchResponse.ok) {\n await handleLCSFetchError(\n fetchResponse,\n logger,\n 'updating conversation',\n response,\n );\n return;\n }\n\n const data = await fetchResponse.json();\n response.status(fetchResponse.status).json(data);\n } catch (error) {\n const errormsg = `Error while updating topic summary: ${error}`;\n logger.error(errormsg);\n response.status(500).json({ error: errormsg });\n }\n },\n );\n\n router.post(\n '/v1/validate-model-vision',\n generalRateLimiter,\n requirePermission(iaChatUsePermission),\n async (request, response) => {\n const { model, provider } = request.body;\n\n if (\n typeof model !== 'string' ||\n !model.trim() ||\n typeof provider !== 'string' ||\n !provider.trim()\n ) {\n response.status(400).json({ error: 'model and provider are required' });\n return;\n }\n\n const cacheKey = `${provider}/${model}`;\n\n try {\n logger.info(`Vision validation requested for model: ${cacheKey}`);\n\n if (ModelCapabilitiesCache.has(cacheKey)) {\n const cached = ModelCapabilitiesCache.get(cacheKey)!;\n logger.info(`Cache hit for ${cacheKey}: ${cached}`);\n response.json({ model, provider, supportsVision: cached });\n return;\n }\n\n const testJpeg = `data:image/jpeg;base64,${TEST_VISION_JPEG}`;\n const testResponse = await fetch(`${lcsBaseUrl}/v1/responses`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: cacheKey,\n input: [\n {\n type: 'message',\n role: 'user',\n content: [\n {\n type: 'input_image',\n image_url: testJpeg,\n detail: 'low',\n },\n {\n type: 'input_text',\n text: 'hi, respond with hi.',\n },\n ],\n },\n ],\n tool_choice: 'none',\n temperature: 0,\n store: false,\n stream: false,\n }),\n });\n\n if (testResponse.ok) {\n ModelCapabilitiesCache.set(cacheKey, true);\n response.json({ model, provider, supportsVision: true });\n }\n } catch (error) {\n logger.error(`Vision test error for ${cacheKey}:`, error);\n response.status(502).json({\n error:\n 'Unable to verify vision support for model — upstream unreachable',\n model,\n provider,\n });\n }\n },\n );\n\n router.use((_request, response) => {\n response.status(404).json({ error: 'Requested path is not available' });\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n\n router.use(middleware.error());\n return router;\n}\n"],"names":["Router","express","DEFAULT_LIGHTSPEED_SERVICE_PORT","DEFAULT_LIGHTSPEED_SERVICE_HOST","createProxyMiddleware","rewriteProxyPath","VectorStoresOperator","createTokenEncryptor","McpUserSettingsStore","McpServerValidator","createPermissionIntegrationRouter","iaPermissions","createIdentityMiddleware","userPermissionAuthorization","createPermissionMiddleware","createRateLimitMiddleware","iaMcpUsePermission","getIdentity","iaMcpManagePermission","iaNotebooksUsePermission","NotAllowedError","iaChatAccessPermission","iaChatManagePermission","iaSavedPromptsManagePermission","iaSkillsAccessPermission","iaChatUsePermission","handleLCSFetchError","EXPRESS_JSON_BODY_LIMIT","validateCompletionsRequest","validateAttachmentsForModel","Readable","ModelCapabilitiesCache","TEST_VISION_JPEG","MiddlewareFactory"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@red-hat-developer-hub/backstage-plugin-intelligent-assistant-backend",
3
- "version": "3.2.0",
3
+ "version": "4.0.0",
4
4
  "main": "./dist/index.cjs.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -58,7 +58,7 @@
58
58
  "@backstage/plugin-permission-node": "^0.11.1",
59
59
  "@langchain/core": "^0.3.80",
60
60
  "@langchain/openai": "^0.6.0",
61
- "@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common": "^3.2.0",
61
+ "@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common": "^4.0.0",
62
62
  "express": "^4.21.1",
63
63
  "express-rate-limit": "^8.2.2",
64
64
  "form-data": "^4.0.6",