@burtson-labs/bandit-engine 2.0.8 → 2.0.10

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 (193) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +161 -56
  3. package/dist/{aiProviderStore-YWJHSWFA.mjs → aiProviderStore-3YS2BZU3.mjs} +2 -2
  4. package/dist/chat-ZPJNWIXI.mjs +15 -0
  5. package/dist/chat-provider.js +9608 -0
  6. package/dist/chat-provider.js.map +1 -0
  7. package/dist/chat-provider.mjs +17 -0
  8. package/dist/chunk-2ZNIQD26.mjs +259 -0
  9. package/dist/chunk-2ZNIQD26.mjs.map +1 -0
  10. package/dist/chunk-5UVULH77.mjs +9427 -0
  11. package/dist/chunk-5UVULH77.mjs.map +1 -0
  12. package/dist/chunk-CY227I4F.mjs +160 -0
  13. package/dist/chunk-CY227I4F.mjs.map +1 -0
  14. package/dist/chunk-IFN52MQL.mjs +8763 -0
  15. package/dist/chunk-IFN52MQL.mjs.map +1 -0
  16. package/dist/{chunk-AVC6IZJQ.mjs → chunk-IHJPVIGB.mjs} +179 -2
  17. package/dist/chunk-IHJPVIGB.mjs.map +1 -0
  18. package/dist/chunk-L7UOQ2Y2.mjs +2810 -0
  19. package/dist/chunk-L7UOQ2Y2.mjs.map +1 -0
  20. package/dist/chunk-ONQMRE2G.mjs +26 -0
  21. package/dist/chunk-ONQMRE2G.mjs.map +1 -0
  22. package/dist/chunk-RTQDQ6TC.mjs +231 -0
  23. package/dist/chunk-RTQDQ6TC.mjs.map +1 -0
  24. package/dist/chunk-UMPVXYVC.mjs +5658 -0
  25. package/dist/chunk-UMPVXYVC.mjs.map +1 -0
  26. package/dist/chunk-XEG45Q6V.mjs +8925 -0
  27. package/dist/chunk-XEG45Q6V.mjs.map +1 -0
  28. package/dist/{chunk-WYS5CZVG.mjs → chunk-XUBYA5I7.mjs} +2 -2
  29. package/dist/{chunk-WYS5CZVG.mjs.map → chunk-XUBYA5I7.mjs.map} +1 -1
  30. package/dist/cli/cli.js +24 -13
  31. package/dist/cli/cli.js.map +1 -1
  32. package/dist/gateway-BiHRHJMM.d.mts +314 -0
  33. package/dist/gateway-BiHRHJMM.d.ts +314 -0
  34. package/dist/index.d.mts +11 -309
  35. package/dist/index.d.ts +11 -309
  36. package/dist/index.js +400 -155
  37. package/dist/index.js.map +1 -1
  38. package/dist/index.mjs +86 -11874
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/management/management.js +39535 -0
  41. package/dist/management/management.js.map +1 -0
  42. package/dist/management/management.mjs +16 -0
  43. package/dist/management/management.mjs.map +1 -0
  44. package/dist/{chunk-BIPELT57.mjs → modals/chat-modal/chat-modal.js} +16818 -20860
  45. package/dist/modals/chat-modal/chat-modal.js.map +1 -0
  46. package/dist/modals/chat-modal/chat-modal.mjs +19 -0
  47. package/dist/modals/chat-modal/chat-modal.mjs.map +1 -0
  48. package/dist/{modelStore-Y3LZWRQC.mjs → modelStore-UMJBDSEF.mjs} +2 -2
  49. package/dist/modelStore-UMJBDSEF.mjs.map +1 -0
  50. package/dist/public-types.d.mts +32 -0
  51. package/dist/public-types.d.ts +32 -0
  52. package/docs/01_quickstart.md +9 -6
  53. package/docs/02_gateway_api.md +55 -12
  54. package/docs/04_local_dev.md +1 -1
  55. package/docs/api_reference/assets/navigation.js +1 -1
  56. package/docs/api_reference/assets/search.js +1 -1
  57. package/docs/api_reference/classes/DebugLogger.html +11 -11
  58. package/docs/api_reference/classes/FeatureFlagService.html +13 -13
  59. package/docs/api_reference/classes/NotificationService.html +10 -10
  60. package/docs/api_reference/classes/StreamingTTSClient.html +9 -9
  61. package/docs/api_reference/classes/VectorDatabaseService.html +24 -24
  62. package/docs/api_reference/classes/VectorMigrationService.html +8 -8
  63. package/docs/api_reference/classes/VoiceService.html +2 -2
  64. package/docs/api_reference/enums/TTSState.html +2 -2
  65. package/docs/api_reference/functions/Chat.html +1 -1
  66. package/docs/api_reference/functions/ChatModal.html +4 -4
  67. package/docs/api_reference/functions/ChatProvider.html +1 -1
  68. package/docs/api_reference/functions/FeatureFlagProvider.html +1 -1
  69. package/docs/api_reference/functions/FeedbackButton.html +1 -1
  70. package/docs/api_reference/functions/FeedbackModal.html +1 -1
  71. package/docs/api_reference/functions/Management.html +1 -1
  72. package/docs/api_reference/functions/NotificationProvider.html +1 -1
  73. package/docs/api_reference/functions/SubscriptionExpiredGuard.html +1 -1
  74. package/docs/api_reference/functions/SubscriptionExpiredModal.html +1 -1
  75. package/docs/api_reference/functions/defineCustomElement.html +1 -1
  76. package/docs/api_reference/functions/getCriticalConfig.html +1 -1
  77. package/docs/api_reference/functions/getFeatureMatrix.html +1 -1
  78. package/docs/api_reference/functions/getStreamingTTSClient.html +1 -1
  79. package/docs/api_reference/functions/getSystemConstants.html +1 -1
  80. package/docs/api_reference/functions/getTTSState.html +1 -1
  81. package/docs/api_reference/functions/handleHttpError.html +1 -1
  82. package/docs/api_reference/functions/handleSubscriptionUpgrade.html +1 -1
  83. package/docs/api_reference/functions/handleValidationError.html +1 -1
  84. package/docs/api_reference/functions/initializeCoreSystem.html +1 -1
  85. package/docs/api_reference/functions/pauseTTS.html +1 -1
  86. package/docs/api_reference/functions/previewTierUpgrade.html +1 -1
  87. package/docs/api_reference/functions/resumeTTS.html +1 -1
  88. package/docs/api_reference/functions/showInfoNotification.html +1 -1
  89. package/docs/api_reference/functions/showSuccessNotification.html +1 -1
  90. package/docs/api_reference/functions/speakWithStreaming.html +1 -1
  91. package/docs/api_reference/functions/stopTTS.html +1 -1
  92. package/docs/api_reference/functions/syncSubscriptionWithAPI.html +1 -1
  93. package/docs/api_reference/functions/updateSubscriptionTier.html +1 -1
  94. package/docs/api_reference/functions/useFeatureFlag.html +1 -1
  95. package/docs/api_reference/functions/useFeatureVisibility.html +1 -1
  96. package/docs/api_reference/functions/useFeatures.html +1 -1
  97. package/docs/api_reference/functions/useGatewayHealth.html +1 -1
  98. package/docs/api_reference/functions/useGatewayMemory.html +1 -1
  99. package/docs/api_reference/functions/useGatewayModels.html +1 -1
  100. package/docs/api_reference/functions/useGlobalTTS.html +1 -1
  101. package/docs/api_reference/functions/useNotification.html +1 -1
  102. package/docs/api_reference/functions/useNotificationService.html +1 -1
  103. package/docs/api_reference/functions/useTTS.html +1 -1
  104. package/docs/api_reference/functions/useVectorStore.html +1 -1
  105. package/docs/api_reference/functions/useVoiceStore.html +2 -2
  106. package/docs/api_reference/functions/useVoices.html +1 -1
  107. package/docs/api_reference/functions/validateEnvironment.html +1 -1
  108. package/docs/api_reference/functions/validateSystemIntegrity.html +1 -1
  109. package/docs/api_reference/index.html +130 -40
  110. package/docs/api_reference/interfaces/AIChatRequest.html +2 -2
  111. package/docs/api_reference/interfaces/AIChatResponse.html +2 -2
  112. package/docs/api_reference/interfaces/AIGenerateRequest.html +2 -2
  113. package/docs/api_reference/interfaces/AIGenerateResponse.html +2 -2
  114. package/docs/api_reference/interfaces/AIMessage.html +2 -2
  115. package/docs/api_reference/interfaces/AIModel.html +2 -2
  116. package/docs/api_reference/interfaces/AIProviderConfig.html +2 -2
  117. package/docs/api_reference/interfaces/ChatConfig.html +3 -3
  118. package/docs/api_reference/interfaces/ChatModalProps.html +7 -0
  119. package/docs/api_reference/interfaces/CreateMemoryOptions.html +2 -2
  120. package/docs/api_reference/interfaces/FeatureEvaluation.html +7 -7
  121. package/docs/api_reference/interfaces/FeatureFlagConfig.html +9 -9
  122. package/docs/api_reference/interfaces/FeatureFlagContextValue.html +8 -8
  123. package/docs/api_reference/interfaces/FeatureFlagProviderProps.html +2 -2
  124. package/docs/api_reference/interfaces/FeedbackButtonProps.html +10 -10
  125. package/docs/api_reference/interfaces/FeedbackCategories.html +2 -2
  126. package/docs/api_reference/interfaces/FeedbackModalProps.html +2 -2
  127. package/docs/api_reference/interfaces/FeedbackPriorities.html +2 -2
  128. package/docs/api_reference/interfaces/FeedbackRequest.html +2 -2
  129. package/docs/api_reference/interfaces/FeedbackResponse.html +2 -2
  130. package/docs/api_reference/interfaces/FileUploadResult.html +2 -2
  131. package/docs/api_reference/interfaces/GatewayChatRequest.html +2 -2
  132. package/docs/api_reference/interfaces/GatewayChatResponse.html +2 -2
  133. package/docs/api_reference/interfaces/GatewayContract.html +2 -2
  134. package/docs/api_reference/interfaces/GatewayGenerateRequest.html +2 -2
  135. package/docs/api_reference/interfaces/GatewayGenerateResponse.html +2 -2
  136. package/docs/api_reference/interfaces/GatewayHealthResponse.html +2 -2
  137. package/docs/api_reference/interfaces/GatewayMemoryRecord.html +2 -2
  138. package/docs/api_reference/interfaces/GatewayMemoryResponse.html +2 -2
  139. package/docs/api_reference/interfaces/GatewayMessage.html +2 -2
  140. package/docs/api_reference/interfaces/GatewayMessageContent.html +2 -2
  141. package/docs/api_reference/interfaces/GatewayModel.html +2 -2
  142. package/docs/api_reference/interfaces/GatewayModelsResponse.html +2 -2
  143. package/docs/api_reference/interfaces/MemorySearchFilters.html +2 -2
  144. package/docs/api_reference/interfaces/MigrationProgress.html +2 -2
  145. package/docs/api_reference/interfaces/MigrationStatus.html +2 -2
  146. package/docs/api_reference/interfaces/NotificationConfig.html +2 -2
  147. package/docs/api_reference/interfaces/NotificationContextType.html +2 -2
  148. package/docs/api_reference/interfaces/NotificationProviderProps.html +2 -2
  149. package/docs/api_reference/interfaces/PackageSettings.html +5 -3
  150. package/docs/api_reference/interfaces/SearchOptions.html +2 -2
  151. package/docs/api_reference/interfaces/SearchResult.html +2 -2
  152. package/docs/api_reference/interfaces/SubscriptionExpiredGuardProps.html +2 -2
  153. package/docs/api_reference/interfaces/SubscriptionExpiredModalProps.html +2 -2
  154. package/docs/api_reference/interfaces/TTSOptions.html +2 -2
  155. package/docs/api_reference/interfaces/TTSProgress.html +2 -2
  156. package/docs/api_reference/interfaces/TrialUsage.html +2 -2
  157. package/docs/api_reference/interfaces/UploadRequest.html +3 -3
  158. package/docs/api_reference/interfaces/UseTTSReturn.html +2 -2
  159. package/docs/api_reference/interfaces/VectorDocument.html +2 -2
  160. package/docs/api_reference/interfaces/VectorMemory.html +2 -2
  161. package/docs/api_reference/interfaces/VectorMemoryMetadata.html +2 -2
  162. package/docs/api_reference/interfaces/VectorStoreStatus.html +2 -2
  163. package/docs/api_reference/interfaces/VoiceModelsResponse.html +2 -2
  164. package/docs/api_reference/interfaces/VoiceState.html +2 -2
  165. package/docs/api_reference/media/02_gateway_api.md +55 -12
  166. package/docs/api_reference/media/LICENSE +2 -2
  167. package/docs/api_reference/media/PROTECTION-README.md +6 -8
  168. package/docs/api_reference/media/README.md +37 -9
  169. package/docs/api_reference/modules.html +1 -0
  170. package/docs/api_reference/types/FeatureKey.html +1 -1
  171. package/docs/api_reference/types/FeatureMatrix.html +1 -1
  172. package/docs/api_reference/types/GatewayQueryOptions.html +1 -1
  173. package/docs/api_reference/types/LogContext.html +1 -1
  174. package/docs/api_reference/types/SubscriptionTier.html +1 -1
  175. package/docs/api_reference/variables/DEFAULT_TIER_FEATURES.html +1 -1
  176. package/docs/api_reference/variables/FeatureFlagContext.html +1 -1
  177. package/docs/api_reference/variables/OSS_DEFAULT_FEATURES.html +1 -1
  178. package/docs/api_reference/variables/SYSTEM_FLAGS.html +1 -1
  179. package/docs/api_reference/variables/authenticationService.html +1 -1
  180. package/docs/api_reference/variables/debugLogger-1.html +1 -1
  181. package/docs/api_reference/variables/featureFlagService-1.html +1 -1
  182. package/docs/api_reference/variables/notificationService-1.html +1 -1
  183. package/docs/api_reference/variables/vectorDatabaseService-1.html +1 -1
  184. package/docs/api_reference/variables/vectorMigrationService-1.html +1 -1
  185. package/docs/api_reference/variables/voiceService-1.html +1 -1
  186. package/package.json +24 -13
  187. package/dist/chat-QXB526NZ.mjs +0 -11
  188. package/dist/chunk-AVC6IZJQ.mjs.map +0 -1
  189. package/dist/chunk-BIPELT57.mjs.map +0 -1
  190. package/docs/api_reference/media/README-1.md +0 -23
  191. /package/dist/{aiProviderStore-YWJHSWFA.mjs.map → aiProviderStore-3YS2BZU3.mjs.map} +0 -0
  192. /package/dist/{chat-QXB526NZ.mjs.map → chat-ZPJNWIXI.mjs.map} +0 -0
  193. /package/dist/{modelStore-Y3LZWRQC.mjs.map → chat-provider.mjs.map} +0 -0
