@burtson-labs/bandit-engine 2.0.167 → 2.0.168

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.
Files changed (34) hide show
  1. package/dist/{chat-6N5B7A7F.mjs → chat-7LOFYEWE.mjs} +5 -5
  2. package/dist/chat-provider.js +154 -38
  3. package/dist/chat-provider.js.map +1 -1
  4. package/dist/chat-provider.mjs +2 -2
  5. package/dist/{chunk-PK3LFBGC.mjs → chunk-4SXXEGEK.mjs} +142 -27
  6. package/dist/chunk-4SXXEGEK.mjs.map +1 -0
  7. package/dist/{chunk-KDIL5WUL.mjs → chunk-62IYSU3I.mjs} +4 -3
  8. package/dist/chunk-62IYSU3I.mjs.map +1 -0
  9. package/dist/{chunk-5BZWJQ5O.mjs → chunk-JD6C64CT.mjs} +2 -2
  10. package/dist/{chunk-46OGYEME.mjs → chunk-KAXUI5H7.mjs} +154 -40
  11. package/dist/chunk-KAXUI5H7.mjs.map +1 -0
  12. package/dist/{chunk-US4TG745.mjs → chunk-QI67R5F6.mjs} +2 -2
  13. package/dist/{chunk-N4BQ6HKL.mjs → chunk-R3NOM2DG.mjs} +3 -3
  14. package/dist/{chunk-SHYNXDRO.mjs → chunk-YGOLNWXJ.mjs} +4 -4
  15. package/dist/index.d.mts +54 -2
  16. package/dist/index.d.ts +54 -2
  17. package/dist/index.js +306 -68
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +7 -7
  20. package/dist/management/management.js +305 -68
  21. package/dist/management/management.js.map +1 -1
  22. package/dist/management/management.mjs +5 -5
  23. package/dist/modals/chat-modal/chat-modal.js +159 -42
  24. package/dist/modals/chat-modal/chat-modal.js.map +1 -1
  25. package/dist/modals/chat-modal/chat-modal.mjs +3 -3
  26. package/package.json +1 -1
  27. package/dist/chunk-46OGYEME.mjs.map +0 -1
  28. package/dist/chunk-KDIL5WUL.mjs.map +0 -1
  29. package/dist/chunk-PK3LFBGC.mjs.map +0 -1
  30. /package/dist/{chat-6N5B7A7F.mjs.map → chat-7LOFYEWE.mjs.map} +0 -0
  31. /package/dist/{chunk-5BZWJQ5O.mjs.map → chunk-JD6C64CT.mjs.map} +0 -0
  32. /package/dist/{chunk-US4TG745.mjs.map → chunk-QI67R5F6.mjs.map} +0 -0
  33. /package/dist/{chunk-N4BQ6HKL.mjs.map → chunk-R3NOM2DG.mjs.map} +0 -0
  34. /package/dist/{chunk-SHYNXDRO.mjs.map → chunk-YGOLNWXJ.mjs.map} +0 -0
