@adminforth/agent 1.34.2 → 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.
@@ -1,37 +1,22 @@
1
1
  import { defineStore } from 'pinia';
2
- import { IAgentSession, ISessionsListItem, IMessage, IPart } from '../types';
3
- import { ref, nextTick, computed, watch, onMounted, shallowRef } from 'vue';
4
- import { callAdminForthApi } from '@/utils';
2
+ import { IAgentSession, ISessionsListItem } from '../types';
3
+ import { ref, nextTick, computed, watch, onMounted } from 'vue';
5
4
  import { useAdminforth } from '@/adminforth';
6
- import { Chat } from '../chat';
7
- import { DefaultChatTransport } from 'ai';
8
5
  import { useCoreStore } from '@/stores/core';
9
6
  import { useAgentTransitions } from './useAgentTransitions';
10
7
  import { useWindowSize } from '@vueuse/core';
11
8
  import { remToPx, pxToRem } from '../utils';
12
-
13
- type AgentMode = {
14
- name: string;
15
- };
16
-
17
- function getCurrentPageContext() {
18
- return {
19
- path: window.location.pathname,
20
- fullPath: `${window.location.pathname}${window.location.search}${window.location.hash}`,
21
- title: document.title,
22
- url: window.location.href,
23
- };
24
- }
25
-
26
- const DEFAULT_TEXTAREA_PLACEHOLDER = 'Type a message...';
27
- const PLACEHOLDER_TYPING_DELAY_MS = 60;
28
- const PLACEHOLDER_DELETING_DELAY_MS = 35;
29
- const PLACEHOLDER_HOLD_DELAY_MS = 3000;
9
+ import {
10
+ type AgentMode,
11
+ DEFAULT_CHAT_WIDTH,
12
+ MAX_WIDTH,
13
+ MIN_WIDTH,
14
+ } from './agentStore/constants';
15
+ import { createAgentChatManager } from './agentStore/useAgentChat';
16
+ import { createAgentPlaceholderController } from './agentStore/useAgentPlaceholder';
17
+ import { createAgentSessionManager } from './agentStore/useAgentSessions';
30
18
 
