@eclipse-lyra/extension-rag-system 0.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/dist/api.d.ts +9 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +90 -0
- package/dist/api.js.map +1 -0
- package/dist/chunkers/chunker-interface.d.ts +21 -0
- package/dist/chunkers/chunker-interface.d.ts.map +1 -0
- package/dist/chunkers/document-chunker.d.ts +12 -0
- package/dist/chunkers/document-chunker.d.ts.map +1 -0
- package/dist/chunkers/fallback-chunker.d.ts +10 -0
- package/dist/chunkers/fallback-chunker.d.ts.map +1 -0
- package/dist/chunkers/langchain-chunker.d.ts +12 -0
- package/dist/chunkers/langchain-chunker.d.ts.map +1 -0
- package/dist/document-index-service.d.ts +102 -0
- package/dist/document-index-service.d.ts.map +1 -0
- package/dist/embedding-service.d.ts +18 -0
- package/dist/embedding-service.d.ts.map +1 -0
- package/dist/extractors/document-extractor-interface.d.ts +26 -0
- package/dist/extractors/document-extractor-interface.d.ts.map +1 -0
- package/dist/extractors/document-extractor.d.ts +13 -0
- package/dist/extractors/document-extractor.d.ts.map +1 -0
- package/dist/extractors/llm-ocr-extractor.d.ts +16 -0
- package/dist/extractors/llm-ocr-extractor.d.ts.map +1 -0
- package/dist/extractors/pdfjs-extractor.d.ts +7 -0
- package/dist/extractors/pdfjs-extractor.d.ts.map +1 -0
- package/dist/i18n.json.d.ts +13 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/rag-integration-DO7-zvk2.js +191 -0
- package/dist/rag-integration-DO7-zvk2.js.map +1 -0
- package/dist/rag-integration.d.ts +6 -0
- package/dist/rag-integration.d.ts.map +1 -0
- package/dist/rag-service-BKBGCuO-.js +1872 -0
- package/dist/rag-service-BKBGCuO-.js.map +1 -0
- package/dist/rag-service.d.ts +25 -0
- package/dist/rag-service.d.ts.map +1 -0
- package/dist/rag-system-extension-DfD6H8Vr.js +1142 -0
- package/dist/rag-system-extension-DfD6H8Vr.js.map +1 -0
- package/dist/rag-system-extension.d.ts +2 -0
- package/dist/rag-system-extension.d.ts.map +1 -0
- package/dist/rag-system-manager.d.ts +41 -0
- package/dist/rag-system-manager.d.ts.map +1 -0
- package/dist/rxdb-loader.d.ts +9 -0
- package/dist/rxdb-loader.d.ts.map +1 -0
- package/dist/services/rag-result-formatter.d.ts +23 -0
- package/dist/services/rag-result-formatter.d.ts.map +1 -0
- package/dist/services/relevance-calculator.d.ts +7 -0
- package/dist/services/relevance-calculator.d.ts.map +1 -0
- package/dist/utils/constants.d.ts +35 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/context-scopes.d.ts +39 -0
- package/dist/utils/context-scopes.d.ts.map +1 -0
- package/dist/utils/query-utils.d.ts +7 -0
- package/dist/utils/query-utils.d.ts.map +1 -0
- package/dist/utils/snippet-extractor.d.ts +22 -0
- package/dist/utils/snippet-extractor.d.ts.map +1 -0
- package/dist/utils/workspace-utils.d.ts +8 -0
- package/dist/utils/workspace-utils.d.ts.map +1 -0
- package/dist/vector-utils.d.ts +28 -0
- package/dist/vector-utils.d.ts.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,1142 @@
|
|
|
1
|
+
import { S as SnippetExtractor, d as documentIndexService, f as getWorkspacePath, s as searchWorkspaceDocuments, h as SNIPPET_LENGTHS, C as CONTENT_PREVIEW_LENGTHS } from "./rag-service-BKBGCuO-.js";
|
|
2
|
+
import { createLogger, LyraPart, toastError, toastInfo, File, taskService, editorRegistry, registerAll, activeSelectionSignal, workspaceService, TOOLBAR_MAIN_RIGHT, contributionRegistry } from "@eclipse-lyra/core";
|
|
3
|
+
import { css, html, nothing } from "lit";
|
|
4
|
+
import { property, state, customElement } from "lit/decorators.js";
|
|
5
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
9
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
10
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
11
|
+
if (decorator = decorators[i])
|
|
12
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
13
|
+
if (kind && result) __defProp(target, key, result);
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
16
|
+
const logger$1 = createLogger("RAGSystemManager");
|
|
17
|
+
const snippetExtractor = new SnippetExtractor();
|
|
18
|
+
let LyraRAGSystemManager = class extends LyraPart {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
this.documents = [];
|
|
22
|
+
this.stats = {
|
|
23
|
+
totalDocuments: 0,
|
|
24
|
+
byWorkspace: {}
|
|
25
|
+
};
|
|
26
|
+
this.loading = false;
|
|
27
|
+
this.selectedDocument = null;
|
|
28
|
+
this.searchQuery = "";
|
|
29
|
+
this.filterWorkspace = null;
|
|
30
|
+
this.filterByActiveWorkspace = true;
|
|
31
|
+
this.filteredDocuments = [];
|
|
32
|
+
this.searchResults = /* @__PURE__ */ new Map();
|
|
33
|
+
this.reindexing = false;
|
|
34
|
+
this.treeRef = createRef();
|
|
35
|
+
this.searchInputValue = "";
|
|
36
|
+
}
|
|
37
|
+
async doInitUI() {
|
|
38
|
+
try {
|
|
39
|
+
await documentIndexService.initialize();
|
|
40
|
+
await Promise.all([
|
|
41
|
+
this.loadDocuments(),
|
|
42
|
+
this.loadStats()
|
|
43
|
+
]);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
logger$1.error(`Failed to initialize document index manager: ${error}`);
|
|
46
|
+
toastError(`Failed to initialize: ${error}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async loadDocuments() {
|
|
50
|
+
this.loading = true;
|
|
51
|
+
this.requestUpdate();
|
|
52
|
+
try {
|
|
53
|
+
let workspacePath;
|
|
54
|
+
if (this.filterByActiveWorkspace) {
|
|
55
|
+
const workspaceResult = await getWorkspacePath();
|
|
56
|
+
workspacePath = workspaceResult?.workspacePath;
|
|
57
|
+
}
|
|
58
|
+
this.documents = await documentIndexService.listDocuments(workspacePath);
|
|
59
|
+
await this.updateFilteredDocuments();
|
|
60
|
+
} catch (error) {
|
|
61
|
+
logger$1.error(`Failed to load documents: ${error}`);
|
|
62
|
+
toastError(`Failed to load documents: ${error}`);
|
|
63
|
+
} finally {
|
|
64
|
+
this.loading = false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async updateFilteredDocuments() {
|
|
68
|
+
this.filteredDocuments = await this.getFilteredDocuments();
|
|
69
|
+
this.requestUpdate();
|
|
70
|
+
}
|
|
71
|
+
async loadStats() {
|
|
72
|
+
try {
|
|
73
|
+
this.stats = await documentIndexService.getStats();
|
|
74
|
+
this.requestUpdate();
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logger$1.error(`Failed to load stats: ${error}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
handleTreeSelection(e) {
|
|
80
|
+
let selection = e.detail?.selection || [];
|
|
81
|
+
if (selection.length === 0 && this.treeRef.value) {
|
|
82
|
+
selection = this.treeRef.value.selectedItems || [];
|
|
83
|
+
}
|
|
84
|
+
if (selection.length > 0) {
|
|
85
|
+
const selectedItem = selection[0];
|
|
86
|
+
if (selectedItem?.model) {
|
|
87
|
+
this.selectedDocument = selectedItem.model;
|
|
88
|
+
} else {
|
|
89
|
+
this.selectedDocument = null;
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
this.selectedDocument = null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async getFilteredDocuments() {
|
|
96
|
+
if (!this.documents || this.documents.length === 0) {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
if (this.searchQuery.trim()) {
|
|
100
|
+
try {
|
|
101
|
+
const searchResults = await searchWorkspaceDocuments(this.searchQuery, {
|
|
102
|
+
limit: 50,
|
|
103
|
+
workspacePath: this.filterWorkspace || void 0
|
|
104
|
+
});
|
|
105
|
+
this.searchResults.clear();
|
|
106
|
+
const uniqueDocs = /* @__PURE__ */ new Map();
|
|
107
|
+
const aggregatedResults = /* @__PURE__ */ new Map();
|
|
108
|
+
for (const result of searchResults) {
|
|
109
|
+
const docId = result.document.id;
|
|
110
|
+
uniqueDocs.set(docId, result.document);
|
|
111
|
+
const existing = aggregatedResults.get(docId);
|
|
112
|
+
if (!existing) {
|
|
113
|
+
aggregatedResults.set(docId, {
|
|
114
|
+
document: result.document,
|
|
115
|
+
relevance: result.relevance,
|
|
116
|
+
matchedSnippets: [...result.matchedSnippets]
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
if (result.relevance > existing.relevance) {
|
|
120
|
+
existing.relevance = result.relevance;
|
|
121
|
+
}
|
|
122
|
+
const seenSnippets = new Set(existing.matchedSnippets);
|
|
123
|
+
for (const snippet of result.matchedSnippets) {
|
|
124
|
+
if (!seenSnippets.has(snippet)) {
|
|
125
|
+
existing.matchedSnippets.push(snippet);
|
|
126
|
+
seenSnippets.add(snippet);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const [docId, result] of aggregatedResults) {
|
|
132
|
+
this.searchResults.set(docId, result);
|
|
133
|
+
}
|
|
134
|
+
const resultDocs = Array.from(uniqueDocs.values());
|
|
135
|
+
if (this.filterWorkspace) {
|
|
136
|
+
return resultDocs.filter((doc) => doc.workspacePath === this.filterWorkspace);
|
|
137
|
+
}
|
|
138
|
+
return resultDocs;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
logger$1.debug(`RAG search failed in document manager: ${error}`);
|
|
141
|
+
this.searchResults.clear();
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
this.searchResults.clear();
|
|
146
|
+
}
|
|
147
|
+
let filtered = [...this.documents];
|
|
148
|
+
if (this.filterWorkspace) {
|
|
149
|
+
filtered = filtered.filter((doc) => doc.workspacePath === this.filterWorkspace);
|
|
150
|
+
}
|
|
151
|
+
return filtered;
|
|
152
|
+
}
|
|
153
|
+
highlightMatches(text, query) {
|
|
154
|
+
if (!query || !query.trim()) {
|
|
155
|
+
return html`${text}`;
|
|
156
|
+
}
|
|
157
|
+
const queryLower = query.toLowerCase();
|
|
158
|
+
const textLower = text.toLowerCase();
|
|
159
|
+
const parts = [];
|
|
160
|
+
let lastIndex = 0;
|
|
161
|
+
let index = textLower.indexOf(queryLower, lastIndex);
|
|
162
|
+
while (index !== -1) {
|
|
163
|
+
if (index > lastIndex) {
|
|
164
|
+
parts.push(text.substring(lastIndex, index));
|
|
165
|
+
}
|
|
166
|
+
parts.push(html`<mark class="search-match">${text.substring(index, index + query.length)}</mark>`);
|
|
167
|
+
lastIndex = index + query.length;
|
|
168
|
+
index = textLower.indexOf(queryLower, lastIndex);
|
|
169
|
+
}
|
|
170
|
+
if (lastIndex < text.length) {
|
|
171
|
+
parts.push(text.substring(lastIndex));
|
|
172
|
+
}
|
|
173
|
+
return html`${parts}`;
|
|
174
|
+
}
|
|
175
|
+
getContentPreview(doc) {
|
|
176
|
+
const searchResult = this.searchResults.get(doc.id);
|
|
177
|
+
if (searchResult && searchResult.matchedSnippets.length > 0) {
|
|
178
|
+
return html`
|
|
179
|
+
<table class="snippets-table">
|
|
180
|
+
<thead>
|
|
181
|
+
<tr>
|
|
182
|
+
<th class="snippet-number-col">#</th>
|
|
183
|
+
<th class="snippet-content-col">Content</th>
|
|
184
|
+
</tr>
|
|
185
|
+
</thead>
|
|
186
|
+
<tbody>
|
|
187
|
+
${searchResult.matchedSnippets.map((snippet, idx) => html`
|
|
188
|
+
<tr>
|
|
189
|
+
<td class="snippet-number">${idx + 1}</td>
|
|
190
|
+
<td class="snippet-content">${this.highlightMatches(snippet, this.searchQuery)}</td>
|
|
191
|
+
</tr>
|
|
192
|
+
`)}
|
|
193
|
+
</tbody>
|
|
194
|
+
</table>
|
|
195
|
+
`;
|
|
196
|
+
}
|
|
197
|
+
if (this.searchQuery && this.searchQuery.trim()) {
|
|
198
|
+
const snippets = snippetExtractor.extractContextSnippets(
|
|
199
|
+
doc.content,
|
|
200
|
+
this.searchQuery,
|
|
201
|
+
SNIPPET_LENGTHS.CONTEXT
|
|
202
|
+
);
|
|
203
|
+
if (snippets.length > 0) {
|
|
204
|
+
return html`
|
|
205
|
+
<table class="snippets-table">
|
|
206
|
+
<thead>
|
|
207
|
+
<tr>
|
|
208
|
+
<th class="snippet-number-col">#</th>
|
|
209
|
+
<th class="snippet-content-col">Content</th>
|
|
210
|
+
</tr>
|
|
211
|
+
</thead>
|
|
212
|
+
<tbody>
|
|
213
|
+
${snippets.map((snippet, idx) => html`
|
|
214
|
+
<tr>
|
|
215
|
+
<td class="snippet-number">${idx + 1}</td>
|
|
216
|
+
<td class="snippet-content">${this.highlightMatches(doc.content.substring(snippet.start, snippet.end), this.searchQuery)}</td>
|
|
217
|
+
</tr>
|
|
218
|
+
`)}
|
|
219
|
+
</tbody>
|
|
220
|
+
</table>
|
|
221
|
+
`;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const preview = snippetExtractor.extractSimpleSnippet(doc.content, CONTENT_PREVIEW_LENGTHS.LONG);
|
|
225
|
+
return html`
|
|
226
|
+
<div class="snippet-preview">${preview}</div>
|
|
227
|
+
`;
|
|
228
|
+
}
|
|
229
|
+
async deleteDocument(doc) {
|
|
230
|
+
try {
|
|
231
|
+
await documentIndexService.deleteDocument(doc.id);
|
|
232
|
+
toastInfo(`Deleted: ${doc.fileName}`);
|
|
233
|
+
await this.loadDocuments();
|
|
234
|
+
await this.loadStats();
|
|
235
|
+
if (this.selectedDocument?.id === doc.id) {
|
|
236
|
+
this.selectedDocument = null;
|
|
237
|
+
}
|
|
238
|
+
} catch (error) {
|
|
239
|
+
toastError(`Failed to delete document: ${error}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async reindexDocument(doc) {
|
|
243
|
+
try {
|
|
244
|
+
const workspaceResult = await getWorkspacePath();
|
|
245
|
+
if (!workspaceResult) {
|
|
246
|
+
toastError("No workspace connected");
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const resource = await workspaceResult.workspace.getResource(doc.filePath);
|
|
250
|
+
if (!resource) {
|
|
251
|
+
toastError(`File not found: ${doc.filePath}`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (!(resource instanceof File)) {
|
|
255
|
+
toastError(`Resource is not a file: ${doc.filePath}`);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const file = resource;
|
|
259
|
+
await taskService.runAsync("Reindexing document", async (progress) => {
|
|
260
|
+
progress.message = `Reindexing ${doc.fileName}...`;
|
|
261
|
+
await documentIndexService.reindexDocument(file);
|
|
262
|
+
progress.progress = 100;
|
|
263
|
+
});
|
|
264
|
+
toastInfo(`Reindexed: ${doc.fileName}`);
|
|
265
|
+
await this.loadDocuments();
|
|
266
|
+
if (this.selectedDocument?.id === doc.id) {
|
|
267
|
+
this.selectedDocument = await documentIndexService.getDocument(doc.id);
|
|
268
|
+
}
|
|
269
|
+
} catch (error) {
|
|
270
|
+
toastError(`Failed to reindex document: ${error}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
async reindexAllDocuments() {
|
|
274
|
+
if (this.reindexing) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const stats = await documentIndexService.getStats();
|
|
278
|
+
if (stats.totalDocuments === 0) {
|
|
279
|
+
toastInfo("No documents to reindex");
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
this.reindexing = true;
|
|
283
|
+
this.requestUpdate();
|
|
284
|
+
try {
|
|
285
|
+
const result = await taskService.runAsync("Reindexing all documents", async (progress) => {
|
|
286
|
+
progress.message = "Starting reindexing...";
|
|
287
|
+
const total = stats.totalDocuments;
|
|
288
|
+
const reindexResult = await documentIndexService.reindexAllDocuments();
|
|
289
|
+
const processed = reindexResult.succeeded + reindexResult.failed;
|
|
290
|
+
progress.progress = total > 0 ? processed / total * 100 : 100;
|
|
291
|
+
progress.message = `Reindexed ${reindexResult.succeeded}/${total} documents${reindexResult.failed > 0 ? ` (${reindexResult.failed} failed)` : ""}`;
|
|
292
|
+
return reindexResult;
|
|
293
|
+
});
|
|
294
|
+
await this.loadDocuments();
|
|
295
|
+
await this.loadStats();
|
|
296
|
+
toastInfo(`Reindexing completed: ${result.succeeded} succeeded, ${result.failed} failed`);
|
|
297
|
+
} catch (error) {
|
|
298
|
+
logger$1.error(`Failed to reindex all documents: ${error}`);
|
|
299
|
+
toastError(`Failed to reindex all documents: ${error}`);
|
|
300
|
+
} finally {
|
|
301
|
+
this.reindexing = false;
|
|
302
|
+
this.requestUpdate();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
formatFileSize(bytes) {
|
|
306
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
307
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} LyraB`;
|
|
308
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
309
|
+
}
|
|
310
|
+
formatDate(timestamp) {
|
|
311
|
+
return new Date(timestamp).toLocaleString();
|
|
312
|
+
}
|
|
313
|
+
getFileIcon(fileType) {
|
|
314
|
+
return editorRegistry.getFileIcon(fileType);
|
|
315
|
+
}
|
|
316
|
+
renderToolbar() {
|
|
317
|
+
const workspaces = Object.keys(this.stats?.byWorkspace || {});
|
|
318
|
+
return html`
|
|
319
|
+
<wa-input
|
|
320
|
+
type="search"
|
|
321
|
+
placeholder="Search documents..."
|
|
322
|
+
.value=${this.searchInputValue}
|
|
323
|
+
@input=${(e) => {
|
|
324
|
+
this.searchInputValue = e.target.value;
|
|
325
|
+
if (this.searchDebounceTimer) {
|
|
326
|
+
clearTimeout(this.searchDebounceTimer);
|
|
327
|
+
}
|
|
328
|
+
this.searchDebounceTimer = window.setTimeout(async () => {
|
|
329
|
+
this.searchQuery = this.searchInputValue;
|
|
330
|
+
await this.updateFilteredDocuments();
|
|
331
|
+
}, 200);
|
|
332
|
+
}}
|
|
333
|
+
@wa-clear=${async () => {
|
|
334
|
+
if (this.searchDebounceTimer) {
|
|
335
|
+
clearTimeout(this.searchDebounceTimer);
|
|
336
|
+
}
|
|
337
|
+
this.searchInputValue = "";
|
|
338
|
+
this.searchQuery = "";
|
|
339
|
+
await this.updateFilteredDocuments();
|
|
340
|
+
}}
|
|
341
|
+
size="small"
|
|
342
|
+
with-clear
|
|
343
|
+
autocomplete="off"
|
|
344
|
+
style="flex: 1; max-width: 400px;">
|
|
345
|
+
<wa-icon name="magnifying-glass" slot="start"></wa-icon>
|
|
346
|
+
</wa-input>
|
|
347
|
+
|
|
348
|
+
<wa-switch
|
|
349
|
+
.checked=${this.filterByActiveWorkspace}
|
|
350
|
+
@change=${async (e) => {
|
|
351
|
+
this.filterByActiveWorkspace = e.target.checked;
|
|
352
|
+
await this.loadDocuments();
|
|
353
|
+
}}
|
|
354
|
+
size="small">
|
|
355
|
+
Active workspace only
|
|
356
|
+
</wa-switch>
|
|
357
|
+
|
|
358
|
+
${workspaces.length > 1 ? html`
|
|
359
|
+
<wa-select
|
|
360
|
+
.value=${this.filterWorkspace || ""}
|
|
361
|
+
@change=${async (e) => {
|
|
362
|
+
this.filterWorkspace = e.target.value || null;
|
|
363
|
+
await this.updateFilteredDocuments();
|
|
364
|
+
}}
|
|
365
|
+
size="small"
|
|
366
|
+
style="width: 200px;">
|
|
367
|
+
<wa-option value="">All Workspaces</wa-option>
|
|
368
|
+
${workspaces.map((ws) => html`
|
|
369
|
+
<wa-option value="${ws}">${ws} (${this.stats.byWorkspace[ws]})</wa-option>
|
|
370
|
+
`)}
|
|
371
|
+
</wa-select>
|
|
372
|
+
` : nothing}
|
|
373
|
+
|
|
374
|
+
<lyra-command
|
|
375
|
+
size="small"
|
|
376
|
+
icon="arrow-rotate-right"
|
|
377
|
+
title="Refresh document list"
|
|
378
|
+
.action=${() => this.loadDocuments()}
|
|
379
|
+
?disabled=${this.reindexing}>
|
|
380
|
+
Refresh
|
|
381
|
+
</lyra-command>
|
|
382
|
+
|
|
383
|
+
<lyra-command
|
|
384
|
+
size="small"
|
|
385
|
+
icon="database"
|
|
386
|
+
title="Re-index all documents"
|
|
387
|
+
.action=${() => this.reindexAllDocuments()}
|
|
388
|
+
?disabled=${this.reindexing || this.loading}>
|
|
389
|
+
${this.reindexing ? "Reindexing..." : "Re-index All"}
|
|
390
|
+
</lyra-command>
|
|
391
|
+
`;
|
|
392
|
+
}
|
|
393
|
+
render() {
|
|
394
|
+
if (!this.stats) {
|
|
395
|
+
this.stats = { totalDocuments: 0, byWorkspace: {} };
|
|
396
|
+
}
|
|
397
|
+
const filteredDocs = this.filteredDocuments;
|
|
398
|
+
const workspaces = Object.keys(this.stats.byWorkspace || {});
|
|
399
|
+
return html`
|
|
400
|
+
<div class="rag-system-manager">
|
|
401
|
+
<div class="header">
|
|
402
|
+
<div class="header-content">
|
|
403
|
+
<div class="stats">
|
|
404
|
+
<span>Total: ${this.stats.totalDocuments} documents</span>
|
|
405
|
+
${workspaces.length > 0 ? html`
|
|
406
|
+
<span>Workspaces: ${workspaces.length}</span>
|
|
407
|
+
` : nothing}
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
|
|
412
|
+
<wa-split-panel position="40" style="height: 100%;">
|
|
413
|
+
<div class="document-list" slot="start">
|
|
414
|
+
${this.loading ? html`
|
|
415
|
+
<div class="loading">
|
|
416
|
+
<wa-spinner></wa-spinner>
|
|
417
|
+
<span>Loading documents...</span>
|
|
418
|
+
</div>
|
|
419
|
+
` : filteredDocs.length === 0 ? html`
|
|
420
|
+
<div class="empty">
|
|
421
|
+
<wa-icon name="inbox" style="font-size: 3rem; opacity: 0.3;"></wa-icon>
|
|
422
|
+
<p>${this.searchQuery || this.filterWorkspace ? "No documents match your filters" : "No documents indexed yet"}</p>
|
|
423
|
+
</div>
|
|
424
|
+
` : html`
|
|
425
|
+
<wa-tree
|
|
426
|
+
${ref(this.treeRef)}
|
|
427
|
+
selection="leaf"
|
|
428
|
+
style="--indent-guide-width: 1px;"
|
|
429
|
+
@wa-selection-change=${(e) => {
|
|
430
|
+
this.handleTreeSelection(e);
|
|
431
|
+
}}>
|
|
432
|
+
${filteredDocs.map((doc) => html`
|
|
433
|
+
<wa-tree-item
|
|
434
|
+
.model=${doc}
|
|
435
|
+
?selected=${this.selectedDocument?.id === doc.id}>
|
|
436
|
+
<wa-icon name="${this.getFileIcon(doc.fileType)}"></wa-icon>
|
|
437
|
+
<div class="tree-item-info">
|
|
438
|
+
<strong class="tree-item-path">${doc.filePath}</strong>
|
|
439
|
+
<div class="tree-item-meta">
|
|
440
|
+
<small class="meta-size">${this.formatFileSize(doc.metadata.size)}</small>
|
|
441
|
+
<small class="meta-date">${this.formatDate(doc.indexedAt)}</small>
|
|
442
|
+
</div>
|
|
443
|
+
</div>
|
|
444
|
+
<div class="tree-item-actions" @click=${(e) => e.stopPropagation()}>
|
|
445
|
+
<wa-button
|
|
446
|
+
variant="neutral"
|
|
447
|
+
appearance="plain"
|
|
448
|
+
size="small"
|
|
449
|
+
title="Reindex"
|
|
450
|
+
@click=${() => this.reindexDocument(doc)}>
|
|
451
|
+
<wa-icon name="arrow-rotate-right"></wa-icon>
|
|
452
|
+
</wa-button>
|
|
453
|
+
<wa-button
|
|
454
|
+
variant="danger"
|
|
455
|
+
appearance="plain"
|
|
456
|
+
size="small"
|
|
457
|
+
title="Delete"
|
|
458
|
+
@click=${() => this.deleteDocument(doc)}>
|
|
459
|
+
<wa-icon name="trash"></wa-icon>
|
|
460
|
+
</wa-button>
|
|
461
|
+
</div>
|
|
462
|
+
</wa-tree-item>
|
|
463
|
+
`)}
|
|
464
|
+
</wa-tree>
|
|
465
|
+
`}
|
|
466
|
+
</div>
|
|
467
|
+
|
|
468
|
+
<div slot="end">
|
|
469
|
+
${this.selectedDocument ? html`
|
|
470
|
+
<div class="document-details">
|
|
471
|
+
<div class="details-content">
|
|
472
|
+
<div class="metadata-grid">
|
|
473
|
+
<wa-input
|
|
474
|
+
label="File Path"
|
|
475
|
+
.value=${this.selectedDocument.filePath}
|
|
476
|
+
readonly
|
|
477
|
+
size="small">
|
|
478
|
+
<wa-copy-button
|
|
479
|
+
slot="end"
|
|
480
|
+
.value=${this.selectedDocument.filePath}
|
|
481
|
+
size="small"
|
|
482
|
+
label="Copy file path">
|
|
483
|
+
</wa-copy-button>
|
|
484
|
+
</wa-input>
|
|
485
|
+
|
|
486
|
+
<wa-input
|
|
487
|
+
label="Workspace"
|
|
488
|
+
.value=${this.selectedDocument.workspacePath}
|
|
489
|
+
readonly
|
|
490
|
+
size="small">
|
|
491
|
+
<wa-copy-button
|
|
492
|
+
slot="end"
|
|
493
|
+
.value=${this.selectedDocument.workspacePath}
|
|
494
|
+
size="small"
|
|
495
|
+
label="Copy workspace">
|
|
496
|
+
</wa-copy-button>
|
|
497
|
+
</wa-input>
|
|
498
|
+
|
|
499
|
+
<wa-input
|
|
500
|
+
label="File Type"
|
|
501
|
+
.value=${this.selectedDocument.fileType}
|
|
502
|
+
readonly
|
|
503
|
+
size="small">
|
|
504
|
+
<wa-copy-button
|
|
505
|
+
slot="end"
|
|
506
|
+
.value=${this.selectedDocument.fileType}
|
|
507
|
+
size="small"
|
|
508
|
+
label="Copy file type">
|
|
509
|
+
</wa-copy-button>
|
|
510
|
+
</wa-input>
|
|
511
|
+
|
|
512
|
+
<wa-input
|
|
513
|
+
label="Size"
|
|
514
|
+
.value=${this.formatFileSize(this.selectedDocument.metadata.size)}
|
|
515
|
+
readonly
|
|
516
|
+
size="small">
|
|
517
|
+
<wa-copy-button
|
|
518
|
+
slot="end"
|
|
519
|
+
.value=${this.formatFileSize(this.selectedDocument.metadata.size)}
|
|
520
|
+
size="small"
|
|
521
|
+
label="Copy size">
|
|
522
|
+
</wa-copy-button>
|
|
523
|
+
</wa-input>
|
|
524
|
+
|
|
525
|
+
<wa-input
|
|
526
|
+
label="Indexed At"
|
|
527
|
+
.value=${this.formatDate(this.selectedDocument.indexedAt)}
|
|
528
|
+
readonly
|
|
529
|
+
size="small">
|
|
530
|
+
<wa-copy-button
|
|
531
|
+
slot="end"
|
|
532
|
+
.value=${this.formatDate(this.selectedDocument.indexedAt)}
|
|
533
|
+
size="small"
|
|
534
|
+
label="Copy indexed date">
|
|
535
|
+
</wa-copy-button>
|
|
536
|
+
</wa-input>
|
|
537
|
+
|
|
538
|
+
<wa-input
|
|
539
|
+
label="Last Updated"
|
|
540
|
+
.value=${this.formatDate(this.selectedDocument.updatedAt)}
|
|
541
|
+
readonly
|
|
542
|
+
size="small">
|
|
543
|
+
<wa-copy-button
|
|
544
|
+
slot="end"
|
|
545
|
+
.value=${this.formatDate(this.selectedDocument.updatedAt)}
|
|
546
|
+
size="small"
|
|
547
|
+
label="Copy updated date">
|
|
548
|
+
</wa-copy-button>
|
|
549
|
+
</wa-input>
|
|
550
|
+
</div>
|
|
551
|
+
|
|
552
|
+
${this.selectedDocument.metadata.tags && this.selectedDocument.metadata.tags.length > 0 ? html`
|
|
553
|
+
<div class="tags-section">
|
|
554
|
+
<wa-input
|
|
555
|
+
label="Tags"
|
|
556
|
+
.value=${this.selectedDocument.metadata.tags.join(", ")}
|
|
557
|
+
readonly
|
|
558
|
+
size="small">
|
|
559
|
+
<wa-copy-button
|
|
560
|
+
slot="end"
|
|
561
|
+
.value=${this.selectedDocument.metadata.tags.join(", ")}
|
|
562
|
+
size="small"
|
|
563
|
+
label="Copy tags">
|
|
564
|
+
</wa-copy-button>
|
|
565
|
+
</wa-input>
|
|
566
|
+
</div>
|
|
567
|
+
` : nothing}
|
|
568
|
+
|
|
569
|
+
<div class="detail-section">
|
|
570
|
+
<label>Content Preview${this.searchQuery ? html` <span class="search-hint">(showing matches for "${this.searchQuery}")</span>` : nothing}</label>
|
|
571
|
+
<wa-scroller class="content-preview" orientation="vertical">
|
|
572
|
+
<div class="content-preview-inner">
|
|
573
|
+
${this.getContentPreview(this.selectedDocument)}
|
|
574
|
+
</div>
|
|
575
|
+
</wa-scroller>
|
|
576
|
+
</div>
|
|
577
|
+
</div>
|
|
578
|
+
</div>
|
|
579
|
+
` : html`
|
|
580
|
+
<div class="document-details empty">
|
|
581
|
+
<wa-icon name="file-lines" style="font-size: 3rem; opacity: 0.3;"></wa-icon>
|
|
582
|
+
<p>Select a document to view details</p>
|
|
583
|
+
</div>
|
|
584
|
+
`}
|
|
585
|
+
</div>
|
|
586
|
+
</wa-split-panel>
|
|
587
|
+
</div>
|
|
588
|
+
`;
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
LyraRAGSystemManager.styles = css`
|
|
592
|
+
:host {
|
|
593
|
+
display: flex;
|
|
594
|
+
flex-direction: column;
|
|
595
|
+
height: 100%;
|
|
596
|
+
overflow: hidden;
|
|
597
|
+
min-height: 0;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.rag-system-manager {
|
|
601
|
+
display: flex;
|
|
602
|
+
flex-direction: column;
|
|
603
|
+
height: 100%;
|
|
604
|
+
min-height: 0;
|
|
605
|
+
overflow: hidden;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
wa-split-panel {
|
|
609
|
+
flex: 1;
|
|
610
|
+
min-height: 0;
|
|
611
|
+
overflow: hidden;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.document-list {
|
|
615
|
+
height: 100%;
|
|
616
|
+
overflow-y: auto;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.tree-item-info {
|
|
620
|
+
flex: 1;
|
|
621
|
+
min-width: 0;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.tree-item-path {
|
|
625
|
+
overflow: hidden;
|
|
626
|
+
text-overflow: ellipsis;
|
|
627
|
+
white-space: nowrap;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.tree-item-meta {
|
|
631
|
+
display: flex;
|
|
632
|
+
align-items: center;
|
|
633
|
+
gap: var(--wa-space-xs);
|
|
634
|
+
flex-wrap: wrap;
|
|
635
|
+
margin-top: var(--wa-space-xs);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
.tree-item-actions {
|
|
639
|
+
opacity: 0;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
wa-tree-item:hover .tree-item-actions {
|
|
643
|
+
opacity: 1;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.document-details {
|
|
647
|
+
height: 100%;
|
|
648
|
+
display: flex;
|
|
649
|
+
flex-direction: column;
|
|
650
|
+
min-height: 0;
|
|
651
|
+
overflow: hidden;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.details-content {
|
|
655
|
+
flex: 1;
|
|
656
|
+
display: flex;
|
|
657
|
+
flex-direction: column;
|
|
658
|
+
padding: var(--wa-space-s);
|
|
659
|
+
min-height: 0;
|
|
660
|
+
overflow: hidden;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
.metadata-grid {
|
|
664
|
+
display: grid;
|
|
665
|
+
grid-template-columns: 1fr 1fr;
|
|
666
|
+
gap: var(--wa-space-s);
|
|
667
|
+
flex-shrink: 0;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.tags-section {
|
|
671
|
+
margin-top: var(--wa-space-s);
|
|
672
|
+
flex-shrink: 0;
|
|
673
|
+
margin-bottom: var(--wa-space-s);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.detail-section {
|
|
677
|
+
flex: 1;
|
|
678
|
+
display: flex;
|
|
679
|
+
flex-direction: column;
|
|
680
|
+
min-height: 0;
|
|
681
|
+
position: relative;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.detail-section label {
|
|
685
|
+
flex-shrink: 0;
|
|
686
|
+
margin-bottom: var(--wa-space-xs);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.content-preview {
|
|
690
|
+
position: absolute;
|
|
691
|
+
top: 0;
|
|
692
|
+
right: 0;
|
|
693
|
+
left: 0;
|
|
694
|
+
bottom: 0;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.content-preview-inner {
|
|
698
|
+
width: 100%;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.snippets-table {
|
|
702
|
+
width: 100%;
|
|
703
|
+
border-collapse: collapse;
|
|
704
|
+
background-color: var(--wa-color-surface-raised);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.snippets-table thead {
|
|
708
|
+
background-color: var(--wa-color-neutral-fill-quiet);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.snippets-table th {
|
|
712
|
+
padding: var(--wa-space-xs) var(--wa-space-s);
|
|
713
|
+
text-align: left;
|
|
714
|
+
font-size: 0.75rem;
|
|
715
|
+
font-weight: 600;
|
|
716
|
+
color: var(--wa-color-text-quiet);
|
|
717
|
+
border-bottom: 1px solid var(--wa-color-surface-border);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.snippets-table td {
|
|
721
|
+
padding: var(--wa-space-s);
|
|
722
|
+
border-bottom: 1px solid var(--wa-color-surface-border);
|
|
723
|
+
vertical-align: top;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
.snippets-table tbody tr:last-child td {
|
|
727
|
+
border-bottom: none;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.snippets-table tbody tr:hover {
|
|
731
|
+
background-color: var(--wa-color-neutral-fill-quiet);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
.snippet-number-col {
|
|
735
|
+
width: 3rem;
|
|
736
|
+
text-align: center;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.snippet-content-col {
|
|
740
|
+
width: auto;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.snippet-number {
|
|
744
|
+
font-size: 0.75rem;
|
|
745
|
+
font-weight: 600;
|
|
746
|
+
color: var(--wa-color-text-quiet);
|
|
747
|
+
text-align: center;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
.snippet-content {
|
|
751
|
+
white-space: pre-wrap;
|
|
752
|
+
word-wrap: breaword;
|
|
753
|
+
overflow-wrap: breaword;
|
|
754
|
+
font-family: monospace;
|
|
755
|
+
font-size: 0.875rem;
|
|
756
|
+
line-height: 1.5;
|
|
757
|
+
color: var(--wa-color-text-normal);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.snippet-preview {
|
|
761
|
+
white-space: pre-wrap;
|
|
762
|
+
word-wrap: breaword;
|
|
763
|
+
overflow-wrap: breaword;
|
|
764
|
+
font-family: monospace;
|
|
765
|
+
font-size: 0.875rem;
|
|
766
|
+
line-height: 1.5;
|
|
767
|
+
color: var(--wa-color-text-normal);
|
|
768
|
+
padding: var(--wa-space-s);
|
|
769
|
+
background-color: var(--wa-color-surface-raised);
|
|
770
|
+
border-radius: var(--wa-border-radius-medium);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.snippet-content mark.search-match {
|
|
774
|
+
background: var(--wa-color-warning-fill-loud);
|
|
775
|
+
color: var(--wa-color-warning-text-loud);
|
|
776
|
+
padding: 0 2px;
|
|
777
|
+
border-radius: 2px;
|
|
778
|
+
font-weight: 600;
|
|
779
|
+
}
|
|
780
|
+
`;
|
|
781
|
+
__decorateClass([
|
|
782
|
+
property({ attribute: false })
|
|
783
|
+
], LyraRAGSystemManager.prototype, "input", 2);
|
|
784
|
+
__decorateClass([
|
|
785
|
+
state()
|
|
786
|
+
], LyraRAGSystemManager.prototype, "documents", 2);
|
|
787
|
+
__decorateClass([
|
|
788
|
+
state()
|
|
789
|
+
], LyraRAGSystemManager.prototype, "stats", 2);
|
|
790
|
+
__decorateClass([
|
|
791
|
+
state()
|
|
792
|
+
], LyraRAGSystemManager.prototype, "loading", 2);
|
|
793
|
+
__decorateClass([
|
|
794
|
+
state()
|
|
795
|
+
], LyraRAGSystemManager.prototype, "selectedDocument", 2);
|
|
796
|
+
__decorateClass([
|
|
797
|
+
state()
|
|
798
|
+
], LyraRAGSystemManager.prototype, "searchQuery", 2);
|
|
799
|
+
__decorateClass([
|
|
800
|
+
state()
|
|
801
|
+
], LyraRAGSystemManager.prototype, "filterWorkspace", 2);
|
|
802
|
+
__decorateClass([
|
|
803
|
+
state()
|
|
804
|
+
], LyraRAGSystemManager.prototype, "filterByActiveWorkspace", 2);
|
|
805
|
+
__decorateClass([
|
|
806
|
+
state()
|
|
807
|
+
], LyraRAGSystemManager.prototype, "filteredDocuments", 2);
|
|
808
|
+
__decorateClass([
|
|
809
|
+
state()
|
|
810
|
+
], LyraRAGSystemManager.prototype, "searchResults", 2);
|
|
811
|
+
__decorateClass([
|
|
812
|
+
state()
|
|
813
|
+
], LyraRAGSystemManager.prototype, "reindexing", 2);
|
|
814
|
+
LyraRAGSystemManager = __decorateClass([
|
|
815
|
+
customElement("lyra-rag-system-manager")
|
|
816
|
+
], LyraRAGSystemManager);
|
|
817
|
+
const logger = createLogger("RAGSystemExtension");
|
|
818
|
+
function ragSystemExtension(context) {
|
|
819
|
+
documentIndexService.initialize().catch((err) => {
|
|
820
|
+
logger.error(`Failed to initialize document index service: ${err}`);
|
|
821
|
+
});
|
|
822
|
+
registerAll({
|
|
823
|
+
command: {
|
|
824
|
+
id: "rag-system.index-file",
|
|
825
|
+
name: "Index Document",
|
|
826
|
+
description: "Index the currently selected file for search and retrieval",
|
|
827
|
+
parameters: [
|
|
828
|
+
{
|
|
829
|
+
name: "includeContent",
|
|
830
|
+
description: "Whether to include full content in index (default: true)",
|
|
831
|
+
required: false
|
|
832
|
+
}
|
|
833
|
+
]
|
|
834
|
+
},
|
|
835
|
+
handler: {
|
|
836
|
+
canExecute: (context2) => {
|
|
837
|
+
const selection = activeSelectionSignal.get();
|
|
838
|
+
return selection instanceof File;
|
|
839
|
+
},
|
|
840
|
+
execute: async (context2) => {
|
|
841
|
+
const selection = activeSelectionSignal.get();
|
|
842
|
+
if (!(selection instanceof File)) {
|
|
843
|
+
toastError("Please select a file to index");
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
const includeContent = context2.params?.includeContent !== false;
|
|
847
|
+
await taskService.runAsync("Indexing document", async (progress) => {
|
|
848
|
+
progress.message = `Indexing ${selection.getName()}...`;
|
|
849
|
+
try {
|
|
850
|
+
const document = await documentIndexService.indexDocument(selection, {
|
|
851
|
+
includeContent
|
|
852
|
+
});
|
|
853
|
+
progress.progress = 100;
|
|
854
|
+
toastInfo(`Document indexed: ${document.fileName}`);
|
|
855
|
+
} catch (error) {
|
|
856
|
+
toastError(`Failed to index document: ${error}`);
|
|
857
|
+
throw error;
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
registerAll({
|
|
864
|
+
command: {
|
|
865
|
+
id: "rag-system.index-workspace",
|
|
866
|
+
name: "Index Workspace",
|
|
867
|
+
description: "Index all indexable files in the current workspace",
|
|
868
|
+
parameters: [
|
|
869
|
+
{
|
|
870
|
+
name: "includeContent",
|
|
871
|
+
description: "Whether to include full content in index (default: true)",
|
|
872
|
+
required: false
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
name: "maxFileSize",
|
|
876
|
+
description: "Maximum file size in bytes to index (default: 5MB)",
|
|
877
|
+
required: false
|
|
878
|
+
}
|
|
879
|
+
]
|
|
880
|
+
},
|
|
881
|
+
handler: {
|
|
882
|
+
canExecute: (context2) => {
|
|
883
|
+
return true;
|
|
884
|
+
},
|
|
885
|
+
execute: async (context2) => {
|
|
886
|
+
const workspace = await workspaceService.getWorkspace();
|
|
887
|
+
if (!workspace) {
|
|
888
|
+
toastError("No workspace selected");
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
const includeContent = context2.params?.includeContent !== false;
|
|
892
|
+
const maxFileSize = context2.params?.maxFileSize ? parseInt(context2.params.maxFileSize) : void 0;
|
|
893
|
+
await taskService.runAsync("Indexing workspace", async (progress) => {
|
|
894
|
+
progress.message = "Collecting files...";
|
|
895
|
+
progress.progress = 0;
|
|
896
|
+
try {
|
|
897
|
+
const result = await documentIndexService.indexWorkspace(workspace, {
|
|
898
|
+
includeContent,
|
|
899
|
+
maxFileSize
|
|
900
|
+
});
|
|
901
|
+
progress.progress = 100;
|
|
902
|
+
if (result.failed > 0) {
|
|
903
|
+
toastError(
|
|
904
|
+
`Indexing complete: ${result.indexed} indexed, ${result.failed} failed. Check console for details.`
|
|
905
|
+
);
|
|
906
|
+
} else {
|
|
907
|
+
toastInfo(`Workspace indexed: ${result.indexed} documents`);
|
|
908
|
+
}
|
|
909
|
+
} catch (error) {
|
|
910
|
+
toastError(`Failed to index workspace: ${error}`);
|
|
911
|
+
throw error;
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
registerAll({
|
|
918
|
+
command: {
|
|
919
|
+
id: "rag-system.list-documents",
|
|
920
|
+
name: "List Indexed Documents",
|
|
921
|
+
description: "List all indexed documents in the current workspace",
|
|
922
|
+
parameters: []
|
|
923
|
+
},
|
|
924
|
+
handler: {
|
|
925
|
+
canExecute: (context2) => {
|
|
926
|
+
return true;
|
|
927
|
+
},
|
|
928
|
+
execute: async (context2) => {
|
|
929
|
+
const workspace = await workspaceService.getWorkspace();
|
|
930
|
+
const workspacePath = workspace?.getName();
|
|
931
|
+
await taskService.runAsync("Loading indexed documents", async (progress) => {
|
|
932
|
+
try {
|
|
933
|
+
const documents = await documentIndexService.listDocuments(workspacePath);
|
|
934
|
+
progress.progress = 100;
|
|
935
|
+
if (documents.length === 0) {
|
|
936
|
+
toastInfo("No documents indexed in this workspace");
|
|
937
|
+
} else {
|
|
938
|
+
logger.info(`Found ${documents.length} indexed documents`);
|
|
939
|
+
toastInfo(`Found ${documents.length} indexed documents (check console for details)`);
|
|
940
|
+
}
|
|
941
|
+
} catch (error) {
|
|
942
|
+
toastError(`Failed to list documents: ${error}`);
|
|
943
|
+
throw error;
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
registerAll({
|
|
950
|
+
command: {
|
|
951
|
+
id: "rag-system.delete-document",
|
|
952
|
+
name: "Delete Document from Index",
|
|
953
|
+
description: "Remove the selected file from the document index",
|
|
954
|
+
parameters: []
|
|
955
|
+
},
|
|
956
|
+
handler: {
|
|
957
|
+
canExecute: (context2) => {
|
|
958
|
+
const selection = activeSelectionSignal.get();
|
|
959
|
+
return selection instanceof File;
|
|
960
|
+
},
|
|
961
|
+
execute: async (context2) => {
|
|
962
|
+
const selection = activeSelectionSignal.get();
|
|
963
|
+
if (!(selection instanceof File)) {
|
|
964
|
+
toastError("Please select a file to remove from index");
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
const workspace = selection.getWorkspace();
|
|
968
|
+
const workspacePath = workspace.getName();
|
|
969
|
+
const filePath = selection.getWorkspacePath();
|
|
970
|
+
await taskService.runAsync("Deleting document from index", async (progress) => {
|
|
971
|
+
try {
|
|
972
|
+
const deleted = await documentIndexService.deleteDocumentByPath(
|
|
973
|
+
workspacePath,
|
|
974
|
+
filePath
|
|
975
|
+
);
|
|
976
|
+
progress.progress = 100;
|
|
977
|
+
if (deleted) {
|
|
978
|
+
toastInfo(`Document removed from index: ${selection.getName()}`);
|
|
979
|
+
} else {
|
|
980
|
+
toastInfo(`Document not found in index: ${selection.getName()}`);
|
|
981
|
+
}
|
|
982
|
+
} catch (error) {
|
|
983
|
+
toastError(`Failed to delete document from index: ${error}`);
|
|
984
|
+
throw error;
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
registerAll({
|
|
991
|
+
command: {
|
|
992
|
+
id: "rag-system.clear-workspace",
|
|
993
|
+
name: "Clear Workspace Index",
|
|
994
|
+
description: "Remove all indexed documents from the current workspace",
|
|
995
|
+
parameters: []
|
|
996
|
+
},
|
|
997
|
+
handler: {
|
|
998
|
+
canExecute: (context2) => {
|
|
999
|
+
return true;
|
|
1000
|
+
},
|
|
1001
|
+
execute: async (context2) => {
|
|
1002
|
+
const workspace = await workspaceService.getWorkspace();
|
|
1003
|
+
if (!workspace) {
|
|
1004
|
+
toastError("No workspace selected");
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
const workspacePath = workspace.getName();
|
|
1008
|
+
await taskService.runAsync("Clearing workspace index", async (progress) => {
|
|
1009
|
+
try {
|
|
1010
|
+
const deleted = await documentIndexService.deleteWorkspace(workspacePath);
|
|
1011
|
+
progress.progress = 100;
|
|
1012
|
+
toastInfo(`Removed ${deleted} documents from index`);
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
toastError(`Failed to clear workspace index: ${error}`);
|
|
1015
|
+
throw error;
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
});
|
|
1021
|
+
registerAll({
|
|
1022
|
+
command: {
|
|
1023
|
+
id: "rag-system.get-stats",
|
|
1024
|
+
name: "Document Index Statistics",
|
|
1025
|
+
description: "Get statistics about the document index",
|
|
1026
|
+
parameters: []
|
|
1027
|
+
},
|
|
1028
|
+
handler: {
|
|
1029
|
+
canExecute: (context2) => {
|
|
1030
|
+
return true;
|
|
1031
|
+
},
|
|
1032
|
+
execute: async (context2) => {
|
|
1033
|
+
await taskService.runAsync("Loading statistics", async (progress) => {
|
|
1034
|
+
try {
|
|
1035
|
+
const stats = await documentIndexService.getStats();
|
|
1036
|
+
progress.progress = 100;
|
|
1037
|
+
logger.info(`Document index statistics: ${JSON.stringify(stats)}`);
|
|
1038
|
+
toastInfo(
|
|
1039
|
+
`Index statistics: ${stats.totalDocuments} total documents. Check console for details.`
|
|
1040
|
+
);
|
|
1041
|
+
} catch (error) {
|
|
1042
|
+
toastError(`Failed to get statistics: ${error}`);
|
|
1043
|
+
throw error;
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
registerAll({
|
|
1050
|
+
command: {
|
|
1051
|
+
id: "rag-system.reindex-file",
|
|
1052
|
+
name: "Reindex Document",
|
|
1053
|
+
description: "Reindex the selected file (useful after file changes)",
|
|
1054
|
+
parameters: []
|
|
1055
|
+
},
|
|
1056
|
+
handler: {
|
|
1057
|
+
canExecute: (context2) => {
|
|
1058
|
+
const selection = activeSelectionSignal.get();
|
|
1059
|
+
return selection instanceof File;
|
|
1060
|
+
},
|
|
1061
|
+
execute: async (context2) => {
|
|
1062
|
+
const selection = activeSelectionSignal.get();
|
|
1063
|
+
if (!(selection instanceof File)) {
|
|
1064
|
+
toastError("Please select a file to reindex");
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
await taskService.runAsync("Reindexing document", async (progress) => {
|
|
1068
|
+
progress.message = `Reindexing ${selection.getName()}...`;
|
|
1069
|
+
try {
|
|
1070
|
+
const document = await documentIndexService.reindexDocument(selection);
|
|
1071
|
+
progress.progress = 100;
|
|
1072
|
+
toastInfo(`Document reindexed: ${document.fileName}`);
|
|
1073
|
+
} catch (error) {
|
|
1074
|
+
toastError(`Failed to reindex document: ${error}`);
|
|
1075
|
+
throw error;
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
logger.info("RAG system extension loaded");
|
|
1082
|
+
editorRegistry.registerEditorInputHandler({
|
|
1083
|
+
editorId: "system.rag-system-manager",
|
|
1084
|
+
label: "RAG System Manager",
|
|
1085
|
+
ranking: 1e3,
|
|
1086
|
+
canHandle: (input) => {
|
|
1087
|
+
return input.key === ".system.rag-system";
|
|
1088
|
+
},
|
|
1089
|
+
handle: async (input) => {
|
|
1090
|
+
input.widgetFactory = () => html`
|
|
1091
|
+
<lyra-rag-system-manager .input=${input}></lyra-rag-system-manager>
|
|
1092
|
+
`;
|
|
1093
|
+
return input;
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
registerAll({
|
|
1097
|
+
command: {
|
|
1098
|
+
id: "open-rag-system-manager",
|
|
1099
|
+
name: "Open RAG System Manager",
|
|
1100
|
+
description: "Opens the RAG system manager to view and manage indexed documents",
|
|
1101
|
+
parameters: []
|
|
1102
|
+
},
|
|
1103
|
+
handler: {
|
|
1104
|
+
execute: (_context) => {
|
|
1105
|
+
const editorInput = {
|
|
1106
|
+
title: "RAG System Manager",
|
|
1107
|
+
data: {},
|
|
1108
|
+
key: ".system.rag-system",
|
|
1109
|
+
icon: "database",
|
|
1110
|
+
state: {}
|
|
1111
|
+
};
|
|
1112
|
+
editorRegistry.loadEditor(editorInput).catch((err) => {
|
|
1113
|
+
logger.error(`Failed to open document index manager: ${err}`);
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
},
|
|
1117
|
+
contribution: {
|
|
1118
|
+
target: TOOLBAR_MAIN_RIGHT,
|
|
1119
|
+
icon: "database",
|
|
1120
|
+
label: "RAG System"
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
contributionRegistry.registerContribution("contextmenu:filebrowser", {
|
|
1124
|
+
command: "rag-system.index-file",
|
|
1125
|
+
icon: "database",
|
|
1126
|
+
label: "Index Document",
|
|
1127
|
+
disabled: () => {
|
|
1128
|
+
const selection = activeSelectionSignal.get();
|
|
1129
|
+
return !(selection instanceof File);
|
|
1130
|
+
}
|
|
1131
|
+
});
|
|
1132
|
+
import("./rag-integration-DO7-zvk2.js").then((rag) => {
|
|
1133
|
+
rag.integrateRAGWithAI();
|
|
1134
|
+
logger.info("RAG integration enabled");
|
|
1135
|
+
}).catch((err) => {
|
|
1136
|
+
logger.warn(`Failed to load RAG integration: ${err}`);
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
export {
|
|
1140
|
+
ragSystemExtension as default
|
|
1141
|
+
};
|
|
1142
|
+
//# sourceMappingURL=rag-system-extension-DfD6H8Vr.js.map
|