@adminforth/agent 1.35.0 → 1.36.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.
@@ -0,0 +1,142 @@
1
+ import { ref, watch, type Ref } from 'vue';
2
+ import { callAdminForthApi } from '@/utils';
3
+ import {
4
+ DEFAULT_TEXTAREA_PLACEHOLDER,
5
+ PLACEHOLDER_DELETING_DELAY_MS,
6
+ PLACEHOLDER_HOLD_DELAY_MS,
7
+ PLACEHOLDER_TYPING_DELAY_MS,
8
+ } from './constants';
9
+
10
+ type CreateAgentPlaceholderControllerOptions = {
11
+ userMessageInput: Ref<unknown>;
12
+ };
13
+
14
+ export function createAgentPlaceholderController({
15
+ userMessageInput,
16
+ }: CreateAgentPlaceholderControllerOptions) {
17
+ const userMessagePlaceholder = ref(DEFAULT_TEXTAREA_PLACEHOLDER);
18
+ const placeholderMessages = ref<string[]>([]);
19
+ const hasTypedMessageInPageSession = ref(false);
20
+
21
+ let placeholderAnimationTimer: ReturnType<typeof setTimeout> | null = null;
22
+
23
+ function clearPlaceholderAnimationTimer() {
24
+ if (placeholderAnimationTimer !== null) {
25
+ clearTimeout(placeholderAnimationTimer);
26
+ placeholderAnimationTimer = null;
27
+ }
28
+ }
29
+
30
+ function resetPlaceholder() {
31
+ clearPlaceholderAnimationTimer();
32
+ userMessagePlaceholder.value = DEFAULT_TEXTAREA_PLACEHOLDER;
33
+ }
34
+
35
+ function stopPlaceholderAnimation() {
36
+ resetPlaceholder();
37
+ }
38
+
39
+ function startPlaceholderAnimation(messages: string[]) {
40
+ clearPlaceholderAnimationTimer();
41
+
42
+ if (!messages.length) {
43
+ userMessagePlaceholder.value = DEFAULT_TEXTAREA_PLACEHOLDER;
44
+ return;
45
+ }
46
+
47
+ let messageIndex = 0;
48
+ let visibleLength = 0;
49
+ let isDeleting = false;
50
+
51
+ const animate = () => {
52
+ const currentMessage = messages[messageIndex];
53
+
54
+ if (!currentMessage) {
55
+ resetPlaceholder();
56
+ return;
57
+ }
58
+
59
+ if (!isDeleting) {
60
+ visibleLength += 1;
61
+ userMessagePlaceholder.value = currentMessage.slice(0, visibleLength);
62
+
63
+ if (visibleLength >= currentMessage.length) {
64
+ isDeleting = true;
65
+ placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_HOLD_DELAY_MS);
66
+ return;
67
+ }
68
+
69
+ placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_TYPING_DELAY_MS);
70
+ return;
71
+ }
72
+
73
+ visibleLength -= 1;
74
+ userMessagePlaceholder.value = currentMessage.slice(0, Math.max(visibleLength, 0));
75
+
76
+ if (visibleLength <= 0) {
77
+ isDeleting = false;
78
+ messageIndex = (messageIndex + 1) % messages.length;
79
+ placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_TYPING_DELAY_MS);
80
+ return;
81
+ }
82
+
83
+ placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_DELETING_DELAY_MS);
84
+ };
85
+
86
+ animate();
87
+ }
88
+
89
+ async function fetchPlaceholderMessages() {
90
+ if (hasTypedMessageInPageSession.value) {
91
+ stopPlaceholderAnimation();
92
+ return;
93
+ }
94
+
95
+ try {
96
+ const res = await callAdminForthApi({
97
+ method: 'POST',
98
+ path: '/agent/get-placeholder-messages',
99
+ });
100
+
101
+ if (res.error) {
102
+ console.error('Error fetching placeholder messages:', res.error);
103
+ placeholderMessages.value = [];
104
+ resetPlaceholder();
105
+ return;
106
+ }
107
+
108
+ placeholderMessages.value = Array.isArray(res.messages)
109
+ ? res.messages.filter((message: unknown): message is string => typeof message === 'string' && message.length > 0)
110
+ : [];
111
+
112
+ if (!placeholderMessages.value.length) {
113
+ resetPlaceholder();
114
+ return;
115
+ }
116
+
117
+ startPlaceholderAnimation(placeholderMessages.value);
118
+ } catch (error) {
119
+ console.error('Error fetching placeholder messages', error);
120
+ placeholderMessages.value = [];
121
+ resetPlaceholder();
122
+ }
123
+ }
124
+
125
+ watch(userMessageInput, (newVal: unknown) => {
126
+ if (hasTypedMessageInPageSession.value) {
127
+ return;
128
+ }
129
+
130
+ if (typeof newVal === 'string' && newVal.trim() !== '') {
131
+ hasTypedMessageInPageSession.value = true;
132
+ stopPlaceholderAnimation();
133
+ }
134
+ });
135
+
136
+ return {
137
+ userMessagePlaceholder,
138
+ hasTypedMessageInPageSession,
139
+ fetchPlaceholderMessages,
140
+ stopPlaceholderAnimation,
141
+ };
142
+ }
@@ -0,0 +1,270 @@
1
+ import type { ComputedRef, Ref, ShallowRef } from 'vue';
2
+ import { callAdminForthApi } from '@/utils';
3
+ import type { Chat } from '../../chat';
4
+ import type { IAgentSession, ISessionsListItem, IPart } from '../../types';
5
+
6
+ type AdminforthLike = {
7
+ confirm(options: { message: string; yes: string; no: string }): Promise<boolean>;
8
+ };
9
+
10
+ type CreateAgentSessionManagerOptions = {
11
+ activeSessionId: Ref<string | null>;
12
+ currentSession: Ref<IAgentSession | null>;
13
+ sessionList: Ref<ISessionsListItem[]>;
14
+ sessions: Ref<Record<string, IAgentSession>>;
15
+ currentChat: ShallowRef<Chat<any> | null | undefined>;
16
+ trimmedUserMessage: ComputedRef<string>;
17
+ isResponseInProgress: ComputedRef<boolean>;
18
+ userMessageInput: Ref<any>;
19
+ lastMessage: Ref<string>;
20
+ blockCloseOfChat: Ref<boolean>;
21
+ adminforth: AdminforthLike;
22
+ setCurrentChat: (sessionId: string) => void;
23
+ };
24
+
25
+ export function createAgentSessionManager({
26
+ activeSessionId,
27
+ currentSession,
28
+ sessionList,
29
+ sessions,
30
+ currentChat,
31
+ trimmedUserMessage,
32
+ isResponseInProgress,
33
+ userMessageInput,
34
+ lastMessage,
35
+ blockCloseOfChat,
36
+ adminforth,
37
+ setCurrentChat,
38
+ }: CreateAgentSessionManagerOptions) {
39
+ function sortSessionsListByTimestamp(sessionsListToSort: ISessionsListItem[]) {
40
+ return [...sessionsListToSort].sort((a: ISessionsListItem, b: ISessionsListItem) => b.timestamp.localeCompare(a.timestamp));
41
+ }
42
+
43
+ function saveCurrentSessionInCache() {
44
+ if (currentSession.value) {
45
+ currentSession.value.messages = currentChat.value?.messages.map((m: any) => ({
46
+ role: m.role,
47
+ text: m.parts.map((p: IPart) => p.type === 'text' ? p.text : '').join(''),
48
+ })) || [];
49
+ sessions.value[currentSession.value.sessionId] = currentSession.value;
50
+ }
51
+ }
52
+
53
+ async function fetchSession(sessionId: string) {
54
+ try {
55
+ const res = await callAdminForthApi({
56
+ method: 'POST',
57
+ path: '/agent/get-session-info',
58
+ body: { sessionId },
59
+ });
60
+ if (res.error) {
61
+ console.error('Error fetching session:', res.error);
62
+ return;
63
+ }
64
+ sessions.value[sessionId] = res.session;
65
+ setCurrentChat(sessionId);
66
+ } catch (error) {
67
+ console.error('Error fetching session', error);
68
+ }
69
+ }
70
+
71
+ async function setActiveSession(sessionId: string) {
72
+ activeSessionId.value = sessionId;
73
+ saveCurrentSessionInCache();
74
+ if (!sessions.value[sessionId]) {
75
+ await fetchSession(sessionId);
76
+ }
77
+ currentSession.value = sessions.value[sessionId];
78
+ setCurrentChat(sessionId);
79
+ if (currentChat.value.messages.length === 0) {
80
+ currentChat.value.messages = currentSession.value?.messages.map((m: any) => ({
81
+ role: m.role,
82
+ parts:[{
83
+ type: 'text',
84
+ text: m.text,
85
+ state: 'done',
86
+ }]
87
+ }));
88
+ }
89
+ }
90
+
91
+ async function deletePreSession() {
92
+ sessionList.value = sessionList.value.filter((s: ISessionsListItem) => s.sessionId !== 'pre-session');
93
+ if (activeSessionId.value === 'pre-session') {
94
+ activeSessionId.value = null;
95
+ currentSession.value = null;
96
+ }
97
+ }
98
+
99
+ async function createNewSession(triggerMessage?: string) {
100
+ try {
101
+ const res = await callAdminForthApi({
102
+ method: 'POST',
103
+ path: '/agent/create-session',
104
+ body: {
105
+ triggerMessage
106
+ },
107
+ });
108
+ if (res.error) {
109
+ console.error('Error creating new session:', res.error);
110
+ return;
111
+ }
112
+ deletePreSession();
113
+ sessions.value[res.sessionId] = res;
114
+ sessionList.value.unshift({
115
+ sessionId: res.sessionId,
116
+ title: res.title,
117
+ timestamp: new Date().toISOString(),
118
+ });
119
+ setActiveSession(res.sessionId);
120
+ } catch (error) {
121
+ console.error('Error creating new session', error);
122
+ }
123
+ }
124
+
125
+ async function sendMessage() {
126
+ const message = trimmedUserMessage.value;
127
+ if (!message || isResponseInProgress.value) {
128
+ return;
129
+ }
130
+ if (!currentSession.value || currentSession.value.sessionId === 'pre-session') {
131
+ await createNewSession(message);
132
+ }
133
+ currentSession.value!.timestamp = new Date().toISOString();
134
+ sessionList.value = sortSessionsListByTimestamp(sessionList.value.map((s: ISessionsListItem) => s.sessionId === currentSession.value?.sessionId ? {
135
+ ...s,
136
+ timestamp: currentSession.value?.timestamp || s.timestamp,
137
+ } : s));
138
+ lastMessage.value = message;
139
+ currentChat.value?.sendMessage({
140
+ text: message,
141
+ });
142
+ userMessageInput.value = '';
143
+ }
144
+
145
+ async function createPreSession() {
146
+ saveCurrentSessionInCache();
147
+ if (!sessionList.value.some((s: ISessionsListItem) => s.sessionId === 'pre-session')) {
148
+ sessionList.value.unshift({
149
+ sessionId: 'pre-session',
150
+ title: 'New Session',
151
+ timestamp: new Date().toISOString(),
152
+ });
153
+ }
154
+
155
+ activeSessionId.value = 'pre-session';
156
+ currentSession.value = {
157
+ sessionId: 'pre-session',
158
+ title: 'New Session',
159
+ timestamp: new Date().toISOString(),
160
+ messages: [],
161
+ };
162
+ sessions.value['pre-session'] = currentSession.value;
163
+ setCurrentChat('pre-session');
164
+ }
165
+
166
+ async function deleteSession(sessionId: string) {
167
+ if (sessionId === 'pre-session') {
168
+ deletePreSession();
169
+ return;
170
+ }
171
+ blockCloseOfChat.value = true;
172
+ const isConfirmed = await adminforth.confirm({message: 'Are you sure, that you want to delete this session?', yes: 'Yes', no: 'No'});
173
+ blockCloseOfChat.value = false;
174
+ if (!isConfirmed) {
175
+ return;
176
+ }
177
+ try {
178
+ const res = await callAdminForthApi({
179
+ method: 'POST',
180
+ path: '/agent/delete-session',
181
+ body: { sessionId },
182
+ });
183
+ if (res.error) {
184
+ console.error('Error deleting session:', res.error);
185
+ return;
186
+ }
187
+ delete sessions.value[sessionId];
188
+ sessionList.value = sessionList.value.filter((s: ISessionsListItem) => s.sessionId !== sessionId);
189
+ if (activeSessionId.value === sessionId) {
190
+ activeSessionId.value = null;
191
+ currentSession.value = null;
192
+ }
193
+ } catch (error) {
194
+ console.error('Error deleting session', error);
195
+ }
196
+ if(sessionId === activeSessionId.value) {
197
+ activeSessionId.value = sessionList.value.length > 0 ? sessionList.value[0].sessionId : null;
198
+ if (activeSessionId.value) {
199
+ currentSession.value = sessions.value[activeSessionId.value] || null;
200
+ } else {
201
+ currentSession.value = null;
202
+ }
203
+ }
204
+ }
205
+
206
+ async function fetchSessionsList() {
207
+ try {
208
+ const res = await callAdminForthApi({
209
+ method: 'POST',
210
+ path: '/agent/get-sessions',
211
+ body: {
212
+ limit: 100,
213
+ },
214
+ });
215
+ if (res.error) {
216
+ console.error('Error fetching sessions list:', res.error);
217
+ return;
218
+ }
219
+ sessionList.value = res.sessions;
220
+ } catch (error) {
221
+ console.error('Error fetching sessions list', error);
222
+ }
223
+ }
224
+
225
+ function addDebugMessage(message: string) {
226
+ const debugMessage = {
227
+ role: 'assistant',
228
+ parts: [{
229
+ type: 'text',
230
+ text: message,
231
+ state: 'done',
232
+ }]
233
+ };
234
+ currentChat.value?.messages.push(debugMessage);
235
+ }
236
+
237
+ function addSystemMessage(message: string) {
238
+ const systemMessage = {
239
+ role: 'system',
240
+ parts: [{
241
+ type: 'text',
242
+ text: message,
243
+ state: 'done',
244
+ }]
245
+ };
246
+ currentChat.value?.messages.push(systemMessage);
247
+ try {
248
+ const res = callAdminForthApi({
249
+ method: 'POST',
250
+ path: '/agent/add-system-message-to-turns',
251
+ body: {
252
+ sessionId: activeSessionId.value,
253
+ systemMessage: message,
254
+ },
255
+ });
256
+ } catch (error) {
257
+ console.error('Error adding system message', error);
258
+ }
259
+ }
260
+
261
+ return {
262
+ sendMessage,
263
+ createPreSession,
264
+ setActiveSession,
265
+ fetchSessionsList,
266
+ deleteSession,
267
+ addDebugMessage,
268
+ addSystemMessage,
269
+ };
270
+ }