package/dist/index.js CHANGED
@@ -5387,6 +5387,185 @@ var init_gateway_provider = __esm({
5387
5387
  }
5388
5388
  });
5389
5389
 
5390
+ // src/services/ai-provider/providers/playground.provider.ts
5391
+ var import_rxjs8, PLAYGROUND_MODELS, PLAYGROUND_CONVERSATION_STARTERS, PLAYGROUND_SCRIPTS, FALLBACK_RESPONSE, STREAM_DELAY_MS, PlaygroundProvider;
5392
+ var init_playground_provider = __esm({
5393
+ "src/services/ai-provider/providers/playground.provider.ts"() {
5394
+ "use strict";
5395
+ import_rxjs8 = require("rxjs");
5396
+ init_common_types();
5397
+ PLAYGROUND_MODELS = [
5398
+ {
5399
+ name: "bandit-playground",
5400
+ details: {
5401
+ format: "chat",
5402
+ family: "bandit",
5403
+ families: ["bandit", "demo"],
5404
+ parameter_size: "demo",
5405
+ quantization_level: "synthetic"
5406
+ },
5407
+ digest: "playground-demo-001",
5408
+ modified_at: (/* @__PURE__ */ new Date()).toISOString()
5409
+ },
5410
+ {
5411
+ name: "bandit-starter",
5412
+ details: {
5413
+ format: "chat",
5414
+ family: "bandit",
5415
+ families: ["bandit", "demo"],
5416
+ parameter_size: "demo",
5417
+ quantization_level: "synthetic"
5418
+ },
5419
+ digest: "playground-demo-002",
5420
+ modified_at: (/* @__PURE__ */ new Date()).toISOString()
5421
+ }
5422
+ ];
5423
+ PLAYGROUND_CONVERSATION_STARTERS = [
5424
+ "What can I build with Bandit Engine if my backend is not ready yet?",
5425
+ "How does the gateway contract keep API keys out of the browser?",
5426
+ "Can I theme the chat UI to match my product brand?",
5427
+ "How do I switch between Ollama and OpenAI without redeploying the frontend?",
5428
+ "Show me how the management console handles personas and models."
5429
+ ];
5430
+ PLAYGROUND_SCRIPTS = [
5431
+ {
5432
+ match: (input) => /model|switch|personas|management/i.test(input),
5433
+ response: [
5434
+ "Absolutely \u2014 the management console ships with live model switching, persona editing, and feature toggles.",
5435
+ "",
5436
+ "- Use the **Models** tab to expose whichever gateway-backed models you want customers to see.",
5437
+ "- Personas hydrate the chat with branded system prompts, voice preferences, and avatars.",
5438
+ "- Everything persists through the gateway, so you can roll out changes without shipping a new build."
5439
+ ].join("\n")
5440
+ },
5441
+ {
5442
+ match: (input) => /gateway|api|contract|backend/i.test(input),
5443
+ response: [
5444
+ "The gateway contract keeps secrets on the server while giving the UI a unified AI API.",
5445
+ "",
5446
+ "Key highlights:",
5447
+ "1. `/api/chat/completions` is the default OpenAI-format endpoint when no provider override is set.",
5448
+ "2. `/api/{provider}/chat/completions` handles OpenAI, Azure OpenAI, and Anthropic while `/api/ollama/chat` streams Ollama responses.",
5449
+ "3. The contract is language-agnostic \u2014 Express, FastAPI, .NET, Go\u2026 anything works as long as it speaks HTTP."
5450
+ ].join("\n")
5451
+ },
5452
+ {
5453
+ match: (input) => /style|theme|brand|ui/i.test(input),
5454
+ response: [
5455
+ "Every surface in Bandit Engine is themeable.",
5456
+ "",
5457
+ "- Drop a JSON config into your `public/` folder (or host it on a CDN) to control themes, logos, and accent colors.",
5458
+ "- The React components expose hooks for custom headers, menus, and call-to-action buttons.",
5459
+ "- Need a modal? `ChatModal` reuses the same store, so the handoff between embedded chat and floating assistant stays seamless."
5460
+ ].join("\n")
5461
+ },
5462
+ {
5463
+ match: (input) => /voice|tts|audio/i.test(input),
5464
+ response: [
5465
+ "Voice is opt-in, but the plumbing is ready.",
5466
+ "",
5467
+ "- Configure `/api/tts` and `/api/stt` on the gateway to unlock the speak/listen controls.",
5468
+ "- The UI lazily loads voices and respects feature flags, so you can leave it disabled in the playground.",
5469
+ "- Everything streams \u2014 the assistant starts speaking before the full response lands."
5470
+ ].join("\n")
5471
+ },
5472
+ {
5473
+ match: (input) => /deploy|production|secure/i.test(input),
5474
+ response: [
5475
+ "Production hardening is front and center.",
5476
+ "",
5477
+ "- Gateway tokens ride in the `Authorization` header; rotate them server-side without touching the bundle.",
5478
+ "- Feature flags gate premium surfaces, letting you trial the UI before wiring billing.",
5479
+ "- Vector search, knowledge, and memories are isolated behind `/api/embedding/*` so you can plug in your own storage policies."
5480
+ ].join("\n")
5481
+ }
5482
+ ];
5483
+ FALLBACK_RESPONSE = [
5484
+ "Bandit Engine is running in playground mode. I'm simulating how streaming works so you can explore the UX without connecting a live model.",
5485
+ "",
5486
+ "Try asking about the gateway contract, theming, voice features, or model management to see tailored walkthroughs."
5487
+ ].join("\n");
5488
+ STREAM_DELAY_MS = 350;
5489
+ PlaygroundProvider = class {
5490
+ config;
5491
+ constructor(config) {
5492
+ this.config = { type: "playground" /* PLAYGROUND */, ...config };
5493
+ }
5494
+ chat(request) {
5495
+ const lastUserMessage = [...request.messages].reverse().find((m) => m.role === "user")?.content ?? "";
5496
+ const script = PLAYGROUND_SCRIPTS.find(
5497
+ (scenario) => scenario.match(lastUserMessage)
5498
+ );
5499
+ const responseText = script?.response ?? FALLBACK_RESPONSE;
5500
+ const chunks = this.splitIntoChunks(responseText);
5501
+ return new import_rxjs8.Observable((observer) => {
5502
+ let index = 0;
5503
+ const emitChunk = () => {
5504
+ if (index >= chunks.length) {
5505
+ observer.complete();
5506
+ return;
5507
+ }
5508
+ const chunk = chunks[index];
5509
+ observer.next({
5510
+ message: {
5511
+ content: chunk,
5512
+ role: "assistant"
5513
+ },
5514
+ done: index === chunks.length - 1
5515
+ });
5516
+ index += 1;
5517
+ setTimeout(emitChunk, STREAM_DELAY_MS);
5518
+ };
5519
+ emitChunk();
5520
+ return () => {
5521
+ index = chunks.length;
5522
+ };
5523
+ });
5524
+ }
5525
+ generate(_request) {
5526
+ const starters = PLAYGROUND_CONVERSATION_STARTERS.join("\n");
5527
+ return new import_rxjs8.Observable((observer) => {
5528
+ observer.next({
5529
+ response: starters,
5530
+ done: true
5531
+ });
5532
+ observer.complete();
5533
+ });
5534
+ }
5535
+ listModels() {
5536
+ return new import_rxjs8.Observable((observer) => {
5537
+ observer.next(PLAYGROUND_MODELS);
5538
+ observer.complete();
5539
+ });
5540
+ }
5541
+ async validateServiceAvailability(args) {
5542
+ const simulatedUrl = this.config.baseUrl ?? "playground://local";
5543
+ if (args.timeoutMs > 0) {
5544
+ await new Promise((resolve) => setTimeout(resolve, Math.min(args.timeoutMs, 250)));
5545
+ }
5546
+ return {
5547
+ url: simulatedUrl,
5548
+ isAvailable: true
5549
+ };
5550
+ }
5551
+ getProviderType() {
5552
+ return "playground" /* PLAYGROUND */;
5553
+ }
5554
+ getConfig() {
5555
+ return this.config;
5556
+ }
5557
+ splitIntoChunks(response) {
5558
+ const paragraphs = response.split("\n\n").map((p) => p.trim()).filter(Boolean);
5559
+ if (paragraphs.length <= 1) {
5560
+ const sentences = response.split(/(?<=[.!?])\s+/).filter(Boolean);
5561
+ return sentences.length > 0 ? sentences : [response];
5562
+ }
5563
+ return paragraphs;
5564
+ }
5565
+ };
5566
+ }
5567
+ });
5568
+
5390
5569
  // src/services/ai-provider/ai-provider.factory.ts