31
19
  export const useAgentStore = defineStore('agent', () => {
32
- const DEFAULT_CHAT_WIDTH = 30;
33
- const MAX_WIDTH = 60;
34
- const MIN_WIDTH = 25
35
20
  const agentTransitions = useAgentTransitions();
36
21
 
37
22
  const activeSessionId = ref<string | null>(null);
@@ -43,8 +28,6 @@ export const useAgentStore = defineStore('agent', () => {
43
28
  const isSessionHistoryOpen = ref(false);
44
29
  const textInput = ref<HTMLTextAreaElement | null>(null);
45
30
  const userMessageInput = ref();
46
- const userMessagePlaceholder = ref(DEFAULT_TEXTAREA_PLACEHOLDER);
47
- const placeholderMessages = ref<string[]>([]);
48
31
  const trimmedUserMessage = computed(() => userMessageInput.value ? userMessageInput.value.trim() : '');
49
32
  const lastMessage = ref('');
50
33
  const isTeleportedToBody = ref(false);
@@ -58,13 +41,24 @@ export const useAgentStore = defineStore('agent', () => {
58
41
  const chatWidth = ref(DEFAULT_CHAT_WIDTH);
59
42
  const availableModes = ref<AgentMode[]>([]);
60
43
  const activeModeName = ref<string | null>(null);
61
- const hasTypedMessageInPageSession = ref(false);
62
44
  const { width: windowWidth } = useWindowSize();
63
45
 
64
- const chats = new Map<string, Chat<any>>();
65
- const currentChat = shallowRef<Chat<any>>();
66
-
67
- let placeholderAnimationTimer: ReturnType<typeof setTimeout> | null = null;
46
+ const {
47
+ currentChat,
48
+ setCurrentChat,
49
+ abortCurrentChatRequest,
50
+ } = createAgentChatManager({
51
+ lastMessage,
52
+ activeModeName,
53
+ });
54
+ const {
55
+ userMessagePlaceholder,
56
+ hasTypedMessageInPageSession,
57
+ fetchPlaceholderMessages,
58
+ stopPlaceholderAnimation,
59
+ } = createAgentPlaceholderController({
60
+ userMessageInput,
61
+ });
68
62
 
69
63
  function setLocalStorageItem(key: string, value: string) {
70
64
  window.localStorage.setItem(`${coreStore.config.brandName || 'adminforth'}-${key}`, value);
@@ -72,7 +66,35 @@ export const useAgentStore = defineStore('agent', () => {
72
66
  function getLocalStorageItem(key: string) {
73
67
  return window.localStorage.getItem(`${coreStore.config.brandName || 'adminforth'}-${key}`);
74
68
  }
75
- watch(windowWidth, (newWidth: number) => {
69
+
70
+ const isResponseInProgress = computed( () => {
71
+ return currentChat.value?.status === 'streaming';
72
+ });
73
+ const blockCloseOfChat = ref(false);
74
+ const {
75
+ sendMessage,
76
+ createPreSession,
77
+ setActiveSession,
78
+ fetchSessionsList,
79
+ deleteSession,
80
+ addDebugMessage,
81
+ addSystemMessage,
82
+ } = createAgentSessionManager({
83
+ activeSessionId,
84
+ currentSession,
85
+ sessionList,
86
+ sessions,
87
+ currentChat,
88
+ trimmedUserMessage,
89
+ isResponseInProgress,
90
+ userMessageInput,
91
+ lastMessage,
92
+ blockCloseOfChat,
93
+ adminforth,
94
+ setCurrentChat,
95
+ });
96
+
97
+ watch(() => windowWidth.value, (newWidth) => {
76
98
  if (isFullScreen.value) {
77
99
  setChatWidth(newWidth, false);
78
100
  }
@@ -94,16 +116,6 @@ export const useAgentStore = defineStore('agent', () => {
94
116
  setLocalStorageItem('lastSessionId', newVal);
95
117
  }
96
118
  })
97
- watch(userMessageInput, (newVal: unknown) => {
98
- if (hasTypedMessageInPageSession.value) {
99
- return;
100
- }
101
-
102
- if (typeof newVal === 'string' && newVal.trim() !== '') {
103
- hasTypedMessageInPageSession.value = true;
104
- stopPlaceholderAnimation();
105
- }
106
- })
107
119
  onMounted(() => {
108
120
  const chatWidthBeforeFullScreen = parseInt(getLocalStorageItem('chatWidthBeforeFullScreen') || '0', 10);
109
121
  if (chatWidthBeforeFullScreen && (chatWidthBeforeFullScreen > MAX_WIDTH || chatWidthBeforeFullScreen < MIN_WIDTH)) {
@@ -122,10 +134,11 @@ export const useAgentStore = defineStore('agent', () => {
122
134
  }
123
135
  if (!coreStore.isMobile) {
124
136
  const savedIsTeleportedToBody = getLocalStorageItem('isTeleportedToBody');
137
+ const savedIsTeleportedToBodyBeforeFullScreen = getLocalStorageItem('isTeleportedToBodyBeforeFullScreen');
138
+ const isTeleportedToBodyFromLocalStorage = savedIsTeleportedToBody === 'true' || savedIsTeleportedToBodyBeforeFullScreen === 'true';
125
139
  const savedIsChatOpen = getLocalStorageItem('isChatOpen');
126
- const shouldTeleportToBody = savedIsTeleportedToBody === null ? true : savedIsTeleportedToBody === 'true';
127
140
 
128
- setIsTeleportedToBody(shouldTeleportToBody);
141
+ setIsTeleportedToBody(isTeleportedToBodyFromLocalStorage);
129
142
  if (isTeleportedToBody.value) {
130
143
  isChatOpen.value = savedIsChatOpen === null ? true : savedIsChatOpen === 'true';
131
144
  }
@@ -137,10 +150,6 @@ export const useAgentStore = defineStore('agent', () => {
137
150
  if (coreStore.isMobile) {
138
151
  setChatWidth(window.innerWidth);
139
152
  }
140
- const ativeModeNameFromLocalStorage = getLocalStorageItem('activeModeName');
141
- if (ativeModeNameFromLocalStorage) {
142
- setActiveMode(ativeModeNameFromLocalStorage);
143
- }
144
153
  appRoot.value = document.getElementById('app');
145
154
  header.value = document.getElementById('af-header-nav');
146
155
  if (appRoot.value && header.value) {
@@ -207,6 +216,13 @@ export const useAgentStore = defineStore('agent', () => {
207
216
  ?? null;
208
217
  }
209
218
 
219
+ function setCurrentGenerationModeFromLocalStorage() {
220
+ const activeModeNameFromLocalStorage = getLocalStorageItem('activeModeName');
221
+ if (activeModeNameFromLocalStorage) {
222
+ setActiveMode(activeModeNameFromLocalStorage);
223
+ }
224
+ }
225
+
210
226
  function setActiveMode(modeName: string) {
211
227
  if (!availableModes.value.some((mode: AgentMode) => mode.name === modeName)) {
212
228
  return;
@@ -215,138 +231,6 @@ export const useAgentStore = defineStore('agent', () => {
215
231
  activeModeName.value = modeName;
216
232
  }
217
233
 
218
- function setCurrentChat(sessionId: string) {
219
- if (chats.has(sessionId)) {
220
- currentChat.value = chats.get(sessionId) || null;
221
- } else {
222
- const newChat = new Chat({
223
- transport: new DefaultChatTransport({
224
- api: `${import.meta.env.VITE_ADMINFORTH_PUBLIC_PATH || ''}/adminapi/v1/agent/response`,
225
- credentials: 'include',
226
- prepareSendMessagesRequest({ messages }: any) {
227
- const message = lastMessage.value;
228
- const body = {
229
- message,
230
- sessionId,
231
- timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
232
- mode: activeModeName.value,
233
- currentPage: getCurrentPageContext(),
234
- };
235
-
236
- return {
237
- headers: {
238
- Accept: 'text/event-stream',
239
- 'x-vercel-ai-ui-message-stream': 'v1',
240
- },
241
- body
242
- };
243
- }
244
- }),
245
- onError(error: unknown) {
246
- console.error("Chat error:", error);
247
- },
248
- });
249
- chats.set(sessionId, newChat);
250
- currentChat.value = newChat;
251
- }
252
-
253
- }
254
-
255
- function clearPlaceholderAnimationTimer() {
256
- if (placeholderAnimationTimer !== null) {
257
- clearTimeout(placeholderAnimationTimer);
258
- placeholderAnimationTimer = null;
259
- }
260
- }
261
-
262
- function resetPlaceholder() {
263
- clearPlaceholderAnimationTimer();
264
- userMessagePlaceholder.value = DEFAULT_TEXTAREA_PLACEHOLDER;
265
- }
266
-
267
- function stopPlaceholderAnimation() {
268
- resetPlaceholder();
269
- }
270
-
271
- function startPlaceholderAnimation(messages: string[]) {
272
- clearPlaceholderAnimationTimer();
273
-
274
- if (!messages.length) {
275
- userMessagePlaceholder.value = DEFAULT_TEXTAREA_PLACEHOLDER;
276
- return;
277
- }
278
-
279
- let messageIndex = 0;
280
- let visibleLength = 0;
281
- let isDeleting = false;
282
-
283
- const animate = () => {
284
- const currentMessage = messages[messageIndex];
285
-
286
- if (!currentMessage) {
287
- resetPlaceholder();
288
- return;
289
- }
290
-
291
- if (!isDeleting) {
292
- visibleLength += 1;
293
- userMessagePlaceholder.value = currentMessage.slice(0, visibleLength);
294
-
295
- if (visibleLength >= currentMessage.length) {
296
- isDeleting = true;
297
- placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_HOLD_DELAY_MS);
298
- return;
299
- }
300
-
301
- placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_TYPING_DELAY_MS);
302
- return;
303
- }
304
-
305
- visibleLength -= 1;
306
- userMessagePlaceholder.value = currentMessage.slice(0, Math.max(visibleLength, 0));
307
-
308
- if (visibleLength <= 0) {
309
- isDeleting = false;
310
- messageIndex = (messageIndex + 1) % messages.length;
311
- placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_TYPING_DELAY_MS);
312
- return;
313
- }
314
-
315
- placeholderAnimationTimer = setTimeout(animate, PLACEHOLDER_DELETING_DELAY_MS);
316
- };
317
-
318
- animate();
319
- }
320
-
321
- const isResponseInProgress = computed( () => {
322
- return currentChat.value?.status === 'streaming';
323
- });
324
- const blockCloseOfChat = ref(false);
325
-
326
- function sortSessionsListByTimestamp(sessionsList: ISessionsListItem[]) {
327
- return [...sessionsList].sort((a: ISessionsListItem, b: ISessionsListItem) => b.timestamp.localeCompare(a.timestamp));
328
- }
329
-
330
- async function sendMessage() {
331
- const message = trimmedUserMessage.value;
332
- if (!message || isResponseInProgress.value) {
333
- return;
334
- }
335
- if (!currentSession.value || currentSession.value.sessionId === 'pre-session') {
336
- await createNewSession(message);
337
- }
338
- currentSession.value!.timestamp = new Date().toISOString();
339
- sessionList.value = sortSessionsListByTimestamp(sessionList.value.map((s: ISessionsListItem) => s.sessionId === currentSession.value?.sessionId ? {
340
- ...s,
341
- timestamp: currentSession.value?.timestamp || s.timestamp,
342
- } : s));
343
- lastMessage.value = message;
344
- currentChat.value?.sendMessage({
345
- text: message,
346
- });
347
- userMessageInput.value = '';
348
- }
349
-
350
234
  function closeChat() {
351
235
  if(isFullScreen.value) {
352
236
  document.body.style.overflow = '';
@@ -387,216 +271,9 @@ export const useAgentStore = defineStore('agent', () => {
387
271
  textInput.value = el;
388
272
  }
389
273
 
390
- async function fetchPlaceholderMessages() {
391
- if (hasTypedMessageInPageSession.value) {
392
- stopPlaceholderAnimation();
393
- return;
394
- }
395
-
396
- try {
397
- const res = await callAdminForthApi({
398
- method: 'POST',
399
- path: '/agent/get-placeholder-messages',
400
- });
401
-
402
- if (res.error) {
403
- console.error('Error fetching placeholder messages:', res.error);
404
- placeholderMessages.value = [];
405
- resetPlaceholder();
406
- return;
407
- }
408
-
409
- placeholderMessages.value = Array.isArray(res.messages)
410
- ? res.messages.filter((message: unknown): message is string => typeof message === 'string' && message.length > 0)
411
- : [];
412
-
413
- if (!placeholderMessages.value.length) {
414
- resetPlaceholder();
415
- return;
416
- }
417
-
418
- startPlaceholderAnimation(placeholderMessages.value);
419
- } catch (error) {
420
- console.error('Error fetching placeholder messages', error);
421
- placeholderMessages.value = [];
422
- resetPlaceholder();
423
- }
424
- }
425
-
426
-
427
- //create a pre-session, until user will type something, so we can save session
428
- async function createPreSession() {
429
- saveCurrentSessionInCache();
430
- if (!sessionList.value.some((s: ISessionsListItem) => s.sessionId === 'pre-session')) {
431
- sessionList.value.unshift({
432
- sessionId: 'pre-session',
433
- title: 'New Session',
434
- timestamp: new Date().toISOString(),
435
- });
436
- }
437
-
438
- activeSessionId.value = 'pre-session';
439
- currentSession.value = {
440
- sessionId: 'pre-session',
441
- title: 'New Session',
442
- timestamp: new Date().toISOString(),
443
- messages: [],
444
- };
445
- sessions.value['pre-session'] = currentSession.value;
446
- setCurrentChat('pre-session');
447
- }
448
-
449
- async function deletePreSession() {
450
- sessionList.value = sessionList.value.filter((s: ISessionsListItem) => s.sessionId !== 'pre-session');
451
- if (activeSessionId.value === 'pre-session') {
452
- activeSessionId.value = null;
453
- currentSession.value = null;
454
- }
455
- }
456
-
457
- async function createNewSession(triggerMessage?: string) {
458
- try {
459
- const res = await callAdminForthApi({
460
- method: 'POST',
461
- path: '/agent/create-session',
462
- body: {
463
- triggerMessage
464
- },
465
- });
466
- if (res.error) {
467
- console.error('Error creating new session:', res.error);
468
- return;
469
- }
470
- deletePreSession();
471
- sessions.value[res.sessionId] = res;
472
- sessionList.value.unshift({
473
- sessionId: res.sessionId,
474
- title: res.title,
475
- timestamp: new Date().toISOString(),
476
- });
477
- setActiveSession(res.sessionId);
478
- } catch (error) {
479
- console.error('Error creating new session', error);
480
- }
481
- }
482
-
483
- async function deleteSession(sessionId: string) {
484
- if (sessionId === 'pre-session') {
485
- deletePreSession();
486
- return;
487
- }
488
- blockCloseOfChat.value = true;
489
- const isConfirmed = await adminforth.confirm({message: 'Are you sure, that you want to delete this session?', yes: 'Yes', no: 'No'})
490
- blockCloseOfChat.value = false;
491
- if (!isConfirmed) {
492
- return;
493
- }
494
- try {
495
- const res = await callAdminForthApi({
496
- method: 'POST',
497
- path: '/agent/delete-session',
498
- body: { sessionId },
499
- });
500
- if (res.error) {
501
- console.error('Error deleting session:', res.error);
502
- return;
503
- }
504
- delete sessions.value[sessionId];
505
- sessionList.value = sessionList.value.filter((s: ISessionsListItem) => s.sessionId !== sessionId);
506
- if (activeSessionId.value === sessionId) {
507
- activeSessionId.value = null;
508
- currentSession.value = null;
509
- }
510
- } catch (error) {
511
- console.error('Error deleting session', error);
512
- }
513
- if(sessionId === activeSessionId.value) {
514
- activeSessionId.value = sessionList.value.length > 0 ? sessionList.value[0].sessionId : null;
515
- if (activeSessionId.value) {
516
- currentSession.value = sessions.value[activeSessionId.value] || null;
517
- } else {
518
- currentSession.value = null;
519
- }
520
- }
521
- }
522
-
523
- async function fetchSession(sessionId: string) {
524
- try {
525
- const res = await callAdminForthApi({
526
- method: 'POST',
527
- path: '/agent/get-session-info',
528
- body: { sessionId },
529
- });
530
- if (res.error) {
531
- console.error('Error fetching session:', res.error);
532
- return;
533
- }
534
- sessions.value[sessionId] = res.session;
535
- setCurrentChat(sessionId);
536
- } catch (error) {
537
- console.error('Error fetching session', error);
538
- }
539
- }
540
-
541
- function saveCurrentSessionInCache() {
542
- if (currentSession.value) {
543
- currentSession.value.messages = currentChat.value?.messages.map((m: any) => ({
544
- role: m.role,
545
- text: m.parts.map((p: IPart) => p.type === 'text' ? p.text : '').join(''),
546
- })) || [];
547
- sessions.value[currentSession.value.sessionId] = currentSession.value;
548
- }
549
- }
550
-
551
- async function setActiveSession(sessionId: string) {
552
- activeSessionId.value = sessionId;
553
- saveCurrentSessionInCache();
554
- if (!sessions.value[sessionId]) {
555
- await fetchSession(sessionId);
556
- }
557
- currentSession.value = sessions.value[sessionId];
558
- setCurrentChat(sessionId);
559
- if (currentChat.value.messages.length === 0) {
560
- currentChat.value.messages = currentSession.value?.messages.map((m: any) => ({
561
- role: m.role,
562
- parts:[{
563
- type: 'text',
564
- text: m.text,
565
- state: 'done',
566
- }]
567
- }));
568
- }
569
- }
570
-
571
- async function fetchSessionsList() {
572
- try {
573
- const res = await callAdminForthApi({
574
- method: 'POST',
575
- path: '/agent/get-sessions',
576
- body: {
577
- limit: 100,
578
- },
579
- });
580
- if (res.error) {
581
- console.error('Error fetching sessions list:', res.error);
582
- return;
583
- }
584
- sessionList.value = res.sessions;
585
- } catch (error) {
586
- console.error('Error fetching sessions list', error);
587
- }
588
- }
589
-
590
- function addDebugMessage(message: string) {
591
- const debugMessage = {
592
- role: 'assistant',
593
- parts: [{
594
- type: 'text',
595
- text: message,
596
- state: 'done',
597
- }]
598
- };
599
- currentChat.value?.messages.push(debugMessage);
274
+ function abortCurrentChatRequestAndAddSystemMessage() {
275
+ abortCurrentChatRequest();
276
+ addSystemMessage('[Response generation aborted]');
600
277
  }
601
278
 
602
279
  return {
@@ -633,11 +310,14 @@ export const useAgentStore = defineStore('agent', () => {
633
310
  availableModes,
634
311
  activeModeName,
635
312
  setAvailableModes,
313
+ setCurrentGenerationModeFromLocalStorage,
636
314
  setActiveMode,
637
315
  DEFAULT_CHAT_WIDTH,
638
316
  MAX_WIDTH,
639
317
  MIN_WIDTH,
640
318
  getLocalStorageItem,
641
- addDebugMessage
319
+ addDebugMessage,
320
+ abortCurrentChatRequestAndAddSystemMessage,
321
+ addSystemMessage
642
322
  }
643
323
  })
@@ -68,7 +68,7 @@
68
68
  });
69
69
 
70
70
  const showFakeThinkingMessage = computed(() => {
71
- if (props.message.parts.length === 0) return true;
71
+ if (props.message.parts.length === 0 && props.isLastMessageInChat) return true;
72
72
  return false;
73
73
  })
74
74
 
@@ -0,0 +1,7 @@
1
+ interface ImportMetaEnv {
2
+ readonly VITE_ADMINFORTH_PUBLIC_PATH?: string;
3
+ }
4
+
5
+ interface ImportMeta {
6
+ readonly env: ImportMetaEnv;
7
+ }
@@ -19,6 +19,7 @@ export const contextSchema = z.object({
19
19
  userTimeZone: z.string(),
20
20
  sessionId: z.string(),
21
21
  turnId: z.string(),
22
+ currentPage: z.custom().optional(),
22
23
  httpExtra: z.custom().optional(),
23
24
  emitToolCallEvent: z.custom(),
24
25
  });
@@ -131,7 +132,7 @@ export function createAgentChatModel(params) {
131
132
  }
132
133
  export function callAgent(params) {
133
134
  return __awaiter(this, void 0, void 0, function* () {
134
- const { name, model, summaryModel, modelMiddleware = [], checkpointer, messages, adminUser, adminforth, apiBasedTools, customComponentsDir, sessionId, turnId, httpExtra, userTimeZone, emitToolCallEvent, sequenceDebugSink, } = params;
135
+ const { name, model, summaryModel, modelMiddleware = [], checkpointer, messages, adminUser, adminforth, apiBasedTools, customComponentsDir, sessionId, turnId, currentPage, httpExtra, userTimeZone, emitToolCallEvent, sequenceDebugSink, } = params;
135
136
  const tools = yield createAgentTools(customComponentsDir, apiBasedTools);
136
137
  const apiBasedToolsMiddleware = createApiBasedToolsMiddleware(apiBasedTools, adminforth);
137
138
  const sequenceDebugMiddleware = createSequenceDebugMiddleware(sequenceDebugSink);
@@ -165,6 +166,7 @@ export function callAgent(params) {
165
166
  userTimeZone,
166
167
  sessionId,
167
168
  turnId,
169
+ currentPage,
168
170
  httpExtra,
169
171
  emitToolCallEvent,
170
172
  },
@@ -0,0 +1,31 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { tool } from "langchain";
11
+ import { z } from "zod";
12
+ const getUserLocationSchema = z.object({});
13
+ export function createGetUserLocationTool() {
14
+ return tool((_input, runtime) => __awaiter(this, void 0, void 0, function* () {
15
+ const currentPage = runtime.context.currentPage;
16
+ if (!currentPage) {
17
+ return JSON.stringify({
18
+ status: 404,
19
+ message: "Current user location is not available.",
20
+ }, null, 2);
21
+ }
22
+ return JSON.stringify({
23
+ status: 200,
24
+ location: currentPage,
25
+ }, null, 2);
26
+ }), {
27
+ name: "get_user_location",
28
+ description: "Get the user's current location in the AdminForth UI, including current page path, full path, title, and URL. Call this tool when you do not understand what the user is referring to, especially when they say here, this page, current page, opened page, or otherwise rely on page context.",
29
+ schema: getUserLocationSchema,
30
+ });
31
+ }
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { createFetchSkillTool } from "./fetchSkill.js";
11
11
  import { createFetchToolSchemaTool } from "./fetchToolSchema.js";
12
12
  import { createApiTool } from "./apiTool.js";
13
+ import { createGetUserLocationTool } from "./getUserLocation.js";
13
14
  export const ALWAYS_AVAILABLE_API_TOOL_NAMES = ["get_resource"];
14
15
  export function createAgentTools(customComponentsDir, apiBasedTools) {
15
16
  return __awaiter(this, void 0, void 0, function* () {
@@ -21,6 +22,7 @@ export function createAgentTools(customComponentsDir, apiBasedTools) {
21
22
  }
22
23
  return createApiTool(toolName, apiBasedTool);
23
24
  }),
25
+ createGetUserLocationTool(),
24
26
  yield createFetchSkillTool(customComponentsDir),
25
27
  yield createFetchToolSchemaTool(apiBasedTools),
26
28
  ];
@@ -170,6 +170,7 @@
170
170
  </div>
171
171
  </div>
172
172
  <Button
173
+ v-if="!agentStore.isResponseInProgress"
173
174
  class="absolute right-4 bottom-2 !p-0 h-9 w-9"
174
175
  @click="sendMessage"
175
176
  :disabled="!agentStore.trimmedUserMessage || agentStore.isResponseInProgress"
@@ -179,6 +180,15 @@
179
180
  text-white"
180
181
  />
181
182
  </Button>
183
+ <Button
184
+ v-else
185
+ class="absolute right-4 bottom-2 !p-0 h-9 w-9"
186
+ @click="stopCurrentRequest"
187
+ >
188
+ <div
189
+ class="w-3 h-3 bg-white rounded-sm"
190
+ />
191
+ </Button>
182
192
  </div>
183
193
  </div>
184
194
  </div>
@@ -231,6 +241,7 @@ onClickOutside(modeMenu, () => { isModeMenuOpen.value = false; });
231
241
 
232
242
  onMounted(async () => {
233
243
  agentStore.setAvailableModes(props.meta.modes, props.meta.defaultModeName);
244
+ agentStore.setCurrentGenerationModeFromLocalStorage();
234
245
  agentStore.regisrerTextInput(textInput.value);
235
246
  window.addEventListener('resize', updateHeight)
236
247
  textInput.value?.focus();
@@ -316,6 +327,10 @@ async function sendMessage() {
316
327
  conversationArea.value?.handleSendMessage();
317
328
  }
318
329
 
330
+ function stopCurrentRequest() {
331
+ agentStore.abortCurrentChatRequestAndAddSystemMessage();
332
+ }
333
+
319
334
  function updateHeight() {
320
335
  dvh.value = Math.round(window.visualViewport?.height || window.innerHeight);
321
336
  }
@@ -0,0 +1,12 @@
1
+ export type AgentMode = {
2
+ name: string;
3
+ };
4
+
5
+ export const DEFAULT_CHAT_WIDTH = 30;
6
+ export const MAX_WIDTH = 60;
7
+ export const MIN_WIDTH = 25;
8
+
9
+ export const DEFAULT_TEXTAREA_PLACEHOLDER = 'Type a message...';
10
+ export const PLACEHOLDER_TYPING_DELAY_MS = 60;
11
+ export const PLACEHOLDER_DELETING_DELAY_MS = 35;
12
+ export const PLACEHOLDER_HOLD_DELAY_MS = 3000;