@adminforth/agent 1.7.0 → 1.9.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/agent/simpleAgent.ts +2 -14
- package/build.log +2 -2
- package/custom/ChatSurface.vue +66 -7
- package/custom/Message.vue +40 -0
- package/custom/ToolsGroup.vue +0 -1
- package/custom/incremark_code_renderers/IncremarkShikiCodeBlock.vue +1 -0
- package/custom/useAgentStore.ts +31 -2
- package/dist/agent/simpleAgent.js +3 -12
- package/dist/custom/ChatSurface.vue +66 -7
- package/dist/custom/Message.vue +40 -0
- package/dist/custom/ToolsGroup.vue +0 -1
- package/dist/custom/incremark_code_renderers/IncremarkShikiCodeBlock.vue +1 -0
- package/dist/custom/useAgentStore.ts +31 -2
- package/dist/index.js +9 -9
- package/index.ts +8 -12
- package/package.json +1 -1
- package/types.ts +15 -6
package/agent/simpleAgent.ts
CHANGED
|
@@ -170,21 +170,9 @@ function createAgentLlmMetricsLogger() {
|
|
|
170
170
|
return new AgentLlmMetricsLogger();
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
function normalizeReasoning(reasoning: AgentReasoning) {
|
|
174
|
-
if (reasoning === "none") {
|
|
175
|
-
return undefined;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
effort: reasoning as "minimal" | "low" | "medium" | "high" | "xhigh",
|
|
180
|
-
summary: "auto" as const,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
173
|
export function createAgentChatModel(params: {
|
|
185
174
|
adapter: CompletionAdapter;
|
|
186
175
|
maxTokens: number;
|
|
187
|
-
reasoning: AgentReasoning;
|
|
188
176
|
modelName?: string;
|
|
189
177
|
}) {
|
|
190
178
|
const adapter = params.adapter as OpenAIBackedCompletionAdapter;
|
|
@@ -198,7 +186,7 @@ export function createAgentChatModel(params: {
|
|
|
198
186
|
|
|
199
187
|
const model = params.modelName ?? options.model ?? "gpt-5-nano";
|
|
200
188
|
const baseURL = options.baseURL ?? options.baseUrl;
|
|
201
|
-
const reasoning =
|
|
189
|
+
const reasoning = options.extraRequestBodyParameters?.reasoning;
|
|
202
190
|
|
|
203
191
|
// @ts-ignore
|
|
204
192
|
return new ChatOpenAI({
|
|
@@ -285,7 +273,7 @@ export async function callAgent(params: {
|
|
|
285
273
|
|
|
286
274
|
return await agent.stream({ messages } as any, {
|
|
287
275
|
streamMode: "messages",
|
|
288
|
-
recursionLimit:
|
|
276
|
+
recursionLimit: 100,
|
|
289
277
|
callbacks: [createAgentLlmMetricsLogger()],
|
|
290
278
|
configurable: {
|
|
291
279
|
thread_id: sessionId,
|
package/build.log
CHANGED
|
@@ -29,5 +29,5 @@ custom/skills/fetch_data/SKILL.md
|
|
|
29
29
|
custom/skills/mutate_data/
|
|
30
30
|
custom/skills/mutate_data/SKILL.md
|
|
31
31
|
|
|
32
|
-
sent
|
|
33
|
-
total size is
|
|
32
|
+
sent 174,667 bytes received 413 bytes 350,160.00 bytes/sec
|
|
33
|
+
total size is 173,014 speedup is 0.99
|
package/custom/ChatSurface.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="relative w-6 h-6 cursor-pointer mr-
|
|
3
|
+
class="relative w-6 h-6 cursor-pointer mr-1 mt-1
|
|
4
4
|
text-lightNavbarIcons hover:text-lightNavbarIcons/80
|
|
5
5
|
dark:text-darkNavbarIcons hover:text-darkNavbarIcons/80
|
|
6
6
|
hover:scale-110 transition-colors duration-200"
|
|
@@ -78,13 +78,49 @@
|
|
|
78
78
|
v-model="agentStore.userMessageInput"
|
|
79
79
|
ref="textInput"
|
|
80
80
|
@input="autoResize"
|
|
81
|
-
class="
|
|
81
|
+
:class="[
|
|
82
|
+
'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',
|
|
83
|
+
agentStore.availableModes.length > 1 ? 'p-4 pr-12 pb-12' : 'p-4 pr-12',
|
|
84
|
+
]"
|
|
82
85
|
placeholder="Type a message..."
|
|
83
|
-
@keydown.enter.exact.prevent="
|
|
86
|
+
@keydown.enter.exact.prevent="sendMessage"
|
|
84
87
|
/>
|
|
88
|
+
<div
|
|
89
|
+
v-if="agentStore.availableModes.length > 1"
|
|
90
|
+
ref="modeMenu"
|
|
91
|
+
class="absolute bottom-2 left-4"
|
|
92
|
+
>
|
|
93
|
+
<button
|
|
94
|
+
aria-label="Select mode"
|
|
95
|
+
class="flex h-8 w-8 items-center justify-center rounded-md border border-gray-200 bg-white text-lightNavbarIcons transition-colors duration-200 hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-darkNavbarIcons dark:hover:bg-gray-700"
|
|
96
|
+
:class="isModeMenuOpen ? 'bg-gray-100 dark:bg-gray-700' : ''"
|
|
97
|
+
:disabled="agentStore.isResponseInProgress"
|
|
98
|
+
title="Select mode"
|
|
99
|
+
type="button"
|
|
100
|
+
@click="toggleModeMenu"
|
|
101
|
+
>
|
|
102
|
+
<IconBrainOutline class="h-4 w-4" />
|
|
103
|
+
</button>
|
|
104
|
+
|
|
105
|
+
<div
|
|
106
|
+
v-if="isModeMenuOpen"
|
|
107
|
+
class="absolute bottom-full left-0 mb-2 min-w-40 overflow-hidden rounded-md border border-gray-200 bg-white shadow-lg dark:border-gray-600 dark:bg-gray-800"
|
|
108
|
+
>
|
|
109
|
+
<button
|
|
110
|
+
v-for="mode in agentStore.availableModes"
|
|
111
|
+
:key="mode.name"
|
|
112
|
+
class="block w-full px-3 py-2 text-left text-sm text-lightInputText transition-colors duration-150 hover:bg-gray-100 dark:text-darkInputText dark:hover:bg-gray-700"
|
|
113
|
+
:class="mode.name === agentStore.activeModeName ? 'bg-gray-100 dark:bg-gray-700' : ''"
|
|
114
|
+
type="button"
|
|
115
|
+
@click="selectMode(mode.name)"
|
|
116
|
+
>
|
|
117
|
+
{{ mode.name }}
|
|
118
|
+
</button>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
85
121
|
<Button
|
|
86
122
|
class="absolute right-4 bottom-2 !p-0 h-[34px] w-[34px]"
|
|
87
|
-
@click="
|
|
123
|
+
@click="sendMessage"
|
|
88
124
|
:disabled="!agentStore.trimmedUserMessage || agentStore.isResponseInProgress"
|
|
89
125
|
>
|
|
90
126
|
<IconArrowUpOutline
|
|
@@ -101,8 +137,8 @@
|
|
|
101
137
|
|
|
102
138
|
<script setup lang="ts">
|
|
103
139
|
import { IconChatBubbleLeft20Solid, IconSparklesSolid } from '@iconify-prerendered/vue-heroicons';
|
|
104
|
-
import { IconCloseOutline, IconBarsOutline, IconArrowUpOutline, IconCloseSidebarSolid, IconOpenSidebarSolid } from '@iconify-prerendered/vue-flowbite';
|
|
105
|
-
import { useTemplateRef, onMounted, ref
|
|
140
|
+
import { IconCloseOutline, IconBarsOutline, IconArrowUpOutline, IconCloseSidebarSolid, IconOpenSidebarSolid, IconBrainOutline } from '@iconify-prerendered/vue-flowbite';
|
|
141
|
+
import { useTemplateRef, onMounted, ref } from 'vue';
|
|
106
142
|
import { onClickOutside } from '@vueuse/core'
|
|
107
143
|
import ConversationArea from './ConversationArea.vue';
|
|
108
144
|
import { useAgentStore } from './useAgentStore';
|
|
@@ -112,13 +148,19 @@ import { useCoreStore } from '@/stores/core';
|
|
|
112
148
|
const props = defineProps<{
|
|
113
149
|
meta: {
|
|
114
150
|
pluginInstanceId: string;
|
|
151
|
+
modes: Array<{
|
|
152
|
+
name: string;
|
|
153
|
+
}>;
|
|
154
|
+
defaultModeName: string | null;
|
|
115
155
|
}
|
|
116
156
|
}>();
|
|
117
157
|
|
|
118
158
|
const chatSurface = useTemplateRef('chatSurface');
|
|
119
159
|
const textInput = useTemplateRef('textInput');
|
|
160
|
+
const modeMenu = useTemplateRef('modeMenu');
|
|
120
161
|
const agentStore = useAgentStore();
|
|
121
162
|
const coreStore = useCoreStore();
|
|
163
|
+
const isModeMenuOpen = ref(false);
|
|
122
164
|
|
|
123
165
|
const MAX_WIDTH = 800;
|
|
124
166
|
const MIN_WIDTH = 382; //w-96
|
|
@@ -158,8 +200,10 @@ const stopResize = () => {
|
|
|
158
200
|
}
|
|
159
201
|
|
|
160
202
|
onClickOutside(chatSurface, () => {if (!agentStore.isTeleportedToBody) agentStore.setIsChatOpen(false);});
|
|
203
|
+
onClickOutside(modeMenu, () => { isModeMenuOpen.value = false; });
|
|
161
204
|
|
|
162
205
|
onMounted(async () => {
|
|
206
|
+
agentStore.setAvailableModes(props.meta.modes, props.meta.defaultModeName);
|
|
163
207
|
agentStore.regisrerTextInput(textInput.value);
|
|
164
208
|
textInput.value?.focus();
|
|
165
209
|
await agentStore.fetchSessionsList();
|
|
@@ -181,4 +225,19 @@ function autoResize() {
|
|
|
181
225
|
}
|
|
182
226
|
}
|
|
183
227
|
|
|
184
|
-
|
|
228
|
+
function toggleModeMenu() {
|
|
229
|
+
isModeMenuOpen.value = !isModeMenuOpen.value;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function selectMode(modeName: string) {
|
|
233
|
+
agentStore.setActiveMode(modeName);
|
|
234
|
+
isModeMenuOpen.value = false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function sendMessage() {
|
|
238
|
+
isModeMenuOpen.value = false;
|
|
239
|
+
await agentStore.sendMessage();
|
|
240
|
+
autoResize();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
</script>
|
package/custom/Message.vue
CHANGED
|
@@ -207,4 +207,44 @@
|
|
|
207
207
|
max-height: 144px;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
</style>
|
|
211
|
+
|
|
212
|
+
<style lang="scss">
|
|
213
|
+
.incremark a.incremark-link,
|
|
214
|
+
.incremark a.incremark-link:visited {
|
|
215
|
+
display: inline-block;
|
|
216
|
+
text-decoration: underline;
|
|
217
|
+
text-underline-offset: 4px;
|
|
218
|
+
text-decoration-style:dotted;
|
|
219
|
+
color: rgb(0, 0, 0);
|
|
220
|
+
transition: color 0.2s ease;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.incremark a.incremark-link:hover {
|
|
224
|
+
color: rgb(74, 74, 255);
|
|
225
|
+
text-decoration: underline;
|
|
226
|
+
text-underline-offset: 4px;
|
|
227
|
+
text-decoration-style:dotted;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
html[data-theme="dark"] .incremark a.incremark-link,
|
|
231
|
+
html[data-theme="dark"] .incremark a.incremark-link:visited {
|
|
232
|
+
color: rgb(220, 220, 220);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
html[data-theme="dark"] .incremark a.incremark-link:hover {
|
|
236
|
+
color: rgb(147, 147, 255);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
a.incremark-link::after {
|
|
240
|
+
content: "";
|
|
241
|
+
display: inline-block;
|
|
242
|
+
width: 16px;
|
|
243
|
+
height: 16px;
|
|
244
|
+
vertical-align: middle;
|
|
245
|
+
rotate: -45deg;
|
|
246
|
+
background-color: currentColor;
|
|
247
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M13 12H2m12 0l-4 4m4-4l-4-4'/%3E%3C/svg%3E") no-repeat center;
|
|
248
|
+
mask-size: contain;
|
|
249
|
+
}
|
|
210
250
|
</style>
|
package/custom/ToolsGroup.vue
CHANGED
package/custom/useAgentStore.ts
CHANGED
|
@@ -7,6 +7,10 @@ import { Chat } from './chat';
|
|
|
7
7
|
import { DefaultChatTransport } from 'ai';
|
|
8
8
|
import { useCoreStore } from '@/stores/core';
|
|
9
9
|
|
|
10
|
+
type AgentMode = {
|
|
11
|
+
name: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
10
14
|
export const useAgentStore = defineStore('agent', () => {
|
|
11
15
|
const activeSessionId = ref<string | null>(null);
|
|
12
16
|
const currentSession = ref<IAgentSession | null>(null);
|
|
@@ -28,6 +32,8 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
28
32
|
const header = ref<HTMLElement | null>(null);
|
|
29
33
|
const lastSessionId = ref<string | null>(null);
|
|
30
34
|
const chatWidth = ref(600);
|
|
35
|
+
const availableModes = ref<AgentMode[]>([]);
|
|
36
|
+
const activeModeName = ref<string | null>(null);
|
|
31
37
|
function setLocalStorageItem(key: string, value: string) {
|
|
32
38
|
window.localStorage.setItem(`${coreStore.config.brandName || 'adminforth'}-${key}`, value);
|
|
33
39
|
}
|
|
@@ -91,6 +97,24 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
91
97
|
})
|
|
92
98
|
const chats = new Map<string, Chat<any>>();
|
|
93
99
|
const currentChat = shallowRef<Chat<any>>();
|
|
100
|
+
|
|
101
|
+
function setAvailableModes(modes: AgentMode[], defaultModeName?: string | null) {
|
|
102
|
+
availableModes.value = modes;
|
|
103
|
+
activeModeName.value =
|
|
104
|
+
modes.find((mode) => mode.name === activeModeName.value)?.name
|
|
105
|
+
?? defaultModeName
|
|
106
|
+
?? modes[0]?.name
|
|
107
|
+
?? null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function setActiveMode(modeName: string) {
|
|
111
|
+
if (!availableModes.value.some((mode) => mode.name === modeName)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
activeModeName.value = modeName;
|
|
116
|
+
}
|
|
117
|
+
|
|
94
118
|
function setCurrentChat(sessionId: string) {
|
|
95
119
|
if (chats.has(sessionId)) {
|
|
96
120
|
currentChat.value = chats.get(sessionId) || null;
|
|
@@ -105,6 +129,7 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
105
129
|
message,
|
|
106
130
|
sessionId,
|
|
107
131
|
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
132
|
+
mode: activeModeName.value,
|
|
108
133
|
};
|
|
109
134
|
|
|
110
135
|
return {
|
|
@@ -368,6 +393,10 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
368
393
|
setIsTeleportedToBody,
|
|
369
394
|
chatWidth,
|
|
370
395
|
setChatWidth,
|
|
371
|
-
focusTextInput
|
|
396
|
+
focusTextInput,
|
|
397
|
+
availableModes,
|
|
398
|
+
activeModeName,
|
|
399
|
+
setAvailableModes,
|
|
400
|
+
setActiveMode,
|
|
372
401
|
}
|
|
373
|
-
})
|
|
402
|
+
})
|
|
@@ -103,17 +103,8 @@ class AgentLlmMetricsLogger extends BaseCallbackHandler {
|
|
|
103
103
|
function createAgentLlmMetricsLogger() {
|
|
104
104
|
return new AgentLlmMetricsLogger();
|
|
105
105
|
}
|
|
106
|
-
function normalizeReasoning(reasoning) {
|
|
107
|
-
if (reasoning === "none") {
|
|
108
|
-
return undefined;
|
|
109
|
-
}
|
|
110
|
-
return {
|
|
111
|
-
effort: reasoning,
|
|
112
|
-
summary: "auto",
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
106
|
export function createAgentChatModel(params) {
|
|
116
|
-
var _a, _b, _c, _d;
|
|
107
|
+
var _a, _b, _c, _d, _e;
|
|
117
108
|
const adapter = params.adapter;
|
|
118
109
|
const options = (_a = adapter.options) !== null && _a !== void 0 ? _a : {};
|
|
119
110
|
if (!options.openAiApiKey) {
|
|
@@ -121,7 +112,7 @@ export function createAgentChatModel(params) {
|
|
|
121
112
|
}
|
|
122
113
|
const model = (_c = (_b = params.modelName) !== null && _b !== void 0 ? _b : options.model) !== null && _c !== void 0 ? _c : "gpt-5-nano";
|
|
123
114
|
const baseURL = (_d = options.baseURL) !== null && _d !== void 0 ? _d : options.baseUrl;
|
|
124
|
-
const reasoning =
|
|
115
|
+
const reasoning = (_e = options.extraRequestBodyParameters) === null || _e === void 0 ? void 0 : _e.reasoning;
|
|
125
116
|
// @ts-ignore
|
|
126
117
|
return new ChatOpenAI(Object.assign(Object.assign(Object.assign({ apiKey: options.openAiApiKey, model, maxTokens: params.maxTokens, useResponsesApi: true, outputVersion: "v1", promptCacheKey: `adminforth-agent:${model}:system-v1:tools-v1`, promptCacheRetention: "in_memory" }, (reasoning ? { reasoning } : {})), (typeof options.timeoutMs === "number"
|
|
127
118
|
? { timeout: options.timeoutMs }
|
|
@@ -160,7 +151,7 @@ export function callAgent(params) {
|
|
|
160
151
|
});
|
|
161
152
|
return yield agent.stream({ messages }, {
|
|
162
153
|
streamMode: "messages",
|
|
163
|
-
recursionLimit:
|
|
154
|
+
recursionLimit: 100,
|
|
164
155
|
callbacks: [createAgentLlmMetricsLogger()],
|
|
165
156
|
configurable: {
|
|
166
157
|
thread_id: sessionId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="relative w-6 h-6 cursor-pointer mr-
|
|
3
|
+
class="relative w-6 h-6 cursor-pointer mr-1 mt-1
|
|
4
4
|
text-lightNavbarIcons hover:text-lightNavbarIcons/80
|
|
5
5
|
dark:text-darkNavbarIcons hover:text-darkNavbarIcons/80
|
|
6
6
|
hover:scale-110 transition-colors duration-200"
|
|
@@ -78,13 +78,49 @@
|
|
|
78
78
|
v-model="agentStore.userMessageInput"
|
|
79
79
|
ref="textInput"
|
|
80
80
|
@input="autoResize"
|
|
81
|
-
class="
|
|
81
|
+
:class="[
|
|
82
|
+
'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',
|
|
83
|
+
agentStore.availableModes.length > 1 ? 'p-4 pr-12 pb-12' : 'p-4 pr-12',
|
|
84
|
+
]"
|
|
82
85
|
placeholder="Type a message..."
|
|
83
|
-
@keydown.enter.exact.prevent="
|
|
86
|
+
@keydown.enter.exact.prevent="sendMessage"
|
|
84
87
|
/>
|
|
88
|
+
<div
|
|
89
|
+
v-if="agentStore.availableModes.length > 1"
|
|
90
|
+
ref="modeMenu"
|
|
91
|
+
class="absolute bottom-2 left-4"
|
|
92
|
+
>
|
|
93
|
+
<button
|
|
94
|
+
aria-label="Select mode"
|
|
95
|
+
class="flex h-8 w-8 items-center justify-center rounded-md border border-gray-200 bg-white text-lightNavbarIcons transition-colors duration-200 hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-darkNavbarIcons dark:hover:bg-gray-700"
|
|
96
|
+
:class="isModeMenuOpen ? 'bg-gray-100 dark:bg-gray-700' : ''"
|
|
97
|
+
:disabled="agentStore.isResponseInProgress"
|
|
98
|
+
title="Select mode"
|
|
99
|
+
type="button"
|
|
100
|
+
@click="toggleModeMenu"
|
|
101
|
+
>
|
|
102
|
+
<IconBrainOutline class="h-4 w-4" />
|
|
103
|
+
</button>
|
|
104
|
+
|
|
105
|
+
<div
|
|
106
|
+
v-if="isModeMenuOpen"
|
|
107
|
+
class="absolute bottom-full left-0 mb-2 min-w-40 overflow-hidden rounded-md border border-gray-200 bg-white shadow-lg dark:border-gray-600 dark:bg-gray-800"
|
|
108
|
+
>
|
|
109
|
+
<button
|
|
110
|
+
v-for="mode in agentStore.availableModes"
|
|
111
|
+
:key="mode.name"
|
|
112
|
+
class="block w-full px-3 py-2 text-left text-sm text-lightInputText transition-colors duration-150 hover:bg-gray-100 dark:text-darkInputText dark:hover:bg-gray-700"
|
|
113
|
+
:class="mode.name === agentStore.activeModeName ? 'bg-gray-100 dark:bg-gray-700' : ''"
|
|
114
|
+
type="button"
|
|
115
|
+
@click="selectMode(mode.name)"
|
|
116
|
+
>
|
|
117
|
+
{{ mode.name }}
|
|
118
|
+
</button>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
85
121
|
<Button
|
|
86
122
|
class="absolute right-4 bottom-2 !p-0 h-[34px] w-[34px]"
|
|
87
|
-
@click="
|
|
123
|
+
@click="sendMessage"
|
|
88
124
|
:disabled="!agentStore.trimmedUserMessage || agentStore.isResponseInProgress"
|
|
89
125
|
>
|
|
90
126
|
<IconArrowUpOutline
|
|
@@ -101,8 +137,8 @@
|
|
|
101
137
|
|
|
102
138
|
<script setup lang="ts">
|
|
103
139
|
import { IconChatBubbleLeft20Solid, IconSparklesSolid } from '@iconify-prerendered/vue-heroicons';
|
|
104
|
-
import { IconCloseOutline, IconBarsOutline, IconArrowUpOutline, IconCloseSidebarSolid, IconOpenSidebarSolid } from '@iconify-prerendered/vue-flowbite';
|
|
105
|
-
import { useTemplateRef, onMounted, ref
|
|
140
|
+
import { IconCloseOutline, IconBarsOutline, IconArrowUpOutline, IconCloseSidebarSolid, IconOpenSidebarSolid, IconBrainOutline } from '@iconify-prerendered/vue-flowbite';
|
|
141
|
+
import { useTemplateRef, onMounted, ref } from 'vue';
|
|
106
142
|
import { onClickOutside } from '@vueuse/core'
|
|
107
143
|
import ConversationArea from './ConversationArea.vue';
|
|
108
144
|
import { useAgentStore } from './useAgentStore';
|
|
@@ -112,13 +148,19 @@ import { useCoreStore } from '@/stores/core';
|
|
|
112
148
|
const props = defineProps<{
|
|
113
149
|
meta: {
|
|
114
150
|
pluginInstanceId: string;
|
|
151
|
+
modes: Array<{
|
|
152
|
+
name: string;
|
|
153
|
+
}>;
|
|
154
|
+
defaultModeName: string | null;
|
|
115
155
|
}
|
|
116
156
|
}>();
|
|
117
157
|
|
|
118
158
|
const chatSurface = useTemplateRef('chatSurface');
|
|
119
159
|
const textInput = useTemplateRef('textInput');
|
|
160
|
+
const modeMenu = useTemplateRef('modeMenu');
|
|
120
161
|
const agentStore = useAgentStore();
|
|
121
162
|
const coreStore = useCoreStore();
|
|
163
|
+
const isModeMenuOpen = ref(false);
|
|
122
164
|
|
|
123
165
|
const MAX_WIDTH = 800;
|
|
124
166
|
const MIN_WIDTH = 382; //w-96
|
|
@@ -158,8 +200,10 @@ const stopResize = () => {
|
|
|
158
200
|
}
|
|
159
201
|
|
|
160
202
|
onClickOutside(chatSurface, () => {if (!agentStore.isTeleportedToBody) agentStore.setIsChatOpen(false);});
|
|
203
|
+
onClickOutside(modeMenu, () => { isModeMenuOpen.value = false; });
|
|
161
204
|
|
|
162
205
|
onMounted(async () => {
|
|
206
|
+
agentStore.setAvailableModes(props.meta.modes, props.meta.defaultModeName);
|
|
163
207
|
agentStore.regisrerTextInput(textInput.value);
|
|
164
208
|
textInput.value?.focus();
|
|
165
209
|
await agentStore.fetchSessionsList();
|
|
@@ -181,4 +225,19 @@ function autoResize() {
|
|
|
181
225
|
}
|
|
182
226
|
}
|
|
183
227
|
|
|
184
|
-
|
|
228
|
+
function toggleModeMenu() {
|
|
229
|
+
isModeMenuOpen.value = !isModeMenuOpen.value;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function selectMode(modeName: string) {
|
|
233
|
+
agentStore.setActiveMode(modeName);
|
|
234
|
+
isModeMenuOpen.value = false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function sendMessage() {
|
|
238
|
+
isModeMenuOpen.value = false;
|
|
239
|
+
await agentStore.sendMessage();
|
|
240
|
+
autoResize();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
</script>
|
package/dist/custom/Message.vue
CHANGED
|
@@ -207,4 +207,44 @@
|
|
|
207
207
|
max-height: 144px;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
</style>
|
|
211
|
+
|
|
212
|
+
<style lang="scss">
|
|
213
|
+
.incremark a.incremark-link,
|
|
214
|
+
.incremark a.incremark-link:visited {
|
|
215
|
+
display: inline-block;
|
|
216
|
+
text-decoration: underline;
|
|
217
|
+
text-underline-offset: 4px;
|
|
218
|
+
text-decoration-style:dotted;
|
|
219
|
+
color: rgb(0, 0, 0);
|
|
220
|
+
transition: color 0.2s ease;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.incremark a.incremark-link:hover {
|
|
224
|
+
color: rgb(74, 74, 255);
|
|
225
|
+
text-decoration: underline;
|
|
226
|
+
text-underline-offset: 4px;
|
|
227
|
+
text-decoration-style:dotted;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
html[data-theme="dark"] .incremark a.incremark-link,
|
|
231
|
+
html[data-theme="dark"] .incremark a.incremark-link:visited {
|
|
232
|
+
color: rgb(220, 220, 220);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
html[data-theme="dark"] .incremark a.incremark-link:hover {
|
|
236
|
+
color: rgb(147, 147, 255);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
a.incremark-link::after {
|
|
240
|
+
content: "";
|
|
241
|
+
display: inline-block;
|
|
242
|
+
width: 16px;
|
|
243
|
+
height: 16px;
|
|
244
|
+
vertical-align: middle;
|
|
245
|
+
rotate: -45deg;
|
|
246
|
+
background-color: currentColor;
|
|
247
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M13 12H2m12 0l-4 4m4-4l-4-4'/%3E%3C/svg%3E") no-repeat center;
|
|
248
|
+
mask-size: contain;
|
|
249
|
+
}
|
|
210
250
|
</style>
|
|
@@ -7,6 +7,10 @@ import { Chat } from './chat';
|
|
|
7
7
|
import { DefaultChatTransport } from 'ai';
|
|
8
8
|
import { useCoreStore } from '@/stores/core';
|
|
9
9
|
|
|
10
|
+
type AgentMode = {
|
|
11
|
+
name: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
10
14
|
export const useAgentStore = defineStore('agent', () => {
|
|
11
15
|
const activeSessionId = ref<string | null>(null);
|
|
12
16
|
const currentSession = ref<IAgentSession | null>(null);
|
|
@@ -28,6 +32,8 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
28
32
|
const header = ref<HTMLElement | null>(null);
|
|
29
33
|
const lastSessionId = ref<string | null>(null);
|
|
30
34
|
const chatWidth = ref(600);
|
|
35
|
+
const availableModes = ref<AgentMode[]>([]);
|
|
36
|
+
const activeModeName = ref<string | null>(null);
|
|
31
37
|
function setLocalStorageItem(key: string, value: string) {
|
|
32
38
|
window.localStorage.setItem(`${coreStore.config.brandName || 'adminforth'}-${key}`, value);
|
|
33
39
|
}
|
|
@@ -91,6 +97,24 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
91
97
|
})
|
|
92
98
|
const chats = new Map<string, Chat<any>>();
|
|
93
99
|
const currentChat = shallowRef<Chat<any>>();
|
|
100
|
+
|
|
101
|
+
function setAvailableModes(modes: AgentMode[], defaultModeName?: string | null) {
|
|
102
|
+
availableModes.value = modes;
|
|
103
|
+
activeModeName.value =
|
|
104
|
+
modes.find((mode) => mode.name === activeModeName.value)?.name
|
|
105
|
+
?? defaultModeName
|
|
106
|
+
?? modes[0]?.name
|
|
107
|
+
?? null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function setActiveMode(modeName: string) {
|
|
111
|
+
if (!availableModes.value.some((mode) => mode.name === modeName)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
activeModeName.value = modeName;
|
|
116
|
+
}
|
|
117
|
+
|
|
94
118
|
function setCurrentChat(sessionId: string) {
|
|
95
119
|
if (chats.has(sessionId)) {
|
|
96
120
|
currentChat.value = chats.get(sessionId) || null;
|
|
@@ -105,6 +129,7 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
105
129
|
message,
|
|
106
130
|
sessionId,
|
|
107
131
|
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
132
|
+
mode: activeModeName.value,
|
|
108
133
|
};
|
|
109
134
|
|
|
110
135
|
return {
|
|
@@ -368,6 +393,10 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
368
393
|
setIsTeleportedToBody,
|
|
369
394
|
chatWidth,
|
|
370
395
|
setChatWidth,
|
|
371
|
-
focusTextInput
|
|
396
|
+
focusTextInput,
|
|
397
|
+
availableModes,
|
|
398
|
+
activeModeName,
|
|
399
|
+
setAvailableModes,
|
|
400
|
+
setActiveMode,
|
|
372
401
|
}
|
|
373
|
-
})
|
|
402
|
+
})
|
package/dist/index.js
CHANGED
|
@@ -100,7 +100,11 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
100
100
|
modifyResourceConfig: { get: () => super.modifyResourceConfig }
|
|
101
101
|
});
|
|
102
102
|
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
+
var _a;
|
|
103
104
|
_super.modifyResourceConfig.call(this, adminforth, resourceConfig);
|
|
105
|
+
if (!((_a = this.options.modes) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
106
|
+
throw new Error("modes is required for AdminForthAgentPlugin");
|
|
107
|
+
}
|
|
104
108
|
if (!this.adminforth.config.customization.globalInjections.header) {
|
|
105
109
|
this.adminforth.config.customization.globalInjections.header = [];
|
|
106
110
|
}
|
|
@@ -108,11 +112,10 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
108
112
|
file: this.componentPath("ChatSurface.vue"),
|
|
109
113
|
meta: {
|
|
110
114
|
pluginInstanceId: this.pluginInstanceId,
|
|
115
|
+
modes: this.options.modes.map((mode) => ({ name: mode.name })),
|
|
116
|
+
defaultModeName: this.options.modes[0].name,
|
|
111
117
|
}
|
|
112
118
|
});
|
|
113
|
-
if (!this.pluginOptions.completionAdapter) {
|
|
114
|
-
throw new Error("CompletionAdapter is required for AdminForthAgentPlugin");
|
|
115
|
-
}
|
|
116
119
|
if (!this.pluginOptions.sessionResource) {
|
|
117
120
|
throw new Error("sessionResource is required for AdminForthAgentPlugin");
|
|
118
121
|
}
|
|
@@ -210,17 +213,14 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
210
213
|
messageId,
|
|
211
214
|
});
|
|
212
215
|
const maxTokens = (_f = this.options.maxTokens) !== null && _f !== void 0 ? _f : 10000;
|
|
213
|
-
const
|
|
214
|
-
const summaryReasoning = 'low';
|
|
216
|
+
const selectedMode = (_g = this.options.modes.find((mode) => mode.name === body.mode)) !== null && _g !== void 0 ? _g : this.options.modes[0];
|
|
215
217
|
const model = createAgentChatModel({
|
|
216
|
-
adapter:
|
|
218
|
+
adapter: selectedMode.completionAdapter,
|
|
217
219
|
maxTokens,
|
|
218
|
-
reasoning,
|
|
219
220
|
});
|
|
220
221
|
const summaryModel = createAgentChatModel({
|
|
221
|
-
adapter:
|
|
222
|
+
adapter: selectedMode.completionAdapter,
|
|
222
223
|
maxTokens,
|
|
223
|
-
reasoning: summaryReasoning,
|
|
224
224
|
});
|
|
225
225
|
const systemPrompt = yield this.agentSystemPromptPromise;
|
|
226
226
|
const stream = yield callAgent({
|
package/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AdminForthResource,
|
|
3
|
-
AdminUser,
|
|
4
3
|
IAdminForth,
|
|
5
4
|
IHttpServer
|
|
6
5
|
} from "adminforth";
|
|
@@ -115,6 +114,9 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
115
114
|
|
|
116
115
|
async modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
|
|
117
116
|
super.modifyResourceConfig(adminforth, resourceConfig);
|
|
117
|
+
if (!this.options.modes?.length) {
|
|
118
|
+
throw new Error("modes is required for AdminForthAgentPlugin");
|
|
119
|
+
}
|
|
118
120
|
if (!this.adminforth.config.customization.globalInjections.header) {
|
|
119
121
|
this.adminforth.config.customization.globalInjections.header = [];
|
|
120
122
|
}
|
|
@@ -122,12 +124,10 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
122
124
|
file: this.componentPath("ChatSurface.vue"),
|
|
123
125
|
meta: {
|
|
124
126
|
pluginInstanceId: this.pluginInstanceId,
|
|
127
|
+
modes: this.options.modes.map((mode) => ({ name: mode.name })),
|
|
128
|
+
defaultModeName: this.options.modes[0].name,
|
|
125
129
|
}
|
|
126
130
|
});
|
|
127
|
-
|
|
128
|
-
if (!this.pluginOptions.completionAdapter) {
|
|
129
|
-
throw new Error("CompletionAdapter is required for AdminForthAgentPlugin");
|
|
130
|
-
}
|
|
131
131
|
if (!this.pluginOptions.sessionResource) {
|
|
132
132
|
throw new Error("sessionResource is required for AdminForthAgentPlugin");
|
|
133
133
|
}
|
|
@@ -244,19 +244,15 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
244
244
|
});
|
|
245
245
|
|
|
246
246
|
const maxTokens = this.options.maxTokens ?? 10000;
|
|
247
|
-
const
|
|
248
|
-
const summaryReasoning = 'low';
|
|
249
|
-
|
|
247
|
+
const selectedMode = this.options.modes.find((mode) => mode.name === body.mode) ?? this.options.modes[0];
|
|
250
248
|
const model = createAgentChatModel({
|
|
251
|
-
adapter:
|
|
249
|
+
adapter: selectedMode.completionAdapter,
|
|
252
250
|
maxTokens,
|
|
253
|
-
reasoning,
|
|
254
251
|
});
|
|
255
252
|
|
|
256
253
|
const summaryModel = createAgentChatModel({
|
|
257
|
-
adapter:
|
|
254
|
+
adapter: selectedMode.completionAdapter,
|
|
258
255
|
maxTokens,
|
|
259
|
-
reasoning: summaryReasoning,
|
|
260
256
|
});
|
|
261
257
|
const systemPrompt = await this.agentSystemPromptPromise;
|
|
262
258
|
const stream = await callAgent({
|
package/package.json
CHANGED
package/types.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { type CompletionAdapter } from "adminforth";
|
|
1
|
+
import { type PluginsCommonOptions, type CompletionAdapter } from "adminforth";
|
|
3
2
|
|
|
4
3
|
interface ISessionResource {
|
|
5
4
|
resourceId: string;
|
|
@@ -22,11 +21,14 @@ interface ITurnResource {
|
|
|
22
21
|
|
|
23
22
|
export interface PluginOptions extends PluginsCommonOptions {
|
|
24
23
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* Modes for the plugin.
|
|
25
|
+
* Each mode can have its own configuration.
|
|
26
|
+
* Each mode uses its own completion adapter instance.
|
|
28
27
|
*/
|
|
29
|
-
|
|
28
|
+
modes: {
|
|
29
|
+
name: string;
|
|
30
|
+
completionAdapter: CompletionAdapter;
|
|
31
|
+
}[];
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
34
|
* Max tokens for the generation.
|
|
@@ -40,6 +42,13 @@ export interface PluginOptions extends PluginsCommonOptions {
|
|
|
40
42
|
*/
|
|
41
43
|
reasoning?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
42
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Resource configuration for sessions.
|
|
47
|
+
*/
|
|
43
48
|
sessionResource: ISessionResource;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Resource configuration for turns.
|
|
52
|
+
*/
|
|
44
53
|
turnResource: ITurnResource;
|
|
45
54
|
}
|