5391
5570
  var AIProviderFactory;
5392
5571
  var init_ai_provider_factory = __esm({
@@ -5398,6 +5577,7 @@ var init_ai_provider_factory = __esm({
5398
5577
  init_azure_openai_provider();
5399
5578
  init_anthropic_provider();
5400
5579
  init_gateway_provider();
5580
+ init_playground_provider();
5401
5581
  AIProviderFactory = class {
5402
5582
  static createProvider(config) {
5403
5583
  switch (config.type) {
@@ -5411,6 +5591,8 @@ var init_ai_provider_factory = __esm({
5411
5591
  return new AnthropicProvider(config);
5412
5592
  case "gateway" /* GATEWAY */:
5413
5593
  return new GatewayProvider(config);
5594
+ case "playground" /* PLAYGROUND */:
5595
+ return new PlaygroundProvider(config);
5414
5596
  default:
5415
5597
  throw new Error(`Unsupported AI provider type: ${config.type}`);
5416
5598
  }
@@ -5421,7 +5603,8 @@ var init_ai_provider_factory = __esm({
5421
5603
  "openai" /* OPENAI */,
5422
5604
  "azure-openai" /* AZURE_OPENAI */,
5423
5605
  "anthropic" /* ANTHROPIC */,
5424
- "gateway" /* GATEWAY */
5606
+ "gateway" /* GATEWAY */,
5607
+ "playground" /* PLAYGROUND */
5425
5608
  ];
5426
5609
  }
5427
5610
  static validateConfig(config) {
@@ -5437,6 +5620,8 @@ var init_ai_provider_factory = __esm({
5437
5620
  return !!config.apiKey;
5438
5621
  case "gateway" /* GATEWAY */:
5439
5622
  return !!(config.gatewayUrl && config.provider);
5623
+ case "playground" /* PLAYGROUND */:
5624
+ return true;
5440
5625
  default:
5441
5626
  return false;
5442
5627
  }
@@ -5791,11 +5976,11 @@ var init_notificationService = __esm({
5791
5976
  });
5792
5977
 
5793
5978
  // src/services/prompts/conversationStarters.ts
5794
- var import_rxjs8, generateConversationStarters;
5979
+ var import_rxjs9, generateConversationStarters;
5795
5980
  var init_conversationStarters = __esm({
5796
5981
  "src/services/prompts/conversationStarters.ts"() {
5797
5982
  "use strict";
5798
- import_rxjs8 = require("rxjs");
5983
+ import_rxjs9 = require("rxjs");
5799
5984
  init_aiProviderStore();
5800
5985
  init_packageSettingsStore();
5801
5986
  init_getStableQuestionPrompt();
@@ -5816,13 +6001,13 @@ var init_conversationStarters = __esm({
5816
6001
  stream: false,
5817
6002
  options: { temperature: 1.5, num_predict: 250 }
5818
6003
  });
5819
- const questions$ = data$.pipe((0, import_rxjs8.map)((d) => {
6004
+ const questions$ = data$.pipe((0, import_rxjs9.map)((d) => {
5820
6005
  const lines = d.response.split("\n").map((line) => line.trim()).filter((line) => {
5821
6006
  return line.length > 10 && !line.toLowerCase().includes("sorry") && !line.toLowerCase().includes("i cannot") && !line.toLowerCase().includes("i can't") && !line.toLowerCase().includes("unable to") && !line.toLowerCase().startsWith("as an ai") && line.includes("?");
5822
6007
  });
5823
6008
  return lines;
5824
6009
  }));
5825
- const starters = await (0, import_rxjs8.lastValueFrom)(questions$);
6010
+ const starters = await (0, import_rxjs9.lastValueFrom)(questions$);
5826
6011
  if (starters.length === 0) {
5827
6012
  debugLogger.warn("No meaningful conversation starters generated");
5828
6013
  return [];
@@ -5838,11 +6023,11 @@ var init_conversationStarters = __esm({
5838
6023
  });
5839
6024
 
5840
6025
  // src/services/prompts/moodDetection.ts
5841
- var import_rxjs9, detectMessageMood;
6026
+ var import_rxjs10, detectMessageMood;
5842
6027
  var init_moodDetection = __esm({
5843
6028
  "src/services/prompts/moodDetection.ts"() {
5844
6029
  "use strict";
5845
- import_rxjs9 = require("rxjs");
6030
+ import_rxjs10 = require("rxjs");
5846
6031
  init_aiProviderStore();
5847
6032
  init_packageSettingsStore();
5848
6033
  init_debugLogger();
@@ -5873,8 +6058,8 @@ Response:`;
5873
6058
  options: { temperature: 0.3, num_predict: 10 }
5874
6059
  });
5875
6060
  const chunks$ = response$.pipe(
5876
- (0, import_rxjs9.map)((chunk) => chunk.response.trim().toLowerCase()),
5877
- (0, import_rxjs9.toArray)()
6061
+ (0, import_rxjs10.map)((chunk) => chunk.response.trim().toLowerCase()),
6062
+ (0, import_rxjs10.toArray)()
5878
6063
  );
5879
6064
  const result = await chunks$.toPromise();
5880
6065
  const finalResult = (result || []).join("").trim();
@@ -5891,11 +6076,11 @@ Response:`;
5891
6076
  });
5892
6077
 
5893
6078
  // src/services/prompts/detectUserInterestAndExcitement.ts
5894
- var import_rxjs10, detectUserInterestAndExcitement;
6079
+ var import_rxjs11, detectUserInterestAndExcitement;
5895
6080
  var init_detectUserInterestAndExcitement = __esm({
5896
6081
  "src/services/prompts/detectUserInterestAndExcitement.ts"() {
5897
6082
  "use strict";
5898
- import_rxjs10 = require("rxjs");
6083
+ import_rxjs11 = require("rxjs");
5899
6084
  init_aiProviderStore();
5900
6085
  init_packageSettingsStore();
5901
6086
  init_debugLogger();
@@ -5942,10 +6127,10 @@ var init_detectUserInterestAndExcitement = __esm({
5942
6127
  options: { temperature: 0.1, num_predict: 5 }
5943
6128
  });
5944
6129
  const chunks$ = response$.pipe(
5945
- (0, import_rxjs10.map)((chunk) => chunk.response.trim().toUpperCase()),
5946
- (0, import_rxjs10.toArray)()
6130
+ (0, import_rxjs11.map)((chunk) => chunk.response.trim().toUpperCase()),
6131
+ (0, import_rxjs11.toArray)()
5947
6132
  );
5948
- const result = await (0, import_rxjs10.lastValueFrom)(chunks$);
6133
+ const result = await (0, import_rxjs11.lastValueFrom)(chunks$);
5949
6134
  const decision = result.join("").trim();
5950
6135
  debugLogger.llmDebug("detectUserInterestAndExcitement result", { decision });
5951
6136
  return decision.includes("YES");
@@ -5958,11 +6143,11 @@ var init_detectUserInterestAndExcitement = __esm({
5958
6143
  });
5959
6144
 
5960
6145
  // src/services/prompts/documentSummarization.ts
5961
- var import_rxjs11, summarizeDocument;
6146
+ var import_rxjs12, summarizeDocument;
5962
6147
  var init_documentSummarization = __esm({
5963
6148
  "src/services/prompts/documentSummarization.ts"() {
5964
6149
  "use strict";
5965
- import_rxjs11 = require("rxjs");
6150
+ import_rxjs12 = require("rxjs");
5966
6151
  init_aiProviderStore();
5967
6152
  init_packageSettingsStore();
5968
6153
  init_debugLogger();
@@ -5990,8 +6175,8 @@ ${content.slice(0, 4e3)}
5990
6175
  stream: false,
5991
6176
  options: { temperature: 0.3, num_predict: 100 }
5992
6177
  });
5993
- const summary$ = data$.pipe((0, import_rxjs11.map)((d) => d.response.trim()));
5994
- const summary = await (0, import_rxjs11.lastValueFrom)(summary$);
6178
+ const summary$ = data$.pipe((0, import_rxjs12.map)((d) => d.response.trim()));
6179
+ const summary = await (0, import_rxjs12.lastValueFrom)(summary$);
5995
6180
  debugLogger.ragDebug("summarizeDocument result", { name, summary });
5996
6181
  return summary || `Document summary for ${name}`;
5997
6182
  } catch (error) {
@@ -6003,11 +6188,11 @@ ${content.slice(0, 4e3)}
6003
6188
  });
6004
6189
 
6005
6190
  // src/services/prompts/documentRelevance.ts
6006
- var import_rxjs12, determineRelevantDocuments;
6191
+ var import_rxjs13, determineRelevantDocuments;
6007
6192
  var init_documentRelevance = __esm({
6008
6193
  "src/services/prompts/documentRelevance.ts"() {
6009
6194
  "use strict";
6010
- import_rxjs12 = require("rxjs");
6195
+ import_rxjs13 = require("rxjs");
6011
6196
  init_aiProviderStore();
6012
6197
  init_packageSettingsStore();
6013
6198
  init_debugLogger();
@@ -6048,10 +6233,10 @@ Response:`;
6048
6233
  options: { temperature: 0.2, num_predict: 50 }
6049
6234
  });
6050
6235
  const chunks$ = response$.pipe(
6051
- (0, import_rxjs12.map)((chunk) => chunk.response.trim()),
6052
- (0, import_rxjs12.toArray)()
6236
+ (0, import_rxjs13.map)((chunk) => chunk.response.trim()),
6237
+ (0, import_rxjs13.toArray)()
6053
6238
  );
6054
- const result = await (0, import_rxjs12.lastValueFrom)(chunks$);
6239
+ const result = await (0, import_rxjs13.lastValueFrom)(chunks$);
6055
6240
  const vetResult = result.join("").trim().toLowerCase();
6056
6241
  debugLogger.ragDebug("determineRelevantDocuments result", { vetResult });
6057
6242
  if (vetResult.includes("none") || !vetResult) {
@@ -6513,16 +6698,16 @@ var init_vectorDatabaseService = __esm({
6513
6698
  init_debugLogger();
6514
6699
  VectorDatabaseService = class {
6515
6700
  baseUrl;
6516
- s3ApiUrl;
6701
+ fileStorageApiUrl;
6517
6702
  token = null;
6518
6703
  lastAvailabilityState;
6519
6704
  lastConfigState;
6520
- constructor(gatewayApiUrl, s3ApiUrl) {
6705
+ constructor(gatewayApiUrl, fileStorageApiUrl) {
6521
6706
  this.baseUrl = gatewayApiUrl || "https://localhost:5001/api";
6522
- this.s3ApiUrl = s3ApiUrl || "https://localhost:5001/api";
6707
+ this.fileStorageApiUrl = fileStorageApiUrl || "https://localhost:5001/api";
6523
6708
  debugLogger.info("Vector database service initialized", {
6524
6709
  baseUrl: this.baseUrl,
6525
- s3ApiUrl: this.s3ApiUrl,
6710
+ fileStorageApiUrl: this.fileStorageApiUrl,
6526
6711
  hasToken: Boolean(this.token)
6527
6712
  });
6528
6713
  }
@@ -6548,11 +6733,11 @@ var init_vectorDatabaseService = __esm({
6548
6733
  * Check if vector database is available and configured
6549
6734
  */
6550
6735
  isAvailable() {
6551
- const available = !!(this.baseUrl && this.s3ApiUrl && this.token);
6736
+ const available = !!(this.baseUrl && this.fileStorageApiUrl && this.token);
6552
6737
  if (this.lastAvailabilityState !== available) {
6553
6738
  debugLogger.debug("Vector service availability check", {
6554
6739
  baseUrl: this.baseUrl,
6555
- s3ApiUrl: this.s3ApiUrl,
6740
+ fileStorageApiUrl: this.fileStorageApiUrl,
6556
6741
  hasToken: Boolean(this.token),
6557
6742
  available
6558
6743
  });
@@ -7052,7 +7237,7 @@ var init_vectorDatabaseService = __esm({
7052
7237
  }
7053
7238
  // ===== DOCUMENT OPERATIONS =====
7054
7239
  /**
7055
- * Upload file to S3 API and get file ID
7240
+ * Upload file to file storage API and get file ID
7056
7241
  *
7057
7242
  * @param file - The file to upload
7058
7243
  * @param shareWithTeam - Whether to share the file with team members.
@@ -7062,8 +7247,8 @@ var init_vectorDatabaseService = __esm({
7062
7247
  * @returns Promise<FileUploadResult> with success status and file ID
7063
7248
  */
7064
7249
  async uploadFile(file, shareWithTeam = true) {
7065
- if (!this.s3ApiUrl) {
7066
- throw new Error("S3 API URL not configured");
7250
+ if (!this.fileStorageApiUrl) {
7251
+ throw new Error("File storage API URL not configured");
7067
7252
  }
7068
7253
  if (!this.token) {
7069
7254
  throw new Error("Authentication token not available");
@@ -7072,14 +7257,14 @@ var init_vectorDatabaseService = __esm({
7072
7257
  const formData = new FormData();
7073
7258
  formData.append("file", file);
7074
7259
  formData.append("shareWithTeam", shareWithTeam.toString());
7075
- debugLogger.info("Uploading file to S3 API", {
7260
+ debugLogger.info("Uploading file to file storage API", {
7076
7261
  filename: file.name,
7077
7262
  size: file.size,
7078
7263
  type: file.type,
7079
7264
  shareWithTeam,
7080
- s3ApiUrl: this.s3ApiUrl
7265
+ fileStorageApiUrl: this.fileStorageApiUrl
7081
7266
  });
7082
- const response = await fetch(`${this.s3ApiUrl}/file/upload`, {
7267
+ const response = await fetch(`${this.fileStorageApiUrl}/file/upload`, {
7083
7268
  method: "POST",
7084
7269
  headers: {
7085
7270
  "Authorization": `Bearer ${this.token}`
@@ -7088,13 +7273,13 @@ var init_vectorDatabaseService = __esm({
7088
7273
  });
7089
7274
  if (!response.ok) {
7090
7275
  const errorData = await response.json().catch(() => ({}));
7091
- throw new Error(errorData.message || `S3 upload failed: ${response.status}`);
7276
+ throw new Error(errorData.message || `file storage upload failed: ${response.status}`);
7092
7277
  }
7093
7278
  const result = await response.json();
7094
7279
  const fileId = result.fileId || result.id;
7095
- debugLogger.debug("S3 upload response", result);
7280
+ debugLogger.debug("File storage API upload response", result);
7096
7281
  debugLogger.debug("Extracted vector file id", { fileId });
7097
- debugLogger.info("File uploaded successfully to S3", {
7282
+ debugLogger.info("File uploaded successfully to file storage", {
7098
7283
  fileId,
7099
7284
  filename: file.name,
7100
7285
  originalResponse: result
@@ -7105,8 +7290,8 @@ var init_vectorDatabaseService = __esm({
7105
7290
  message: result.message
7106
7291
  };
7107
7292
  } catch (error) {
7108
- debugLogger.error("Failed to upload file to S3", { error });
7109
- throw new Error(`S3 file upload failed: ${error instanceof Error ? error.message : String(error)}`);
7293
+ debugLogger.error("Failed to upload file to file storage", { error });
7294
+ throw new Error(`File storage upload failed: ${error instanceof Error ? error.message : String(error)}`);
7110
7295
  }
7111
7296
  }
7112
7297
  /**
@@ -7270,7 +7455,7 @@ var init_vectorDatabaseService = __esm({
7270
7455
  }
7271
7456
  }
7272
7457
  /**
7273
- * Get user's files - tries both Gateway API and S3 API
7458
+ * Get user's files - tries both Gateway API and file storage API
7274
7459
  */
7275
7460
  async getUserFiles(skip = 0, limit = 50) {
7276
7461
  if (!this.isAvailable()) {
@@ -7283,10 +7468,10 @@ var init_vectorDatabaseService = __esm({
7283
7468
  headers: this.getHeaders()
7284
7469
  });
7285
7470
  if (!response.ok) {
7286
- debugLogger.warn("Gateway API files endpoint failed, falling back to S3 API", {
7471
+ debugLogger.warn("Gateway API files endpoint failed, falling back to file storage API", {
7287
7472
  status: response.status
7288
7473
  });
7289
- return await this.getUserFilesFromS3(skip, limit);
7474
+ return await this.getUserFilesFromFileStorage(skip, limit);
7290
7475
  }
7291
7476
  const result = await response.json();
7292
7477
  debugLogger.debug("Gateway API files response", result);
@@ -7298,17 +7483,17 @@ var init_vectorDatabaseService = __esm({
7298
7483
  }
7299
7484
  return [];
7300
7485
  } catch (error) {
7301
- debugLogger.error("Gateway API failed while fetching user files, trying S3 API", { error });
7302
- return await this.getUserFilesFromS3(skip, limit);
7486
+ debugLogger.error("Gateway API failed while fetching user files, trying file storage API", { error });
7487
+ return await this.getUserFilesFromFileStorage(skip, limit);
7303
7488
  }
7304
7489
  }
7305
7490
  /**
7306
- * Get user's files from S3 API as fallback
7491
+ * Get user's files from file storage API as fallback
7307
7492
  */
7308
- async getUserFilesFromS3(skip = 0, limit = 50) {
7493
+ async getUserFilesFromFileStorage(skip = 0, limit = 50) {
7309
7494
  try {
7310
- debugLogger.debug("Fetching user files from S3 API", { skip, limit });
7311
- const response = await fetch(`${this.s3ApiUrl}/file/files?skip=${skip}&limit=${limit}`, {
7495
+ debugLogger.debug("Fetching user files from file storage API", { skip, limit });
7496
+ const response = await fetch(`${this.fileStorageApiUrl}/file/files?skip=${skip}&limit=${limit}`, {
7312
7497
  method: "GET",
7313
7498
  headers: {
7314
7499
  "Authorization": `Bearer ${this.token}`,
@@ -7316,10 +7501,10 @@ var init_vectorDatabaseService = __esm({
7316
7501
  }
7317
7502
  });
7318
7503
  if (!response.ok) {
7319
- throw new Error(`S3 API failed: ${response.status}`);
7504
+ throw new Error(`File storage API failed: ${response.status}`);
7320
7505
  }
7321
7506
  const result = await response.json();
7322
- debugLogger.debug("S3 API files response", result);
7507
+ debugLogger.debug("File storage API files response", result);
7323
7508
  if (Array.isArray(result)) {
7324
7509
  return this.toRecordArray(result);
7325
7510
  }
@@ -7328,7 +7513,7 @@ var init_vectorDatabaseService = __esm({
7328
7513
  }
7329
7514
  return [];
7330
7515
  } catch (error) {
7331
- debugLogger.error("Failed to fetch user files from S3 API", { error });
7516
+ debugLogger.error("Failed to fetch user files from file storage API", { error });
7332
7517
  return [];
7333
7518
  }
7334
7519
  }
@@ -7341,7 +7526,7 @@ var init_vectorDatabaseService = __esm({
7341
7526
  }
7342
7527
  try {
7343
7528
  debugLogger.debug("Downloading vector file", { fileId, filename });
7344
- const response = await fetch(`${this.s3ApiUrl}/file/download/${fileId}`, {
7529
+ const response = await fetch(`${this.fileStorageApiUrl}/file/download/${fileId}`, {
7345
7530
  method: "GET",
7346
7531
  headers: {
7347
7532
  "Authorization": `Bearer ${this.token}`
@@ -7374,7 +7559,7 @@ var init_vectorDatabaseService = __esm({
7374
7559
  }
7375
7560
  try {
7376
7561
  debugLogger.debug("Fetching vector file blob", { fileId });
7377
- const response = await fetch(`${this.s3ApiUrl}/file/download/${fileId}`, {
7562
+ const response = await fetch(`${this.fileStorageApiUrl}/file/download/${fileId}`, {
7378
7563
  method: "GET",
7379
7564
  headers: {
7380
7565
  "Authorization": `Bearer ${this.token}`
@@ -7486,16 +7671,16 @@ var init_vectorDatabaseService = __esm({
7486
7671
  * Configure the service with API URLs
7487
7672
  * This should be called by the main application with environment variables
7488
7673
  */
7489
- configure(gatewayApiUrl, s3ApiUrl) {
7674
+ configure(gatewayApiUrl, fileStorageApiUrl) {
7490
7675
  this.baseUrl = gatewayApiUrl;
7491
- this.s3ApiUrl = s3ApiUrl;
7492
- if (this.lastConfigState !== `${gatewayApiUrl}|${s3ApiUrl}`) {
7676
+ this.fileStorageApiUrl = fileStorageApiUrl;
7677
+ if (this.lastConfigState !== `${gatewayApiUrl}|${fileStorageApiUrl}`) {
7493
7678
  debugLogger.info("Vector database service configured", {
7494
7679
  baseUrl: this.baseUrl,
7495
- s3ApiUrl: this.s3ApiUrl,
7680
+ fileStorageApiUrl: this.fileStorageApiUrl,
7496
7681
  hasToken: Boolean(this.token)
7497
7682
  });
7498
- this.lastConfigState = `${gatewayApiUrl}|${s3ApiUrl}`;
7683
+ this.lastConfigState = `${gatewayApiUrl}|${fileStorageApiUrl}`;
7499
7684
  }
7500
7685
  }
7501
7686
  /**
@@ -7506,7 +7691,7 @@ var init_vectorDatabaseService = __esm({
7506
7691
  debugLogger.info("Testing Gateway API connection");
7507
7692
  debugLogger.info("Vector service status snapshot", {
7508
7693
  baseUrl: this.baseUrl,
7509
- s3ApiUrl: this.s3ApiUrl,
7694
+ fileStorageApiUrl: this.fileStorageApiUrl,
7510
7695
  hasToken: Boolean(this.token),
7511
7696
  tokenLength: this.token?.length || 0,
7512
7697
  tokenPreview: this.token ? `${this.token.substring(0, 30)}...` : void 0,
@@ -7533,15 +7718,15 @@ var init_vectorDatabaseService = __esm({
7533
7718
  debugLogger.error("Cannot reach Gateway API", { error });
7534
7719
  }
7535
7720
  try {
7536
- debugLogger.debug("Testing S3 API connectivity");
7537
- const files = await this.getUserFilesFromS3(0, 5);
7538
- debugLogger.info("S3 API files response", {
7721
+ debugLogger.debug("Testing file storage API connectivity");
7722
+ const files = await this.getUserFilesFromFileStorage(0, 5);
7723
+ debugLogger.info("File storage API files response", {
7539
7724
  count: files.length,
7540
7725
  files: files.slice(0, 3)
7541
7726
  // Show first 3 files
7542
7727
  });
7543
7728
  } catch (error) {
7544
- debugLogger.error("S3 API test failed", { error });
7729
+ debugLogger.error("File storage API test failed", { error });
7545
7730
  }
7546
7731
  try {
7547
7732
  debugLogger.debug("Testing embedding endpoint availability");
@@ -8627,8 +8812,8 @@ var init_useVectorStore = __esm({
8627
8812
  return;
8628
8813
  }
8629
8814
  const gatewayApiUrl = packageSettings.gatewayApiUrl;
8630
- const s3ApiUrl = packageSettings.s3ApiUrl || packageSettings.gatewayApiUrl;
8631
- vectorDatabaseService.configure(gatewayApiUrl, s3ApiUrl);
8815
+ const fileStorageApiUrl = packageSettings.fileStorageApiUrl || packageSettings.gatewayApiUrl;
8816
+ vectorDatabaseService.configure(gatewayApiUrl, fileStorageApiUrl);
8632
8817
  if (authStore.token) {
8633
8818
  vectorDatabaseService.setAuthToken(authStore.token);
8634
8819
  }
@@ -11439,11 +11624,11 @@ var init_ttsSanitizer = __esm({
11439
11624
  });
11440
11625
 
11441
11626
  // src/services/tts/tts-client.ts
11442
- var import_rxjs13, getOrAppendAuthHeader;
11627
+ var import_rxjs14, getOrAppendAuthHeader;
11443
11628
  var init_tts_client = __esm({
11444
11629
  "src/services/tts/tts-client.ts"() {
11445
11630
  "use strict";
11446
- import_rxjs13 = require("rxjs");
11631
+ import_rxjs14 = require("rxjs");
11447
11632
  init_authenticationService();
11448
11633
  init_voiceStore();
11449
11634
  init_ttsSanitizer();
@@ -11463,11 +11648,11 @@ var init_tts_client = __esm({
11463
11648
  });
11464
11649
 
11465
11650
  // src/services/tts/streaming-tts.ts
11466
- var import_rxjs14, TTSState, StreamingTTSClient, getStreamingTTSClient, speakStream, stopTTS, pauseTTS, resumeTTS, getTTSState;
11651
+ var import_rxjs15, TTSState, StreamingTTSClient, getStreamingTTSClient, speakStream, stopTTS, pauseTTS, resumeTTS, getTTSState;
11467
11652
  var init_streaming_tts = __esm({
11468
11653
  "src/services/tts/streaming-tts.ts"() {
11469
11654
  "use strict";
11470
- import_rxjs14 = require("rxjs");
11655
+ import_rxjs15 = require("rxjs");
11471
11656
  init_debugLogger();
11472
11657
  init_packageSettingsStore();
11473
11658
  init_tts_client();
@@ -11487,8 +11672,8 @@ var init_streaming_tts = __esm({
11487
11672
  // Store event handler references for proper cleanup
11488
11673
  audioHandlers = /* @__PURE__ */ new Map();
11489
11674
  // State management
11490
- stateSubject = new import_rxjs14.BehaviorSubject("IDLE" /* IDLE */);
11491
- progressSubject = new import_rxjs14.Subject();
11675
+ stateSubject = new import_rxjs15.BehaviorSubject("IDLE" /* IDLE */);
11676
+ progressSubject = new import_rxjs15.Subject();
11492
11677
  constructor() {
11493
11678
  }
11494
11679
  static getInstance() {
@@ -11519,7 +11704,7 @@ var init_streaming_tts = __esm({
11519
11704
  * Speak text with simple streaming
11520
11705
  */
11521
11706
  speakStream(text, voice, options = {}) {
11522
- return new import_rxjs14.Observable((subscriber) => {
11707
+ return new import_rxjs15.Observable((subscriber) => {
11523
11708
  this.performSimpleStreaming(text, voice, options, subscriber);
11524
11709
  });
11525
11710
  }
@@ -14048,28 +14233,28 @@ var init_create_audio_blob = __esm({
14048
14233
  });
14049
14234
 
14050
14235
  // src/services/stt/sound-recorder.service.ts
14051
- var import_rxjs15, SoundRecorderService;
14236
+ var import_rxjs16, SoundRecorderService;
14052
14237
  var init_sound_recorder_service = __esm({
14053
14238
  "src/services/stt/sound-recorder.service.ts"() {
14054
14239
  "use strict";
14055
- import_rxjs15 = require("rxjs");
14240
+ import_rxjs16 = require("rxjs");
14056
14241
  init_create_audio_blob();
14057
14242
  SoundRecorderService = class {
14058
14243
  _mediaRecorder;
14059
14244
  start() {
14060
- const mediaStream = (0, import_rxjs15.from)(navigator.mediaDevices.getUserMedia({ audio: true }));
14061
- this._mediaRecorder = mediaStream.pipe((0, import_rxjs15.map)((stream) => {
14245
+ const mediaStream = (0, import_rxjs16.from)(navigator.mediaDevices.getUserMedia({ audio: true }));
14246
+ this._mediaRecorder = mediaStream.pipe((0, import_rxjs16.map)((stream) => {
14062
14247
  const rec = new MediaRecorder(stream);
14063
14248
  rec.start();
14064
14249
  return rec;
14065
- }), (0, import_rxjs15.shareReplay)(1));
14250
+ }), (0, import_rxjs16.shareReplay)(1));
14066
14251
  const dataAvailableEvent = this._mediaRecorder.pipe(
14067
- (0, import_rxjs15.switchMap)((recorder) => (0, import_rxjs15.fromEvent)(recorder, "dataavailable"))
14252
+ (0, import_rxjs16.switchMap)((recorder) => (0, import_rxjs16.fromEvent)(recorder, "dataavailable"))
14068
14253
  );
14069
14254
  const blob = dataAvailableEvent.pipe(
14070
- (0, import_rxjs15.first)(),
14071
- (0, import_rxjs15.map)((event) => createAudioBlob(event.data)),
14072
- (0, import_rxjs15.shareReplay)(1)
14255
+ (0, import_rxjs16.first)(),
14256
+ (0, import_rxjs16.map)((event) => createAudioBlob(event.data)),
14257
+ (0, import_rxjs16.shareReplay)(1)
14073
14258
  );
14074
14259
  return blob;
14075
14260
  }
@@ -14077,7 +14262,7 @@ var init_sound_recorder_service = __esm({
14077
14262
  if (!this._mediaRecorder) {
14078
14263
  return;
14079
14264
  }
14080
- this._mediaRecorder.pipe((0, import_rxjs15.first)()).subscribe((recorder) => {
14265
+ this._mediaRecorder.pipe((0, import_rxjs16.first)()).subscribe((recorder) => {
14081
14266
  recorder.stop();
14082
14267
  });
14083
14268
  }
@@ -14197,7 +14382,7 @@ var init_stt_client = __esm({
14197
14382
  });
14198
14383
 
14199
14384
  // src/services/stt/transcriber.tsx
14200
- var import_react16, import_Mic, import_Check4, import_Close3, import_material10, import_rxjs16, import_jsx_runtime13, initialButtonStyles, Transcriber, transcriber_default;
14385
+ var import_react16, import_Mic, import_Check4, import_Close3, import_material10, import_rxjs17, import_jsx_runtime13, initialButtonStyles, Transcriber, transcriber_default;
14201
14386
  var init_transcriber = __esm({
14202
14387
  "src/services/stt/transcriber.tsx"() {
14203
14388
  "use strict";
@@ -14208,7 +14393,7 @@ var init_transcriber = __esm({
14208
14393
  init_sound_recorder_service();
14209
14394
  init_stt_client();
14210
14395
  import_material10 = require("@mui/material");
14211
- import_rxjs16 = require("rxjs");
14396
+ import_rxjs17 = require("rxjs");
14212
14397
  init_debugLogger();
14213
14398
  import_jsx_runtime13 = require("react/jsx-runtime");
14214
14399
  initialButtonStyles = (badgeBackground, fileText, hoverBadgeBackground) => ({
@@ -14227,14 +14412,14 @@ var init_transcriber = __esm({
14227
14412
  const [status, setStatus] = (0, import_react16.useState)("IDLE");
14228
14413
  const recorderRef = (0, import_react16.useRef)(new SoundRecorderService());
14229
14414
  const [iconButtonStyles] = (0, import_react16.useState)(() => initialButtonStyles(badgeBackground, fileText, hoverBadgeBackground));
14230
- const [recordingSub, setRecordingSub] = (0, import_react16.useState)(() => new import_rxjs16.Subscription());
14415
+ const [recordingSub, setRecordingSub] = (0, import_react16.useState)(() => new import_rxjs17.Subscription());
14231
14416
  const start = () => {
14232
14417
  recordingSub.unsubscribe();
14233
14418
  const recording = recorderRef.current.start();
14234
14419
  const text = recording.pipe(
14235
- (0, import_rxjs16.switchMap)((blob) => {
14420
+ (0, import_rxjs17.switchMap)((blob) => {
14236
14421
  debugLogger.debug("Processing audio blob for transcription");
14237
- return (0, import_rxjs16.from)(STTClient.transcribe(blob));
14422
+ return (0, import_rxjs17.from)(STTClient.transcribe(blob));
14238
14423
  })
14239
14424
  );
14240
14425
  const sub = text.subscribe({
@@ -17731,21 +17916,6 @@ ${sanitize(
17731
17916
  !isMobile && renderAttachmentButton("attach-inline"),
17732
17917
  !isMobile && renderMemoryButton("memory-inline"),
17733
17918
  !isMobile && renderSttButton("stt-inline"),
17734
- !isMobile && isFeedbackEnabled && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material14.Tooltip, { title: "Send Feedback", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
17735
- import_material14.IconButton,
17736
- {
17737
- onClick: () => setFeedbackModalOpen(true),
17738
- sx: {
17739
- bgcolor: badgeBackground,
17740
- color: fileText,
17741
- width: primaryIconSize,
17742
- height: primaryIconSize,
17743
- borderRadius: "50%",
17744
- "&:hover": { bgcolor: hoverBadgeBackground }
17745
- },
17746
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_Feedback.default, { fontSize: "small" })
17747
- }
17748
- ) }),
17749
17919
  isMobile && hasSecondaryActions && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
17750
17920
  import_material14.IconButton,
17751
17921
  {
@@ -17765,7 +17935,7 @@ ${sanitize(
17765
17935
  fontSize: "small",
17766
17936
  sx: {
17767
17937
  transition: "transform 0.2s ease",
17768
- transform: moreActionsOpen ? "rotate(180deg)" : "rotate(0deg)"
17938
+ transform: moreActionsOpen ? "rotate(0deg)" : "rotate(180deg)"
17769
17939
  }
17770
17940
  }
17771
17941
  )
@@ -17861,11 +18031,11 @@ ${sanitize(
17861
18031
  });
17862
18032
 
17863
18033
  // src/chat/hooks/useMemoryEnhancer.tsx
17864
- var import_rxjs17, MEMORY_LIMIT, MIN_MEMORY_WORDS, MERGE_THRESHOLD, REJECT_ECHO_THRESHOLD, REJECT_DUPLICATE_THRESHOLD, CONTEXTUAL_DIVERGENCE_THRESHOLD, normalizeText, isStructurallyDuplicate, isAboutBandit, hasEngagementValue, isMemoryTooShortOrGeneric, isPersonalText, mergeMemory, isVoiceShifted, sanitizeMemory, sanitizeMemoryText, shouldAcceptMemory, isContextuallyDivergent, useMemoryEnhancer;
18034
+ var import_rxjs18, MEMORY_LIMIT, MIN_MEMORY_WORDS, MERGE_THRESHOLD, REJECT_ECHO_THRESHOLD, REJECT_DUPLICATE_THRESHOLD, CONTEXTUAL_DIVERGENCE_THRESHOLD, normalizeText, isStructurallyDuplicate, isAboutBandit, hasEngagementValue, isMemoryTooShortOrGeneric, isPersonalText, mergeMemory, isVoiceShifted, sanitizeMemory, sanitizeMemoryText, shouldAcceptMemory, isContextuallyDivergent, useMemoryEnhancer;
17865
18035
  var init_useMemoryEnhancer = __esm({
17866
18036
  "src/chat/hooks/useMemoryEnhancer.tsx"() {
17867
18037
  "use strict";
17868
- import_rxjs17 = require("rxjs");
18038
+ import_rxjs18 = require("rxjs");
17869
18039
  init_memoryStore();
17870
18040
  init_aiProviderStore();
17871
18041
  init_packageSettingsStore();
@@ -18257,8 +18427,8 @@ var init_useMemoryEnhancer = __esm({
18257
18427
  stream: false,
18258
18428
  options: { temperature: 0.1, num_predict: 150 }
18259
18429
  });
18260
- const suggestion = await (0, import_rxjs17.lastValueFrom)(
18261
- result$.pipe((0, import_rxjs17.map)((chunk) => chunk.response))
18430
+ const suggestion = await (0, import_rxjs18.lastValueFrom)(
18431
+ result$.pipe((0, import_rxjs18.map)((chunk) => chunk.response))
18262
18432
  );
18263
18433
  debugLogger.memoryDebug(`LLM memory suggestion received (${attempt})`, {
18264
18434
  suggestion: typeof suggestion === "string" ? suggestion.slice(0, 200) : suggestion,
@@ -23774,14 +23944,14 @@ var init_chat_app_bar = __esm({
23774
23944
  });
23775
23945
 
23776
23946
  // src/chat/hooks/useConversationNameGenerator.tsx
23777
- var import_rxjs18, import_operators5, useConversationNameGenerator;
23947
+ var import_rxjs19, import_operators5, useConversationNameGenerator;
23778
23948
  var init_useConversationNameGenerator = __esm({
23779
23949
  "src/chat/hooks/useConversationNameGenerator.tsx"() {
23780
23950
  "use strict";
23781
23951
  init_aiProviderStore();
23782
23952
  init_packageSettingsStore();
23783
23953
  init_debugLogger();
23784
- import_rxjs18 = require("rxjs");
23954
+ import_rxjs19 = require("rxjs");
23785
23955
  import_operators5 = require("rxjs/operators");
23786
23956
  init_conversationStore();
23787
23957
  useConversationNameGenerator = () => {
@@ -23817,7 +23987,7 @@ Respond with just the title and nothing else.
23817
23987
  num_predict: 20
23818
23988
  }
23819
23989
  });
23820
- const title = await (0, import_rxjs18.lastValueFrom)(
23990
+ const title = await (0, import_rxjs19.lastValueFrom)(
23821
23991
  result$.pipe((0, import_operators5.map)((d) => d.response?.trim().replace(/["']/g, "")))
23822
23992
  );
23823
23993
  if (title && title.length > 0) {
@@ -23887,10 +24057,12 @@ var init_query_suggestion_picker = __esm({
23887
24057
  } else {
23888
24058
  setExamplePrompts([]);
23889
24059
  setVisiblePrompts([]);
24060
+ hasGenerated.current = false;
23890
24061
  }
23891
24062
  }).catch((error) => {
23892
24063
  setExamplePrompts([]);
23893
24064
  setVisiblePrompts([]);
24065
+ hasGenerated.current = false;
23894
24066
  });
23895
24067
  }, [getCurrentModel, isLoading]);
23896
24068
  (0, import_react31.useEffect)(() => {
@@ -27119,6 +27291,7 @@ var init_chat2 = __esm({
27119
27291
  const featureFlag = useFeatureFlag();
27120
27292
  const { isOSSMode } = featureFlag;
27121
27293
  const ossMode = isOSSMode() || !packageSettings?.featureFlags?.subscriptionType;
27294
+ const playgroundBypassAccess = packageSettings?.playgroundBypassAuth || typeof window !== "undefined" && window.location.pathname.includes("/playground");
27122
27295
  const notificationService2 = useNotificationService();
27123
27296
  const [selectedTheme, setSelectedTheme] = (0, import_react35.useState)(null);
27124
27297
  const [themeLoading, setThemeLoading] = (0, import_react35.useState)(true);
@@ -27952,7 +28125,7 @@ var init_chat2 = __esm({
27952
28125
  }
27953
28126
  };
27954
28127
  if (!hydrated || brandingLoading || themeLoading) return null;
27955
- const userHasAccess = ossMode || claims?.roles?.includes("super-user") || claims?.roles?.includes("admin");
28128
+ const userHasAccess = playgroundBypassAccess || ossMode || claims?.roles?.includes("super-user") || claims?.roles?.includes("admin");
27956
28129
  if (!userHasAccess) {
27957
28130
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_material27.ThemeProvider, { theme: banditTheme, children: [
27958
28131
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_material27.CssBaseline, {}),
@@ -28155,13 +28328,19 @@ var init_chat2 = __esm({
28155
28328
  }
28156
28329
  const ossConfigured = !packageSettings.featureFlags?.subscriptionType;
28157
28330
  const allowUnauthenticated = isOSSMode() || ossConfigured;
28331
+ const playgroundBypassAuth = packageSettings.playgroundBypassAuth;
28332
+ const isPlaygroundRoute = typeof window !== "undefined" && window.location.pathname.includes("/playground");
28333
+ const bypassAuth = playgroundBypassAuth || isPlaygroundRoute;
28158
28334
  debugLogger.info("Chat authentication gate", {
28159
28335
  ossConfigured,
28160
28336
  isOSSMode: isOSSMode(),
28161
28337
  tier: featureFlag.getEvaluation()?.tier,
28162
- hasToken: authenticationService.isAuthenticated()
28338
+ hasToken: authenticationService.isAuthenticated(),
28339
+ playgroundBypassAuth,
28340
+ isPlaygroundRoute,
28341
+ bypassAuth
28163
28342
  });
28164
- if (!allowUnauthenticated && !authenticationService.isAuthenticated()) {
28343
+ if (!allowUnauthenticated && !bypassAuth && !authenticationService.isAuthenticated()) {
28165
28344
  debugLogger.debug("User is not authenticated, redirecting to login");
28166
28345
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom3.Navigate, { to: "/login", replace: true });
28167
28346
  }
@@ -28541,10 +28720,16 @@ var ChatProvider = (props) => {
28541
28720
  useProjectStore.getState().hydrate();
28542
28721
  useAIQueryStore.getState().hydrate();
28543
28722
  useMemoryStore.getState().hydrate();
28544
- await usePreferencesStore.getState().loadPreferences();
28545
- await useKnowledgeStore.getState().loadDocs();
28546
- await useMCPToolsStore.getState().loadTools();
28547
- await useConversationSyncStore.getState().initialize();
28723
+ const isPlaygroundRoute = typeof window !== "undefined" && window.location.pathname.includes("/playground");
28724
+ const isPlaygroundMode = isPlaygroundRoute || props.packageSettings.playgroundMode === true;
28725
+ if (isPlaygroundMode) {
28726
+ debugLogger.info("ChatProvider: Playground mode detected \u2014 skipping remote preference and sync initialization");
28727
+ } else {
28728
+ await usePreferencesStore.getState().loadPreferences();
28729
+ await useKnowledgeStore.getState().loadDocs();
28730
+ await useMCPToolsStore.getState().loadTools();
28731
+ await useConversationSyncStore.getState().initialize();
28732
+ }
28548
28733
  debugLogger.info("ChatProvider about to call initModels - checking for existing branding first");
28549
28734
  const storeConfigs6 = [{ name: "config", keyPath: "id" }];
28550
28735
  let existingBranding = null;
@@ -28606,10 +28791,14 @@ var ChatProvider = (props) => {
28606
28791
  debugLogger.error("\u274C Failed to fetch or apply branding config:", { error: err });
28607
28792
  });
28608
28793
  }
28609
- loadDocuments();
28610
- embeddingService.backfillMissingEmbeddings().catch((err) => {
28611
- debugLogger.error("\u274C Failed to backfill memory embeddings:", { error: err });
28612
- });
28794
+ if (!isPlaygroundMode) {
28795
+ loadDocuments();
28796
+ embeddingService.backfillMissingEmbeddings().catch((err) => {
28797
+ debugLogger.error("\u274C Failed to backfill memory embeddings:", { error: err });
28798
+ });
28799
+ } else {
28800
+ debugLogger.info("ChatProvider: Playground mode skipping knowledge backfill");
28801
+ }
28613
28802
  };
28614
28803
  initializeAsync();
28615
28804
  }, [props.packageSettings, loadDocuments]);
@@ -29063,7 +29252,7 @@ init_modelStore();
29063
29252
  init_ai_response_text_field();
29064
29253
  init_memory_modal();
29065
29254
  init_streaming_tts();
29066
- var import_rxjs19 = require("rxjs");
29255
+ var import_rxjs20 = require("rxjs");
29067
29256
  init_debugLogger();
29068
29257
  init_util();
29069
29258
  var import_jsx_runtime32 = require("react/jsx-runtime");
@@ -29092,7 +29281,7 @@ var AIQueriesDrawer = ({ drawerOpen, onClose, onClearComplete, onNavigateToMain
29092
29281
  const [memoryModalOpen, setMemoryModalOpen] = (0, import_react39.useState)(false);
29093
29282
  const [contextMode, setContextMode] = (0, import_react39.useState)("local");
29094
29283
  const [expandedSections, setExpandedSections] = (0, import_react39.useState)(/* @__PURE__ */ new Set(["history", "voice"]));
29095
- const [audioSub, setAudioSub] = (0, import_react39.useState)(new import_rxjs19.Subscription());
29284
+ const [audioSub, setAudioSub] = (0, import_react39.useState)(new import_rxjs20.Subscription());
29096
29285
  const [isContextSwitching, setIsContextSwitching] = (0, import_react39.useState)(false);
29097
29286
  const [isDrawerLoading, setIsDrawerLoading] = (0, import_react39.useState)(false);
29098
29287
  (0, import_react39.useEffect)(() => {
@@ -30755,7 +30944,7 @@ init_debugLogger();
30755
30944
  init_banditTheme();
30756
30945
  init_themeMap();
30757
30946
  init_useTTS();
30758
- var import_rxjs20 = require("rxjs");
30947
+ var import_rxjs21 = require("rxjs");
30759
30948
  var import_jsx_runtime34 = require("react/jsx-runtime");
30760
30949
  var FULL_SCREEN_THRESHOLD = 100;
30761
30950
  var CDN_BASE2 = "https://cdn.burtson.ai/";
@@ -30822,7 +31011,7 @@ var ChatModal = ({
30822
31011
  const [modalLogo, setModalLogo] = (0, import_react42.useState)("https://cdn.burtson.ai/logos/bandit-ai-logo.png");
30823
31012
  const [modelAnchorEl, setModelAnchorEl] = (0, import_react42.useState)(null);
30824
31013
  const [voiceAnchorEl, setVoiceAnchorEl] = (0, import_react42.useState)(null);
30825
- const [audioSub, setAudioSub] = (0, import_react42.useState)(new import_rxjs20.Subscription());
31014
+ const [audioSub, setAudioSub] = (0, import_react42.useState)(new import_rxjs21.Subscription());
30826
31015
  const [selectedTheme, setSelectedTheme] = (0, import_react42.useState)(null);
30827
31016
  const [themeLoading, setThemeLoading] = (0, import_react42.useState)(true);
30828
31017
  const [autoFullscreenTriggered, setAutoFullscreenTriggered] = (0, import_react42.useState)(false);
@@ -33363,7 +33552,7 @@ init_conversationSyncStore();
33363
33552
 
33364
33553
  // src/hooks/useGatewayQueries.ts
33365
33554
  var import_react45 = require("react");
33366
- var import_rxjs21 = require("rxjs");
33555
+ var import_rxjs22 = require("rxjs");
33367
33556
  var import_react_query2 = require("@tanstack/react-query");
33368
33557
  init_packageSettingsStore();
33369
33558
  init_gateway_service();
@@ -33394,7 +33583,7 @@ var useGatewayHealth = (options) => {
33394
33583
  if (!service) {
33395
33584
  throw new Error("Gateway service is not configured");
33396
33585
  }
33397
- return (0, import_rxjs21.lastValueFrom)(service.getHealth());
33586
+ return (0, import_rxjs22.lastValueFrom)(service.getHealth());
33398
33587
  },
33399
33588
  enabled
33400
33589
  });
@@ -33409,7 +33598,7 @@ var useGatewayModels = (options) => {
33409
33598
  if (!service) {
33410
33599
  throw new Error("Gateway service is not configured");
33411
33600
  }
33412
- return (0, import_rxjs21.lastValueFrom)(service.listModels());
33601
+ return (0, import_rxjs22.lastValueFrom)(service.listModels());
33413
33602
  },
33414
33603
  enabled
33415
33604
  });
@@ -33424,7 +33613,7 @@ var useGatewayMemory = (options) => {
33424
33613
  if (!service) {
33425
33614
  throw new Error("Gateway service is not configured");
33426
33615
  }
33427
- return (0, import_rxjs21.lastValueFrom)(service.getMemory());
33616
+ return (0, import_rxjs22.lastValueFrom)(service.getMemory());
33428
33617
  },
33429
33618
  enabled
33430
33619
  });
@@ -35181,7 +35370,7 @@ var BrandingTab = ({
35181
35370
  )) }),
35182
35371
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_material39.Paper, { elevation: 3, sx: { px: 2, py: 1.5, borderRadius: 2, width: "100%", maxWidth: 500 }, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_material39.Typography, { variant: "body1", sx: { color: "text.secondary" }, children: "What's on your mind?" }) }),
35183
35372
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_material39.Typography, { variant: "caption", sx: { textAlign: "center", color: "text.secondary", mt: 1 }, children: [
35184
- brandingText ? `${brandingText} \u2022 ` : "",
35373
+ brandingText ? `${brandingText} \u2022 ` : "Bandit AI \u2022 ",
35185
35374
  "may be wrong \u2014 double-check important info."
35186
35375
  ] })
35187
35376
  ] })
@@ -37167,7 +37356,10 @@ var import_CheckCircle3 = __toESM(require("@mui/icons-material/CheckCircle"));
37167
37356
  var import_Error3 = __toESM(require("@mui/icons-material/Error"));
37168
37357
  init_debugLogger();
37169
37358
  init_indexedDBService();
37359
+ init_conversationSyncStore();
37170
37360
  var import_jsx_runtime42 = require("react/jsx-runtime");
37361
+ var DEFAULT_DISPLAY_QUOTA_BYTES = 1024 * 1024 * 1024;
37362
+ var MAX_DISPLAY_QUOTA_BYTES = 5 * 1024 * 1024 * 1024;
37171
37363
  var formatBytes = (bytes) => {
37172
37364
  if (bytes === 0) return "0 B";
37173
37365
  const k = 1024;
@@ -37384,20 +37576,22 @@ var estimateStoreSize = async (dbName, storeName) => {
37384
37576
  const storeConfigs6 = [{ name: storeName, keyPath: "id" }];
37385
37577
  try {
37386
37578
  const items = await indexedDBService_default.getAll(dbName, 1, storeName, storeConfigs6);
37387
- debugLogger.info(`Retrieved ${items?.length || 0} items from ${dbName}.${storeName}`);
37388
- if (!items || items.length === 0) {
37579
+ const rawItems = Array.isArray(items) ? items : [];
37580
+ debugLogger.info(`Retrieved ${rawItems.length} items from ${dbName}.${storeName}`);
37581
+ if (rawItems.length === 0) {
37389
37582
  debugLogger.info(`No items found in ${dbName}.${storeName}`);
37390
37583
  return { size: 0, count: 0 };
37391
37584
  }
37392
- const totalSize = items.reduce((acc, item) => {
37585
+ const totalSize = rawItems.reduce((acc, item) => {
37393
37586
  try {
37394
- return acc + JSON.stringify(item).length * 2;
37587
+ return acc + JSON.stringify(item ?? "").length * 2;
37395
37588
  } catch {
37396
37589
  return acc + 1e3;
37397
37590
  }
37398
37591
  }, 0);
37399
- debugLogger.info(`Estimated size for ${dbName}.${storeName}: ${totalSize} bytes, ${items.length} items`);
37400
- return { size: totalSize, count: items.length };
37592
+ const itemCount = rawItems.length;
37593
+ debugLogger.info(`Estimated size for ${dbName}.${storeName}: ${totalSize} bytes, ${itemCount} items`);
37594
+ return { size: totalSize, count: itemCount };
37401
37595
  } catch (dbError) {
37402
37596
  debugLogger.info(`Database ${dbName} or store ${storeName} does not exist or is inaccessible`, { error: dbError });
37403
37597
  return { size: 0, count: 0 };
@@ -37421,14 +37615,18 @@ var clearStorageCategory = async (category) => {
37421
37615
  }
37422
37616
  const storeConfigs6 = [{ name: storeName, keyPath: "id" }];
37423
37617
  const items = await indexedDBService_default.getAll(dbName, 1, storeName, storeConfigs6);
37424
- if (items && items.length > 0) {
37425
- for (const item of items) {
37426
- const key = item.id || item.key || item.name;
37427
- if (key) {
37428
- await indexedDBService_default.delete(dbName, 1, storeName, key, storeConfigs6);
37618
+ const records = Array.isArray(items) ? items : [];
37619
+ if (records.length > 0) {
37620
+ for (const rawItem of records) {
37621
+ if (rawItem && typeof rawItem === "object") {
37622
+ const record = rawItem;
37623
+ const candidate = record["id"] ?? record["key"] ?? record["name"];
37624
+ if (typeof candidate === "string" && candidate.length > 0) {
37625
+ await indexedDBService_default.delete(dbName, 1, storeName, candidate, storeConfigs6);
37626
+ }
37429
37627
  }
37430
37628
  }
37431
- debugLogger.info(`Cleared ${items.length} items from ${dbName}.${storeName}`);
37629
+ debugLogger.info(`Cleared ${records.length} items from ${dbName}.${storeName}`);
37432
37630
  } else {
37433
37631
  debugLogger.info(`No items found in ${dbName}.${storeName}`);
37434
37632
  }
@@ -37456,7 +37654,12 @@ var clearEntireDatabase = async (dbName) => {
37456
37654
  };
37457
37655
  var StorageTab = ({ currentTheme }) => {
37458
37656
  const theme = (0, import_material42.useTheme)();
37459
- const [storageQuota, setStorageQuota] = (0, import_react52.useState)({ used: 0, quota: 0 });
37657
+ const [storageQuota, setStorageQuota] = (0, import_react52.useState)({
37658
+ used: 0,
37659
+ quota: 0,
37660
+ available: 0,
37661
+ browserQuotaEstimate: 0
37662
+ });
37460
37663
  const [storageCategories, setStorageCategories] = (0, import_react52.useState)([]);
37461
37664
  const [loading, setLoading] = (0, import_react52.useState)(true);
37462
37665
  const [clearAllDialogOpen, setClearAllDialogOpen] = (0, import_react52.useState)(false);
@@ -37465,16 +37668,31 @@ var StorageTab = ({ currentTheme }) => {
37465
37668
  const [snackbarMessage, setSnackbarMessage] = (0, import_react52.useState)("");
37466
37669
  const [showSnackbar, setShowSnackbar] = (0, import_react52.useState)(false);
37467
37670
  const [snackbarSeverity, setSnackbarSeverity] = (0, import_react52.useState)("success");
37671
+ const { syncEnabled, isAdvancedVectorFeaturesEnabled } = useConversationSyncStore((state) => ({
37672
+ syncEnabled: state.syncEnabled,
37673
+ isAdvancedVectorFeaturesEnabled: state.isAdvancedVectorFeaturesEnabled
37674
+ }));
37675
+ const syncFeaturesActive = syncEnabled || isAdvancedVectorFeaturesEnabled;
37676
+ const usageSummaryMessage = syncFeaturesActive ? "IndexedDB/local storage is shown below. Conversation sync or advanced vector storage may copy items to your configured gateway." : "IndexedDB/local storage lives entirely in this browser when sync features are disabled.";
37677
+ const storageStatusPrimary = syncFeaturesActive ? "IndexedDB/local storage (sync features enabled)" : "IndexedDB/local storage only";
37468
37678
  const loadStorageData = async () => {
37469
37679
  setLoading(true);
37470
37680
  try {
37471
37681
  debugLogger.info("Loading storage data...");
37472
- const [quota, categories] = await Promise.all([
37682
+ const [quotaEstimate, categories] = await Promise.all([
37473
37683
  getStorageQuota(),
37474
37684
  getIndexedDBSize()
37475
37685
  ]);
37686
+ const calculatedUsed = categories.reduce((sum, cat) => sum + cat.size, 0);
37687
+ const browserQuota = quotaEstimate.quota && quotaEstimate.quota > 0 ? quotaEstimate.quota : 0;
37688
+ let normalizedQuota = browserQuota > 0 ? Math.min(Math.max(browserQuota, calculatedUsed || DEFAULT_DISPLAY_QUOTA_BYTES), MAX_DISPLAY_QUOTA_BYTES) : Math.max(DEFAULT_DISPLAY_QUOTA_BYTES, calculatedUsed);
37689
+ const available = Math.max(normalizedQuota - calculatedUsed, 0);
37476
37690
  debugLogger.info("Storage data loaded successfully", {
37477
- quota: quota.used + "/" + quota.quota,
37691
+ browserQuota,
37692
+ browserUsageEstimate: quotaEstimate.used,
37693
+ normalizedQuota,
37694
+ calculatedUsed,
37695
+ available,
37478
37696
  categoriesCount: categories.length,
37479
37697
  categories: categories.map((cat) => ({
37480
37698
  name: cat.name,
@@ -37483,7 +37701,12 @@ var StorageTab = ({ currentTheme }) => {
37483
37701
  canClear: cat.canClear
37484
37702
  }))
37485
37703
  });
37486
- setStorageQuota(quota);
37704
+ setStorageQuota({
37705
+ used: calculatedUsed,
37706
+ quota: normalizedQuota,
37707
+ available,
37708
+ browserQuotaEstimate: browserQuota
37709
+ });
37487
37710
  setStorageCategories(categories);
37488
37711
  } catch (error) {
37489
37712
  debugLogger.error("Failed to load storage data", { error });
@@ -37491,7 +37714,7 @@ var StorageTab = ({ currentTheme }) => {
37491
37714
  setSnackbarSeverity("error");
37492
37715
  setShowSnackbar(true);
37493
37716
  setStorageCategories([]);
37494
- setStorageQuota({ used: 0, quota: 0 });
37717
+ setStorageQuota({ used: 0, quota: DEFAULT_DISPLAY_QUOTA_BYTES, available: DEFAULT_DISPLAY_QUOTA_BYTES, browserQuotaEstimate: 0 });
37495
37718
  } finally {
37496
37719
  setLoading(false);
37497
37720
  }
@@ -37504,7 +37727,7 @@ var StorageTab = ({ currentTheme }) => {
37504
37727
  }, [storageCategories]);
37505
37728
  const usagePercentage = (0, import_react52.useMemo)(() => {
37506
37729
  if (storageQuota.quota === 0) return 0;
37507
- const percentage = storageQuota.used / storageQuota.quota * 100;
37730
+ const percentage = Math.min(storageQuota.used / storageQuota.quota * 100, 100);
37508
37731
  return percentage > 0 && percentage < 0.1 ? 0.1 : percentage;
37509
37732
  }, [storageQuota]);
37510
37733
  const clearableCategories = (0, import_react52.useMemo)(() => {
@@ -37704,7 +37927,7 @@ var StorageTab = ({ currentTheme }) => {
37704
37927
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
37705
37928
  import_material42.Chip,
37706
37929
  {
37707
- label: `${formatBytes(storageQuota.quota - storageQuota.used)} Available`,
37930
+ label: `${formatBytes(storageQuota.available)} Available`,
37708
37931
  color: "success",
37709
37932
  size: "small",
37710
37933
  variant: "outlined"
@@ -37718,6 +37941,15 @@ var StorageTab = ({ currentTheme }) => {
37718
37941
  size: "small",
37719
37942
  variant: "outlined"
37720
37943
  }
37944
+ ),
37945
+ storageQuota.browserQuotaEstimate > 0 && storageQuota.quota > 0 && Math.abs(storageQuota.browserQuotaEstimate - storageQuota.quota) > storageQuota.quota * 0.05 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
37946
+ import_material42.Chip,
37947
+ {
37948
+ label: `\u2248${formatBytes(storageQuota.browserQuotaEstimate)} Browser Estimate`,
37949
+ color: "default",
37950
+ size: "small",
37951
+ variant: "outlined"
37952
+ }
37721
37953
  )
37722
37954
  ] }),
37723
37955
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
@@ -37775,7 +38007,7 @@ var StorageTab = ({ currentTheme }) => {
37775
38007
  }
37776
38008
  )
37777
38009
  ] }),
37778
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material42.Typography, { variant: "body2", color: "text.secondary", sx: { mt: "auto" }, children: "Data is stored locally in your browser and never sent to external servers." })
38010
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material42.Typography, { variant: "body2", color: "text.secondary", sx: { mt: "auto" }, children: usageSummaryMessage })
37779
38011
  ] }) })
37780
38012
  ] }),
37781
38013
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material42.Typography, { variant: "h6", gutterBottom: true, sx: { mb: 2, fontWeight: 600, color: "text.primary" }, children: "Storage Categories" }),
@@ -37903,12 +38135,19 @@ var StorageTab = ({ currentTheme }) => {
37903
38135
  ] }),
37904
38136
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_material42.List, { children: [
37905
38137
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_material42.ListItem, { children: [
37906
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material42.ListItemIcon, { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_CheckCircle3.default, { color: "success" }) }),
38138
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material42.ListItemIcon, { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
38139
+ import_CheckCircle3.default,
38140
+ {
38141
+ sx: {
38142
+ color: syncFeaturesActive ? theme.palette.warning.main : theme.palette.success.main
38143
+ }
38144
+ }
38145
+ ) }),
37907
38146
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
37908
38147
  import_material42.ListItemText,
37909
38148
  {
37910
- primary: "All data is stored locally",
37911
- secondary: "Your data never leaves your browser and is not sent to external servers"
38149
+ primary: storageStatusPrimary,
38150
+ secondary: syncFeaturesActive ? "Some features (conversation sync or advanced vector storage) can sync items to your configured gateway storage." : "With conversation sync and advanced vector storage turned off, everything stays in this browser."
37912
38151
  }
37913
38152
  )
37914
38153
  ] }),
@@ -38203,6 +38442,11 @@ var ProviderTab = () => {
38203
38442
  provider: "openai"
38204
38443
  });
38205
38444
  break;
38445
+ case "playground" /* PLAYGROUND */:
38446
+ setProviderConfig({
38447
+ ...baseConfig
38448
+ });
38449
+ break;
38206
38450
  }
38207
38451
  };
38208
38452
  const handleSaveProviderConfig = async () => {
@@ -38322,7 +38566,8 @@ var ProviderTab = () => {
38322
38566
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_material43.MenuItem, { value: "ollama", children: "Ollama" }),
38323
38567
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_material43.MenuItem, { value: "openai", children: "OpenAI" }),
38324
38568
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_material43.MenuItem, { value: "azure-openai", children: "Azure OpenAI" }),
38325
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_material43.MenuItem, { value: "anthropic", children: "Anthropic" })
38569
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_material43.MenuItem, { value: "anthropic", children: "Anthropic" }),
38570
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_material43.MenuItem, { value: "playground", children: "Playground (Mock Demo)" })
38326
38571
  ]
38327
38572
  }
38328
38573
  ),