@hivegpt/hiveai-angular 0.0.610 → 0.0.612

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.
@@ -1639,6 +1639,11 @@ class ChatDrawerComponent {
1639
1639
  this.displayAvatarUrl = 'https://www.jotform.com/uploads/mehmetkarakasli/form_files/1564593667676a8e85f23758.86945537_icon.png';
1640
1640
  /** When true, chat auto-scrolls to bottom when new content is added. Default: false (no auto scroll). */
1641
1641
  this.autoScrollOnNewMessage = false;
1642
+ /** Tracks whether the user has manually scrolled up, suppressing auto-scroll until they scroll back to bottom or send a new message. */
1643
+ this.userHasScrolled = false;
1644
+ /** Guards against our own programmatic scrolls triggering the userHasScrolled detection. */
1645
+ this.isProgrammaticScroll = false;
1646
+ this.scrollListenerTimer = null;
1642
1647
  /** Connections list from host (e.g. from store selectConnectionsList). Each item has userId. When set, used for Connect/Request Sent/Disconnect button state. */
1643
1648
  this.connectionsList = [];
1644
1649
  /** Pending sent request user IDs from host (e.g. from store selectPendingConnectionsSentList). When set, used for Request Sent state. */
@@ -3336,6 +3341,8 @@ class ChatDrawerComponent {
3336
3341
  if (!this.input || this.loading) {
3337
3342
  return;
3338
3343
  }
3344
+ // Reset auto-scroll suppression when user sends a new message
3345
+ this.userHasScrolled = false;
3339
3346
  this.chatLog.push({
3340
3347
  type: 'user',
3341
3348
  message: this.processMessageForDisplay(this.input),
@@ -3359,6 +3366,8 @@ class ChatDrawerComponent {
3359
3366
  if (!inputMsg || this.loading) {
3360
3367
  return;
3361
3368
  }
3369
+ // Reset auto-scroll suppression when user sends a new message
3370
+ this.userHasScrolled = false;
3362
3371
  try {
3363
3372
  chat.relatedListItems = [];
3364
3373
  this.cdr.detectChanges();
@@ -3417,7 +3426,8 @@ class ChatDrawerComponent {
3417
3426
  var _a, _b, _c, _d;
3418
3427
  const lastItem = this.chatLog[this.chatLog.length - 1];
3419
3428
  if (done) {
3420
- lastItem.message = this.processMessageForDisplay(lastItem.message);
3429
+ // Final pass with the complete raw text (aiResponse) for a clean render
3430
+ lastItem.message = this.processMessageForDisplay(this.aiResponse);
3421
3431
  this.chatLog.pop();
3422
3432
  this.chatLog.push(lastItem);
3423
3433
  if (allSuggestions === null || allSuggestions === void 0 ? void 0 : allSuggestions.length) {
@@ -3446,7 +3456,7 @@ class ChatDrawerComponent {
3446
3456
  allSuggestions.push(match === null || match === void 0 ? void 0 : match.replace(/<\/?sug>/g, ''));
3447
3457
  });
3448
3458
  }
3449
- lastItem.message = this.aiResponse;
3459
+ lastItem.message = this.processMessageForDisplay(this.aiResponse);
3450
3460
  this.cdr.markForCheck();
3451
3461
  }
3452
3462
  else {
@@ -3734,32 +3744,43 @@ class ChatDrawerComponent {
3734
3744
  }
3735
3745
  this.cdr.detectChanges();
3736
3746
  }
3737
- scrollToBottom(force = false) {
3747
+ scrollToBottom(force = false, smooth = true) {
3738
3748
  var _a;
3739
3749
  if (!force && !this.autoScrollOnNewMessage) {
3740
3750
  return;
3741
3751
  }
3752
+ if (this.userHasScrolled) {
3753
+ return;
3754
+ }
3742
3755
  if (!((_a = this.chatMain) === null || _a === void 0 ? void 0 : _a.nativeElement))
3743
3756
  return;
3744
- let counter = 0;
3745
- const interval = setInterval(() => {
3746
- this.chatMain.nativeElement.scrollTop =
3747
- this.chatMain.nativeElement.scrollHeight;
3748
- if (counter++ > 5)
3749
- clearInterval(interval);
3750
- }, 5);
3757
+ const el = this.chatMain.nativeElement;
3758
+ this.isProgrammaticScroll = true;
3759
+ el.scrollTo({
3760
+ top: el.scrollHeight,
3761
+ behavior: smooth ? 'smooth' : 'auto',
3762
+ });
3763
+ // Release the guard after the smooth scroll settles
3764
+ setTimeout(() => { this.isProgrammaticScroll = false; }, smooth ? 400 : 50);
3751
3765
  }
3752
3766
  /** Scrolls the chat container so the top of the AI message with the given id is visible. */
3753
3767
  scrollToAiMessage(messageId) {
3754
3768
  var _a;
3769
+ if (this.userHasScrolled)
3770
+ return;
3755
3771
  if (!((_a = this.chatMain) === null || _a === void 0 ? void 0 : _a.nativeElement))
3756
3772
  return;
3757
3773
  const container = this.chatMain.nativeElement;
3758
3774
  const el = container.querySelector(`[data-msg-id="${messageId}"]`);
3759
3775
  if (!el)
3760
3776
  return;
3761
- const offset = el.getBoundingClientRect().top - container.getBoundingClientRect().top;
3762
- container.scrollTop = container.scrollTop + offset - 8;
3777
+ const targetTop = el.getBoundingClientRect().top - container.getBoundingClientRect().top;
3778
+ this.isProgrammaticScroll = true;
3779
+ container.scrollTo({
3780
+ top: container.scrollTop + targetTop - 8,
3781
+ behavior: 'smooth',
3782
+ });
3783
+ setTimeout(() => { this.isProgrammaticScroll = false; }, 400);
3763
3784
  }
3764
3785
  focusOnTextarea() {
3765
3786
  setTimeout(() => {
@@ -3775,6 +3796,23 @@ class ChatDrawerComponent {
3775
3796
  }
3776
3797
  }
3777
3798
  ngAfterViewInit() {
3799
+ var _a;
3800
+ // Detect user manual scroll to suppress auto-scroll (debounced, ignores programmatic scrolls)
3801
+ if ((_a = this.chatMain) === null || _a === void 0 ? void 0 : _a.nativeElement) {
3802
+ this.chatMain.nativeElement.addEventListener('scroll', () => {
3803
+ if (this.isProgrammaticScroll)
3804
+ return;
3805
+ clearTimeout(this.scrollListenerTimer);
3806
+ this.scrollListenerTimer = setTimeout(() => {
3807
+ var _a;
3808
+ const el = (_a = this.chatMain) === null || _a === void 0 ? void 0 : _a.nativeElement;
3809
+ if (!el)
3810
+ return;
3811
+ const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
3812
+ this.userHasScrolled = !atBottom;
3813
+ }, 100);
3814
+ });
3815
+ }
3778
3816
  // Check if the drawer is initially open and apply overflow hidden to body if so
3779
3817
  if (this.drawer.opened) {
3780
3818
  this.setBodyOverflow();
@@ -4613,7 +4651,7 @@ class ChatDrawerComponent {
4613
4651
  return false;
4614
4652
  }
4615
4653
  handleAskWebSocketMessage(rawMessage) {
4616
- var _a, _b, _c, _d, _e;
4654
+ var _a, _b, _c, _d, _e, _f;
4617
4655
  if (!rawMessage)
4618
4656
  return;
4619
4657
  let parsed = null;
@@ -4635,7 +4673,9 @@ class ChatDrawerComponent {
4635
4673
  return;
4636
4674
  const isNewAiMessage = !this.chatLog.find((p) => p._id == messageId);
4637
4675
  const currentChatMessage = this.upsertAiChatMessage(messageId);
4638
- currentChatMessage.message = `${currentChatMessage.message || ''}${(payload === null || payload === void 0 ? void 0 : payload.text) || ''}`;
4676
+ // Accumulate raw text and render markdown in real-time
4677
+ currentChatMessage.rawMessage = `${currentChatMessage.rawMessage || ''}${(payload === null || payload === void 0 ? void 0 : payload.text) || ''}`;
4678
+ currentChatMessage.message = this.processMessageForDisplay(currentChatMessage.rawMessage);
4639
4679
  if (isNewAiMessage) {
4640
4680
  // First chunk: hide Thinking indicator and scroll to the message start
4641
4681
  this.isChatingWithAi = false;
@@ -4644,7 +4684,7 @@ class ChatDrawerComponent {
4644
4684
  }
4645
4685
  else {
4646
4686
  this.cdr.markForCheck();
4647
- setTimeout(() => this.scrollToBottom(true), 0);
4687
+ setTimeout(() => this.scrollToBottom(true, false), 0);
4648
4688
  }
4649
4689
  break;
4650
4690
  }
@@ -4655,19 +4695,21 @@ class ChatDrawerComponent {
4655
4695
  break;
4656
4696
  }
4657
4697
  const currentChatMessage = this.upsertAiChatMessage(messageId);
4658
- const finalAnswer = (_c = (_b = payload === null || payload === void 0 ? void 0 : payload.text) !== null && _b !== void 0 ? _b : currentChatMessage.message) !== null && _c !== void 0 ? _c : '';
4698
+ const finalAnswer = (_d = (_c = (_b = payload === null || payload === void 0 ? void 0 : payload.text) !== null && _b !== void 0 ? _b : currentChatMessage.rawMessage) !== null && _c !== void 0 ? _c : currentChatMessage.message) !== null && _d !== void 0 ? _d : '';
4659
4699
  const hasCardResponse = this.applyToolResultCardMessage(currentChatMessage, messageId, finalAnswer, payload === null || payload === void 0 ? void 0 : payload.tool_results);
4660
4700
  if (!hasCardResponse) {
4661
4701
  currentChatMessage.type = 'ai';
4662
4702
  currentChatMessage.message = this.processMessageForDisplay(finalAnswer);
4663
4703
  }
4704
+ // Clean up raw accumulator
4705
+ delete currentChatMessage.rawMessage;
4664
4706
  if (Array.isArray(payload === null || payload === void 0 ? void 0 : payload.suggestions)) {
4665
4707
  currentChatMessage.relatedListItems = payload.suggestions;
4666
4708
  }
4667
4709
  if (Array.isArray(payload === null || payload === void 0 ? void 0 : payload.web_results)) {
4668
4710
  currentChatMessage.sourcesList = payload.web_results;
4669
- currentChatMessage.displayedSources = (_d = payload.web_results) === null || _d === void 0 ? void 0 : _d.slice(0, 3);
4670
- currentChatMessage.remainingSources = (_e = payload.web_results) === null || _e === void 0 ? void 0 : _e.slice(3);
4711
+ currentChatMessage.displayedSources = (_e = payload.web_results) === null || _e === void 0 ? void 0 : _e.slice(0, 3);
4712
+ currentChatMessage.remainingSources = (_f = payload.web_results) === null || _f === void 0 ? void 0 : _f.slice(3);
4671
4713
  }
4672
4714
  if (payload === null || payload === void 0 ? void 0 : payload.tool_results) {
4673
4715
  currentChatMessage.toolResults = payload.tool_results;
@@ -4675,7 +4717,12 @@ class ChatDrawerComponent {
4675
4717
  this.showFeedBackIconsIndex = this.chatLog.length - 1;
4676
4718
  this.activeAskMessageId = '';
4677
4719
  this.isChatingWithAi = false;
4678
- this.scrollToBottom();
4720
+ // For card responses (tool results), don't scroll at all —
4721
+ // user is already viewing the AI text from the streaming phase,
4722
+ // cards render below and the user can scroll down to see them.
4723
+ if (!hasCardResponse) {
4724
+ this.scrollToBottom();
4725
+ }
4679
4726
  this.focusOnTextarea();
4680
4727
  this.cdr.markForCheck();
4681
4728
  break;
@@ -4794,6 +4841,7 @@ class ChatDrawerComponent {
4794
4841
  return Object.keys(obj).map((key) => ({ key, value: obj[key] }));
4795
4842
  }
4796
4843
  startNewConversation() {
4844
+ this.userHasScrolled = false;
4797
4845
  this.conversationKey = this.conversationService.getKey(this.botId, true, this.eventId);
4798
4846
  this.chatLog = [this.chatLog[0]];
4799
4847
  this.isChatingWithAi = false;