@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.
@@ -19,12 +19,14 @@ import {
19
19
  } from "./middleware/sequenceDebug.js";
20
20
  import type { ApiBasedTool } from "../apiBasedTools.js";
21
21
  import type { ToolCallEventSink } from "./toolCallEvents.js";
22
+ import type { CurrentPageContext } from "./tools/getUserLocation.js";
22
23
 
23
24
  export const contextSchema = z.object({
24
25
  adminUser: z.custom<AdminUser>(),
25
26
  userTimeZone: z.string(),
26
27
  sessionId: z.string(),
27
28
  turnId: z.string(),
29
+ currentPage: z.custom<CurrentPageContext>().optional(),
28
30
  httpExtra: z.custom<Partial<HttpExtra>>().optional(),
29
31
  emitToolCallEvent: z.custom<ToolCallEventSink>(),
30
32
  });
@@ -231,6 +233,7 @@ export async function callAgent(params: {
231
233
  customComponentsDir: string;
232
234
  sessionId: string;
233
235
  turnId: string;
236
+ currentPage?: CurrentPageContext;
234
237
  httpExtra?: Partial<HttpExtra>;
235
238
  userTimeZone: string;
236
239
  emitToolCallEvent: ToolCallEventSink;
@@ -249,6 +252,7 @@ export async function callAgent(params: {
249
252
  customComponentsDir,
250
253
  sessionId,
251
254
  turnId,
255
+ currentPage,
252
256
  httpExtra,
253
257
  userTimeZone,
254
258
  emitToolCallEvent,
@@ -293,6 +297,7 @@ export async function callAgent(params: {
293
297
  userTimeZone,
294
298
  sessionId,
295
299
  turnId,
300
+ currentPage,
296
301
  httpExtra,
297
302
  emitToolCallEvent,
298
303
  },
@@ -0,0 +1,45 @@
1
+ import { tool } from "langchain";
2
+ import { z } from "zod";
3
+
4
+ export type CurrentPageContext = {
5
+ path: string;
6
+ fullPath: string;
7
+ title: string;
8
+ url: string;
9
+ };
10
+
11
+ const getUserLocationSchema = z.object({});
12
+
13
+ export function createGetUserLocationTool() {
14
+ return tool(
15
+ async (_input, runtime) => {
16
+ const currentPage = (runtime.context as { currentPage?: CurrentPageContext }).currentPage;
17
+
18
+ if (!currentPage) {
19
+ return JSON.stringify(
20
+ {
21
+ status: 404,
22
+ message: "Current user location is not available.",
23
+ },
24
+ null,
25
+ 2,
26
+ );
27
+ }
28
+
29
+ return JSON.stringify(
30
+ {
31
+ status: 200,
32
+ location: currentPage,
33
+ },
34
+ null,
35
+ 2,
36
+ );
37
+ },
38
+ {
39
+ name: "get_user_location",
40
+ description:
41
+ "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.",
42
+ schema: getUserLocationSchema,
43
+ },
44
+ );
45
+ }
@@ -3,6 +3,7 @@ import { createFetchSkillTool } from "./fetchSkill.js";
3
3
  import { createFetchToolSchemaTool } from "./fetchToolSchema.js";
4
4
  import type { ApiBasedTool } from "../../apiBasedTools.js";
5
5
  import { createApiTool } from "./apiTool.js";
6
+ import { createGetUserLocationTool } from "./getUserLocation.js";
6
7
 
7
8
  export const ALWAYS_AVAILABLE_API_TOOL_NAMES = ["get_resource"] as const;
8
9
 
@@ -20,6 +21,7 @@ export async function createAgentTools(
20
21
 
21
22
  return createApiTool(toolName, apiBasedTool);
22
23
  }),
24
+ createGetUserLocationTool(),
23
25
  await createFetchSkillTool(customComponentsDir),
24
26
  await createFetchToolSchemaTool(apiBasedTools),
25
27
  ];
package/build.log CHANGED
@@ -8,6 +8,7 @@ custom/ChatSurface.vue
8
8
  custom/CustomAutoScrollContainer.vue
9
9
  custom/SessionsHistory.vue
10
10
  custom/chat.ts
11
+ custom/env.d.ts
11
12
  custom/package.json
12
13
  custom/pnpm-lock.yaml
13
14
  custom/tsconfig.json
@@ -16,6 +17,12 @@ custom/utils.ts
16
17
  custom/composables/
17
18
  custom/composables/useAgentStore.ts
18
19
  custom/composables/useAgentTransitions.ts
20
+ custom/composables/agentStore/
21
+ custom/composables/agentStore/constants.ts
22
+ custom/composables/agentStore/pageContext.ts
23
+ custom/composables/agentStore/useAgentChat.ts
24
+ custom/composables/agentStore/useAgentPlaceholder.ts
25
+ custom/composables/agentStore/useAgentSessions.ts
19
26
  custom/conversation_area/
20
27
  custom/conversation_area/ConversationArea.vue
21
28
  custom/conversation_area/MessageRenderer.vue
@@ -40,5 +47,5 @@ custom/skills/fetch_data/SKILL.md
40
47
  custom/skills/mutate_data/
41
48
  custom/skills/mutate_data/SKILL.md
42
49
 
43
- sent 210,653 bytes received 585 bytes 422,476.00 bytes/sec
44
- total size is 208,279 speedup is 0.99
50
+ sent 216,415 bytes received 699 bytes 434,228.00 bytes/sec
51
+ total size is 213,565 speedup is 0.98
@@ -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;
@@ -0,0 +1,8 @@
1
+ export function getCurrentPageContext() {
2
+ return {
3
+ path: window.location.pathname,
4
+ fullPath: `${window.location.pathname}${window.location.search}${window.location.hash}`,
5
+ title: document.title,
6
+ url: window.location.href,
7
+ };
8
+ }
@@ -0,0 +1,69 @@
1
+ import { DefaultChatTransport } from 'ai';
2
+ import { shallowRef, type Ref } from 'vue';
3
+ import { Chat } from '../../chat';
4
+ import { getCurrentPageContext } from './pageContext';
5
+
6
+ type AgentImportMeta = ImportMeta & {
7
+ env: {
8
+ VITE_ADMINFORTH_PUBLIC_PATH?: string;
9
+ };
10
+ };
11
+
12
+ type CreateAgentChatManagerOptions = {
13
+ lastMessage: Ref<string>;
14
+ activeModeName: Ref<string | null>;
15
+ };
16
+
17
+ export function createAgentChatManager({
18
+ lastMessage,
19
+ activeModeName,
20
+ }: CreateAgentChatManagerOptions) {
21
+ const chats = new Map<string, Chat<any>>();
22
+ const currentChat = shallowRef<Chat<any> | null>();
23
+
24
+ function setCurrentChat(sessionId: string) {
25
+ if (chats.has(sessionId)) {
26
+ currentChat.value = chats.get(sessionId) || null;
27
+ } else {
28
+ const newChat = new Chat({
29
+ transport: new DefaultChatTransport({
30
+ api: `${(import.meta as AgentImportMeta).env.VITE_ADMINFORTH_PUBLIC_PATH || ''}/adminapi/v1/agent/response`,
31
+ credentials: 'include',
32
+ prepareSendMessagesRequest({ messages }: any) {
33
+ const message = lastMessage.value;
34
+ const body = {
35
+ message,
36
+ sessionId,
37
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
38
+ mode: activeModeName.value,
39
+ currentPage: getCurrentPageContext(),
40
+ };
41
+
42
+ return {
43
+ headers: {
44
+ Accept: 'text/event-stream',
45
+ 'x-vercel-ai-ui-message-stream': 'v1',
46
+ },
47
+ body
48
+ };
49
+ }
50
+ }),
51
+ onError(error: unknown) {
52
+ console.error('Chat error:', error);
53
+ },
54
+ });
55
+ chats.set(sessionId, newChat);
56
+ currentChat.value = newChat;
57
+ }
58
+ }
59
+
60
+ function abortCurrentChatRequest() {
61
+ currentChat.value?.stop();
62
+ }
63
+
64
+ return {
65
+ currentChat,
66
+ setCurrentChat,
67
+ abortCurrentChatRequest,
68
+ };
69
+ }
@@ -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
+ }