@adminforth/agent 1.14.0 → 1.15.0
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 +2 -2
- package/custom/ChatSurface.vue +1 -1
- package/custom/ConversationArea.vue +6 -1
- package/custom/Message.vue +6 -1
- package/custom/composables/useAgentStore.ts +130 -4
- package/dist/custom/ChatSurface.vue +1 -1
- package/dist/custom/ConversationArea.vue +6 -1
- package/dist/custom/Message.vue +6 -1
- package/dist/custom/composables/useAgentStore.ts +130 -4
- package/dist/index.js +25 -0
- package/index.ts +27 -0
- package/package.json +1 -1
- package/types.ts +15 -1
package/build.log
CHANGED
|
@@ -31,5 +31,5 @@ custom/skills/fetch_data/SKILL.md
|
|
|
31
31
|
custom/skills/mutate_data/
|
|
32
32
|
custom/skills/mutate_data/SKILL.md
|
|
33
33
|
|
|
34
|
-
sent
|
|
35
|
-
total size is
|
|
34
|
+
sent 184,200 bytes received 436 bytes 369,272.00 bytes/sec
|
|
35
|
+
total size is 182,411 speedup is 0.99
|
package/custom/ChatSurface.vue
CHANGED
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
'min-h-12 w-full resize-none overflow-hidden border text-lightInputText dark:text-darkInputText rounded-md bg-transparent text-sm bg-gray-50 dark:bg-gray-700 dark:border-gray-600 focus:outline-none',
|
|
112
112
|
agentStore.availableModes.length > 1 ? 'p-4 pr-12 pb-12' : 'p-4 pr-12',
|
|
113
113
|
]"
|
|
114
|
-
placeholder="
|
|
114
|
+
:placeholder="agentStore.userMessagePlaceholder"
|
|
115
115
|
@keydown.enter.exact.prevent="sendMessage"
|
|
116
116
|
/>
|
|
117
117
|
<div
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
<script setup lang="ts">
|
|
75
75
|
import Message from './Message.vue';
|
|
76
76
|
import type { IMessage, IPart } from './types';
|
|
77
|
-
import { useTemplateRef, ref, defineAsyncComponent, onMounted, watch, computed } from 'vue';
|
|
77
|
+
import { useTemplateRef, ref, defineAsyncComponent, onMounted, onUnmounted, watch, computed } from 'vue';
|
|
78
78
|
import { IconArrowDownOutline } from '@iconify-prerendered/vue-flowbite';
|
|
79
79
|
import SessionsHistory from './SessionsHistory.vue';
|
|
80
80
|
import { useAgentStore } from './composables/useAgentStore';
|
|
@@ -98,6 +98,11 @@ function recalculateScroll() {
|
|
|
98
98
|
|
|
99
99
|
onMounted(async () => {
|
|
100
100
|
await import('@incremark/theme/styles.css')
|
|
101
|
+
await agentStore.fetchPlaceholderMessages()
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
onUnmounted(() => {
|
|
105
|
+
agentStore.stopPlaceholderAnimation();
|
|
101
106
|
});
|
|
102
107
|
|
|
103
108
|
watch(scrollContainer, () => {
|
package/custom/Message.vue
CHANGED
|
@@ -57,10 +57,12 @@
|
|
|
57
57
|
import { computed, defineAsyncComponent, onMounted, ref, watch } from 'vue';
|
|
58
58
|
import { useRouter } from 'vue-router';
|
|
59
59
|
import { IconAngleDownOutline } from '@iconify-prerendered/vue-flowbite';
|
|
60
|
-
|
|
60
|
+
import { useAgentStore } from './composables/useAgentStore';
|
|
61
61
|
const IncremarkContent = defineAsyncComponent(() => import('@incremark/vue').then(module => module.IncremarkContent))
|
|
62
62
|
const ShikiCodeBlock = defineAsyncComponent(() => import('./incremark_code_renderers/IncremarkShikiCodeBlock.vue'))
|
|
63
63
|
|
|
64
|
+
const agentStore = useAgentStore();
|
|
65
|
+
|
|
64
66
|
const incremarkComponents = {
|
|
65
67
|
code: ShikiCodeBlock,
|
|
66
68
|
};
|
|
@@ -132,6 +134,9 @@
|
|
|
132
134
|
|
|
133
135
|
const internalRoute = resolveInternalRoute(href);
|
|
134
136
|
if (internalRoute !== null) {
|
|
137
|
+
if (agentStore.isFullScreen) {
|
|
138
|
+
agentStore.setFullScreen(false);
|
|
139
|
+
}
|
|
135
140
|
void router.push(internalRoute);
|
|
136
141
|
return;
|
|
137
142
|
}
|
|
@@ -12,6 +12,11 @@ type AgentMode = {
|
|
|
12
12
|
name: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
const DEFAULT_TEXTAREA_PLACEHOLDER = 'Type a message...';
|
|
16
|
+
const PLACEHOLDER_TYPING_DELAY_MS = 60;
|
|
17
|
+
const PLACEHOLDER_DELETING_DELAY_MS = 35;
|
|
18
|
+
const PLACEHOLDER_HOLD_DELAY_MS = 3000;
|
|
19
|
+
|
|
15
20
|
export const useAgentStore = defineStore('agent', () => {
|
|
16
21
|
const DEFAULT_CHAT_WIDTH = 600;
|
|
17
22
|
const MAX_WIDTH = 800;
|
|
@@ -25,8 +30,10 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
25
30
|
const adminforth = useAdminforth();
|
|
26
31
|
const isChatOpen = ref(false);
|
|
27
32
|
const isSessionHistoryOpen = ref(false);
|
|
28
|
-
const textInput = ref<
|
|
33
|
+
const textInput = ref<HTMLTextAreaElement | null>(null);
|
|
29
34
|
const userMessageInput = ref();
|
|
35
|
+
const userMessagePlaceholder = ref(DEFAULT_TEXTAREA_PLACEHOLDER);
|
|
36
|
+
const placeholderMessages = ref<string[]>([]);
|
|
30
37
|
const trimmedUserMessage = computed(() => userMessageInput.value ? userMessageInput.value.trim() : '');
|
|
31
38
|
const lastMessage = ref('');
|
|
32
39
|
const isTeleportedToBody = ref(false);
|
|
@@ -40,6 +47,9 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
40
47
|
const chatWidth = ref(DEFAULT_CHAT_WIDTH);
|
|
41
48
|
const availableModes = ref<AgentMode[]>([]);
|
|
42
49
|
const activeModeName = ref<string | null>(null);
|
|
50
|
+
const hasTypedMessageInPageSession = ref(false);
|
|
51
|
+
let placeholderAnimationTimer: ReturnType<typeof setTimeout> | null = null;
|
|
52
|
+
|
|
43
53
|
function setLocalStorageItem(key: string, value: string) {
|
|
44
54
|
window.localStorage.setItem(`${coreStore.config.brandName || 'adminforth'}-${key}`, value);
|
|
45
55
|
}
|
|
@@ -60,6 +70,16 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
60
70
|
setLocalStorageItem('lastSessionId', newVal);
|
|
61
71
|
}
|
|
62
72
|
})
|
|
73
|
+
watch(userMessageInput, (newVal: unknown) => {
|
|
74
|
+
if (hasTypedMessageInPageSession.value) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (typeof newVal === 'string' && newVal.trim() !== '') {
|
|
79
|
+
hasTypedMessageInPageSession.value = true;
|
|
80
|
+
stopPlaceholderAnimation();
|
|
81
|
+
}
|
|
82
|
+
})
|
|
63
83
|
onMounted(() => {
|
|
64
84
|
const chatWidthBeforeFullScreen = parseInt(getLocalStorageItem('chatWidthBeforeFullScreen') || '0', 10);
|
|
65
85
|
if (chatWidthBeforeFullScreen) {
|
|
@@ -130,14 +150,14 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
130
150
|
function setAvailableModes(modes: AgentMode[], defaultModeName?: string | null) {
|
|
131
151
|
availableModes.value = modes;
|
|
132
152
|
activeModeName.value =
|
|
133
|
-
modes.find((mode) => mode.name === activeModeName.value)?.name
|
|
153
|
+
modes.find((mode: AgentMode) => mode.name === activeModeName.value)?.name
|
|
134
154
|
?? defaultModeName
|
|
135
155
|
?? modes[0]?.name
|
|
136
156
|
?? null;
|
|
137
157
|
}
|
|
138
158
|
|
|
139
159
|
function setActiveMode(modeName: string) {
|
|
140
|
-
if (!availableModes.value.some((mode) => mode.name === modeName)) {
|
|
160
|
+
if (!availableModes.value.some((mode: AgentMode) => mode.name === modeName)) {
|
|
141
161
|
return;
|
|
142
162
|
}
|
|
143
163
|
|
|
@@ -179,6 +199,73 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
179
199
|
}
|
|
180
200
|
|
|
181
201
|
}
|
|
202
|
+
|
|
203
|
+
function clearPlaceholderAnimationTimer() {
|
|
204
|
+
if (placeholderAnimationTimer !== null) {
|
|
205
|
+
clearTimeout(placeholderAnimationTimer);
|
|
206
|
+
placeholderAnimationTimer = null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function resetPlaceholder() {
|
|
211
|
+
clearPlaceholderAnimationTimer();
|
|
212
|
+
userMessagePlaceholder.value = DEFAULT_TEXTAREA_PLACEHOLDER;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function stopPlaceholderAnimation() {
|
|
216
|
+
resetPlaceholder();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function startPlaceholderAnimation(messages: string[]) {
|
|
220
|
+
clearPlaceholderAnimationTimer();
|
|
221
|
+
|
|
222
|
+
if (!messages.length) {
|
|
223
|
+
userMessagePlaceholder.value = DEFAULT_TEXTAREA_PLACEHOLDER;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
let messageIndex = 0;
|
|
228
|
+
let visibleLength = 0;
|
|
229
|
+
let isDeleting = false;
|
|
230
|
+
|
|
231
|
+
const animate = () => {
|
|
232
|
+
const currentMessage = messages[messageIndex];
|
|
233
|
+
|
|
234
|
+
if (!currentMessage) {
|
|
235
|
+
resetPlaceholder();
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!isDeleting) {
|
|
240
|
+
visibleLength += 1;
|
|
241
|
+
userMessagePlaceholder.value = currentMessage.slice(0, visibleLength);
|
|
242
|
+
|
|
243
|
+
if (visibleLength >= currentMessage.length) {
|
|
244
|
+
isDeleting = true;
|
|
245
|
+
placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_HOLD_DELAY_MS);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_TYPING_DELAY_MS);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
visibleLength -= 1;
|
|
254
|
+
userMessagePlaceholder.value = currentMessage.slice(0, Math.max(visibleLength, 0));
|
|
255
|
+
|
|
256
|
+
if (visibleLength <= 0) {
|
|
257
|
+
isDeleting = false;
|
|
258
|
+
messageIndex = (messageIndex + 1) % messages.length;
|
|
259
|
+
placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_TYPING_DELAY_MS);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_DELETING_DELAY_MS);
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
animate();
|
|
267
|
+
}
|
|
268
|
+
|
|
182
269
|
const isResponseInProgress = computed( () => {
|
|
183
270
|
return currentChat.value?.status === 'streaming';
|
|
184
271
|
});
|
|
@@ -234,10 +321,46 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
234
321
|
function setSessionHistoryOpen(isOpen: boolean) {
|
|
235
322
|
isSessionHistoryOpen.value = isOpen;
|
|
236
323
|
}
|
|
237
|
-
function regisrerTextInput(el:
|
|
324
|
+
function regisrerTextInput(el: HTMLTextAreaElement | null) {
|
|
238
325
|
textInput.value = el;
|
|
239
326
|
}
|
|
240
327
|
|
|
328
|
+
async function fetchPlaceholderMessages() {
|
|
329
|
+
if (hasTypedMessageInPageSession.value) {
|
|
330
|
+
stopPlaceholderAnimation();
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
const res = await callAdminForthApi({
|
|
336
|
+
method: 'POST',
|
|
337
|
+
path: '/agent/get-placeholder-messages',
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
if (res.error) {
|
|
341
|
+
console.error('Error fetching placeholder messages:', res.error);
|
|
342
|
+
placeholderMessages.value = [];
|
|
343
|
+
resetPlaceholder();
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
placeholderMessages.value = Array.isArray(res.messages)
|
|
348
|
+
? res.messages.filter((message: unknown): message is string => typeof message === 'string' && message.length > 0)
|
|
349
|
+
: [];
|
|
350
|
+
|
|
351
|
+
if (!placeholderMessages.value.length) {
|
|
352
|
+
resetPlaceholder();
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
startPlaceholderAnimation(placeholderMessages.value);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.error('Error fetching placeholder messages', error);
|
|
359
|
+
placeholderMessages.value = [];
|
|
360
|
+
resetPlaceholder();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
241
364
|
|
|
242
365
|
//create a pre-session, until user will type something, so we can save session
|
|
243
366
|
async function createPreSession() {
|
|
@@ -409,12 +532,15 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
409
532
|
createPreSession,
|
|
410
533
|
//____________________________________________
|
|
411
534
|
regisrerTextInput,
|
|
535
|
+
fetchPlaceholderMessages,
|
|
536
|
+
stopPlaceholderAnimation,
|
|
412
537
|
isChatOpen,
|
|
413
538
|
setIsChatOpen,
|
|
414
539
|
isSessionHistoryOpen,
|
|
415
540
|
setSessionHistoryOpen,
|
|
416
541
|
sendMessage,
|
|
417
542
|
userMessageInput,
|
|
543
|
+
userMessagePlaceholder,
|
|
418
544
|
chatMessages: computed(() => currentChat.value?.messages || []),
|
|
419
545
|
trimmedUserMessage,
|
|
420
546
|
isResponseInProgress,
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
'min-h-12 w-full resize-none overflow-hidden border text-lightInputText dark:text-darkInputText rounded-md bg-transparent text-sm bg-gray-50 dark:bg-gray-700 dark:border-gray-600 focus:outline-none',
|
|
112
112
|
agentStore.availableModes.length > 1 ? 'p-4 pr-12 pb-12' : 'p-4 pr-12',
|
|
113
113
|
]"
|
|
114
|
-
placeholder="
|
|
114
|
+
:placeholder="agentStore.userMessagePlaceholder"
|
|
115
115
|
@keydown.enter.exact.prevent="sendMessage"
|
|
116
116
|
/>
|
|
117
117
|
<div
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
<script setup lang="ts">
|
|
75
75
|
import Message from './Message.vue';
|
|
76
76
|
import type { IMessage, IPart } from './types';
|
|
77
|
-
import { useTemplateRef, ref, defineAsyncComponent, onMounted, watch, computed } from 'vue';
|
|
77
|
+
import { useTemplateRef, ref, defineAsyncComponent, onMounted, onUnmounted, watch, computed } from 'vue';
|
|
78
78
|
import { IconArrowDownOutline } from '@iconify-prerendered/vue-flowbite';
|
|
79
79
|
import SessionsHistory from './SessionsHistory.vue';
|
|
80
80
|
import { useAgentStore } from './composables/useAgentStore';
|
|
@@ -98,6 +98,11 @@ function recalculateScroll() {
|
|
|
98
98
|
|
|
99
99
|
onMounted(async () => {
|
|
100
100
|
await import('@incremark/theme/styles.css')
|
|
101
|
+
await agentStore.fetchPlaceholderMessages()
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
onUnmounted(() => {
|
|
105
|
+
agentStore.stopPlaceholderAnimation();
|
|
101
106
|
});
|
|
102
107
|
|
|
103
108
|
watch(scrollContainer, () => {
|
package/dist/custom/Message.vue
CHANGED
|
@@ -57,10 +57,12 @@
|
|
|
57
57
|
import { computed, defineAsyncComponent, onMounted, ref, watch } from 'vue';
|
|
58
58
|
import { useRouter } from 'vue-router';
|
|
59
59
|
import { IconAngleDownOutline } from '@iconify-prerendered/vue-flowbite';
|
|
60
|
-
|
|
60
|
+
import { useAgentStore } from './composables/useAgentStore';
|
|
61
61
|
const IncremarkContent = defineAsyncComponent(() => import('@incremark/vue').then(module => module.IncremarkContent))
|
|
62
62
|
const ShikiCodeBlock = defineAsyncComponent(() => import('./incremark_code_renderers/IncremarkShikiCodeBlock.vue'))
|
|
63
63
|
|
|
64
|
+
const agentStore = useAgentStore();
|
|
65
|
+
|
|
64
66
|
const incremarkComponents = {
|
|
65
67
|
code: ShikiCodeBlock,
|
|
66
68
|
};
|
|
@@ -132,6 +134,9 @@
|
|
|
132
134
|
|
|
133
135
|
const internalRoute = resolveInternalRoute(href);
|
|
134
136
|
if (internalRoute !== null) {
|
|
137
|
+
if (agentStore.isFullScreen) {
|
|
138
|
+
agentStore.setFullScreen(false);
|
|
139
|
+
}
|
|
135
140
|
void router.push(internalRoute);
|
|
136
141
|
return;
|
|
137
142
|
}
|
|
@@ -12,6 +12,11 @@ type AgentMode = {
|
|
|
12
12
|
name: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
const DEFAULT_TEXTAREA_PLACEHOLDER = 'Type a message...';
|
|
16
|
+
const PLACEHOLDER_TYPING_DELAY_MS = 60;
|
|
17
|
+
const PLACEHOLDER_DELETING_DELAY_MS = 35;
|
|
18
|
+
const PLACEHOLDER_HOLD_DELAY_MS = 3000;
|
|
19
|
+
|
|
15
20
|
export const useAgentStore = defineStore('agent', () => {
|
|
16
21
|
const DEFAULT_CHAT_WIDTH = 600;
|
|
17
22
|
const MAX_WIDTH = 800;
|
|
@@ -25,8 +30,10 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
25
30
|
const adminforth = useAdminforth();
|
|
26
31
|
const isChatOpen = ref(false);
|
|
27
32
|
const isSessionHistoryOpen = ref(false);
|
|
28
|
-
const textInput = ref<
|
|
33
|
+
const textInput = ref<HTMLTextAreaElement | null>(null);
|
|
29
34
|
const userMessageInput = ref();
|
|
35
|
+
const userMessagePlaceholder = ref(DEFAULT_TEXTAREA_PLACEHOLDER);
|
|
36
|
+
const placeholderMessages = ref<string[]>([]);
|
|
30
37
|
const trimmedUserMessage = computed(() => userMessageInput.value ? userMessageInput.value.trim() : '');
|
|
31
38
|
const lastMessage = ref('');
|
|
32
39
|
const isTeleportedToBody = ref(false);
|
|
@@ -40,6 +47,9 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
40
47
|
const chatWidth = ref(DEFAULT_CHAT_WIDTH);
|
|
41
48
|
const availableModes = ref<AgentMode[]>([]);
|
|
42
49
|
const activeModeName = ref<string | null>(null);
|
|
50
|
+
const hasTypedMessageInPageSession = ref(false);
|
|
51
|
+
let placeholderAnimationTimer: ReturnType<typeof setTimeout> | null = null;
|
|
52
|
+
|
|
43
53
|
function setLocalStorageItem(key: string, value: string) {
|
|
44
54
|
window.localStorage.setItem(`${coreStore.config.brandName || 'adminforth'}-${key}`, value);
|
|
45
55
|
}
|
|
@@ -60,6 +70,16 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
60
70
|
setLocalStorageItem('lastSessionId', newVal);
|
|
61
71
|
}
|
|
62
72
|
})
|
|
73
|
+
watch(userMessageInput, (newVal: unknown) => {
|
|
74
|
+
if (hasTypedMessageInPageSession.value) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (typeof newVal === 'string' && newVal.trim() !== '') {
|
|
79
|
+
hasTypedMessageInPageSession.value = true;
|
|
80
|
+
stopPlaceholderAnimation();
|
|
81
|
+
}
|
|
82
|
+
})
|
|
63
83
|
onMounted(() => {
|
|
64
84
|
const chatWidthBeforeFullScreen = parseInt(getLocalStorageItem('chatWidthBeforeFullScreen') || '0', 10);
|
|
65
85
|
if (chatWidthBeforeFullScreen) {
|
|
@@ -130,14 +150,14 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
130
150
|
function setAvailableModes(modes: AgentMode[], defaultModeName?: string | null) {
|
|
131
151
|
availableModes.value = modes;
|
|
132
152
|
activeModeName.value =
|
|
133
|
-
modes.find((mode) => mode.name === activeModeName.value)?.name
|
|
153
|
+
modes.find((mode: AgentMode) => mode.name === activeModeName.value)?.name
|
|
134
154
|
?? defaultModeName
|
|
135
155
|
?? modes[0]?.name
|
|
136
156
|
?? null;
|
|
137
157
|
}
|
|
138
158
|
|
|
139
159
|
function setActiveMode(modeName: string) {
|
|
140
|
-
if (!availableModes.value.some((mode) => mode.name === modeName)) {
|
|
160
|
+
if (!availableModes.value.some((mode: AgentMode) => mode.name === modeName)) {
|
|
141
161
|
return;
|
|
142
162
|
}
|
|
143
163
|
|
|
@@ -179,6 +199,73 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
179
199
|
}
|
|
180
200
|
|
|
181
201
|
}
|
|
202
|
+
|
|
203
|
+
function clearPlaceholderAnimationTimer() {
|
|
204
|
+
if (placeholderAnimationTimer !== null) {
|
|
205
|
+
clearTimeout(placeholderAnimationTimer);
|
|
206
|
+
placeholderAnimationTimer = null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function resetPlaceholder() {
|
|
211
|
+
clearPlaceholderAnimationTimer();
|
|
212
|
+
userMessagePlaceholder.value = DEFAULT_TEXTAREA_PLACEHOLDER;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function stopPlaceholderAnimation() {
|
|
216
|
+
resetPlaceholder();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function startPlaceholderAnimation(messages: string[]) {
|
|
220
|
+
clearPlaceholderAnimationTimer();
|
|
221
|
+
|
|
222
|
+
if (!messages.length) {
|
|
223
|
+
userMessagePlaceholder.value = DEFAULT_TEXTAREA_PLACEHOLDER;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
let messageIndex = 0;
|
|
228
|
+
let visibleLength = 0;
|
|
229
|
+
let isDeleting = false;
|
|
230
|
+
|
|
231
|
+
const animate = () => {
|
|
232
|
+
const currentMessage = messages[messageIndex];
|
|
233
|
+
|
|
234
|
+
if (!currentMessage) {
|
|
235
|
+
resetPlaceholder();
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!isDeleting) {
|
|
240
|
+
visibleLength += 1;
|
|
241
|
+
userMessagePlaceholder.value = currentMessage.slice(0, visibleLength);
|
|
242
|
+
|
|
243
|
+
if (visibleLength >= currentMessage.length) {
|
|
244
|
+
isDeleting = true;
|
|
245
|
+
placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_HOLD_DELAY_MS);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_TYPING_DELAY_MS);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
visibleLength -= 1;
|
|
254
|
+
userMessagePlaceholder.value = currentMessage.slice(0, Math.max(visibleLength, 0));
|
|
255
|
+
|
|
256
|
+
if (visibleLength <= 0) {
|
|
257
|
+
isDeleting = false;
|
|
258
|
+
messageIndex = (messageIndex + 1) % messages.length;
|
|
259
|
+
placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_TYPING_DELAY_MS);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_DELETING_DELAY_MS);
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
animate();
|
|
267
|
+
}
|
|
268
|
+
|
|
182
269
|
const isResponseInProgress = computed( () => {
|
|
183
270
|
return currentChat.value?.status === 'streaming';
|
|
184
271
|
});
|
|
@@ -234,10 +321,46 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
234
321
|
function setSessionHistoryOpen(isOpen: boolean) {
|
|
235
322
|
isSessionHistoryOpen.value = isOpen;
|
|
236
323
|
}
|
|
237
|
-
function regisrerTextInput(el:
|
|
324
|
+
function regisrerTextInput(el: HTMLTextAreaElement | null) {
|
|
238
325
|
textInput.value = el;
|
|
239
326
|
}
|
|
240
327
|
|
|
328
|
+
async function fetchPlaceholderMessages() {
|
|
329
|
+
if (hasTypedMessageInPageSession.value) {
|
|
330
|
+
stopPlaceholderAnimation();
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
const res = await callAdminForthApi({
|
|
336
|
+
method: 'POST',
|
|
337
|
+
path: '/agent/get-placeholder-messages',
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
if (res.error) {
|
|
341
|
+
console.error('Error fetching placeholder messages:', res.error);
|
|
342
|
+
placeholderMessages.value = [];
|
|
343
|
+
resetPlaceholder();
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
placeholderMessages.value = Array.isArray(res.messages)
|
|
348
|
+
? res.messages.filter((message: unknown): message is string => typeof message === 'string' && message.length > 0)
|
|
349
|
+
: [];
|
|
350
|
+
|
|
351
|
+
if (!placeholderMessages.value.length) {
|
|
352
|
+
resetPlaceholder();
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
startPlaceholderAnimation(placeholderMessages.value);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.error('Error fetching placeholder messages', error);
|
|
359
|
+
placeholderMessages.value = [];
|
|
360
|
+
resetPlaceholder();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
241
364
|
|
|
242
365
|
//create a pre-session, until user will type something, so we can save session
|
|
243
366
|
async function createPreSession() {
|
|
@@ -409,12 +532,15 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
409
532
|
createPreSession,
|
|
410
533
|
//____________________________________________
|
|
411
534
|
regisrerTextInput,
|
|
535
|
+
fetchPlaceholderMessages,
|
|
536
|
+
stopPlaceholderAnimation,
|
|
412
537
|
isChatOpen,
|
|
413
538
|
setIsChatOpen,
|
|
414
539
|
isSessionHistoryOpen,
|
|
415
540
|
setSessionHistoryOpen,
|
|
416
541
|
sendMessage,
|
|
417
542
|
userMessageInput,
|
|
543
|
+
userMessagePlaceholder,
|
|
418
544
|
chatMessages: computed(() => currentChat.value?.messages || []),
|
|
419
545
|
trimmedUserMessage,
|
|
420
546
|
isResponseInProgress,
|
package/dist/index.js
CHANGED
|
@@ -133,6 +133,31 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
133
133
|
return `single`;
|
|
134
134
|
}
|
|
135
135
|
setupEndpoints(server) {
|
|
136
|
+
server.endpoint({
|
|
137
|
+
method: 'POST',
|
|
138
|
+
path: `/agent/get-placeholder-messages`,
|
|
139
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, query, headers, cookies, adminUser, response, requestUrl }) {
|
|
140
|
+
if (!this.options.placeholderMessages) {
|
|
141
|
+
return {
|
|
142
|
+
messages: [],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const messages = yield this.options.placeholderMessages({
|
|
146
|
+
adminUser,
|
|
147
|
+
httpExtra: {
|
|
148
|
+
body,
|
|
149
|
+
query,
|
|
150
|
+
headers,
|
|
151
|
+
cookies,
|
|
152
|
+
requestUrl,
|
|
153
|
+
response,
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
return {
|
|
157
|
+
messages,
|
|
158
|
+
};
|
|
159
|
+
})
|
|
160
|
+
});
|
|
136
161
|
server.endpoint({
|
|
137
162
|
method: 'POST',
|
|
138
163
|
path: `/agent/response`,
|
package/index.ts
CHANGED
|
@@ -147,6 +147,33 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
setupEndpoints(server: IHttpServer) {
|
|
150
|
+
server.endpoint({
|
|
151
|
+
method: 'POST',
|
|
152
|
+
path: `/agent/get-placeholder-messages`,
|
|
153
|
+
handler: async ({ body, query, headers, cookies, adminUser, response, requestUrl }) => {
|
|
154
|
+
if (!this.options.placeholderMessages) {
|
|
155
|
+
return {
|
|
156
|
+
messages: [],
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const messages = await this.options.placeholderMessages({
|
|
161
|
+
adminUser,
|
|
162
|
+
httpExtra: {
|
|
163
|
+
body,
|
|
164
|
+
query,
|
|
165
|
+
headers,
|
|
166
|
+
cookies,
|
|
167
|
+
requestUrl,
|
|
168
|
+
response,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
messages,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
});
|
|
150
177
|
server.endpoint({
|
|
151
178
|
method: 'POST',
|
|
152
179
|
path: `/agent/response`,
|
package/package.json
CHANGED
package/types.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type PluginsCommonOptions,
|
|
3
|
+
type CompletionAdapter,
|
|
4
|
+
type AdminUser,
|
|
5
|
+
type HttpExtra,
|
|
6
|
+
} from "adminforth";
|
|
2
7
|
|
|
3
8
|
interface ISessionResource {
|
|
4
9
|
resourceId: string;
|
|
@@ -20,6 +25,15 @@ interface ITurnResource {
|
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
export interface PluginOptions extends PluginsCommonOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Optional placeholder examples to preload for the chat textarea.
|
|
30
|
+
* They are resolved once when the chat frontend loads.
|
|
31
|
+
*/
|
|
32
|
+
placeholderMessages?: ((input: {
|
|
33
|
+
adminUser: AdminUser;
|
|
34
|
+
httpExtra: HttpExtra;
|
|
35
|
+
}) => string[] | Promise<string[]>);
|
|
36
|
+
|
|
23
37
|
/**
|
|
24
38
|
* Modes for the plugin.
|
|
25
39
|
* Each mode can have its own configuration.
|