@adminforth/agent 1.24.4 → 1.24.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build.log CHANGED
@@ -38,5 +38,5 @@ custom/skills/fetch_data/SKILL.md
38
38
  custom/skills/mutate_data/
39
39
  custom/skills/mutate_data/SKILL.md
40
40
 
41
- sent 200,251 bytes received 562 bytes 401,626.00 bytes/sec
42
- total size is 197,947 speedup is 0.99
41
+ sent 201,498 bytes received 566 bytes 404,128.00 bytes/sec
42
+ total size is 199,190 speedup is 0.99
@@ -32,7 +32,7 @@
32
32
  ></div>
33
33
 
34
34
  <div
35
- class="w-full h-full flex flex-col"
35
+ class="w-full min-h-0 max-h-full flex flex-col"
36
36
  >
37
37
  <div
38
38
  class="flex items-center justify-between h-14 border-b border-gray-200 dark:border-gray-700"
@@ -91,11 +91,10 @@
91
91
 
92
92
  </div>
93
93
  <div
94
- class="relative flex-1 flex flex-col overflow-hidden"
94
+ class="relative flex-1 min-h-0 flex flex-col overflow-hidden"
95
95
  >
96
96
  <ConversationArea
97
97
  v-if="agentStore.isChatOpen"
98
- class="flex-1 overflow-auto"
99
98
  :messages="agentStore.chatMessages"
100
99
  />
101
100
 
@@ -1,11 +1,29 @@
1
+ <template>
2
+ <CustomScrollbar
3
+ ref="containerRef"
4
+ class="auto-scroll-container mask-y"
5
+ :wrapperStyle = "wrapperStyle"
6
+ :contentStyle = "contentStyle"
7
+ >
8
+ <slot />
9
+ </CustomScrollbar>
10
+ </template>
11
+
1
12
  <script setup lang="ts">
2
13
  import { ref, watch, onMounted, onUnmounted, nextTick } from 'vue'
3
- import vueCustomScrollbar from 'vue-custom-scrollbar'
14
+ import CustomScrollbar from 'custom-vue-scrollbar';
15
+ import 'custom-vue-scrollbar/dist/style.css';
16
+ import { useScroll } from '@vueuse/core'
17
+ import { useAgentStore } from './composables/useAgentStore';
18
+
19
+ const agentStore = useAgentStore();
4
20
 
5
21
  const props = withDefaults(defineProps<{
6
22
  enabled?: boolean
7
23
  threshold?: number
8
24
  behavior?: ScrollBehavior
25
+ wrapperStyle?: Record<string, string>
26
+ contentStyle?: Record<string, string>
9
27
  }>(), {
10
28
  enabled: true,
11
29
  threshold: 50,
@@ -14,12 +32,18 @@ const props = withDefaults(defineProps<{
14
32
 
15
33
  const containerRef = ref<HTMLDivElement | null>(null)
16
34
  const isUserScrolledUp = ref(false)
35
+ const scrollElement = ref<HTMLElement | null>(null)
36
+ const { y } = useScroll(scrollElement)
37
+
38
+ watch(y, () => {
39
+ handleScroll()
40
+ })
17
41
 
18
42
  let lastScrollTop = 0
19
43
  let lastScrollHeight = 0
20
44
 
21
45
  function isNearBottom(): boolean {
22
- const container = containerRef.value
46
+ const container = containerRef.value?.scrollEl
23
47
  if (!container) return true
24
48
 
25
49
  const { scrollTop, scrollHeight, clientHeight } = container
@@ -27,7 +51,7 @@ function isNearBottom(): boolean {
27
51
  }
28
52
 
29
53
  function scrollToBottom(force = false): void {
30
- const container = containerRef.value
54
+ const container = containerRef.value?.scrollEl
31
55
  if (!container) return
32
56
 
33
57
  if (isUserScrolledUp.value && !force) return
@@ -40,14 +64,14 @@ function scrollToBottom(force = false): void {
40
64
 
41
65
 
42
66
  function hasScrollbar(): boolean {
43
- const container = containerRef.value
67
+ const container = containerRef.value?.scrollEl
44
68
  if (!container) return false
45
69
  return container.scrollHeight > container.clientHeight
46
70
  }
47
71
 
48
72
 
49
73
  function handleScroll(): void {
50
- const container = containerRef.value
74
+ const container = containerRef.value.scrollEl
51
75
  if (!container) return
52
76
 
53
77
  const { scrollTop, scrollHeight, clientHeight } = container
@@ -58,7 +82,6 @@ function handleScroll(): void {
58
82
  lastScrollHeight = scrollHeight
59
83
  return
60
84
  }
61
-
62
85
  if (isNearBottom()) {
63
86
  isUserScrolledUp.value = false
64
87
  } else {
@@ -69,7 +92,6 @@ function handleScroll(): void {
69
92
  isUserScrolledUp.value = true
70
93
  }
71
94
  }
72
-
73
95
  lastScrollTop = scrollTop
74
96
  lastScrollHeight = scrollHeight
75
97
  }
@@ -79,18 +101,19 @@ let observer: MutationObserver | null = null
79
101
  onMounted(() => {
80
102
  if (!containerRef.value) return
81
103
 
82
- lastScrollTop = containerRef.value.scrollTop
83
- lastScrollHeight = containerRef.value.scrollHeight
104
+ scrollElement.value = containerRef.value.scrollEl
105
+ lastScrollTop = containerRef.value.scrollEl.scrollTop
106
+ lastScrollHeight = containerRef.value.scrollEl.scrollHeight
84
107
 
85
108
  observer = new MutationObserver(() => {
86
109
  nextTick(() => {
87
- if (!containerRef.value) return
110
+ if (!containerRef.value?.scrollEl) return
88
111
 
89
112
  if (!hasScrollbar()) {
90
113
  isUserScrolledUp.value = false
91
114
  }
92
115
 
93
- lastScrollHeight = containerRef.value.scrollHeight
116
+ lastScrollHeight = containerRef.value.scrollEl.scrollHeight
94
117
 
95
118
  if (props.enabled && !isUserScrolledUp.value) {
96
119
  scrollToBottom()
@@ -98,7 +121,7 @@ onMounted(() => {
98
121
  })
99
122
  })
100
123
 
101
- observer.observe(containerRef.value, {
124
+ observer.observe(containerRef.value?.scrollEl, {
102
125
  childList: true,
103
126
  subtree: true,
104
127
  characterData: true
@@ -112,16 +135,19 @@ onUnmounted(() => {
112
135
  defineExpose({
113
136
  scrollToBottom: () => scrollToBottom(true),
114
137
  isUserScrolledUp: () => isUserScrolledUp.value,
115
- container: containerRef
138
+ container: containerRef,
139
+ handleScroll
116
140
  })
117
141
  </script>
118
142
 
119
- <template>
120
- <div
121
- ref="containerRef"
122
- class="auto-scroll-container h-full"
123
- @scroll="handleScroll"
124
- >
125
- <slot />
126
- </div>
127
- </template>
143
+ <style>
144
+ .mask-y {
145
+ mask-image: linear-gradient(
146
+ to bottom,
147
+ transparent,
148
+ black 20px,
149
+ black calc(100% - 20px),
150
+ transparent
151
+ );
152
+ }
153
+ </style>
@@ -8,7 +8,7 @@
8
8
  <h3 :class="h3Style">{{ $t('Chat history') }}</h3>
9
9
  <div class="w-full flex items-center justify-center">
10
10
  <Button
11
- @click="agentStore.createPreSession(); agentStore.setSessionHistoryOpen(false); agentStore.focusTextInput(); recalculateScroll();"
11
+ @click="agentStore.createPreSession(); agentStore.setSessionHistoryOpen(false); agentStore.focusTextInput();"
12
12
  :disabled="agentStore.isResponseInProgress"
13
13
  class="w-[90%] my-2 mb-4 rounded-3xl text-gray-800 dark:text-gray-200"
14
14
  >
@@ -34,7 +34,7 @@
34
34
  'bg-lightPrimary/20 hover:bg-lightPrimary/20 dark:bg-darkPrimary/20 dark:hover:bg-darkPrimary/20': agentStore.activeSessionId === session.sessionId,
35
35
  'cursor-default opacity-50 pointer-events-none': agentStore.isResponseInProgress,
36
36
  }"
37
- @click="agentStore.setActiveSession(session.sessionId); agentStore.setSessionHistoryOpen(false); recalculateScroll();"
37
+ @click="agentStore.setActiveSession(session.sessionId); agentStore.setSessionHistoryOpen(false);"
38
38
  :disabled="agentStore.isResponseInProgress"
39
39
  >
40
40
  <p class="truncate">{{ session.title || session.sessionId }}</p>
@@ -99,13 +99,4 @@ const groupedSessions = computed(() => {
99
99
  return Array.from(groups.values());
100
100
  });
101
101
 
102
- const emit = defineEmits<{
103
- (e: 'recalculateScroll'): void
104
- }>()
105
-
106
- function recalculateScroll() {
107
- // Emit an event to notify the parent component to recalculate scroll
108
- emit('recalculateScroll');
109
- }
110
-
111
102
  </script>
@@ -1,12 +1,4 @@
1
1
  <template>
2
- <button @click="scrollContainer.scrollToBottom(); recalculateScroll();">
3
- <IconArrowDownOutline
4
- class="absolute z-10 bottom-32 left-1/2 bg-lightPrimary dark:bg-darkPrimary text-white p-2 w-10 h-10 rounded-full transition-opacity duration-100 ease-in"
5
- :class="showScrollToBottomButton ? 'opacity-100' : 'opacity-0 pointer-events-none'"
6
- :disabled="!showScrollToBottomButton"
7
- />
8
- </button>
9
-
10
2
  <SessionsHistory
11
3
  :class="agentStore.isSessionHistoryOpen ? 'translate-x-0' : '-translate-x-full'"
12
4
  @recalculateScroll="recalculateScroll"
@@ -16,38 +8,59 @@
16
8
  @click="agentStore.setSessionHistoryOpen(false)"
17
9
  class="absolute bg-black/10 backdrop-blur-md z-10 h-full w-full"
18
10
  >
19
-
20
11
  </div>
21
- <CustomAutoScrollContainer
22
- :enabled="!showScrollToBottomButton"
23
- class="relative flex flex-col overflow-y-auto translate-x-[-50%] left-1/2"
24
- ref="scrollContainer"
25
- :threshold="10"
26
- behavior="smooth"
27
- :style="{
28
- maxWidth: agentStore.isFullScreen ? agentStore.MAX_WIDTH+'rem' : '100%',
29
- transition: `
30
- max-width ${agentTransitions.TRANSITION_DURATION}ms ease-in-out,
31
- transform ${agentTransitions.TRANSITION_DURATION}ms ease-in-out
32
- `
33
- }"
34
- >
12
+ <div class="relative flex-1 min-h-0 overflow-hidden">
13
+ <button @click="scrollContainer.scrollToBottom(); recalculateScroll();">
14
+ <IconArrowDownOutline
15
+ class="absolute z-10 bottom-8 left-1/2 bg-lightPrimary dark:bg-darkPrimary text-white p-2 w-10 h-10 rounded-full transition-opacity duration-100 ease-in"
16
+ :class="showScrollToBottomButton ? 'opacity-100' : 'opacity-0 pointer-events-none'"
17
+ :disabled="!showScrollToBottomButton"
18
+ />
19
+ </button>
20
+ <CustomAutoScrollContainer
21
+ v-if="showScrollContainer"
22
+ :enabled="!showScrollToBottomButton"
23
+ class="relative h-full flex flex-col overflow-y-auto translate-x-[-50%] left-1/2"
24
+ ref="scrollContainer"
25
+ :threshold="10"
26
+ behavior="smooth"
27
+ :wrapperStyle = "{
28
+ height: '100%',
29
+ maxHeight: '100%',
30
+ maxWidth: agentStore.isFullScreen ? agentStore.MAX_WIDTH+'rem' : '100%',
31
+ width: '100%',
32
+ marginLeft: 'auto',
33
+ marginRight: 'auto',
34
+ }"
35
+ :contentStyle="{
36
+ height: '100%',
37
+ maxHeight: '100%',
38
+ }"
39
+ :style="{
40
+ maxWidth: agentStore.isFullScreen ? agentStore.MAX_WIDTH+'rem' : '100%',
41
+ transition: `
42
+ max-width ${agentTransitions.TRANSITION_DURATION}ms ease-in-out,
43
+ transform ${agentTransitions.TRANSITION_DURATION}ms ease-in-out
44
+ `
45
+ }"
46
+ >
35
47
 
36
- <div
37
- v-for="(message, index) in props.messages" :key="message.id"
38
- class="flex flex-col w-full"
39
- :class="message.role === 'user' ? 'self-end' : 'self-start'"
40
- >
41
- <MessageRenderer :message="message" :isLastMessageInChat="index === props.messages.length - 1"/>
42
- </div>
43
- <div
44
- v-if="props.messages.length === 0"
45
- class="flex-1 flex flex-col items-center justify-center text-gray-400 tracking-widest text-xl font-medium"
46
- >
47
- <p>{{ $t('Start the conversation') }}</p>
48
- <p class="tracking-normal text-base text">{{ $t('Give any input to begin') }}</p>
49
- </div>
50
- </CustomAutoScrollContainer>
48
+ <div
49
+ v-for="(message, index) in props.messages" :key="message.id"
50
+ class="flex flex-col w-full"
51
+ :class="message.role === 'user' ? 'self-end' : 'self-start'"
52
+ >
53
+ <MessageRenderer :message="message" :isLastMessageInChat="index === props.messages.length - 1"/>
54
+ </div>
55
+ <div
56
+ v-if="props.messages.length === 0"
57
+ class="flex-1 flex flex-col items-center justify-center text-gray-400 tracking-widest text-xl font-medium h-full"
58
+ >
59
+ <p>{{ $t('Start the conversation') }}</p>
60
+ <p class="tracking-normal text-base text">{{ $t('Give any input to begin') }}</p>
61
+ </div>
62
+ </CustomAutoScrollContainer>
63
+ </div>
51
64
  </template>
52
65
 
53
66
 
@@ -71,14 +84,24 @@ const innerScrollContainerRef = ref(null);
71
84
  const agentStore = useAgentStore();
72
85
  const agentTransitions = useAgentTransitions();
73
86
  const clicks = ref(0);
87
+ const showScrollContainer = ref(true);
74
88
 
75
89
  function recalculateScroll() {
76
90
  if (scrollContainer.value) {
91
+ scrollContainer.value.handleScroll();
77
92
  const isScrolledUp = scrollContainer.value.isUserScrolledUp();
78
93
  showScrollToBottomButton.value = !!isScrolledUp;
79
94
  }
80
95
  }
81
96
 
97
+ watch(() => agentStore.activeSessionId, async () => {
98
+ showScrollContainer.value = false;
99
+ await nextTick();
100
+ showScrollContainer.value = true;
101
+ await nextTick();
102
+ recalculateScroll();
103
+ });
104
+
82
105
  onMounted(async () => {
83
106
  await import('@incremark/theme/styles.css')
84
107
  await agentStore.fetchPlaceholderMessages()
@@ -90,7 +113,7 @@ onUnmounted(() => {
90
113
 
91
114
  watch(scrollContainer, () => {
92
115
  if (scrollContainer.value) {
93
- innerScrollContainerRef.value = scrollContainer.value.container;
116
+ innerScrollContainerRef.value = scrollContainer.value.container.scrollEl;
94
117
 
95
118
  innerScrollContainerRef.value.addEventListener('scroll', () => {
96
119
  recalculateScroll();
@@ -18,7 +18,9 @@
18
18
  behavior="smooth"
19
19
  v-if="ToolOrReasoningParts.length > 0"
20
20
  v-show="isExpanded"
21
- class="mask-y"
21
+ :wrapperStyle="{
22
+ marginRight: '8rem',
23
+ }"
22
24
  >
23
25
  <ol class="ml-8 relative border-l border-l-2 border-black border-default border-listTableHeadingText dark:border-darkListTableHeadingText">
24
26
  <li class="mb-6 ms-2 z-50" v-for="(part, index) in ToolOrReasoningParts" :key="index">
@@ -99,6 +101,7 @@
99
101
  durationMs: finishedPart?.data?.durationMs,
100
102
  input: part.data.input,
101
103
  output: finishedPart?.data?.output,
104
+ toolInfo: part.data.toolInfo,
102
105
  }
103
106
  };
104
107
  };
@@ -176,15 +179,5 @@
176
179
  opacity: 1;
177
180
  max-height: 384px;
178
181
  }
179
-
180
- .mask-y {
181
- mask-image: linear-gradient(
182
- to bottom,
183
- transparent,
184
- black 20px,
185
- black calc(100% - 20px),
186
- transparent
187
- );
188
- }
189
182
 
190
183
  </style>
@@ -16,15 +16,17 @@
16
16
  />
17
17
  </h3>
18
18
  <transition name="expand">
19
- <div v-show="isExpanded" class="overflow-hidden mb-4 text-sm mr-48 max-h-64 pl-4 ">
20
- <AutoScrollContainer
21
- :enabled="true"
22
- >
23
- <IncremarkContent
24
- :content="reasoningText"
25
- />
26
- </AutoScrollContainer>
27
- </div>
19
+ <CustomAutoScrollContainer
20
+ v-if="isExpanded" v-show="isExpanded" class="mb-4 text-sm max-h-64 pl-4"
21
+ :wrapperStyle="{
22
+ marginRight: '8rem',
23
+ }"
24
+ :enabled="true"
25
+ >
26
+ <IncremarkContent
27
+ :content="reasoningText"
28
+ />
29
+ </CustomAutoScrollContainer>
28
30
  </transition>
29
31
  </template>
30
32
 
@@ -37,10 +39,10 @@ import { ref, computed, watch, defineAsyncComponent } from 'vue';
37
39
  import ThreeDotsAnimation from './ThreeDotsAnimation.vue';
38
40
  import { extractTitleAndTextFromReasoning } from '../utils';
39
41
  import { useAgentStore } from '../composables/useAgentStore';
40
-
42
+ import CustomAutoScrollContainer from '../CustomAutoScrollContainer.vue';
41
43
 
42
44
  const IncremarkContent = defineAsyncComponent(() => import('@incremark/vue').then(module => module.IncremarkContent))
43
- const AutoScrollContainer = defineAsyncComponent(() => import('@incremark/vue').then(module => module.AutoScrollContainer))
45
+ // const AutoScrollContainer = defineAsyncComponent(() => import('@incremark/vue').then(module => module.AutoScrollContainer))
44
46
 
45
47
  const props = defineProps<{
46
48
  state?: IPart['state']
@@ -18,10 +18,10 @@
18
18
  "@shikijs/themes": "^4.0.2",
19
19
  "@vueuse/core": "^14.2.1",
20
20
  "ai": "^6.0.168",
21
+ "custom-vue-scrollbar": "^0.0.8",
21
22
  "dompurify": "^3.3.3",
22
23
  "katex": "^0.16.45",
23
24
  "marked": "^18.0.0",
24
- "vega-embed": "^7.1.0",
25
- "vue-custom-scrollbar": "^2.0.2"
25
+ "vega-embed": "^7.1.0"
26
26
  }
27
27
  }
@@ -29,6 +29,9 @@ importers:
29
29
  ai:
30
30
  specifier: ^6.0.168
31
31
  version: 6.0.168(zod@4.3.6)
32
+ custom-vue-scrollbar:
33
+ specifier: ^0.0.8
34
+ version: 0.0.8(lodash-es@4.18.1)(vue@3.5.32)
32
35
  dompurify:
33
36
  specifier: ^3.3.3
34
37
  version: 3.3.3
@@ -41,9 +44,6 @@ importers:
41
44
  vega-embed:
42
45
  specifier: ^7.1.0
43
46
  version: 7.1.0(vega-lite@6.4.2(vega@6.2.0))(vega@6.2.0)
44
- vue-custom-scrollbar:
45
- specifier: ^2.0.2
46
- version: 2.0.2(vue@3.5.32)
47
47
 
48
48
  packages:
49
49
 
@@ -307,6 +307,12 @@ packages:
307
307
  csstype@3.2.3:
308
308
  resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
309
309
 
310
+ custom-vue-scrollbar@0.0.8:
311
+ resolution: {integrity: sha512-JcO0B+02Kf9wXSL9SaxXVvuToaY+lvJAtmrwNfSLS3x6xx5+mO24r5/dGkNK8av0VlSDzviypYUXTjEZbwgGHA==}
312
+ peerDependencies:
313
+ lodash-es: ^4.17.21
314
+ vue: ^3.2.13
315
+
310
316
  d3-array@3.2.4:
311
317
  resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
312
318
  engines: {node: '>=12'}
@@ -656,9 +662,6 @@ packages:
656
662
  parse-entities@4.0.2:
657
663
  resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
658
664
 
659
- perfect-scrollbar@1.5.6:
660
- resolution: {integrity: sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw==}
661
-
662
665
  picocolors@1.1.1:
663
666
  resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
664
667
 
@@ -879,11 +882,6 @@ packages:
879
882
  vfile@6.0.3:
880
883
  resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
881
884
 
882
- vue-custom-scrollbar@2.0.2:
883
- resolution: {integrity: sha512-eRyxGb7UFLLH8P0B8FDux2uPrzNBH0X6IN+A/RB5sfmLq1ym7shbCPVKua1pC7LPqPB7dc86evFXyWO/svrfKA==}
884
- peerDependencies:
885
- vue: ^3.3.0
886
-
887
885
  vue@3.5.32:
888
886
  resolution: {integrity: sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==}
889
887
  peerDependencies:
@@ -1219,6 +1217,11 @@ snapshots:
1219
1217
 
1220
1218
  csstype@3.2.3: {}
1221
1219
 
1220
+ custom-vue-scrollbar@0.0.8(lodash-es@4.18.1)(vue@3.5.32):
1221
+ dependencies:
1222
+ lodash-es: 4.18.1
1223
+ vue: 3.5.32
1224
+
1222
1225
  d3-array@3.2.4:
1223
1226
  dependencies:
1224
1227
  internmap: 2.0.3
@@ -1766,8 +1769,6 @@ snapshots:
1766
1769
  is-decimal: 2.0.1
1767
1770
  is-hexadecimal: 2.0.1
1768
1771
 
1769
- perfect-scrollbar@1.5.6: {}
1770
-
1771
1772
  picocolors@1.1.1: {}
1772
1773
 
1773
1774
  postcss@8.5.10:
@@ -2142,11 +2143,6 @@ snapshots:
2142
2143
  '@types/unist': 3.0.3
2143
2144
  vfile-message: 4.0.3
2144
2145
 
2145
- vue-custom-scrollbar@2.0.2(vue@3.5.32):
2146
- dependencies:
2147
- perfect-scrollbar: 1.5.6
2148
- vue: 3.5.32
2149
-
2150
2146
  vue@3.5.32:
2151
2147
  dependencies:
2152
2148
  '@vue/compiler-dom': 3.5.32
package/custom/types.ts CHANGED
@@ -5,6 +5,7 @@ export interface IPartData {
5
5
  input?: any;
6
6
  output?: any;
7
7
  durationMs?: number;
8
+ toolInfo?: string;
8
9
  }
9
10
  export interface IPart {
10
11
  type: 'reasoning' | 'data-tool-call' | 'text';
@@ -32,7 +32,7 @@
32
32
  ></div>
33
33
 
34
34
  <div
35
- class="w-full h-full flex flex-col"
35
+ class="w-full min-h-0 max-h-full flex flex-col"
36
36
  >
37
37
  <div
38
38
  class="flex items-center justify-between h-14 border-b border-gray-200 dark:border-gray-700"
@@ -91,11 +91,10 @@
91
91
 
92
92
  </div>
93
93
  <div
94
- class="relative flex-1 flex flex-col overflow-hidden"
94
+ class="relative flex-1 min-h-0 flex flex-col overflow-hidden"
95
95
  >
96
96
  <ConversationArea
97
97
  v-if="agentStore.isChatOpen"
98
- class="flex-1 overflow-auto"
99
98
  :messages="agentStore.chatMessages"
100
99
  />
101
100
 
@@ -1,11 +1,29 @@
1
+ <template>
2
+ <CustomScrollbar
3
+ ref="containerRef"
4
+ class="auto-scroll-container mask-y"
5
+ :wrapperStyle = "wrapperStyle"
6
+ :contentStyle = "contentStyle"
7
+ >
8
+ <slot />
9
+ </CustomScrollbar>
10
+ </template>
11
+
1
12
  <script setup lang="ts">
2
13
  import { ref, watch, onMounted, onUnmounted, nextTick } from 'vue'
3
- import vueCustomScrollbar from 'vue-custom-scrollbar'
14
+ import CustomScrollbar from 'custom-vue-scrollbar';
15
+ import 'custom-vue-scrollbar/dist/style.css';
16
+ import { useScroll } from '@vueuse/core'
17
+ import { useAgentStore } from './composables/useAgentStore';
18
+
19
+ const agentStore = useAgentStore();
4
20
 
5
21
  const props = withDefaults(defineProps<{
6
22
  enabled?: boolean
7
23
  threshold?: number
8
24
  behavior?: ScrollBehavior
25
+ wrapperStyle?: Record<string, string>
26
+ contentStyle?: Record<string, string>
9
27
  }>(), {
10
28
  enabled: true,
11
29
  threshold: 50,
@@ -14,12 +32,18 @@ const props = withDefaults(defineProps<{
14
32
 
15
33
  const containerRef = ref<HTMLDivElement | null>(null)
16
34
  const isUserScrolledUp = ref(false)
35
+ const scrollElement = ref<HTMLElement | null>(null)
36
+ const { y } = useScroll(scrollElement)
37
+
38
+ watch(y, () => {
39
+ handleScroll()
40
+ })
17
41
 
18
42
  let lastScrollTop = 0
19
43
  let lastScrollHeight = 0
20
44
 
21
45
  function isNearBottom(): boolean {
22
- const container = containerRef.value
46
+ const container = containerRef.value?.scrollEl
23
47
  if (!container) return true
24
48
 
25
49
  const { scrollTop, scrollHeight, clientHeight } = container
@@ -27,7 +51,7 @@ function isNearBottom(): boolean {
27
51
  }
28
52
 
29
53
  function scrollToBottom(force = false): void {
30
- const container = containerRef.value
54
+ const container = containerRef.value?.scrollEl
31
55
  if (!container) return
32
56
 
33
57
  if (isUserScrolledUp.value && !force) return
@@ -40,14 +64,14 @@ function scrollToBottom(force = false): void {
40
64
 
41
65
 
42
66
  function hasScrollbar(): boolean {
43
- const container = containerRef.value
67
+ const container = containerRef.value?.scrollEl
44
68
  if (!container) return false
45
69
  return container.scrollHeight > container.clientHeight
46
70
  }
47
71
 
48
72
 
49
73
  function handleScroll(): void {
50
- const container = containerRef.value
74
+ const container = containerRef.value.scrollEl
51
75
  if (!container) return
52
76
 
53
77
  const { scrollTop, scrollHeight, clientHeight } = container
@@ -58,7 +82,6 @@ function handleScroll(): void {
58
82
  lastScrollHeight = scrollHeight
59
83
  return
60
84
  }
61
-
62
85
  if (isNearBottom()) {
63
86
  isUserScrolledUp.value = false
64
87
  } else {
@@ -69,7 +92,6 @@ function handleScroll(): void {
69
92
  isUserScrolledUp.value = true
70
93
  }
71
94
  }
72
-
73
95
  lastScrollTop = scrollTop
74
96
  lastScrollHeight = scrollHeight
75
97
  }
@@ -79,18 +101,19 @@ let observer: MutationObserver | null = null
79
101
  onMounted(() => {
80
102
  if (!containerRef.value) return
81
103
 
82
- lastScrollTop = containerRef.value.scrollTop
83
- lastScrollHeight = containerRef.value.scrollHeight
104
+ scrollElement.value = containerRef.value.scrollEl
105
+ lastScrollTop = containerRef.value.scrollEl.scrollTop
106
+ lastScrollHeight = containerRef.value.scrollEl.scrollHeight
84
107
 
85
108
  observer = new MutationObserver(() => {
86
109
  nextTick(() => {
87
- if (!containerRef.value) return
110
+ if (!containerRef.value?.scrollEl) return
88
111
 
89
112
  if (!hasScrollbar()) {
90
113
  isUserScrolledUp.value = false
91
114
  }
92
115
 
93
- lastScrollHeight = containerRef.value.scrollHeight
116
+ lastScrollHeight = containerRef.value.scrollEl.scrollHeight
94
117
 
95
118
  if (props.enabled && !isUserScrolledUp.value) {
96
119
  scrollToBottom()
@@ -98,7 +121,7 @@ onMounted(() => {
98
121
  })
99
122
  })
100
123
 
101
- observer.observe(containerRef.value, {
124
+ observer.observe(containerRef.value?.scrollEl, {
102
125
  childList: true,
103
126
  subtree: true,
104
127
  characterData: true
@@ -112,16 +135,19 @@ onUnmounted(() => {
112
135
  defineExpose({
113
136
  scrollToBottom: () => scrollToBottom(true),
114
137
  isUserScrolledUp: () => isUserScrolledUp.value,
115
- container: containerRef
138
+ container: containerRef,
139
+ handleScroll
116
140
  })
117
141
  </script>
118
142
 
119
- <template>
120
- <div
121
- ref="containerRef"
122
- class="auto-scroll-container h-full"
123
- @scroll="handleScroll"
124
- >
125
- <slot />
126
- </div>
127
- </template>
143
+ <style>
144
+ .mask-y {
145
+ mask-image: linear-gradient(
146
+ to bottom,
147
+ transparent,
148
+ black 20px,
149
+ black calc(100% - 20px),
150
+ transparent
151
+ );
152
+ }
153
+ </style>
@@ -8,7 +8,7 @@
8
8
  <h3 :class="h3Style">{{ $t('Chat history') }}</h3>
9
9
  <div class="w-full flex items-center justify-center">
10
10
  <Button
11
- @click="agentStore.createPreSession(); agentStore.setSessionHistoryOpen(false); agentStore.focusTextInput(); recalculateScroll();"
11
+ @click="agentStore.createPreSession(); agentStore.setSessionHistoryOpen(false); agentStore.focusTextInput();"
12
12
  :disabled="agentStore.isResponseInProgress"
13
13
  class="w-[90%] my-2 mb-4 rounded-3xl text-gray-800 dark:text-gray-200"
14
14
  >
@@ -34,7 +34,7 @@
34
34
  'bg-lightPrimary/20 hover:bg-lightPrimary/20 dark:bg-darkPrimary/20 dark:hover:bg-darkPrimary/20': agentStore.activeSessionId === session.sessionId,
35
35
  'cursor-default opacity-50 pointer-events-none': agentStore.isResponseInProgress,
36
36
  }"
37
- @click="agentStore.setActiveSession(session.sessionId); agentStore.setSessionHistoryOpen(false); recalculateScroll();"
37
+ @click="agentStore.setActiveSession(session.sessionId); agentStore.setSessionHistoryOpen(false);"
38
38
  :disabled="agentStore.isResponseInProgress"
39
39
  >
40
40
  <p class="truncate">{{ session.title || session.sessionId }}</p>
@@ -99,13 +99,4 @@ const groupedSessions = computed(() => {
99
99
  return Array.from(groups.values());
100
100
  });
101
101
 
102
- const emit = defineEmits<{
103
- (e: 'recalculateScroll'): void
104
- }>()
105
-
106
- function recalculateScroll() {
107
- // Emit an event to notify the parent component to recalculate scroll
108
- emit('recalculateScroll');
109
- }
110
-
111
102
  </script>
@@ -1,12 +1,4 @@
1
1
  <template>
2
- <button @click="scrollContainer.scrollToBottom(); recalculateScroll();">
3
- <IconArrowDownOutline
4
- class="absolute z-10 bottom-32 left-1/2 bg-lightPrimary dark:bg-darkPrimary text-white p-2 w-10 h-10 rounded-full transition-opacity duration-100 ease-in"
5
- :class="showScrollToBottomButton ? 'opacity-100' : 'opacity-0 pointer-events-none'"
6
- :disabled="!showScrollToBottomButton"
7
- />
8
- </button>
9
-
10
2
  <SessionsHistory
11
3
  :class="agentStore.isSessionHistoryOpen ? 'translate-x-0' : '-translate-x-full'"
12
4
  @recalculateScroll="recalculateScroll"
@@ -16,38 +8,59 @@
16
8
  @click="agentStore.setSessionHistoryOpen(false)"
17
9
  class="absolute bg-black/10 backdrop-blur-md z-10 h-full w-full"
18
10
  >
19
-
20
11
  </div>
21
- <CustomAutoScrollContainer
22
- :enabled="!showScrollToBottomButton"
23
- class="relative flex flex-col overflow-y-auto translate-x-[-50%] left-1/2"
24
- ref="scrollContainer"
25
- :threshold="10"
26
- behavior="smooth"
27
- :style="{
28
- maxWidth: agentStore.isFullScreen ? agentStore.MAX_WIDTH+'rem' : '100%',
29
- transition: `
30
- max-width ${agentTransitions.TRANSITION_DURATION}ms ease-in-out,
31
- transform ${agentTransitions.TRANSITION_DURATION}ms ease-in-out
32
- `
33
- }"
34
- >
12
+ <div class="relative flex-1 min-h-0 overflow-hidden">
13
+ <button @click="scrollContainer.scrollToBottom(); recalculateScroll();">
14
+ <IconArrowDownOutline
15
+ class="absolute z-10 bottom-8 left-1/2 bg-lightPrimary dark:bg-darkPrimary text-white p-2 w-10 h-10 rounded-full transition-opacity duration-100 ease-in"
16
+ :class="showScrollToBottomButton ? 'opacity-100' : 'opacity-0 pointer-events-none'"
17
+ :disabled="!showScrollToBottomButton"
18
+ />
19
+ </button>
20
+ <CustomAutoScrollContainer
21
+ v-if="showScrollContainer"
22
+ :enabled="!showScrollToBottomButton"
23
+ class="relative h-full flex flex-col overflow-y-auto translate-x-[-50%] left-1/2"
24
+ ref="scrollContainer"
25
+ :threshold="10"
26
+ behavior="smooth"
27
+ :wrapperStyle = "{
28
+ height: '100%',
29
+ maxHeight: '100%',
30
+ maxWidth: agentStore.isFullScreen ? agentStore.MAX_WIDTH+'rem' : '100%',
31
+ width: '100%',
32
+ marginLeft: 'auto',
33
+ marginRight: 'auto',
34
+ }"
35
+ :contentStyle="{
36
+ height: '100%',
37
+ maxHeight: '100%',
38
+ }"
39
+ :style="{
40
+ maxWidth: agentStore.isFullScreen ? agentStore.MAX_WIDTH+'rem' : '100%',
41
+ transition: `
42
+ max-width ${agentTransitions.TRANSITION_DURATION}ms ease-in-out,
43
+ transform ${agentTransitions.TRANSITION_DURATION}ms ease-in-out
44
+ `
45
+ }"
46
+ >
35
47
 
36
- <div
37
- v-for="(message, index) in props.messages" :key="message.id"
38
- class="flex flex-col w-full"
39
- :class="message.role === 'user' ? 'self-end' : 'self-start'"
40
- >
41
- <MessageRenderer :message="message" :isLastMessageInChat="index === props.messages.length - 1"/>
42
- </div>
43
- <div
44
- v-if="props.messages.length === 0"
45
- class="flex-1 flex flex-col items-center justify-center text-gray-400 tracking-widest text-xl font-medium"
46
- >
47
- <p>{{ $t('Start the conversation') }}</p>
48
- <p class="tracking-normal text-base text">{{ $t('Give any input to begin') }}</p>
49
- </div>
50
- </CustomAutoScrollContainer>
48
+ <div
49
+ v-for="(message, index) in props.messages" :key="message.id"
50
+ class="flex flex-col w-full"
51
+ :class="message.role === 'user' ? 'self-end' : 'self-start'"
52
+ >
53
+ <MessageRenderer :message="message" :isLastMessageInChat="index === props.messages.length - 1"/>
54
+ </div>
55
+ <div
56
+ v-if="props.messages.length === 0"
57
+ class="flex-1 flex flex-col items-center justify-center text-gray-400 tracking-widest text-xl font-medium h-full"
58
+ >
59
+ <p>{{ $t('Start the conversation') }}</p>
60
+ <p class="tracking-normal text-base text">{{ $t('Give any input to begin') }}</p>
61
+ </div>
62
+ </CustomAutoScrollContainer>
63
+ </div>
51
64
  </template>
52
65
 
53
66
 
@@ -71,14 +84,24 @@ const innerScrollContainerRef = ref(null);
71
84
  const agentStore = useAgentStore();
72
85
  const agentTransitions = useAgentTransitions();
73
86
  const clicks = ref(0);
87
+ const showScrollContainer = ref(true);
74
88
 
75
89
  function recalculateScroll() {
76
90
  if (scrollContainer.value) {
91
+ scrollContainer.value.handleScroll();
77
92
  const isScrolledUp = scrollContainer.value.isUserScrolledUp();
78
93
  showScrollToBottomButton.value = !!isScrolledUp;
79
94
  }
80
95
  }
81
96
 
97
+ watch(() => agentStore.activeSessionId, async () => {
98
+ showScrollContainer.value = false;
99
+ await nextTick();
100
+ showScrollContainer.value = true;
101
+ await nextTick();
102
+ recalculateScroll();
103
+ });
104
+
82
105
  onMounted(async () => {
83
106
  await import('@incremark/theme/styles.css')
84
107
  await agentStore.fetchPlaceholderMessages()
@@ -90,7 +113,7 @@ onUnmounted(() => {
90
113
 
91
114
  watch(scrollContainer, () => {
92
115
  if (scrollContainer.value) {
93
- innerScrollContainerRef.value = scrollContainer.value.container;
116
+ innerScrollContainerRef.value = scrollContainer.value.container.scrollEl;
94
117
 
95
118
  innerScrollContainerRef.value.addEventListener('scroll', () => {
96
119
  recalculateScroll();
@@ -18,7 +18,9 @@
18
18
  behavior="smooth"
19
19
  v-if="ToolOrReasoningParts.length > 0"
20
20
  v-show="isExpanded"
21
- class="mask-y"
21
+ :wrapperStyle="{
22
+ marginRight: '8rem',
23
+ }"
22
24
  >
23
25
  <ol class="ml-8 relative border-l border-l-2 border-black border-default border-listTableHeadingText dark:border-darkListTableHeadingText">
24
26
  <li class="mb-6 ms-2 z-50" v-for="(part, index) in ToolOrReasoningParts" :key="index">
@@ -99,6 +101,7 @@
99
101
  durationMs: finishedPart?.data?.durationMs,
100
102
  input: part.data.input,
101
103
  output: finishedPart?.data?.output,
104
+ toolInfo: part.data.toolInfo,
102
105
  }
103
106
  };
104
107
  };
@@ -176,15 +179,5 @@
176
179
  opacity: 1;
177
180
  max-height: 384px;
178
181
  }
179
-
180
- .mask-y {
181
- mask-image: linear-gradient(
182
- to bottom,
183
- transparent,
184
- black 20px,
185
- black calc(100% - 20px),
186
- transparent
187
- );
188
- }
189
182
 
190
183
  </style>
@@ -16,15 +16,17 @@
16
16
  />
17
17
  </h3>
18
18
  <transition name="expand">
19
- <div v-show="isExpanded" class="overflow-hidden mb-4 text-sm mr-48 max-h-64 pl-4 ">
20
- <AutoScrollContainer
21
- :enabled="true"
22
- >
23
- <IncremarkContent
24
- :content="reasoningText"
25
- />
26
- </AutoScrollContainer>
27
- </div>
19
+ <CustomAutoScrollContainer
20
+ v-if="isExpanded" v-show="isExpanded" class="mb-4 text-sm max-h-64 pl-4"
21
+ :wrapperStyle="{
22
+ marginRight: '8rem',
23
+ }"
24
+ :enabled="true"
25
+ >
26
+ <IncremarkContent
27
+ :content="reasoningText"
28
+ />
29
+ </CustomAutoScrollContainer>
28
30
  </transition>
29
31
  </template>
30
32
 
@@ -37,10 +39,10 @@ import { ref, computed, watch, defineAsyncComponent } from 'vue';
37
39
  import ThreeDotsAnimation from './ThreeDotsAnimation.vue';
38
40
  import { extractTitleAndTextFromReasoning } from '../utils';
39
41
  import { useAgentStore } from '../composables/useAgentStore';
40
-
42
+ import CustomAutoScrollContainer from '../CustomAutoScrollContainer.vue';
41
43
 
42
44
  const IncremarkContent = defineAsyncComponent(() => import('@incremark/vue').then(module => module.IncremarkContent))
43
- const AutoScrollContainer = defineAsyncComponent(() => import('@incremark/vue').then(module => module.AutoScrollContainer))
45
+ // const AutoScrollContainer = defineAsyncComponent(() => import('@incremark/vue').then(module => module.AutoScrollContainer))
44
46
 
45
47
  const props = defineProps<{
46
48
  state?: IPart['state']
@@ -18,10 +18,10 @@
18
18
  "@shikijs/themes": "^4.0.2",
19
19
  "@vueuse/core": "^14.2.1",
20
20
  "ai": "^6.0.168",
21
+ "custom-vue-scrollbar": "^0.0.8",
21
22
  "dompurify": "^3.3.3",
22
23
  "katex": "^0.16.45",
23
24
  "marked": "^18.0.0",
24
- "vega-embed": "^7.1.0",
25
- "vue-custom-scrollbar": "^2.0.2"
25
+ "vega-embed": "^7.1.0"
26
26
  }
27
27
  }
@@ -29,6 +29,9 @@ importers:
29
29
  ai:
30
30
  specifier: ^6.0.168
31
31
  version: 6.0.168(zod@4.3.6)
32
+ custom-vue-scrollbar:
33
+ specifier: ^0.0.8
34
+ version: 0.0.8(lodash-es@4.18.1)(vue@3.5.32)
32
35
  dompurify:
33
36
  specifier: ^3.3.3
34
37
  version: 3.3.3
@@ -41,9 +44,6 @@ importers:
41
44
  vega-embed:
42
45
  specifier: ^7.1.0
43
46
  version: 7.1.0(vega-lite@6.4.2(vega@6.2.0))(vega@6.2.0)
44
- vue-custom-scrollbar:
45
- specifier: ^2.0.2
46
- version: 2.0.2(vue@3.5.32)
47
47
 
48
48
  packages:
49
49
 
@@ -307,6 +307,12 @@ packages:
307
307
  csstype@3.2.3:
308
308
  resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
309
309
 
310
+ custom-vue-scrollbar@0.0.8:
311
+ resolution: {integrity: sha512-JcO0B+02Kf9wXSL9SaxXVvuToaY+lvJAtmrwNfSLS3x6xx5+mO24r5/dGkNK8av0VlSDzviypYUXTjEZbwgGHA==}
312
+ peerDependencies:
313
+ lodash-es: ^4.17.21
314
+ vue: ^3.2.13
315
+
310
316
  d3-array@3.2.4:
311
317
  resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
312
318
  engines: {node: '>=12'}
@@ -656,9 +662,6 @@ packages:
656
662
  parse-entities@4.0.2:
657
663
  resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
658
664
 
659
- perfect-scrollbar@1.5.6:
660
- resolution: {integrity: sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw==}
661
-
662
665
  picocolors@1.1.1:
663
666
  resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
664
667
 
@@ -879,11 +882,6 @@ packages:
879
882
  vfile@6.0.3:
880
883
  resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
881
884
 
882
- vue-custom-scrollbar@2.0.2:
883
- resolution: {integrity: sha512-eRyxGb7UFLLH8P0B8FDux2uPrzNBH0X6IN+A/RB5sfmLq1ym7shbCPVKua1pC7LPqPB7dc86evFXyWO/svrfKA==}
884
- peerDependencies:
885
- vue: ^3.3.0
886
-
887
885
  vue@3.5.32:
888
886
  resolution: {integrity: sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==}
889
887
  peerDependencies:
@@ -1219,6 +1217,11 @@ snapshots:
1219
1217
 
1220
1218
  csstype@3.2.3: {}
1221
1219
 
1220
+ custom-vue-scrollbar@0.0.8(lodash-es@4.18.1)(vue@3.5.32):
1221
+ dependencies:
1222
+ lodash-es: 4.18.1
1223
+ vue: 3.5.32
1224
+
1222
1225
  d3-array@3.2.4:
1223
1226
  dependencies:
1224
1227
  internmap: 2.0.3
@@ -1766,8 +1769,6 @@ snapshots:
1766
1769
  is-decimal: 2.0.1
1767
1770
  is-hexadecimal: 2.0.1
1768
1771
 
1769
- perfect-scrollbar@1.5.6: {}
1770
-
1771
1772
  picocolors@1.1.1: {}
1772
1773
 
1773
1774
  postcss@8.5.10:
@@ -2142,11 +2143,6 @@ snapshots:
2142
2143
  '@types/unist': 3.0.3
2143
2144
  vfile-message: 4.0.3
2144
2145
 
2145
- vue-custom-scrollbar@2.0.2(vue@3.5.32):
2146
- dependencies:
2147
- perfect-scrollbar: 1.5.6
2148
- vue: 3.5.32
2149
-
2150
2146
  vue@3.5.32:
2151
2147
  dependencies:
2152
2148
  '@vue/compiler-dom': 3.5.32
@@ -5,6 +5,7 @@ export interface IPartData {
5
5
  input?: any;
6
6
  output?: any;
7
7
  durationMs?: number;
8
+ toolInfo?: string;
8
9
  }
9
10
  export interface IPart {
10
11
  type: 'reasoning' | 'data-tool-call' | 'text';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/agent",
3
- "version": "1.24.4",
3
+ "version": "1.24.5",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",