package/dist/index.js CHANGED
@@ -7026,7 +7026,7 @@ var init_util = __esm({
7026
7026
  "src/util.ts"() {
7027
7027
  "use strict";
7028
7028
  init_debugLogger();
7029
- toTitleCase = (str) => str.toLowerCase().split(" ").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
7029
+ toTitleCase = (str2) => str2.toLowerCase().split(" ").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
7030
7030
  generateSeed = () => Math.floor(Math.random() * 1e4);
7031
7031
  fetchAndConvertToBase64 = async (src) => {
7032
7032
  const response = await fetch(src);
@@ -7835,6 +7835,99 @@ var init_embeddingService = __esm({
7835
7835
  }
7836
7836
  });
7837
7837
 
7838
+ // src/services/vectorDatabase/knowledgeFiles.ts
7839
+ var KNOWLEDGE_PAGE_LIMIT_MAX, MEDIA_MIME_PREFIXES, MEDIA_EXTENSIONS, TEMP_NAME, str, recordName, recordMime, isLikelyKnowledgeFile, toRecords, num, parseKnowledgeFileList;
7840
+ var init_knowledgeFiles = __esm({
7841
+ "src/services/vectorDatabase/knowledgeFiles.ts"() {
7842
+ "use strict";
7843
+ KNOWLEDGE_PAGE_LIMIT_MAX = 200;
7844
+ MEDIA_MIME_PREFIXES = ["image/", "video/", "audio/"];
7845
+ MEDIA_EXTENSIONS = /* @__PURE__ */ new Set([
7846
+ "png",
7847
+ "jpg",
7848
+ "jpeg",
7849
+ "gif",
7850
+ "webp",
7851
+ "bmp",
7852
+ "tif",
7853
+ "tiff",
7854
+ "heic",
7855
+ "heif",
7856
+ "svg",
7857
+ "ico",
7858
+ "avif",
7859
+ "mp4",
7860
+ "mov",
7861
+ "m4v",
7862
+ "webm",
7863
+ "avi",
7864
+ "mkv",
7865
+ "mp3",
7866
+ "wav",
7867
+ "m4a",
7868
+ "aac",
7869
+ "ogg",
7870
+ "flac"
7871
+ ]);
7872
+ TEMP_NAME = /^(~WRD\d*|~\$|~\w+\.tmp$)|\.tmp$/i;
7873
+ str = (value) => typeof value === "string" ? value : "";
7874
+ recordName = (record) => str(record.filename) || str(record.fileName) || str(record.name);
7875
+ recordMime = (record) => (str(record.mimeType) || str(record.contentType) || str(record.type)).toLowerCase();
7876
+ isLikelyKnowledgeFile = (record) => {
7877
+ const name = recordName(record);
7878
+ if (TEMP_NAME.test(name)) return false;
7879
+ const ext = name.includes(".") ? name.split(".").pop().toLowerCase() : "";
7880
+ if (MEDIA_EXTENSIONS.has(ext)) return false;
7881
+ const mime = recordMime(record);
7882
+ if (MEDIA_MIME_PREFIXES.some((prefix) => mime.startsWith(prefix))) return false;
7883
+ return true;
7884
+ };
7885
+ toRecords = (value) => Array.isArray(value) ? value.filter((item) => !!item && typeof item === "object" && !Array.isArray(item)) : [];
7886
+ num = (value, fallback) => typeof value === "number" && Number.isFinite(value) ? value : fallback;
7887
+ parseKnowledgeFileList = (body, request) => {
7888
+ if (body && typeof body === "object" && !Array.isArray(body) && "total" in body) {
7889
+ const envelope = body;
7890
+ const files2 = toRecords(envelope.files);
7891
+ const total = num(envelope.total, files2.length);
7892
+ const skip = num(envelope.skip, request.skip);
7893
+ const scope = envelope.scope === "all" ? "all" : "knowledge";
7894
+ return {
7895
+ files: files2,
7896
+ total,
7897
+ hasMore: typeof envelope.hasMore === "boolean" ? envelope.hasMore : skip + files2.length < total,
7898
+ scope,
7899
+ serverScoped: true,
7900
+ knowledgeFilterUnavailable: envelope.knowledgeFilterUnavailable === true,
7901
+ hiddenCount: 0
7902
+ };
7903
+ }
7904
+ const raw = body && typeof body === "object" && !Array.isArray(body) ? toRecords(body.files) : toRecords(body);
7905
+ const hasMore = raw.length >= request.limit;
7906
+ if (request.scope === "all") {
7907
+ return {
7908
+ files: raw,
7909
+ total: request.skip + raw.length,
7910
+ hasMore,
7911
+ scope: "all",
7912
+ serverScoped: false,
7913
+ knowledgeFilterUnavailable: false,
7914
+ hiddenCount: 0
7915
+ };
7916
+ }
7917
+ const files = raw.filter(isLikelyKnowledgeFile);
7918
+ return {
7919
+ files,
7920
+ total: files.length,
7921
+ hasMore,
7922
+ scope: "knowledge",
7923
+ serverScoped: false,
7924
+ knowledgeFilterUnavailable: false,
7925
+ hiddenCount: raw.length - files.length
7926
+ };
7927
+ };
7928
+ }
7929
+ });
7930
+
7838
7931
  // src/utils/memoryUtils.ts
7839
7932
  var memoryUtils_exports = {};
7840
7933
  __export(memoryUtils_exports, {
@@ -8069,6 +8162,7 @@ var init_vectorDatabaseService = __esm({
8069
8162
  "src/services/vectorDatabase/vectorDatabaseService.ts"() {
8070
8163
  "use strict";
8071
8164
  init_debugLogger();
8165
+ init_knowledgeFiles();
8072
8166
  VectorDatabaseService = class {
8073
8167
  baseUrl;
8074
8168
  fileStorageApiUrl;
@@ -8828,36 +8922,44 @@ var init_vectorDatabaseService = __esm({
8828
8922
  }
8829
8923
  }
8830
8924
  /**
8831
- * Get user's files - tries both Gateway API and file storage API
8925
+ * One page of the Knowledge file list from the gateway (see ./knowledgeFiles).
8926
+ *
8927
+ * No fallback to the file storage API here: its listing is the whole Drive (every product's
8928
+ * files), which is exactly what Knowledge must not show. A failure surfaces to the caller.
8832
8929
  */
8833
- async getUserFiles(skip = 0, limit = 50) {
8930
+ async listKnowledgeFiles(skip = 0, limit = 50, scope = "knowledge") {
8834
8931
  if (!this.isAvailable()) {
8835
- return [];
8932
+ return parseKnowledgeFileList([], { skip, limit, scope });
8933
+ }
8934
+ const safeSkip = Math.max(0, Math.floor(skip));
8935
+ const safeLimit = Math.min(KNOWLEDGE_PAGE_LIMIT_MAX, Math.max(1, Math.floor(limit)));
8936
+ const query = new URLSearchParams({
8937
+ skip: String(safeSkip),
8938
+ limit: String(safeLimit),
8939
+ scope
8940
+ });
8941
+ debugLogger.debug("Fetching knowledge files from Gateway API", { skip: safeSkip, limit: safeLimit, scope });
8942
+ const response = await fetch(`${this.baseUrl}/embedding/files?${query.toString()}`, {
8943
+ method: "GET",
8944
+ headers: this.getHeaders()
8945
+ });
8946
+ if (!response.ok) {
8947
+ throw new Error(`Couldn't list documents (gateway answered ${response.status})`);
8836
8948
  }
8949
+ const body = await response.json();
8950
+ return parseKnowledgeFileList(body, { skip: safeSkip, limit: safeLimit, scope });
8951
+ }
8952
+ /**
8953
+ * Get the user's Knowledge files (first page, knowledge scope). Kept for existing callers;
8954
+ * prefer listKnowledgeFiles for totals and paging.
8955
+ */
8956
+ async getUserFiles(skip = 0, limit = 50) {
8837
8957
  try {
8838
- debugLogger.debug("Fetching user files from Gateway API", { skip, limit });
8839
- const response = await fetch(`${this.baseUrl}/embedding/files?skip=${skip}&limit=${limit}`, {
8840
- method: "GET",
8841
- headers: this.getHeaders()
8842
- });
8843
- if (!response.ok) {
8844
- debugLogger.warn("Gateway API files endpoint failed, falling back to file storage API", {
8845
- status: response.status
8846
- });
8847
- return await this.getUserFilesFromFileStorage(skip, limit);
8848
- }
8849
- const result = await response.json();
8850
- debugLogger.debug("Gateway API files response", result);
8851
- if (Array.isArray(result)) {
8852
- return this.toRecordArray(result);
8853
- }
8854
- if (result && Array.isArray(result.files)) {
8855
- return this.toRecordArray(result.files);
8856
- }
8857
- return [];
8958
+ const page = await this.listKnowledgeFiles(skip, limit, "knowledge");
8959
+ return page.files;
8858
8960
  } catch (error) {
8859
- debugLogger.error("Gateway API failed while fetching user files, trying file storage API", { error });
8860
- return await this.getUserFilesFromFileStorage(skip, limit);
8961
+ debugLogger.error("Failed to fetch knowledge files from Gateway API", { error });
8962
+ return [];
8861
8963
  }
8862
8964
  }
8863
8965
  /**
@@ -10064,7 +10166,7 @@ var init_useFeatures = __esm({
10064
10166
  });
10065
10167
 
10066
10168
  // src/hooks/useVectorStore.tsx
10067
- var import_react3, toIsoString, memoryEntryToVectorMemory, knowledgeDocToVectorDocument, rawFileRecordToVectorDocument, useVectorStore;
10169
+ var import_react3, toIsoString, memoryEntryToVectorMemory, knowledgeDocToVectorDocument, optionalString, rawFileRecordToVectorDocument, useVectorStore;
10068
10170
  var init_useVectorStore = __esm({
10069
10171
  "src/hooks/useVectorStore.tsx"() {
10070
10172
  "use strict";
@@ -10108,6 +10210,7 @@ var init_useVectorStore = __esm({
10108
10210
  isTeamContent: doc.isTeamContent ?? false,
10109
10211
  contentSource: doc.contentSource ?? (doc.isTeamContent ? "team" : "user")
10110
10212
  });
10213
+ optionalString = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
10111
10214
  rawFileRecordToVectorDocument = (record) => {
10112
10215
  if (!record || typeof record !== "object") {
10113
10216
  return null;
@@ -10122,10 +10225,12 @@ var init_useVectorStore = __esm({
10122
10225
  const mimeType = typeof record.mimeType === "string" ? record.mimeType : "application/octet-stream";
10123
10226
  const uploadedBy = typeof record.uploadedBy === "string" ? record.uploadedBy : "unknown";
10124
10227
  const uploadedAt = typeof record.uploadedAt === "string" ? record.uploadedAt : (/* @__PURE__ */ new Date()).toISOString();
10125
- const isUserContent = typeof record.isUserContent === "boolean" ? record.isUserContent : true;
10126
- const isTeamContent = typeof record.isTeamContent === "boolean" ? record.isTeamContent : false;
10127
- const contentSource = record.contentSource === "team" ? "team" : "user";
10228
+ const teamSid = optionalString(record.teamSid);
10229
+ const isTeamContent = typeof record.isTeamContent === "boolean" ? record.isTeamContent : !!teamSid;
10230
+ const isUserContent = typeof record.isUserContent === "boolean" ? record.isUserContent : !isTeamContent;
10231
+ const contentSource = record.contentSource === "team" || record.contentSource === void 0 && isTeamContent ? "team" : "user";
10128
10232
  const score = typeof record.score === "number" ? record.score : void 0;
10233
+ const size = typeof record.size === "number" && Number.isFinite(record.size) && record.size >= 0 ? record.size : void 0;
10129
10234
  return {
10130
10235
  id,
10131
10236
  filename,
@@ -10136,7 +10241,12 @@ var init_useVectorStore = __esm({
10136
10241
  isUserContent,
10137
10242
  isTeamContent,
10138
10243
  contentSource,
10139
- score
10244
+ score,
10245
+ size,
10246
+ bucket: optionalString(record.bucket),
10247
+ teamSid,
10248
+ userEmail: optionalString(record.userEmail),
10249
+ preview
10140
10250
  };
10141
10251
  };
10142
10252
  useVectorStore = () => {
@@ -10688,22 +10798,32 @@ var init_useVectorStore = __esm({
10688
10798
  (0, import_react3.useEffect)(() => {
10689
10799
  initializeVectorService();
10690
10800
  }, [initializeVectorService]);
10691
- const getUserDocuments = (0, import_react3.useCallback)(async (skip = 0, limit = 50) => {
10801
+ const getKnowledgeDocumentsPage = (0, import_react3.useCallback)(async (skip = 0, limit = 50, scope = "knowledge") => {
10692
10802
  if (!status.isEnabled || status.migrationRequired) {
10693
- return [];
10803
+ return {
10804
+ documents: [],
10805
+ total: 0,
10806
+ hasMore: false,
10807
+ scope,
10808
+ serverScoped: false,
10809
+ knowledgeFilterUnavailable: false,
10810
+ hiddenCount: 0
10811
+ };
10694
10812
  }
10813
+ const { files, ...meta } = await vectorDatabaseService.listKnowledgeFiles(skip, limit, scope);
10814
+ const documents = files.map(rawFileRecordToVectorDocument).filter((doc) => doc !== null);
10815
+ debugLogger.info("Retrieved knowledge documents", { count: documents.length, total: meta.total, scope: meta.scope });
10816
+ return { documents, ...meta };
10817
+ }, [status.isEnabled, status.migrationRequired]);
10818
+ const getUserDocuments = (0, import_react3.useCallback)(async (skip = 0, limit = 50) => {
10695
10819
  try {
10696
- const records = await vectorDatabaseService.getUserFiles(skip, limit);
10697
- const documents = records.map(rawFileRecordToVectorDocument).filter((doc) => doc !== null);
10698
- debugLogger.info("Retrieved user documents from vector database", {
10699
- count: documents.length
10700
- });
10701
- return documents;
10820
+ const page = await getKnowledgeDocumentsPage(skip, limit, "knowledge");
10821
+ return page.documents;
10702
10822
  } catch (error) {
10703
10823
  debugLogger.error("Failed to get user documents", { error });
10704
10824
  return [];
10705
10825
  }
10706
- }, [status.isEnabled, status.migrationRequired]);
10826
+ }, [getKnowledgeDocumentsPage]);
10707
10827
  const deleteDocument = (0, import_react3.useCallback)(async (fileId) => {
10708
10828
  if (!status.isEnabled || status.migrationRequired) {
10709
10829
  return {
@@ -10800,6 +10920,7 @@ var init_useVectorStore = __esm({
10800
10920
  uploadDocument,
10801
10921
  searchDocuments,
10802
10922
  getUserDocuments,
10923
+ getKnowledgeDocumentsPage,
10803
10924
  deleteDocument,
10804
10925
  downloadVectorFile,
10805
10926
  getFilePreview,
@@ -12181,7 +12302,7 @@ var init_StreamingMarkdown = __esm({
12181
12302
  **Sources**
12182
12303
  ${listMarkdown}`;
12183
12304
  }, [sanitizedContent, effectiveSources, isStreaming]);
12184
- const escapeHtml = (str) => str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
12305
+ const escapeHtml = (str2) => str2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
12185
12306
  const isPlainAppend = (s) => {
12186
12307
  return !/[`*_\[\]<>|#~]/.test(s);
12187
12308
  };
@@ -12946,7 +13067,8 @@ var init_DocumentCard = __esm({
12946
13067
  const metaLine = [
12947
13068
  sourceLabel,
12948
13069
  fileInfo.language ?? fileInfo.category,
12949
- formatFileSize((doc.content?.length || 0) * 2)
13070
+ // Real file size when the listing reports one; otherwise estimate from the text content.
13071
+ formatFileSize(typeof doc.size === "number" && doc.size > 0 ? doc.size : (doc.content?.length || 0) * 2)
12950
13072
  ].join(" \xB7 ");
12951
13073
  if (documentState === "unavailable" && !allowErrorStates) {
12952
13074
  return null;
@@ -15961,9 +16083,9 @@ var init_source_chips = __esm({
15961
16083
  };
15962
16084
  linkifyCitations = (content, sources) => {
15963
16085
  if (!content || sources.length === 0) return content;
15964
- const link = (text) => text.replace(/\[(\d{1,2})\]/g, (full, num) => {
15965
- const src = sources[parseInt(num, 10) - 1];
15966
- return src ? `[\\[${num}\\]](${src.url})` : full;
16086
+ const link = (text) => text.replace(/\[(\d{1,2})\]/g, (full, num2) => {
16087
+ const src = sources[parseInt(num2, 10) - 1];
16088
+ return src ? `[\\[${num2}\\]](${src.url})` : full;
15967
16089
  });
15968
16090
  return content.split(/(```[\s\S]*?```)/g).map((seg, i) => i % 2 === 0 ? link(seg) : seg).join("");
15969
16091
  };
@@ -34057,8 +34179,8 @@ var ChatModal = ({
34057
34179
  }
34058
34180
  }
34059
34181
  };
34060
- const toTitleCase2 = (str) => {
34061
- return str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
34182
+ const toTitleCase2 = (str2) => {
34183
+ return str2.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
34062
34184
  };
34063
34185
  (0, import_react66.useEffect)(() => {
34064
34186
  if (!SYSTEM_PROMPT) {
@@ -38418,6 +38540,21 @@ var getContentSourceInfo = (doc, isVectorMode) => {
38418
38540
  }
38419
38541
  return { label: "Local", icon: import_lock.Lock };
38420
38542
  };
38543
+ var KNOWLEDGE_PAGE_SIZE = 50;
38544
+ var EMPTY_LIST_META = {
38545
+ total: null,
38546
+ hasMore: false,
38547
+ nextSkip: 0,
38548
+ scope: "knowledge",
38549
+ serverScoped: false,
38550
+ knowledgeFilterUnavailable: false,
38551
+ hiddenCount: 0
38552
+ };
38553
+ var docTime = (doc) => {
38554
+ const time = doc.addedDate instanceof Date ? doc.addedDate.getTime() : NaN;
38555
+ return Number.isFinite(time) ? time : 0;
38556
+ };
38557
+ var docBytes = (doc) => typeof doc.size === "number" && doc.size > 0 ? doc.size : (doc.content?.length || 0) * 2;
38421
38558
  var KnowledgeTab = ({
38422
38559
  documents,
38423
38560
  addDocuments,
@@ -38436,7 +38573,7 @@ var KnowledgeTab = ({
38436
38573
  isVectorEnabled,
38437
38574
  uploadDocument: uploadToVector,
38438
38575
  searchDocuments: searchVectorDocuments,
38439
- getUserDocuments,
38576
+ getKnowledgeDocumentsPage,
38440
38577
  downloadVectorFile,
38441
38578
  getFilePreview,
38442
38579
  refreshCompatibilityCheck,
@@ -38449,6 +38586,9 @@ var KnowledgeTab = ({
38449
38586
  const [vectorDocuments, setVectorDocuments] = (0, import_react76.useState)([]);
38450
38587
  const [loadingVectorDocs, setLoadingVectorDocs] = (0, import_react76.useState)(false);
38451
38588
  const [vectorLoadError, setVectorLoadError] = (0, import_react76.useState)(null);
38589
+ const [knowledgeScope, setKnowledgeScope] = (0, import_react76.useState)("knowledge");
38590
+ const [listMeta, setListMeta] = (0, import_react76.useState)(EMPTY_LIST_META);
38591
+ const [loadingMoreVectorDocs, setLoadingMoreVectorDocs] = (0, import_react76.useState)(false);
38452
38592
  const [searchQuery, setSearchQuery] = (0, import_react76.useState)("");
38453
38593
  const [selectedCategory, setSelectedCategory] = (0, import_react76.useState)("all");
38454
38594
  const [contentSourceFilter, setContentSourceFilter] = (0, import_react76.useState)("all");
@@ -38499,16 +38639,52 @@ var KnowledgeTab = ({
38499
38639
  setLoadingVectorDocs(true);
38500
38640
  setVectorLoadError(null);
38501
38641
  try {
38502
- const docs = await getUserDocuments(0, 100);
38503
- const mappedDocs = mapVectorDocsToKnowledgeDocs(docs);
38504
- setVectorDocuments(mappedDocs);
38642
+ const page = await getKnowledgeDocumentsPage(0, KNOWLEDGE_PAGE_SIZE, knowledgeScope);
38643
+ setVectorDocuments(mapVectorDocsToKnowledgeDocs(page.documents));
38644
+ setListMeta({
38645
+ total: page.serverScoped ? page.total : null,
38646
+ hasMore: page.hasMore,
38647
+ nextSkip: page.serverScoped ? page.documents.length : KNOWLEDGE_PAGE_SIZE,
38648
+ scope: page.scope,
38649
+ serverScoped: page.serverScoped,
38650
+ knowledgeFilterUnavailable: page.knowledgeFilterUnavailable,
38651
+ hiddenCount: page.hiddenCount
38652
+ });
38505
38653
  } catch (error) {
38506
38654
  console.error("Failed to load vector documents:", error);
38507
38655
  setVectorLoadError(error instanceof Error ? error.message : String(error));
38508
38656
  } finally {
38509
38657
  setLoadingVectorDocs(false);
38510
38658
  }
38511
- }, [shouldUseVector, getUserDocuments, mapVectorDocsToKnowledgeDocs]);
38659
+ }, [shouldUseVector, getKnowledgeDocumentsPage, mapVectorDocsToKnowledgeDocs, knowledgeScope]);
38660
+ const loadMoreVectorDocuments = (0, import_react76.useCallback)(async () => {
38661
+ if (!shouldUseVector || !listMeta.hasMore || loadingMoreVectorDocs) {
38662
+ return;
38663
+ }
38664
+ setLoadingMoreVectorDocs(true);
38665
+ try {
38666
+ const page = await getKnowledgeDocumentsPage(listMeta.nextSkip, KNOWLEDGE_PAGE_SIZE, knowledgeScope);
38667
+ const mapped = mapVectorDocsToKnowledgeDocs(page.documents);
38668
+ setVectorDocuments((prev) => {
38669
+ const seen = new Set(prev.map((doc) => doc.id));
38670
+ return [...prev, ...mapped.filter((doc) => !seen.has(doc.id))];
38671
+ });
38672
+ setListMeta((prev) => ({
38673
+ ...prev,
38674
+ total: page.serverScoped ? page.total : null,
38675
+ hasMore: page.hasMore,
38676
+ nextSkip: prev.nextSkip + (page.serverScoped ? page.documents.length : KNOWLEDGE_PAGE_SIZE),
38677
+ knowledgeFilterUnavailable: page.knowledgeFilterUnavailable,
38678
+ hiddenCount: prev.hiddenCount + page.hiddenCount
38679
+ }));
38680
+ } catch (error) {
38681
+ setSnackbarSeverity("error");
38682
+ setSnackbarMessage(`Couldn't load more documents: ${error instanceof Error ? error.message : String(error)}`);
38683
+ setShowSnackbar(true);
38684
+ } finally {
38685
+ setLoadingMoreVectorDocs(false);
38686
+ }
38687
+ }, [shouldUseVector, listMeta.hasMore, listMeta.nextSkip, loadingMoreVectorDocs, getKnowledgeDocumentsPage, knowledgeScope, mapVectorDocsToKnowledgeDocs]);
38512
38688
  (0, import_react76.useEffect)(() => {
38513
38689
  if (shouldUseVector) {
38514
38690
  loadVectorDocuments();
@@ -38516,7 +38692,7 @@ var KnowledgeTab = ({
38516
38692
  }, [shouldUseVector, loadVectorDocuments]);
38517
38693
  const filteredAndSortedDocuments = (0, import_react76.useMemo)(() => {
38518
38694
  const sourceDocuments2 = shouldUseVector ? vectorDocuments : documents;
38519
- let filtered = sourceDocuments2;
38695
+ let filtered = [...sourceDocuments2];
38520
38696
  if (searchQuery) {
38521
38697
  if (shouldUseVector) {
38522
38698
  filtered = filtered.filter(
@@ -38551,10 +38727,10 @@ var KnowledgeTab = ({
38551
38727
  comparison = a.name.localeCompare(b.name);
38552
38728
  break;
38553
38729
  case "date":
38554
- comparison = documents.indexOf(a) - documents.indexOf(b);
38730
+ comparison = docTime(a) - docTime(b) || sourceDocuments2.indexOf(a) - sourceDocuments2.indexOf(b);
38555
38731
  break;
38556
38732
  case "size":
38557
- comparison = (a.content.length || 0) - (b.content.length || 0);
38733
+ comparison = docBytes(a) - docBytes(b);
38558
38734
  break;
38559
38735
  case "type":
38560
38736
  comparison = getFileTypeInfo3(a.name).category.localeCompare(getFileTypeInfo3(b.name).category);
@@ -38583,12 +38759,15 @@ var KnowledgeTab = ({
38583
38759
  acc[category] = (acc[category] || 0) + 1;
38584
38760
  return acc;
38585
38761
  }, {});
38762
+ const serverTotal = shouldUseVector && listMeta.total !== null ? listMeta.total : null;
38763
+ const totalDocuments = serverTotal !== null ? Math.max(serverTotal, sourceDocuments2.length) : sourceDocuments2.length;
38586
38764
  return {
38587
- totalDocuments: sourceDocuments2.length,
38765
+ totalDocuments,
38766
+ loadedDocuments: sourceDocuments2.length,
38588
38767
  totalSize: formatFileSize2(totalSize),
38589
38768
  categoryCounts
38590
38769
  };
38591
- }, [documents, vectorDocuments, shouldUseVector]);
38770
+ }, [documents, vectorDocuments, shouldUseVector, listMeta.total]);
38592
38771
  const handleDocumentUpload = async (files) => {
38593
38772
  if (shouldUseVector) {
38594
38773
  showProcessing(
@@ -38900,6 +39079,12 @@ var KnowledgeTab = ({
38900
39079
  const openFilePicker = () => document.getElementById("file-upload")?.click();
38901
39080
  const storageHint = shouldUseVector ? hasTeam && shareWithTeam ? "Shared with your team: members can search these documents." : "Stored privately in your account." : "Stored locally in this browser.";
38902
39081
  const isInitialVectorLoad = shouldUseVector && loadingVectorDocs && vectorDocuments.length === 0;
39082
+ const isWorkspaceView = shouldUseVector && listMeta.scope === "all";
39083
+ const canDeleteListed = !isWorkspaceView;
39084
+ const changeKnowledgeScope = (scope) => {
39085
+ setSelectedDocuments([]);
39086
+ setKnowledgeScope(scope);
39087
+ };
38903
39088
  const touchIcon = { width: { xs: 44, sm: 36 }, height: { xs: 44, sm: 36 } };
38904
39089
  const dropHandlers = {
38905
39090
  onDrop: handleFileDrop,
@@ -38932,13 +39117,30 @@ var KnowledgeTab = ({
38932
39117
  /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_material51.Typography, { variant: "body2", color: "text.secondary", sx: { minWidth: 0 }, children: [
38933
39118
  statistics.totalDocuments,
38934
39119
  " ",
38935
- statistics.totalDocuments === 1 ? "document" : "documents",
39120
+ isWorkspaceView ? statistics.totalDocuments === 1 ? "file" : "files" : statistics.totalDocuments === 1 ? "document" : "documents",
38936
39121
  " \xB7 ",
38937
39122
  statistics.totalSize,
39123
+ statistics.loadedDocuments < statistics.totalDocuments && ` in ${statistics.loadedDocuments} loaded`,
38938
39124
  Object.entries(statistics.categoryCounts).map(([category, count]) => ` \xB7 ${category} ${count}`),
38939
- shouldUseVector && " \xB7 Synced workspace"
39125
+ shouldUseVector && (isWorkspaceView ? " \xB7 All workspace files" : " \xB7 Synced workspace")
38940
39126
  ] }),
38941
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_material51.Stack, { direction: "row", spacing: 1, children: [
39127
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_material51.Stack, { direction: "row", spacing: 1, alignItems: "center", children: [
39128
+ shouldUseVector && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
39129
+ import_material51.TextField,
39130
+ {
39131
+ select: true,
39132
+ label: "Show",
39133
+ value: knowledgeScope,
39134
+ onChange: (e) => changeKnowledgeScope(e.target.value),
39135
+ size: "small",
39136
+ sx: { minWidth: 170 },
39137
+ inputProps: { "aria-label": "Which files to show" },
39138
+ children: [
39139
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material51.MenuItem, { value: "knowledge", children: "Knowledge documents" }),
39140
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material51.MenuItem, { value: "all", children: "All workspace files" })
39141
+ ]
39142
+ }
39143
+ ),
38942
39144
  shouldUseVector && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
38943
39145
  import_material51.Button,
38944
39146
  {
@@ -38990,6 +39192,30 @@ var KnowledgeTab = ({
38990
39192
  ]
38991
39193
  }
38992
39194
  ),
39195
+ shouldUseVector && !vectorLoadError && listMeta.knowledgeFilterUnavailable && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material51.Alert, { severity: "warning", sx: { mb: 1.5 }, children: "Couldn't check which files are indexed for Knowledge, so every file in your workspace is listed. Refresh to try again." }),
39196
+ shouldUseVector && !vectorLoadError && isWorkspaceView && !listMeta.knowledgeFilterUnavailable && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
39197
+ import_material51.Alert,
39198
+ {
39199
+ severity: "info",
39200
+ sx: { mb: 1.5 },
39201
+ action: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material51.Button, { color: "inherit", size: "small", onClick: () => changeKnowledgeScope("knowledge"), children: "Knowledge only" }),
39202
+ children: "Every file stored in your workspace, including Drive uploads, email attachments and app images. Only Knowledge documents are searched in chat. Files here can be viewed and downloaded, not deleted."
39203
+ }
39204
+ ),
39205
+ shouldUseVector && !vectorLoadError && !isWorkspaceView && !listMeta.serverScoped && listMeta.hiddenCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
39206
+ import_material51.Alert,
39207
+ {
39208
+ severity: "info",
39209
+ sx: { mb: 1.5 },
39210
+ action: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material51.Button, { color: "inherit", size: "small", onClick: () => changeKnowledgeScope("all"), children: "Show all" }),
39211
+ children: [
39212
+ listMeta.hiddenCount,
39213
+ " ",
39214
+ listMeta.hiddenCount === 1 ? "image or temporary file is" : "images and temporary files are",
39215
+ " hidden. They come from other apps (Drive, email attachments) and aren't Knowledge documents."
39216
+ ]
39217
+ }
39218
+ ),
38993
39219
  uploadStatuses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material51.Stack, { spacing: 0.75, sx: { mb: 1.5 }, children: uploadStatuses.map((status, index) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
38994
39220
  import_material51.Stack,
38995
39221
  {
@@ -39231,8 +39457,9 @@ var KnowledgeTab = ({
39231
39457
  "Showing ",
39232
39458
  filteredAndSortedDocuments.length,
39233
39459
  " of ",
39234
- sourceDocuments.length,
39235
- " documents",
39460
+ statistics.totalDocuments,
39461
+ " ",
39462
+ isWorkspaceView ? "files" : "documents",
39236
39463
  searchQuery && ` for "${searchQuery}"`
39237
39464
  ] }),
39238
39465
  viewMode === "grid" ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
@@ -39258,8 +39485,8 @@ var KnowledgeTab = ({
39258
39485
  isSelected: selectedDocuments.includes(doc.id),
39259
39486
  isDeleting: deletingDocuments.has(doc.id),
39260
39487
  variant: "full",
39261
- showSelection: true,
39262
- showDelete: true,
39488
+ showSelection: canDeleteListed,
39489
+ showDelete: canDeleteListed,
39263
39490
  showPreview: true
39264
39491
  },
39265
39492
  doc.id
@@ -39300,7 +39527,7 @@ var KnowledgeTab = ({
39300
39527
  transform: isDeleting ? "scale(0.98)" : "none"
39301
39528
  },
39302
39529
  children: [
39303
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
39530
+ canDeleteListed && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
39304
39531
  import_material51.Checkbox,
39305
39532
  {
39306
39533
  size: "small",
@@ -39321,7 +39548,7 @@ var KnowledgeTab = ({
39321
39548
  " \xB7 ",
39322
39549
  fileInfo.language ?? fileInfo.category,
39323
39550
  " \xB7 ",
39324
- formatFileSize2(doc.content.length * 2)
39551
+ formatFileSize2(docBytes(doc))
39325
39552
  ] })
39326
39553
  ] })
39327
39554
  ] }),
@@ -39337,7 +39564,7 @@ var KnowledgeTab = ({
39337
39564
  children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_download.Download, { sx: { fontSize: 18 } })
39338
39565
  }
39339
39566
  ),
39340
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
39567
+ canDeleteListed && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
39341
39568
  import_material51.IconButton,
39342
39569
  {
39343
39570
  onClick: (e) => handleRemoveDocument(e, doc.id),
@@ -39350,7 +39577,17 @@ var KnowledgeTab = ({
39350
39577
  },
39351
39578
  doc.id
39352
39579
  );
39353
- }) })
39580
+ }) }),
39581
+ shouldUseVector && listMeta.hasMore && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material51.Stack, { alignItems: "center", sx: { mt: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
39582
+ import_material51.Button,
39583
+ {
39584
+ variant: "outlined",
39585
+ size: "small",
39586
+ onClick: loadMoreVectorDocuments,
39587
+ disabled: loadingMoreVectorDocs || loadingVectorDocs,
39588
+ children: loadingMoreVectorDocs ? "Loading\u2026" : "Load more"
39589
+ }
39590
+ ) })
39354
39591
  ] })
39355
39592
  ] }),
39356
39593
  selectedDocuments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
@@ -45539,6 +45776,7 @@ function getCriticalConfig() {
45539
45776
 
45540
45777
  // src/services/vectorDatabase/index.ts
45541
45778
  init_vectorDatabaseService();
45779
+ init_knowledgeFiles();
45542
45780
  init_vectorMigrationService();
45543
45781
  init_useVectorStore();
45544
45782
  // Annotate the CommonJS export names for ESM import in node: