@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.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  IS_STORE_BUILD,
3
3
  chat_default
4
- } from "./chunk-SHYNXDRO.mjs";
4
+ } from "./chunk-YGOLNWXJ.mjs";
5
5
  import {
6
6
  chat_provider_default
7
- } from "./chunk-US4TG745.mjs";
7
+ } from "./chunk-QI67R5F6.mjs";
8
8
  import "./chunk-ONQMRE2G.mjs";
9
9
  import {
10
10
  MANAGEMENT_SECTIONS,
@@ -15,8 +15,8 @@ import {
15
15
  useGatewayMemory,
16
16
  useGatewayModels,
17
17
  useManagementAccess
18
- } from "./chunk-PK3LFBGC.mjs";
19
- import "./chunk-5BZWJQ5O.mjs";
18
+ } from "./chunk-4SXXEGEK.mjs";
19
+ import "./chunk-JD6C64CT.mjs";
20
20
  import "./chunk-CABOLDNR.mjs";
21
21
  import "./chunk-E5WMDLE3.mjs";
22
22
  import {
@@ -25,7 +25,7 @@ import {
25
25
  import {
26
26
  FeedbackButton,
27
27
  chat_modal_default
28
- } from "./chunk-N4BQ6HKL.mjs";
28
+ } from "./chunk-R3NOM2DG.mjs";
29
29
  import {
30
30
  FeedbackModal,
31
31
  StreamingTTSClient,
@@ -42,7 +42,7 @@ import {
42
42
  useTTS,
43
43
  useVoiceStore,
44
44
  voiceService
45
- } from "./chunk-KDIL5WUL.mjs";
45
+ } from "./chunk-62IYSU3I.mjs";
46
46
  import {
47
47
  DEFAULT_TIER_FEATURES,
48
48
  FeatureFlagContext,
@@ -61,7 +61,7 @@ import {
61
61
  useVectorStore,
62
62
  vectorDatabaseService,
63
63
  vectorMigrationService
64
- } from "./chunk-46OGYEME.mjs";
64
+ } from "./chunk-KAXUI5H7.mjs";
65
65
  import {
66
66
  usePackageSettingsStore,
67
67
  usePreferencesStore
@@ -3902,7 +3902,7 @@ var init_util = __esm({
3902
3902
  "src/util.ts"() {
3903
3903
  "use strict";
3904
3904
  init_debugLogger();
3905
- toTitleCase = (str) => str.toLowerCase().split(" ").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3905
+ toTitleCase = (str2) => str2.toLowerCase().split(" ").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3906
3906
  generateSeed = () => Math.floor(Math.random() * 1e4);
3907
3907
  fetchAndConvertToBase64 = async (src) => {
3908
3908
  const response = await fetch(src);
@@ -4795,6 +4795,99 @@ var init_embeddingService = __esm({
4795
4795
  }
4796
4796
  });
4797
4797
 
4798
+ // src/services/vectorDatabase/knowledgeFiles.ts
4799
+ var KNOWLEDGE_PAGE_LIMIT_MAX, MEDIA_MIME_PREFIXES, MEDIA_EXTENSIONS, TEMP_NAME, str, recordName, recordMime, isLikelyKnowledgeFile, toRecords, num, parseKnowledgeFileList;
4800
+ var init_knowledgeFiles = __esm({
4801
+ "src/services/vectorDatabase/knowledgeFiles.ts"() {
4802
+ "use strict";
4803
+ KNOWLEDGE_PAGE_LIMIT_MAX = 200;
4804
+ MEDIA_MIME_PREFIXES = ["image/", "video/", "audio/"];
4805
+ MEDIA_EXTENSIONS = /* @__PURE__ */ new Set([
4806
+ "png",
4807
+ "jpg",
4808
+ "jpeg",
4809
+ "gif",
4810
+ "webp",
4811
+ "bmp",
4812
+ "tif",
4813
+ "tiff",
4814
+ "heic",
4815
+ "heif",
4816
+ "svg",
4817
+ "ico",
4818
+ "avif",
4819
+ "mp4",
4820
+ "mov",
4821
+ "m4v",
4822
+ "webm",
4823
+ "avi",
4824
+ "mkv",
4825
+ "mp3",
4826
+ "wav",
4827
+ "m4a",
4828
+ "aac",
4829
+ "ogg",
4830
+ "flac"
4831
+ ]);
4832
+ TEMP_NAME = /^(~WRD\d*|~\$|~\w+\.tmp$)|\.tmp$/i;
4833
+ str = (value) => typeof value === "string" ? value : "";
4834
+ recordName = (record) => str(record.filename) || str(record.fileName) || str(record.name);
4835
+ recordMime = (record) => (str(record.mimeType) || str(record.contentType) || str(record.type)).toLowerCase();
4836
+ isLikelyKnowledgeFile = (record) => {
4837
+ const name = recordName(record);
4838
+ if (TEMP_NAME.test(name)) return false;
4839
+ const ext = name.includes(".") ? name.split(".").pop().toLowerCase() : "";
4840
+ if (MEDIA_EXTENSIONS.has(ext)) return false;
4841
+ const mime = recordMime(record);
4842
+ if (MEDIA_MIME_PREFIXES.some((prefix) => mime.startsWith(prefix))) return false;
4843
+ return true;
4844
+ };
4845
+ toRecords = (value) => Array.isArray(value) ? value.filter((item) => !!item && typeof item === "object" && !Array.isArray(item)) : [];
4846
+ num = (value, fallback) => typeof value === "number" && Number.isFinite(value) ? value : fallback;
4847
+ parseKnowledgeFileList = (body, request) => {
4848
+ if (body && typeof body === "object" && !Array.isArray(body) && "total" in body) {
4849
+ const envelope = body;
4850
+ const files2 = toRecords(envelope.files);
4851
+ const total = num(envelope.total, files2.length);
4852
+ const skip = num(envelope.skip, request.skip);
4853
+ const scope = envelope.scope === "all" ? "all" : "knowledge";
4854
+ return {
4855
+ files: files2,
4856
+ total,
4857
+ hasMore: typeof envelope.hasMore === "boolean" ? envelope.hasMore : skip + files2.length < total,
4858
+ scope,
4859
+ serverScoped: true,
4860
+ knowledgeFilterUnavailable: envelope.knowledgeFilterUnavailable === true,
4861
+ hiddenCount: 0
4862
+ };
4863
+ }
4864
+ const raw = body && typeof body === "object" && !Array.isArray(body) ? toRecords(body.files) : toRecords(body);
4865
+ const hasMore = raw.length >= request.limit;
4866
+ if (request.scope === "all") {
4867
+ return {
4868
+ files: raw,
4869
+ total: request.skip + raw.length,
4870
+ hasMore,
4871
+ scope: "all",
4872
+ serverScoped: false,
4873
+ knowledgeFilterUnavailable: false,
4874
+ hiddenCount: 0
4875
+ };
4876
+ }
4877
+ const files = raw.filter(isLikelyKnowledgeFile);
4878
+ return {
4879
+ files,
4880
+ total: files.length,
4881
+ hasMore,
4882
+ scope: "knowledge",
4883
+ serverScoped: false,
4884
+ knowledgeFilterUnavailable: false,
4885
+ hiddenCount: raw.length - files.length
4886
+ };
4887
+ };
4888
+ }
4889
+ });
4890
+
4798
4891
  // src/utils/memoryUtils.ts
4799
4892
  var memoryUtils_exports = {};
4800
4893
  __export(memoryUtils_exports, {
@@ -5029,6 +5122,7 @@ var init_vectorDatabaseService = __esm({
5029
5122
  "src/services/vectorDatabase/vectorDatabaseService.ts"() {
5030
5123
  "use strict";
5031
5124
  init_debugLogger();
5125
+ init_knowledgeFiles();
5032
5126
  VectorDatabaseService = class {
5033
5127
  baseUrl;
5034
5128
  fileStorageApiUrl;
@@ -5788,36 +5882,44 @@ var init_vectorDatabaseService = __esm({
5788
5882
  }
5789
5883
  }
5790
5884
  /**
5791
- * Get user's files - tries both Gateway API and file storage API
5885
+ * One page of the Knowledge file list from the gateway (see ./knowledgeFiles).
5886
+ *
5887
+ * No fallback to the file storage API here: its listing is the whole Drive (every product's
5888
+ * files), which is exactly what Knowledge must not show. A failure surfaces to the caller.
5792
5889
  */
5793
- async getUserFiles(skip = 0, limit = 50) {
5890
+ async listKnowledgeFiles(skip = 0, limit = 50, scope = "knowledge") {
5794
5891
  if (!this.isAvailable()) {
5795
- return [];
5892
+ return parseKnowledgeFileList([], { skip, limit, scope });
5893
+ }
5894
+ const safeSkip = Math.max(0, Math.floor(skip));
5895
+ const safeLimit = Math.min(KNOWLEDGE_PAGE_LIMIT_MAX, Math.max(1, Math.floor(limit)));
5896
+ const query = new URLSearchParams({
5897
+ skip: String(safeSkip),
5898
+ limit: String(safeLimit),
5899
+ scope
5900
+ });
5901
+ debugLogger.debug("Fetching knowledge files from Gateway API", { skip: safeSkip, limit: safeLimit, scope });
5902
+ const response = await fetch(`${this.baseUrl}/embedding/files?${query.toString()}`, {
5903
+ method: "GET",
5904
+ headers: this.getHeaders()
5905
+ });
5906
+ if (!response.ok) {
5907
+ throw new Error(`Couldn't list documents (gateway answered ${response.status})`);
5796
5908
  }
5909
+ const body = await response.json();
5910
+ return parseKnowledgeFileList(body, { skip: safeSkip, limit: safeLimit, scope });
5911
+ }
5912
+ /**
5913
+ * Get the user's Knowledge files (first page, knowledge scope). Kept for existing callers;
5914
+ * prefer listKnowledgeFiles for totals and paging.
5915
+ */
5916
+ async getUserFiles(skip = 0, limit = 50) {
5797
5917
  try {
5798
- debugLogger.debug("Fetching user files from Gateway API", { skip, limit });
5799
- const response = await fetch(`${this.baseUrl}/embedding/files?skip=${skip}&limit=${limit}`, {
5800
- method: "GET",
5801
- headers: this.getHeaders()
5802
- });
5803
- if (!response.ok) {
5804
- debugLogger.warn("Gateway API files endpoint failed, falling back to file storage API", {
5805
- status: response.status
5806
- });
5807
- return await this.getUserFilesFromFileStorage(skip, limit);
5808
- }
5809
- const result = await response.json();
5810
- debugLogger.debug("Gateway API files response", result);
5811
- if (Array.isArray(result)) {
5812
- return this.toRecordArray(result);
5813
- }
5814
- if (result && Array.isArray(result.files)) {
5815
- return this.toRecordArray(result.files);
5816
- }
5817
- return [];
5918
+ const page = await this.listKnowledgeFiles(skip, limit, "knowledge");
5919
+ return page.files;
5818
5920
  } catch (error) {
5819
- debugLogger.error("Gateway API failed while fetching user files, trying file storage API", { error });
5820
- return await this.getUserFilesFromFileStorage(skip, limit);
5921
+ debugLogger.error("Failed to fetch knowledge files from Gateway API", { error });
5922
+ return [];
5821
5923
  }
5822
5924
  }
5823
5925
  /**
@@ -9365,7 +9467,7 @@ var init_conversationSyncStore = __esm({
9365
9467
  });
9366
9468
 
9367
9469
  // src/hooks/useVectorStore.tsx
9368
- var import_react3, toIsoString, memoryEntryToVectorMemory, knowledgeDocToVectorDocument, rawFileRecordToVectorDocument, useVectorStore;
9470
+ var import_react3, toIsoString, memoryEntryToVectorMemory, knowledgeDocToVectorDocument, optionalString, rawFileRecordToVectorDocument, useVectorStore;
9369
9471
  var init_useVectorStore = __esm({
9370
9472
  "src/hooks/useVectorStore.tsx"() {
9371
9473
  "use strict";
@@ -9409,6 +9511,7 @@ var init_useVectorStore = __esm({
9409
9511
  isTeamContent: doc.isTeamContent ?? false,
9410
9512
  contentSource: doc.contentSource ?? (doc.isTeamContent ? "team" : "user")
9411
9513
  });
9514
+ optionalString = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
9412
9515
  rawFileRecordToVectorDocument = (record) => {
9413
9516
  if (!record || typeof record !== "object") {
9414
9517
  return null;
@@ -9423,10 +9526,12 @@ var init_useVectorStore = __esm({
9423
9526
  const mimeType = typeof record.mimeType === "string" ? record.mimeType : "application/octet-stream";
9424
9527
  const uploadedBy = typeof record.uploadedBy === "string" ? record.uploadedBy : "unknown";
9425
9528
  const uploadedAt = typeof record.uploadedAt === "string" ? record.uploadedAt : (/* @__PURE__ */ new Date()).toISOString();
9426
- const isUserContent = typeof record.isUserContent === "boolean" ? record.isUserContent : true;
9427
- const isTeamContent = typeof record.isTeamContent === "boolean" ? record.isTeamContent : false;
9428
- const contentSource = record.contentSource === "team" ? "team" : "user";
9529
+ const teamSid = optionalString(record.teamSid);
9530
+ const isTeamContent = typeof record.isTeamContent === "boolean" ? record.isTeamContent : !!teamSid;
9531
+ const isUserContent = typeof record.isUserContent === "boolean" ? record.isUserContent : !isTeamContent;
9532
+ const contentSource = record.contentSource === "team" || record.contentSource === void 0 && isTeamContent ? "team" : "user";
9429
9533
  const score = typeof record.score === "number" ? record.score : void 0;
9534
+ const size = typeof record.size === "number" && Number.isFinite(record.size) && record.size >= 0 ? record.size : void 0;
9430
9535
  return {
9431
9536
  id,
9432
9537
  filename,
@@ -9437,7 +9542,12 @@ var init_useVectorStore = __esm({
9437
9542
  isUserContent,
9438
9543
  isTeamContent,
9439
9544
  contentSource,
9440
- score
9545
+ score,
9546
+ size,
9547
+ bucket: optionalString(record.bucket),
9548
+ teamSid,
9549
+ userEmail: optionalString(record.userEmail),
9550
+ preview
9441
9551
  };
9442
9552
  };
9443
9553
  useVectorStore = () => {
@@ -9989,22 +10099,32 @@ var init_useVectorStore = __esm({
9989
10099
  (0, import_react3.useEffect)(() => {
9990
10100
  initializeVectorService();
9991
10101
  }, [initializeVectorService]);
9992
- const getUserDocuments = (0, import_react3.useCallback)(async (skip = 0, limit = 50) => {
10102
+ const getKnowledgeDocumentsPage = (0, import_react3.useCallback)(async (skip = 0, limit = 50, scope = "knowledge") => {
9993
10103
  if (!status.isEnabled || status.migrationRequired) {
9994
- return [];
10104
+ return {
10105
+ documents: [],
10106
+ total: 0,
10107
+ hasMore: false,
10108
+ scope,
10109
+ serverScoped: false,
10110
+ knowledgeFilterUnavailable: false,
10111
+ hiddenCount: 0
10112
+ };
9995
10113
  }
10114
+ const { files, ...meta } = await vectorDatabaseService.listKnowledgeFiles(skip, limit, scope);
10115
+ const documents = files.map(rawFileRecordToVectorDocument).filter((doc) => doc !== null);
10116
+ debugLogger.info("Retrieved knowledge documents", { count: documents.length, total: meta.total, scope: meta.scope });
10117
+ return { documents, ...meta };
10118
+ }, [status.isEnabled, status.migrationRequired]);
10119
+ const getUserDocuments = (0, import_react3.useCallback)(async (skip = 0, limit = 50) => {
9996
10120
  try {
9997
- const records = await vectorDatabaseService.getUserFiles(skip, limit);
9998
- const documents = records.map(rawFileRecordToVectorDocument).filter((doc) => doc !== null);
9999
- debugLogger.info("Retrieved user documents from vector database", {
10000
- count: documents.length
10001
- });
10002
- return documents;
10121
+ const page = await getKnowledgeDocumentsPage(skip, limit, "knowledge");
10122
+ return page.documents;
10003
10123
  } catch (error) {
10004
10124
  debugLogger.error("Failed to get user documents", { error });
10005
10125
  return [];
10006
10126
  }
10007
- }, [status.isEnabled, status.migrationRequired]);
10127
+ }, [getKnowledgeDocumentsPage]);
10008
10128
  const deleteDocument = (0, import_react3.useCallback)(async (fileId) => {
10009
10129
  if (!status.isEnabled || status.migrationRequired) {
10010
10130
  return {
@@ -10101,6 +10221,7 @@ var init_useVectorStore = __esm({
10101
10221
  uploadDocument,
10102
10222
  searchDocuments,
10103
10223
  getUserDocuments,
10224
+ getKnowledgeDocumentsPage,
10104
10225
  deleteDocument,
10105
10226
  downloadVectorFile,
10106
10227
  getFilePreview,
@@ -10550,7 +10671,8 @@ var init_DocumentCard = __esm({
10550
10671
  const metaLine = [
10551
10672
  sourceLabel,
10552
10673
  fileInfo.language ?? fileInfo.category,
10553
- formatFileSize((doc.content?.length || 0) * 2)
10674
+ // Real file size when the listing reports one; otherwise estimate from the text content.
10675
+ formatFileSize(typeof doc.size === "number" && doc.size > 0 ? doc.size : (doc.content?.length || 0) * 2)
10554
10676
  ].join(" \xB7 ");
10555
10677
  if (documentState === "unavailable" && !allowErrorStates) {
10556
10678
  return null;
@@ -17855,7 +17977,7 @@ var init_StreamingMarkdown = __esm({
17855
17977
  **Sources**
17856
17978
  ${listMarkdown}`;
17857
17979
  }, [sanitizedContent, effectiveSources, isStreaming]);
17858
- const escapeHtml = (str) => str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
17980
+ const escapeHtml = (str2) => str2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
17859
17981
  const isPlainAppend = (s) => {
17860
17982
  return !/[`*_\[\]<>|#~]/.test(s);
17861
17983
  };
@@ -19108,9 +19230,9 @@ var init_source_chips = __esm({
19108
19230
  };
19109
19231
  linkifyCitations = (content, sources) => {
19110
19232
  if (!content || sources.length === 0) return content;
19111
- const link = (text) => text.replace(/\[(\d{1,2})\]/g, (full, num) => {
19112
- const src = sources[parseInt(num, 10) - 1];
19113
- return src ? `[\\[${num}\\]](${src.url})` : full;
19233
+ const link = (text) => text.replace(/\[(\d{1,2})\]/g, (full, num2) => {
19234
+ const src = sources[parseInt(num2, 10) - 1];
19235
+ return src ? `[\\[${num2}\\]](${src.url})` : full;
19114
19236
  });
19115
19237
  return content.split(/(```[\s\S]*?```)/g).map((seg, i) => i % 2 === 0 ? link(seg) : seg).join("");
19116
19238
  };
@@ -33197,8 +33319,8 @@ var ChatModal = ({
33197
33319
  }
33198
33320
  }
33199
33321
  };
33200
- const toTitleCase2 = (str) => {
33201
- return str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
33322
+ const toTitleCase2 = (str2) => {
33323
+ return str2.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
33202
33324
  };
33203
33325
  (0, import_react27.useEffect)(() => {
33204
33326
  if (!SYSTEM_PROMPT) {
@@ -37528,6 +37650,21 @@ var getContentSourceInfo = (doc, isVectorMode) => {
37528
37650
  }
37529
37651
  return { label: "Local", icon: import_lock.Lock };
37530
37652
  };
37653
+ var KNOWLEDGE_PAGE_SIZE = 50;
37654
+ var EMPTY_LIST_META = {
37655
+ total: null,
37656
+ hasMore: false,
37657
+ nextSkip: 0,
37658
+ scope: "knowledge",
37659
+ serverScoped: false,
37660
+ knowledgeFilterUnavailable: false,
37661
+ hiddenCount: 0
37662
+ };
37663
+ var docTime = (doc) => {
37664
+ const time = doc.addedDate instanceof Date ? doc.addedDate.getTime() : NaN;
37665
+ return Number.isFinite(time) ? time : 0;
37666
+ };
37667
+ var docBytes = (doc) => typeof doc.size === "number" && doc.size > 0 ? doc.size : (doc.content?.length || 0) * 2;
37531
37668
  var KnowledgeTab = ({
37532
37669
  documents,
37533
37670
  addDocuments,
@@ -37546,7 +37683,7 @@ var KnowledgeTab = ({
37546
37683
  isVectorEnabled,
37547
37684
  uploadDocument: uploadToVector,
37548
37685
  searchDocuments: searchVectorDocuments,
37549
- getUserDocuments,
37686
+ getKnowledgeDocumentsPage,
37550
37687
  downloadVectorFile,
37551
37688
  getFilePreview,
37552
37689
  refreshCompatibilityCheck,
@@ -37559,6 +37696,9 @@ var KnowledgeTab = ({
37559
37696
  const [vectorDocuments, setVectorDocuments] = (0, import_react37.useState)([]);
37560
37697
  const [loadingVectorDocs, setLoadingVectorDocs] = (0, import_react37.useState)(false);
37561
37698
  const [vectorLoadError, setVectorLoadError] = (0, import_react37.useState)(null);
37699
+ const [knowledgeScope, setKnowledgeScope] = (0, import_react37.useState)("knowledge");
37700
+ const [listMeta, setListMeta] = (0, import_react37.useState)(EMPTY_LIST_META);
37701
+ const [loadingMoreVectorDocs, setLoadingMoreVectorDocs] = (0, import_react37.useState)(false);
37562
37702
  const [searchQuery, setSearchQuery] = (0, import_react37.useState)("");
37563
37703
  const [selectedCategory, setSelectedCategory] = (0, import_react37.useState)("all");
37564
37704
  const [contentSourceFilter, setContentSourceFilter] = (0, import_react37.useState)("all");
@@ -37609,16 +37749,52 @@ var KnowledgeTab = ({
37609
37749
  setLoadingVectorDocs(true);
37610
37750
  setVectorLoadError(null);
37611
37751
  try {
37612
- const docs = await getUserDocuments(0, 100);
37613
- const mappedDocs = mapVectorDocsToKnowledgeDocs(docs);
37614
- setVectorDocuments(mappedDocs);
37752
+ const page = await getKnowledgeDocumentsPage(0, KNOWLEDGE_PAGE_SIZE, knowledgeScope);
37753
+ setVectorDocuments(mapVectorDocsToKnowledgeDocs(page.documents));
37754
+ setListMeta({
37755
+ total: page.serverScoped ? page.total : null,
37756
+ hasMore: page.hasMore,
37757
+ nextSkip: page.serverScoped ? page.documents.length : KNOWLEDGE_PAGE_SIZE,
37758
+ scope: page.scope,
37759
+ serverScoped: page.serverScoped,
37760
+ knowledgeFilterUnavailable: page.knowledgeFilterUnavailable,
37761
+ hiddenCount: page.hiddenCount
37762
+ });
37615
37763
  } catch (error) {
37616
37764
  console.error("Failed to load vector documents:", error);
37617
37765
  setVectorLoadError(error instanceof Error ? error.message : String(error));
37618
37766
  } finally {
37619
37767
  setLoadingVectorDocs(false);
37620
37768
  }
37621
- }, [shouldUseVector, getUserDocuments, mapVectorDocsToKnowledgeDocs]);
37769
+ }, [shouldUseVector, getKnowledgeDocumentsPage, mapVectorDocsToKnowledgeDocs, knowledgeScope]);
37770
+ const loadMoreVectorDocuments = (0, import_react37.useCallback)(async () => {
37771
+ if (!shouldUseVector || !listMeta.hasMore || loadingMoreVectorDocs) {
37772
+ return;
37773
+ }
37774
+ setLoadingMoreVectorDocs(true);
37775
+ try {
37776
+ const page = await getKnowledgeDocumentsPage(listMeta.nextSkip, KNOWLEDGE_PAGE_SIZE, knowledgeScope);
37777
+ const mapped = mapVectorDocsToKnowledgeDocs(page.documents);
37778
+ setVectorDocuments((prev) => {
37779
+ const seen = new Set(prev.map((doc) => doc.id));
37780
+ return [...prev, ...mapped.filter((doc) => !seen.has(doc.id))];
37781
+ });
37782
+ setListMeta((prev) => ({
37783
+ ...prev,
37784
+ total: page.serverScoped ? page.total : null,
37785
+ hasMore: page.hasMore,
37786
+ nextSkip: prev.nextSkip + (page.serverScoped ? page.documents.length : KNOWLEDGE_PAGE_SIZE),
37787
+ knowledgeFilterUnavailable: page.knowledgeFilterUnavailable,
37788
+ hiddenCount: prev.hiddenCount + page.hiddenCount
37789
+ }));
37790
+ } catch (error) {
37791
+ setSnackbarSeverity("error");
37792
+ setSnackbarMessage(`Couldn't load more documents: ${error instanceof Error ? error.message : String(error)}`);
37793
+ setShowSnackbar(true);
37794
+ } finally {
37795
+ setLoadingMoreVectorDocs(false);
37796
+ }
37797
+ }, [shouldUseVector, listMeta.hasMore, listMeta.nextSkip, loadingMoreVectorDocs, getKnowledgeDocumentsPage, knowledgeScope, mapVectorDocsToKnowledgeDocs]);
37622
37798
  (0, import_react37.useEffect)(() => {
37623
37799
  if (shouldUseVector) {
37624
37800
  loadVectorDocuments();
@@ -37626,7 +37802,7 @@ var KnowledgeTab = ({
37626
37802
  }, [shouldUseVector, loadVectorDocuments]);
37627
37803
  const filteredAndSortedDocuments = (0, import_react37.useMemo)(() => {
37628
37804
  const sourceDocuments2 = shouldUseVector ? vectorDocuments : documents;
37629
- let filtered = sourceDocuments2;
37805
+ let filtered = [...sourceDocuments2];
37630
37806
  if (searchQuery) {
37631
37807
  if (shouldUseVector) {
37632
37808
  filtered = filtered.filter(
@@ -37661,10 +37837,10 @@ var KnowledgeTab = ({
37661
37837
  comparison = a.name.localeCompare(b.name);
37662
37838
  break;
37663
37839
  case "date":
37664
- comparison = documents.indexOf(a) - documents.indexOf(b);
37840
+ comparison = docTime(a) - docTime(b) || sourceDocuments2.indexOf(a) - sourceDocuments2.indexOf(b);
37665
37841
  break;
37666
37842
  case "size":
37667
- comparison = (a.content.length || 0) - (b.content.length || 0);
37843
+ comparison = docBytes(a) - docBytes(b);
37668
37844
  break;
37669
37845
  case "type":
37670
37846
  comparison = getFileTypeInfo3(a.name).category.localeCompare(getFileTypeInfo3(b.name).category);
@@ -37693,12 +37869,15 @@ var KnowledgeTab = ({
37693
37869
  acc[category] = (acc[category] || 0) + 1;
37694
37870
  return acc;
37695
37871
  }, {});
37872
+ const serverTotal = shouldUseVector && listMeta.total !== null ? listMeta.total : null;
37873
+ const totalDocuments = serverTotal !== null ? Math.max(serverTotal, sourceDocuments2.length) : sourceDocuments2.length;
37696
37874
  return {
37697
- totalDocuments: sourceDocuments2.length,
37875
+ totalDocuments,
37876
+ loadedDocuments: sourceDocuments2.length,
37698
37877
  totalSize: formatFileSize2(totalSize),
37699
37878
  categoryCounts
37700
37879
  };
37701
- }, [documents, vectorDocuments, shouldUseVector]);
37880
+ }, [documents, vectorDocuments, shouldUseVector, listMeta.total]);
37702
37881
  const handleDocumentUpload = async (files) => {
37703
37882
  if (shouldUseVector) {
37704
37883
  showProcessing(
@@ -38010,6 +38189,12 @@ var KnowledgeTab = ({
38010
38189
  const openFilePicker = () => document.getElementById("file-upload")?.click();
38011
38190
  const storageHint = shouldUseVector ? hasTeam && shareWithTeam ? "Shared with your team: members can search these documents." : "Stored privately in your account." : "Stored locally in this browser.";
38012
38191
  const isInitialVectorLoad = shouldUseVector && loadingVectorDocs && vectorDocuments.length === 0;
38192
+ const isWorkspaceView = shouldUseVector && listMeta.scope === "all";
38193
+ const canDeleteListed = !isWorkspaceView;
38194
+ const changeKnowledgeScope = (scope) => {
38195
+ setSelectedDocuments([]);
38196
+ setKnowledgeScope(scope);
38197
+ };
38013
38198
  const touchIcon = { width: { xs: 44, sm: 36 }, height: { xs: 44, sm: 36 } };
38014
38199
  const dropHandlers = {
38015
38200
  onDrop: handleFileDrop,
@@ -38042,13 +38227,30 @@ var KnowledgeTab = ({
38042
38227
  /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_material26.Typography, { variant: "body2", color: "text.secondary", sx: { minWidth: 0 }, children: [
38043
38228
  statistics.totalDocuments,
38044
38229
  " ",
38045
- statistics.totalDocuments === 1 ? "document" : "documents",
38230
+ isWorkspaceView ? statistics.totalDocuments === 1 ? "file" : "files" : statistics.totalDocuments === 1 ? "document" : "documents",
38046
38231
  " \xB7 ",
38047
38232
  statistics.totalSize,
38233
+ statistics.loadedDocuments < statistics.totalDocuments && ` in ${statistics.loadedDocuments} loaded`,
38048
38234
  Object.entries(statistics.categoryCounts).map(([category, count]) => ` \xB7 ${category} ${count}`),
38049
- shouldUseVector && " \xB7 Synced workspace"
38235
+ shouldUseVector && (isWorkspaceView ? " \xB7 All workspace files" : " \xB7 Synced workspace")
38050
38236
  ] }),
38051
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_material26.Stack, { direction: "row", spacing: 1, children: [
38237
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_material26.Stack, { direction: "row", spacing: 1, alignItems: "center", children: [
38238
+ shouldUseVector && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
38239
+ import_material26.TextField,
38240
+ {
38241
+ select: true,
38242
+ label: "Show",
38243
+ value: knowledgeScope,
38244
+ onChange: (e) => changeKnowledgeScope(e.target.value),
38245
+ size: "small",
38246
+ sx: { minWidth: 170 },
38247
+ inputProps: { "aria-label": "Which files to show" },
38248
+ children: [
38249
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material26.MenuItem, { value: "knowledge", children: "Knowledge documents" }),
38250
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material26.MenuItem, { value: "all", children: "All workspace files" })
38251
+ ]
38252
+ }
38253
+ ),
38052
38254
  shouldUseVector && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
38053
38255
  import_material26.Button,
38054
38256
  {
@@ -38100,6 +38302,30 @@ var KnowledgeTab = ({
38100
38302
  ]
38101
38303
  }
38102
38304
  ),
38305
+ shouldUseVector && !vectorLoadError && listMeta.knowledgeFilterUnavailable && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material26.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." }),
38306
+ shouldUseVector && !vectorLoadError && isWorkspaceView && !listMeta.knowledgeFilterUnavailable && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
38307
+ import_material26.Alert,
38308
+ {
38309
+ severity: "info",
38310
+ sx: { mb: 1.5 },
38311
+ action: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material26.Button, { color: "inherit", size: "small", onClick: () => changeKnowledgeScope("knowledge"), children: "Knowledge only" }),
38312
+ 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."
38313
+ }
38314
+ ),
38315
+ shouldUseVector && !vectorLoadError && !isWorkspaceView && !listMeta.serverScoped && listMeta.hiddenCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
38316
+ import_material26.Alert,
38317
+ {
38318
+ severity: "info",
38319
+ sx: { mb: 1.5 },
38320
+ action: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material26.Button, { color: "inherit", size: "small", onClick: () => changeKnowledgeScope("all"), children: "Show all" }),
38321
+ children: [
38322
+ listMeta.hiddenCount,
38323
+ " ",
38324
+ listMeta.hiddenCount === 1 ? "image or temporary file is" : "images and temporary files are",
38325
+ " hidden. They come from other apps (Drive, email attachments) and aren't Knowledge documents."
38326
+ ]
38327
+ }
38328
+ ),
38103
38329
  uploadStatuses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material26.Stack, { spacing: 0.75, sx: { mb: 1.5 }, children: uploadStatuses.map((status, index) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
38104
38330
  import_material26.Stack,
38105
38331
  {
@@ -38341,8 +38567,9 @@ var KnowledgeTab = ({
38341
38567
  "Showing ",
38342
38568
  filteredAndSortedDocuments.length,
38343
38569
  " of ",
38344
- sourceDocuments.length,
38345
- " documents",
38570
+ statistics.totalDocuments,
38571
+ " ",
38572
+ isWorkspaceView ? "files" : "documents",
38346
38573
  searchQuery && ` for "${searchQuery}"`
38347
38574
  ] }),
38348
38575
  viewMode === "grid" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
@@ -38368,8 +38595,8 @@ var KnowledgeTab = ({
38368
38595
  isSelected: selectedDocuments.includes(doc.id),
38369
38596
  isDeleting: deletingDocuments.has(doc.id),
38370
38597
  variant: "full",
38371
- showSelection: true,
38372
- showDelete: true,
38598
+ showSelection: canDeleteListed,
38599
+ showDelete: canDeleteListed,
38373
38600
  showPreview: true
38374
38601
  },
38375
38602
  doc.id
@@ -38410,7 +38637,7 @@ var KnowledgeTab = ({
38410
38637
  transform: isDeleting ? "scale(0.98)" : "none"
38411
38638
  },
38412
38639
  children: [
38413
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
38640
+ canDeleteListed && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
38414
38641
  import_material26.Checkbox,
38415
38642
  {
38416
38643
  size: "small",
@@ -38431,7 +38658,7 @@ var KnowledgeTab = ({
38431
38658
  " \xB7 ",
38432
38659
  fileInfo.language ?? fileInfo.category,
38433
38660
  " \xB7 ",
38434
- formatFileSize2(doc.content.length * 2)
38661
+ formatFileSize2(docBytes(doc))
38435
38662
  ] })
38436
38663
  ] })
38437
38664
  ] }),
@@ -38447,7 +38674,7 @@ var KnowledgeTab = ({
38447
38674
  children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_download.Download, { sx: { fontSize: 18 } })
38448
38675
  }
38449
38676
  ),
38450
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
38677
+ canDeleteListed && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
38451
38678
  import_material26.IconButton,
38452
38679
  {
38453
38680
  onClick: (e) => handleRemoveDocument(e, doc.id),
@@ -38460,7 +38687,17 @@ var KnowledgeTab = ({
38460
38687
  },
38461
38688
  doc.id
38462
38689
  );
38463
- }) })
38690
+ }) }),
38691
+ shouldUseVector && listMeta.hasMore && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material26.Stack, { alignItems: "center", sx: { mt: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
38692
+ import_material26.Button,
38693
+ {
38694
+ variant: "outlined",
38695
+ size: "small",
38696
+ onClick: loadMoreVectorDocuments,
38697
+ disabled: loadingMoreVectorDocs || loadingVectorDocs,
38698
+ children: loadingMoreVectorDocs ? "Loading\u2026" : "Load more"
38699
+ }
38700
+ ) })
38464
38701
  ] })
38465
38702
  ] }),
38466
38703
  selectedDocuments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(